diff --git a/.clang-format b/.clang-format index 603c00c59b1..15012747148 100644 --- a/.clang-format +++ b/.clang-format @@ -67,6 +67,7 @@ ForEachMacros: - 'Z_GENLIST_FOR_EACH_NODE_SAFE' - 'STRUCT_SECTION_FOREACH' - 'TYPE_SECTION_FOREACH' + - 'K_SPINLOCK' IfMacros: - 'CHECKIF' # Disabled for now, see bug https://github.com/zephyrproject-rtos/zephyr/issues/48520 diff --git a/.github/workflows/assigner.yml b/.github/workflows/assigner.yml index 6a3198086de..6e4e01c8ea1 100644 --- a/.github/workflows/assigner.yml +++ b/.github/workflows/assigner.yml @@ -9,6 +9,7 @@ on: - ready_for_review branches: - main + - collab-* - v*-branch issues: types: @@ -27,7 +28,7 @@ jobs: pip3 install -U PyGithub>=1.55 west - name: Check out source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run assignment script env: diff --git a/.github/workflows/backport_issue_check.yml b/.github/workflows/backport_issue_check.yml index a66edd318f7..95175ecf1bb 100644 --- a/.github/workflows/backport_issue_check.yml +++ b/.github/workflows/backport_issue_check.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Check out source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python dependencies run: | diff --git a/.github/workflows/bsim-tests.yaml b/.github/workflows/bsim-tests.yaml index f52a0439d20..402ae686593 100644 --- a/.github/workflows/bsim-tests.yaml +++ b/.github/workflows/bsim-tests.yaml @@ -20,6 +20,8 @@ on: - "include/zephyr/net/openthread.h" - "drivers/ieee802154/**" - "include/zephyr/net/ieee802154*" + - "drivers/serial/*nrfx*" + - "tests/drivers/uart/**" concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} @@ -30,13 +32,12 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject env: ZEPHYR_TOOLCHAIN_VARIANT: zephyr - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components EDTT_PATH: ../tools/edtt @@ -44,6 +45,7 @@ jobs: bsim_bt_53_test_results_file: ./bsim_bt/53_bsim_results.xml bsim_bt_53split_test_results_file: ./bsim_bt/53_bsim_split_results.xml bsim_net_52_test_results_file: ./bsim_net/52_bsim_results.xml + bsim_uart_test_results_file: ./bsim_uart/uart_bsim_results.xml steps: - name: Apply container owner mismatch workaround run: | @@ -60,7 +62,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -79,8 +81,10 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check common triggering files - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-common-files with: files: | @@ -95,7 +99,7 @@ jobs: tests/bsim/* - name: Check if Bluethooth files changed - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-bluetooth-files with: files: | @@ -104,7 +108,7 @@ jobs: subsys/bluetooth/** - name: Check if Networking files changed - uses: tj-actions/changed-files@v35 + uses: tj-actions/changed-files@v41 id: check-networking-files with: files: | @@ -116,10 +120,20 @@ jobs: drivers/ieee802154/** include/zephyr/net/ieee802154* + - name: Check if UART files changed + uses: tj-actions/changed-files@v41 + id: check-uart-files + with: + files: | + tests/bsim/drivers/uart/** + drivers/serial/*nrfx* + tests/drivers/uart/** + - name: Update BabbleSim to manifest revision if: > steps.check-bluetooth-files.outputs.any_changed == 'true' || steps.check-networking-files.outputs.any_changed == 'true' + || steps.check-uart-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' run: | export BSIM_VERSION=$( west list bsim -f {revision} ) @@ -163,9 +177,21 @@ jobs: RESULTS_FILE=${ZEPHYR_BASE}/${bsim_net_52_test_results_file} \ SEARCH_PATH=tests/bsim/net/ tests/bsim/run_parallel.sh + - name: Run UART Tests with BSIM + if: steps.check-uart-files.outputs.any_changed == 'true' || steps.check-common-files.outputs.any_changed == 'true' + run: | + echo "UART: Single device tests" + ./scripts/twister -T tests/drivers/uart/ --force-color --inline-logs -v -M -p nrf52_bsim \ + --fixture gpio_loopback -- -uart0_loopback + echo "UART: Multi device tests" + export ZEPHYR_BASE=${PWD} + WORK_DIR=${ZEPHYR_BASE}/bsim_uart nice tests/bsim/drivers/uart/compile.sh + RESULTS_FILE=${ZEPHYR_BASE}/${bsim_uart_test_results_file} \ + SEARCH_PATH=tests/bsim/drivers/uart/ tests/bsim/run_parallel.sh + - name: Upload Test Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bsim-test-results path: | @@ -173,12 +199,15 @@ jobs: ./bsim_bt/53_bsim_results.xml ./bsim_bt/53_bsim_split_results.xml ./bsim_net/52_bsim_results.xml + ./bsim_uart/uart_bsim_results.xml + ./twister-out/twister.xml + ./twister-out/twister.json ${{ github.event_path }} if-no-files-found: warn - name: Upload Event Details if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: event path: | diff --git a/.github/workflows/bug_snapshot.yaml b/.github/workflows/bug_snapshot.yaml index d19f881ddcd..16b251b7f2f 100644 --- a/.github/workflows/bug_snapshot.yaml +++ b/.github/workflows/bug_snapshot.yaml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python dependencies run: | diff --git a/.github/workflows/clang.yaml b/.github/workflows/clang.yaml index 34b4b8595a9..b28d3c387e4 100644 --- a/.github/workflows/clang.yaml +++ b/.github/workflows/clang.yaml @@ -10,17 +10,16 @@ jobs: clang-build: runs-on: ubuntu-latest container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject strategy: fail-fast: false matrix: - platform: ["native_posix"] + platform: ["native_sim"] subset: [1, 2, 3, 4, 5] env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 LLVM_TOOLCHAIN_PATH: /usr/lib/llvm-16 COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} BASE_REF: ${{ github.base_ref }} @@ -43,7 +42,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -67,6 +66,8 @@ jobs: # west caching). west update --path-cache /github/cache/zephyrproject 2>&1 1> west.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west2.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check Environment run: | cmake --version @@ -136,7 +137,7 @@ jobs: - name: Upload Unit Test Results if: always() && steps.twister.outputs.report_needed != 0 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Unit Test Results (Subset ${{ matrix.subset }}) path: twister-out/twister.xml @@ -148,7 +149,7 @@ jobs: if: (success() || failure() ) && needs.clang-build.outputs.report_needed != 0 steps: - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts - name: Merge Test Results @@ -159,7 +160,7 @@ jobs: - name: Upload Unit Test Results in HTML if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: HTML Unit Test Results if-no-files-found: ignore diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 92cf90b8299..7888529ee40 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -2,7 +2,7 @@ name: Code Coverage with codecov on: schedule: - - cron: '25 */3 * * 1-5' + - cron: '25 06,18 * * 1-5' concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} @@ -13,16 +13,14 @@ jobs: if: github.repository == 'zephyrproject-rtos/zephyr' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject strategy: fail-fast: false matrix: - platform: ["native_posix", "qemu_x86", "unit_testing"] - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + platform: ["mps2_an385", "native_sim", "qemu_x86", "unit_testing"] steps: - name: Apply container owner mismatch workaround run: | @@ -43,7 +41,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 @@ -52,11 +50,14 @@ jobs: west init -l . || true west update 1> west.update.log || west update 1> west.update-2.log - - name: Check Environment + - name: Environment Setup run: | cmake --version gcc --version ls -la + + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Prepare ccache keys id: ccache_cache_prop shell: cmake -P {0} @@ -88,27 +89,25 @@ jobs: export ZEPHYR_BASE=${PWD} export ZEPHYR_TOOLCHAIN_VARIANT=zephyr mkdir -p coverage/reports - ./scripts/twister --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests - - - name: Generate Coverage Report - run: | - mv twister-out/coverage.info lcov.pre.info - lcov -q --remove lcov.pre.info mylib.c --remove lcov.pre.info tests/\* \ - --remove lcov.pre.info samples/\* --remove lcov.pre.info ext/\* \ - --remove lcov.pre.info *generated* \ - -o coverage/reports/${{ matrix.platform }}.info --rc lcov_branch_coverage=1 + pip3 install gcovr==6.0 + ./scripts/twister -i --force-color -N -v --filter runnable -p ${{ matrix.platform }} --coverage -T tests --coverage-tool gcovr -xCONFIG_TEST_EXTRA_STACK_SIZE=4096 -e nano - name: ccache stats post run: | ccache -s ccache -p + - name: Rename coverage files + if: always() + run: | + cp twister-out/coverage.json coverage/reports/${{ matrix.platform }}.json + - name: Upload Coverage Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Coverage Data (Subset ${{ matrix.platform }}) - path: coverage/reports/${{ matrix.platform }}.info + path: coverage/reports/${{ matrix.platform }}.json codecov-results: name: "Publish Coverage Results" @@ -119,24 +118,24 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: coverage/reports - name: Move coverage files run: | - mv ./coverage/reports/*/*.info ./coverage/reports + mv ./coverage/reports/*/*.json ./coverage/reports ls -la ./coverage/reports - name: Generate list of coverage files id: get-coverage-files shell: cmake -P {0} run: | - file(GLOB INPUT_FILES_LIST "coverage/reports/*.info") + file(GLOB INPUT_FILES_LIST "coverage/reports/*.json") set(MERGELIST "") set(FILELIST "") foreach(ITEM ${INPUT_FILES_LIST}) @@ -150,7 +149,7 @@ jobs: foreach(ITEM ${INPUT_FILES_LIST}) get_filename_component(f ${ITEM} NAME) if(MERGELIST STREQUAL "") - set(MERGELIST "-a ${f}") + set(MERGELIST "--add-tracefile ${f}") else() set(MERGELIST "${MERGELIST} -a ${f}") endif() @@ -160,10 +159,19 @@ jobs: - name: Merge coverage files run: | - sudo apt-get update - sudo apt-get install -y lcov cd ./coverage/reports - lcov ${{ steps.get-coverage-files.outputs.mergefiles }} -o merged.info --rc lcov_branch_coverage=1 + pip3 install gcovr==6.0 + gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --json merged.json + gcovr ${{ steps.get-coverage-files.outputs.mergefiles }} --merge-mode-functions=separate --cobertura merged.xml + + - name: Upload Merged Coverage Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Merged Coverage Data + path: | + coverage/reports/merged.json + coverage/reports/merged.xml - name: Upload coverage to Codecov if: always() @@ -173,4 +181,4 @@ jobs: env_vars: OS,PYTHON fail_ci_if_error: false verbose: true - files: merged.info + files: merged.xml diff --git a/.github/workflows/coding_guidelines.yml b/.github/workflows/coding_guidelines.yml index c810a22415e..1bc6ee2e666 100644 --- a/.github/workflows/coding_guidelines.yml +++ b/.github/workflows/coding_guidelines.yml @@ -8,13 +8,13 @@ jobs: name: Run coding guidelines checks on patch series (PR) steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/coding_guidelines.yml') }} diff --git a/.github/workflows/compliance.yml b/.github/workflows/compliance.yml index 036729418cb..5dc913626cd 100644 --- a/.github/workflows/compliance.yml +++ b/.github/workflows/compliance.yml @@ -12,13 +12,13 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('.github/workflows/compliance.yml') }} @@ -44,7 +44,7 @@ jobs: # debug git log --pretty=oneline | head -n 10 west init -l . || true - west config manifest.group-filter -- +ci,+optional + west config manifest.group-filter -- +ci,-optional west update -o=--depth=1 -n 2>&1 1> west.update.log || west update -o=--depth=1 -n 2>&1 1> west.update2.log - name: Run Compliance Tests @@ -61,7 +61,7 @@ jobs: -e KconfigBasicNoModules -e ModulesMaintainers -c origin/${BASE_REF}.. - name: upload-results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: compliance.xml diff --git a/.github/workflows/daily_test_version.yml b/.github/workflows/daily_test_version.yml index ba02bb68975..31e9fcde9b8 100644 --- a/.github/workflows/daily_test_version.yml +++ b/.github/workflows/daily_test_version.yml @@ -28,7 +28,7 @@ jobs: pip3 install gitpython - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/.github/workflows/devicetree_checks.yml b/.github/workflows/devicetree_checks.yml index b2d73453b28..c8408f68c09 100644 --- a/.github/workflows/devicetree_checks.yml +++ b/.github/workflows/devicetree_checks.yml @@ -35,14 +35,14 @@ jobs: python-version: 3.6 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} @@ -50,7 +50,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }} - name: cache-pip-mac if: startsWith(runner.os, 'macOS') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/Library/Caches/pip # Trailing '-' was just to get a different cache name @@ -59,7 +59,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }}- - name: cache-pip-win if: startsWith(runner.os, 'Windows') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/do_not_merge.yml b/.github/workflows/do_not_merge.yml index 14c651a25f1..b6954e288c9 100644 --- a/.github/workflows/do_not_merge.yml +++ b/.github/workflows/do_not_merge.yml @@ -7,12 +7,14 @@ on: jobs: do-not-merge: if: ${{ contains(github.event.*.labels.*.name, 'DNM') || - contains(github.event.*.labels.*.name, 'TSC') }} + contains(github.event.*.labels.*.name, 'TSC') || + contains(github.event.*.labels.*.name, 'Architecture Review') || + contains(github.event.*.labels.*.name, 'dev-review') }} name: Prevent Merging runs-on: ubuntu-22.04 steps: - name: Check for label run: | - echo "Pull request is labeled as 'DNM' or 'TSC'" - echo "This workflow fails so that the pull request cannot be merged" + echo "Pull request is labeled as 'DNM', 'TSC', 'Architecture Review' or 'dev-review'." + echo "This workflow fails so that the pull request cannot be merged." exit 1 diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index fa83fe252c7..9dde3128477 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -44,7 +44,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -70,7 +70,7 @@ jobs: echo "${PWD}/doxygen-${DOXYGEN_VERSION}/bin" >> $GITHUB_PATH - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: pip-${{ hashFiles('doc/requirements.txt') }} @@ -116,13 +116,13 @@ jobs: tar cfJ api-coverage.tar.xz coverage-report - name: upload-build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: html-output path: html-output.tar.xz - name: upload-api-coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: api-coverage path: api-coverage.tar.xz @@ -142,7 +142,7 @@ jobs: echo "API Coverage Report will be available shortly at: ${API_COVERAGE_URL}" >> $GITHUB_STEP_SUMMARY - name: upload-pr-number - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: github.event_name == 'pull_request' with: name: pr_num @@ -166,7 +166,7 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: install-pkgs run: | @@ -174,7 +174,7 @@ jobs: apt-get install -y python3-pip python3-venv ninja-build doxygen graphviz librsvg2-bin - name: cache-pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: pip-${{ hashFiles('doc/requirements.txt') }} @@ -210,7 +210,7 @@ jobs: - name: upload-build if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pdf-output if-no-files-found: ignore diff --git a/.github/workflows/errno.yml b/.github/workflows/errno.yml index 537470f0a22..e6bea7dca4a 100644 --- a/.github/workflows/errno.yml +++ b/.github/workflows/errno.yml @@ -10,9 +10,7 @@ jobs: check-errno: runs-on: ubuntu-22.04 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 steps: - name: Apply container owner mismatch workaround @@ -24,7 +22,11 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Environment Setup + run: | + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV - name: Run errno.py run: | diff --git a/.github/workflows/footprint-tracking.yml b/.github/workflows/footprint-tracking.yml index fee3a00449f..e028ddd5329 100644 --- a/.github/workflows/footprint-tracking.yml +++ b/.github/workflows/footprint-tracking.yml @@ -25,12 +25,11 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository_owner == 'zephyrproject-rtos' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround @@ -52,11 +51,15 @@ jobs: sudo pip3 install -U setuptools wheel pip gitpython - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: Environment Setup + run: | + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: west setup run: | west init -l . || true diff --git a/.github/workflows/footprint.yml b/.github/workflows/footprint.yml index 685c5644b0c..e25ef7f4652 100644 --- a/.github/workflows/footprint.yml +++ b/.github/workflows/footprint.yml @@ -11,12 +11,11 @@ jobs: runs-on: zephyr-runner-linux-x64-4xlarge if: github.repository == 'zephyrproject-rtos/zephyr' container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' strategy: fail-fast: false env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 ZEPHYR_TOOLCHAIN_VARIANT: zephyr steps: - name: Apply container owner mismatch workaround @@ -32,7 +31,7 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -53,6 +52,9 @@ jobs: git remote -v git rebase origin/${BASE_REF} git checkout -b this_pr + + export ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION ) + west update west build -b frdm_k64f tests/benchmarks/footprints -t ram_report cp build/ram.json ram2.json diff --git a/.github/workflows/greet_first_time_contributor.yml b/.github/workflows/greet_first_time_contributor.yml index 5984b29fe1f..5f62c03d6de 100644 --- a/.github/workflows/greet_first_time_contributor.yml +++ b/.github/workflows/greet_first_time_contributor.yml @@ -12,8 +12,8 @@ jobs: if: github.repository == 'zephyrproject-rtos/zephyr' steps: - - uses: actions/checkout@v3 - - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-4 + - uses: actions/checkout@v4 + - uses: zephyrproject-rtos/action-first-interaction@v1.1.1-zephyr-5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/hello_world_multiplatform.yaml b/.github/workflows/hello_world_multiplatform.yaml new file mode 100644 index 00000000000..e30b09af51d --- /dev/null +++ b/.github/workflows/hello_world_multiplatform.yaml @@ -0,0 +1,79 @@ +name: Hello World (Multiplatform) + +on: + push: + branches: + - main + - v*-branch + - collab-* + pull_request: + branches: + - main + - v*-branch + - collab-* + paths: + - 'scripts/build/**' + - 'scripts/requirements*.txt' + - '.github/workflows/hello_world_multiplatform.yaml' + - 'SDK_VERSION' + +concurrency: + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, macos-12, macos-14, windows-2022] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + path: zephyr + fetch-depth: 0 + + - name: Rebase + if: github.event_name == 'pull_request' + env: + BASE_REF: ${{ github.base_ref }} + PR_HEAD: ${{ github.event.pull_request.head.sha }} + working-directory: zephyr + shell: bash + run: | + git config --global user.email "actions@zephyrproject.org" + git config --global user.name "Github Actions" + git rebase origin/${BASE_REF} + git log --graph --oneline HEAD...${PR_HEAD} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: zephyr + toolchains: all + + - name: Build firmware + working-directory: zephyr + shell: bash + run: | + if [ "${{ runner.os }}" = "macOS" ]; then + EXTRA_TWISTER_FLAGS="-P native_sim --build-only" + elif [ "${{ runner.os }}" = "Windows" ]; then + EXTRA_TWISTER_FLAGS="-P native_sim --short-build-path -O/tmp/twister-out" + fi + ./scripts/twister --force-color --inline-logs -T samples/hello_world -v $EXTRA_TWISTER_FLAGS + + - name: Upload artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + if-no-files-found: ignore + path: + zephyr/twister-out/*/samples/hello_world/sample.basic.helloworld/build.log diff --git a/.github/workflows/issue_count.yml b/.github/workflows/issue_count.yml index 9c143dbd1f4..f44ef5531d4 100644 --- a/.github/workflows/issue_count.yml +++ b/.github/workflows/issue_count.yml @@ -35,7 +35,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: upload-stats - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: ${{ env.OUTPUT_FILE_NAME }} diff --git a/.github/workflows/license_check.yml b/.github/workflows/license_check.yml index 0efedb13489..7d2d083faae 100644 --- a/.github/workflows/license_check.yml +++ b/.github/workflows/license_check.yml @@ -8,7 +8,7 @@ jobs: name: Scan code for licenses steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Scan the code @@ -17,7 +17,7 @@ jobs: with: directory-to-scan: 'scan/' - name: Artifact Upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: scancode path: ./artifacts diff --git a/.github/workflows/manifest.yml b/.github/workflows/manifest.yml index fcae7973996..040ec957e39 100644 --- a/.github/workflows/manifest.yml +++ b/.github/workflows/manifest.yml @@ -8,7 +8,7 @@ jobs: name: Manifest steps: - name: Checkout the code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: zephyrproject/zephyr ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/pylib_tests.yml b/.github/workflows/pylib_tests.yml index 4368a66d04f..70bd107f8e5 100644 --- a/.github/workflows/pylib_tests.yml +++ b/.github/workflows/pylib_tests.yml @@ -29,14 +29,14 @@ jobs: os: [ubuntu-22.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab0e9384ae7..ccecd17df80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: release: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -26,7 +26,7 @@ jobs: args: spdx -o zephyr-${{ steps.get_version.outputs.VERSION }}.spdx - name: upload-results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 continue-on-error: true with: name: zephyr-${{ steps.get_version.outputs.VERSION }}.spdx diff --git a/.github/workflows/scripts_tests.yml b/.github/workflows/scripts_tests.yml index 7c1a2887ae6..2e2356910b1 100644 --- a/.github/workflows/scripts_tests.yml +++ b/.github/workflows/scripts_tests.yml @@ -29,7 +29,7 @@ jobs: os: [ubuntu-20.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -52,7 +52,7 @@ jobs: - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/stats_merged_prs.yml b/.github/workflows/stats_merged_prs.yml new file mode 100644 index 00000000000..cd874b65b1a --- /dev/null +++ b/.github/workflows/stats_merged_prs.yml @@ -0,0 +1,24 @@ +name: Merged PR stats + +on: + pull_request_target: + branches: + - main + - v*-branch + types: [closed] +jobs: + record_merged: + if: github.event.pull_request.merged == true && github.repository == 'zephyrproject-rtos/zephyr' + runs-on: ubuntu-22.04 + steps: + - name: checkout + uses: actions/checkout@v4 + - name: PR event + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ELASTICSEARCH_KEY: ${{ secrets.ELASTICSEARCH_KEY }} + ELASTICSEARCH_SERVER: "https://elasticsearch.zephyrproject.io:443" + PR_STAT_ES_INDEX: ${{ vars.PR_STAT_ES_INDEX }} + run: | + pip3 install pygithub elasticsearch + python3 ./scripts/ci/stats/merged_prs.py --pull-request ${{ github.event.pull_request.number }} --repo ${{ github.repository }} diff --git a/.github/workflows/twister.yaml b/.github/workflows/twister.yaml index 23174d7ab7c..a56ce93c42d 100644 --- a/.github/workflows/twister.yaml +++ b/.github/workflows/twister.yaml @@ -24,7 +24,7 @@ jobs: if: github.repository_owner == 'zephyrproject-rtos' runs-on: zephyr-runner-linux-x64-4xlarge container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -36,7 +36,6 @@ jobs: MATRIX_SIZE: 10 PUSH_MATRIX_SIZE: 15 DAILY_MATRIX_SIZE: 80 - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TESTS_PER_BUILDER: 700 @@ -60,7 +59,7 @@ jobs: - name: Checkout if: github.event_name == 'pull_request_target' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -80,6 +79,8 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Generate Test Plan with Twister if: github.event_name == 'pull_request_target' id: test-plan @@ -122,7 +123,7 @@ jobs: needs: twister-build-prep if: needs.twister-build-prep.outputs.size != 0 container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 options: '--entrypoint /bin/bash' volumes: - /repo-cache/zephyrproject:/github/cache/zephyrproject @@ -131,7 +132,6 @@ jobs: matrix: subset: ${{fromJSON(needs.twister-build-prep.outputs.subset)}} env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 BSIM_OUT_PATH: /opt/bsim/ BSIM_COMPONENTS_PATH: /opt/bsim/components TWISTER_COMMON: ' --force-color --inline-logs -v -N -M --retry-failed 3 ' @@ -156,7 +156,7 @@ jobs: git remote set-url origin ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -179,6 +179,14 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + # Hotfix until we have kitware ninja in the docker image. + # Needed for full functionality of the job server functionality in twister which only works with + # kitware supplied ninja version. + wget -c https://github.com/Kitware/ninja/releases/download/v1.11.1.g95dee.kitware.jobserver-1/ninja-1.11.1.g95dee.kitware.jobserver-1_x86_64-linux-gnu.tar.gz -O - | tar xz --strip-components=1 + sudo cp ninja /usr/local/bin + + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Check Environment run: | cmake --version @@ -263,7 +271,7 @@ jobs: - name: Upload Unit Test Results if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Unit Test Results (Subset ${{ matrix.subset }}) if-no-files-found: ignore @@ -273,6 +281,24 @@ jobs: module_tests/twister.xml testplan.json + - if: matrix.subset == 1 && github.event_name == 'push' + name: Save the list of Python packages + shell: bash + run: | + FREEZE_FILE="frozen-requirements.txt" + timestamp="$(date)" + version="$(git describe --abbrev=12 --always)" + echo -e "# Generated at $timestamp ($version)\n" > $FREEZE_FILE + pip3 freeze | tee -a $FREEZE_FILE + + - if: matrix.subset == 1 && github.event_name == 'push' + name: Upload the list of Python packages + uses: actions/upload-artifact@v4 + with: + name: Frozen PIP package set + path: | + frozen-requirements.txt + twister-test-results: name: "Publish Unit Tests Results" env: @@ -287,13 +313,13 @@ jobs: # Needed for opensearch and upload script - if: github.event_name == 'push' || github.event_name == 'schedule' name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false - name: Download Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts @@ -319,7 +345,7 @@ jobs: - name: Upload Unit Test Results in HTML if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: HTML Unit Test Results if-no-files-found: ignore diff --git a/.github/workflows/twister_tests.yml b/.github/workflows/twister_tests.yml index 606c49dfdf9..92de15b81b0 100644 --- a/.github/workflows/twister_tests.yml +++ b/.github/workflows/twister_tests.yml @@ -9,7 +9,7 @@ on: - main - v*-branch paths: - - 'scripts/pylib/twister/**' + - 'scripts/pylib/**' - 'scripts/twister' - 'scripts/tests/twister/**' - '.github/workflows/twister_tests.yml' @@ -18,7 +18,7 @@ on: - main - v*-branch paths: - - 'scripts/pylib/twister/**' + - 'scripts/pylib/**' - 'scripts/twister' - 'scripts/tests/twister/**' - '.github/workflows/twister_tests.yml' @@ -33,14 +33,14 @@ jobs: os: [ubuntu-22.04] steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index a18f79ae455..cdb11d95286 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -22,9 +22,7 @@ jobs: python-version: [3.8, 3.9, '3.10', '3.11', '3.12'] os: [ubuntu-22.04] container: - image: ghcr.io/zephyrproject-rtos/ci:v0.26.5 - env: - ZEPHYR_SDK_INSTALL_DIR: /opt/toolchains/zephyr-sdk-0.16.3 + image: ghcr.io/zephyrproject-rtos/ci:v0.26.7 steps: - name: Apply Container Owner Mismatch Workaround @@ -36,7 +34,7 @@ jobs: git config --global --add safe.directory ${GITHUB_WORKSPACE} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Environment Setup run: | @@ -47,6 +45,8 @@ jobs: west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' + echo "ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-$( cat SDK_VERSION )" >> $GITHUB_ENV + - name: Set Up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: diff --git a/.github/workflows/west_cmds.yml b/.github/workflows/west_cmds.yml index 4a3c1964643..25a5fc88fd6 100644 --- a/.github/workflows/west_cmds.yml +++ b/.github/workflows/west_cmds.yml @@ -36,14 +36,14 @@ jobs: python-version: 3.6 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: cache-pip-linux if: startsWith(runner.os, 'Linux') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ matrix.python-version }} @@ -51,7 +51,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }} - name: cache-pip-mac if: startsWith(runner.os, 'macOS') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/Library/Caches/pip # Trailing '-' was just to get a different cache name @@ -60,7 +60,7 @@ jobs: ${{ runner.os }}-pip-${{ matrix.python-version }}- - name: cache-pip-win if: startsWith(runner.os, 'Windows') - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache key: ${{ runner.os }}-pip-${{ matrix.python-version }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 97bcd98d0d7..f1fb89660f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,11 @@ endif() # Apply the final optimization flag(s) zephyr_compile_options(${OPTIMIZATION_FLAG}) +if(CONFIG_LTO) + add_compile_options($) + add_link_options($) +endif() + # @Intent: Obtain compiler specific flags related to C++ that are not influenced by kconfig zephyr_compile_options($<$:$>) @@ -581,12 +586,14 @@ foreach(module_name ${ZEPHYR_MODULE_NAMES}) # https://cmake.org/pipermail/cmake/2019-June/069547.html zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR} STREQUAL "") + set(ZEPHYR_CURRENT_MODULE_NAME ${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_NAME}) set(ZEPHYR_CURRENT_MODULE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR}) set(ZEPHYR_CURRENT_CMAKE_DIR ${ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR}) add_subdirectory(${ZEPHYR_CURRENT_CMAKE_DIR} ${CMAKE_BINARY_DIR}/modules/${module_name}) endif() endforeach() -# Done processing modules, clear ZEPHYR_CURRENT_MODULE_DIR and ZEPHYR_CURRENT_CMAKE_DIR. +# Done processing modules, clear module variables +set(ZEPHYR_CURRENT_MODULE_NAME) set(ZEPHYR_CURRENT_MODULE_DIR) set(ZEPHYR_CURRENT_CMAKE_DIR) @@ -803,6 +810,10 @@ target_include_directories(${OFFSETS_LIB} PRIVATE kernel/include ${ARCH_DIR}/${ARCH}/include ) + +# Make sure that LTO will never be enabled when compiling offsets.c +set_source_files_properties(${OFFSETS_C_PATH} PROPERTIES COMPILE_OPTIONS $) + target_link_libraries(${OFFSETS_LIB} zephyr_interface) add_dependencies(zephyr_interface ${SYSCALL_LIST_H_TARGET} @@ -1226,10 +1237,11 @@ if(CONFIG_GEN_ISR_TABLES) # isr_tables.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by # gen_isr_tables.py add_custom_command( - OUTPUT isr_tables.c + OUTPUT isr_tables.c isr_tables_vt.ld isr_tables_swi.ld COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/gen_isr_tables.py --output-source isr_tables.c + --linker-output-files isr_tables_vt.ld isr_tables_swi.ld --kernel $ --intlist-section .intList --intlist-section intList @@ -1622,18 +1634,20 @@ if(CONFIG_BUILD_OUTPUT_BIN AND CONFIG_BUILD_OUTPUT_UF2) endif() if(CONFIG_BUILD_OUTPUT_META) + set(KERNEL_META_PATH ${PROJECT_BINARY_DIR}/${KERNEL_META_NAME} CACHE INTERNAL "") + list(APPEND post_build_commands COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py - ${WEST_ARG} ${ZEPHYR_MODULES_ARG} ${EXTRA_ZEPHYR_MODULES_ARG} - --meta-out ${KERNEL_META_NAME} + --meta-out ${KERNEL_META_PATH} + --zephyr-base=${ZEPHYR_BASE} $<$:--meta-state-propagate> ) list(APPEND post_build_byproducts - ${KERNEL_META_NAME} + ${KERNEL_META_PATH} ) endif() @@ -1751,7 +1765,6 @@ if(CONFIG_BUILD_OUTPUT_EXE) post_build_byproducts ${KERNEL_EXE_NAME} ) - set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) else() if(CMAKE_GENERATOR STREQUAL "Unix Makefiles") set(MAKE "${CMAKE_MAKE_PROGRAM}" CACHE FILEPATH "cmake defined make") @@ -1768,6 +1781,7 @@ if(CONFIG_BUILD_OUTPUT_EXE) BYPRODUCTS ${KERNEL_EXE_NAME} ) endif() + set(BYPRODUCT_KERNEL_EXE_NAME "${PROJECT_BINARY_DIR}/${KERNEL_EXE_NAME}" CACHE FILEPATH "Kernel exe file" FORCE) endif() if(CONFIG_BUILD_OUTPUT_INFO_HEADER) @@ -1784,42 +1798,51 @@ if(CONFIG_BUILD_OUTPUT_INFO_HEADER) ) endif() -if(CONFIG_CHECK_INIT_PRIORITIES) - list(APPEND - post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} +if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") + set(check_init_priorities_input + $,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}> + ) + set(check_init_priorities_command + ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py + --elf-file=${check_init_priorities_input} + ) + set(check_init_priorities_dependencies + ${logical_target_for_zephyr_elf} + $<$:native_runner_executable> + ) + + if(CONFIG_CHECK_INIT_PRIORITIES) + add_custom_target( + check_init_priorities + ALL + COMMAND ${check_init_priorities_command} + DEPENDS ${check_init_priorities_dependencies} ) -endif() + endif() -if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang") add_custom_target( initlevels - COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/check_init_priorities.py - --elf-file=${ZEPHYR_BINARY_DIR}/${KERNEL_ELF_NAME} - --initlevels - DEPENDS ${logical_target_for_zephyr_elf} + COMMAND ${check_init_priorities_command} --initlevels + DEPENDS ${check_init_priorities_dependencies} USES_TERMINAL ) endif() -# Generate and use MCUboot related artifacts as needed. -if(CONFIG_BOOTLOADER_MCUBOOT) - get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) +# Generate signed (MCUboot or other) related artifacts as needed. Priority is: +# * Sysbuild (if set) +# * SIGNING_SCRIPT target property (if set) +# * MCUboot signing script (if MCUboot is enabled) +zephyr_get(signing_script VAR SIGNING_SCRIPT SYSBUILD) - if(NOT signing_script) - zephyr_get(signing_script VAR SIGNING_SCRIPT SYSBUILD) +if(NOT signing_script) + get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) - if(signing_script) - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${signing_script}) - else() - set_target_properties(zephyr_property_target PROPERTIES SIGNING_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) - endif() + if(NOT signing_script AND CONFIG_BOOTLOADER_MCUBOOT) + set(signing_script ${CMAKE_CURRENT_LIST_DIR}/cmake/mcuboot.cmake) endif() endif() # Include signing script, if set -get_target_property(signing_script zephyr_property_target SIGNING_SCRIPT) if(signing_script) message(STATUS "Including signing script: ${signing_script}") @@ -1881,12 +1904,11 @@ endif() add_custom_command( TARGET ${logical_target_for_zephyr_elf} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Generating files from ${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME} for board: ${BOARD}" ${post_build_commands} BYPRODUCTS ${post_build_byproducts} - COMMENT "Generating files from ${KERNEL_ELF_NAME} for board: ${BOARD}" COMMAND_EXPAND_LISTS - # NB: COMMENT only works for some CMake-Generators ) # To populate with hex files to merge, do the following: diff --git a/CODEOWNERS b/CODEOWNERS index 2c8b9db3961..b561567baa1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -134,6 +134,7 @@ /boards/shields/inventek_eswifi/ @nandojve /boards/xtensa/odroid_go/ @ydamigos /boards/xtensa/nxp_adsp_imx8/ @iuliana-prodan @dbaluta +/boards/xtensa/kincony_kc868_a32/ @bbilas /boards/arm64/qemu_cortex_a53/ @carlocaione /boards/arm64/bcm958402m2_a72/ @abhishek-brcm /boards/arm64/mimx8mm_evk/ @MrVan @JiafeiPan @@ -234,6 +235,7 @@ /drivers/flash/*cc13xx_cc26xx* @pepe2k /drivers/flash/*nrf* @de-nordic /drivers/flash/*esp32* @sylvioalves +/drivers/flash/flash_cadence_nand* @nbalabak /drivers/gpio/*b91* @andy-liu-telink /drivers/gpio/*lmp90xxx* @henrikbrixandersen /drivers/gpio/*nct38xx* @MulinChao @ChiHuaL @@ -364,6 +366,8 @@ /drivers/spi/spi_rv32m1_lpspi* @karstenkoenig /drivers/spi/*esp32* @sylvioalves /drivers/spi/*pl022* @soburi +/drivers/sdhc/ @danieldegrasse +/drivers/sdhc/sdhc_cdns* @roymurlidhar @tanmaykathpalia /drivers/timer/*arm_arch* @carlocaione /drivers/timer/*cortex_m_systick* @anangl /drivers/timer/*altera_avalon* @nashif @@ -399,7 +403,7 @@ /drivers/watchdog/Kconfig.it8xxx2 @RuibinChang /drivers/watchdog/wdt_counter.c @nordic-krch /drivers/watchdog/*rpi_pico* @thedjnK -/drivers/watchdog/*dw* @softwarecki +/drivers/watchdog/*dw* @softwarecki @pbalsundar /drivers/watchdog/*ifx* @sreeramIfx /drivers/wifi/esp_at/ @mniestroj /drivers/wifi/eswifi/ @loicpoulain @nandojve @@ -417,7 +421,7 @@ /dts/arm/atmel/ @galak /dts/arm/broadcom/ @sbranden /dts/arm/cypress/ @ifyall @npal-cy -/dts/arm/gigadevice/ @nandojve +/dts/arm/gd/ @nandojve /dts/arm/infineon/xmc4* @parthitce @ifyall @npal-cy /dts/arm/infineon/psoc6/ @ifyall @npal-cy /dts/arm64/armv8-r.dtsi @povergoing diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 18d668a1332..f81c519c783 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,77 +2,138 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission +* Publishing others' private information, such as a physical or email address, + without their explicit permission * Other conduct which could reasonably be considered inappropriate in a - professional setting + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at conduct@zephyrproject.org. -Reports will be received by Kate Stewart (Linux Foundation) and Amy Occhialino -(Intel). All complaints will be reviewed and investigated, and will result in a -response that is deemed necessary and appropriate to the circumstances. The -project team is obligated to maintain confidentiality with regard to the -reporter of an incident. Further details of specific enforcement policies may -be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +reported to the community leaders responsible for enforcement at +conduct@zephyrproject.org. Reports will be received by the Chair of the Zephyr +Governing Board, the Zephyr Project Director (Linux Foundation), and the Zephyr +Project Developer Advocate (Linux Foundation). You may refer to the [Governing +Board](https://zephyrproject.org/governing-board/) and [Linux Foundation +Staff](https://zephyrproject.org/staff/) web pages to identify who are the +individuals currently holding these positions. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. +The only changes made by The Zephyr Project to the original document were to +make explicit who the recipients of Code of Conduct incident reports are. -[homepage]: https://www.contributor-covenant.org +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/Kconfig.zephyr b/Kconfig.zephyr index c484898206b..829deac2a9c 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -141,6 +141,17 @@ config ROM_START_OFFSET alignment requirements on most ARM targets, although some targets may require smaller or larger values. +config ROM_END_OFFSET + hex "ROM end offset" + default 0 + help + If non-zero, this option reduces the maximum size that the Zephyr image is allowed to + occupy, this is to allow for additional image storage which can be created and used by + other systems such as bootloaders (for MCUboot, this would include the image swap + fields and TLV storage at the end of the image). + + If unsure, leave at the default value 0. + config LD_LINKER_SCRIPT_SUPPORTED bool default y @@ -417,6 +428,13 @@ config NO_OPTIMIZATIONS default stack sizes in order to avoid stack overflows. endchoice +config LTO + bool "Link Time Optimization [EXPERIMENTAL]" + depends on !(GEN_ISR_TABLES || GEN_IRQ_VECTOR_TABLE) || ISR_TABLES_LOCAL_DECLARATION + select EXPERIMENTAL + help + This option enables Link Time Optimization. + config COMPILER_WARNINGS_AS_ERRORS bool "Treat warnings as errors" help @@ -777,7 +795,9 @@ config BUILD_OUTPUT_STRIP_PATHS config CHECK_INIT_PRIORITIES bool "Build time initialization priorities check" default y - depends on !NATIVE_LIBRARY + # If we are building a native_simulator target, we can only check the init priorities + # if we are building the final output but we are not assembling several images together + depends on !(NATIVE_LIBRARY && (!BUILD_OUTPUT_EXE || NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS != "")) depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "armclang" help Check the build for initialization priority issues by comparing the @@ -859,7 +879,7 @@ config IS_BOOTLOADER a separate Zephyr image payload. config BOOTLOADER_SRAM_SIZE - int "SRAM reserved for bootloader" + int "SRAM reserved for bootloader [DEPRECATED]" default 0 depends on !XIP || IS_BOOTLOADER depends on ARM || XTENSA @@ -870,6 +890,20 @@ config BOOTLOADER_SRAM_SIZE - Zephyr is a !XIP image, which implicitly assumes existence of a bootloader that loads the Zephyr !XIP image onto SRAM. + This option is deprecated, users should transition to using DTS to set this, if needed. + To be removed after Zephyr 3.7 release. + +config BOOTLOADER_SRAM_SIZE_DEPRECATED + bool + default y + select DEPRECATED + depends on BOOTLOADER_SRAM_SIZE != 0 + depends on !XIP || IS_BOOTLOADER + depends on ARM || XTENSA + help + Non-prompt symbol to indicate that the deprecated BOOTLOADER_SRAM_SIZE Kconfig has a + non-0 value. Please transition to using devicetree. + config BOOTLOADER_ESP_IDF bool "ESP-IDF bootloader support" depends on SOC_FAMILY_ESP32 && !BOOTLOADER_MCUBOOT && !MCUBOOT diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index a36838cd65d..cf21dd88330 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -125,6 +125,8 @@ ACPI: - tests/lib/acpi/ labels: - "area: ACPI" + tests: + - acpi ARC arch: status: maintained @@ -142,6 +144,8 @@ ARC arch: - doc/hardware/arch/arc-support-status.rst labels: - "area: ARC" + tests: + - arch.arc ARM arch: status: maintained @@ -155,6 +159,7 @@ ARM arch: - bbolen - povergoing - ithinuel + - sgrrzhf files: - arch/arm/ - arch/arm/core/offsets/ @@ -163,8 +168,11 @@ ARM arch: - doc/hardware/arch/arm_cortex_m.rst - boards/arm/qemu_cortex_m3/ - boards/arm/qemu_cortex_m0/ + - soc/arm/* labels: - "area: ARM" + tests: + - arch.arm ARM64 arch: status: maintained @@ -183,6 +191,8 @@ ARM64 arch: - dts/arm64/ labels: - "area: ARM64" + tests: + - arch.arm64 ARM Platforms: status: odd fixes @@ -190,9 +200,20 @@ ARM Platforms: - boards/arm/mps*/ - soc/arm/arm/ - boards/arm/v2m_*/ + - dts/arm/armv*.dtsi labels: - "platform: ARM" +ASPEED Platforms: + status: odd fixes + files: + - soc/arm/aspeed/ + - dts/arm/aspeed/ + - drivers/*/*_ast10x0.c + - drivers/*/Kconfig.aspeed + labels: + - "platform: ASPEED" + ARM SiP SVC: status: odd fixes files: @@ -203,6 +224,8 @@ ARM SiP SVC: - drivers/sip_svc/ labels: - "area: ARM SiP SVC" + tests: + - sip_svc MIPS arch: status: odd fixes @@ -213,6 +236,8 @@ MIPS arch: - boards/mips/ labels: - "area: MIPS" + tests: + - arch.mips Ambiq Platforms: status: maintained @@ -221,15 +246,33 @@ Ambiq Platforms: collaborators: - tgorochowik - msobkowski + - aaronyegx + - RichardSWheatley files: - soc/arm/ambiq/ - boards/arm/apollo*/ - dts/arm/ambiq/ - - dts/bindings/*/ambiq* - - drivers/*/*_ambiq* + - dts/bindings/*/ambiq,* + - drivers/*/*ambiq* + - drivers/*/*/*ambiq* + - drivers/*/*/*apollo* labels: - "platform: Ambiq" +BeagleBoard Platforms: + status: maintained + maintainers: + - jadonk + collaborators: + - ayush1325 + - con-pax + - vaishnavachath + files: + - boards/arm/beagle*/ + - boards/riscv/beagle*/ + labels: + - "platform: BeagleBoard" + Benchmarks: status: maintained maintainers: @@ -254,6 +297,8 @@ Binary Descriptors: - tests/subsys/bindesc/ labels: - "area: Binary Descriptors" + tests: + - bindesc Bluetooth: status: maintained @@ -268,7 +313,6 @@ Bluetooth: files: - doc/connectivity/bluetooth/ - include/zephyr/bluetooth/ - - include/zephyr/drivers/bluetooth/ - samples/bluetooth/ - subsys/bluetooth/ - subsys/bluetooth/common/ @@ -294,6 +338,30 @@ Bluetooth: - tests/bluetooth/shell/audio* labels: - "area: Bluetooth" + tests: + - bluetooth + +Bluetooth HCI: + status: maintained + maintainers: + - jhedberg + - jori-nordic + collaborators: + - hermabe + - alwa-nordic + - Thalley + - sjanc + - theob-pro + - HoZHel + files: + - include/zephyr/drivers/bluetooth/ + - drivers/bluetooth/ + - samples/bluetooth/hci_*/ + labels: + - "area: Bluetooth Host" + - "area: Bluetooth" + tests: + - bluetooth Bluetooth controller: status: maintained @@ -314,23 +382,21 @@ Bluetooth controller: labels: - "area: Bluetooth Controller" - "area: Bluetooth" + tests: + - bluetooth.controller Bluetooth Host: status: maintained maintainers: + - jori-nordic - jhedberg collaborators: - hermabe - - jori-nordic - alwa-nordic - - Vudentz - Thalley - - asbjornsabo - sjanc - theob-pro - - kruithofa files: - - drivers/bluetooth/ - subsys/bluetooth/host/ - subsys/bluetooth/services/ - subsys/bluetooth/shell/ @@ -350,6 +416,7 @@ Bluetooth Mesh: - alxelax - Andrewpini - akredalen + - HaavardRei files: - subsys/bluetooth/mesh/ - include/zephyr/bluetooth/mesh/ @@ -359,6 +426,8 @@ Bluetooth Mesh: labels: - "area: Bluetooth Mesh" - "area: Bluetooth" + tests: + - bluetooth.mesh Bluetooth Audio: status: maintained @@ -374,6 +443,7 @@ Bluetooth Audio: - fredrikdanebjer - kruithofa - larsgk + - pin-zephyr files: - subsys/bluetooth/audio/ - include/zephyr/bluetooth/audio/ @@ -383,6 +453,39 @@ Bluetooth Audio: labels: - "area: Bluetooth Audio" - "area: Bluetooth" + tests: + - bluetooth.audio + +Bluetooth Classic: + status: maintained + maintainers: + - lylezhu2012 + collaborators: + - jhedberg + - sjanc + files: + - subsys/bluetooth/host/a2dp* + - subsys/bluetooth/host/at.* + - subsys/bluetooth/host/avdtp* + - subsys/bluetooth/host/br.* + - subsys/bluetooth/host/hfp* + - subsys/bluetooth/host/l2cap_br* + - subsys/bluetooth/host/rfcomm* + - subsys/bluetooth/host/sdp* + - subsys/bluetooth/host/ssp* + labels: + - "area: Bluetooth Classic" + tests: + - bluetooth + +Bootloaders: + status: odd fixes + files: + - tests/boot/ + labels: + - "area: Bootloader" + tests: + - bootloader Build system: status: maintained @@ -402,8 +505,14 @@ Build system: - doc/develop/modules.rst - scripts/build/ - tests/cmake/ + - misc/empty_file.c + - misc/generated/ + - snippets/ + - modules/Kconfig.sysbuild labels: - "area: Build System" + tests: + - buildsystem Board/SoC configuration: status: maintained @@ -433,6 +542,8 @@ Board/SoC configuration: - samples/cpp/ labels: - "area: C++" + tests: + - cpp Cache: status: maintained @@ -445,8 +556,11 @@ Cache: - include/zephyr/cache.h - doc/hardware/cache/index.rst - drivers/cache/ + - tests/kernel/cache/ labels: - "area: Cache" + tests: + - kernel.cache C library: status: maintained @@ -462,6 +576,8 @@ C library: - tests/lib/newlib/ labels: - "area: C Library" + tests: + - libraries.libc CMSIS API layer: status: odd fixes @@ -472,10 +588,13 @@ CMSIS API layer: - include/zephyr/portability/cmsis* - samples/subsys/portability/cmsis_rtos_v*/ - tests/subsys/portability/cmsis_rtos_v*/ - - doc/services/portability/ + - doc/services/portability/cmsis* labels: - "area: CMSIS API Layer" - "area: Portability" + tests: + - portability.cmsis_rtos_v1 + - portability.cmsis_rtos_v2 DSP subsystem: status: maintained @@ -491,6 +610,8 @@ DSP subsystem: - doc/services/dsp/ labels: - "area: DSP" + tests: + - zdsp CMSIS-DSP integration: status: maintained @@ -505,6 +626,8 @@ CMSIS-DSP integration: - tests/lib/cmsis_dsp/ labels: - "area: CMSIS-DSP" + tests: + - libraries.cmsis_dsp CMSIS-NN integration: status: maintained @@ -518,6 +641,8 @@ CMSIS-NN integration: - tests/lib/cmsis_nn/ labels: - "area: CMSIS-NN" + tests: + - libraries.cmsis_nn Coding Guidelines: status: maintained @@ -554,6 +679,7 @@ Common Architecture Interface: - dcpleung - nashif files: + - arch/Kconfig - include/zephyr/arch/ - arch/common/ - include/zephyr/arch/common/ @@ -561,6 +687,8 @@ Common Architecture Interface: - doc/hardware/porting/arch.rst labels: - "area: Architectures" + tests: + - arch Console: status: odd fixes @@ -569,6 +697,8 @@ Console: - subsys/console/ labels: - "area: Console" + tests: + - sample.console Debug: status: maintained @@ -586,6 +716,8 @@ Debug: - doc/services/debugging/ labels: - "area: Debugging" + tests: + - debug Demand Paging: status: maintained @@ -597,6 +729,9 @@ Demand Paging: - nashif files: - subsys/demand_paging/ + - tests/kernel/mem_protect/demand_paging/ + tests: + - kernel.demand_paging Device Driver Model: status: maintained @@ -612,8 +747,11 @@ Device Driver Model: - include/zephyr/init.h - tests/kernel/device/ - doc/kernel/drivers/ + - tests/misc/check_init_priorities/ labels: - "area: Device Model" + tests: + - kernel.device DFU: status: maintained @@ -626,11 +764,12 @@ DFU: - tests/subsys/dfu/ labels: - "area: DFU" + tests: + - dfu Devicetree: status: maintained maintainers: - - mbolivar-ampere - galak files: - scripts/dts/ @@ -642,6 +781,8 @@ Devicetree: - include/zephyr/devicetree.h labels: - "area: Devicetree" + tests: + - libraries.devicetree Devicetree Bindings: status: maintained @@ -650,6 +791,7 @@ Devicetree Bindings: files: - dts/bindings/ - include/zephyr/dt-bindings/ + - dts/binding-template.yaml labels: - "area: Devicetree Binding" @@ -671,11 +813,14 @@ Disk: - include/zephyr/sd/ labels: - "area: Disk Access" + tests: + - drivers.disk Display drivers: status: odd fixes collaborators: - jfischer-no + - danieldegrasse files: - drivers/display/ - dts/bindings/display/ @@ -685,6 +830,7 @@ Display drivers: - subsys/fb/ - samples/subsys/display/ - doc/hardware/peripherals/display/ + - tests/drivers/*/display/ labels: - "area: Display" @@ -696,6 +842,9 @@ Documentation: collaborators: - nashif files: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.rst + - doc/glossary.rst - doc/contribute/ - doc/develop/ - doc/introduction/ @@ -710,6 +859,7 @@ Documentation: - doc/known-warnings.txt - doc/templates/sample.tmpl - doc/templates/board.tmpl + - boards/index.rst files-exclude: - doc/releases/migration-guide-* - doc/releases/release-notes-* @@ -761,6 +911,8 @@ Release Notes: - include/zephyr/dt-bindings/adc/ labels: - "area: ADC" + tests: + - drivers.adc "Drivers: Audio": status: odd fixes @@ -787,6 +939,8 @@ Release Notes: - doc/hardware/peripherals/bbram.rst labels: - "area: Battery Backed RAM (bbram)" + tests: + - drivers.bbram "Drivers: Aux display": status: maintained @@ -801,6 +955,8 @@ Release Notes: - doc/hardware/peripherals/auxdisplay.rst labels: - "area: Aux display" + tests: + - sample.drivers.auxdisplay "Drivers: CAN": status: maintained @@ -838,20 +994,27 @@ Release Notes: - tests/subsys/canbus/ labels: - "area: CAN" + tests: + - drivers.can + - canbus "Drivers: Charger": status: maintained maintainers: - - aaronemassey - rriveramcrus + collaborators: + - GRobertZieba files: - drivers/charger/ - dts/bindings/charger/ - include/zephyr/drivers/charger.h - tests/drivers/charger/ - doc/hardware/peripherals/charger.rst + - tests/drivers/build_all/charger/ labels: - "area: Charger" + tests: + - drivers.charger "Drivers: Clock control": status: maintained @@ -867,6 +1030,8 @@ Release Notes: - doc/hardware/peripherals/clock_control.rst labels: - "area: Clock control" + tests: + - drivers.clock "Drivers: Console": status: odd fixes @@ -877,6 +1042,8 @@ Release Notes: - samples/subsys/console/ labels: - "area: Console" + tests: + - drivers.console "Drivers: Coredump": status: maintained @@ -890,6 +1057,8 @@ Release Notes: - doc/hardware/peripherals/coredump.rst labels: - "area: Coredump" + tests: + - debug.codedump "Drivers: Counter": status: maintained @@ -904,6 +1073,8 @@ Release Notes: - tests/drivers/build_all/counter/ labels: - "area: Counter" + tests: + - drivers.counter "Drivers: Crypto": status: maintained @@ -917,6 +1088,8 @@ Release Notes: - tests/crypto/ labels: - "area: Crypto / RNG" + tests: + - crypto "Drivers: DAC": status: maintained @@ -931,6 +1104,8 @@ Release Notes: - tests/drivers/build_all/dac/ labels: - "area: DAC" + tests: + - drivers.dac "Drivers: DAI": status: maintained @@ -946,6 +1121,19 @@ Release Notes: labels: - "area: DAI" +"Drivers: Devmux": + status: maintained + maintainers: + - cfriedt + files: + - drivers/misc/devmux/ + - include/zephyr/drivers/misc/devmux/ + - tests/drivers/console_switching/ + labels: + - "area: Devmux" + tests: + - drivers.devmux + "Drivers: DMA": status: maintained maintainers: @@ -959,6 +1147,8 @@ Release Notes: - include/zephyr/dt-bindings/dma/ labels: - "area: DMA" + tests: + - drivers.dma "Drivers: EDAC": status: maintained @@ -973,6 +1163,8 @@ Release Notes: - doc/hardware/peripherals/edac/ labels: - "area: EDAC" + tests: + - edac "Drivers: EEPROM": status: maintained @@ -980,13 +1172,17 @@ Release Notes: - henrikbrixandersen files: - drivers/eeprom/ + - include/zephyr/drivers/eeprom/eeprom_fake.h - dts/bindings/mtd/*eeprom* - include/zephyr/drivers/eeprom.h - samples/drivers/eeprom/ - tests/drivers/eeprom/ + - tests/drivers/*/eeprom/ - doc/hardware/peripherals/eeprom.rst labels: - "area: EEPROM" + tests: + - drivers.eeprom "Drivers: Entropy": status: maintained @@ -999,6 +1195,8 @@ Release Notes: - doc/hardware/peripherals/entropy.rst labels: - "area: Crypto / RNG" + tests: + - drivers.entropy "Drivers: ESPI": status: maintained @@ -1015,19 +1213,28 @@ Release Notes: - dts/bindings/espi/ - doc/hardware/peripherals/espi.rst - include/zephyr/drivers/espi_saf.h + - tests/drivers/espi/ labels: - "area: eSPI" + tests: + - sample.drivers.espi + - drivers.espi "Drivers: Ethernet": status: odd fixes + collaborators: + - decsny files: - drivers/ethernet/ - include/zephyr/dt-bindings/ethernet/ - tests/drivers/build_all/ethernet/ - dts/bindings/ethernet/ - tests/drivers/ethernet/ + - include/zephyr/drivers/ethernet/ labels: - "area: Ethernet" + tests: + - net.ethernet "Drivers: Flash": status: maintained @@ -1041,8 +1248,12 @@ Release Notes: - samples/drivers/soc_flash_nrf/ - tests/drivers/flash/ - doc/hardware/peripherals/flash.rst + - include/zephyr/drivers/flash/ + - tests/drivers/flash_simulator/ labels: - "area: Flash" + tests: + - drivers.flash "Drivers: FPGA": status: maintained @@ -1060,6 +1271,8 @@ Release Notes: - tests/drivers/build_all/fpga/ labels: - "area: FPGA" + tests: + - drivers.fpga "Drivers: Fuel Gauge": status: maintained @@ -1074,6 +1287,8 @@ Release Notes: - doc/hardware/peripherals/fuel_gauge.rst labels: - "area: Fuel Gauge" + tests: + - drivers.fuel_gauge "Drivers: GPIO": status: odd fixes @@ -1090,6 +1305,8 @@ Release Notes: - tests/drivers/build_all/gpio/ labels: - "area: GPIO" + tests: + - drivers.gpio "Drivers: GNSS": status: maintained @@ -1099,9 +1316,13 @@ Release Notes: - doc/hardware/peripherals/gnss.rst - drivers/gnss/ - include/zephyr/drivers/gnss.h + - include/zephyr/drivers/gnss/ + - tests/drivers/build_all/gnss/ - tests/drivers/gnss/ labels: - "area: GNSS" + tests: + - drivers.gnss "Drivers: HW Info": status: maintained @@ -1115,6 +1336,17 @@ Release Notes: - doc/hardware/peripherals/hwinfo.rst labels: - "area: HWINFO" + tests: + - drivers.hwinfo + +"Drivers: Hardware Spinlock": + status: odd fixes + files: + - drivers/hwspinlock/ + - dts/bindings/hwspinlock/ + - include/zephyr/drivers/hwspinlock.h + labels: + - "area: Hardware Spinlock" "Drivers: I2C": status: maintained @@ -1128,9 +1360,12 @@ Release Notes: - tests/drivers/i2c/ - doc/hardware/peripherals/i2c.rst - include/zephyr/dt-bindings/i2c/ - - tests/boards/frdm_k64f/i2c/ + - tests/boards/*/i2c/ + - tests/drivers/*/i2c/ labels: - "area: I2C" + tests: + - drivers.i2c "Drivers: I2S": status: maintained @@ -1145,6 +1380,8 @@ Release Notes: - samples/drivers/i2s/ labels: - "area: I2S" + tests: + - drivers.i2s "Drivers: I3C": status: maintained @@ -1161,6 +1398,8 @@ Release Notes: - tests/drivers/build_all/i3c/ labels: - "area: I3C" + tests: + - drivers.i3c "Drivers: IEEE 802.15.4": status: maintained @@ -1173,19 +1412,92 @@ Release Notes: - jukkar files: - drivers/ieee802154/ + - include/zephyr/drivers/ieee802154/ - include/zephyr/net/ieee802154_radio.h + - tests/drivers/build_all/ieee802154/ labels: - "area: IEEE 802.15.4" + tests: + - drivers.ieee802154 + +"Drivers: Mbox": + status: maintained + maintainers: + - carlocaione + files: + - include/zephyr/drivers/mbox.h + - drivers/mbox/ + - samples/drivers/mbox/ + - dts/bindings/mbox/ + - doc/hardware/peripherals/mbox.rst + labels: + - "area: mbox" + tests: + - sample.drivers.mbox + +"Drivers: MEMC": + status: odd fixes + files: + - drivers/memc/ + - samples/drivers/memc/ + - tests/drivers/memc/ + labels: + - "area: MEMC" + tests: + - samples.drivers.memc + - drivers.memc -"Drivers: Interrupt controllers": +"Drivers: MDIO": + status: odd fixes + collaborators: + - decsny + files: + - doc/hardware/peripherals/mdio.rst + - drivers/mdio/ + - include/zephyr/drivers/mdio.h + - tests/drivers/build_all/mdio/ + labels: + - "area: MDIO" + tests: + - drivers.mdio + +"Drivers: MIPI-DSI": + status: odd fixes + files: + - drivers/mipi_dsi/ + - doc/hardware/peripherals/mipi_dsi.rst + - include/zephyr/drivers/mipi_dsi.h + - include/zephyr/drivers/mipi_dsi/ + - tests/drivers/mipi_dsi/ + - include/zephyr/dt-bindings/mipi_dsi/ + - dts/bindings/mipi-dsi/ + labels: + - "area: MIPI-DSI" + tests: + - drivers.mipi_dsi + +"Drivers: Reset": + status: odd fixes + files: + - drivers/reset/ + - include/zephyr/drivers/reset.h + +"Interrupt Handling": status: odd fixes files: - drivers/interrupt_controller/ - dts/bindings/interrupt-controller/ - include/zephyr/drivers/interrupt_controller/ - include/zephyr/dt-bindings/interrupt-controller/ + - include/zephyr/irq* + - include/zephyr/sw_isr_table.h + - include/zephyr/shared_irq.h + - tests/drivers/interrupt_controller/ + - tests/drivers/build_all/interrupt_controller/ labels: - "area: Interrupt Controller" + tests: + - drivers.interrupt_controller "Drivers: IPM": status: odd fixes @@ -1202,6 +1514,8 @@ Release Notes: Inter-processor mailboxes labels: - "area: IPM" + tests: + - drivers.ipm "Drivers: kscan": status: maintained @@ -1212,14 +1526,14 @@ Release Notes: files: - drivers/kscan/ - include/zephyr/drivers/kscan.h - - samples/drivers/espi/ - samples/drivers/kscan/ - tests/drivers/kscan/ - - tests/drivers/espi/ - dts/bindings/kscan/ - doc/hardware/peripherals/kscan.rst labels: - "area: Kscan" + tests: + - drivers.kscan "Drivers: LED": status: maintained @@ -1235,8 +1549,11 @@ Release Notes: - samples/drivers/led_*/ - tests/drivers/led/ - doc/hardware/peripherals/led.rst + - tests/drivers/build_all/led/ labels: - "area: LED" + tests: + - drivers.led "Drivers: LED Strip": status: maintained @@ -1248,8 +1565,11 @@ Release Notes: - dts/bindings/led_strip/ - include/zephyr/drivers/led_strip.h - tests/drivers/build_all/led_strip/ + - include/zephyr/drivers/led_strip/ labels: - "area: LED" + tests: + - drivers.led_strip "Drivers: MFD": status: odd fixes @@ -1263,6 +1583,8 @@ Release Notes: - tests/drivers/build_all/mfd/ labels: - "area: MFD" + tests: + - drivers.mfd "Drivers: Modem": status: maintained @@ -1275,6 +1597,8 @@ Release Notes: - include/zephyr/drivers/modem/ labels: - "area: Modem Drivers" + tests: + - drivers.modem "Drivers: Regulators": status: maintained @@ -1293,6 +1617,8 @@ Release Notes: - doc/hardware/peripherals/regulators.rst labels: - "area: Regulators" + tests: + - drivers.regulator "Drivers: Retained Memory": status: maintained @@ -1306,6 +1632,8 @@ Release Notes: - doc/hardware/peripherals/retained_mem.rst labels: - "area: Retained Memory" + tests: + - drivers.retained_mem "Drivers: RTC": status: maintained @@ -1317,8 +1645,11 @@ Release Notes: - tests/drivers/rtc/ - doc/hardware/peripherals/rtc.rst - include/zephyr/drivers/rtc.h + - tests/drivers/build_all/rtc/ labels: - "area: RTC" + tests: + - drivers.rtc "Drivers: PCI": status: maintained @@ -1348,6 +1679,8 @@ Release Notes: - doc/hardware/peripherals/peci.rst labels: - "area: PECI" + tests: + - samples.drivers.peci "Drivers: Pin Control": status: maintained @@ -1363,6 +1696,21 @@ Release Notes: - include/zephyr/dt-bindings/pinctrl/ labels: - "area: Pinctrl" + tests: + - drivers.pinctrl + +"Drivers: PS2": + status: odd fixes + files: + - drivers/ps2/ + - doc/hardware/peripherals/ps2.rst + - include/zephyr/drivers/ps2.h + - samples/drivers/ps2/ + - dts/bindings/ps2/ + labels: + - "area: PS2" + tests: + - sample.drivers.espi.ps2 "Drivers: PTP Clock": status: maintained @@ -1403,8 +1751,11 @@ Release Notes: - doc/hardware/peripherals/pwm.rst - tests/drivers/build_all/pwm/ - include/zephyr/drivers/pwm.h + - include/zephyr/drivers/pwm/ labels: - "area: PWM" + tests: + - drivers.pwm "Drivers: SDHC": status: maintained @@ -1418,6 +1769,8 @@ Release Notes: - doc/hardware/peripherals/sdhc.rst labels: - "area: Disk Access" + tests: + - drivers.sdhc "Drivers: Serial/UART": status: maintained @@ -1432,8 +1785,12 @@ Release Notes: - tests/drivers/uart/ - tests/drivers/build_all/uart/ - doc/hardware/peripherals/uart.rst + - include/zephyr/drivers/serial/ + - include/zephyr/drivers/uart_pipe.h labels: - "area: UART" + tests: + - drivers.uart "Drivers: Sensors": status: maintained @@ -1457,6 +1814,8 @@ Release Notes: - tests/drivers/build_all/sensor/ labels: - "area: Sensors" + tests: + - drivers.sensors "Drivers: SMBus": status: maintained @@ -1471,6 +1830,8 @@ Release Notes: - doc/hardware/peripherals/smbus.rst labels: - "area: SMBus" + tests: + - drivers.smbus "Drivers: SPI": status: maintained @@ -1485,6 +1846,8 @@ Release Notes: - doc/hardware/peripherals/spi.rst labels: - "area: SPI" + tests: + - drivers.spi "Drivers: System timer": status: maintained @@ -1507,8 +1870,11 @@ Release Notes: - include/zephyr/drivers/video.h - include/zephyr/drivers/video-controls.h - doc/hardware/peripherals/video.rst + - tests/drivers/*/video/ labels: - "area: Video" + tests: + - drivers.video "Drivers: W1": status: maintained @@ -1526,6 +1892,8 @@ Release Notes: - samples/drivers/w1/ labels: - "area: W1" + tests: + - drivers.w1 "Drivers: Watchdog": status: odd fixes @@ -1539,8 +1907,11 @@ Release Notes: - include/zephyr/drivers/watchdog.h - samples/drivers/watchdog/ - tests/drivers/watchdog/ + - tests/drivers/build_all/watchdog/ labels: - "area: Watchdog" + tests: + - drivers.watchdog "Drivers: Wi-Fi": status: maintained @@ -1583,6 +1954,16 @@ Release Notes: labels: - "area: Memory Management" +"Drivers: MIPI DBI": + status: maintained + maintainers: + - danieldegrasse + files: + - drivers/mipi_dbi/ + - dts/bindings/mipi-dbi/ + labels: + - "area: Display Controller" + "Drivers: Virtualization": status: maintained maintainers: @@ -1596,17 +1977,21 @@ Release Notes: - include/zephyr/drivers/virtualization/ivshmem.h labels: - "area: Virtualization" + tests: + - drivers.virtualization EC Host Commands: status: maintained maintainers: - - semihalf-niedzwiecki-dawid + - niedzwiecki-dawid files: - subsys/mgmt/ec_host_cmd/ - include/zephyr/mgmt/ec_host_cmd/ - tests/subsys/mgmt/ec_host_cmd/ labels: - "area: ec_host_cmd" + tests: + - mgmt.ec_host_cmd Xen Platform: status: maintained @@ -1640,6 +2025,8 @@ Filesystems: - tests/subsys/fs/ labels: - "area: File System" + tests: + - filesystem "Filesystems: FatFs reentrant support": status: maintained @@ -1650,6 +2037,8 @@ Filesystems: - tests/subsys/fs/fat_fs_api/src/test_fat_file_reentrant.c labels: - "area: File System" + tests: + - filesystem.fat Formatted Output: status: maintained @@ -1666,6 +2055,9 @@ Formatted Output: - doc/services/formatted_output.rst labels: - "area: Formatting Output" + tests: + - utilities.prf + - libraries.cbprintf Google Platforms: status: maintained @@ -1689,6 +2081,9 @@ Hash Utilities: Hash Functions and Hash Maps (Hash Tables) labels: - "area: hash utils" + tests: + - libraries.hash_function + - libraries.hash_map Input: status: maintained @@ -1711,6 +2106,9 @@ Input: Input subsystem and drivers labels: - "area: Input" + tests: + - drivers.input + - input IPC: status: maintained @@ -1722,10 +2120,13 @@ IPC: - samples/subsys/ipc/ - subsys/ipc/ - tests/subsys/ipc/ + - doc/services/ipc/ description: >- Inter-Processor Communication labels: - "area: IPC" + tests: + - ipc JSON Web Token: status: maintained @@ -1737,11 +2138,14 @@ JSON Web Token: files: - subsys/jwt/ - include/zephyr/data/ - - lib/os/json.c + - lib/utils/json.c - tests/subsys/jwt/ - tests/lib/json/ labels: - "area: JSON" + tests: + - libraries.encoding.json + - libraries.encoding.jwt Kconfig: status: odd fixes @@ -1759,6 +2163,8 @@ Kconfig: description: >- See https://docs.zephyrproject.org/latest/build/kconfig/index.html and https://docs.zephyrproject.org/latest/hardware/porting/board_porting.html#default-board-configuration + tests: + - kconfig Kernel: status: maintained @@ -1774,6 +2180,8 @@ Kernel: files: - doc/kernel/ - include/zephyr/kernel*.h + - include/zephyr/spinlock.h + - include/zephyr/fatal.h - kernel/ - tests/kernel/ - include/zephyr/sys_clock.h @@ -1784,6 +2192,43 @@ Kernel: - tests/kernel/mem_protect/ labels: - "area: Kernel" + tests: + - kernel + +Utilities: + status: maintained + maintainers: + - andyross + - nashif + collaborators: + - dcpleung + - peter-mitsis + files: + - lib/crc/ + - lib/utils/ + - tests/unit/timeutil/ + - tests/unit/time_units/ + - tests/unit/rbtree/ + - tests/unit/math_extras/ + - tests/unit/crc/ + - tests/unit/base64/ + - tests/unit/math_extras/ + - tests/unit/list/ + - tests/unit/intmath/ + - tests/unit/pot/ + - tests/lib/time/ + - tests/lib/onoff/ + - tests/lib/sys_util/ + - tests/lib/sprintf/ + - tests/lib/ringbuffer/ + - tests/lib/notify/ + - tests/lib/linear_range/ + labels: + - "area: Utilities" + tests: + - utilities + - libraries.ring_buffer + - libraries.linear_range Base OS: status: maintained @@ -1796,6 +2241,9 @@ Base OS: files: - include/zephyr/sys/ - lib/os/ + - tests/misc/print_format/ + - tests/lib/p4workq/ + - tests/lib/fdtable/ files-exclude: - include/zephyr/sys/cbprintf* - tests/unit/cbprintf/ @@ -1808,6 +2256,38 @@ Base OS: - lib/os/mpsc_pbuf.c labels: - "area: Base OS" + tests: + - printk + +Heap Management: + status: maintained + maintainers: + - npitre + - andyross + files: + - tests/lib/shared_multi_heap/ + - lib/heap/ + - tests/lib/heap/ + - tests/lib/heap_align/ + - tests/lib/multi_heap/ + - include/zephyr/multi_heap/ + +Memory Management: + status: maintained + maintainers: + - carlocaione + - dcpleung + files: + - subsys/mem_mgmt/ + - lib/mem_blocks/ + - tests/subsys/mem_mgmt/ + - include/zephyr/mem_mgmt/mem_attr_heap.h + - tests/lib/mem_alloc/ + - tests/lib/mem_blocks/ + - doc/services/mem_mgmt/ + - include/zephyr/mem_mgmt/mem_attr.h + - tests/lib/mem_blocks_stats/ + - tests/drivers/mm/ Laird Connectivity platforms: status: maintained @@ -1825,6 +2305,19 @@ Laird Connectivity platforms: labels: - "platform: Laird Connectivity" +Linker Scripts: + status: maintained + maintainers: + - nashif + files: + - include/zephyr/linker/ + - tests/misc/iterable_sections/ + - tests/application_development/code_relocation/ + labels: + - "area: Linker Scripts" + tests: + - linker + Little FS: status: odd fixes files: @@ -1835,6 +2328,8 @@ Little FS: Little FS labels: - "area: File System" + tests: + - filesystem.littlefs Logging: status: maintained @@ -1857,6 +2352,8 @@ Logging: - tests/lib/spsc_pbuf/ labels: - "area: Logging" + tests: + - logging LoRa and LoRaWAN: status: maintained @@ -1876,6 +2373,8 @@ LoRa and LoRaWAN: - doc/connectivity/lora_lorawan/index.rst labels: - "area: LoRa" + tests: + - sample.driver.lora MAINTAINERS file: status: maintained @@ -1904,6 +2403,9 @@ Mbed TLS: - "area: Crypto / RNG" description: >- Mbed TLS module implementing the PSA Crypto API and TLS. + tests: + - benchmark.crypto.mbedtls + - crypto.mbedtls MCU Manager: status: maintained @@ -1917,8 +2419,11 @@ MCU Manager: - samples/subsys/mgmt/mcumgr/ - tests/subsys/mgmt/mcumgr/ - doc/services/device_mgmt/ + - scripts/utils/migrate_mcumgr_kconfigs.py labels: - "area: mcumgr" + tests: + - mgmt.mcumgr Modbus: status: maintained @@ -1932,8 +2437,10 @@ Modbus: - doc/services/modbus/ labels: - "area: modbus" + tests: + - modbus -Modem Modules: +Modem: status: maintained maintainers: - bjarki-trackunit @@ -1943,8 +2450,11 @@ Modem Modules: - tests/subsys/modem/ - doc/services/modem/ - samples/net/cellular_modem/ + - include/zephyr/drivers/cellular.h labels: - "area: Modem" + tests: + - modem OSDP: status: maintained @@ -1959,6 +2469,8 @@ OSDP: - samples/subsys/mgmt/osdp/ labels: - "area: OSDP" + tests: + - sample.mgmt.osdp hawkBit: status: odd fixes @@ -1970,6 +2482,8 @@ hawkBit: - samples/subsys/mgmt/hawkbit/ labels: - "area: hawkBit" + tests: + - sample.net.hawkbit "mgmt: updatehub": status: maintained @@ -1977,11 +2491,14 @@ hawkBit: - nandojve files: - subsys/mgmt/updatehub/ + - include/zephyr/mgmt/updatehub.h - samples/subsys/mgmt/updatehub/ labels: - "area: updatehub" description: >- UpdateHub embedded Firmware Over-The-Air (FOTA) upgrade agent + tests: + - sample.net.updatehub Native POSIX/Sim and POSIX arch: status: maintained @@ -2002,11 +2519,13 @@ Native POSIX/Sim and POSIX arch: - scripts/native_simulator/ - scripts/valgrind.supp - soc/posix/ - - tests/boards/native_posix/ + - tests/boards/native_sim/ labels: - "area: native port" description: >- POSIX architecture and SOC, native_posix & native_sim boards, and related drivers + tests: + - boards.native_sim Networking: status: maintained @@ -2017,12 +2536,14 @@ Networking: - tbursztyka - ssharks files: + - scripts/net/ - drivers/net/ - include/zephyr/net/ - samples/net/ - subsys/net/ - doc/connectivity/networking/ - tests/net/ + - tests/unit/net_timeout/ files-exclude: - doc/connectivity/networking/api/gptp.rst - doc/connectivity/networking/api/ieee802154.rst @@ -2047,6 +2568,8 @@ Networking: - tests/net/wifi/ labels: - "area: Networking" + tests: + - net "Networking: BSD sockets": status: odd fixes @@ -2059,6 +2582,8 @@ Networking: - tests/net/socket/ labels: - "area: Sockets" + tests: + - net.socket "Networking: Buffers": status: maintained @@ -2074,6 +2599,8 @@ Networking: - tests/net/buf/ labels: - "area: Networking Buffers" + tests: + - net.buf "Networking: Connection Manager": status: maintained @@ -2090,6 +2617,8 @@ Networking: - doc/connectivity/networking/conn_mgr/ labels: - "area: Networking" + tests: + - net.conn_mgr "Networking: CoAP": status: maintained @@ -2103,6 +2632,8 @@ Networking: - tests/net/lib/coap/ labels: - "area: Networking" + tests: + - net.coap "Networking: gPTP": status: maintained @@ -2117,6 +2648,8 @@ Networking: - subsys/net/l2/ethernet/gptp/ labels: - "area: Networking" + tests: + - sample.net.gptp "Networking: LWM2M": status: maintained @@ -2130,6 +2663,8 @@ Networking: - subsys/net/lib/lwm2m/ labels: - "area: LWM2M" + tests: + - net.lwm2m "Networking: MQTT": status: maintained @@ -2144,6 +2679,8 @@ Networking: - tests/net/lib/mqtt_sn*/ labels: - "area: Networking" + tests: + - net.mqtt "Networking: MQTT-SN": status: maintained @@ -2157,6 +2694,8 @@ Networking: - samples/net/mqtt_sn_publisher/ labels: - "area: Networking" + tests: + - net.mqtt_sn "Networking: Native IEEE 802.15.4": status: maintained @@ -2173,6 +2712,8 @@ Networking: - tests/net/ieee802154/ labels: - "area: IEEE 802.15.4" + tests: + - net.ieee802154 "Networking: OpenThread": status: maintained @@ -2183,6 +2724,7 @@ Networking: - canisLupus1313 - mariuszpos - edmont + - maciejbaczmanski files: - subsys/net/l2/openthread/ - samples/net/openthread/ @@ -2190,6 +2732,8 @@ Networking: labels: - "area: Networking" - "area: OpenThread" + tests: + - openthread "Networking: Wi-Fi": status: maintained @@ -2207,6 +2751,8 @@ Networking: labels: - "area: Networking" - "area: Wi-Fi" + tests: + - net.wifi NIOS-2 arch: status: maintained @@ -2214,14 +2760,18 @@ NIOS-2 arch: - nashif files: - arch/nios2/ + - dts/nios2/intel/ - boards/common/nios2.board.cmake - boards/nios2/ - soc/nios2/ - include/zephyr/arch/nios2/ - tests/boards/altera_max10/ - boards/nios2/qemu_nios2/ + - scripts/support/quartus-flash.py labels: - "area: NIOS2" + tests: + - boards.altera_max10 nRF BSIM: status: maintained @@ -2235,19 +2785,35 @@ nRF BSIM: - tests/bsim/*/ labels: - "platform: nRF BSIM" + tests: + - boards.nrf52_bsim + +Open AMP: + status: maintained + maintainers: + - carlocaione + files: + - lib/open-amp/ + POSIX API layer: status: maintained maintainers: - cfriedt + collaborators: + - ycsin files: - include/zephyr/posix/ - lib/posix/ - tests/posix/ - samples/posix/ - tests/lib/fdtable/ + - doc/services/portability/posix/ labels: - "area: POSIX" + tests: + - libraries.fdtable + - portability.posix Power management: status: maintained @@ -2267,6 +2833,16 @@ Power management: - drivers/power_domain/ labels: - "area: Power Management" + tests: + - pm + +"Quicklogic Platform": + status: odd fixes + files: + - soc/arm/quicklogic_eos_s3/ + - dts/arm/quicklogic/ + labels: + - "platform: Quicklogic" RISCV arch: status: maintained @@ -2292,6 +2868,8 @@ RISCV arch: - drivers/interrupt_controller/intc_plic.c labels: - "area: RISCV" + tests: + - arch.riscv Retention: status: maintained @@ -2333,6 +2911,8 @@ Sensor Subsystem: - samples/subsys/sensing/ labels: - "area: Sensor Subsystem" + tests: + - sample.sensing Stats: status: odd fixes @@ -2363,6 +2943,8 @@ Twister: - scripts/pylib/pytest-twister-harness/ - doc/develop/test/pytest.rst - tests/test_config.yaml + - scripts/utils/twister_to_list.py + - tests/robot/common.robot labels: - "area: Twister" @@ -2376,6 +2958,8 @@ Settings: - doc/services/settings/ labels: - "area: Settings" + tests: + - settings Shell: status: maintained @@ -2391,6 +2975,8 @@ Shell: - doc/services/shell/ labels: - "area: Shell" + tests: + - shell Shields: status: maintained @@ -2406,6 +2992,8 @@ Shields: - samples/shields/ labels: - "area: Shields" + tests: + - sample.shields SPARC arch: status: odd fixes @@ -2433,6 +3021,8 @@ State machine framework: - tests/lib/smf/ labels: - "area: State Machine Framework" + tests: + - libraries.smf ADI Platforms: status: maintained @@ -2442,6 +3032,7 @@ ADI Platforms: - galak - microbuilder files: + - boards/arm/adi_*/ - drivers/*/max* - drivers/*/*max*/ - drivers/dac/dac_ltc* @@ -2456,6 +3047,13 @@ ADI Platforms: labels: - "platform: ADI" +Broadcom Platforms: + status: odd fixes + files: + - dts/arm/broadcom/ + - soc/arm/bcm_vk/ + - boards/arm/bcm95840*/ + GD32 Platforms: status: maintained maintainers: @@ -2469,10 +3067,9 @@ GD32 Platforms: - boards/riscv/gd32*/ - boards/riscv/longan_nano/ - drivers/*/*gd32* - - dts/*/gigadevice/ + - dts/*/gd/ - dts/bindings/*/*gd32* - - soc/arm/gigadevice/ - - soc/riscv/riscv-privileged/gd32vf103/ + - soc/*/gd_gd32/ - scripts/west_commands/*/*gd32* labels: - "platform: GD32" @@ -2501,8 +3098,8 @@ Nuvoton NPCX Platforms: - MulinChao - ChiHuaL collaborators: - - MulinChao - - ChiHuaL + - TomChang19 + - alvsun - sjg20 - keith-zephyr - jackrosenthal @@ -2596,7 +3193,6 @@ Intel Platforms (Xtensa): - marc-hb - kv2019i - ceolin - - aborisovich - tmleman - softwarecki - jxstelter @@ -2639,52 +3235,114 @@ Intel Platforms (Agilex): - boards/arm64/intel_*/ - soc/arm64/intel_*/ - dts/arm64/intel/ - - samples/boards/intel_adsp/ - dts/bindings/*/intel,agilex* + - dts/arm/intel_socfpga_std/ labels: - "platform: Intel SoC FPGA Agilex" -NXP Platforms: +NXP Drivers: status: maintained maintainers: - dleach02 collaborators: - mmahadevan108 - danieldegrasse - - DerekSnell - - yvanderv - - EmilioCBen - decsny - manuargue - - PetervdPerk-NXP - - bperseghetti - dbaluta - - iuliana-prodan - - Dat-NguyenDuy files: - - boards/arm/mimx*/ - - boards/arm/frdm_k*/ - - boards/arm/lpcxpress*/ - - boards/arm/twr_*/ - - boards/arm/s32*/ - - boards/arm/mr_canhubk3/ - - boards/arm/vmu_rt*/ - - soc/arm/nxp_*/ - drivers/*/*imx* - drivers/*/*lpc*.c - drivers/*/*mcux*.c - drivers/*/*.mcux - drivers/*/*.nxp - drivers/*/*nxp* - - dts/arm/nxp/ + - drivers/*/*kinetis* + - drivers/misc/*/nxp* + - include/zephyr/dt-bindings/*/*nxp* + - include/zephyr/dt-bindings/*/*mcux* + - include/zephyr/drivers/*/*nxp* + - include/zephyr/drivers/*/*mcux* + - arch/arm/core/mpu/nxp_mpu.c - dts/bindings/*/nxp* - - soc/xtensa/nxp_adsp/ - - boards/xtensa/nxp_adsp_*/ + files-exclude: + - drivers/*/*s32* + - drivers/misc/*/*s32* + - include/zephyr/dt-bindings/*/*s32* + - include/zephyr/drivers/*/*s32* + - dts/bindings/*/*s32* + labels: + - "platform: NXP Drivers" + description: NXP Drivers + +NXP Platforms (MCUX): + status: maintained + maintainers: + - dleach02 + collaborators: + - mmahadevan108 + - danieldegrasse + - DerekSnell + - yvanderv + - EmilioCBen + - decsny + files: + - boards/arm/mimx*/ + - boards/arm/frdm*/ + - boards/arm/lpcxpress*/ + - boards/arm/twr_*/ + - boards/arm/vmu*/ + - soc/arm/nxp_imx/ + - soc/arm/nxp_kinetis/ + - soc/arm/nxp_lpc/ + - dts/arm/nxp/ - samples/boards/nxp*/ - - include/zephyr/dt-bindings/*/nxp* - - include/zephyr/drivers/*/*nxp* + files-exclude: + - boards/arm/*s32*/ + - dts/arm/nxp/*s32* + - samples/boards/nxp_s32/ labels: - "platform: NXP" + description: NXP Platforms supported by MCUXpresso suite + +NXP Platforms (S32): + status: maintained + maintainers: + - manuargue + collaborators: + - PetervdPerk-NXP + - bperseghetti + - Dat-NguyenDuy + files: + - boards/arm/s32*/ + - boards/arm/mr_canhubk3/ + - boards/arm/ucans32k1sic/ + - boards/common/*nxp_s32* + - soc/arm/nxp_s32/ + - drivers/*/*nxp_s32* + - drivers/misc/*nxp_s32*/ + - dts/bindings/*/nxp,s32* + - dts/arm/nxp/*s32* + - samples/boards/nxp_s32/ + - include/zephyr/dt-bindings/*/nxp-s32* + - include/zephyr/dt-bindings/*/nxp_s32* + - include/zephyr/drivers/*/*nxp_s32* + labels: + - "platform: NXP S32" + description: NXP S32 platforms and S32-specific drivers + +NXP Platforms (Xtensa): + status: maintained + maintainers: + - dbaluta + collaborators: + - iuliana-prodan + files: + - soc/xtensa/nxp_adsp/ + - boards/xtensa/nxp_adsp_*/ + labels: + - "platform: NXP ADSP" + description: NXP Xtensa platforms Microchip MEC Platforms: status: maintained @@ -2755,6 +3413,38 @@ Renesas SmartBond Platforms: Renesas SmartBond SOCs, dts files, and related drivers. Renesas boards based on SmartBond SoCs. +Renesas RA Platforms: + status: maintained + maintainers: + - soburi + files: + - boards/arm/arduino_uno_r4/ + - drivers/*/*renesas_ra* + - dts/arm/renesas/ra/ + - dts/bindings/*/*renesas,ra* + - soc/arm/renesas_ra/ + labels: + - "platforms: Renesas RA" + description: >- + Renesas RA SOCs, dts files, and related drivers. Boards based + on Renesas RA SoCs. + +Renesas RZ Platforms: + status: maintained + maintainers: + - tgorochowik + files: + - boards/arm/rzt2m_*/ + - drivers/*/*rzt2m* + - dts/arm/renesas/rz/ + - dts/bindings/*/*rzt2m* + - soc/arm/renesas_rzt2m/ + labels: + - "platforms: Renesas RZ" + description: >- + Renesas RZ SOCs, dts files, and related drivers. Renesas boards based + on RZ SoCs. + Renesas R-Car Platforms: status: maintained maintainers: @@ -2763,6 +3453,7 @@ Renesas R-Car Platforms: collaborators: - xakep-amatop files: + - dts/arm/renesas/rcar/ - boards/arm/rcar_*/ - boards/arm64/rcar_*/ - drivers/*/*rcar* @@ -2799,7 +3490,7 @@ STM32 Platforms: - drivers/*/*stm32*.c - drivers/*/*stm32*.h - drivers/*/*/*stm32* - - drivers/*/*stm32 + - drivers/*/*stm32* - dts/arm/st/ - dts/bindings/*/*stm32* - soc/arm/st_stm32/ @@ -2848,9 +3539,10 @@ ITE Platforms: - boards/riscv/it8*_evb/ - drivers/*/*/*it8xxx2*.c - drivers/*/*it8xxx2*.c + - drivers/*/*_ite_* - dts/bindings/*/*ite* - dts/riscv/ite/ - - soc/riscv/riscv-ite/ + - soc/riscv/ite_ec/ labels: - "platform: ITE" @@ -2860,7 +3552,6 @@ TI SimpleLink Platforms: - vaishnavachath collaborators: - vanti - - cfriedt files: - boards/arm/cc13*/ - boards/arm/cc26*/ @@ -2874,6 +3565,7 @@ TI SimpleLink Platforms: - dts/bindings/*/ti,* - soc/arm/ti_simplelink/ - dts/bindings/*/ti,* + - modules/Kconfig.simplelink labels: - "platform: TI SimpleLink" @@ -2892,6 +3584,14 @@ TI K3 Platforms: labels: - "platform: TI K3" +TI Platforms: + status: odd fixes + files: + - soc/arm/ti_lm3s6965/ + - dts/arm/ti/lm3s6965.dtsi + labels: + - "platform: TI" + Xilinx Platforms: status: odd fixes collaborators: @@ -2922,6 +3622,8 @@ Infineon Platforms: - drivers/*/*xmc*.c - drivers/*/*/*xmc* - dts/arm/infineon/ + - dts/arm/cypress/ + - soc/arm/cypress/ - dts/bindings/*/*infineon* - soc/arm/infineon_*/ labels: @@ -2930,6 +3632,15 @@ Infineon Platforms: Infineon SOCs, dts files and related drivers. Infineon Proto, Pioneer, Eval and Relax boards. +Panasonic Platforms: + status: maintained + maintainers: + - pideu-sj + files: + - boards/arm/pan17*/ + labels: + - "platform: Panasonic" + RTIO: status: maintained maintainers: @@ -2944,6 +3655,8 @@ RTIO: - doc/services/rtio/ labels: - "area: RTIO" + tests: + - rtio Storage: status: odd fixes @@ -2954,6 +3667,8 @@ Storage: - doc/services/storage/ labels: - "area: Storage" + tests: + - storage Sysbuild: status: maintained @@ -2968,6 +3683,8 @@ Sysbuild: - doc/build/sysbuild/ labels: - "area: Sysbuild" + tests: + - sample.application_development.sysbuild Task Watchdog: status: maintained @@ -2980,6 +3697,19 @@ Task Watchdog: - doc/services/task_wdt/index.rst labels: - "area: Task Watchdog" + tests: + - sample.task_wdt + +"Drivers: Syscon": + status: maintained + maintainers: + - carlocaione + files: + - include/zephyr/drivers/syscon.h + - drivers/syscon/ + - tests/drivers/syscon/ + tests: + - drivers.syscon "Drivers: Time Aware GPIO": status: maintained @@ -2992,19 +3722,23 @@ Task Watchdog: - samples/drivers/misc/timeaware_gpio/ labels: - "area: Time Aware GPIO" + tests: + - sample.drivers.misc.timeaware_gpio TF-M Integration: status: maintained maintainers: - d3zd3z collaborators: - - joerchan + - SebastianBoe files: - samples/tfm_integration/ - modules/trusted-firmware-m/ - doc/services/tfm/ labels: - "area: TF-M" + tests: + - tfm "Toolchain Integration": @@ -3073,6 +3807,8 @@ Tracing: - tests/subsys/tracing/ labels: - "area: tracing" + tests: + - tracing USB: status: maintained @@ -3088,11 +3824,15 @@ USB: - samples/subsys/usb/ - subsys/usb/ - tests/subsys/usb/ + - tests/drivers/usb/ - tests/drivers/udc/ - doc/connectivity/usb/ - scripts/generate_usb_vif/ labels: - "area: USB" + tests: + - usb + - drivers.usb USB-C: status: maintained @@ -3111,6 +3851,8 @@ USB-C: - doc/hardware/peripherals/usbc_vbus.rst labels: - "area: USB-C" + tests: + - sample.usbc Userspace: status: maintained @@ -3139,6 +3881,8 @@ Userspace: - include/zephyr/kernel/mm/demand_paging.h labels: - "area: Userspace" + tests: + - kernel.memory_protection VFS: status: maintained @@ -3152,6 +3896,8 @@ VFS: labels: - "area: File System" + tests: + - filesystem West: status: maintained @@ -3269,6 +4015,8 @@ West: collaborators: - tgorochowik - msobkowski + - aaronyegx + - RichardSWheatley files: - modules/hal_ambiq/ labels: @@ -3451,9 +4199,7 @@ West: collaborators: - erwango files: - - modules/Kconfig.st - labels: - - "area: Sensors" + - modules/hal_st/Kconfig "West project: hal_stm32": status: maintained @@ -3482,8 +4228,6 @@ West: status: maintained maintainers: - vaishnavachath - collaborators: - - cfriedt files: [] labels: - "platform: TI" @@ -3494,8 +4238,6 @@ West: - mah-eiSmart files: - modules/Kconfig.wurthelektronik - labels: - - "area: Sensors" "West project: hal_xtensa": status: maintained @@ -3664,6 +4406,7 @@ West: - canisLupus1313 - mariuszpos - edmont + - maciejbaczmanski files: - modules/openthread/ labels: @@ -3749,7 +4492,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: - modules/trusted-firmware-m/ @@ -3761,7 +4503,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: @@ -3784,7 +4525,6 @@ West: maintainers: - d3zd3z collaborators: - - joerchan - SebastianBoe files: [] labels: @@ -3816,8 +4556,6 @@ West: maintainers: - microbuilder files: [] - labels: - - "area: Sensors" "West project: hostap": status: maintained @@ -3845,6 +4583,7 @@ Xtensa arch: - boards/xtensa/xt-sim/ - soc/xtensa/dc233c/ - soc/xtensa/sample_controller/ + - soc/xtensa/CMakeLists.txt labels: - "area: Xtensa" @@ -3875,7 +4614,9 @@ Continuous Integration: maintainers: - stephanosio - nashif - - galak + collaborators: + - fabiobaltieri + - kartben files: - .github/ - scripts/ci/ @@ -3885,7 +4626,7 @@ Continuous Integration: labels: - "area: Continuous Integration" -ZTest: +Test Framework (Ztest): status: maintained maintainers: - nashif @@ -3916,6 +4657,7 @@ Emulation: - tristan-google files: - subsys/emul/ + - include/zephyr/drivers/emul_* - include/zephyr/drivers/emul.h - include/zephyr/drivers/espi_emul.h - include/zephyr/drivers/i2c_emul.h @@ -3960,6 +4702,8 @@ zbus: - doc/services/zbus/ labels: - "area: zbus" + tests: + - message_bus.zbus "Linkable Loadable Extensions": status: maintained @@ -3967,6 +4711,7 @@ zbus: - teburd collaborators: - lyakh + - pillo79 files: - samples/subsys/llext/ - include/zephyr/llext/ @@ -3975,3 +4720,5 @@ zbus: - doc/services/llext/ labels: - "area: Linkable Loadable Extensions" + tests: + - llext diff --git a/SDK_VERSION b/SDK_VERSION new file mode 100644 index 00000000000..19270385eaf --- /dev/null +++ b/SDK_VERSION @@ -0,0 +1 @@ +0.16.5 diff --git a/arch/Kconfig b/arch/Kconfig index 5e3b96f414d..1e28103509f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -125,7 +125,7 @@ config XTENSA select IRQ_OFFLOAD_NESTED if IRQ_OFFLOAD select ARCH_HAS_CODE_DATA_RELOCATION select ARCH_HAS_TIMING_FUNCTIONS - imply ATOMIC_OPERATIONS_ARCH + select ARCH_MEM_DOMAIN_DATA if USERSPACE help Xtensa architecture @@ -139,7 +139,7 @@ config ARCH_POSIX select NATIVE_BUILD select HAS_COVERAGE_SUPPORT select BARRIER_OPERATIONS_BUILTIN - # native_posix gets its memory cleared on entry by the host OS + # POSIX arch based targets get their memory cleared on entry by the host OS select SKIP_BSS_CLEAR help POSIX (native) architecture @@ -391,6 +391,29 @@ config NOCACHE_MEMORY menu "Interrupt Configuration" +config ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + bool + default y + # Userspace is currently not supported + depends on !USERSPACE + # List of currently supported architectures + depends on ARM || ARM64 + # List of currently supported toolchains + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" || "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "gnuarmemb" + +config ISR_TABLES_LOCAL_DECLARATION + bool "ISR tables created locally and placed by linker [EXPERIMENTAL]" + depends on ISR_TABLES_LOCAL_DECLARATION_SUPPORTED + select EXPERIMENTAL + help + Enable new scheme of interrupt tables generation. + This is totally different generator that would create tables entries locally + where the IRQ_CONNECT macro is called and then use the linker script to position it + in the right place in memory. + The most important advantage of such approach is that the generated interrupt tables + are LTO compatible. + The drawback is that the support on the architecture port is required. + config DYNAMIC_INTERRUPTS bool "Installation of IRQs at runtime" help @@ -513,6 +536,16 @@ config IRQ_OFFLOAD_NESTED synchronous nested interrupt on the current CPU. Not all hardware is capable. +config EXCEPTION_DEBUG + bool "Unhandled exception debugging" + default y + depends on PRINTK || LOG + help + Install handlers for various CPU exception/trap vectors to + make debugging them easier, at a small expense in code size. + This prints out the specific exception vector and any associated + error codes. + config EXTRA_EXCEPTION_INFO bool "Collect extra exception info" depends on ARCH_HAS_EXTRA_EXCEPTION_INFO @@ -655,6 +688,11 @@ config CPU_HAS_FPU This option is enabled when the CPU has hardware floating point unit. +config CPU_HAS_DSP + bool + help + This option is enabled when the CPU has hardware DSP unit. + config CPU_HAS_FPU_DOUBLE_PRECISION bool select CPU_HAS_FPU @@ -692,6 +730,13 @@ config CPU_HAS_DCACHE help This hidden configuration should be selected when the CPU has a d-cache. +config CPU_CACHE_INCOHERENT + bool + help + This hidden configuration should be selected when the CPU has + incoherent cache. This applies to intra-CPU multiprocessing + incoherence and makes only sense when MP_NUM_CPUS > 1. + config CPU_HAS_ICACHE bool help @@ -819,6 +864,17 @@ config CODE_DATA_RELOCATION the target regions should be specified in CMakeLists.txt using zephyr_code_relocate(). +menu "DSP Options" + +config DSP_SHARING + bool "DSP register sharing" + depends on CPU_HAS_DSP + help + This option enables preservation of the hardware DSP registers + across context switches to allow multiple threads to perform concurrent + DSP operations. +endmenu + menu "Floating Point Options" config FPU @@ -876,6 +932,17 @@ config ICACHE help This option enables the support for the instruction cache (i-cache). +config CACHE_DOUBLEMAP + bool "Cache double-mapping support" + depends on CPU_CACHE_INCOHERENT + default y + help + Double-mapping behavior where a pointer can be cheaply converted to + point to the same cached/uncached memory at different locations. + + This applies to intra-CPU multiprocessing incoherence and makes only + sense when MP_NUM_CPUS > 1. + config CACHE_MANAGEMENT bool "Cache management features" depends on DCACHE || ICACHE diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index ce23b12aa1d..80b46876e10 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -253,6 +253,18 @@ config ARC_USE_UNALIGNED_MEM_ACCESS to support unaligned memory access which is then disabled by default. Enable unaligned access in hardware and make software to use it. +config ARC_CURRENT_THREAD_USE_NO_TLS + bool + select CURRENT_THREAD_USE_NO_TLS + default y if (RGF_NUM_BANKS > 1) || ("$(ZEPHYR_TOOLCHAIN_VARIANT)" = "arcmwdt") + help + Disable current Thread Local Storage for ARC. For cores with more then one + RGF_NUM_BANKS the parameter is disabled by-default because banks syncronization + requires significant time, and it slows down performance. + ARCMWDT works with tls pointer in different way then GCC. Optimized access to + TLS pointer via _current variable does not provide significant advantages + in case of MetaWare. + config FAULT_DUMP int "Fault dump level" default 2 @@ -376,15 +388,6 @@ config ARC_EXCEPTION_STACK_SIZE endmenu -config ARC_EXCEPTION_DEBUG - bool "Unhandled exception debugging information" - default n - depends on PRINTK || LOG - help - Print human-readable information about exception vectors, cause codes, - and parameters, at a cost of code/data size for the human-readable - strings. - config ARC_EARLY_SOC_INIT bool "Make early stage SoC-specific initialization" help diff --git a/arch/arc/core/CMakeLists.txt b/arch/arc/core/CMakeLists.txt index 3325e27ff88..00c9f775038 100644 --- a/arch/arc/core/CMakeLists.txt +++ b/arch/arc/core/CMakeLists.txt @@ -26,7 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_connect.c) -zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT arc_smp.c) +zephyr_library_sources_ifdef(CONFIG_ARC_CONNECT smp.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) diff --git a/arch/arc/core/arc_smp.c b/arch/arc/core/arc_smp.c deleted file mode 100644 index 9fb43c41152..00000000000 --- a/arch/arc/core/arc_smp.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2019 Synopsys. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief codes required for ARC multicore and Zephyr smp support - * - */ -#include -#include -#include -#include -#include -#include -#include - -volatile struct { - arch_cpustart_t fn; - void *arg; -} arc_cpu_init[CONFIG_MP_MAX_NUM_CPUS]; - -/* - * arc_cpu_wake_flag is used to sync up master core and slave cores - * Slave core will spin for arc_cpu_wake_flag until master core sets - * it to the core id of slave core. Then, slave core clears it to notify - * master core that it's waken - * - */ -volatile uint32_t arc_cpu_wake_flag; - -volatile char *arc_cpu_sp; -/* - * _curr_cpu is used to record the struct of _cpu_t of each cpu. - * for efficient usage in assembly - */ -volatile _cpu_t *_curr_cpu[CONFIG_MP_MAX_NUM_CPUS]; - -/* Called from Zephyr initialization */ -void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, - arch_cpustart_t fn, void *arg) -{ - _curr_cpu[cpu_num] = &(_kernel.cpus[cpu_num]); - arc_cpu_init[cpu_num].fn = fn; - arc_cpu_init[cpu_num].arg = arg; - - /* set the initial sp of target sp through arc_cpu_sp - * arc_cpu_wake_flag will protect arc_cpu_sp that - * only one slave cpu can read it per time - */ - arc_cpu_sp = Z_KERNEL_STACK_BUFFER(stack) + sz; - - arc_cpu_wake_flag = cpu_num; - - /* wait slave cpu to start */ - while (arc_cpu_wake_flag != 0U) { - ; - } -} - -#ifdef CONFIG_SMP -static void arc_connect_debug_mask_update(int cpu_num) -{ - uint32_t core_mask = 1 << cpu_num; - - /* - * MDB debugger may modify debug_select and debug_mask registers on start, so we can't - * rely on debug_select reset value. - */ - if (cpu_num != ARC_MP_PRIMARY_CPU_ID) { - core_mask |= z_arc_connect_debug_select_read(); - } - - z_arc_connect_debug_select_set(core_mask); - /* Debugger halts cores at all conditions: - * ARC_CONNECT_CMD_DEBUG_MASK_H: Core global halt. - * ARC_CONNECT_CMD_DEBUG_MASK_AH: Actionpoint halt. - * ARC_CONNECT_CMD_DEBUG_MASK_BH: Software breakpoint halt. - * ARC_CONNECT_CMD_DEBUG_MASK_SH: Self halt. - */ - z_arc_connect_debug_mask_set(core_mask, (ARC_CONNECT_CMD_DEBUG_MASK_SH - | ARC_CONNECT_CMD_DEBUG_MASK_BH | ARC_CONNECT_CMD_DEBUG_MASK_AH - | ARC_CONNECT_CMD_DEBUG_MASK_H)); -} -#endif - -void arc_core_private_intc_init(void); - -/* the C entry of slave cores */ -void z_arc_slave_start(int cpu_num) -{ - arch_cpustart_t fn; - -#ifdef CONFIG_SMP - struct arc_connect_bcr bcr; - - bcr.val = z_arc_v2_aux_reg_read(_ARC_V2_CONNECT_BCR); - - if (bcr.dbg) { - /* configure inter-core debug unit if available */ - arc_connect_debug_mask_update(cpu_num); - } - - z_irq_setup(); - - arc_core_private_intc_init(); - - arc_irq_offload_init_smp(); - - z_arc_connect_ici_clear(); - z_irq_priority_set(DT_IRQN(DT_NODELABEL(ici)), - DT_IRQ(DT_NODELABEL(ici), priority), 0); - irq_enable(DT_IRQN(DT_NODELABEL(ici))); -#endif - /* call the function set by arch_start_cpu */ - fn = arc_cpu_init[cpu_num].fn; - - fn(arc_cpu_init[cpu_num].arg); -} - -#ifdef CONFIG_SMP - -static void sched_ipi_handler(const void *unused) -{ - ARG_UNUSED(unused); - - z_arc_connect_ici_clear(); - z_sched_ipi(); -} - -/* arch implementation of sched_ipi */ -void arch_sched_ipi(void) -{ - uint32_t i; - - /* broadcast sched_ipi request to other cores - * if the target is current core, hardware will ignore it - */ - unsigned int num_cpus = arch_num_cpus(); - - for (i = 0U; i < num_cpus; i++) { - z_arc_connect_ici_generate(i); - } -} - -static int arc_smp_init(void) -{ - struct arc_connect_bcr bcr; - - /* necessary master core init */ - _curr_cpu[0] = &(_kernel.cpus[0]); - - bcr.val = z_arc_v2_aux_reg_read(_ARC_V2_CONNECT_BCR); - - if (bcr.dbg) { - /* configure inter-core debug unit if available */ - arc_connect_debug_mask_update(ARC_MP_PRIMARY_CPU_ID); - } - - if (bcr.ipi) { - /* register ici interrupt, just need master core to register once */ - z_arc_connect_ici_clear(); - IRQ_CONNECT(DT_IRQN(DT_NODELABEL(ici)), - DT_IRQ(DT_NODELABEL(ici), priority), - sched_ipi_handler, NULL, 0); - - irq_enable(DT_IRQN(DT_NODELABEL(ici))); - } else { - __ASSERT(0, - "ARC connect has no inter-core interrupt\n"); - return -ENODEV; - } - - if (bcr.gfrc) { - /* global free running count init */ - z_arc_connect_gfrc_enable(); - - /* when all cores halt, gfrc halt */ - z_arc_connect_gfrc_core_set((1 << arch_num_cpus()) - 1); - z_arc_connect_gfrc_clear(); - } else { - __ASSERT(0, - "ARC connect has no global free running counter\n"); - return -ENODEV; - } - - return 0; -} - -SYS_INIT(arc_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); -#endif diff --git a/arch/arc/core/cache.c b/arch/arc/core/cache.c index 1536c5a173f..8c2aab29fed 100644 --- a/arch/arc/core/cache.c +++ b/arch/arc/core/cache.c @@ -218,8 +218,7 @@ int arch_icache_flush_and_invd_range(void *addr, size_t size) static int init_dcache(void) { - - arch_dcache_enable(); + sys_cache_data_enable(); #if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) init_dcache_line_size(); diff --git a/arch/arc/core/dsp/Kconfig b/arch/arc/core/dsp/Kconfig index 396f9c6840e..48a910198ec 100644 --- a/arch/arc/core/dsp/Kconfig +++ b/arch/arc/core/dsp/Kconfig @@ -3,13 +3,8 @@ # Copyright (c) 2022 Synopsys # SPDX-License-Identifier: Apache-2.0 -config ARC_HAS_DSP - bool - help - This option is enabled when the ARC CPU has hardware DSP unit. - menu "ARC DSP Options" -depends on ARC_HAS_DSP +depends on CPU_HAS_DSP config ARC_DSP bool "digital signal processing (DSP)" @@ -22,7 +17,7 @@ config ARC_DSP_TURNED_OFF help This option disables DSP block via resetting DSP_CRTL register. -config ARC_DSP_SHARING +config DSP_SHARING bool "DSP register sharing" depends on ARC_DSP && MULTITHREADING select ARC_HAS_ACCL_REGS @@ -49,7 +44,7 @@ config ARC_XY_ENABLE config ARC_AGU_SHARING bool "ARC address generation unit register sharing" depends on ARC_XY_ENABLE && MULTITHREADING - default y if ARC_DSP_SHARING + default y if DSP_SHARING help This option enables preservation of the hardware AGU registers across context switches to allow multiple threads to perform concurrent diff --git a/arch/arc/core/dsp/dsp_offsets.c b/arch/arc/core/dsp/dsp_offsets.c index bc606c9c26e..77db2d82c1f 100644 --- a/arch/arc/core/dsp/dsp_offsets.c +++ b/arch/arc/core/dsp/dsp_offsets.c @@ -9,7 +9,7 @@ * @brief ARCv2 DSP and AGU structure member offset definition file * */ -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING GEN_OFFSET_SYM(_callee_saved_stack_t, dsp_ctrl); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_glo); GEN_OFFSET_SYM(_callee_saved_stack_t, acc0_ghi); diff --git a/arch/arc/core/dsp/swap_dsp_macros.h b/arch/arc/core/dsp/swap_dsp_macros.h index 0d322fa28fc..07615286683 100644 --- a/arch/arc/core/dsp/swap_dsp_macros.h +++ b/arch/arc/core/dsp/swap_dsp_macros.h @@ -10,7 +10,7 @@ * */ .macro _save_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_save lr r13, [_ARC_V2_DSP_CTRL] @@ -136,7 +136,7 @@ agu_skip_save : .endm .macro _load_dsp_regs -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING ld_s r13, [r2, ___thread_base_t_user_options_OFFSET] bbit0 r13, K_DSP_IDX, dsp_skip_load ld_s r13, [sp, ___callee_saved_stack_t_dsp_ctrl_OFFSET] diff --git a/arch/arc/core/fatal.c b/arch/arc/core/fatal.c index df8af4c1b44..346a04062c1 100644 --- a/arch/arc/core/fatal.c +++ b/arch/arc/core/fatal.c @@ -17,11 +17,11 @@ #include #include #include -#include +#include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG static void dump_arc_esf(const z_arch_esf_t *esf) { LOG_ERR(" r0: 0x%" PRIxPTR " r1: 0x%" PRIxPTR " r2: 0x%" PRIxPTR " r3: 0x%" PRIxPTR "", @@ -42,11 +42,11 @@ static void dump_arc_esf(const z_arch_esf_t *esf) void z_arc_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { dump_arc_esf(esf); } -#endif /* CONFIG_ARC_EXCEPTION_DEBUG */ +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } diff --git a/arch/arc/core/fault.c b/arch/arc/core/fault.c index 9e0ddaf7ed9..8034f5673d4 100644 --- a/arch/arc/core/fault.c +++ b/arch/arc/core/fault.c @@ -69,7 +69,7 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) * "guard" installed in this case, instead what's * happening is that the stack pointer is crashing * into the privilege mode stack buffer which - * immediately precededs it. + * immediately precedes it. */ guard_end = thread->stack_info.start; guard_start = (uint32_t)thread->stack_obj; @@ -104,7 +104,7 @@ static bool z_check_thread_stack_fail(const uint32_t fault_addr, uint32_t sp) } #endif -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG /* For EV_ProtV, the numbering/semantics of the parameter are consistent across * several codes, although not all combination will be reported. * @@ -335,7 +335,7 @@ static void dump_exception_info(uint32_t vector, uint32_t cause, uint32_t parame break; } } -#endif /* CONFIG_ARC_EXCEPTION_DEBUG */ +#endif /* CONFIG_EXCEPTION_DEBUG */ /* * @brief Fault handler @@ -387,7 +387,7 @@ void _Fault(z_arch_esf_t *esf, uint32_t old_sp) LOG_ERR("***** Exception vector: 0x%x, cause code: 0x%x, parameter 0x%x", vector, cause, parameter); LOG_ERR("Address 0x%x", exc_addr); -#ifdef CONFIG_ARC_EXCEPTION_DEBUG +#ifdef CONFIG_EXCEPTION_DEBUG dump_exception_info(vector, cause, parameter); #endif diff --git a/arch/arc/core/offsets/offsets.c b/arch/arc/core/offsets/offsets.c index 450a6d23047..855270fa3ab 100644 --- a/arch/arc/core/offsets/offsets.c +++ b/arch/arc/core/offsets/offsets.c @@ -26,7 +26,7 @@ #include #include #include -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #include "../dsp/dsp_offsets.c" #endif diff --git a/arch/arc/core/prep_c.c b/arch/arc/core/prep_c.c index 8bf481c86b2..0e4975cd3fc 100644 --- a/arch/arc/core/prep_c.c +++ b/arch/arc/core/prep_c.c @@ -20,10 +20,10 @@ #include #include #include +#include #include #include - /* XXX - keep for future use in full-featured cache APIs */ #if 0 /** @@ -67,6 +67,51 @@ static void invalidate_dcache(void) } #endif +#ifdef CONFIG_ISA_ARCV3 +/* NOTE: it will be called from early C code - we must NOT use global / static variables in it! */ +static void arc_cluster_scm_enable(void) +{ + unsigned int cluster_version; + + /* Check that we have cluster and its version is supported */ + cluster_version = z_arc_v2_aux_reg_read(_ARC_REG_CLN_BCR) & _ARC_CLN_BCR_VER_MAJOR_MASK; + if (cluster_version < _ARC_REG_CLN_BCR_VER_MAJOR_ARCV3_MIN) { + return; + } + + /* Check that we have shared cache in cluster */ + if (!(z_arc_v2_aux_reg_read(_ARC_CLNR_BCR_0) & _ARC_CLNR_BCR_0_HAS_SCM)) { + return; + } + + /* Disable SCM, just in case. */ + arc_cln_write_reg_nolock(ARC_CLN_CACHE_STATUS, 0); + + /* Invalidate SCM before enabling. */ + arc_cln_write_reg_nolock(ARC_CLN_CACHE_CMD, + ARC_CLN_CACHE_CMD_OP_REG_INV | ARC_CLN_CACHE_CMD_INCR); + while (arc_cln_read_reg_nolock(ARC_CLN_CACHE_STATUS) & ARC_CLN_CACHE_STATUS_BUSY) + ; + + arc_cln_write_reg_nolock(ARC_CLN_CACHE_STATUS, ARC_CLN_CACHE_STATUS_EN); +} +#endif /* CONFIG_ISA_ARCV3 */ + +#ifdef __CCAC__ +extern char __device_states_start[]; +extern char __device_states_end[]; +/** + * @brief Clear device_states section + * + * This routine clears the device_states section, + * as MW compiler marks the section with NOLOAD flag. + */ +static void dev_state_zero(void) +{ + z_early_memset(__device_states_start, 0, __device_states_end - __device_states_start); +} +#endif + extern FUNC_NORETURN void z_cstart(void); /** * @brief Prepare to and run C code @@ -74,9 +119,16 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { +#ifdef CONFIG_ISA_ARCV3 + arc_cluster_scm_enable(); +#endif + z_bss_zero(); +#ifdef __CCAC__ + dev_state_zero(); +#endif z_data_copy(); z_cstart(); CODE_UNREACHABLE; diff --git a/arch/arc/core/reset.S b/arch/arc/core/reset.S index ba29f44051b..a2b038d387e 100644 --- a/arch/arc/core/reset.S +++ b/arch/arc/core/reset.S @@ -40,7 +40,7 @@ GTEXT(__start) * * Locking interrupts prevents anything from interrupting the CPU. * - * When these steps are completed, jump to _PrepC(), which will finish setting + * When these steps are completed, jump to z_prep_c(), which will finish setting * up the system for running C code. */ @@ -151,6 +151,16 @@ done_mpu_regions_reset: #endif #endif +#ifdef CONFIG_ISA_ARCV3 + /* Enable HW prefetcher if exist */ + lr r0, [_ARC_HW_PF_BUILD] + breq r0, 0, hw_pf_setup_done + lr r1, [_ARC_HW_PF_CTRL] + or r1, r1, _ARC_HW_PF_CTRL_ENABLE + sr r1, [_ARC_HW_PF_CTRL] +hw_pf_setup_done: +#endif + #if defined(CONFIG_SMP) || CONFIG_MP_MAX_NUM_CPUS > 1 _get_cpu_id r0 breq r0, 0, _master_core_startup @@ -174,7 +184,7 @@ _slave_core_wait: jl z_arc_firq_stack_set pop r0 #endif - j z_arc_slave_start + j arch_secondary_cpu_init _master_core_startup: #endif @@ -202,4 +212,4 @@ _master_core_startup: jl z_arc_firq_stack_set #endif - j _PrepC + j z_prep_c diff --git a/arch/arc/core/smp.c b/arch/arc/core/smp.c new file mode 100644 index 00000000000..6bc89883fad --- /dev/null +++ b/arch/arc/core/smp.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019 Synopsys. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief codes required for ARC multicore and Zephyr smp support + * + */ +#include +#include +#include +#include +#include +#include +#include + +volatile struct { + arch_cpustart_t fn; + void *arg; +} arc_cpu_init[CONFIG_MP_MAX_NUM_CPUS]; + +/* + * arc_cpu_wake_flag is used to sync up master core and slave cores + * Slave core will spin for arc_cpu_wake_flag until master core sets + * it to the core id of slave core. Then, slave core clears it to notify + * master core that it's waken + * + */ +volatile uint32_t arc_cpu_wake_flag; + +volatile char *arc_cpu_sp; +/* + * _curr_cpu is used to record the struct of _cpu_t of each cpu. + * for efficient usage in assembly + */ +volatile _cpu_t *_curr_cpu[CONFIG_MP_MAX_NUM_CPUS]; + +/* Called from Zephyr initialization */ +void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, + arch_cpustart_t fn, void *arg) +{ + _curr_cpu[cpu_num] = &(_kernel.cpus[cpu_num]); + arc_cpu_init[cpu_num].fn = fn; + arc_cpu_init[cpu_num].arg = arg; + + /* set the initial sp of target sp through arc_cpu_sp + * arc_cpu_wake_flag will protect arc_cpu_sp that + * only one slave cpu can read it per time + */ + arc_cpu_sp = Z_KERNEL_STACK_BUFFER(stack) + sz; + + arc_cpu_wake_flag = cpu_num; + + /* wait slave cpu to start */ + while (arc_cpu_wake_flag != 0U) { + ; + } +} + +#ifdef CONFIG_SMP +static void arc_connect_debug_mask_update(int cpu_num) +{ + uint32_t core_mask = 1 << cpu_num; + + /* + * MDB debugger may modify debug_select and debug_mask registers on start, so we can't + * rely on debug_select reset value. + */ + if (cpu_num != ARC_MP_PRIMARY_CPU_ID) { + core_mask |= z_arc_connect_debug_select_read(); + } + + z_arc_connect_debug_select_set(core_mask); + /* Debugger halts cores at all conditions: + * ARC_CONNECT_CMD_DEBUG_MASK_H: Core global halt. + * ARC_CONNECT_CMD_DEBUG_MASK_AH: Actionpoint halt. + * ARC_CONNECT_CMD_DEBUG_MASK_BH: Software breakpoint halt. + * ARC_CONNECT_CMD_DEBUG_MASK_SH: Self halt. + */ + z_arc_connect_debug_mask_set(core_mask, (ARC_CONNECT_CMD_DEBUG_MASK_SH + | ARC_CONNECT_CMD_DEBUG_MASK_BH | ARC_CONNECT_CMD_DEBUG_MASK_AH + | ARC_CONNECT_CMD_DEBUG_MASK_H)); +} +#endif + +void arc_core_private_intc_init(void); + +/* the C entry of slave cores */ +void arch_secondary_cpu_init(int cpu_num) +{ + arch_cpustart_t fn; + +#ifdef CONFIG_SMP + struct arc_connect_bcr bcr; + + bcr.val = z_arc_v2_aux_reg_read(_ARC_V2_CONNECT_BCR); + + if (bcr.dbg) { + /* configure inter-core debug unit if available */ + arc_connect_debug_mask_update(cpu_num); + } + + z_irq_setup(); + + arc_core_private_intc_init(); + + arc_irq_offload_init_smp(); + + z_arc_connect_ici_clear(); + z_irq_priority_set(DT_IRQN(DT_NODELABEL(ici)), + DT_IRQ(DT_NODELABEL(ici), priority), 0); + irq_enable(DT_IRQN(DT_NODELABEL(ici))); +#endif + /* call the function set by arch_start_cpu */ + fn = arc_cpu_init[cpu_num].fn; + + fn(arc_cpu_init[cpu_num].arg); +} + +#ifdef CONFIG_SMP + +static void sched_ipi_handler(const void *unused) +{ + ARG_UNUSED(unused); + + z_arc_connect_ici_clear(); + z_sched_ipi(); +} + +/* arch implementation of sched_ipi */ +void arch_sched_ipi(void) +{ + uint32_t i; + + /* broadcast sched_ipi request to other cores + * if the target is current core, hardware will ignore it + */ + unsigned int num_cpus = arch_num_cpus(); + + for (i = 0U; i < num_cpus; i++) { + z_arc_connect_ici_generate(i); + } +} + +int arch_smp_init(void) +{ + struct arc_connect_bcr bcr; + + /* necessary master core init */ + _curr_cpu[0] = &(_kernel.cpus[0]); + + bcr.val = z_arc_v2_aux_reg_read(_ARC_V2_CONNECT_BCR); + + if (bcr.dbg) { + /* configure inter-core debug unit if available */ + arc_connect_debug_mask_update(ARC_MP_PRIMARY_CPU_ID); + } + + if (bcr.ipi) { + /* register ici interrupt, just need master core to register once */ + z_arc_connect_ici_clear(); + IRQ_CONNECT(DT_IRQN(DT_NODELABEL(ici)), + DT_IRQ(DT_NODELABEL(ici), priority), + sched_ipi_handler, NULL, 0); + + irq_enable(DT_IRQN(DT_NODELABEL(ici))); + } else { + __ASSERT(0, + "ARC connect has no inter-core interrupt\n"); + return -ENODEV; + } + + if (bcr.gfrc) { + /* global free running count init */ + z_arc_connect_gfrc_enable(); + + /* when all cores halt, gfrc halt */ + z_arc_connect_gfrc_core_set((1 << arch_num_cpus()) - 1); + z_arc_connect_gfrc_clear(); + } else { + __ASSERT(0, + "ARC connect has no global free running counter\n"); + return -ENODEV; + } + + return 0; +} +SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/arch/arc/core/thread.c b/arch/arc/core/thread.c index eeb12d45f6a..56340120143 100644 --- a/arch/arc/core/thread.c +++ b/arch/arc/core/thread.c @@ -19,7 +19,7 @@ #include #endif -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) #include static struct k_spinlock lock; #endif @@ -297,7 +297,7 @@ FUNC_NORETURN void z_arc_switch_to_main_no_multithreading(k_thread_entry_t main_ } #endif /* !CONFIG_MULTITHREADING */ -#if defined(CONFIG_ARC_DSP) && defined(CONFIG_ARC_DSP_SHARING) +#if defined(CONFIG_ARC_DSP) && defined(CONFIG_DSP_SHARING) void arc_dsp_disable(struct k_thread *thread, unsigned int options) { /* Ensure a preemptive context switch does not occur */ @@ -319,4 +319,4 @@ void arc_dsp_enable(struct k_thread *thread, unsigned int options) k_spin_unlock(&lock, key); } -#endif /* CONFIG_ARC_DSP && CONFIG_ARC_DSP_SHARING */ +#endif /* CONFIG_ARC_DSP && CONFIG_DSP_SHARING */ diff --git a/arch/arc/include/kernel_arch_data.h b/arch/arc/include/kernel_arch_data.h index 14f7869763f..efe2bd7d1c6 100644 --- a/arch/arc/include/kernel_arch_data.h +++ b/arch/arc/include/kernel_arch_data.h @@ -160,7 +160,7 @@ struct _callee_saved_stack { #endif #endif -#ifdef CONFIG_ARC_DSP_SHARING +#ifdef CONFIG_DSP_SHARING #ifdef CONFIG_ARC_DSP_BFLY_SHARING uintptr_t dsp_fft_ctrl; uintptr_t dsp_bfly0; diff --git a/arch/arc/include/vector_table.h b/arch/arc/include/vector_table.h index fc828c7ddaf..1d7b1ca1220 100644 --- a/arch/arc/include/vector_table.h +++ b/arch/arc/include/vector_table.h @@ -46,7 +46,7 @@ GTEXT(__ev_div_zero) GTEXT(__ev_dc_error) GTEXT(__ev_maligned) -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(_isr_wrapper) #else diff --git a/arch/arm/core/CMakeLists.txt b/arch/arm/core/CMakeLists.txt index 1b4fa58eae5..922dab2ddba 100644 --- a/arch/arm/core/CMakeLists.txt +++ b/arch/arm/core/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) zephyr_library_sources_ifdef(CONFIG_ARM_ZIMAGE_HEADER header.S) zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c) +zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M cortex_m) add_subdirectory_ifdef(CONFIG_CPU_CORTEX_M_HAS_CMSE cortex_m/cmse) @@ -34,3 +35,11 @@ else() zephyr_linker_sources(ROM_START SORT_KEY 0x0vectors vector_table.ld) zephyr_linker_sources(ROM_START SORT_KEY 0x1vectors cortex_m/vector_table_pad.ld) endif() + +if(CONFIG_GEN_SW_ISR_TABLE) + if(CONFIG_DYNAMIC_INTERRUPTS) + zephyr_linker_sources(RWDATA swi_tables.ld) + else() + zephyr_linker_sources(RODATA swi_tables.ld) + endif() +endif() diff --git a/arch/arm/core/Kconfig b/arch/arm/core/Kconfig index 4afe6c06ab5..e446eb25c1d 100644 --- a/arch/arm/core/Kconfig +++ b/arch/arm/core/Kconfig @@ -58,9 +58,18 @@ config CPU_AARCH32_CORTEX_A select ARCH_HAS_EXTRA_EXCEPTION_INFO if !USE_SWITCH select ARCH_HAS_NOCACHE_MEMORY_SUPPORT select USE_SWITCH_SUPPORTED + # GDBSTUB has not yet been tested on Cortex M or R SoCs + select ARCH_HAS_GDBSTUB + # GDB on ARM needs the etxra registers + select EXTRA_EXCEPTION_INFO if GDBSTUB help This option signifies the use of a CPU of the Cortex-A family. +config GDBSTUB_BUF_SZ + # GDB for ARM expects up to 18 4-byte plus 8 12-byte + # registers - 336 HEX letters + default 350 if GDBSTUB + config ISA_THUMB2 bool help @@ -273,8 +282,6 @@ config FP_HARDABI point instructions are generated and uses FPU-specific calling conventions. - Note: When building with TF-M enabled only the IPC mode is supported. - config FP_SOFTABI bool "Floating point Soft ABI" help diff --git a/arch/arm/core/cortex_a_r/fault.c b/arch/arm/core/cortex_a_r/fault.c index 4b1624cd54b..a39efeb96e0 100644 --- a/arch/arm/core/cortex_a_r/fault.c +++ b/arch/arm/core/cortex_a_r/fault.c @@ -10,6 +10,11 @@ #include #include #include +#if defined(CONFIG_GDBSTUB) +#include +#include +#endif + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #define FAULT_DUMP_VERBOSE (CONFIG_FAULT_DUMP == 2) @@ -213,6 +218,12 @@ bool z_arm_fault_undef_instruction(z_arch_esf_t *esf) z_arm_fpu_caller_save(&esf->fpu); #endif +#if defined(CONFIG_GDBSTUB) + z_gdb_entry(esf, GDB_EXCEPTION_INVALID_INSTRUCTION); + /* Might not be fatal if GDB stub placed it in the code. */ + return false; +#endif + /* Print fault information */ LOG_ERR("***** UNDEFINED INSTRUCTION ABORT *****"); @@ -247,6 +258,17 @@ bool z_arm_fault_prefetch(z_arch_esf_t *esf) /* Read Instruction Fault Address Register (IFAR) */ uint32_t ifar = __get_IFAR(); +#if defined(CONFIG_GDBSTUB) + /* The BKPT instruction could have caused a software breakpoint */ + if (fs == IFSR_DEBUG_EVENT) { + /* Debug event, call the gdbstub handler */ + z_gdb_entry(esf, GDB_EXCEPTION_BREAKPOINT); + } else { + /* Fatal */ + z_gdb_entry(esf, GDB_EXCEPTION_MEMORY_FAULT); + } + return false; +#endif /* Print fault information*/ LOG_ERR("***** PREFETCH ABORT *****"); if (FAULT_DUMP_VERBOSE) { @@ -314,6 +336,12 @@ bool z_arm_fault_data(z_arch_esf_t *esf) /* Read Data Fault Address Register (DFAR) */ uint32_t dfar = __get_DFAR(); +#if defined(CONFIG_GDBSTUB) + z_gdb_entry(esf, GDB_EXCEPTION_MEMORY_FAULT); + /* return false - non-fatal error */ + return false; +#endif + #if defined(CONFIG_USERSPACE) if ((fs == COND_CODE_1(CONFIG_AARCH32_ARMV8_R, (FSR_FS_TRANSLATION_FAULT), diff --git a/arch/arm/core/cortex_a_r/prep_c.c b/arch/arm/core/cortex_a_r/prep_c.c index 95dbb49cf1e..e510d06ee95 100644 --- a/arch/arm/core/cortex_a_r/prep_c.c +++ b/arch/arm/core/cortex_a_r/prep_c.c @@ -145,7 +145,7 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. * */ -void z_arm_prep_c(void) +void z_prep_c(void) { /* Initialize tpidruro with our struct _cpu instance address */ write_tpidruro((uintptr_t)&_kernel.cpus[0]); diff --git a/arch/arm/core/cortex_a_r/reset.S b/arch/arm/core/cortex_a_r/reset.S index ff3c35e0f18..0b107fbf596 100644 --- a/arch/arm/core/cortex_a_r/reset.S +++ b/arch/arm/core/cortex_a_r/reset.S @@ -42,7 +42,7 @@ GTEXT(z_arm_platform_init) * and interrupts are disabled. The processor architectural registers are in * an indeterminate state. * - * When these steps are completed, jump to z_arm_prep_c(), which will finish + * When these steps are completed, jump to z_prep_c(), which will finish * setting up the system for running C code. * */ @@ -217,7 +217,7 @@ EL1_Reset_Handler: bne 1b /* we can now move on */ - ldr r4, =z_arm_secondary_start + ldr r4, =arch_secondary_cpu_init ldr r5, [r0, #BOOT_PARAM_FIQ_SP_OFFSET] ldr r6, [r0, #BOOT_PARAM_IRQ_SP_OFFSET] ldr r7, [r0, #BOOT_PARAM_ABT_SP_OFFSET] @@ -229,7 +229,7 @@ EL1_Reset_Handler: _primary_core: #endif - ldr r4, =z_arm_prep_c + ldr r4, =z_prep_c ldr r5, =(z_arm_fiq_stack + CONFIG_ARMV7_FIQ_STACK_SIZE) ldr r6, =(z_interrupt_stacks + CONFIG_ISR_STACK_SIZE) ldr r7, =(z_arm_abort_stack + CONFIG_ARMV7_EXCEPTION_STACK_SIZE) diff --git a/arch/arm/core/cortex_a_r/smp.c b/arch/arm/core/cortex_a_r/smp.c index 2aeb36c1735..f581c770310 100644 --- a/arch/arm/core/cortex_a_r/smp.c +++ b/arch/arm/core/cortex_a_r/smp.c @@ -148,7 +148,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_ * \todo Support PSCI */ - /* Wait secondary cores up, see z_arm64_secondary_start */ + /* Wait secondary cores up, see arch_secondary_cpu_init */ while (arm_cpu_boot_params.fn) { wfe(); } @@ -159,7 +159,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_ } /* the C entry of secondary cores */ -void z_arm_secondary_start(void) +void arch_secondary_cpu_init(void) { int cpu_num = arm_cpu_boot_params.cpu_num; arch_cpustart_t fn; @@ -245,7 +245,7 @@ void arch_sched_ipi(void) broadcast_ipi(SGI_SCHED_IPI); } -static int arm_smp_init(void) +int arch_smp_init(void) { cpu_map[0] = MPIDR_TO_CORE(GET_MPIDR()); @@ -259,6 +259,6 @@ static int arm_smp_init(void) return 0; } -SYS_INIT(arm_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/arch/arm/core/cortex_a_r/vector_table.h b/arch/arm/core/cortex_a_r/vector_table.h index 7d2122b4828..449b6044d9c 100644 --- a/arch/arm/core/cortex_a_r/vector_table.h +++ b/arch/arm/core/cortex_a_r/vector_table.h @@ -40,7 +40,7 @@ GTEXT(z_arm_data_abort) GTEXT(z_arm_pendsv) GTEXT(z_arm_reserved) -GTEXT(z_arm_prep_c) +GTEXT(z_prep_c) GTEXT(_isr_wrapper) #else /* _ASMLANGUAGE */ diff --git a/arch/arm/core/cortex_m/Kconfig b/arch/arm/core/cortex_m/Kconfig index 95e05604783..e2a0fbb42da 100644 --- a/arch/arm/core/cortex_m/Kconfig +++ b/arch/arm/core/cortex_m/Kconfig @@ -78,8 +78,6 @@ config CPU_CORTEX_M7 select CPU_CORTEX_M select ARMV7_M_ARMV8_M_MAINLINE select ARMV7_M_ARMV8_M_FP if CPU_HAS_FPU - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a Cortex-M7 CPU @@ -283,7 +281,20 @@ config ARMV8_1_M_MVEF supporting the M-Profile Vector Extension (MVE) floating-point instruction set. -menu "ARM Cortex-M0/M0+/M1/M3/M4/M7/M23/M33 options" +config ARMV8_1_M_PMU + bool + help + This option is enabled when the CPU implements ARMv8-M Performance + Monitoring Unit (PMU). + +config ARMV8_M_PMU_EVENTCNT + int "Number of event counters in the Performance Monitoring Unit" + depends on ARMV8_1_M_PMU + range 2 8 + help + The number of event counters implemented. + +menu "ARM Cortex-M0/M0+/M1/M3/M4/M7/M23/M33/M55 options" depends on ARMV6_M_ARMV8_M_BASELINE || ARMV7_M_ARMV8_M_MAINLINE config GEN_ISR_TABLES diff --git a/arch/arm/core/cortex_m/fault.c b/arch/arm/core/cortex_m/fault.c index 1d9feff2e52..5090381fa31 100644 --- a/arch/arm/core/cortex_m/fault.c +++ b/arch/arm/core/cortex_m/fault.c @@ -863,7 +863,7 @@ static uint32_t fault_handle(z_arch_esf_t *esf, int fault, bool *recoverable) break; #if defined(CONFIG_ARM_SECURE_FIRMWARE) case 7: - secure_fault(esf); + reason = secure_fault(esf); break; #endif /* CONFIG_ARM_SECURE_FIRMWARE */ case 12: diff --git a/arch/arm/core/cortex_m/prep_c.c b/arch/arm/core/cortex_m/prep_c.c index 329f7f8987d..422d45b57e1 100644 --- a/arch/arm/core/cortex_m/prep_c.c +++ b/arch/arm/core/cortex_m/prep_c.c @@ -179,7 +179,7 @@ extern FUNC_NORETURN void z_cstart(void); * This routine prepares for the execution of and runs C code. * */ -void z_arm_prep_c(void) +void z_prep_c(void) { relocate_vector_table(); #if defined(CONFIG_CPU_HAS_FPU) diff --git a/arch/arm/core/cortex_m/reset.S b/arch/arm/core/cortex_m/reset.S index 6c5599b9fb8..332f1a60c10 100644 --- a/arch/arm/core/cortex_m/reset.S +++ b/arch/arm/core/cortex_m/reset.S @@ -53,7 +53,7 @@ GTEXT(arch_pm_s2ram_resume) * MSP is to be set up to point to the one-and-only interrupt stack during * later boot. That would not be possible if in use for running C code. * - * When these steps are completed, jump to z_arm_prep_c(), which will finish + * When these steps are completed, jump to z_prep_c(), which will finish * setting up the system for running C code. * */ @@ -163,7 +163,7 @@ SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start) /* * 'bl' jumps the furthest of the branch instructions that are - * supported on all platforms. So it is used when jumping to z_arm_prep_c + * supported on all platforms. So it is used when jumping to z_prep_c * (even though we do not intend to return). */ - bl z_arm_prep_c + bl z_prep_c diff --git a/arch/arm/core/cortex_m/scb.c b/arch/arm/core/cortex_m/scb.c index 472c8242465..e3c35073ea3 100644 --- a/arch/arm/core/cortex_m/scb.c +++ b/arch/arm/core/cortex_m/scb.c @@ -21,6 +21,7 @@ #include #include #include +#include #if defined(CONFIG_CPU_HAS_NXP_MPU) #include @@ -120,15 +121,27 @@ void z_arm_init_arch_hw_at_boot(void) * reset it to a known clean state. */ if (SCB->CCR & SCB_CCR_DC_Msk) { - sys_cache_data_disable(); + /* + * Do not use sys_cache_data_disable at this point, but instead + * the architecture specific function. This ensures that the + * cache is disabled although CONFIG_CACHE_MANAGEMENT might be + * disabled. + */ + SCB_DisableDCache(); } else { - sys_cache_data_invd_all(); + SCB_InvalidateDCache(); } #endif /* CONFIG_DCACHE */ #if defined(CONFIG_ICACHE) - /* Reset I-Cache settings. */ - sys_cache_instr_disable(); + /* + * Reset I-Cache settings. + * Do not use sys_cache_data_disable at this point, but instead + * the architecture specific function. This ensures that the + * cache is disabled although CONFIG_CACHE_MANAGEMENT might be + * disabled. + */ + SCB_DisableICache(); #endif /* CONFIG_ICACHE */ #endif /* CONFIG_ARCH_CACHE */ diff --git a/arch/arm/core/cortex_m/tz/CMakeLists.txt b/arch/arm/core/cortex_m/tz/CMakeLists.txt index 67f7e0ab367..19c67476e40 100644 --- a/arch/arm/core/cortex_m/tz/CMakeLists.txt +++ b/arch/arm/core/cortex_m/tz/CMakeLists.txt @@ -33,9 +33,3 @@ endif() zephyr_link_libraries_ifdef(CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS ${CMAKE_BINARY_DIR}/${CONFIG_ARM_ENTRY_VENEERS_LIB_NAME} ) - -if(CONFIG_ARM_SECURE_FIRMWARE) - zephyr_library() - - zephyr_library_sources(arm_core_tz.c) -endif() diff --git a/arch/arm/core/cortex_m/tz/arm_core_tz.c b/arch/arm/core/cortex_m/tz/arm_core_tz.c deleted file mode 100644 index 8371a08bfef..00000000000 --- a/arch/arm/core/cortex_m/tz/arm_core_tz.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -static void configure_nonsecure_vtor_offset(uint32_t vtor_ns) -{ - SCB_NS->VTOR = vtor_ns; -} - -static void configure_nonsecure_msp(uint32_t msp_ns) -{ - __TZ_set_MSP_NS(msp_ns); -} - -static void configure_nonsecure_psp(uint32_t psp_ns) -{ - __TZ_set_PSP_NS(psp_ns); -} - -static void configure_nonsecure_control(uint32_t spsel_ns, uint32_t npriv_ns) -{ - uint32_t control_ns = __TZ_get_CONTROL_NS(); - - /* Only nPRIV and SPSEL bits are banked between security states. */ - control_ns &= ~(CONTROL_SPSEL_Msk | CONTROL_nPRIV_Msk); - - if (spsel_ns) { - control_ns |= CONTROL_SPSEL_Msk; - } - if (npriv_ns) { - control_ns |= CONTROL_nPRIV_Msk; - } - - __TZ_set_CONTROL_NS(control_ns); -} - -#if defined(CONFIG_ARMV8_M_MAINLINE) - -/* Only ARMv8-M Mainline implementations have Non-Secure instances of - * Stack Pointer Limit registers. - */ - -void tz_nonsecure_msplim_set(uint32_t val) -{ - __TZ_set_MSPLIM_NS(val); -} - -void tz_nonsecure_psplim_set(uint32_t val) -{ - __TZ_set_PSPLIM_NS(val); -} -#endif /* CONFIG_ARMV8_M_MAINLINE */ - -void tz_nonsecure_state_setup(const tz_nonsecure_setup_conf_t *p_ns_conf) -{ - configure_nonsecure_vtor_offset(p_ns_conf->vtor_ns); - configure_nonsecure_msp(p_ns_conf->msp_ns); - configure_nonsecure_psp(p_ns_conf->psp_ns); - /* Select which stack-pointer to use (MSP or PSP) and - * the privilege level for thread mode. - */ - configure_nonsecure_control(p_ns_conf->control_ns.spsel, - p_ns_conf->control_ns.npriv); -} - -void tz_nbanked_exception_target_state_set(int secure_state) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (secure_state) { - aircr_payload &= ~(SCB_AIRCR_BFHFNMINS_Msk); - } else { - aircr_payload |= SCB_AIRCR_BFHFNMINS_Msk; - } - SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -void tz_nonsecure_exception_prio_config(int secure_boost) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (secure_boost) { - aircr_payload |= SCB_AIRCR_PRIS_Msk; - } else { - aircr_payload &= ~(SCB_AIRCR_PRIS_Msk); - } - SCB->AIRCR = ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -void tz_nonsecure_system_reset_req_block(int block) -{ - uint32_t aircr_payload = SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk)); - if (block) { - aircr_payload |= SCB_AIRCR_SYSRESETREQS_Msk; - } else { - aircr_payload &= ~(SCB_AIRCR_SYSRESETREQS_Msk); - } - SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) - & SCB_AIRCR_VECTKEY_Msk) - | aircr_payload; -} - -#if defined(CONFIG_ARMV7_M_ARMV8_M_FP) -void tz_nonsecure_fpu_access_enable(void) -{ - SCB->NSACR |= - (1UL << SCB_NSACR_CP10_Pos) | (1UL << SCB_NSACR_CP11_Pos); -} -#endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ - -void tz_sau_configure(int enable, int allns) -{ - if (enable) { - TZ_SAU_Enable(); - } else { - TZ_SAU_Disable(); - if (allns) { - SAU->CTRL |= SAU_CTRL_ALLNS_Msk; - } else { - SAU->CTRL &= ~(SAU_CTRL_ALLNS_Msk); - } - } -} - -uint32_t tz_sau_number_of_regions_get(void) -{ - return SAU->TYPE & SAU_TYPE_SREGION_Msk; -} - -#if defined(CONFIG_CPU_HAS_ARM_SAU) -#if defined (__SAUREGION_PRESENT) && (__SAUREGION_PRESENT == 1U) -int tz_sau_region_configure_enable(tz_sau_conf_t *p_sau_conf) -{ - uint32_t regions = tz_sau_number_of_regions_get(); - - if ((p_sau_conf->region_num == 0) || - (p_sau_conf->region_num > (regions - 1))) { - return 0; - } - - /* Valid region */ - SAU->RNR = p_sau_conf->region_num & SAU_RNR_REGION_Msk; - - if (p_sau_conf->enable) { - SAU->RLAR = SAU_RLAR_ENABLE_Msk - | (SAU_RLAR_LADDR_Msk & p_sau_conf->limit_addr) - | (p_sau_conf->nsc ? SAU_RLAR_NSC_Msk : 0); - SAU->RBAR = p_sau_conf->base_addr & SAU_RBAR_BADDR_Msk; - } else { - SAU->RLAR &= ~(SAU_RLAR_ENABLE_Msk); - } - - return 1; -} -#else -#error "ARM SAU not implemented" -#endif -#endif /* CONFIG_CPU_HAS_ARM_SAU */ diff --git a/arch/arm/core/cortex_m/vector_table.h b/arch/arm/core/cortex_m/vector_table.h index f79765aefbf..a10663b4821 100644 --- a/arch/arm/core/cortex_m/vector_table.h +++ b/arch/arm/core/cortex_m/vector_table.h @@ -50,7 +50,7 @@ GTEXT(z_arm_debug_monitor) GTEXT(z_arm_pendsv) GTEXT(z_arm_exc_spurious) -GTEXT(z_arm_prep_c) +GTEXT(z_prep_c) #if defined(CONFIG_GEN_ISR_TABLES) GTEXT(_isr_wrapper) #endif /* CONFIG_GEN_ISR_TABLES */ diff --git a/arch/arm/core/fatal.c b/arch/arm/core/fatal.c index c053bb53e4a..c5adebf8ee7 100644 --- a/arch/arm/core/fatal.c +++ b/arch/arm/core/fatal.c @@ -17,6 +17,7 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#ifdef CONFIG_EXCEPTION_DEBUG static void esf_dump(const z_arch_esf_t *esf) { LOG_ERR("r0/a1: 0x%08x r1/a2: 0x%08x r2/a3: 0x%08x", @@ -63,13 +64,15 @@ static void esf_dump(const z_arch_esf_t *esf) LOG_ERR("Faulting instruction address (r15/pc): 0x%08x", esf->basic.pc); } +#endif /* CONFIG_EXCEPTION_DEBUG */ void z_arm_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { - +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { esf_dump(esf); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } diff --git a/arch/arm/core/gdbstub.c b/arch/arm/core/gdbstub.c new file mode 100644 index 00000000000..5386cfa619f --- /dev/null +++ b/arch/arm/core/gdbstub.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2023 Marek Vedral + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/* Position of each register in the packet - n-th register in the ctx.registers array needs to be + * the packet_pos[n]-th byte of the g (read all registers) packet. See struct arm_register_names in + * GDB file gdb/arm-tdep.c, which defines these positions. + */ +static const int packet_pos[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 41}; + +/* Required struct */ +static struct gdb_ctx ctx; + +/* Return true if BKPT instruction caused the current entry */ +static int is_bkpt(unsigned int exc_cause) +{ + int ret = 0; + + if (exc_cause == GDB_EXCEPTION_BREAKPOINT) { + /* Get the instruction */ + unsigned int instr = sys_read32(ctx.registers[PC]); + /* Try to check the instruction encoding */ + int ist = ((ctx.registers[SPSR] & BIT(SPSR_J)) >> (SPSR_J - 1)) | + ((ctx.registers[SPSR] & BIT(SPSR_T)) >> SPSR_T); + + if (ist == SPSR_ISETSTATE_ARM) { + /* ARM instruction set state */ + ret = ((instr & 0xFF00000) == 0x1200000) && ((instr & 0xF0) == 0x70); + } else if (ist != SPSR_ISETSTATE_JAZELLE) { + /* Thumb or ThumbEE encoding */ + ret = ((instr & 0xFF00) == 0xBE00); + } + } + return ret; +} + +/* Wrapper function to save and restore execution c */ +void z_gdb_entry(z_arch_esf_t *esf, unsigned int exc_cause) +{ + /* Disable the hardware breakpoint in case it was set */ + __asm__ volatile("mcr p14, 0, %0, c0, c0, 5" ::"r"(0x0) :); + + ctx.exception = exc_cause; + /* save the registers */ + ctx.registers[R0] = esf->basic.r0; + ctx.registers[R1] = esf->basic.r1; + ctx.registers[R2] = esf->basic.r2; + ctx.registers[R3] = esf->basic.r3; + /* The EXTRA_EXCEPTION_INFO kernel option ensures these regs are set */ + ctx.registers[R4] = esf->extra_info.callee->v1; + ctx.registers[R5] = esf->extra_info.callee->v2; + ctx.registers[R6] = esf->extra_info.callee->v3; + ctx.registers[R7] = esf->extra_info.callee->v4; + ctx.registers[R8] = esf->extra_info.callee->v5; + ctx.registers[R9] = esf->extra_info.callee->v6; + ctx.registers[R10] = esf->extra_info.callee->v7; + ctx.registers[R11] = esf->extra_info.callee->v8; + ctx.registers[R13] = esf->extra_info.callee->psp; + + ctx.registers[R12] = esf->basic.r12; + ctx.registers[LR] = esf->basic.lr; + ctx.registers[PC] = esf->basic.pc; + ctx.registers[SPSR] = esf->basic.xpsr; + + /* True if entering after a BKPT instruction */ + const int bkpt_entry = is_bkpt(exc_cause); + + z_gdb_main_loop(&ctx); + + /* The registers part of EXTRA_EXCEPTION_INFO are read-only - the excpetion return code + * does not restore them, thus we don't need to do so here + */ + esf->basic.r0 = ctx.registers[R0]; + esf->basic.r1 = ctx.registers[R1]; + esf->basic.r2 = ctx.registers[R2]; + esf->basic.r3 = ctx.registers[R3]; + esf->basic.r12 = ctx.registers[R12]; + esf->basic.lr = ctx.registers[LR]; + esf->basic.pc = ctx.registers[PC]; + esf->basic.xpsr = ctx.registers[SPSR]; + /* TODO: restore regs from extra exc. info */ + + if (bkpt_entry) { + /* Apply this offset, so that the process won't be affected by the + * BKPT instruction + */ + esf->basic.pc += 0x4; + } + esf->basic.xpsr = ctx.registers[SPSR]; +} + +void arch_gdb_init(void) +{ + uint32_t reg_val; + /* Enable the monitor debug mode */ + __asm__ volatile("mrc p14, 0, %0, c0, c2, 2" : "=r"(reg_val)::); + reg_val |= DBGDSCR_MONITOR_MODE_EN; + __asm__ volatile("mcr p14, 0, %0, c0, c2, 2" ::"r"(reg_val) :); + + /* Generate the Prefetch abort exception */ + __asm__ volatile("BKPT"); +} + +void arch_gdb_continue(void) +{ + /* No need to do anything, return to the code. */ +} + +void arch_gdb_step(void) +{ + /* Set the hardware breakpoint */ + uint32_t reg_val = ctx.registers[PC]; + /* set BVR (Breakpoint value register) to PC, make sure it is word aligned */ + reg_val &= ~(0x3); + __asm__ volatile("mcr p14, 0, %0, c0, c0, 4" ::"r"(reg_val) :); + + reg_val = 0; + /* Address mismatch */ + reg_val |= (DBGDBCR_MEANING_ADDR_MISMATCH & DBGDBCR_MEANING_MASK) << DBGDBCR_MEANING_SHIFT; + /* Match any other instruction */ + reg_val |= (0xF & DBGDBCR_BYTE_ADDR_MASK) << DBGDBCR_BYTE_ADDR_SHIFT; + /* Breakpoint enable */ + reg_val |= DBGDBCR_BRK_EN_MASK; + __asm__ volatile("mcr p14, 0, %0, c0, c0, 5" ::"r"(reg_val) :); +} + +size_t arch_gdb_reg_readall(struct gdb_ctx *c, uint8_t *buf, size_t buflen) +{ + int ret = 0; + /* All other registers are not supported */ + memset(buf, 'x', buflen); + for (int i = 0; i < GDB_NUM_REGS; i++) { + /* offset inside the packet */ + int pos = packet_pos[i] * 8; + int r = bin2hex((const uint8_t *)(c->registers + i), 4, buf + pos, buflen - pos); + /* remove the newline character placed by the bin2hex function */ + buf[pos + 8] = 'x'; + if (r == 0) { + ret = 0; + break; + } + ret += r; + } + + if (ret) { + /* Since we don't support some floating point registers, set the packet size + * manually + */ + ret = GDB_READALL_PACKET_SIZE; + } + return ret; +} + +size_t arch_gdb_reg_writeall(struct gdb_ctx *c, uint8_t *hex, size_t hexlen) +{ + int ret = 0; + + for (unsigned int i = 0; i < hexlen; i += 8) { + if (hex[i] != 'x') { + /* check if the stub supports this register */ + for (unsigned int j = 0; j < GDB_NUM_REGS; j++) { + if (packet_pos[j] != i) { + continue; + } + int r = hex2bin(hex + i * 8, 8, (uint8_t *)(c->registers + j), 4); + + if (r == 0) { + return 0; + } + ret += r; + } + } + } + return ret; +} + +size_t arch_gdb_reg_readone(struct gdb_ctx *c, uint8_t *buf, size_t buflen, uint32_t regno) +{ + /* Reading four bytes (could be any return value except 0, which would indicate an error) */ + int ret = 4; + /* Fill the buffer with 'x' in case the stub does not support the required register */ + memset(buf, 'x', 8); + if (regno == SPSR_REG_IDX) { + /* The SPSR register is at the end, we have to check separately */ + ret = bin2hex((uint8_t *)(c->registers + GDB_NUM_REGS - 1), 4, buf, buflen); + } else { + /* Check which of our registers corresponds to regnum */ + for (int i = 0; i < GDB_NUM_REGS; i++) { + if (packet_pos[i] == regno) { + ret = bin2hex((uint8_t *)(c->registers + i), 4, buf, buflen); + break; + } + } + } + return ret; +} + +size_t arch_gdb_reg_writeone(struct gdb_ctx *c, uint8_t *hex, size_t hexlen, uint32_t regno) +{ + int ret = 0; + /* Set the value of a register */ + if (hexlen != 8) { + return ret; + } + + if (regno < (GDB_NUM_REGS - 1)) { + /* Again, check the corresponding register index */ + for (int i = 0; i < GDB_NUM_REGS; i++) { + if (packet_pos[i] == regno) { + ret = hex2bin(hex, hexlen, (uint8_t *)(c->registers + i), 4); + break; + } + } + } else if (regno == SPSR_REG_IDX) { + ret = hex2bin(hex, hexlen, (uint8_t *)(c->registers + GDB_NUM_REGS - 1), 4); + } + return ret; +} diff --git a/arch/arm/core/mmu/arm_mmu.c b/arch/arm/core/mmu/arm_mmu.c index 77c79fdfc3d..f37b4354d46 100644 --- a/arch/arm/core/mmu/arm_mmu.c +++ b/arch/arm/core/mmu/arm_mmu.c @@ -81,7 +81,14 @@ static const struct arm_mmu_flat_range mmu_zephyr_ranges[] = { .start = (uint32_t)__text_region_start, .end = (uint32_t)__text_region_end, .attrs = MT_NORMAL | MATTR_SHARED | + /* The code needs to have write permission in order for + * software breakpoints (which modify instructions) to work + */ +#if defined(CONFIG_GDBSTUB) + MPERM_R | MPERM_X | MPERM_W | +#else MPERM_R | MPERM_X | +#endif MATTR_CACHE_OUTER_WB_nWA | MATTR_CACHE_INNER_WB_nWA | MATTR_MAY_MAP_L1_SECTION}, diff --git a/arch/arm/core/mpu/arm_core_mpu_dev.h b/arch/arm/core/mpu/arm_core_mpu_dev.h index ec0126e6e9b..fd56131d7dc 100644 --- a/arch/arm/core/mpu/arm_core_mpu_dev.h +++ b/arch/arm/core/mpu/arm_core_mpu_dev.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ #include #include @@ -269,4 +269,4 @@ int arm_core_mpu_buffer_validate(void *addr, size_t size, int write); } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MPU_ARM_CORE_MPU_DEV_H_ */ diff --git a/arch/arm/core/mpu/arm_mpu.c b/arch/arm/core/mpu/arm_mpu.c index 9b2feffe5ee..cd4c8ccd7a0 100644 --- a/arch/arm/core/mpu/arm_mpu.c +++ b/arch/arm/core/mpu/arm_mpu.c @@ -30,10 +30,6 @@ LOG_MODULE_DECLARE(mpu); #define MPU_NODEID DT_INST(0, arm_armv6m_mpu) #endif -#if DT_NODE_HAS_PROP(MPU_NODEID, arm_num_mpu_regions) -#define NUM_MPU_REGIONS DT_PROP(MPU_NODEID, arm_num_mpu_regions) -#endif - #define NODE_HAS_PROP_AND_OR(node_id, prop) \ DT_NODE_HAS_PROP(node_id, prop) || @@ -463,6 +459,11 @@ int z_arm_mpu_init(void) return -EINVAL; } + /* Clear all regions before enabling MPU */ + for (int i = static_regions_num; i < get_num_regions(); i++) { + mpu_clear_region(i); + } + arm_core_mpu_enable(); /* Program additional fixed flash region for null-pointer @@ -527,11 +528,6 @@ int z_arm_mpu_init(void) __ASSERT( (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == 8, "Invalid number of MPU regions\n"); -#elif defined(NUM_MPU_REGIONS) - __ASSERT( - (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == - NUM_MPU_REGIONS, - "Invalid number of MPU regions\n"); #endif /* CORTEX_M0PLUS || CPU_CORTEX_M3 || CPU_CORTEX_M4 */ return 0; diff --git a/arch/arm/core/mpu/arm_mpu_v7_internal.h b/arch/arm/core/mpu/arm_mpu_v7_internal.h index 508d1b67600..1fe3417901e 100644 --- a/arch/arm/core/mpu/arm_mpu_v7_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v7_internal.h @@ -269,4 +269,9 @@ static int mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition return mpu_reg_index; } +static inline void mpu_clear_region(uint32_t rnr) +{ + ARM_MPU_ClrRegion(rnr); +} + #endif /* ZEPHYR_ARCH_ARM_CORE_AARCH32_MPU_ARM_MPU_V7_INTERNAL_H_ */ diff --git a/arch/arm/core/mpu/arm_mpu_v8_internal.h b/arch/arm/core/mpu/arm_mpu_v8_internal.h index 1f7cb04839e..751786d5a4c 100644 --- a/arch/arm/core/mpu/arm_mpu_v8_internal.h +++ b/arch/arm/core/mpu/arm_mpu_v8_internal.h @@ -720,12 +720,7 @@ static int mpu_mark_areas_for_dynamic_regions( */ static inline uint8_t get_num_regions(void) { -#if defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else return mpu_get_num_regions(); -#endif /* NUM_MPU_REGIONS */ } /* This internal function programs the dynamic MPU regions. diff --git a/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h b/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h index a0f7d174436..636bce50fae 100644 --- a/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h +++ b/arch/arm/core/mpu/cortex_a_r/arm_mpu_internal.h @@ -10,10 +10,6 @@ */ static inline uint8_t get_num_regions(void) { -#if defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else uint32_t type; __asm__ volatile("mrc p15, 0, %0, c0, c0, 4" : "=r" (type) ::); @@ -21,7 +17,6 @@ static inline uint8_t get_num_regions(void) type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; return (uint8_t)type; -#endif /* NUM_MPU_REGIONS */ } static inline uint32_t get_region_attributes(void) diff --git a/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h b/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h index 337f7ac3657..297eb38bf65 100644 --- a/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h +++ b/arch/arm/core/mpu/cortex_m/arm_mpu_internal.h @@ -10,23 +10,11 @@ */ static inline uint8_t get_num_regions(void) { -#if defined(CONFIG_CPU_CORTEX_M0PLUS) || \ - defined(CONFIG_CPU_CORTEX_M3) || \ - defined(CONFIG_CPU_CORTEX_M4) - /* Cortex-M0+, Cortex-M3, and Cortex-M4 MCUs may - * have a fixed number of 8 MPU regions. - */ - return 8; -#elif defined(NUM_MPU_REGIONS) - /* Retrieve the number of regions from DTS configuration. */ - return NUM_MPU_REGIONS; -#else uint32_t type = MPU->TYPE; type = (type & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; return (uint8_t)type; -#endif /* CPU_CORTEX_M0PLUS | CPU_CORTEX_M3 | CPU_CORTEX_M4 */ } static inline void set_region_number(uint32_t index) diff --git a/arch/arm/core/swi_tables.ld b/arch/arm/core/swi_tables.ld new file mode 100644 index 00000000000..a5dd3eaf652 --- /dev/null +++ b/arch/arm/core/swi_tables.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) +INCLUDE isr_tables_swi.ld +#endif diff --git a/arch/arm/core/userspace.S b/arch/arm/core/userspace.S index bf89c7d663d..3594940078d 100644 --- a/arch/arm/core/userspace.S +++ b/arch/arm/core/userspace.S @@ -12,7 +12,7 @@ #include #include -#include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) #include diff --git a/arch/arm/core/vector_table.ld b/arch/arm/core/vector_table.ld index 615067dbf74..463e389de9f 100644 --- a/arch/arm/core/vector_table.ld +++ b/arch/arm/core/vector_table.ld @@ -51,6 +51,10 @@ _vector_start = .; KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) +INCLUDE isr_tables_vt.ld +#else KEEP(*(.vectors)) +#endif _vector_end = .; diff --git a/arch/arm/include/cortex_a_r/exc.h b/arch/arm/include/cortex_a_r/exc.h deleted file mode 100644 index 6cddaa1c72c..00000000000 --- a/arch/arm/include/cortex_a_r/exc.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 Lexmark International, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Exception/interrupt context helpers for Cortex-A and Cortex-R CPUs - * - * Exception/interrupt context helpers. - */ - -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ - -#include - -#ifdef _ASMLANGUAGE - -/* nothing */ - -#else - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef CONFIG_IRQ_OFFLOAD -extern volatile irq_offload_routine_t offload_routine; -#endif - -/* Check the CPSR mode bits to see if we are in IRQ or FIQ mode */ -static ALWAYS_INLINE bool arch_is_in_isr(void) -{ - return (arch_curr_cpu()->nested != 0U); -} - -static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) -{ - return (arch_curr_cpu()->arch.exc_depth > 1U) ? (true) : (false); -} - -#if defined(CONFIG_USERSPACE) -/* - * This function is used by privileged code to determine if the thread - * associated with the stack frame is in user mode. - */ -static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t *esf) -{ - return ((esf->basic.xpsr & CPSR_M_Msk) == CPSR_M_USR); -} -#endif - -#ifndef CONFIG_USE_SWITCH -extern void z_arm_cortex_r_svc(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_A_R_EXC_H_ */ diff --git a/arch/arm/include/cortex_a_r/exception.h b/arch/arm/include/cortex_a_r/exception.h new file mode 100644 index 00000000000..7519016176c --- /dev/null +++ b/arch/arm/include/cortex_a_r/exception.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 Lexmark International, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Exception/interrupt context helpers for Cortex-A and Cortex-R CPUs + * + * Exception/interrupt context helpers. + */ + +#ifndef ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ + +#include + +#ifdef _ASMLANGUAGE + +/* nothing */ + +#else + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_IRQ_OFFLOAD +extern volatile irq_offload_routine_t offload_routine; +#endif + +/* Check the CPSR mode bits to see if we are in IRQ or FIQ mode */ +static ALWAYS_INLINE bool arch_is_in_isr(void) +{ + return (arch_curr_cpu()->nested != 0U); +} + +static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) +{ + return (arch_curr_cpu()->arch.exc_depth > 1U) ? (true) : (false); +} + +#if defined(CONFIG_USERSPACE) +/* + * This function is used by privileged code to determine if the thread + * associated with the stack frame is in user mode. + */ +static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t *esf) +{ + return ((esf->basic.xpsr & CPSR_M_Msk) == CPSR_M_USR); +} +#endif + +#ifndef CONFIG_USE_SWITCH +extern void z_arm_cortex_r_svc(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_A_R_EXCEPTION_H_ */ diff --git a/arch/arm/include/cortex_m/exc.h b/arch/arm/include/cortex_m/exc.h deleted file mode 100644 index b46e74341a9..00000000000 --- a/arch/arm/include/cortex_m/exc.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Exception/interrupt context helpers for Cortex-M CPUs - * - * Exception/interrupt context helpers. - */ - -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ - -#include - -#ifdef _ASMLANGUAGE - -/* nothing */ - -#else - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef CONFIG_IRQ_OFFLOAD -extern volatile irq_offload_routine_t offload_routine; -#endif - -/* Writes to the AIRCR must be accompanied by a write of the value 0x05FA - * to the Vector Key field, otherwise the writes are ignored. - */ -#define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL - -/* - * The current executing vector is found in the IPSR register. All - * IRQs and system exceptions are considered as interrupt context. - */ -static ALWAYS_INLINE bool arch_is_in_isr(void) -{ - return (__get_IPSR()) ? (true) : (false); -} - -/** - * @brief Find out if we were in ISR context - * before the current exception occurred. - * - * A function that determines, based on inspecting the current - * ESF, whether the processor was in handler mode before entering - * the current exception state (i.e. nested exception) or not. - * - * Notes: - * - The function shall only be called from ISR context. - * - We do not use ARM processor state flags to determine - * whether we are in a nested exception; we rely on the - * RETPSR value stacked on the ESF. Hence, the function - * assumes that the ESF stack frame has a valid RETPSR - * value. - * - * @param esf the exception stack frame (cannot be NULL) - * @return true if execution state was in handler mode, before - * the current exception occurred, otherwise false. - */ -static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) -{ - return (esf->basic.xpsr & IPSR_ISR_Msk) ? (true) : (false); -} - -#if defined(CONFIG_USERSPACE) -/** - * @brief Is the thread in unprivileged mode - * - * @param esf the exception stack frame (unused) - * @return true if the current thread was in unprivileged mode - */ -static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t *esf) -{ - return z_arm_thread_is_in_user_mode(); -} -#endif - -/** - * @brief Setup system exceptions - * - * Set exception priorities to conform with the BASEPRI locking mechanism. - * Set PendSV priority to lowest possible. - * - * Enable fault exceptions. - */ -static ALWAYS_INLINE void z_arm_exc_setup(void) -{ - /* PendSV is set to lowest priority, regardless of it being used. - * This is done as the IRQ is always enabled. - */ - NVIC_SetPriority(PendSV_IRQn, _EXC_PENDSV_PRIO); - -#ifdef CONFIG_CPU_CORTEX_M_HAS_BASEPRI - /* Note: SVCall IRQ priority level is left to default (0) - * for Cortex-M variants without BASEPRI (e.g. ARMv6-M). - */ - NVIC_SetPriority(SVCall_IRQn, _EXC_SVC_PRIO); -#endif - -#ifdef CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS - NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO); - NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO); - NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO); -#if defined(CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK) - NVIC_SetPriority(DebugMonitor_IRQn, IRQ_PRIO_LOWEST); -#elif defined(CONFIG_CPU_CORTEX_M_HAS_DWT) - NVIC_SetPriority(DebugMonitor_IRQn, _EXC_FAULT_PRIO); -#endif -#if defined(CONFIG_ARM_SECURE_FIRMWARE) - NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO); -#endif /* CONFIG_ARM_SECURE_FIRMWARE */ - - /* Enable Usage, Mem, & Bus Faults */ - SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | - SCB_SHCSR_BUSFAULTENA_Msk; -#if defined(CONFIG_ARM_SECURE_FIRMWARE) - /* Enable Secure Fault */ - SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; - /* Clear BFAR before setting BusFaults to target Non-Secure state. */ - SCB->BFAR = 0; -#endif /* CONFIG_ARM_SECURE_FIRMWARE */ -#endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */ - -#if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ - !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) - /* Set NMI, Hard, and Bus Faults as Non-Secure. - * NMI and Bus Faults targeting the Secure state will - * escalate to a SecureFault or SecureHardFault. - */ - SCB->AIRCR = - (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) - | SCB_AIRCR_BFHFNMINS_Msk - | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & - SCB_AIRCR_VECTKEY_Msk); - /* Note: Fault conditions that would generate a SecureFault - * in a PE with the Main Extension instead generate a - * SecureHardFault in a PE without the Main Extension. - */ -#endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */ - -#if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && \ - !defined(CONFIG_CORTEX_M_SYSTICK) - /* SoC implements SysTick, but the system does not use it - * as driver for system timing. However, the SysTick IRQ is - * always enabled, so we must ensure the interrupt priority - * is set to a level lower than the kernel interrupts (for - * the assert mechanism to work properly) in case the SysTick - * interrupt is accidentally raised. - */ - NVIC_SetPriority(SysTick_IRQn, _EXC_IRQ_DEFAULT_PRIO); -#endif /* CPU_CORTEX_M_HAS_SYSTICK && ! CORTEX_M_SYSTICK */ - -} - -/** - * @brief Clear Fault exceptions - * - * Clear out exceptions for Mem, Bus, Usage and Hard Faults - */ -static ALWAYS_INLINE void z_arm_clear_faults(void) -{ -#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) -#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - /* Reset all faults */ - SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | - SCB_CFSR_MEMFAULTSR_Msk | - SCB_CFSR_BUSFAULTSR_Msk; - - /* Clear all Hard Faults - HFSR is write-one-to-clear */ - SCB->HFSR = 0xffffffff; -#else -#error Unknown ARM architecture -#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ -} - -/** - * @brief Assess whether a debug monitor event should be treated as an error - * - * This routine checks the status of a debug_monitor() exception, and - * evaluates whether this needs to be considered as a processor error. - * - * @return true if the DM exception is a processor error, otherwise false - */ -bool z_arm_debug_monitor_event_error_check(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_EXC_H_ */ diff --git a/arch/arm/include/cortex_m/exception.h b/arch/arm/include/cortex_m/exception.h new file mode 100644 index 00000000000..bf86abd77c7 --- /dev/null +++ b/arch/arm/include/cortex_m/exception.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Exception/interrupt context helpers for Cortex-M CPUs + * + * Exception/interrupt context helpers. + */ + +#ifndef ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ + +#include + +#ifdef _ASMLANGUAGE + +/* nothing */ + +#else + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_IRQ_OFFLOAD +extern volatile irq_offload_routine_t offload_routine; +#endif + +/* Writes to the AIRCR must be accompanied by a write of the value 0x05FA + * to the Vector Key field, otherwise the writes are ignored. + */ +#define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL + +/* + * The current executing vector is found in the IPSR register. All + * IRQs and system exceptions are considered as interrupt context. + */ +static ALWAYS_INLINE bool arch_is_in_isr(void) +{ + return (__get_IPSR()) ? (true) : (false); +} + +/** + * @brief Find out if we were in ISR context + * before the current exception occurred. + * + * A function that determines, based on inspecting the current + * ESF, whether the processor was in handler mode before entering + * the current exception state (i.e. nested exception) or not. + * + * Notes: + * - The function shall only be called from ISR context. + * - We do not use ARM processor state flags to determine + * whether we are in a nested exception; we rely on the + * RETPSR value stacked on the ESF. Hence, the function + * assumes that the ESF stack frame has a valid RETPSR + * value. + * + * @param esf the exception stack frame (cannot be NULL) + * @return true if execution state was in handler mode, before + * the current exception occurred, otherwise false. + */ +static ALWAYS_INLINE bool arch_is_in_nested_exception(const z_arch_esf_t *esf) +{ + return (esf->basic.xpsr & IPSR_ISR_Msk) ? (true) : (false); +} + +#if defined(CONFIG_USERSPACE) +/** + * @brief Is the thread in unprivileged mode + * + * @param esf the exception stack frame (unused) + * @return true if the current thread was in unprivileged mode + */ +static ALWAYS_INLINE bool z_arm_preempted_thread_in_user_mode(const z_arch_esf_t *esf) +{ + return z_arm_thread_is_in_user_mode(); +} +#endif + +/** + * @brief Setup system exceptions + * + * Set exception priorities to conform with the BASEPRI locking mechanism. + * Set PendSV priority to lowest possible. + * + * Enable fault exceptions. + */ +static ALWAYS_INLINE void z_arm_exc_setup(void) +{ + /* PendSV is set to lowest priority, regardless of it being used. + * This is done as the IRQ is always enabled. + */ + NVIC_SetPriority(PendSV_IRQn, _EXC_PENDSV_PRIO); + +#ifdef CONFIG_CPU_CORTEX_M_HAS_BASEPRI + /* Note: SVCall IRQ priority level is left to default (0) + * for Cortex-M variants without BASEPRI (e.g. ARMv6-M). + */ + NVIC_SetPriority(SVCall_IRQn, _EXC_SVC_PRIO); +#endif + +#ifdef CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS + NVIC_SetPriority(MemoryManagement_IRQn, _EXC_FAULT_PRIO); + NVIC_SetPriority(BusFault_IRQn, _EXC_FAULT_PRIO); + NVIC_SetPriority(UsageFault_IRQn, _EXC_FAULT_PRIO); +#if defined(CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK) + NVIC_SetPriority(DebugMonitor_IRQn, IRQ_PRIO_LOWEST); +#elif defined(CONFIG_CPU_CORTEX_M_HAS_DWT) + NVIC_SetPriority(DebugMonitor_IRQn, _EXC_FAULT_PRIO); +#endif +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + NVIC_SetPriority(SecureFault_IRQn, _EXC_FAULT_PRIO); +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ + + /* Enable Usage, Mem, & Bus Faults */ + SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk | + SCB_SHCSR_BUSFAULTENA_Msk; +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + /* Enable Secure Fault */ + SCB->SHCSR |= SCB_SHCSR_SECUREFAULTENA_Msk; + /* Clear BFAR before setting BusFaults to target Non-Secure state. */ + SCB->BFAR = 0; +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ +#endif /* CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS */ + +#if defined(CONFIG_ARM_SECURE_FIRMWARE) && \ + !defined(CONFIG_ARM_SECURE_BUSFAULT_HARDFAULT_NMI) + /* Set NMI, Hard, and Bus Faults as Non-Secure. + * NMI and Bus Faults targeting the Secure state will + * escalate to a SecureFault or SecureHardFault. + */ + SCB->AIRCR = + (SCB->AIRCR & (~(SCB_AIRCR_VECTKEY_Msk))) + | SCB_AIRCR_BFHFNMINS_Msk + | ((AIRCR_VECT_KEY_PERMIT_WRITE << SCB_AIRCR_VECTKEY_Pos) & + SCB_AIRCR_VECTKEY_Msk); + /* Note: Fault conditions that would generate a SecureFault + * in a PE with the Main Extension instead generate a + * SecureHardFault in a PE without the Main Extension. + */ +#endif /* ARM_SECURE_FIRMWARE && !ARM_SECURE_BUSFAULT_HARDFAULT_NMI */ + +#if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK) && \ + !defined(CONFIG_CORTEX_M_SYSTICK) + /* SoC implements SysTick, but the system does not use it + * as driver for system timing. However, the SysTick IRQ is + * always enabled, so we must ensure the interrupt priority + * is set to a level lower than the kernel interrupts (for + * the assert mechanism to work properly) in case the SysTick + * interrupt is accidentally raised. + */ + NVIC_SetPriority(SysTick_IRQn, _EXC_IRQ_DEFAULT_PRIO); +#endif /* CPU_CORTEX_M_HAS_SYSTICK && ! CORTEX_M_SYSTICK */ + +} + +/** + * @brief Clear Fault exceptions + * + * Clear out exceptions for Mem, Bus, Usage and Hard Faults + */ +static ALWAYS_INLINE void z_arm_clear_faults(void) +{ +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) +#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + /* Reset all faults */ + SCB->CFSR = SCB_CFSR_USGFAULTSR_Msk | + SCB_CFSR_MEMFAULTSR_Msk | + SCB_CFSR_BUSFAULTSR_Msk; + + /* Clear all Hard Faults - HFSR is write-one-to-clear */ + SCB->HFSR = 0xffffffff; +#else +#error Unknown ARM architecture +#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */ +} + +/** + * @brief Assess whether a debug monitor event should be treated as an error + * + * This routine checks the status of a debug_monitor() exception, and + * evaluates whether this needs to be considered as a processor error. + * + * @return true if the DM exception is a processor error, otherwise false + */ +bool z_arm_debug_monitor_event_error_check(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_ARM_INCLUDE_CORTEX_M_EXCEPTION_H_ */ diff --git a/arch/arm/include/cortex_m/tz.h b/arch/arm/include/cortex_m/tz.h deleted file mode 100644 index 0262376469e..00000000000 --- a/arch/arm/include/cortex_m/tz.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief TrustZone API - * - * TrustZone API for Cortex-M23/M33 CPUs implementing the Security Extension. - */ - -#ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ -#define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ - -#ifdef _ASMLANGUAGE - -/* nothing */ - -#else - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * - * @brief Initial Non-Secure state configuration - * - * A convenient struct to include all required Non-Secure - * state configuration. - */ -typedef struct tz_nonsecure_setup_conf { - uint32_t msp_ns; - uint32_t psp_ns; - uint32_t vtor_ns; - struct { - uint32_t npriv:1; - uint32_t spsel:1; - uint32_t reserved:30; - } control_ns; -} tz_nonsecure_setup_conf_t; - - -/** - * - * @brief Setup Non-Secure state core registers - * - * Configure the Non-Secure instances of the VTOR, MSP, PSP, - * and CONTROL register. - * - * @param p_ns_conf Pointer to a structure holding the desired configuration. - * - * Notes: - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instances of the core registers are RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - */ -void tz_nonsecure_state_setup(const tz_nonsecure_setup_conf_t *p_ns_conf); - -#if defined(CONFIG_ARMV8_M_MAINLINE) - -/** - * - * @brief Setup Non-Secure Main Stack Pointer limit register - * - * Configure the Non-Secure instance of the MSPLIM register. - * - * @param val value to configure the MSPLIM_NS register with. - * - * Notes: - * - * This function shall only be called from Secure state. - * Only ARMv8-M Mainline implementations have Non-Secure MSPLIM instance. - * - */ -void tz_nonsecure_msplim_set(uint32_t val); - -/** - * - * @brief Setup Non-Secure Process Stack Pointer limit register - * - * Configure the Non-Secure instance of the PSPLIM register. - * - * @param val value to configure the PSPLIM_NS register with. - * - * Notes: - * - * This function shall only be called from Secure state. - * Only ARMv8-M Mainline implementations have Non-Secure PSPLIM instance. - * - */ -void tz_nonsecure_psplim_set(uint32_t val); - -#endif /* CONFIG_ARMV8_M_MAINLINE */ - -/** - * @brief Block or permit Non-Secure System Reset Requests - * - * Function allows the user to configure the system to block or - * permit the Non-Secure domain to issue System Reset Requests. - * - * @param block Flag indicating whether Non-Secure System Reset - * Requests shall be blocked (1), or permitted (0). - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_system_reset_req_block(int block); - -/** - * @brief Prioritize Secure exceptions - * - * Function allows the user to prioritize Secure exceptions over Non-Secure, - * enabling Secure exception priority boosting. - * - * @param secure_boost Flag indicating whether Secure priority boosting - * is desired; select 1 for priority boosting, otherwise 0. - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_exception_prio_config(int secure_boost); - -/** - * @brief Set target state for exceptions not banked between security states - * - * Function sets the security state (Secure or Non-Secure) target - * for ARMv8-M HardFault, NMI, and BusFault exception. - * - * @param secure_state 1 if target state is Secure, 0 if target state - * is Non-Secure. - * - * Secure state: BusFault, HardFault, and NMI are Secure. - * Non-Secure state: BusFault and NMI are Non-Secure and exceptions can - * target Non-Secure HardFault. - * - * Notes: - * - * - This function shall only be called from Secure state. - * - NMI and BusFault are not banked between security states; they - * shall either target Secure or Non-Secure state based on user selection. - * - HardFault exception generated through escalation will target the - * security state of the original fault before its escalation to HardFault. - * - If secure_state is set to 1 (Secure), all Non-Secure HardFaults are - * escalated to Secure HardFaults. - * - BusFault is present only if the Main Extension is implemented. - */ -void tz_nbanked_exception_target_state_set(int secure_state); - -#if defined(CONFIG_ARMV7_M_ARMV8_M_FP) -/** - * @brief Allow Non-Secure firmware to access the FPU - * - * Function allows the Non-Secure firmware to access the Floating Point Unit. - * - * Relevant for ARMv8-M MCUs supporting the Floating Point Extension. - * - * Note: - * - * This function shall only be called from Secure state. - */ -void tz_nonsecure_fpu_access_enable(void); -#endif /* CONFIG_ARMV7_M_ARMV8_M_FP */ - -/** - * - * @brief Configure SAU - * - * Configure (enable or disable) the ARMv8-M Security Attribution Unit. - * - * @param enable SAU enable flag: 1 if SAU is to be enabled, 0 if SAU is - * to be disabled. - * @param allns SAU_CTRL.ALLNS flag: select 1 to set SAU_CTRL.ALLNS, 0 - * to clear SAU_CTRL.ALLNS. - * - * Notes: - * - * SAU_CTRL.ALLNS bit: All Non-secure. When SAU_CTRL.ENABLE is 0 - * this bit controls if the memory is marked as Non-secure or Secure. - * Values: - * Secure (not Non-Secure Callable): 0 - * Non-Secure: 1 - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instance of SAU_CTRL register is RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - */ -void tz_sau_configure(int enable, int allns); - -/** - * - * @brief Get number of SAU regions - * - * Get the number of regions implemented by the Security Attribution Unit, - * indicated by SAU_TYPE.SREGION (read-only) register field. - * - * Notes: - * - * The SREGION field reads as an IMPLEMENTATION DEFINED value. - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instance of SAU_TYPE register is RAZ. - * - * @return The number of configured SAU regions. - */ -uint32_t tz_sau_number_of_regions_get(void); - -#if defined(CONFIG_CPU_HAS_ARM_SAU) -/** - * - * @brief SAU Region configuration - * - * A convenient struct to include all required elements - * for a SAU region configuration. - */ -typedef struct { - uint8_t region_num; - uint8_t enable:1; - uint8_t nsc:1; - uint32_t base_addr; - uint32_t limit_addr; -} tz_sau_conf_t; - - -/** - * - * @brief Configure SAU Region - * - * Configure an existing ARMv8-M SAU region. - * - * @param p_sau_conf pointer to a tz_sau_conf_t structure - * - * This function shall only be called from Secure state, otherwise the - * Non-Secure instances of SAU RNR, RLAR, RBAR registers are RAZ/WI. - * - * This function shall be called before the Secure Firmware may transition - * to Non-Secure state. - * - * @return 1 if configuration is successful, otherwise 0. - - */ -int tz_sau_region_configure(tz_sau_conf_t *p_sau_conf); - -#endif /* CONFIG_CPU_HAS_ARM_SAU */ - -/** - * @brief Non-Secure function type - * - * Defines a function pointer type to implement a non-secure function call, - * i.e. a function call that switches state from Secure to Non-secure. - * - * Note: - * - * A non-secure function call can only happen through function pointers. - * This is a consequence of separating secure and non-secure code into - * separate executable files. - */ -typedef void __attribute__((cmse_nonsecure_call)) (*tz_ns_func_ptr_t) (void); - -/* Required for C99 compilation (required for GCC-8.x version, - * where typeof is used instead of __typeof__) - */ -#ifndef typeof -#define typeof __typeof__ -#endif - -#if defined(CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS) -/** - * @brief Non-Secure entry function attribute. - * - * Declares a non-secure entry function that may be called from Non-Secure - * or from Secure state using the CMSE _cmse_nonsecure_entry intrinsic. - * - * Note: - * - * The function must reside in Non-Secure Callable memory region. - */ -#define __TZ_NONSECURE_ENTRY_FUNC \ - __attribute__((cmse_nonsecure_entry, noinline)) - -#endif /* CONFIG_ARM_FIRMWARE_HAS_SECURE_ENTRY_FUNCS */ - -/** - * @brief Declare a pointer of non-secure function type - * - * Note: - * - * A non-secure function type must only be used as a base type of pointer. - */ -#define TZ_NONSECURE_FUNC_PTR_DECLARE(fptr) tz_ns_func_ptr_t fptr - -/** - * @brief Define a non-secure function pointer - * - * A non-secure function pointer is a function pointer that has its LSB unset. - * The macro uses the CMSE intrinsic: cmse_nsfptr_create(p) to return the - * value of a pointer with its LSB cleared. - */ -#define TZ_NONSECURE_FUNC_PTR_CREATE(fptr) \ - ((tz_ns_func_ptr_t)(cmse_nsfptr_create(fptr))) - -/** - * @brief Check if pointer can be of non-secure function type - * - * A non-secure function pointer is a function pointer that has its LSB unset. - * The macro uses the CMSE intrinsic: cmse_is_nsfptr(p) to evaluate whether - * the supplied pointer has its LSB cleared and, thus, can be of non-secure - * function type. - * - * @param fptr supplied pointer to be checked - * - * @return non-zero if pointer can be of non-secure function type - * (i.e. with LSB unset), zero otherwise. - */ -#define TZ_NONSECURE_FUNC_PTR_IS_NS(fptr) \ - cmse_is_nsfptr(fptr) - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_H_ */ diff --git a/arch/arm/include/kernel_arch_data.h b/arch/arm/include/kernel_arch_data.h index 6ae5f643341..5ad19db8f84 100644 --- a/arch/arm/include/kernel_arch_data.h +++ b/arch/arm/include/kernel_arch_data.h @@ -26,10 +26,10 @@ #if defined(CONFIG_CPU_CORTEX_M) #include -#include +#include #elif defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include -#include +#include #endif #ifndef _ASMLANGUAGE diff --git a/arch/arm64/core/CMakeLists.txt b/arch/arm64/core/CMakeLists.txt index 1804556c1a7..05e4be8c0ea 100644 --- a/arch/arm64/core/CMakeLists.txt +++ b/arch/arm64/core/CMakeLists.txt @@ -55,3 +55,11 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU") endif() add_subdirectory_ifdef(CONFIG_XEN xen) + +if(CONFIG_GEN_SW_ISR_TABLE) + if(CONFIG_DYNAMIC_INTERRUPTS) + zephyr_linker_sources(RWDATA swi_tables.ld) + else() + zephyr_linker_sources(RODATA swi_tables.ld) + endif() +endif() diff --git a/arch/arm64/core/Kconfig b/arch/arm64/core/Kconfig index fd74a526416..8f09d49a04c 100644 --- a/arch/arm64/core/Kconfig +++ b/arch/arm64/core/Kconfig @@ -253,15 +253,6 @@ config ARM_MMU help Memory Management Unit support. -config EXCEPTION_DEBUG - bool "Unhandled exception debugging information" - default y - depends on LOG - help - Print human-readable information about exception vectors, cause codes, - and parameters, at a cost of code/data size for the human-readable - strings. - config XIP select AARCH64_IMAGE_HEADER diff --git a/arch/arm64/core/fatal.c b/arch/arm64/core/fatal.c index 1139a818e1f..dbf0c4cdae1 100644 --- a/arch/arm64/core/fatal.c +++ b/arch/arm64/core/fatal.c @@ -250,7 +250,7 @@ static bool z_arm64_stack_corruption_check(z_arch_esf_t *esf, uint64_t esr, uint * so flush the fpu context to its owner, and then set no fpu trap to avoid * a new nested exception triggered by FPU accessing (var_args). */ - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); write_cpacr_el1(read_cpacr_el1() | CPACR_EL1_FPEN_NOTRAP); #endif arch_curr_cpu()->arch.corrupted_sp = 0UL; diff --git a/arch/arm64/core/fpu.c b/arch/arm64/core/fpu.c index 74a32b8009c..0133eed2dca 100644 --- a/arch/arm64/core/fpu.c +++ b/arch/arm64/core/fpu.c @@ -64,7 +64,7 @@ static inline void DBG(char *msg, struct k_thread *t) { } * Flush FPU content and disable access. * This is called locally and also from flush_fpu_ipi_handler(). */ -void z_arm64_flush_local_fpu(void) +void arch_flush_local_fpu(void) { __ASSERT(read_daif() & DAIF_IRQ_BIT, "must be called with IRQs disabled"); @@ -107,10 +107,10 @@ static void flush_owned_fpu(struct k_thread *thread) } /* we found it live on CPU i */ if (i == _current_cpu->id) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); } else { /* the FPU context is live on another CPU */ - z_arm64_flush_fpu_ipi(i); + arch_flush_fpu_ipi(i); /* * Wait for it only if this is about the thread @@ -126,7 +126,7 @@ static void flush_owned_fpu(struct k_thread *thread) * two CPUs want to pull each other's FPU context. */ if (thread == _current) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); while (atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner) == thread) { barrier_dsync_fence_full(); } @@ -334,7 +334,7 @@ int arch_float_disable(struct k_thread *thread) flush_owned_fpu(thread); #else if (thread == atomic_ptr_get(&_current_cpu->arch.fpu_owner)) { - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); } #endif diff --git a/arch/arm64/core/irq_offload.c b/arch/arm64/core/irq_offload.c index 26f88aa77e6..1d5e3c829b8 100644 --- a/arch/arm64/core/irq_offload.c +++ b/arch/arm64/core/irq_offload.c @@ -11,7 +11,7 @@ #include #include -#include +#include void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) { diff --git a/arch/arm64/core/prep_c.c b/arch/arm64/core/prep_c.c index c12d5e7d1c4..bfd3b7c1eaa 100644 --- a/arch/arm64/core/prep_c.c +++ b/arch/arm64/core/prep_c.c @@ -51,7 +51,7 @@ void z_early_memcpy(void *dst, const void *src, size_t n) * This routine prepares for the execution of and runs C code. * */ -void z_arm64_prep_c(void) +void z_prep_c(void) { /* Initialize tpidrro_el0 with our struct _cpu instance address */ write_tpidrro_el0((uintptr_t)&_kernel.cpus[0]); @@ -64,16 +64,17 @@ void z_arm64_prep_c(void) #endif z_arm64_mm_init(true); z_arm64_interrupt_init(); - z_cstart(); + z_cstart(); CODE_UNREACHABLE; } + #if CONFIG_MP_MAX_NUM_CPUS > 1 -extern FUNC_NORETURN void z_arm64_secondary_start(void); +extern FUNC_NORETURN void arch_secondary_cpu_init(void); void z_arm64_secondary_prep_c(void) { - z_arm64_secondary_start(); + arch_secondary_cpu_init(); CODE_UNREACHABLE; } diff --git a/arch/arm64/core/reset.S b/arch/arm64/core/reset.S index 81f11e6f2c9..cfcffec4ce7 100644 --- a/arch/arm64/core/reset.S +++ b/arch/arm64/core/reset.S @@ -188,7 +188,7 @@ primary_core: #endif /* load primary stack and entry point */ ldr x24, =(z_interrupt_stacks + __z_interrupt_stack_SIZEOF) - ldr x25, =z_arm64_prep_c + ldr x25, =z_prep_c boot: /* Prepare for calling C code */ bl __reset_prep_c @@ -248,4 +248,4 @@ switch_el: msr DAIFClr, #(DAIFCLR_ABT_BIT) isb - ret x25 /* either z_arm64_prep_c or z_arm64_secondary_prep_c */ + ret x25 /* either z_prep_c or z_arm64_secondary_prep_c */ diff --git a/arch/arm64/core/smp.c b/arch/arm64/core/smp.c index e67032eb2a4..97fd60b4236 100644 --- a/arch/arm64/core/smp.c +++ b/arch/arm64/core/smp.c @@ -101,7 +101,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, /* store mpid last as this is our synchronization point */ arm64_cpu_boot_params.mpid = cpu_mpid; - sys_cache_data_invd_range((void *)&arm64_cpu_boot_params, + sys_cache_data_flush_range((void *)&arm64_cpu_boot_params, sizeof(arm64_cpu_boot_params)); if (pm_cpu_on(cpu_mpid, (uint64_t)&__start)) { @@ -122,7 +122,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, k_panic(); } - /* Wait secondary cores up, see z_arm64_secondary_start */ + /* Wait secondary cores up, see arch_secondary_cpu_init */ while (arm64_cpu_boot_params.fn) { wfe(); } @@ -133,9 +133,9 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, } /* the C entry of secondary cores */ -void z_arm64_secondary_start(void) +void arch_secondary_cpu_init(int cpu_num) { - int cpu_num = arm64_cpu_boot_params.cpu_num; + cpu_num = arm64_cpu_boot_params.cpu_num; arch_cpustart_t fn; void *arg; @@ -242,11 +242,11 @@ void flush_fpu_ipi_handler(const void *unused) ARG_UNUSED(unused); disable_irq(); - z_arm64_flush_local_fpu(); + arch_flush_local_fpu(); /* no need to re-enable IRQs here */ } -void z_arm64_flush_fpu_ipi(unsigned int cpu) +void arch_flush_fpu_ipi(unsigned int cpu) { const uint64_t mpidr = cpu_map[cpu]; uint8_t aff0; @@ -272,14 +272,14 @@ void arch_spin_relax(void) arm_gic_irq_clear_pending(SGI_FPU_IPI); /* * We may not be in IRQ context here hence cannot use - * z_arm64_flush_local_fpu() directly. + * arch_flush_local_fpu() directly. */ arch_float_disable(_current_cpu->arch.fpu_owner); } } #endif -static int arm64_smp_init(void) +int arch_smp_init(void) { cpu_map[0] = MPIDR_TO_CORE(GET_MPIDR()); @@ -302,6 +302,6 @@ static int arm64_smp_init(void) return 0; } -SYS_INIT(arm64_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif diff --git a/arch/arm64/core/swi_tables.ld b/arch/arm64/core/swi_tables.ld new file mode 100644 index 00000000000..a5dd3eaf652 --- /dev/null +++ b/arch/arm64/core/swi_tables.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) +INCLUDE isr_tables_swi.ld +#endif diff --git a/arch/arm64/include/exc.h b/arch/arm64/include/exc.h deleted file mode 100644 index 03dacc7c51d..00000000000 --- a/arch/arm64/include/exc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019 Carlo Caione - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Exception/interrupt context helpers for Cortex-A CPUs - * - * Exception/interrupt context helpers. - */ - -#ifndef ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ -#define ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ - -#include - -#ifdef _ASMLANGUAGE - -/* nothing */ - -#else - -#ifdef __cplusplus -extern "C" { -#endif - -static ALWAYS_INLINE bool arch_is_in_isr(void) -{ - return arch_curr_cpu()->nested != 0U; -} - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_ARCH_ARM64_INCLUDE_EXC_H_ */ diff --git a/arch/arm64/include/exception.h b/arch/arm64/include/exception.h new file mode 100644 index 00000000000..6ab6bbbfeff --- /dev/null +++ b/arch/arm64/include/exception.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Exception/interrupt context helpers for Cortex-A CPUs + * + * Exception/interrupt context helpers. + */ + +#ifndef ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ +#define ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ + +#include + +#ifdef _ASMLANGUAGE + +/* nothing */ + +#else + +#ifdef __cplusplus +extern "C" { +#endif + +static ALWAYS_INLINE bool arch_is_in_isr(void) +{ + return arch_curr_cpu()->nested != 0U; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_ARCH_ARM64_INCLUDE_EXCEPTION_H_ */ diff --git a/arch/arm64/include/kernel_arch_data.h b/arch/arm64/include/kernel_arch_data.h index 0b2d878537f..ec781fc902d 100644 --- a/arch/arm64/include/kernel_arch_data.h +++ b/arch/arm64/include/kernel_arch_data.h @@ -24,7 +24,7 @@ #include #include -#include +#include #ifndef _ASMLANGUAGE #include diff --git a/arch/arm64/include/kernel_arch_func.h b/arch/arm64/include/kernel_arch_func.h index 3b028b10b37..a5c3d59d87a 100644 --- a/arch/arm64/include/kernel_arch_func.h +++ b/arch/arm64/include/kernel_arch_func.h @@ -48,8 +48,8 @@ extern void z_arm64_set_ttbr0(uint64_t ttbr0); extern void z_arm64_mem_cfg_ipi(void); #ifdef CONFIG_FPU_SHARING -void z_arm64_flush_local_fpu(void); -void z_arm64_flush_fpu_ipi(unsigned int cpu); +void arch_flush_local_fpu(void); +void arch_flush_fpu_ipi(unsigned int cpu); #endif #ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index 1a89ba9c13a..409c378f620 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -39,6 +39,11 @@ zephyr_linker_sources_ifdef(CONFIG_GEN_ISR_TABLES ${ZEPHYR_BASE}/include/zephyr/linker/intlist.ld ) +zephyr_linker_sources_ifdef(CONFIG_ISR_TABLES_LOCAL_DECLARATION + SECTIONS + ${ZEPHYR_BASE}/include/zephyr/linker/isr-local-drop-unused.ld +) + zephyr_linker_sources_ifdef(CONFIG_GEN_IRQ_VECTOR_TABLE ROM_START SORT_KEY 0x0vectors diff --git a/arch/common/isr_tables.c b/arch/common/isr_tables.c index 0311f81f252..050597b7b1d 100644 --- a/arch/common/isr_tables.c +++ b/arch/common/isr_tables.c @@ -15,15 +15,27 @@ struct int_list_header { uint32_t table_size; uint32_t offset; +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + uint32_t swi_table_entry_size; + uint32_t shared_isr_table_entry_size; + uint32_t shared_isr_client_num_offset; +#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ }; /* These values are not included in the resulting binary, but instead form the * header of the initList section, which is used by gen_isr_tables.py to create * the vector and sw isr tables, */ -Z_GENERIC_SECTION(.irq_info) struct int_list_header _iheader = { +Z_GENERIC_SECTION(.irq_info) __used struct int_list_header _iheader = { .table_size = IRQ_TABLE_SIZE, .offset = CONFIG_GEN_IRQ_START_VECTOR, +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + .swi_table_entry_size = sizeof(struct _isr_table_entry), +#if IS_ENABLED(CONFIG_SHARED_INTERRUPTS) + .shared_isr_table_entry_size = sizeof(struct z_shared_isr_table_entry), + .shared_isr_client_num_offset = offsetof(struct z_shared_isr_table_entry, client_num), +#endif /* IS_ENABLED(CONFIG_SHARED_INTERRUPTS) */ +#endif /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ }; /* These are placeholder tables. They will be replaced by the real tables diff --git a/arch/common/multilevel_irq.c b/arch/common/multilevel_irq.c index 96f3ab0801f..53f8e03a4d8 100644 --- a/arch/common/multilevel_irq.c +++ b/arch/common/multilevel_irq.c @@ -6,9 +6,15 @@ */ #include +#include #include +#include #include +BUILD_ASSERT((CONFIG_NUM_2ND_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <= + BIT(CONFIG_2ND_LEVEL_INTERRUPT_BITS), + "L2 bits not enough to cover the number of L2 IRQs"); + /* * Insert code if the node_id is an interrupt controller */ @@ -16,25 +22,25 @@ IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_controller), (code)) /* - * Expands to node_id if its IRQN is equal to `irq`, nothing otherwise - * This only works for `irq` between 0 & 4095, see `IS_EQ` + * Expands to node_id if its IRQN is equal to `_irq`, nothing otherwise + * This only works for `_irq` between 0 & 4095, see `IS_EQ` */ -#define Z_IF_DT_INTC_IRQN_EQ(node_id, irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), irq), (node_id)) +#define Z_IF_DT_INTC_IRQN_EQ(node_id, _irq) IF_ENABLED(IS_EQ(DT_IRQ(node_id, irq), _irq), (node_id)) /* * Expands to node_id if it's an interrupt controller & its IRQN is `irq`, or nothing otherwise */ -#define Z_DT_INTC_GET_IRQN(node_id, irq) \ - Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, irq)) +#define Z_DT_INTC_GET_IRQN(node_id, _irq) \ + Z_IF_DT_IS_INTC(node_id, Z_IF_DT_INTC_IRQN_EQ(node_id, _irq)) /** - * Loop through child of "/soc" and get root interrupt controllers with `irq` as IRQN, + * Loop through child of "/soc" and get root interrupt controllers with `_irq` as IRQN, * this assumes only one device has the IRQN - * @param irq irq number - * @return node_id(s) that has the `irq` number, or empty if none of them has the `irq` + * @param _irq irq number + * @return node_id(s) that has the `_irq` number, or empty if none of them has the `_irq` */ -#define INTC_DT_IRQN_GET(irq) \ - DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, irq) +#define INTC_DT_IRQN_GET(_irq) \ + DT_FOREACH_CHILD_STATUS_OKAY_VARGS(DT_PATH(soc), Z_DT_INTC_GET_IRQN, _irq) /* If can't find any matching interrupt controller, fills with `NULL` */ #define INTC_DEVICE_INIT(node_id) .dev = DEVICE_DT_GET_OR_NULL(node_id), @@ -54,12 +60,16 @@ const struct _irq_parent_entry _lvl2_irq_list[CONFIG_NUM_2ND_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_2ND_LEVEL_AGGREGATORS, CAT_2ND_LVL_LIST, (,), CONFIG_2ND_LVL_ISR_TBL_OFFSET) }; +#ifdef CONFIG_3RD_LEVEL_INTERRUPTS + +BUILD_ASSERT((CONFIG_NUM_3RD_LEVEL_AGGREGATORS * CONFIG_MAX_IRQ_PER_AGGREGATOR) <= + BIT(CONFIG_3RD_LEVEL_INTERRUPT_BITS), + "L3 bits not enough to cover the number of L3 IRQs"); + #define CAT_3RD_LVL_LIST(i, base) \ INIT_IRQ_PARENT_OFFSET(INTC_DT_IRQN_GET(CONFIG_3RD_LVL_INTR_0##i##_OFFSET), \ CONFIG_3RD_LVL_INTR_0##i##_OFFSET, IRQ_INDEX_TO_OFFSET(i, base)) -#ifdef CONFIG_3RD_LEVEL_INTERRUPTS - const struct _irq_parent_entry _lvl3_irq_list[CONFIG_NUM_3RD_LEVEL_AGGREGATORS] = { LISTIFY(CONFIG_NUM_3RD_LEVEL_AGGREGATORS, CAT_3RD_LVL_LIST, (,), CONFIG_3RD_LVL_ISR_TBL_OFFSET) }; @@ -133,28 +143,31 @@ unsigned int z_get_sw_isr_irq_from_device(const struct device *dev) unsigned int z_get_sw_isr_table_idx(unsigned int irq) { - unsigned int table_idx; - unsigned int level, parent_irq, parent_offset; + unsigned int table_idx, level, parent_irq, local_irq, parent_offset; const struct _irq_parent_entry *entry = NULL; level = irq_get_level(irq); if (level == 2U) { + local_irq = irq_from_level_2(irq); + __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR); parent_irq = irq_parent_level_2(irq); entry = get_parent_entry(parent_irq, _lvl2_irq_list, CONFIG_NUM_2ND_LEVEL_AGGREGATORS); parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_2(irq); + table_idx = parent_offset + local_irq; } #ifdef CONFIG_3RD_LEVEL_INTERRUPTS else if (level == 3U) { + local_irq = irq_from_level_3(irq); + __ASSERT_NO_MSG(local_irq < CONFIG_MAX_IRQ_PER_AGGREGATOR); parent_irq = irq_parent_level_3(irq); entry = get_parent_entry(parent_irq, _lvl3_irq_list, CONFIG_NUM_3RD_LEVEL_AGGREGATORS); parent_offset = entry != NULL ? entry->offset : 0U; - table_idx = parent_offset + irq_from_level_3(irq); + table_idx = parent_offset + local_irq; } #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */ else { @@ -163,5 +176,7 @@ unsigned int z_get_sw_isr_table_idx(unsigned int irq) table_idx -= CONFIG_GEN_IRQ_START_VECTOR; + __ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE); + return table_idx; } diff --git a/arch/common/shared_irq.c b/arch/common/shared_irq.c index 68641cb2bb0..a05e78002ce 100644 --- a/arch/common/shared_irq.c +++ b/arch/common/shared_irq.c @@ -20,7 +20,7 @@ void z_shared_isr(const void *data) { size_t i; const struct z_shared_isr_table_entry *entry; - const struct z_shared_isr_client *client; + const struct _isr_table_entry *client; entry = data; @@ -42,7 +42,7 @@ void z_isr_install(unsigned int irq, void (*routine)(const void *), { struct z_shared_isr_table_entry *shared_entry; struct _isr_table_entry *entry; - struct z_shared_isr_client *client; + struct _isr_table_entry *client; unsigned int table_idx; int i; k_spinlock_key_t key; @@ -103,10 +103,10 @@ void z_isr_install(unsigned int irq, void (*routine)(const void *), k_spin_unlock(&lock, key); } -static void swap_client_data(struct z_shared_isr_client *a, - struct z_shared_isr_client *b) +static void swap_client_data(struct _isr_table_entry *a, + struct _isr_table_entry *b) { - struct z_shared_isr_client tmp; + struct _isr_table_entry tmp; tmp.arg = a->arg; tmp.isr = a->isr; @@ -162,7 +162,7 @@ int z_isr_uninstall(unsigned int irq, { struct z_shared_isr_table_entry *shared_entry; struct _isr_table_entry *entry; - struct z_shared_isr_client *client; + struct _isr_table_entry *client; unsigned int table_idx; size_t i; k_spinlock_key_t key; diff --git a/arch/common/sw_isr_common.c b/arch/common/sw_isr_common.c index 5efdeb89a67..43395cd5916 100644 --- a/arch/common/sw_isr_common.c +++ b/arch/common/sw_isr_common.c @@ -15,5 +15,9 @@ unsigned int __weak z_get_sw_isr_table_idx(unsigned int irq) { - return irq - CONFIG_GEN_IRQ_START_VECTOR; + unsigned int table_idx = irq - CONFIG_GEN_IRQ_START_VECTOR; + + __ASSERT_NO_MSG(table_idx < IRQ_TABLE_SIZE); + + return table_idx; } diff --git a/arch/mips/core/fatal.c b/arch/mips/core/fatal.c index 48234680a6a..16011241666 100644 --- a/arch/mips/core/fatal.c +++ b/arch/mips/core/fatal.c @@ -5,35 +5,35 @@ */ #include -#include #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_mips_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { - printk("$ 0 : (ze) %08lx(at) %08lx(v0) %08lx(v1)\n", + LOG_ERR("$ 0 : (ze) %08lx(at) %08lx(v0) %08lx(v1)\n", esf->at, esf->v0, esf->v1); - printk("$ 4 : %08lx(a0) %08lx(a1) %08lx(a2) %08lx(a3)\n", + LOG_ERR("$ 4 : %08lx(a0) %08lx(a1) %08lx(a2) %08lx(a3)\n", esf->a0, esf->a1, esf->a2, esf->a3); - printk("$ 8 : %08lx(t0) %08lx(t1) %08lx(t2) %08lx(t3)\n", + LOG_ERR("$ 8 : %08lx(t0) %08lx(t1) %08lx(t2) %08lx(t3)\n", esf->t0, esf->t1, esf->t2, esf->t3); - printk("$12 : %08lx(t4) %08lx(t5) %08lx(t6) %08lx(t7)\n", + LOG_ERR("$12 : %08lx(t4) %08lx(t5) %08lx(t6) %08lx(t7)\n", esf->t4, esf->t5, esf->t6, esf->t7); - printk("...\n"); - printk("$24 : %08lx(t8) %08lx(t9)\n", + LOG_ERR("...\n"); + LOG_ERR("$24 : %08lx(t8) %08lx(t9)\n", esf->t8, esf->t9); - printk("$28 : %08lx(gp) (sp) (s8) %08lx(ra)\n", + LOG_ERR("$28 : %08lx(gp) (sp) (s8) %08lx(ra)\n", esf->gp, esf->ra); - printk("EPC : %08lx\n", esf->epc); + LOG_ERR("EPC : %08lx\n", esf->epc); - printk("Status: %08lx\n", esf->status); - printk("Cause : %08lx\n", esf->cause); - printk("BadVA : %08lx\n", esf->badvaddr); + LOG_ERR("Status: %08lx\n", esf->status); + LOG_ERR("Cause : %08lx\n", esf->cause); + LOG_ERR("BadVA : %08lx\n", esf->badvaddr); } - +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; } diff --git a/arch/mips/core/prep_c.c b/arch/mips/core/prep_c.c index 6f72699cc5b..19673273b8a 100644 --- a/arch/mips/core/prep_c.c +++ b/arch/mips/core/prep_c.c @@ -42,7 +42,7 @@ static void interrupt_init(void) * @return N/A */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); diff --git a/arch/mips/core/reset.S b/arch/mips/core/reset.S index 8daebf85d4a..eec75bc031b 100644 --- a/arch/mips/core/reset.S +++ b/arch/mips/core/reset.S @@ -11,7 +11,7 @@ GTEXT(__initialize) GTEXT(__stack) -GTEXT(_PrepC) +GTEXT(z_prep_c) /* * Remainder of asm-land initialization code before we can jump into @@ -52,6 +52,6 @@ aa_loop: /* * Jump into C domain. */ - la v0, _PrepC + la v0, z_prep_c jal v0 nop /* delay slot */ diff --git a/arch/nios2/core/crt0.S b/arch/nios2/core/crt0.S index 8ecb37fe926..2f708bf26f4 100644 --- a/arch/nios2/core/crt0.S +++ b/arch/nios2/core/crt0.S @@ -12,7 +12,7 @@ GTEXT(__start) GTEXT(__reset) /* imports */ -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(z_interrupt_stacks) /* Allow use of r1/at (the assembler temporary register) in this @@ -140,7 +140,7 @@ SECTION_FUNC(TEXT, __start) * GH-1821 */ - /* Jump into C domain. _PrepC zeroes BSS, copies rw data into RAM, + /* Jump into C domain. z_prep_c zeroes BSS, copies rw data into RAM, * and then enters z_cstart */ - call _PrepC + call z_prep_c diff --git a/arch/nios2/core/fatal.c b/arch/nios2/core/fatal.c index 9ccb4f3fd92..ac64b5bc309 100644 --- a/arch/nios2/core/fatal.c +++ b/arch/nios2/core/fatal.c @@ -14,6 +14,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_nios2_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#if CONFIG_EXCEPTION_DEBUG if (esf != NULL) { /* Subtract 4 from EA since we added 4 earlier so that the * faulting instruction isn't retried. @@ -33,6 +34,7 @@ FUNC_NORETURN void z_nios2_fatal_error(unsigned int reason, esf->r13, esf->r14, esf->r15, esf->ra); LOG_ERR("estatus: %08x", esf->estatus); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; diff --git a/arch/nios2/core/prep_c.c b/arch/nios2/core/prep_c.c index da8fcd9d4bc..74a3454af48 100644 --- a/arch/nios2/core/prep_c.c +++ b/arch/nios2/core/prep_c.c @@ -28,7 +28,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); z_data_copy(); diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 1573ef82ea1..2ec433ad5cb 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -22,6 +22,11 @@ endif() # RUNNER_LINK_LIBRARIES: # Extra libraries to link with the runner # For ex. set_property(TARGET native_simulator APPEND PROPERTY RUNNER_LINK_LIBRARIES "mylib.a") +# LOCALIZE_EXTRA_OPTIONS: +# Extra options to be passed to objcopy when localizing each Zephyr MCU image symbols +# This can be used to hide symbols a library may have set as visible outside of +# itself once the MCU image has been assembled. +# For ex. set_property(TARGET native_simulator APPEND PROPERTY LOCALIZE_EXTRA_OPTIONS "--localize-symbol=spinel*") # Note: target_link_libraries() cannot be used on this library at this point. # target_link_libraries() updates INTERFACE_LINK_LIBRARIES but wrapping it with extra # information. This means we cannot directly pass it to the native_simulator runner build. @@ -30,6 +35,7 @@ endif() # We use target_link_options() instead add_library(native_simulator INTERFACE) set_property(TARGET native_simulator PROPERTY RUNNER_LINK_LIBRARIES "") +set_property(TARGET native_simulator PROPERTY LOCALIZE_EXTRA_OPTIONS "") set(NSI_DIR ${ZEPHYR_BASE}/scripts/native_simulator CACHE PATH "Path to the native simulator") @@ -102,6 +108,10 @@ elseif (CONFIG_NATIVE_LIBRARY) $ ) endif() + + if (CONFIG_COMPILER_WARNINGS_AS_ERRORS) + target_compile_options(native_simulator INTERFACE $) + endif() endif() if(CONFIG_EXTERNAL_LIBC) @@ -127,8 +137,6 @@ if (CONFIG_GPROF) target_link_options(native_simulator INTERFACE "-pg") endif() -zephyr_compile_definitions(_POSIX_C_SOURCE=200809 _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) - if (CONFIG_NATIVE_APPLICATION) zephyr_ld_options( -ldl diff --git a/arch/posix/core/CMakeLists.txt b/arch/posix/core/CMakeLists.txt index 3cf83c9fdda..12ec5261635 100644 --- a/arch/posix/core/CMakeLists.txt +++ b/arch/posix/core/CMakeLists.txt @@ -28,6 +28,8 @@ if(CONFIG_NATIVE_APPLICATION) ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nce.c ${ZEPHYR_BASE}/scripts/native_simulator/common/src/nsi_host_trampolines.c ) + + zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) else() zephyr_library_sources( posix_core_nsi.c diff --git a/arch/posix/core/nsi_compat/nsi_compat.c b/arch/posix/core/nsi_compat/nsi_compat.c index cd338ca1e4f..eccf419efb1 100644 --- a/arch/posix/core/nsi_compat/nsi_compat.c +++ b/arch/posix/core/nsi_compat/nsi_compat.c @@ -13,6 +13,8 @@ */ #include +#include +#include "posix_board_if.h" void nsi_print_error_and_exit(const char *format, ...) { @@ -41,9 +43,8 @@ void nsi_print_trace(const char *format, ...) va_end(variable_args); } -void nsi_exit(int exit_code) +FUNC_NORETURN void nsi_exit(int exit_code) { - extern void posix_exit(int exit_code); - posix_exit(exit_code); + CODE_UNREACHABLE; } diff --git a/arch/posix/include/posix_cheats.h b/arch/posix/include/posix_cheats.h index 88a68b9fd49..770dab9aac6 100644 --- a/arch/posix/include/posix_cheats.h +++ b/arch/posix/include/posix_cheats.h @@ -151,6 +151,8 @@ extern "C" int _posix_zephyr_main(void); #define sched_yield(...) zap_sched_yield(__VA_ARGS__) #define sched_get_priority_min(...) zap_sched_get_priority_min(__VA_ARGS__) #define sched_get_priority_max(...) zap_sched_get_priority_max(__VA_ARGS__) +#define sched_getparam(...) zap_sched_getparam(__VA_ARGS__) +#define sched_getscheduler(...) zap_sched_getscheduler(__VA_ARGS__) /* Sleep */ #define sleep(...) zap_sleep(__VA_ARGS__) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a1cefcbdf43..2e55d446a75 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -47,6 +47,12 @@ config INCLUDE_RESET_VECTOR Include the reset vector stub, which initializes the stack and prepares for running C code. +config RISCV_PRIVILEGED + bool + select ARCH_HAS_RAMFUNC_SUPPORT if XIP + help + Option selected by SoCs implementing the RISC-V privileged ISA. + config RISCV_SOC_HAS_ISR_STACKING bool depends on !USERSPACE @@ -78,6 +84,13 @@ config RISCV_SOC_HAS_ISR_STACKING saved on the stack by the hardware, and the registers saved by the software macros. The structure must be called '__esf'. +config RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING + bool + help + This allows the SoC to overwrite the irq handling. If enabled, the + function __soc_handle_all_irqs has to be implemented. It shall service + and clear all pending interrupts. + config RISCV_SOC_HAS_CUSTOM_IRQ_LOCK_OPS bool help @@ -147,13 +160,32 @@ config RISCV_SOC_OFFSETS in offsets.h. The last one should not end in a semicolon. See gen_offset.h for more details. +config RISCV_HAS_PLIC + bool + depends on RISCV_PRIVILEGED + help + Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). + +config RISCV_HAS_CLIC + bool + depends on RISCV_PRIVILEGED + help + Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). + +config RISCV_SOC_EXCEPTION_FROM_IRQ + bool + help + Option selected by SoCs that require a custom mechanism to check if + an exception is the result of an interrupt or not. If selected, + __soc_is_irq() needs to be implemented by the SoC. + config RISCV_SOC_INTERRUPT_INIT bool "SOC-based interrupt initialization" help Enable SOC-based interrupt initialization (call soc_interrupt_init, within _IntLibInit when enabled) -config RISCV_SOC_MCAUSE_EXCEPTION_MASK +config RISCV_MCAUSE_EXCEPTION_MASK hex default 0x7FFFFFFFFFFFFFFF if 64BIT default 0x7FFFFFFF @@ -168,11 +200,6 @@ config RISCV_GENERIC_TOOLCHAIN Allow SOCs that have custom extended riscv ISA to still compile with generic riscv32 toolchain. -config RISCV_HAS_CPU_IDLE - bool "Does SOC has CPU IDLE instruction" - help - Does SOC has CPU IDLE instruction - config GEN_ISR_TABLES default y @@ -333,7 +360,7 @@ config RISCV_TRAP_HANDLER_ALIGNMENT The minimum alignment is 4 bytes according to the Spec. config GEN_IRQ_VECTOR_TABLE - select RISCV_VECTORED_MODE if SOC_FAMILY_RISCV_PRIVILEGED + select RISCV_VECTORED_MODE if RISCV_PRIVILEGED config ARCH_HAS_SINGLE_THREAD_SUPPORT default y if !SMP diff --git a/arch/riscv/core/cpu_idle.c b/arch/riscv/core/cpu_idle.c index 0c7f5f3dac7..0d8e4fedeb2 100644 --- a/arch/riscv/core/cpu_idle.c +++ b/arch/riscv/core/cpu_idle.c @@ -5,24 +5,18 @@ */ #include - -/* - * In RISC-V there is no conventional way to handle CPU power save. - * Each RISC-V SOC handles it in its own way. - * Hence, by default, arch_cpu_idle and arch_cpu_atomic_idle functions just - * unlock interrupts and return to the caller, without issuing any CPU power - * saving instruction. - * - * Nonetheless, define the default arch_cpu_idle and arch_cpu_atomic_idle - * functions as weak functions, so that they can be replaced at the SOC-level. - */ +#include void __weak arch_cpu_idle(void) { + sys_trace_idle(); irq_unlock(MSTATUS_IEN); + __asm__ volatile("wfi"); } void __weak arch_cpu_atomic_idle(unsigned int key) { + sys_trace_idle(); irq_unlock(key); + __asm__ volatile("wfi"); } diff --git a/arch/riscv/core/fatal.c b/arch/riscv/core/fatal.c index 171497ff0ca..36457a23de7 100644 --- a/arch/riscv/core/fatal.c +++ b/arch/riscv/core/fatal.c @@ -31,6 +31,7 @@ static const struct z_exc_handle exceptions[] = { FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf != NULL) { LOG_ERR(" a0: " PR_REG " t0: " PR_REG, esf->a0, esf->t0); LOG_ERR(" a1: " PR_REG " t1: " PR_REG, esf->a1, esf->t1); @@ -54,7 +55,7 @@ FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason, LOG_ERR("mstatus: " PR_REG, esf->mstatus); LOG_ERR(""); } - +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); CODE_UNREACHABLE; } @@ -167,7 +168,7 @@ void _Fault(z_arch_esf_t *esf) __asm__ volatile("csrr %0, mtval" : "=r" (mtval)); #endif - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; LOG_ERR(""); LOG_ERR(" mcause: %ld, %s", mcause, cause_str(mcause)); #ifndef CONFIG_SOC_OPENISA_RV32M1_RISCV32 diff --git a/arch/riscv/core/fpu.c b/arch/riscv/core/fpu.c index 293a5bc613f..da5d07b3146 100644 --- a/arch/riscv/core/fpu.c +++ b/arch/riscv/core/fpu.c @@ -98,7 +98,7 @@ static void z_riscv_fpu_load(void) * * This is called locally and also from flush_fpu_ipi_handler(). */ -void z_riscv_flush_local_fpu(void) +void arch_flush_local_fpu(void) { __ASSERT((csr_read(mstatus) & MSTATUS_IEN) == 0, "must be called with IRQs disabled"); @@ -149,11 +149,11 @@ static void flush_owned_fpu(struct k_thread *thread) /* we found it live on CPU i */ if (i == _current_cpu->id) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); break; } /* the FPU context is live on another CPU */ - z_riscv_flush_fpu_ipi(i); + arch_flush_fpu_ipi(i); /* * Wait for it only if this is about the thread @@ -170,7 +170,7 @@ static void flush_owned_fpu(struct k_thread *thread) */ if (thread == _current) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); do { arch_nop(); owner = atomic_ptr_get(&_kernel.cpus[i].arch.fpu_owner); @@ -211,7 +211,7 @@ void z_riscv_fpu_trap(z_arch_esf_t *esf) "called despite FPU being accessible"); /* save current owner's content if any */ - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); if (_current->arch.exception_depth > 0) { /* @@ -271,7 +271,7 @@ static bool fpu_access_allowed(unsigned int exc_update_level) * to come otherwise. */ z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); #ifdef CONFIG_SMP flush_owned_fpu(_current); #endif @@ -329,7 +329,7 @@ int arch_float_disable(struct k_thread *thread) #else if (thread == _current_cpu->arch.fpu_owner) { z_riscv_fpu_disable(); - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); } #endif diff --git a/arch/riscv/core/irq_manage.c b/arch/riscv/core/irq_manage.c index e0ef1374bf1..bf0b6684a5d 100644 --- a/arch/riscv/core/irq_manage.c +++ b/arch/riscv/core/irq_manage.c @@ -10,6 +10,10 @@ #include #include +#ifdef CONFIG_RISCV_HAS_PLIC +#include +#endif + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); FUNC_NORETURN void z_irq_spurious(const void *unused) @@ -20,11 +24,11 @@ FUNC_NORETURN void z_irq_spurious(const void *unused) mcause = csr_read(mcause); - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause); #if defined(CONFIG_RISCV_HAS_PLIC) - if (mcause == RISCV_MACHINE_EXT_IRQ) { + if (mcause == RISCV_IRQ_MEXT) { unsigned int save_irq = riscv_plic_get_irq(); const struct device *save_dev = riscv_plic_get_dev(); @@ -39,15 +43,12 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(const void *parameter), const void *parameter, uint32_t flags) { - ARG_UNUSED(flags); - z_isr_install(irq, routine, parameter); -#if defined(CONFIG_RISCV_HAS_PLIC) - if (irq_get_level(irq) == 2) { - riscv_plic_set_priority(irq, priority); - } +#if defined(CONFIG_RISCV_HAS_PLIC) || defined(CONFIG_RISCV_HAS_CLIC) + z_riscv_irq_priority_set(irq, priority, flags); #else + ARG_UNUSED(flags); ARG_UNUSED(priority); #endif return irq; diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index c36679ae6db..422c2ce23bf 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "asm_macros.inc" @@ -50,7 +51,9 @@ /* imports */ GDATA(_sw_isr_table) +#ifdef CONFIG_RISCV_SOC_EXCEPTION_FROM_IRQ GTEXT(__soc_is_irq) +#endif GTEXT(__soc_handle_irq) GTEXT(_Fault) #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE @@ -72,6 +75,10 @@ GTEXT(sys_trace_isr_exit) GDATA(_k_syscall_table) #endif +#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING +GTEXT(__soc_handle_all_irqs) +#endif + /* exports */ GTEXT(_isr_wrapper) @@ -90,7 +97,8 @@ GTEXT(_isr_wrapper) * what standard behavior is defined). Hence, the arch level code expects * the following functions to be provided at the SOC level: * - * - __soc_is_irq: decide if we're handling an interrupt or an exception + * - __soc_is_irq (optional): decide if we're handling an interrupt or an + exception * - __soc_handle_irq: handle SoC-specific details for a pending IRQ * (e.g. clear a pending bit in a SoC-specific register) * @@ -283,10 +291,14 @@ no_fp: /* increment _current->arch.exception_depth */ * function (that needs to be implemented by each SOC). The result is * returned via register a0 (1: interrupt, 0 exception) */ +#ifdef CONFIG_RISCV_SOC_EXCEPTION_FROM_IRQ jal ra, __soc_is_irq - - /* If a0 != 0, jump to is_interrupt */ bnez a0, is_interrupt +#else + csrr t0, mcause + srli t0, t0, RISCV_MCAUSE_IRQ_POS + bnez t0, is_interrupt +#endif /* * If the exception is the result of an ECALL, check whether to @@ -294,22 +306,22 @@ no_fp: /* increment _current->arch.exception_depth */ * to report the exception. */ csrr t0, mcause - li t2, SOC_MCAUSE_EXP_MASK + li t2, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK and t0, t0, t2 /* - * If mcause == SOC_MCAUSE_ECALL_EXP, handle system call from + * If mcause == RISCV_EXC_ECALLM, handle system call from * kernel thread. */ - li t1, SOC_MCAUSE_ECALL_EXP + li t1, RISCV_EXC_ECALLM beq t0, t1, is_kernel_syscall #ifdef CONFIG_USERSPACE /* - * If mcause == SOC_MCAUSE_USER_ECALL_EXP, handle system call + * If mcause == RISCV_EXC_ECALLU, handle system call * for user mode thread. */ - li t1, SOC_MCAUSE_USER_ECALL_EXP + li t1, RISCV_EXC_ECALLU beq t0, t1, is_user_syscall #endif /* CONFIG_USERSPACE */ @@ -521,13 +533,17 @@ is_interrupt: on_irq_stack: +#ifdef CONFIG_RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING + call __soc_handle_all_irqs +#else + #ifdef CONFIG_TRACING_ISR call sys_trace_isr_enter #endif /* Get IRQ causing interrupt */ csrr a0, mcause - li t0, SOC_MCAUSE_EXP_MASK + li t0, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK and a0, a0, t0 /* @@ -557,6 +573,8 @@ on_irq_stack: call sys_trace_isr_exit #endif +#endif + irq_done: /* Decrement _current_cpu->nested */ lw t2, ___cpu_t_nested_OFFSET(s0) diff --git a/arch/riscv/core/offsets/offsets.c b/arch/riscv/core/offsets/offsets.c index 7730138a376..96982341b1a 100644 --- a/arch/riscv/core/offsets/offsets.c +++ b/arch/riscv/core/offsets/offsets.c @@ -16,7 +16,6 @@ #include #include #include -#include #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE #include @@ -25,6 +24,8 @@ #include #endif +#include + /* struct _callee_saved member offsets */ GEN_OFFSET_SYM(_callee_saved_t, sp); GEN_OFFSET_SYM(_callee_saved_t, ra); diff --git a/arch/riscv/core/prep_c.c b/arch/riscv/core/prep_c.c index 8b9b118b24c..b0fdd3a0569 100644 --- a/arch/riscv/core/prep_c.c +++ b/arch/riscv/core/prep_c.c @@ -20,6 +20,10 @@ #include #include +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + /** * * @brief Prepare to and run C code @@ -27,7 +31,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_bss_zero(); z_data_copy(); diff --git a/arch/riscv/core/reset.S b/arch/riscv/core/reset.S index e2faa6fe94d..e9424e7a8e2 100644 --- a/arch/riscv/core/reset.S +++ b/arch/riscv/core/reset.S @@ -16,10 +16,10 @@ GTEXT(__initialize) GTEXT(__reset) /* imports */ -GTEXT(_PrepC) +GTEXT(z_prep_c) GTEXT(riscv_cpu_wake_flag) GTEXT(riscv_cpu_sp) -GTEXT(z_riscv_secondary_cpu_init) +GTEXT(arch_secondary_cpu_init) #if CONFIG_INCLUDE_RESET_VECTOR SECTION_FUNC(reset, __reset) @@ -86,10 +86,10 @@ aa_loop: #endif /* - * Jump into C domain. _PrepC zeroes BSS, copies rw data into RAM, + * Jump into C domain. z_prep_c zeroes BSS, copies rw data into RAM, * and then enters kernel z_cstart */ - call _PrepC + call z_prep_c boot_secondary_core: #if CONFIG_MP_MAX_NUM_CPUS > 1 @@ -111,7 +111,7 @@ wait_secondary_wake_flag: la t0, riscv_cpu_boot_flag li t1, 1 sr t1, 0(t0) - j z_riscv_secondary_cpu_init + j arch_secondary_cpu_init #else j loop_unconfigured_cores #endif diff --git a/arch/riscv/core/smp.c b/arch/riscv/core/smp.c index 6154450e58d..54de29c0551 100644 --- a/arch/riscv/core/smp.c +++ b/arch/riscv/core/smp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include volatile struct { @@ -22,6 +23,10 @@ volatile void *riscv_cpu_sp; extern void __start(void); +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, arch_cpustart_t fn, void *arg) { @@ -43,7 +48,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, } } -void z_riscv_secondary_cpu_init(int hartid) +void arch_secondary_cpu_init(int hartid) { unsigned int i; unsigned int cpu_num = 0; @@ -67,14 +72,15 @@ void z_riscv_secondary_cpu_init(int hartid) z_riscv_pmp_init(); #endif #ifdef CONFIG_SMP - irq_enable(RISCV_MACHINE_SOFT_IRQ); + irq_enable(RISCV_IRQ_MSOFT); #endif riscv_cpu_init[cpu_num].fn(riscv_cpu_init[cpu_num].arg); } #ifdef CONFIG_SMP -#define MSIP(hartid) ((volatile uint32_t *)RISCV_MSIP_BASE)[hartid] +#define MSIP_BASE 0x2000000UL +#define MSIP(hartid) ((volatile uint32_t *)MSIP_BASE)[hartid] static atomic_val_t cpu_pending_ipi[CONFIG_MP_MAX_NUM_CPUS]; #define IPI_SCHED 0 @@ -97,14 +103,14 @@ void arch_sched_ipi(void) } #ifdef CONFIG_FPU_SHARING -void z_riscv_flush_fpu_ipi(unsigned int cpu) +void arch_flush_fpu_ipi(unsigned int cpu) { atomic_set_bit(&cpu_pending_ipi[cpu], IPI_FPU_FLUSH); MSIP(_kernel.cpus[cpu].arch.hartid) = 1; } #endif -static void ipi_handler(const void *unused) +static void sched_ipi_handler(const void *unused) { ARG_UNUSED(unused); @@ -120,7 +126,7 @@ static void ipi_handler(const void *unused) /* disable IRQs */ csr_clear(mstatus, MSTATUS_IEN); /* perform the flush */ - z_riscv_flush_local_fpu(); + arch_flush_local_fpu(); /* * No need to re-enable IRQs here as long as * this remains the last case. @@ -144,21 +150,20 @@ void arch_spin_relax(void) if (atomic_test_and_clear_bit(pending_ipi, IPI_FPU_FLUSH)) { /* * We may not be in IRQ context here hence cannot use - * z_riscv_flush_local_fpu() directly. + * arch_flush_local_fpu() directly. */ arch_float_disable(_current_cpu->arch.fpu_owner); } } #endif -static int riscv_smp_init(void) +int arch_smp_init(void) { - IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, ipi_handler, NULL, 0); - irq_enable(RISCV_MACHINE_SOFT_IRQ); + IRQ_CONNECT(RISCV_IRQ_MSOFT, 0, sched_ipi_handler, NULL, 0); + irq_enable(RISCV_IRQ_MSOFT); return 0; } - -SYS_INIT(riscv_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(arch_smp_init, PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); #endif /* CONFIG_SMP */ diff --git a/arch/riscv/include/kernel_arch_func.h b/arch/riscv/include/kernel_arch_func.h index fdd39eb8a68..b639f09c6c6 100644 --- a/arch/riscv/include/kernel_arch_func.h +++ b/arch/riscv/include/kernel_arch_func.h @@ -95,8 +95,8 @@ int z_irq_do_offload(void); #endif #ifdef CONFIG_FPU_SHARING -void z_riscv_flush_local_fpu(void); -void z_riscv_flush_fpu_ipi(unsigned int cpu); +void arch_flush_local_fpu(void); +void arch_flush_fpu_ipi(unsigned int cpu); #endif #ifndef CONFIG_MULTITHREADING diff --git a/arch/sparc/core/fatal.c b/arch/sparc/core/fatal.c index ef92fa69f91..55100606b92 100644 --- a/arch/sparc/core/fatal.c +++ b/arch/sparc/core/fatal.c @@ -93,7 +93,7 @@ struct savearea { uint32_t in[8]; }; - +#if CONFIG_EXCEPTION_DEBUG /* * Exception trap type (tt) values according to The SPARC V8 * manual, Table 7-1. @@ -202,10 +202,12 @@ static void print_all(const z_arch_esf_t *esf) print_backtrace(esf); LOG_ERR(""); } +#endif /* CONFIG_EXCEPTION_DEBUG */ FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#if CONFIG_EXCEPTION_DEBUG if (esf != NULL) { if (IS_ENABLED(CONFIG_EXTRA_EXCEPTION_INFO)) { print_all(esf); @@ -213,6 +215,8 @@ FUNC_NORETURN void z_sparc_fatal_error(unsigned int reason, print_special_registers(esf); } } +#endif /* CONFIG_EXCEPTION_DEBUG */ + z_fatal_error(reason, esf); CODE_UNREACHABLE; } diff --git a/arch/sparc/core/prep_c.c b/arch/sparc/core/prep_c.c index 6858b2fb1fb..9ad3955a190 100644 --- a/arch/sparc/core/prep_c.c +++ b/arch/sparc/core/prep_c.c @@ -17,7 +17,7 @@ * This routine prepares for the execution of and runs C code. */ -void _PrepC(void) +void z_prep_c(void) { z_data_copy(); z_cstart(); diff --git a/arch/sparc/core/reset_trap.S b/arch/sparc/core/reset_trap.S index 66b5aafcf26..dd4046c47bc 100644 --- a/arch/sparc/core/reset_trap.S +++ b/arch/sparc/core/reset_trap.S @@ -48,7 +48,7 @@ SECTION_FUNC(TEXT, __sparc_trap_reset) call z_bss_zero nop - call _PrepC + call z_prep_c nop /* We halt the system by generating a "trap in trap" condition. */ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index d7ccfca7ecd..ae7fdef2f77 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -23,7 +23,6 @@ config CPU_ATOM select X86_CPU_HAS_SSE2 select X86_CPU_HAS_SSE3 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Atom family. @@ -41,7 +40,6 @@ config CPU_APOLLO_LAKE select X86_CPU_HAS_SSE41 select X86_CPU_HAS_SSE42 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Apollo Lake family. @@ -56,7 +54,6 @@ config CPU_LAKEMONT select X86_CPU_HAS_SSE3 select X86_CPU_HAS_SSSE3 select CPU_HAS_DCACHE - select CPU_HAS_ICACHE help This option signifies the use of a CPU from the Lakemont family. @@ -295,16 +292,6 @@ config MULTIBOOT_MEMMAP endif # MULTIBOOT -config EXCEPTION_DEBUG - bool "Unhandled exception debugging" - default y - depends on LOG - help - Install handlers for various CPU exception/trap vectors to - make debugging them easier, at a small expense in code size. - This prints out the specific exception vector and any associated - error codes. - config X86_VERY_EARLY_CONSOLE bool "Support very early boot printk" depends on PRINTK @@ -472,7 +459,7 @@ config X86_EFI_CONSOLE bool depends on X86_EFI && X86_64 && !X86_VERY_EARLY_CONSOLE select EFI_CONSOLE - default y + default y if !UART_CONSOLE help This enables the use of the UEFI console device as the Zephyr printk handler. It requires that no interferences diff --git a/arch/x86/core/CMakeLists.txt b/arch/x86/core/CMakeLists.txt index 9268dc4cf4d..e8055c6fae2 100644 --- a/arch/x86/core/CMakeLists.txt +++ b/arch/x86/core/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_REBOOT_RST_CNT reboot_rst_cnt.c) zephyr_library_sources_ifdef(CONFIG_MULTIBOOT_INFO multiboot.c) zephyr_library_sources_ifdef(CONFIG_X86_EFI efi.c) zephyr_library_sources_ifdef(CONFIG_ACPI legacy_bios.c) +zephyr_library_sources_ifdef(CONFIG_ACPI x86_acpi.c) zephyr_library_sources_ifdef(CONFIG_X86_MMU x86_mmu.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.c) zephyr_library_sources_ifdef(CONFIG_ARCH_CACHE cache.c) diff --git a/arch/x86/core/cache.c b/arch/x86/core/cache.c index cd0bbb8e16d..e80cb6d1dbf 100644 --- a/arch/x86/core/cache.c +++ b/arch/x86/core/cache.c @@ -18,6 +18,11 @@ #include #include +/* Not Write-through bit */ +#define X86_REG_CR0_NW BIT(29) +/* Cache Disable bit */ +#define X86_REG_CR0_CD BIT(30) + static inline void z_x86_wbinvd(void) { __asm__ volatile("wbinvd;\n\t" : : : "memory"); @@ -25,25 +30,28 @@ static inline void z_x86_wbinvd(void) void arch_dcache_enable(void) { - uint32_t cr0; + unsigned long cr0 = 0; /* Enable write-back caching by clearing the NW and CD bits */ - __asm__ volatile("movl %%cr0, %0;\n\t" - "andl $0x9fffffff, %0;\n\t" - "movl %0, %%cr0;\n\t" - : "=r" (cr0)); + __asm__ volatile("mov %%cr0, %0;\n\t" + "and %1, %0;\n\t" + "mov %0, %%cr0;\n\t" + : "=r" (cr0) + : "i" (~(X86_REG_CR0_NW | X86_REG_CR0_CD))); } void arch_dcache_disable(void) { - uint32_t cr0; + unsigned long cr0 = 0; /* Enter the no-fill mode by setting NW=0 and CD=1 */ - __asm__ volatile("movl %%cr0, %0;\n\t" - "andl $0xdfffffff, %0;\n\t" - "orl $0x40000000, %0;\n\t" - "movl %0, %%cr0;\n\t" - : "=r" (cr0)); + __asm__ volatile("mov %%cr0, %0;\n\t" + "and %1, %0;\n\t" + "or %2, %0;\n\t" + "mov %0, %%cr0;\n\t" + : "=r" (cr0) + : "i" (~(X86_REG_CR0_NW)), + "i" (X86_REG_CR0_CD)); /* Flush all caches */ z_x86_wbinvd(); diff --git a/arch/x86/core/common.S b/arch/x86/core/common.S index 856ae7b2e0e..1f390df42fb 100644 --- a/arch/x86/core/common.S +++ b/arch/x86/core/common.S @@ -17,7 +17,7 @@ * contains MULTIBOOT_EAX_MAGIC and EBX points to a valid 'struct * multiboot_info'; otherwise EBX is just junk. Check EAX early * before it's clobbered and leave a sentinel (0) in EBX if invalid. - * The valid in EBX will be the argument to z_x86_prep_c(), so the + * The valid in EBX will be the argument to z_prep_c(), so the * subsequent code must, of course, be sure to preserve it meanwhile. */ diff --git a/arch/x86/core/early_serial.c b/arch/x86/core/early_serial.c index 572b71cf5a0..3a0bc7465e1 100644 --- a/arch/x86/core/early_serial.c +++ b/arch/x86/core/early_serial.c @@ -11,10 +11,11 @@ #include -#define UART_IS_IOPORT_ACCESS \ - DT_NODE_HAS_PROP(DT_CHOSEN(zephyr_console), io_mapped) +#if DT_PROP_OR(DT_CHOSEN(zephyr_console), io_mapped, 0) != 0 +#define UART_IS_IOPORT_ACCESS 1 +#endif -#if UART_IS_IOPORT_ACCESS +#if defined(UART_IS_IOPORT_ACCESS) /* Legacy I/O Port Access to a NS16550 UART */ #define IN(reg) sys_in8(reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) #define OUT(reg, val) sys_out8(val, reg + DT_REG_ADDR(DT_CHOSEN(zephyr_console))) @@ -89,7 +90,7 @@ int arch_printk_char_out(int c) void z_x86_early_serial_init(void) { -#if defined(DEVICE_MMIO_IS_IN_RAM) && !UART_IS_IOPORT_ACCESS +#if defined(DEVICE_MMIO_IS_IN_RAM) && !defined(UART_IS_IOPORT_ACCESS) #ifdef X86_SOC_EARLY_SERIAL_PCIDEV struct pcie_bar mbar; pcie_get_mbar(X86_SOC_EARLY_SERIAL_PCIDEV, 0, &mbar); diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index 75a5402a4b2..32513a95790 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -28,7 +28,7 @@ GTEXT(__start) /* externs */ - GTEXT(z_x86_prep_c) + GTEXT(z_prep_c) GTEXT(z_bss_zero) GTEXT(z_data_copy) @@ -287,7 +287,7 @@ __csSet: /* pointer to multiboot info, or NULL */ movl %ebx, __x86_boot_arg_t_arg_OFFSET(%ebp) pushl $x86_cpu_boot_arg - call z_x86_prep_c /* enter kernel; never returns */ + call z_prep_c /* enter kernel; never returns */ #if defined(CONFIG_X86_SSE) diff --git a/arch/x86/core/ia32/gdbstub.c b/arch/x86/core/ia32/gdbstub.c index afda9b5a7e2..692ea78baf4 100644 --- a/arch/x86/core/ia32/gdbstub.c +++ b/arch/x86/core/ia32/gdbstub.c @@ -174,12 +174,8 @@ size_t arch_gdb_reg_readone(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen, * registers instead of stopping in the middle of * "info registers all". */ - if (buflen >= 2) { - memcpy(buf, "xx", 2); - ret = 2; - } else { - ret = 0; - } + memcpy(buf, "xx", 2); + ret = 2; } else { ret = bin2hex((const uint8_t *)&(ctx->registers[regno]), sizeof(ctx->registers[regno]), @@ -218,17 +214,41 @@ size_t arch_gdb_reg_writeone(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen, static __used void z_gdb_debug_isr(z_arch_esf_t *esf) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:enter %s (IV_DEBUG)\n", __func__); +#endif + z_gdb_interrupt(IV_DEBUG, esf); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:exit %s (IV_DEBUG)\n", __func__); +#endif } static __used void z_gdb_break_isr(z_arch_esf_t *esf) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:enter %s (IV_BREAKPOINT)\n", __func__); +#endif + z_gdb_interrupt(IV_BREAKPOINT, esf); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:exit %s (IV_BREAKPOINT)\n", __func__); +#endif } void arch_gdb_init(void) { +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s awaits GDB connection\n", __func__); +#endif + __asm__ volatile ("int3"); + +#ifdef CONFIG_GDBSTUB_TRACE + printk("gdbstub:%s GDB is connected\n", __func__); +#endif } /* Hook current IDT. */ diff --git a/arch/x86/core/intel64.cmake b/arch/x86/core/intel64.cmake index cd37d5c497e..1cb25ebe220 100644 --- a/arch/x86/core/intel64.cmake +++ b/arch/x86/core/intel64.cmake @@ -15,7 +15,8 @@ zephyr_library_sources( intel64/thread.c intel64/fatal.c ) - +zephyr_library_sources_ifdef(CONFIG_SMP intel64/smp.c) +zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD intel64/irq_offload.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE intel64/userspace.S) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE intel64/tls.c) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP intel64/coredump.c) diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 204264cbdf9..2a845960b87 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -110,7 +110,7 @@ struct x86_cpuboot x86_cpuboot[] = { Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_ISR_STACK_SIZE), .stack_size = Z_KERNEL_STACK_SIZE_ADJUST(CONFIG_ISR_STACK_SIZE), - .fn = z_x86_prep_c, + .fn = z_prep_c, .arg = &x86_cpu_boot_arg, }, #if CONFIG_MP_MAX_NUM_CPUS > 1 @@ -176,7 +176,7 @@ void arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz, #endif } -/* Per-CPU initialization, C domain. On the first CPU, z_x86_prep_c is the +/* Per-CPU initialization, C domain. On the first CPU, z_prep_c is the * next step. For other CPUs it is probably smp_init_top(). */ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) @@ -208,4 +208,6 @@ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) /* Enter kernel, never return */ cpuboot->ready++; cpuboot->fn(cpuboot->arg); + + CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } diff --git a/arch/x86/core/intel64/irq.c b/arch/x86/core/intel64/irq.c index a7304271746..f8e251b8046 100644 --- a/arch/x86/core/intel64/irq.c +++ b/arch/x86/core/intel64/irq.c @@ -13,18 +13,11 @@ #include #include #include -#include + LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); unsigned char _irq_to_interrupt_vector[CONFIG_MAX_IRQ_LINES]; - -/* - * The low-level interrupt code consults these arrays to dispatch IRQs, so - * so be sure to keep locore.S up to date with any changes. Note the indices: - * use (vector - IV_IRQS), since exception vectors do not appear here. - */ - #define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); @@ -138,45 +131,6 @@ int arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, return vector; } -#ifdef CONFIG_IRQ_OFFLOAD -#include - -void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) -{ - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine; - x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter; - __asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR) - : "memory"); - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL; -} - -#endif /* CONFIG_IRQ_OFFLOAD */ - -#if defined(CONFIG_SMP) - -void z_x86_ipi_setup(void) -{ - /* - * z_sched_ipi() doesn't have the same signature as a typical ISR, so - * we fudge it with a cast. the argument is ignored, no harm done. - */ - - x86_irq_funcs[CONFIG_SCHED_IPI_VECTOR - IV_IRQS] = - (void *) z_sched_ipi; - - /* TLB shootdown handling */ - x86_irq_funcs[CONFIG_TLB_IPI_VECTOR - IV_IRQS] = z_x86_tlb_ipi; -} - -/* - * it is not clear exactly how/where/why to abstract this, as it - * assumes the use of a local APIC (but there's no other mechanism). - */ -void arch_sched_ipi(void) -{ - z_loapic_ipi(0, LOAPIC_ICR_IPI_OTHERS, CONFIG_SCHED_IPI_VECTOR); -} -#endif /* The first bit is used to indicate whether the list of reserved interrupts * have been initialized based on content stored in the irq_alloc linker diff --git a/arch/x86/core/intel64/irq_offload.c b/arch/x86/core/intel64/irq_offload.c new file mode 100644 index 00000000000..0146321f7d9 --- /dev/null +++ b/arch/x86/core/intel64/irq_offload.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Intel corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file IRQ offload - x8664 implementation + */ + +#include +#include +#include + +#define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ + +extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); +extern const void *x86_irq_args[NR_IRQ_VECTORS]; + + +void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) +{ + x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine; + x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter; + __asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR) + : "memory"); + x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL; +} diff --git a/arch/x86/core/intel64/smp.c b/arch/x86/core/intel64/smp.c new file mode 100644 index 00000000000..a73ba9c8f38 --- /dev/null +++ b/arch/x86/core/intel64/smp.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#define NR_IRQ_VECTORS (IV_NR_VECTORS - IV_IRQS) /* # vectors free for IRQs */ + +extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); +extern const void *x86_irq_args[NR_IRQ_VECTORS]; + + +int arch_smp_init(void) +{ + /* + * z_sched_ipi() doesn't have the same signature as a typical ISR, so + * we fudge it with a cast. the argument is ignored, no harm done. + */ + + x86_irq_funcs[CONFIG_SCHED_IPI_VECTOR - IV_IRQS] = + (void *) z_sched_ipi; + + /* TLB shootdown handling */ + x86_irq_funcs[CONFIG_TLB_IPI_VECTOR - IV_IRQS] = z_x86_tlb_ipi; + return 0; +} + +/* + * it is not clear exactly how/where/why to abstract this, as it + * assumes the use of a local APIC (but there's no other mechanism). + */ +void arch_sched_ipi(void) +{ + z_loapic_ipi(0, LOAPIC_ICR_IPI_OTHERS, CONFIG_SCHED_IPI_VECTOR); +} + +SYS_INIT(arch_smp_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/arch/x86/core/pcie.c b/arch/x86/core/pcie.c index 5c1e83725bb..878e6886d7b 100644 --- a/arch/x86/core/pcie.c +++ b/arch/x86/core/pcie.c @@ -162,7 +162,6 @@ void pcie_conf_write(pcie_bdf_t bdf, unsigned int reg, uint32_t data) #ifdef CONFIG_INTEL_VTD_ICTL #include -#include static const struct device *const vtd = DEVICE_DT_GET_ONE(intel_vt_d); diff --git a/arch/x86/core/prep_c.c b/arch/x86/core/prep_c.c index ee095efe33d..17a4a7f7473 100644 --- a/arch/x86/core/prep_c.c +++ b/arch/x86/core/prep_c.c @@ -21,7 +21,7 @@ __pinned_data x86_boot_arg_t x86_cpu_boot_arg; * CPU for SMP systems. */ __boot_func -FUNC_NORETURN void z_x86_prep_c(void *arg) +FUNC_NORETURN void z_prep_c(void *arg) { x86_boot_arg_t *cpu_arg = arg; @@ -74,8 +74,9 @@ FUNC_NORETURN void z_x86_prep_c(void *arg) #endif #if defined(CONFIG_SMP) - z_x86_ipi_setup(); + arch_smp_init(); #endif z_cstart(); + CODE_UNREACHABLE; } diff --git a/arch/x86/core/userspace.c b/arch/x86/core/userspace.c index 2b058206232..9380c14d005 100644 --- a/arch/x86/core/userspace.c +++ b/arch/x86/core/userspace.c @@ -11,6 +11,10 @@ #include #include +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + #ifndef CONFIG_X86_KPTI /* Update the to the incoming thread's page table, and update the location of * the privilege elevation stack. diff --git a/arch/x86/core/x86_acpi.c b/arch/x86/core/x86_acpi.c new file mode 100644 index 00000000000..badbd3b414f --- /dev/null +++ b/arch/x86/core/x86_acpi.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +uint32_t arch_acpi_encode_irq_flags(uint8_t polarity, uint8_t trigger) +{ + uint32_t irq_flag = IRQ_DELIVERY_LOWEST; + + if (trigger == ACPI_LEVEL_SENSITIVE) { + irq_flag |= IRQ_TYPE_LEVEL; + } else { + irq_flag |= IRQ_TYPE_EDGE; + } + + if (polarity == ACPI_ACTIVE_HIGH) { + irq_flag |= IRQ_TYPE_HIGH; + } else if (polarity == ACPI_ACTIVE_LOW) { + irq_flag |= IRQ_TYPE_LOW; + } + + return irq_flag; +} diff --git a/arch/x86/include/kernel_arch_func.h b/arch/x86/include/kernel_arch_func.h index 7c080b8e25b..00b411978ec 100644 --- a/arch/x86/include/kernel_arch_func.h +++ b/arch/x86/include/kernel_arch_func.h @@ -37,7 +37,7 @@ static inline bool arch_is_in_isr(void) struct multiboot_info; -extern FUNC_NORETURN void z_x86_prep_c(void *arg); +extern FUNC_NORETURN void z_prep_c(void *arg); #ifdef CONFIG_X86_VERY_EARLY_CONSOLE /* Setup ultra-minimal serial driver for printk() */ diff --git a/arch/xtensa/CMakeLists.txt b/arch/xtensa/CMakeLists.txt index 133d74331d8..21de223d4ec 100644 --- a/arch/xtensa/CMakeLists.txt +++ b/arch/xtensa/CMakeLists.txt @@ -1,4 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/arch/xtensa/arch.h) set_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-xtensa-le) add_subdirectory(core) + +if (CONFIG_XTENSA_INSECURE_USERSPACE) + message(WARNING " + This userspace implementation uses the window ABI this means that the kernel + will spill registers in behave of the userpsace. Use it carefully.") +endif() diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index a1517f17ed0..aa888e8331a 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -10,23 +10,9 @@ config ARCH default "xtensa" config SIMULATOR_XTENSA - bool "Simulator Configuration" + bool "Simulator Target" help - Specify if the board configuration should be treated as a simulator. - -config SYS_CLOCK_HW_CYCLES_PER_SEC - prompt "Hardware clock cycles per second, 2000000 for ISS" - default 2000000 - range 1000000 1000000000 - help - This option specifies hardware clock. - -config XTENSA_NO_IPC - bool "Core has no IPC support" - select ATOMIC_OPERATIONS_C - help - Uncheck this if your core does not implement "SCOMPARE1" register and "s32c1i" - instruction. + Enable if building to run on simulator. config XTENSA_RESET_VECTOR bool "Build reset vector code" @@ -111,54 +97,84 @@ if CPU_HAS_MMU config XTENSA_MMU bool "Xtensa MMU Support" - default n select MMU + select ARCH_MEM_DOMAIN_SYNCHRONOUS_API if USERSPACE select XTENSA_SMALL_VECTOR_TABLE_ENTRY select KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK if XTENSA_RPO_CACHE + select CURRENT_THREAD_USE_NO_TLS if USERSPACE help Enable support for Xtensa Memory Management Unit. if XTENSA_MMU - choice - prompt "PageTable virtual adddress" - default XTENSA_MMU_PTEVADDR_20000000 - help - The virtual address for Xtensa page table (PTEVADDR). +choice + prompt "PageTable virtual address" + default XTENSA_MMU_PTEVADDR_20000000 + help + The virtual address for Xtensa page table (PTEVADDR). - config XTENSA_MMU_PTEVADDR_20000000 - bool "0x20000000" +config XTENSA_MMU_PTEVADDR_20000000 + bool "0x20000000" - endchoice +endchoice - config XTENSA_MMU_PTEVADDR - hex - default 0x20000000 if XTENSA_MMU_PTEVADDR_20000000 - help - The virtual address for Xtensa page table (PTEVADDR). +config XTENSA_MMU_PTEVADDR + hex + default 0x20000000 if XTENSA_MMU_PTEVADDR_20000000 + help + The virtual address for Xtensa page table (PTEVADDR). - config XTENSA_MMU_PTEVADDR_SHIFT - int - default 29 if XTENSA_MMU_PTEVADDR_20000000 - help - The bit shift number for the virtual address for Xtensa - page table (PTEVADDR). +config XTENSA_MMU_PTEVADDR_SHIFT + int + default 29 if XTENSA_MMU_PTEVADDR_20000000 + help + The bit shift number for the virtual address for Xtensa + page table (PTEVADDR). - config XTENSA_MMU_NUM_L2_TABLES - int "Number of L2 page tables" - default 10 - help - Each table can address up to 4MB memory address. +config XTENSA_MMU_NUM_L1_TABLES + int "Number of L1 page tables" + default 1 if !USERSPACE + default 4 + help + This option specifies the maximum number of traslation tables. + Translation tables are directly related to the number of + memory domains in the target, considering the kernel itself requires one. + +config XTENSA_MMU_NUM_L2_TABLES + int "Number of L2 page tables" + default 20 if USERSPACE + default 10 + help + Each table can address up to 4MB memory address. - config XTENSA_MMU_DOUBLE_MAP - bool "Map memory in cached and uncached region" - default n +config XTENSA_MMU_DOUBLE_MAP + bool "Map memory in cached and uncached region" + help + This option specifies that the memory is mapped in two + distinct region, cached and uncached. + + config XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP + bool help - This option specifies that the memory is mapped in two - distinct region, cached and uncached. + This invalidates all TLBs referred by the incoming thread's + memory domain when swapping page tables. endif # XTENSA_MMU +config XTENSA_SYSCALL_USE_HELPER + bool "Use userspace syscall helper" + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xt-clang" + depends on USERSPACE + help + Use syscall helpers for passing more then 3 arguments. + This is a workaround for toolchains where they have + issue modeling register usage. + +config XTENSA_INSECURE_USERSPACE + bool + default y if USERSPACE + depends on XTENSA_MMU + endif # CPU_HAS_MMU endmenu diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index c6fffd4f5e1..db0909bb4f8 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -8,9 +8,10 @@ zephyr_library_sources( cpu_idle.c fatal.c window_vectors.S - xtensa-asm2-util.S - xtensa-asm2.c + xtensa_asm2_util.S irq_manage.c + thread.c + vector_handlers.c ) zephyr_library_sources_ifdef(CONFIG_XTENSA_USE_CORE_CRT1 crt1.S) @@ -21,7 +22,11 @@ zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_TIMING_FUNCTIONS timing.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) -zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU xtensa_mmu.c) +zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S) +zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c) +zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c) +zephyr_library_sources_ifdef(CONFIG_SMP smp.c) zephyr_library_sources_ifdef( CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK @@ -32,8 +37,6 @@ if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc") zephyr_library_sources(xcc_stubs.c) endif() -zephyr_library_include_directories(include) - add_subdirectory(startup) # This produces a preprocessed and regenerated (in the sense of gcc @@ -57,6 +60,8 @@ add_custom_command(OUTPUT ${CORE_ISA_DM} set(ZSR_H ${CMAKE_BINARY_DIR}/zephyr/include/generated/zsr.h) add_custom_command(OUTPUT ${ZSR_H} DEPENDS ${CORE_ISA_DM} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_zsr.py + $<$:--mmu> + $<$:--coherence> ${CORE_ISA_DM} ${ZSR_H}) add_custom_target(zsr_h DEPENDS ${ZSR_H}) add_dependencies(zephyr_interface zsr_h) diff --git a/arch/xtensa/core/README_MMU.txt b/arch/xtensa/core/README_MMU.txt new file mode 100644 index 00000000000..499a251cdf2 --- /dev/null +++ b/arch/xtensa/core/README_MMU.txt @@ -0,0 +1,268 @@ +# Xtensa MMU Operation + +As with other elements of the architecture, paged virtual memory +management on Xtensa is somewhat unique. And there is similarly a +lack of introductory material available. This document is an attempt +to introduce the architecture at an overview/tutorial level, and to +describe Zephyr's specific implementation choices. + +## General TLB Operation + +The Xtensa MMU operates on top of a fairly conventional TLB cache. +The TLB stores virtual to physical translation for individual pages of +memory. It is partitioned into an automatically managed +4-way-set-associative bank of entries mapping 4k pages, and 3-6 +"special" ways storing mappings under OS control. Some of these are +for mapping pages larger than 4k, which Zephyr does not directly +support. A few are for bootstrap and initialization, and will be +discussed below. + +Like the L1 cache, the TLB is split into separate instruction and data +entries. Zephyr manages both as needed, but symmetrically. The +architecture technically supports separately-virtualized instruction +and data spaces, but the hardware page table refill mechanism (see +below) does not, and Zephyr's memory spaces are unified regardless. + +The TLB may be loaded with permissions and attributes controlling +cacheability, access control based on ring (i.e. the contents of the +RING field of the PS register) and togglable write and execute access. +Memory access, even with a matching TLB entry, may therefore create +Kernel/User exceptions as desired to enforce permissions choices on +userspace code. + +Live TLB entries are tagged with an 8-bit "ASID" value derived from +their ring field of the PTE that loaded them, via a simple translation +specified in the RASID special register. The intent is that each +non-kernel address space will get a separate ring 3 ASID set in RASID, +such that you can switch between them without a TLB flush. The ASID +value of ring zero is fixed at 1, it may not be changed. (An ASID +value of zero is used to tag an invalid/unmapped TLB entry at +initialization, but this mechanism isn't accessible to OS code except +in special circumstances, and in any case there is already an invalid +attribute value that can be used in a PTE). + +## Virtually-mapped Page Tables + +Xtensa has a unique (and, to someone exposed for the first time, +extremely confusing) "page table" format. The simplest was to begin +to explain this is just to describe the (quite simple) hardware +behavior: + +On a TLB miss, the hardware immediately does a single fetch (at ring 0 +privilege) from RAM by adding the "desired address right shifted by +10 bits with the bottom two bits set to zero" (i.e. the page frame +number in units of 4 bytes) to the value in the PTEVADDR special +register. If this load succeeds, then the word is treated as a PTE +with which to fill the TLB and use for a (restarted) memory access. +This is extremely simple (just one extra hardware state that does just +one thing the hardware can already do), and quite fast (only one +memory fetch vs. e.g. the 2-5 fetches required to walk a page table on +x86). + +This special "refill" fetch is otherwise identical to any other memory +access, meaning it too uses the TLB to translate from a virtual to +physical address. Which means that the page tables occupy a 4M region +of virtual, not physical, address space, in the same memory space +occupied by the running code. The 1024 pages in that range (not all +of which might be mapped in physical memory) are a linear array of +1048576 4-byte PTE entries, each describing a mapping for 4k of +virtual memory. Note especially that exactly one of those pages +contains the 1024 PTE entries for the 4M page table itself, pointed to +by PTEVADDR. + +Obviously, the page table memory being virtual means that the fetch +can fail: there are 1024 possible pages in a complete page table +covering all of memory, and the ~16 entry TLB clearly won't contain +entries mapping all of them. If we are missing a TLB entry for the +page translation we want (NOT for the original requested address, we +already know we're missing that TLB entry), the hardware has exactly +one more special trick: it throws a TLB Miss exception (there are two, +one each for instruction/data TLBs, but in Zephyr they operate +identically). + +The job of that exception handler is simply to ensure that the TLB has +an entry for the page table page we want. And the simplest way to do +that is to just load the faulting PTE as an address, which will then +go through the same refill process above. This second TLB fetch in +the exception handler may result in an invalid/inapplicable mapping +within the 4M page table region. This is an typical/expected runtime +fault, and simply indicates unmapped memory. The result is TLB miss +exception from within the TLB miss exception handler (i.e. while the +EXCM bit is set). This will produce a Double Exception fault, which +is handled by the OS identically to a general Kernel/User data access +prohibited exception. + +After the TLB refill exception, the original faulting instruction is +restarted, which retries the refill process, which succeeds in +fetching a new TLB entry, which is then used to service the original +memory access. (And may then result in yet another exception if it +turns out that the TLB entry doesn't permit the access requested, of +course.) + +## Special Cases + +The page-tables-specified-in-virtual-memory trick works very well in +practice. But it does have a chicken/egg problem with the initial +state. Because everything depends on state in the TLB, something +needs to tell the hardware how to find a physical address using the +TLB to begin the process. Here we exploit the separate +non-automatically-refilled TLB ways to store bootstrap records. + +First, note that the refill process to load a PTE requires that the 4M +space of PTE entries be resolvable by the TLB directly, without +requiring another refill. This 4M mapping is provided by a single +page of PTE entries (which itself lives in the 4M page table region!). +This page must always be in the TLB. + +Thankfully, for the data TLB Xtensa provides 3 special/non-refillable +ways (ways 7-9) with at least one 4k page mapping each. We can use +one of these to "pin" the top-level page table entry in place, +ensuring that a refill access will be able to find a PTE address. + +But now note that the load from that PTE address for the refill is +done in an exception handler. And running an exception handler +requires doing a fetch via the instruction TLB. And that obviously +means that the page(s) containing the exception handler must never +require a refill exception of its own. + +Ideally we would just pin the vector/handler page in the ITLB in the +same way we do for data, but somewhat inexplicably, Xtensa does not +provide 4k "pinnable" ways in the instruction TLB (frankly this seems +like a design flaw). + +Instead, we load ITLB entries for vector handlers via the refill +mechanism using the data TLB, and so need the refill mechanism for the +vector page to succeed always. The way to do this is to similarly pin +the page table page containing the (single) PTE for the vector page in +the data TLB, such that instruction fetches always find their TLB +mapping via refill, without requiring an exception. + +## Initialization + +Unlike most other architectures, Xtensa does not have a "disable" mode +for the MMU. Virtual address translation through the TLB is active at +all times. There therefore needs to be a mechanism for the CPU to +execute code before the OS is able to initialize a refillable page +table. + +The way Xtensa resolves this (on the hardware Zephyr supports, see the +note below) is to have an 8-entry set ("way 6") of 512M pages able to +cover all of memory. These 8 entries are initialized as valid, with +attributes specifying that they are accessible only to an ASID of 1 +(i.e. the fixed ring zero / kernel ASID), writable, executable, and +uncached. So at boot the CPU relies on these TLB entries to provide a +clean view of hardware memory. + +But that means that enabling page-level translation requires some +care, as the CPU will throw an exception ("multi hit") if a memory +access matches more than one live entry in the TLB. The +initialization algorithm is therefore: + +0. Start with a fully-initialized page table layout, including the + top-level "L1" page containing the mappings for the page table + itself. + +1. Ensure that the initialization routine does not cross a page + boundary (to prevent stray TLB refill exceptions), that it occupies + a separate 4k page than the exception vectors (which we must + temporarily double-map), and that it operates entirely in registers + (to avoid doing memory access at inopportune moments). + +2. Pin the L1 page table PTE into the data TLB. This creates a double + mapping condition, but it is safe as nothing will use it until we + start refilling. + +3. Pin the page table page containing the PTE for the TLB miss + exception handler into the data TLB. This will likewise not be + accessed until the double map condition is resolved. + +4. Set PTEVADDR appropriately. The CPU state to handle refill + exceptions is now complete, but cannot be used until we resolve the + double mappings. + +5. Disable the initial/way6 data TLB entries first, by setting them to + an ASID of zero. This is safe as the code being executed is not + doing data accesses yet (including refills), and will resolve the + double mapping conditions we created above. + +6. Disable the initial/way6 instruction TLBs second. The very next + instruction following the invalidation of the currently-executing + code page will then cause a TLB refill exception, which will work + normally because we just resolved the final double-map condition. + (Pedantic note: if the vector page and the currently-executing page + are in different 512M way6 pages, disable the mapping for the + exception handlers first so the trap from our current code can be + handled. Currently Zephyr doesn't handle this condition as in all + reasonable hardware these regions will be near each other) + +Note: there is a different variant of the Xtensa MMU architecture +where the way 5/6 pages are immutable, and specify a set of +unchangable mappings from the final 384M of memory to the bottom and +top of physical memory. The intent here would (presumably) be that +these would be used by the kernel for all physical memory and that the +remaining memory space would be used for virtual mappings. This +doesn't match Zephyr's architecture well, as we tend to assume +page-level control over physical memory (e.g. .text/.rodata is cached +but .data is not on SMP, etc...). And in any case we don't have any +such hardware to experiment with. But with a little address +translation we could support this. + +## ASID vs. Virtual Mapping + +The ASID mechanism in Xtensa works like other architectures, and is +intended to be used similarly. The intent of the design is that at +context switch time, you can simply change RADID and the page table +data, and leave any existing mappings in place in the TLB using the +old ASID value(s). So in the common case where you switch back, +nothing needs to be flushed. + +Unfortunately this runs afoul of the virtual mapping of the page +refill: data TLB entries storing the 4M page table mapping space are +stored at ASID 1 (ring 0), they can't change when the page tables +change! So this region naively would have to be flushed, which is +tantamount to flushing the entire TLB regardless (the TLB is much +smaller than the 1024-page PTE array). + +The resolution in Zephyr is to give each ASID its own PTEVADDR mapping +in virtual space, such that the page tables don't overlap. This is +expensive in virtual address space: assigning 4M of space to each of +the 256 ASIDs (actually 254 as 0 and 1 are never used by user access) +would take a full gigabyte of address space. Zephyr optimizes this a +bit by deriving a unique sequential ASID from the hardware address of +the statically allocated array of L1 page table pages. + +Note, obviously, that any change of the mappings within an ASID +(e.g. to re-use it for another memory domain, or just for any runtime +mapping change other than mapping previously-unmapped pages) still +requires a TLB flush, and always will. + +## SMP/Cache Interaction + +A final important note is that the hardware PTE refill fetch works +like any other CPU memory access, and in particular it is governed by +the cacheability attributes of the TLB entry through which it was +loaded. This means that if the page table entries are marked +cacheable, then the hardware TLB refill process will be downstream of +the L1 data cache on the CPU. If the physical memory storing page +tables has been accessed recently by the CPU (for a refill of another +page mapped within the same cache line, or to change the tables) then +the refill will be served from the data cache and not main memory. + +This may or may not be desirable depending on access patterns. It +lets the L1 data cache act as a "L2 TLB" for applications with a lot +of access variability. But it also means that the TLB entries end up +being stored twice in the same CPU, wasting transistors that could +presumably store other useful data. + +But it it also important to note that the L1 data cache on Xtensa is +incoherent! The cache being used for refill reflects the last access +on the current CPU only, and not of the underlying memory being +mapped. Page table changes in the data cache of one CPU will be +invisible to the data cache of another. There is no simple way of +notifying another CPU of changes to page mappings beyond doing +system-wide flushes on all cpus every time a memory domain is +modified. + +The result is that, when SMP is enabled, Zephyr must ensure that all +page table mappings in the system are set uncached. The OS makes no +attempt to bolt on a software coherence layer. diff --git a/arch/xtensa/core/README-WINDOWS.rst b/arch/xtensa/core/README_WINDOWS.rst similarity index 100% rename from arch/xtensa/core/README-WINDOWS.rst rename to arch/xtensa/core/README_WINDOWS.rst diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c index 26060dea8c3..a2eec620774 100644 --- a/arch/xtensa/core/coredump.c +++ b/arch/xtensa/core/coredump.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #define ARCH_HDR_VER 1 diff --git a/arch/xtensa/core/crt1.S b/arch/xtensa/core/crt1.S index 0fa3ad23099..c616b0889d7 100644 --- a/arch/xtensa/core/crt1.S +++ b/arch/xtensa/core/crt1.S @@ -24,10 +24,6 @@ .global __start .type z_cstart, @function -#ifdef CONFIG_XTENSA_MMU -.type z_xtensa_mmu_init, @function -#endif - /* Macros to abstract away ABI differences */ @@ -192,10 +188,6 @@ _start: #endif /* !XCHAL_HAVE_BOOTLOADER */ -#ifdef CONFIG_XTENSA_MMU - CALL z_xtensa_mmu_init -#endif - /* Enter C domain, never returns from here */ CALL z_cstart diff --git a/arch/xtensa/core/debug_helpers_asm.S b/arch/xtensa/core/debug_helpers_asm.S index 8d895ba39dd..3dacc1a4587 100644 --- a/arch/xtensa/core/debug_helpers_asm.S +++ b/arch/xtensa/core/debug_helpers_asm.S @@ -8,15 +8,15 @@ #include #include #include -#include +#include #include .section .iram1, "ax" .align 4 - .global z_xtensa_backtrace_get_start - .type z_xtensa_backtrace_get_start, @function -z_xtensa_backtrace_get_start: + .global xtensa_backtrace_get_start + .type xtensa_backtrace_get_start, @function +xtensa_backtrace_get_start: entry a1, 32 /* Spill registers onto stack (excluding this function) */ call8 xthal_window_spill diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c new file mode 100644 index 00000000000..976be9f794a --- /dev/null +++ b/arch/xtensa/core/elf.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(llext); + +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_RTLD 2 +#define R_XTENSA_GLOB_DAT 3 +#define R_XTENSA_JMP_SLOT 4 +#define R_XTENSA_RELATIVE 5 +#define R_XTENSA_PLT 6 + +/** + * @brief Architecture specific function for relocating shared elf + * + * Elf files contain a series of relocations described in multiple sections. + * These relocation instructions are architecture specific and each architecture + * supporting modules must implement this. + */ +void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, + elf_rela_t *rel, size_t got_offset) +{ + uint8_t *text = ext->mem[LLEXT_MEM_TEXT]; + int type = ELF32_R_TYPE(rel->r_info); + + if (type == R_XTENSA_RELATIVE) { + elf_word ptr_offset = *(elf_word *)(text + got_offset); + + LOG_DBG("relocation type %u offset %#x value %#x", + type, got_offset, ptr_offset); + + /* Relocate a local symbol: Xtensa specific */ + *(elf_word *)(text + got_offset) = (elf_word)(text + ptr_offset - + ldr->sects[LLEXT_MEM_TEXT].sh_addr); + } +} diff --git a/arch/xtensa/core/fatal.c b/arch/xtensa/core/fatal.c index e693937f99b..c6bd07c2b44 100644 --- a/arch/xtensa/core/fatal.c +++ b/arch/xtensa/core/fatal.c @@ -8,13 +8,11 @@ #include #include #include -#include -#if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) -#if XCHAL_HAVE_WINDOWED #include -#endif -#endif -#include +#include + +#include + #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -22,18 +20,7 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); #include #endif -/* Need to do this as a macro since regnum must be an immediate value */ -#define get_sreg(regnum_p) ({ \ - unsigned int retval; \ - __asm__ volatile( \ - "rsr %[retval], %[regnum]\n\t" \ - : [retval] "=r" (retval) \ - : [regnum] "i" (regnum_p)); \ - retval; \ - }) - - -char *z_xtensa_exccause(unsigned int cause_code) +char *xtensa_exccause(unsigned int cause_code) { #if defined(CONFIG_PRINTK) || defined(CONFIG_LOG) switch (cause_code) { @@ -86,6 +73,8 @@ char *z_xtensa_exccause(unsigned int cause_code) case 63: /* i.e. z_except_reason */ return "zephyr exception"; + case 64: + return "kernel oops"; default: return "unknown/reserved"; } @@ -95,8 +84,9 @@ char *z_xtensa_exccause(unsigned int cause_code) #endif } -void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) +void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) { +#ifdef CONFIG_EXCEPTION_DEBUG if (esf) { /* Don't want to get elbowed by xtensa_switch * in between printing registers and dumping them; @@ -104,18 +94,17 @@ void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf) */ unsigned int key = arch_irq_lock(); - z_xtensa_dump_stack(esf); + xtensa_dump_stack(esf); - coredump(reason, esf, IS_ENABLED(CONFIG_MULTITHREADING) ? k_current_get() : NULL); #if defined(CONFIG_XTENSA_ENABLE_BACKTRACE) #if XCHAL_HAVE_WINDOWED - z_xtensa_backtrace_print(100, (int *)esf); + xtensa_backtrace_print(100, (int *)esf); #endif #endif - arch_irq_unlock(key); } +#endif /* CONFIG_EXCEPTION_DEBUG */ z_fatal_error(reason, esf); } @@ -140,3 +129,31 @@ FUNC_NORETURN void z_system_halt(unsigned int reason) CODE_UNREACHABLE; } #endif + +FUNC_NORETURN void arch_syscall_oops(void *ssf) +{ + xtensa_arch_kernel_oops(K_ERR_KERNEL_OOPS, ssf); + + CODE_UNREACHABLE; +} + +#ifdef CONFIG_USERSPACE +void z_impl_xtensa_user_fault(unsigned int reason) +{ + if ((_current->base.user_options & K_USER) != 0) { + if ((reason != K_ERR_KERNEL_OOPS) && + (reason != K_ERR_STACK_CHK_FAIL)) { + reason = K_ERR_KERNEL_OOPS; + } + } + xtensa_arch_except(reason); +} + +static void z_vrfy_xtensa_user_fault(unsigned int reason) +{ + z_impl_xtensa_user_fault(reason); +} + +#include + +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/gdbstub.c b/arch/xtensa/core/gdbstub.c index 034b3532866..4df72f0d355 100644 --- a/arch/xtensa/core/gdbstub.c +++ b/arch/xtensa/core/gdbstub.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include static bool not_first_break; @@ -972,8 +972,7 @@ void arch_gdb_init(void) * after level-1 interrupts is for level-2 interrupt. * So need to do an offset by subtraction. */ - z_xtensa_irq_enable(XCHAL_NUM_EXTINTERRUPTS + - XCHAL_DEBUGLEVEL - 2); + xtensa_irq_enable(XCHAL_NUM_EXTINTERRUPTS + XCHAL_DEBUGLEVEL - 2); /* * Break and go into the GDB stub. diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 8d052f4891d..7f0ec46b8e9 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # Copyright (c) 2022 Intel corporation # SPDX-License-Identifier: Apache-2.0 -import sys +import argparse import re # Scratch register allocator. Zephyr uses multiple Xtensa SRs as @@ -11,10 +11,30 @@ # -dM") core-isa.h file for the current architecture and assigns # registers to usages. -NEEDED = ("ALLOCA", "CPU", "FLUSH") +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) -coreisa = sys.argv[1] -outfile = sys.argv[2] + parser.add_argument("--coherence", action="store_true", + help="Enable scratch registers for CONFIG_KERNEL_COHERENCE") + parser.add_argument("--mmu", action="store_true", + help="Enable scratch registers for MMU usage") + parser.add_argument("coreisa", + help="Path to preprocessed core-isa.h") + parser.add_argument("outfile", + help="Output file") + + return parser.parse_args() + +args = parse_args() + +NEEDED = ["A0SAVE", "CPU"] +if args.mmu: + NEEDED += ["MMU_0", "MMU_1", "DBLEXC"] +if args.coherence: + NEEDED += ["FLUSH"] + +coreisa = args.coreisa +outfile = args.outfile syms = {} diff --git a/arch/xtensa/core/include/xtensa_mmu_priv.h b/arch/xtensa/core/include/xtensa_mmu_priv.h deleted file mode 100644 index 7519c1b6010..00000000000 --- a/arch/xtensa/core/include/xtensa_mmu_priv.h +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Xtensa MMU support - * - * Private data declarations - * - * Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ -#define ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ - -#include -#include -#include -#include - -#define Z_XTENSA_PTE_VPN_MASK 0xFFFFF000U -#define Z_XTENSA_PTE_PPN_MASK 0xFFFFF000U -#define Z_XTENSA_PTE_ATTR_MASK 0x0000000FU -#define Z_XTENSA_L1_MASK 0x3FF00000U -#define Z_XTENSA_L2_MASK 0x3FFFFFU - -#define Z_XTENSA_PPN_SHIFT 12U - -#define Z_XTENSA_PTE_RING_MASK 0x00000030U - -#define Z_XTENSA_PTE(paddr, ring, attr) \ - (((paddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((ring) << 4) & Z_XTENSA_PTE_RING_MASK) | \ - ((attr) & Z_XTENSA_PTE_ATTR_MASK)) - -#define Z_XTENSA_TLB_ENTRY(vaddr, way) \ - (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | (way)) - -#define Z_XTENSA_AUTOFILL_TLB_ENTRY(vaddr) \ - (((vaddr) & Z_XTENSA_PTE_PPN_MASK) | \ - (((vaddr) >> Z_XTENSA_PPN_SHIFT) & 0x03U)) - -#define Z_XTENSA_L2_POS(vaddr) \ - (((vaddr) & Z_XTENSA_L2_MASK) >> Z_XTENSA_PPN_SHIFT) - -/* Kernel specific ASID. Ring field in the PTE */ -#define Z_XTENSA_KERNEL_RING 0 - -/* Number of data TLB ways [0-9] */ -#define Z_XTENSA_DTLB_WAYS 10 - -/* Number of instruction TLB ways [0-6] */ -#define Z_XTENSA_ITLB_WAYS 7 - -/* Number of auto-refill ways */ -#define Z_XTENSA_TLB_AUTOREFILL_WAYS 4 - - -/* PITLB HIT bit. For more information see - * Xtensa Instruction Set Architecture (ISA) Reference Manual - * 4.6.5.7 Formats for Probing MMU Option TLB Entries - */ -#define Z_XTENSA_PITLB_HIT BIT(3) - -/* PDTLB HIT bit. For more information see - * Xtensa Instruction Set Architecture (ISA) Reference Manual - * 4.6.5.7 Formats for Probing MMU Option TLB Entries - */ -#define Z_XTENSA_PDTLB_HIT BIT(4) - -/* - * Virtual address where the page table is mapped - */ -#define Z_XTENSA_PTEVADDR CONFIG_XTENSA_MMU_PTEVADDR - -/* - * Find the pte entry address of a given vaddr. - * - * For example, assuming PTEVADDR in 0xE0000000, - * the page spans from 0xE0000000 - 0xE03FFFFF - - * - * address 0x00 is in 0xE0000000 - * address 0x1000 is in 0xE0000004 - * ..... - * address 0xE0000000 (where the page is) is in 0xE0380000 - * - * Generalizing it, any PTE virtual address can be calculated this way: - * - * PTE_ENTRY_ADDRESS = PTEVADDR + ((VADDR / 4096) * 4) - */ -#define Z_XTENSA_PTE_ENTRY_VADDR(vaddr) \ - (Z_XTENSA_PTEVADDR + (((vaddr) / KB(4)) * 4)) - -/* - * The address of the top level page where the page - * is located in the virtual address. - */ -#define Z_XTENSA_PAGE_TABLE_VADDR \ - Z_XTENSA_PTE_ENTRY_VADDR(Z_XTENSA_PTEVADDR) - -static ALWAYS_INLINE void xtensa_rasid_set(uint32_t rasid) -{ - __asm__ volatile("wsr %0, rasid\n\t" - "isync\n" : : "a"(rasid)); -} - -static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) -{ - uint32_t rasid; - - __asm__ volatile("rsr %0, rasid" : "=a"(rasid)); - return rasid; -} - -static ALWAYS_INLINE void xtensa_itlb_entry_invalidate(uint32_t entry) -{ - __asm__ volatile("iitlb %0\n\t" - : : "a" (entry)); -} - -static ALWAYS_INLINE void xtensa_itlb_entry_invalidate_sync(uint32_t entry) -{ - __asm__ volatile("iitlb %0\n\t" - "isync\n\t" - : : "a" (entry)); -} - -static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate_sync(uint32_t entry) -{ - __asm__ volatile("idtlb %0\n\t" - "dsync\n\t" - : : "a" (entry)); -} - -static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate(uint32_t entry) -{ - __asm__ volatile("idtlb %0\n\t" - : : "a" (entry)); -} - -static ALWAYS_INLINE void xtensa_dtlb_entry_write_sync(uint32_t pte, uint32_t entry) -{ - __asm__ volatile("wdtlb %0, %1\n\t" - "dsync\n\t" - : : "a" (pte), "a"(entry)); -} - -static ALWAYS_INLINE void xtensa_dtlb_entry_write(uint32_t pte, uint32_t entry) -{ - __asm__ volatile("wdtlb %0, %1\n\t" - : : "a" (pte), "a"(entry)); -} - -static ALWAYS_INLINE void xtensa_itlb_entry_write(uint32_t pte, uint32_t entry) -{ - __asm__ volatile("witlb %0, %1\n\t" - : : "a" (pte), "a"(entry)); -} - -static ALWAYS_INLINE void xtensa_itlb_entry_write_sync(uint32_t pte, uint32_t entry) -{ - __asm__ volatile("witlb %0, %1\n\t" - "isync\n\t" - : : "a" (pte), "a"(entry)); -} - -/** - * @brief Invalidate all ITLB entries. - * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_invalidate_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_ITLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - -/** - * @brief Invalidate all DTLB entries. - * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. - */ -static inline void xtensa_dtlb_invalidate_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_DTLB_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - -/** - * @brief Invalidates an autorefill DTLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_dtlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_dtlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("dsync"); -} - -/** - * @brief Invalidates an autorefill ITLB entry. - * - * Invalidates the page table enrty that maps a given virtual address. - */ -static inline void xtensa_itlb_autorefill_invalidate_sync(void *vaddr) -{ - uint8_t way; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - xtensa_itlb_entry_invalidate(Z_XTENSA_TLB_ENTRY((uint32_t)vaddr, way)); - } - __asm__ volatile("isync"); -} -/** - * @brief Invalidate all autorefill ITLB entries. - * - * This should be used carefully since all entries in the instruction TLB - * will be erased and the only way to find lookup a physical address will be - * through the page tables. - */ -static inline void xtensa_itlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_itlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - -/** - * @brief Invalidate all autorefill DTLB entries. - * - * This should be used carefully since all entries in the data TLB will be - * erased and the only way to find lookup a physical address will be through - * the page tables. - */ -static inline void xtensa_dtlb_autorefill_invalidate_all_sync(void) -{ - uint8_t way, i; - - for (way = 0; way < Z_XTENSA_TLB_AUTOREFILL_WAYS; way++) { - for (i = 0; i < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); i++) { - uint32_t entry = way + (i << Z_XTENSA_PPN_SHIFT); - - xtensa_dtlb_entry_invalidate(entry); - } - } - __asm__ volatile("isync"); -} - - -/** - * @brief Set the page tables. - * - * The page tables is set writing ptevaddr address. - * - * @param ptables The page tables address (virtual address) - */ -static ALWAYS_INLINE void xtensa_ptevaddr_set(void *ptables) -{ - __asm__ volatile("wsr.ptevaddr %0" : : "a"((uint32_t)ptables)); -} - -/* - * The following functions are helpful when debugging. - */ -static ALWAYS_INLINE void *xtensa_dtlb_vaddr_read(uint32_t entry) -{ - uint32_t vaddr; - - __asm__ volatile("rdtlb0 %0, %1\n\t" : "=a" (vaddr) : "a" (entry)); - return (void *)(vaddr & Z_XTENSA_PTE_VPN_MASK); -} - -static ALWAYS_INLINE uint32_t xtensa_dtlb_paddr_read(uint32_t entry) -{ - uint32_t paddr; - - __asm__ volatile("rdtlb1 %0, %1\n\t" : "=a" (paddr) : "a" (entry)); - return (paddr & Z_XTENSA_PTE_PPN_MASK); -} - -static ALWAYS_INLINE void *xtensa_itlb_vaddr_read(uint32_t entry) -{ - uint32_t vaddr; - - __asm__ volatile("ritlb0 %0, %1\n\t" : "=a" (vaddr), "+a" (entry)); - return (void *)(vaddr & Z_XTENSA_PTE_VPN_MASK); -} - -static ALWAYS_INLINE uint32_t xtensa_itlb_paddr_read(uint32_t entry) -{ - uint32_t paddr; - - __asm__ volatile("ritlb1 %0, %1\n\t" : "=a" (paddr), "+a" (entry)); - return (paddr & Z_XTENSA_PTE_PPN_MASK); -} - -static ALWAYS_INLINE uint32_t xtensa_itlb_probe(void *vaddr) -{ - uint32_t ret; - - __asm__ __volatile__("pitlb %0, %1\n\t" : "=a" (ret) : "a" ((uint32_t)vaddr)); - return ret; -} - -static ALWAYS_INLINE uint32_t xtensa_dtlb_probe(void *vaddr) -{ - uint32_t ret; - - __asm__ __volatile__("pdtlb %0, %1\n\t" : "=a" (ret) : "a" ((uint32_t)vaddr)); - return ret; -} - -static inline void xtensa_itlb_vaddr_invalidate(void *vaddr) -{ - uint32_t entry = xtensa_itlb_probe(vaddr); - - if (entry & Z_XTENSA_PITLB_HIT) { - xtensa_itlb_entry_invalidate_sync(entry); - } -} - -static inline void xtensa_dtlb_vaddr_invalidate(void *vaddr) -{ - uint32_t entry = xtensa_dtlb_probe(vaddr); - - if (entry & Z_XTENSA_PDTLB_HIT) { - xtensa_dtlb_entry_invalidate_sync(entry); - } -} - -#endif /* ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ */ diff --git a/arch/xtensa/core/irq_manage.c b/arch/xtensa/core/irq_manage.c index 1c592734084..576eb6e62bb 100644 --- a/arch/xtensa/core/irq_manage.c +++ b/arch/xtensa/core/irq_manage.c @@ -8,6 +8,13 @@ #include #include +#include + +#include + +#include +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + /** * @internal * @@ -56,3 +63,25 @@ int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority, } #endif /* !CONFIG_MULTI_LEVEL_INTERRUPTS */ #endif /* CONFIG_DYNAMIC_INTERRUPTS */ + +void z_irq_spurious(const void *arg) +{ + int irqs, ie; + + ARG_UNUSED(arg); + + __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); + __asm__ volatile("rsr.intenable %0" : "=r"(ie)); + LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p", + (void *)irqs, (void *)ie); + xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); +} + +int xtensa_irq_is_enabled(unsigned int irq) +{ + uint32_t ie; + + __asm__ volatile("rsr.intenable %0" : "=r"(ie)); + + return (ie & (1 << irq)) != 0U; +} diff --git a/arch/xtensa/core/mem_manage.c b/arch/xtensa/core/mem_manage.c index e43bf4b75d6..0085000d5ce 100644 --- a/arch/xtensa/core/mem_manage.c +++ b/arch/xtensa/core/mem_manage.c @@ -8,11 +8,12 @@ #include #include #include +#include __weak bool sys_mm_is_phys_addr_in_range(uintptr_t phys) { bool valid; - uintptr_t cached = (uintptr_t)arch_xtensa_cached_ptr((void *)phys); + uintptr_t cached = (uintptr_t)sys_cache_cached_ptr_get((void *)phys); valid = ((phys >= CONFIG_SRAM_BASE_ADDRESS) && (phys < (CONFIG_SRAM_BASE_ADDRESS + (CONFIG_SRAM_SIZE * 1024UL)))); @@ -28,7 +29,7 @@ __weak bool sys_mm_is_virt_addr_in_range(void *virt) bool valid; uintptr_t addr = (uintptr_t)virt; - uintptr_t cached = (uintptr_t)arch_xtensa_cached_ptr(virt); + uintptr_t cached = (uintptr_t)sys_cache_cached_ptr_get(virt); valid = ((addr >= CONFIG_KERNEL_VM_BASE) && (addr < (CONFIG_KERNEL_VM_BASE + CONFIG_KERNEL_VM_SIZE))); diff --git a/arch/xtensa/core/mmu.c b/arch/xtensa/core/mmu.c new file mode 100644 index 00000000000..294a66dbc22 --- /dev/null +++ b/arch/xtensa/core/mmu.c @@ -0,0 +1,179 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include + +#define ASID_INVALID 0 + +struct tlb_regs { + uint32_t rasid; + uint32_t ptevaddr; + uint32_t ptepin_as; + uint32_t ptepin_at; + uint32_t vecpin_as; + uint32_t vecpin_at; +}; + +static void compute_regs(uint32_t user_asid, uint32_t *l1_page, struct tlb_regs *regs) +{ + uint32_t vecbase = XTENSA_RSR("VECBASE"); + + __ASSERT_NO_MSG((((uint32_t)l1_page) & 0xfff) == 0); + __ASSERT_NO_MSG((user_asid == 0) || ((user_asid > 2) && + (user_asid < XTENSA_MMU_SHARED_ASID))); + + /* We don't use ring 1, ring 0 ASID must be 1 */ + regs->rasid = (XTENSA_MMU_SHARED_ASID << 24) | + (user_asid << 16) | 0x000201; + + /* Derive PTEVADDR from ASID so each domain gets its own PTE area */ + regs->ptevaddr = CONFIG_XTENSA_MMU_PTEVADDR + user_asid * 0x400000; + + /* The ptables code doesn't add the mapping for the l1 page itself */ + l1_page[XTENSA_MMU_L1_POS(regs->ptevaddr)] = + (uint32_t)l1_page | XTENSA_MMU_PAGE_TABLE_ATTR; + + regs->ptepin_at = (uint32_t)l1_page; + regs->ptepin_as = XTENSA_MMU_PTE_ENTRY_VADDR(regs->ptevaddr, regs->ptevaddr) + | XTENSA_MMU_PTE_WAY; + + /* Pin mapping for refilling the vector address into the ITLB + * (for handling TLB miss exceptions). Note: this is NOT an + * instruction TLB entry for the vector code itself, it's a + * DATA TLB entry for the page containing the vector mapping + * so the refill on instruction fetch can find it. The + * hardware doesn't have a 4k pinnable instruction TLB way, + * frustratingly. + */ + uint32_t vb_pte = l1_page[XTENSA_MMU_L1_POS(vecbase)]; + + regs->vecpin_at = vb_pte; + regs->vecpin_as = XTENSA_MMU_PTE_ENTRY_VADDR(regs->ptevaddr, vecbase) + | XTENSA_MMU_VECBASE_WAY; +} + +/* Switch to a new page table. There are four items we have to set in + * the hardware: the PTE virtual address, the ring/ASID mapping + * register, and two pinned entries in the data TLB handling refills + * for the page tables and the vector handlers. + * + * These can be done in any order, provided that we ensure that no + * memory access which cause a TLB miss can happen during the process. + * This means that we must work entirely within registers in a single + * asm block. Also note that instruction fetches are memory accesses + * too, which means we cannot cross a page boundary which might reach + * a new page not in the TLB (a single jump to an aligned address that + * holds our five instructions is sufficient to guarantee that: I + * couldn't think of a way to do the alignment statically that also + * interoperated well with inline assembly). + */ +void xtensa_set_paging(uint32_t user_asid, uint32_t *l1_page) +{ + /* Optimization note: the registers computed here are pure + * functions of the two arguments. With a minor API tweak, + * they could be cached in e.g. a thread struct instead of + * being recomputed. This is called on context switch paths + * and is performance-sensitive. + */ + struct tlb_regs regs; + + compute_regs(user_asid, l1_page, ®s); + + __asm__ volatile("j 1f\n" + ".align 16\n" /* enough for 5 insns */ + "1:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "isync" + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as)); +} + +/* This is effectively the same algorithm from xtensa_set_paging(), + * but it also disables the hardware-initialized 512M TLB entries in + * way 6 (because the hardware disallows duplicate TLB mappings). For + * instruction fetches this produces a critical ordering constraint: + * the instruction following the invalidation of ITLB entry mapping + * the current PC will by definition create a refill condition, which + * will (because the data TLB was invalidated) cause a refill + * exception. Therefore this step must be the very last one, once + * everything else is setup up and working, which includes the + * invalidation of the virtual PTEVADDR area so that the resulting + * refill can complete. + * + * Note that we can't guarantee that the compiler won't insert a data + * fetch from our stack memory after exit from the asm block (while it + * might be double-mapped), so we invalidate that data TLB inside the + * asm for correctness. The other 13 entries get invalidated in a C + * loop at the end. + */ +void xtensa_init_paging(uint32_t *l1_page) +{ + extern char z_xt_init_pc; /* defined in asm below */ + struct tlb_regs regs; + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* The incoherent cache can get into terrible trouble if it's + * allowed to cache PTEs differently across CPUs. We require + * that all page tables supplied by the OS have exclusively + * uncached mappings for page data, but can't do anything + * about earlier code/firmware. Dump the cache to be safe. + */ + sys_cache_data_flush_and_invd_all(); +#endif + + compute_regs(ASID_INVALID, l1_page, ®s); + + uint32_t idtlb_pte = (regs.ptevaddr & 0xe0000000) | XCHAL_SPANNING_WAY; + uint32_t idtlb_stk = (((uint32_t)®s) & ~0xfff) | XCHAL_SPANNING_WAY; + uint32_t iitlb_pc = (((uint32_t)&z_xt_init_pc) & ~0xfff) | XCHAL_SPANNING_WAY; + + /* Note: the jump is mostly pedantry, as it's almost + * inconceivable that a hardware memory region at boot is + * going to cross a 512M page boundary. But we need the entry + * symbol to get the address above, so the jump is here for + * symmetry with the set_paging() code. + */ + __asm__ volatile("j z_xt_init_pc\n" + ".align 32\n" /* room for 10 insns */ + ".globl z_xt_init_pc\n" + "z_xt_init_pc:\n" + "wsr %0, PTEVADDR\n" + "wsr %1, RASID\n" + "wdtlb %2, %3\n" + "wdtlb %4, %5\n" + "idtlb %6\n" /* invalidate pte */ + "idtlb %7\n" /* invalidate stk */ + "isync\n" + "iitlb %8\n" /* invalidate pc */ + "isync\n" /* <--- traps a ITLB miss */ + :: "r"(regs.ptevaddr), "r"(regs.rasid), + "r"(regs.ptepin_at), "r"(regs.ptepin_as), + "r"(regs.vecpin_at), "r"(regs.vecpin_as), + "r"(idtlb_pte), "r"(idtlb_stk), "r"(iitlb_pc)); + + /* Invalidate the remaining (unused by this function) + * initialization entries. Now we're flying free with our own + * page table. + */ + for (uint32_t i = 0; i < 8; i++) { + uint32_t ixtlb = (i * 0x20000000) | XCHAL_SPANNING_WAY; + + if (ixtlb != iitlb_pc) { + __asm__ volatile("iitlb %0" :: "r"(ixtlb)); + } + if (ixtlb != idtlb_stk && ixtlb != idtlb_pte) { + __asm__ volatile("idtlb %0" :: "r"(ixtlb)); + } + } + __asm__ volatile("isync"); +} diff --git a/arch/xtensa/core/offsets/offsets.c b/arch/xtensa/core/offsets/offsets.c index 860a12eb408..8fca6962d3d 100644 --- a/arch/xtensa/core/offsets/offsets.c +++ b/arch/xtensa/core/offsets/offsets.c @@ -5,8 +5,9 @@ #include #include +#include -#include +#include GEN_ABSOLUTE_SYM(___xtensa_irq_bsa_t_SIZEOF, sizeof(_xtensa_irq_bsa_t)); GEN_ABSOLUTE_SYM(___xtensa_irq_stack_frame_raw_t_SIZEOF, sizeof(_xtensa_irq_stack_frame_raw_t)); @@ -60,4 +61,10 @@ GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu14); GEN_OFFSET_SYM(_xtensa_irq_bsa_t, fpu15); #endif +#ifdef CONFIG_USERSPACE +GEN_OFFSET_SYM(_thread_arch_t, psp); +GEN_OFFSET_SYM(_thread_arch_t, ptables); +#endif + + GEN_ABS_SYM_END diff --git a/arch/xtensa/core/ptables.c b/arch/xtensa/core/ptables.c new file mode 100644 index 00000000000..bd2e8a61581 --- /dev/null +++ b/arch/xtensa/core/ptables.c @@ -0,0 +1,1113 @@ +/* + * Copyright (c) 2022 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Skip TLB IPI when updating page tables. + * This allows us to send IPI only after the last + * changes of a series. + */ +#define OPTION_NO_TLB_IPI BIT(0) + +/* Level 1 contains page table entries + * necessary to map the page table itself. + */ +#define XTENSA_L1_PAGE_TABLE_ENTRIES 1024U + +/* Size of level 1 page table. + */ +#define XTENSA_L1_PAGE_TABLE_SIZE (XTENSA_L1_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + +/* Level 2 contains page table entries + * necessary to map the page table itself. + */ +#define XTENSA_L2_PAGE_TABLE_ENTRIES 1024U + +/* Size of level 2 page table. + */ +#define XTENSA_L2_PAGE_TABLE_SIZE (XTENSA_L2_PAGE_TABLE_ENTRIES * sizeof(uint32_t)) + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, + "MMU_PAGE_SIZE value is invalid, only 4 kB pages are supported\n"); + +/* + * Level 1 page table has to be 4Kb to fit into one of the wired entries. + * All entries are initialized as INVALID, so an attempt to read an unmapped + * area will cause a double exception. + * + * Each memory domain contains its own l1 page table. The kernel l1 page table is + * located at the index 0. + */ +static uint32_t l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES][XTENSA_L1_PAGE_TABLE_ENTRIES] + __aligned(KB(4)); + + +/* + * That is an alias for the page tables set used by the kernel. + */ +uint32_t *xtensa_kernel_ptables = (uint32_t *)l1_page_table[0]; + +/* + * Each table in the level 2 maps a 4Mb memory range. It consists of 1024 entries each one + * covering a 4Kb page. + */ +static uint32_t l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES][XTENSA_L2_PAGE_TABLE_ENTRIES] + __aligned(KB(4)); + +/* + * This additional variable tracks which l1 tables are in use. This is kept separated from + * the tables to keep alignment easier. + * + * @note: The first bit is set because it is used for the kernel page tables. + */ +static ATOMIC_DEFINE(l1_page_table_track, CONFIG_XTENSA_MMU_NUM_L1_TABLES); + +/* + * This additional variable tracks which l2 tables are in use. This is kept separated from + * the tables to keep alignment easier. + */ +static ATOMIC_DEFINE(l2_page_tables_track, CONFIG_XTENSA_MMU_NUM_L2_TABLES); + +/* + * Protects xtensa_domain_list and serializes access to page tables. + */ +static struct k_spinlock xtensa_mmu_lock; + +#ifdef CONFIG_USERSPACE + +/* + * Each domain has its own ASID. ASID can go through 1 (kernel) to 255. + * When a TLB entry matches, the hw will check the ASID in the entry and finds + * the correspondent position in the RASID register. This position will then be + * compared with the current ring (CRING) to check the permission. + */ +static uint8_t asid_count = 3; + +/* + * List with all active and initialized memory domains. + */ +static sys_slist_t xtensa_domain_list; +#endif /* CONFIG_USERSPACE */ + +extern char _heap_end[]; +extern char _heap_start[]; +extern char __data_start[]; +extern char __data_end[]; +extern char _bss_start[]; +extern char _bss_end[]; + +/* + * Static definition of all code & data memory regions of the + * current Zephyr image. This information must be available & + * processed upon MMU initialization. + */ + +static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { + /* + * Mark the zephyr execution regions (data, bss, noinit, etc.) + * cacheable, read / write and non-executable + */ + { + /* This includes .data, .bss and various kobject sections. */ + .start = (uint32_t)_image_ram_start, + .end = (uint32_t)_image_ram_end, +#ifdef CONFIG_XTENSA_RPO_CACHE + .attrs = XTENSA_MMU_PERM_W, +#else + .attrs = XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, +#endif + .name = "data", + }, +#if K_HEAP_MEM_POOL_SIZE > 0 + /* System heap memory */ + { + .start = (uint32_t)_heap_start, + .end = (uint32_t)_heap_end, +#ifdef CONFIG_XTENSA_RPO_CACHE + .attrs = XTENSA_MMU_PERM_W, +#else + .attrs = XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, +#endif + .name = "heap", + }, +#endif + /* Mark text segment cacheable, read only and executable */ + { + .start = (uint32_t)__text_region_start, + .end = (uint32_t)__text_region_end, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, + .name = "text", + }, + /* Mark rodata segment cacheable, read only and non-executable */ + { + .start = (uint32_t)__rodata_region_start, + .end = (uint32_t)__rodata_region_end, + .attrs = XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, + .name = "rodata", + }, +}; + +static inline uint32_t *thread_page_tables_get(const struct k_thread *thread) +{ +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) != 0U) { + return thread->arch.ptables; + } +#endif + + return xtensa_kernel_ptables; +} + +/** + * @brief Check if the page table entry is illegal. + * + * @param[in] Page table entry. + */ +static inline bool is_pte_illegal(uint32_t pte) +{ + uint32_t attr = pte & XTENSA_MMU_PTE_ATTR_MASK; + + /* + * The ISA manual states only 12 and 14 are illegal values. + * 13 and 15 are not. So we need to be specific than simply + * testing if bits 2 and 3 are set. + */ + return (attr == 12) || (attr == 14); +} + +/* + * @brief Initialize all page table entries to be illegal. + * + * @param[in] Pointer to page table. + * @param[in] Number of page table entries in the page table. + */ +static void init_page_table(uint32_t *ptable, size_t num_entries) +{ + int i; + + for (i = 0; i < num_entries; i++) { + ptable[i] = XTENSA_MMU_PTE_ILLEGAL; + } +} + +static inline uint32_t *alloc_l2_table(void) +{ + uint16_t idx; + + for (idx = 0; idx < CONFIG_XTENSA_MMU_NUM_L2_TABLES; idx++) { + if (!atomic_test_and_set_bit(l2_page_tables_track, idx)) { + return (uint32_t *)&l2_page_tables[idx]; + } + } + + return NULL; +} + +static void map_memory_range(const uint32_t start, const uint32_t end, + const uint32_t attrs, bool shared) +{ + uint32_t page, *table; + + for (page = start; page < end; page += CONFIG_MMU_PAGE_SIZE) { + uint32_t pte = XTENSA_MMU_PTE(page, + shared ? XTENSA_MMU_SHARED_RING : + XTENSA_MMU_KERNEL_RING, + attrs); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); + + if (is_pte_illegal(xtensa_kernel_ptables[l1_pos])) { + table = alloc_l2_table(); + + __ASSERT(table != NULL, "There is no l2 page table available to " + "map 0x%08x\n", page); + + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + xtensa_kernel_ptables[l1_pos] = + XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); + } + + table = (uint32_t *)(xtensa_kernel_ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + table[l2_pos] = pte; + } +} + +static void map_memory(const uint32_t start, const uint32_t end, + const uint32_t attrs, bool shared) +{ + map_memory_range(start, end, attrs, shared); + +#ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP + if (sys_cache_is_ptr_uncached((void *)start)) { + map_memory_range(POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)start)), + POINTER_TO_UINT(sys_cache_cached_ptr_get((void *)end)), + attrs | XTENSA_MMU_CACHED_WB, shared); + } else if (sys_cache_is_ptr_cached((void *)start)) { + map_memory_range(POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)start)), + POINTER_TO_UINT(sys_cache_uncached_ptr_get((void *)end)), attrs, shared); + } +#endif +} + +static void xtensa_init_page_tables(void) +{ + volatile uint8_t entry; + + init_page_table(xtensa_kernel_ptables, XTENSA_L1_PAGE_TABLE_ENTRIES); + atomic_set_bit(l1_page_table_track, 0); + + for (entry = 0; entry < ARRAY_SIZE(mmu_zephyr_ranges); entry++) { + const struct xtensa_mmu_range *range = &mmu_zephyr_ranges[entry]; + bool shared; + uint32_t attrs; + + shared = !!(range->attrs & XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~XTENSA_MMU_MAP_SHARED; + + map_memory(range->start, range->end, attrs, shared); + } + +/** + * GCC complains about usage of the SoC MMU range ARRAY_SIZE + * (xtensa_soc_mmu_ranges) as the default weak declaration is + * an empty array, and any access to its element is considered + * out of bound access. However, we have a number of element + * variable to guard against this (... if done correctly). + * Besides, this will almost be overridden by the SoC layer. + * So tell GCC to ignore this. + */ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif + for (entry = 0; entry < xtensa_soc_mmu_ranges_num; entry++) { + const struct xtensa_mmu_range *range = &xtensa_soc_mmu_ranges[entry]; + bool shared; + uint32_t attrs; + + shared = !!(range->attrs & XTENSA_MMU_MAP_SHARED); + attrs = range->attrs & ~XTENSA_MMU_MAP_SHARED; + + map_memory(range->start, range->end, attrs, shared); + } +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + /* Finally, the direct-mapped pages used in the page tables + * must be fixed up to use the same cache attribute (but these + * must be writable, obviously). They shouldn't be left at + * the default. + */ + map_memory_range((uint32_t) &l1_page_table[0], + (uint32_t) &l1_page_table[CONFIG_XTENSA_MMU_NUM_L1_TABLES], + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W, false); + map_memory_range((uint32_t) &l2_page_tables[0], + (uint32_t) &l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES], + XTENSA_MMU_PAGE_TABLE_ATTR | XTENSA_MMU_PERM_W, false); + + sys_cache_data_flush_all(); +} + +__weak void arch_xtensa_mmu_post_init(bool is_core0) +{ + ARG_UNUSED(is_core0); +} + +void xtensa_mmu_init(void) +{ + if (_current_cpu->id == 0) { + /* This is normally done via arch_kernel_init() inside z_cstart(). + * However, before that is called, we go through the sys_init of + * INIT_LEVEL_EARLY, which is going to result in TLB misses. + * So setup whatever necessary so the exception handler can work + * properly. + */ + xtensa_init_page_tables(); + } + + xtensa_init_paging(xtensa_kernel_ptables); + + arch_xtensa_mmu_post_init(_current_cpu->id == 0); +} + +#ifdef CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES +/* Zephyr's linker scripts for Xtensa usually puts + * something before z_mapped_start (aka .text), + * i.e. vecbase, so that we need to reserve those + * space or else k_mem_map() would be mapping those, + * resulting in faults. + */ +__weak void arch_reserved_pages_update(void) +{ + uintptr_t page; + struct z_page_frame *pf; + int idx; + + for (page = CONFIG_SRAM_BASE_ADDRESS, idx = 0; + page < (uintptr_t)z_mapped_start; + page += CONFIG_MMU_PAGE_SIZE, idx++) { + pf = &z_page_frames[idx]; + + pf->flags |= Z_PAGE_FRAME_RESERVED; + } +} +#endif /* CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES */ + +static bool l2_page_table_map(uint32_t *l1_table, void *vaddr, uintptr_t phys, + uint32_t flags, bool is_user) +{ + uint32_t l1_pos = XTENSA_MMU_L1_POS((uint32_t)vaddr); + uint32_t l2_pos = XTENSA_MMU_L2_POS((uint32_t)vaddr); + uint32_t *table; + + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { + table = alloc_l2_table(); + + if (table == NULL) { + return false; + } + + init_page_table(table, XTENSA_L2_PAGE_TABLE_ENTRIES); + + l1_table[l1_pos] = XTENSA_MMU_PTE((uint32_t)table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + } + + table = (uint32_t *)(l1_table[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + table[l2_pos] = XTENSA_MMU_PTE(phys, is_user ? XTENSA_MMU_USER_RING : + XTENSA_MMU_KERNEL_RING, + flags); + + sys_cache_data_flush_range((void *)&table[l2_pos], sizeof(table[0])); + xtensa_tlb_autorefill_invalidate(); + + return true; +} + +static inline void __arch_mem_map(void *va, uintptr_t pa, uint32_t xtensa_flags, bool is_user) +{ + bool ret; + void *vaddr, *vaddr_uc; + uintptr_t paddr, paddr_uc; + uint32_t flags, flags_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (sys_cache_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = sys_cache_uncached_ptr_get(va); + } else { + vaddr = sys_cache_cached_ptr_get(va); + vaddr_uc = va; + } + + if (sys_cache_is_ptr_cached((void *)pa)) { + paddr = pa; + paddr_uc = (uintptr_t)sys_cache_uncached_ptr_get((void *)pa); + } else { + paddr = (uintptr_t)sys_cache_cached_ptr_get((void *)pa); + paddr_uc = pa; + } + + flags_uc = (xtensa_flags & ~XTENSA_MMU_PTE_ATTR_CACHED_MASK); + flags = flags_uc | XTENSA_MMU_CACHED_WB; + } else { + vaddr = va; + paddr = pa; + flags = xtensa_flags; + } + + ret = l2_page_table_map(xtensa_kernel_ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", va); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(xtensa_kernel_ptables, (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped", vaddr_uc); + } + +#ifndef CONFIG_USERSPACE + ARG_UNUSED(ret); +#else + if (ret) { + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + ret = l2_page_table_map(domain->ptables, (void *)vaddr, paddr, + flags, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr, domain); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP) && ret) { + ret = l2_page_table_map(domain->ptables, + (void *)vaddr_uc, paddr_uc, + flags_uc, is_user); + __ASSERT(ret, "Virtual address (%p) already mapped for domain %p", + vaddr_uc, domain); + } + } + k_spin_unlock(&z_mem_domain_lock, key); + } +#endif /* CONFIG_USERSPACE */ +} + +void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) +{ + uint32_t va = (uint32_t)virt; + uint32_t pa = (uint32_t)phys; + uint32_t rem_size = (uint32_t)size; + uint32_t xtensa_flags = 0; + k_spinlock_key_t key; + bool is_user; + + if (size == 0) { + LOG_ERR("Cannot map physical memory at 0x%08X: invalid " + "zero size", (uint32_t)phys); + k_panic(); + } + + switch (flags & K_MEM_CACHE_MASK) { + + case K_MEM_CACHE_WB: + xtensa_flags |= XTENSA_MMU_CACHED_WB; + break; + case K_MEM_CACHE_WT: + xtensa_flags |= XTENSA_MMU_CACHED_WT; + break; + case K_MEM_CACHE_NONE: + __fallthrough; + default: + break; + } + + if ((flags & K_MEM_PERM_RW) == K_MEM_PERM_RW) { + xtensa_flags |= XTENSA_MMU_PERM_W; + } + if ((flags & K_MEM_PERM_EXEC) == K_MEM_PERM_EXEC) { + xtensa_flags |= XTENSA_MMU_PERM_X; + } + + is_user = (flags & K_MEM_PERM_USER) == K_MEM_PERM_USER; + + key = k_spin_lock(&xtensa_mmu_lock); + + while (rem_size > 0) { + __arch_mem_map((void *)va, pa, xtensa_flags, is_user); + + rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; + va += KB(4); + pa += KB(4); + } + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + xtensa_mmu_tlb_ipi(); +#endif + + sys_cache_data_flush_and_invd_all(); + k_spin_unlock(&xtensa_mmu_lock, key); +} + +/** + * @return True if page is executable (thus need to invalidate ITLB), + * false if not. + */ +static bool l2_page_table_unmap(uint32_t *l1_table, void *vaddr) +{ + uint32_t l1_pos = XTENSA_MMU_L1_POS((uint32_t)vaddr); + uint32_t l2_pos = XTENSA_MMU_L2_POS((uint32_t)vaddr); + uint32_t *l2_table; + uint32_t table_pos; + bool exec; + + sys_cache_data_invd_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + if (is_pte_illegal(l1_table[l1_pos])) { + /* We shouldn't be unmapping an illegal entry. + * Return true so that we can invalidate ITLB too. + */ + return true; + } + + exec = l1_table[l1_pos] & XTENSA_MMU_PERM_X; + + l2_table = (uint32_t *)(l1_table[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + l2_table[l2_pos] = XTENSA_MMU_PTE_ILLEGAL; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + for (l2_pos = 0; l2_pos < XTENSA_L2_PAGE_TABLE_ENTRIES; l2_pos++) { + if (!is_pte_illegal(l2_table[l2_pos])) { + goto end; + } + } + + l1_table[l1_pos] = XTENSA_MMU_PTE_ILLEGAL; + sys_cache_data_flush_range((void *)&l1_table[l1_pos], sizeof(l1_table[0])); + + table_pos = (l2_table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); + atomic_clear_bit(l2_page_tables_track, table_pos); + +end: + /* Need to invalidate L2 page table as it is no longer valid. */ + xtensa_tlb_autorefill_invalidate(); + return exec; +} + +static inline void __arch_mem_unmap(void *va) +{ + bool is_exec; + void *vaddr, *vaddr_uc; + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + if (sys_cache_is_ptr_cached(va)) { + vaddr = va; + vaddr_uc = sys_cache_uncached_ptr_get(va); + } else { + vaddr = sys_cache_cached_ptr_get(va); + vaddr_uc = va; + } + } else { + vaddr = va; + } + + is_exec = l2_page_table_unmap(xtensa_kernel_ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(xtensa_kernel_ptables, (void *)vaddr_uc); + } + +#ifdef CONFIG_USERSPACE + sys_snode_t *node; + struct arch_mem_domain *domain; + k_spinlock_key_t key; + + key = k_spin_lock(&z_mem_domain_lock); + SYS_SLIST_FOR_EACH_NODE(&xtensa_domain_list, node) { + domain = CONTAINER_OF(node, struct arch_mem_domain, node); + + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr); + + if (IS_ENABLED(CONFIG_XTENSA_MMU_DOUBLE_MAP)) { + (void)l2_page_table_unmap(domain->ptables, (void *)vaddr_uc); + } + } + k_spin_unlock(&z_mem_domain_lock, key); +#endif /* CONFIG_USERSPACE */ +} + +void arch_mem_unmap(void *addr, size_t size) +{ + uint32_t va = (uint32_t)addr; + uint32_t rem_size = (uint32_t)size; + k_spinlock_key_t key; + + if (addr == NULL) { + LOG_ERR("Cannot unmap NULL pointer"); + return; + } + + if (size == 0) { + LOG_ERR("Cannot unmap virtual memory with zero size"); + return; + } + + key = k_spin_lock(&xtensa_mmu_lock); + + while (rem_size > 0) { + __arch_mem_unmap((void *)va); + + rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; + va += KB(4); + } + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + xtensa_mmu_tlb_ipi(); +#endif + + sys_cache_data_flush_and_invd_all(); + k_spin_unlock(&xtensa_mmu_lock, key); +} + +/* This should be implemented in the SoC layer. + * This weak version is here to avoid build errors. + */ +void __weak xtensa_mmu_tlb_ipi(void) +{ +} + +void xtensa_mmu_tlb_shootdown(void) +{ + unsigned int key; + + /* Need to lock interrupts to prevent any context + * switching until all the page tables are updated. + * Or else we would be switching to another thread + * and running that with incorrect page tables + * which would result in permission issues. + */ + key = arch_irq_lock(); + + K_SPINLOCK(&xtensa_mmu_lock) { + /* We don't have information on which page tables have changed, + * so we just invalidate the cache for all L1 page tables. + */ + sys_cache_data_invd_range((void *)l1_page_table, sizeof(l1_page_table)); + sys_cache_data_invd_range((void *)l2_page_tables, sizeof(l2_page_tables)); + } + +#ifdef CONFIG_USERSPACE + struct k_thread *thread = _current_cpu->current; + + /* If current thread is a user thread, we need to see if it has + * been migrated to another memory domain as the L1 page table + * is different from the currently used one. + */ + if ((thread->base.user_options & K_USER) == K_USER) { + uint32_t ptevaddr_entry, ptevaddr, + thread_ptables, current_ptables; + + /* Need to read the currently used L1 page table. + * We know that L1 page table is always mapped at way + * MMU_PTE_WAY, so we can skip the probing step by + * generating the query entry directly. + */ + ptevaddr = (uint32_t)xtensa_ptevaddr_get(); + ptevaddr_entry = XTENSA_MMU_PTE_ENTRY_VADDR(ptevaddr, ptevaddr) + | XTENSA_MMU_PTE_WAY; + current_ptables = xtensa_dtlb_paddr_read(ptevaddr_entry); + thread_ptables = (uint32_t)thread->arch.ptables; + + if (thread_ptables != current_ptables) { + /* Need to remap the thread page tables if the ones + * indicated by the current thread are different + * than the current mapped page table. + */ + struct arch_mem_domain *domain = + &(thread->mem_domain_info.mem_domain->arch); + xtensa_set_paging(domain->asid, (uint32_t *)thread_ptables); + } + + } +#endif /* CONFIG_USERSPACE */ + + /* L2 are done via autofill, so invalidate autofill TLBs + * would refresh the L2 page tables. + * + * L1 will be refreshed during context switch so no need + * to do anything here. + */ + xtensa_tlb_autorefill_invalidate(); + + arch_irq_unlock(key); +} + +#ifdef CONFIG_USERSPACE + +static inline uint32_t *alloc_l1_table(void) +{ + uint16_t idx; + + for (idx = 0; idx < CONFIG_XTENSA_MMU_NUM_L1_TABLES; idx++) { + if (!atomic_test_and_set_bit(l1_page_table_track, idx)) { + return (uint32_t *)&l1_page_table[idx]; + } + } + + return NULL; +} + +static uint32_t *dup_table(uint32_t *source_table) +{ + uint16_t i, j; + uint32_t *dst_table = alloc_l1_table(); + + if (!dst_table) { + return NULL; + } + + for (i = 0; i < XTENSA_L1_PAGE_TABLE_ENTRIES; i++) { + uint32_t *l2_table, *src_l2_table; + + if (is_pte_illegal(source_table[i])) { + dst_table[i] = XTENSA_MMU_PTE_ILLEGAL; + continue; + } + + src_l2_table = (uint32_t *)(source_table[i] & XTENSA_MMU_PTE_PPN_MASK); + l2_table = alloc_l2_table(); + if (l2_table == NULL) { + goto err; + } + + for (j = 0; j < XTENSA_L2_PAGE_TABLE_ENTRIES; j++) { + l2_table[j] = src_l2_table[j]; + } + + /* The page table is using kernel ASID because we don't + * user thread manipulate it. + */ + dst_table[i] = XTENSA_MMU_PTE((uint32_t)l2_table, XTENSA_MMU_KERNEL_RING, + XTENSA_MMU_PAGE_TABLE_ATTR); + + sys_cache_data_flush_range((void *)l2_table, XTENSA_L2_PAGE_TABLE_SIZE); + } + + sys_cache_data_flush_range((void *)dst_table, XTENSA_L1_PAGE_TABLE_SIZE); + + return dst_table; + +err: + /* TODO: Cleanup failed allocation*/ + return NULL; +} + +int arch_mem_domain_init(struct k_mem_domain *domain) +{ + uint32_t *ptables; + k_spinlock_key_t key; + int ret; + + /* + * For now, lets just assert if we have reached the maximum number + * of asid we assert. + */ + __ASSERT(asid_count < (XTENSA_MMU_SHARED_ASID), "Reached maximum of ASID available"); + + key = k_spin_lock(&xtensa_mmu_lock); + ptables = dup_table(xtensa_kernel_ptables); + + if (ptables == NULL) { + ret = -ENOMEM; + goto err; + } + + domain->arch.ptables = ptables; + domain->arch.asid = ++asid_count; + + sys_slist_append(&xtensa_domain_list, &domain->arch.node); + + ret = 0; + +err: + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static int region_map_update(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags) +{ + int ret = 0; + + for (size_t offset = 0; offset < size; offset += CONFIG_MMU_PAGE_SIZE) { + uint32_t *l2_table, pte; + uint32_t page = start + offset; + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); + /* Make sure we grab a fresh copy of L1 page table */ + sys_cache_data_invd_range((void *)&ptables[l1_pos], sizeof(ptables[0])); + + l2_table = (uint32_t *)(ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + + sys_cache_data_invd_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + pte = XTENSA_MMU_PTE_RING_SET(l2_table[l2_pos], ring); + pte = XTENSA_MMU_PTE_ATTR_SET(pte, flags); + + l2_table[l2_pos] = pte; + + sys_cache_data_flush_range((void *)&l2_table[l2_pos], sizeof(l2_table[0])); + + xtensa_dtlb_vaddr_invalidate((void *)page); + } + + return ret; +} + +static inline int update_region(uint32_t *ptables, uintptr_t start, + size_t size, uint32_t ring, uint32_t flags, + uint32_t option) +{ + int ret; + k_spinlock_key_t key; + + key = k_spin_lock(&xtensa_mmu_lock); + +#ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP + uintptr_t va, va_uc; + uint32_t new_flags, new_flags_uc; + + if (sys_cache_is_ptr_cached((void *)start)) { + va = start; + va_uc = (uintptr_t)sys_cache_uncached_ptr_get((void *)start); + } else { + va = (uintptr_t)sys_cache_cached_ptr_get((void *)start); + va_uc = start; + } + + new_flags_uc = (flags & ~XTENSA_MMU_PTE_ATTR_CACHED_MASK); + new_flags = new_flags_uc | XTENSA_MMU_CACHED_WB; + + ret = region_map_update(ptables, va, size, ring, new_flags); + + if (ret == 0) { + ret = region_map_update(ptables, va_uc, size, ring, new_flags_uc); + } +#else + ret = region_map_update(ptables, start, size, ring, flags); +#endif /* CONFIG_XTENSA_MMU_DOUBLE_MAP */ + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + if ((option & OPTION_NO_TLB_IPI) != OPTION_NO_TLB_IPI) { + xtensa_mmu_tlb_ipi(); + } +#endif + + sys_cache_data_flush_and_invd_all(); + k_spin_unlock(&xtensa_mmu_lock, key); + + return ret; +} + +static inline int reset_region(uint32_t *ptables, uintptr_t start, size_t size, uint32_t option) +{ + return update_region(ptables, start, size, + XTENSA_MMU_KERNEL_RING, XTENSA_MMU_PERM_W, option); +} + +void xtensa_user_stack_perms(struct k_thread *thread) +{ + (void)memset((void *)thread->stack_info.start, + (IS_ENABLED(CONFIG_INIT_STACKS)) ? 0xAA : 0x00, + thread->stack_info.size - thread->stack_info.delta); + + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + XTENSA_MMU_USER_RING, XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, 0); +} + +int arch_mem_domain_max_partitions_get(void) +{ + return CONFIG_MAX_DOMAIN_PARTITIONS; +} + +int arch_mem_domain_partition_remove(struct k_mem_domain *domain, + uint32_t partition_id) +{ + struct k_mem_partition *partition = &domain->partitions[partition_id]; + + /* Reset the partition's region back to defaults */ + return reset_region(domain->arch.ptables, partition->start, + partition->size, 0); +} + +int arch_mem_domain_partition_add(struct k_mem_domain *domain, + uint32_t partition_id) +{ + struct k_mem_partition *partition = &domain->partitions[partition_id]; + uint32_t ring = K_MEM_PARTITION_IS_USER(partition->attr) ? XTENSA_MMU_USER_RING : + XTENSA_MMU_KERNEL_RING; + + return update_region(domain->arch.ptables, partition->start, + partition->size, ring, partition->attr, 0); +} + +/* These APIs don't need to do anything */ +int arch_mem_domain_thread_add(struct k_thread *thread) +{ + int ret = 0; + bool is_user, is_migration; + uint32_t *old_ptables; + struct k_mem_domain *domain; + + old_ptables = thread->arch.ptables; + domain = thread->mem_domain_info.mem_domain; + thread->arch.ptables = domain->arch.ptables; + + is_user = (thread->base.user_options & K_USER) != 0; + is_migration = (old_ptables != NULL) && is_user; + + if (is_migration) { + /* Give access to the thread's stack in its new + * memory domain if it is migrating. + */ + update_region(thread_page_tables_get(thread), + thread->stack_info.start, thread->stack_info.size, + XTENSA_MMU_USER_RING, + XTENSA_MMU_PERM_W | XTENSA_MMU_CACHED_WB, + OPTION_NO_TLB_IPI); + /* and reset thread's stack permission in + * the old page tables. + */ + ret = reset_region(old_ptables, + thread->stack_info.start, + thread->stack_info.size, 0); + } + + /* Need to switch to new page tables if this is + * the current thread running. + */ + if (thread == _current_cpu->current) { + xtensa_set_paging(domain->arch.asid, thread->arch.ptables); + } + +#if CONFIG_MP_MAX_NUM_CPUS > 1 + /* Need to tell other CPUs to switch to the new page table + * in case the thread is running on one of them. + * + * Note that there is no need to send TLB IPI if this is + * migration as it was sent above during reset_region(). + */ + if ((thread != _current_cpu->current) && !is_migration) { + xtensa_mmu_tlb_ipi(); + } +#endif + + return ret; +} + +int arch_mem_domain_thread_remove(struct k_thread *thread) +{ + struct k_mem_domain *domain = thread->mem_domain_info.mem_domain; + + if ((thread->base.user_options & K_USER) == 0) { + return 0; + } + + if ((thread->base.thread_state & _THREAD_DEAD) == 0) { + /* Thread is migrating to another memory domain and not + * exiting for good; we weren't called from + * z_thread_abort(). Resetting the stack region will + * take place in the forthcoming thread_add() call. + */ + return 0; + } + + /* Restore permissions on the thread's stack area since it is no + * longer a member of the domain. + * + * Note that, since every thread must have an associated memory + * domain, removing a thread from domain will be followed by + * adding it back to another. So there is no need to send TLB IPI + * at this point. + */ + return reset_region(domain->arch.ptables, + thread->stack_info.start, + thread->stack_info.size, OPTION_NO_TLB_IPI); +} + +static bool page_validate(uint32_t *ptables, uint32_t page, uint8_t ring, bool write) +{ + uint8_t asid_ring; + uint32_t rasid, pte, *l2_table; + uint32_t l1_pos = XTENSA_MMU_L1_POS(page); + uint32_t l2_pos = XTENSA_MMU_L2_POS(page); + + if (is_pte_illegal(ptables[l1_pos])) { + return false; + } + + l2_table = (uint32_t *)(ptables[l1_pos] & XTENSA_MMU_PTE_PPN_MASK); + pte = l2_table[l2_pos]; + + if (is_pte_illegal(pte)) { + return false; + } + + asid_ring = 0; + rasid = xtensa_rasid_get(); + for (uint32_t i = 0; i < 4; i++) { + if (XTENSA_MMU_PTE_ASID_GET(pte, rasid) == XTENSA_MMU_RASID_ASID_GET(rasid, i)) { + asid_ring = i; + break; + } + } + + if (ring > asid_ring) { + return false; + } + + if (write) { + return (XTENSA_MMU_PTE_ATTR_GET((pte)) & XTENSA_MMU_PERM_W) != 0; + } + + return true; +} + +int arch_buffer_validate(void *addr, size_t size, int write) +{ + int ret = 0; + uint8_t *virt; + size_t aligned_size; + const struct k_thread *thread = _current; + uint32_t *ptables = thread_page_tables_get(thread); + uint8_t ring = ((thread->base.user_options & K_USER) != 0) ? + XTENSA_MMU_USER_RING : XTENSA_MMU_KERNEL_RING; + + /* addr/size arbitrary, fix this up into an aligned region */ + k_mem_region_align((uintptr_t *)&virt, &aligned_size, + (uintptr_t)addr, size, CONFIG_MMU_PAGE_SIZE); + + for (size_t offset = 0; offset < aligned_size; + offset += CONFIG_MMU_PAGE_SIZE) { + if (!page_validate(ptables, (uint32_t)(virt + offset), ring, write)) { + ret = -1; + break; + } + } + + return ret; +} + +void xtensa_swap_update_page_tables(struct k_thread *incoming) +{ + uint32_t *ptables = incoming->arch.ptables; + struct arch_mem_domain *domain = + &(incoming->mem_domain_info.mem_domain->arch); + + xtensa_set_paging(domain->asid, ptables); + +#ifdef CONFIG_XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP + struct k_mem_domain *mem_domain = incoming->mem_domain_info.mem_domain; + + for (int idx = 0; idx < mem_domain->num_partitions; idx++) { + struct k_mem_partition *part = &mem_domain->partitions[idx]; + uintptr_t end = part->start + part->size; + + for (uintptr_t addr = part->start; addr < end; addr += CONFIG_MMU_PAGE_SIZE) { + xtensa_dtlb_vaddr_invalidate((void *)addr); + } + } +#endif +} + +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/smp.c b/arch/xtensa/core/smp.c new file mode 100644 index 00000000000..ffd08ab805c --- /dev/null +++ b/arch/xtensa/core/smp.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifdef CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS +/* Some compilers might "optimize out" (i.e. remove) continuous NOPs. + * So force no optimization to avoid that. + */ +__no_optimization +void arch_spin_relax(void) +{ +#define NOP1(_, __) __asm__ volatile("nop.n;"); + LISTIFY(CONFIG_XTENSA_NUM_SPIN_RELAX_NOPS, NOP1, (;)) +#undef NOP1 +} +#endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ diff --git a/arch/xtensa/core/startup/CMakeLists.txt b/arch/xtensa/core/startup/CMakeLists.txt index de30172ced2..fc17c5cd990 100644 --- a/arch/xtensa/core/startup/CMakeLists.txt +++ b/arch/xtensa/core/startup/CMakeLists.txt @@ -10,8 +10,8 @@ if(CONFIG_XTENSA_RESET_VECTOR) ) zephyr_library_sources( - memerror-vector.S + memerror_vector.S memctl_default.S - reset-vector.S + reset_vector.S ) endif() diff --git a/arch/xtensa/core/startup/memerror-vector.S b/arch/xtensa/core/startup/memerror_vector.S similarity index 100% rename from arch/xtensa/core/startup/memerror-vector.S rename to arch/xtensa/core/startup/memerror_vector.S diff --git a/arch/xtensa/core/startup/reset-vector.S b/arch/xtensa/core/startup/reset_vector.S similarity index 100% rename from arch/xtensa/core/startup/reset-vector.S rename to arch/xtensa/core/startup/reset_vector.S diff --git a/arch/xtensa/core/syscall_helper.c b/arch/xtensa/core/syscall_helper.c new file mode 100644 index 00000000000..f8fb7ec903e --- /dev/null +++ b/arch/xtensa/core/syscall_helper.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +} diff --git a/arch/xtensa/core/thread.c b/arch/xtensa/core/thread.c new file mode 100644 index 00000000000..4ba0150f705 --- /dev/null +++ b/arch/xtensa/core/thread.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2017, 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include +#include + +#include +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +#ifdef CONFIG_USERSPACE + +#ifdef CONFIG_THREAD_LOCAL_STORAGE +/* + * Per-thread (TLS) variable indicating whether execution is in user mode. + */ +__thread uint32_t is_user_mode; +#endif + +#endif /* CONFIG_USERSPACE */ + +/** + * Initializes a stack area such that it can be "restored" later and + * begin running with the specified function and three arguments. The + * entry function takes three arguments to match the signature of + * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and + * INTLEVEL set to zero (i.e. it's a user thread, we don't start with + * anything masked, so don't assume that!). + */ +static void *init_stack(struct k_thread *thread, int *stack_top, + void (*entry)(void *, void *, void *), + void *arg1, void *arg2, void *arg3) +{ + void *ret; + _xtensa_irq_stack_frame_a11_t *frame; +#ifdef CONFIG_USERSPACE + struct xtensa_thread_stack_header *header = + (struct xtensa_thread_stack_header *)thread->stack_obj; + + thread->arch.psp = header->privilege_stack + + sizeof(header->privilege_stack); +#endif + + /* Not-a-cpu ID Ensures that the first time this is run, the + * stack will be invalidated. That covers the edge case of + * restarting a thread on a stack that had previously been run + * on one CPU, but then initialized on this one, and + * potentially run THERE and not HERE. + */ + thread->arch.last_cpu = -1; + + /* We cheat and shave 16 bytes off, the top four words are the + * A0-A3 spill area for the caller of the entry function, + * which doesn't exist. It will never be touched, so we + * arrange to enter the function with a CALLINC of 1 and a + * stack pointer 16 bytes above the top, so its ENTRY at the + * start will decrement the stack pointer by 16. + */ + const int bsasz = sizeof(*frame) - 16; + + frame = (void *)(((char *) stack_top) - bsasz); + + (void)memset(frame, 0, bsasz); + + frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); +#ifdef CONFIG_USERSPACE + if ((thread->base.user_options & K_USER) == K_USER) { + frame->bsa.pc = (uintptr_t)arch_user_mode_enter; + } else { + frame->bsa.pc = (uintptr_t)z_thread_entry; + } +#else + frame->bsa.pc = (uintptr_t)z_thread_entry; +#endif + +#if XCHAL_HAVE_THREADPTR +#ifdef CONFIG_THREAD_LOCAL_STORAGE + frame->bsa.threadptr = thread->tls; +#elif CONFIG_USERSPACE + frame->bsa.threadptr = (uintptr_t)((thread->base.user_options & K_USER) ? thread : NULL); +#endif +#endif + + /* Arguments to z_thread_entry(). Remember these start at A6, + * which will be rotated into A2 by the ENTRY instruction that + * begins the C function. And A4-A7 and A8-A11 are optional + * quads that live below the BSA! + */ + frame->a7 = (uintptr_t)arg1; /* a7 */ + frame->a6 = (uintptr_t)entry; /* a6 */ + frame->a5 = 0; /* a5 */ + frame->a4 = 0; /* a4 */ + + frame->a11 = 0; /* a11 */ + frame->a10 = 0; /* a10 */ + frame->a9 = (uintptr_t)arg3; /* a9 */ + frame->a8 = (uintptr_t)arg2; /* a8 */ + + /* Finally push the BSA pointer and return the stack pointer + * as the handle + */ + frame->ptr_to_bsa = (void *)&frame->bsa; + ret = &frame->ptr_to_bsa; + + return ret; +} + +void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, + char *stack_ptr, k_thread_entry_t entry, + void *p1, void *p2, void *p3) +{ + thread->switch_handle = init_stack(thread, (int *)stack_ptr, entry, + p1, p2, p3); +#ifdef CONFIG_KERNEL_COHERENCE + __ASSERT((((size_t)stack) % XCHAL_DCACHE_LINESIZE) == 0, ""); + __ASSERT((((size_t)stack_ptr) % XCHAL_DCACHE_LINESIZE) == 0, ""); + sys_cache_data_flush_and_invd_range(stack, (char *)stack_ptr - (char *)stack); +#endif +} + +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) +int arch_float_disable(struct k_thread *thread) +{ + /* xtensa always has FPU enabled so cannot be disabled */ + return -ENOTSUP; +} + +int arch_float_enable(struct k_thread *thread, unsigned int options) +{ + /* xtensa always has FPU enabled so nothing to do here */ + return 0; +} +#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ + +#ifdef CONFIG_USERSPACE +FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3) +{ + struct k_thread *current = _current; + size_t stack_end; + + /* Transition will reset stack pointer to initial, discarding + * any old context since this is a one-way operation + */ + stack_end = Z_STACK_PTR_ALIGN(current->stack_info.start + + current->stack_info.size - + current->stack_info.delta); + + xtensa_userspace_enter(user_entry, p1, p2, p3, + stack_end, current->stack_info.start); + + CODE_UNREACHABLE; +} +#endif /* CONFIG_USERSPACE */ diff --git a/arch/xtensa/core/userspace.S b/arch/xtensa/core/userspace.S new file mode 100644 index 00000000000..f840aec6c04 --- /dev/null +++ b/arch/xtensa/core/userspace.S @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2022, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +/** + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ +.pushsection .text.xtensa_do_syscall, "ax" +.global xtensa_do_syscall +.align 4 +xtensa_do_syscall: + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + s32i a1, a0, ___xtensa_irq_bsa_t_scratch_OFFSET + s32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + s32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + rsr a2, ZSR_A0SAVE + s32i a2, a0, ___xtensa_irq_bsa_t_a0_OFFSET + rsr.ps a2 + movi a3, ~PS_OWB_MASK + and a2, a2, a3 + s32i a2, a0, ___xtensa_irq_bsa_t_ps_OFFSET + rsr.epc1 a2 + s32i a2, a0, ___xtensa_irq_bsa_t_pc_OFFSET + + movi a2, PS_WOE|PS_INTLEVEL(XCHAL_NMILEVEL) + rsr.ps a3 + or a3, a3, a2 + movi a2, ~(PS_EXCM | PS_RING_MASK) + and a3, a3, a2 + wsr.ps a3 + rsync + l32i a2, a0, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a0, ___xtensa_irq_bsa_t_a3_OFFSET + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + l32i a0, a0, _thread_offset_to_psp + addi a0, a0, -___xtensa_irq_bsa_t_SIZEOF + + mov a1, a0 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET +#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 + bne a2, a3, end_loop + rsr.lcount a2 + beqz a2, end_loop + addi a2, a2, -1 + wsr.lcount a2 + rsr.lbeg a3 +end_loop: +#else + /* EPC1 (and now a3) contains the address that invoked syscall. + * We need to increment it to execute the next instruction when + * we return. The instruction size is 3 bytes, so lets just add it. + */ + addi a3, a3, 3 +#endif + s32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + ODD_REG_SAVE + + call0 xtensa_save_high_regs + + l32i a2, a1, 0 + l32i a2, a2, ___xtensa_irq_bsa_t_a2_OFFSET + movi a0, K_SYSCALL_LIMIT + bgeu a2, a0, _bad_syscall + +_id_ok: + /* Find the function handler for the given syscall id. */ + movi a3, _k_syscall_table + slli a2, a2, 2 + add a2, a2, a3 + l32i a2, a2, 0 + + /* Clear up the threadptr because it is used + * to check if a thread is running on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possibly running in user mode. + */ +#ifdef CONFIG_THREAD_LOCAL_STORAGE + movi a0, is_user_mode@tpoff + rur.THREADPTR a3 + add a0, a3, a0 + + movi a3, 0 + s32i a3, a0, 0 +#else + movi a0, 0 + wur.THREADPTR a0 +#endif + + /* Set syscall parameters. We have an initial call4 to set up the + * the stack and then a new call4 for the syscall function itself. + * So parameters should be put as if it was a call8. + */ + mov a10, a8 + mov a11, a9 + mov a8, a4 + mov a9, a5 + l32i a3, a1, 0 + l32i a7, a3, ___xtensa_irq_bsa_t_a3_OFFSET + + + /* Since we are unmasking EXCM, we need to set RING bits to kernel + * mode, otherwise we won't be able to run the exception handler in C. + */ + movi a0, PS_WOE|PS_CALLINC(0)|PS_UM|PS_INTLEVEL(0) + wsr.ps a0 + rsync + + call4 _syscall_call0 + + /* copy return value. Lets put it in the top of stack + * because registers will be clobbered in + * xtensa_restore_high_regs + */ + l32i a3, a1, 0 + s32i a6, a3, ___xtensa_irq_bsa_t_a2_OFFSET + + j _syscall_returned + +.align 4 +_syscall_call0: + /* We want an ENTRY to set a bit in windowstart */ + jx a2 + + +_syscall_returned: + call0 xtensa_restore_high_regs + + l32i a3, a1, ___xtensa_irq_bsa_t_sar_OFFSET + wsr a3, SAR +#if XCHAL_HAVE_LOOPS + l32i a3, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET + wsr a3, LBEG + l32i a3, a1, ___xtensa_irq_bsa_t_lend_OFFSET + wsr a3, LEND + l32i a3, a1, ___xtensa_irq_bsa_t_lcount_OFFSET + wsr a3, LCOUNT +#endif +#if XCHAL_HAVE_S32C1I + l32i a3, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET + wsr a3, SCOMPARE1 +#endif + +#ifdef CONFIG_THREAD_LOCAL_STORAGE + l32i a3, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 +#endif + + l32i a3, a1, ___xtensa_irq_bsa_t_ps_OFFSET + wsr.ps a3 + + l32i a3, a1, ___xtensa_irq_bsa_t_pc_OFFSET + wsr.epc1 a3 + + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + l32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + + l32i a1, a1, ___xtensa_irq_bsa_t_scratch_OFFSET + rsync + + rfe + +_bad_syscall: + movi a2, K_SYSCALL_BAD + j _id_ok + +.popsection + +/* FUNC_NORETURN void xtensa_userspace_enter(k_thread_entry_t user_entry, + * void *p1, void *p2, void *p3, + * uint32_t stack_end, + * uint32_t stack_start) + * + * A one-way trip to userspace. + */ +.global xtensa_userspace_enter +.type xtensa_userspace_enter, @function +.align 4 +xtensa_userspace_enter: + /* Call entry to set a bit in the windowstart and + * do the rotation, but we are going to set our own + * stack. + */ + entry a1, 16 + + /* We have to switch to kernel stack before spill kernel data and + * erase user stack to avoid leak from previous context. + */ + mov a1, a7 /* stack start (low address) */ + addi a1, a1, -16 + + SPILL_ALL_WINDOWS + + rsr a0, ZSR_CPU + l32i a0, a0, ___cpu_t_current_OFFSET + + addi a1, a1, -28 + s32i a0, a1, 24 + s32i a2, a1, 20 + s32i a3, a1, 16 + s32i a4, a1, 12 + s32i a5, a1, 8 + s32i a6, a1, 4 + s32i a7, a1, 0 + + l32i a6, a1, 24 + call4 xtensa_user_stack_perms + + l32i a6, a1, 24 + call4 xtensa_swap_update_page_tables + +#ifdef CONFIG_THREAD_LOCAL_STORAGE + rur.threadptr a3 + movi a0, is_user_mode@tpoff + add a0, a3, a0 + movi a3, 1 + s32i a3, a0, 0 +#else + rsr a3, ZSR_CPU + l32i a3, a3, ___cpu_t_current_OFFSET + wur.THREADPTR a3 +#endif + + /* Set now z_thread_entry parameters, we are simulating a call4 + * call, so parameters start at a6, a7, ... + */ + l32i a6, a1, 20 + l32i a7, a1, 16 + l32i a8, a1, 12 + l32i a9, a1, 8 + + /* stash user stack */ + l32i a0, a1, 4 + + /* Go back to user stack */ + mov a1, a0 + + movi a0, z_thread_entry + wsr.epc2 a0 + + /* Configuring PS register. + * We have to set callinc as well, since the called + * function will do "entry" + */ + movi a0, PS_WOE|PS_CALLINC(1)|PS_UM|PS_RING(2) + wsr a0, EPS2 + + movi a0, 0 + + rfi 2 + +/* + * size_t arch_user_string_nlen(const char *s, size_t maxsize, int *err_arg) + */ +.global arch_user_string_nlen +.type arch_user_string_nlen, @function +.align 4 +arch_user_string_nlen: + entry a1, 32 + + /* error value, set to -1. */ + movi a5, -1 + s32i a5, a4, 0 + + /* length count */ + xor a5, a5, a5 + + /* This code might page fault */ +strlen_loop: +.global xtensa_user_string_nlen_fault_start +xtensa_user_string_nlen_fault_start: + l8ui a6, a2, 0 /* Current char */ + +.global xtensa_user_string_nlen_fault_end +xtensa_user_string_nlen_fault_end: + beqz a6, strlen_done + addi a5, a5, 1 + addi a2, a2, 1 + beq a5, a3, strlen_done + j strlen_loop + +strlen_done: + /* Set return value */ + mov a2, a5 + + /* Set error value to 0 since we succeeded */ + movi a5, 0x0 + s32i a5, a4, 0 + +.global xtensa_user_string_nlen_fixup +xtensa_user_string_nlen_fixup: + retw diff --git a/arch/xtensa/core/vector_handlers.c b/arch/xtensa/core/vector_handlers.c new file mode 100644 index 00000000000..0a99ec5dd09 --- /dev/null +++ b/arch/xtensa/core/vector_handlers.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2017, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include <_soc_inthandlers.h> +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); + +extern char xtensa_arch_except_epc[]; +extern char xtensa_arch_kernel_oops_epc[]; + +#ifdef CONFIG_USERSPACE +Z_EXC_DECLARE(xtensa_user_string_nlen); + +static const struct z_exc_handle exceptions[] = { + Z_EXC_HANDLE(xtensa_user_string_nlen) +}; +#endif /* CONFIG_USERSPACE */ + +void xtensa_dump_stack(const z_arch_esf_t *stack) +{ + _xtensa_irq_stack_frame_raw_t *frame = (void *)stack; + _xtensa_irq_bsa_t *bsa = frame->ptr_to_bsa; + uintptr_t num_high_regs; + int reg_blks_remaining; + + /* Calculate number of high registers. */ + num_high_regs = (uint8_t *)bsa - (uint8_t *)frame + sizeof(void *); + num_high_regs /= sizeof(uintptr_t); + + /* And high registers are always comes in 4 in a block. */ + reg_blks_remaining = (int)num_high_regs / 4; + + LOG_ERR(" ** A0 %p SP %p A2 %p A3 %p", + (void *)bsa->a0, + (void *)((char *)bsa + sizeof(*bsa)), + (void *)bsa->a2, (void *)bsa->a3); + + if (reg_blks_remaining > 0) { + reg_blks_remaining--; + + LOG_ERR(" ** A4 %p A5 %p A6 %p A7 %p", + (void *)frame->blks[reg_blks_remaining].r0, + (void *)frame->blks[reg_blks_remaining].r1, + (void *)frame->blks[reg_blks_remaining].r2, + (void *)frame->blks[reg_blks_remaining].r3); + } + + if (reg_blks_remaining > 0) { + reg_blks_remaining--; + + LOG_ERR(" ** A8 %p A9 %p A10 %p A11 %p", + (void *)frame->blks[reg_blks_remaining].r0, + (void *)frame->blks[reg_blks_remaining].r1, + (void *)frame->blks[reg_blks_remaining].r2, + (void *)frame->blks[reg_blks_remaining].r3); + } + + if (reg_blks_remaining > 0) { + reg_blks_remaining--; + + LOG_ERR(" ** A12 %p A13 %p A14 %p A15 %p", + (void *)frame->blks[reg_blks_remaining].r0, + (void *)frame->blks[reg_blks_remaining].r1, + (void *)frame->blks[reg_blks_remaining].r2, + (void *)frame->blks[reg_blks_remaining].r3); + } + +#if XCHAL_HAVE_LOOPS + LOG_ERR(" ** LBEG %p LEND %p LCOUNT %p", + (void *)bsa->lbeg, + (void *)bsa->lend, + (void *)bsa->lcount); +#endif + + LOG_ERR(" ** SAR %p", (void *)bsa->sar); + +#if XCHAL_HAVE_THREADPTR + LOG_ERR(" ** THREADPTR %p", (void *)bsa->threadptr); +#endif +} + +static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) +{ + int mask; + + mask = BIT(num_bits) - 1; + val = val >> offset; + return val & mask; +} + +static void print_fatal_exception(void *print_stack, int cause, + bool is_dblexc, uint32_t depc) +{ + void *pc; + uint32_t ps, vaddr; + _xtensa_irq_bsa_t *bsa = (void *)*(int **)print_stack; + + ps = bsa->ps; + pc = (void *)bsa->pc; + + __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); + + LOG_ERR(" ** FATAL EXCEPTION%s", (is_dblexc ? " (DOUBLE)" : "")); + LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", + arch_curr_cpu()->id, cause, + xtensa_exccause(cause)); + LOG_ERR(" ** PC %p VADDR %p", pc, (void *)vaddr); + + if (is_dblexc) { + LOG_ERR(" ** DEPC %p", (void *)depc); + } + + LOG_ERR(" ** PS %p", (void *)bsa->ps); + LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", + get_bits(0, 4, ps), get_bits(4, 1, ps), + get_bits(5, 1, ps), get_bits(6, 2, ps), + get_bits(18, 1, ps), + get_bits(8, 4, ps), get_bits(16, 2, ps)); +} + +static ALWAYS_INLINE void usage_stop(void) +{ +#ifdef CONFIG_SCHED_THREAD_USAGE + z_sched_usage_stop(); +#endif +} + +static inline void *return_to(void *interrupted) +{ +#ifdef CONFIG_MULTITHREADING + return _current_cpu->nested <= 1 ? + z_get_next_switch_handle(interrupted) : interrupted; +#else + return interrupted; +#endif /* CONFIG_MULTITHREADING */ +} + +/* The wrapper code lives here instead of in the python script that + * generates _xtensa_handle_one_int*(). Seems cleaner, still kind of + * ugly. + * + * This may be unused depending on number of interrupt levels + * supported by the SoC. + */ +#define DEF_INT_C_HANDLER(l) \ +__unused void *xtensa_int##l##_c(void *interrupted_stack) \ +{ \ + uint32_t irqs, intenable, m; \ + usage_stop(); \ + __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \ + __asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \ + irqs &= intenable; \ + while ((m = _xtensa_handle_one_int##l(irqs))) { \ + irqs ^= m; \ + __asm__ volatile("wsr.intclear %0" : : "r"(m)); \ + } \ + return return_to(interrupted_stack); \ +} + +#if XCHAL_NMILEVEL >= 2 +DEF_INT_C_HANDLER(2) +#endif + +#if XCHAL_NMILEVEL >= 3 +DEF_INT_C_HANDLER(3) +#endif + +#if XCHAL_NMILEVEL >= 4 +DEF_INT_C_HANDLER(4) +#endif + +#if XCHAL_NMILEVEL >= 5 +DEF_INT_C_HANDLER(5) +#endif + +#if XCHAL_NMILEVEL >= 6 +DEF_INT_C_HANDLER(6) +#endif + +#if XCHAL_NMILEVEL >= 7 +DEF_INT_C_HANDLER(7) +#endif + +static inline DEF_INT_C_HANDLER(1) + +/* C handler for level 1 exceptions/interrupts. Hooked from the + * DEF_EXCINT 1 vector declaration in assembly code. This one looks + * different because exceptions and interrupts land at the same + * vector; other interrupt levels have their own vectors. + */ +void *xtensa_excint1_c(int *interrupted_stack) +{ + int cause; + _xtensa_irq_bsa_t *bsa = (void *)*(int **)interrupted_stack; + bool is_fatal_error = false; + bool is_dblexc = false; + uint32_t ps; + void *pc, *print_stack = (void *)interrupted_stack; + uint32_t depc = 0; + + __asm__ volatile("rsr.exccause %0" : "=r"(cause)); + +#ifdef CONFIG_XTENSA_MMU + __asm__ volatile("rsr.depc %0" : "=r"(depc)); + + is_dblexc = (depc != 0U); +#endif /* CONFIG_XTENSA_MMU */ + + switch (cause) { + case EXCCAUSE_LEVEL1_INTERRUPT: + if (!is_dblexc) { + return xtensa_int1_c(interrupted_stack); + } + break; +#ifndef CONFIG_USERSPACE + /* Syscalls are handled earlier in assembly if MMU is enabled. + * So we don't need this here. + */ + case EXCCAUSE_SYSCALL: + /* Just report it to the console for now */ + LOG_ERR(" ** SYSCALL PS %p PC %p", + (void *)bsa->ps, (void *)bsa->pc); + xtensa_dump_stack(interrupted_stack); + + /* Xtensa exceptions don't automatically advance PC, + * have to skip the SYSCALL instruction manually or + * else it will just loop forever + */ + bsa->pc += 3; + break; +#endif /* !CONFIG_USERSPACE */ + default: + ps = bsa->ps; + pc = (void *)bsa->pc; + +#ifdef CONFIG_USERSPACE + /* If the faulting address is from one of the known + * exceptions that should not be fatal, return to + * the fixup address. + */ + for (int i = 0; i < ARRAY_SIZE(exceptions); i++) { + if ((pc >= exceptions[i].start) && + (pc < exceptions[i].end)) { + bsa->pc = (uintptr_t)exceptions[i].fixup; + + goto fixup_out; + } + } +#endif /* CONFIG_USERSPACE */ + + /* Default for exception */ + int reason = K_ERR_CPU_EXCEPTION; + is_fatal_error = true; + + /* We need to distinguish between an ill in xtensa_arch_except, + * e.g for k_panic, and any other ill. For exceptions caused by + * xtensa_arch_except calls, we also need to pass the reason_p + * to xtensa_fatal_error. Since the ARCH_EXCEPT frame is in the + * BSA, the first arg reason_p is stored at the A2 offset. + * We assign EXCCAUSE the unused, reserved code 63; this may be + * problematic if the app or new boards also decide to repurpose + * this code. + * + * Another intentionally ill is from xtensa_arch_kernel_oops. + * Kernel OOPS has to be explicity raised so we can simply + * set the reason and continue. + */ + if (cause == EXCCAUSE_ILLEGAL) { + if (pc == (void *)&xtensa_arch_except_epc) { + cause = 63; + __asm__ volatile("wsr.exccause %0" : : "r"(cause)); + reason = bsa->a2; + } else if (pc == (void *)&xtensa_arch_kernel_oops_epc) { + cause = 64; /* kernel oops */ + reason = K_ERR_KERNEL_OOPS; + + /* A3 contains the second argument to + * xtensa_arch_kernel_oops(reason, ssf) + * where ssf is the stack frame causing + * the kernel oops. + */ + print_stack = (void *)bsa->a3; + } + } + + if (reason != K_ERR_KERNEL_OOPS) { + print_fatal_exception(print_stack, cause, is_dblexc, depc); + } + + /* FIXME: legacy xtensa port reported "HW" exception + * for all unhandled exceptions, which seems incorrect + * as these are software errors. Should clean this + * up. + */ + xtensa_fatal_error(reason, (void *)print_stack); + break; + } + +#ifdef CONFIG_XTENSA_MMU + switch (cause) { + case EXCCAUSE_LEVEL1_INTERRUPT: +#ifndef CONFIG_USERSPACE + case EXCCAUSE_SYSCALL: +#endif /* !CONFIG_USERSPACE */ + is_fatal_error = false; + break; + default: + is_fatal_error = true; + break; + } +#endif /* CONFIG_XTENSA_MMU */ + + if (is_dblexc || is_fatal_error) { + uint32_t ignore; + + /* We are going to manipulate _current_cpu->nested manually. + * Since the error is fatal, for recoverable errors, code + * execution must not return back to the current thread as + * it is being terminated (via above xtensa_fatal_error()). + * So we need to prevent more interrupts coming in which + * will affect the nested value as we are going outside of + * normal interrupt handling procedure. + * + * Setting nested to 1 has two effects: + * 1. Force return_to() to choose a new thread. + * Since the current thread is being terminated, it will + * not be chosen again. + * 2. When context switches to the newly chosen thread, + * nested must be zero for normal code execution, + * as that is not in interrupt context at all. + * After returning from this function, the rest of + * interrupt handling code will decrement nested, + * resulting it being zero before switching to another + * thread. + */ + __asm__ volatile("rsil %0, %1" + : "=r" (ignore) : "i"(XCHAL_NMILEVEL)); + + _current_cpu->nested = 1; + } + +#ifdef CONFIG_XTENSA_MMU +#ifdef CONFIG_USERSPACE +fixup_out: +#endif + if (is_dblexc) { + __asm__ volatile("wsr.depc %0" : : "r"(0)); + } +#endif /* CONFIG_XTENSA_MMU */ + + + return return_to(interrupted_stack); +} + +#if defined(CONFIG_GDBSTUB) +void *xtensa_debugint_c(int *interrupted_stack) +{ + extern void z_gdb_isr(z_arch_esf_t *esf); + + z_gdb_isr((void *)interrupted_stack); + + return return_to(interrupted_stack); +} +#endif diff --git a/arch/xtensa/core/window_vectors.S b/arch/xtensa/core/window_vectors.S index a63923cbd6f..90eba495bde 100644 --- a/arch/xtensa/core/window_vectors.S +++ b/arch/xtensa/core/window_vectors.S @@ -84,7 +84,7 @@ _WindowUnderflow4: /* Handle alloca exception generated by interruptee executing 'movsp'. * This uses space between the window vectors, so is essentially * "free". All interruptee's regs are intact except a0 which is saved - * in $ZSR_ALLOCA (assigned at build time, see gen_zsr.py for + * in $ZSR_A0SAVE (assigned at build time, see gen_zsr.py for * details), and PS.EXCM has been set by the exception hardware (can't * be interrupted). The fact the alloca exception was taken means the * registers associated with the base-save area have been spilled and @@ -102,7 +102,7 @@ _xt_alloca_exc: rsr a2, PS extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS xor a3, a3, a4 /* bits changed from old to current windowbase */ - rsr a4, ZSR_ALLOCA /* restore original a0 (now in a4) */ + rsr a4, ZSR_A0SAVE /* 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 a2, PS /* update PS.OWB to new window base */ diff --git a/arch/xtensa/core/xtensa-asm2-util.S b/arch/xtensa/core/xtensa-asm2-util.S deleted file mode 100644 index d7ba88aaffc..00000000000 --- a/arch/xtensa/core/xtensa-asm2-util.S +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include - -#if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) -#include -#endif - -/* - * xtensa_spill_reg_windows - * - * Spill all register windows. Not a C function, enter this via CALL0 - * (so you have to save off A0, but no other registers need to be - * spilled). On return, all registers not part of the current - * function will be spilled to memory. The WINDOWSTART SR will have a - * single 1 bit corresponding to the current frame at WINDOWBASE. - */ -.global xtensa_spill_reg_windows -.align 4 -xtensa_spill_reg_windows: - SPILL_ALL_WINDOWS - ret - -/* - * xtensa_save_high_regs - * - * Call with CALL0, with A2/A3 available as scratch. Pushes the high - * A4-A15 GPRs to the stack if needed (i.e. if those registers are not - * part of wrapped-around frames higher up the call stack), returning - * to the caller with the stack pointer HAVING BEEN MODIFIED to - * contain them. - */ -.global xtensa_save_high_regs -.align 4 -xtensa_save_high_regs: - /* Generate a rotated (modulo NREGS/4 bits!) WINDOWSTART in A2 - * by duplicating the bits twice and shifting down by WINDOWBASE - * bits. Now the LSB is the register quad at WINDOWBASE. - */ - rsr a2, WINDOWSTART - slli a3, a2, (XCHAL_NUM_AREGS / 4) - or a2, a2, a3 - rsr a3, WINDOWBASE - ssr a3 - srl a2, a2 - - mov a3, a1 /* Stash our original stack pointer */ - - /* For the next three bits in WINDOWSTART (which correspond to - * the A4-A7, A8-A11 and A12-A15 quads), if we find a one, - * that means that the quad is owned by a wrapped-around call - * in the registers, so we don't need to spill it or any - * further registers from the GPRs and can skip to the end. - */ - bbsi a2, 1, _high_gpr_spill_done - addi a1, a1, -16 - s32i a4, a1, 0 - s32i a5, a1, 4 - s32i a6, a1, 8 - s32i a7, a1, 12 - - bbsi a2, 2, _high_gpr_spill_done - addi a1, a1, -16 - s32i a8, a1, 0 - s32i a9, a1, 4 - s32i a10, a1, 8 - s32i a11, a1, 12 - - bbsi a2, 3, _high_gpr_spill_done - addi a1, a1, -16 - s32i a12, a1, 0 - s32i a13, a1, 4 - s32i a14, a1, 8 - s32i a15, a1, 12 - -_high_gpr_spill_done: - /* Push the original stack pointer so we know at restore - * time how many registers were spilled, then return, leaving the - * modified SP in A1. - */ - addi a1, a1, -4 - s32i a3, a1, 0 - - ret - -/* - * xtensa_restore_high_regs - * - * Does the inverse of xtensa_save_high_regs, taking a stack pointer - * in A1 that resulted and restoring the A4-A15 state (and the stack - * pointer) to the state they had at the earlier call. Call with - * CALL0, leaving A2/A3 available as scratch. - */ -.global xtensa_restore_high_regs -.align 4 -xtensa_restore_high_regs: - /* pop our "original" stack pointer into a2, stash in a3 also */ - l32i a2, a1, 0 - addi a1, a1, 4 - mov a3, a2 - - beq a1, a2, _high_restore_done - addi a2, a2, -16 - l32i a4, a2, 0 - l32i a5, a2, 4 - l32i a6, a2, 8 - l32i a7, a2, 12 - - beq a1, a2, _high_restore_done - addi a2, a2, -16 - l32i a8, a2, 0 - l32i a9, a2, 4 - l32i a10, a2, 8 - l32i a11, a2, 12 - - beq a1, a2, _high_restore_done - addi a2, a2, -16 - l32i a12, a2, 0 - l32i a13, a2, 4 - l32i a14, a2, 8 - l32i a15, a2, 12 - -_high_restore_done: - mov a1, a3 /* Original stack */ - ret - -/* - * _restore_context - * - * Arrive here via a jump. Enters into the restored context and does - * not return. A1 should have a context pointer in it as received - * from switch or an interrupt exit. Interrupts must be disabled, - * and register windows should have been spilled. - * - * Note that exit from the restore is done with the RFI instruction, - * using the EPCn/EPSn registers. Those will have been saved already - * by any interrupt entry so they are save to use. Note that EPC1 and - * RFE are NOT usable (they can't preserve PS). Per the ISA spec, all - * RFI levels do the same thing and differ only in the special - * registers used to hold PC/PS, but Qemu has been observed to behave - * strangely when RFI doesn't "return" to a INTLEVEL strictly lower - * than it started from. So we leverage the zsr.h framework to pick - * the highest level available for our specific platform. - */ -.global _restore_context -_restore_context: - call0 xtensa_restore_high_regs - - l32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET - wsr a0, ZSR_EPC - l32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET - wsr a0, ZSR_EPS - -#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) - FPU_REG_RESTORE -#endif - - l32i a0, a1, ___xtensa_irq_bsa_t_sar_OFFSET - wsr a0, SAR -#if XCHAL_HAVE_LOOPS - l32i a0, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET - wsr a0, LBEG - l32i a0, a1, ___xtensa_irq_bsa_t_lend_OFFSET - wsr a0, LEND - l32i a0, a1, ___xtensa_irq_bsa_t_lcount_OFFSET - wsr a0, LCOUNT -#endif -#if XCHAL_HAVE_S32C1I - l32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET - wsr a0, SCOMPARE1 -#endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) - l32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET - wur a0, THREADPTR -#endif - rsync - - l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET - l32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET - l32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET - addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF - - rfi ZSR_RFI_LEVEL - -/* - * void xtensa_arch_except(int reason_p); - * - * Implements hardware exception for Xtensa ARCH_EXCEPT to save - * interrupted stack frame and reason_p for use in exception handler - * and coredump - */ -.global xtensa_arch_except -.global xtensa_arch_except_epc -.align 4 -xtensa_arch_except: - entry a1, 16 -xtensa_arch_except_epc: - ill - retw - -/* - * void xtensa_switch(void *new, void **old_return); - * - * Context switches into the previously-saved "new" handle, placing - * the saved "old" handle into the address provided by old_return. - */ -.global xtensa_switch -.align 4 -xtensa_switch: - entry a1, 16 - SPILL_ALL_WINDOWS - addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF - - /* Stash our A0/2/3 and the shift/loop registers into the base - * save area so they get restored as they are now. A2/A3 - * don't actually get used post-restore, but they need to be - * stashed across the xtensa_save_high_regs call and this is a - * convenient place. - */ - s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET - s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET - s32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET - ODD_REG_SAVE - - /* Stash our PS register contents and a "restore" PC. */ - rsr a0, PS - s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET - movi a0, _switch_restore_pc - s32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET - - /* Now the high registers */ - call0 xtensa_save_high_regs - -#ifdef CONFIG_KERNEL_COHERENCE - /* Flush the stack. The top of stack was stored for us by - * arch_cohere_stacks(). It can be NULL for a dummy thread. - */ - rsr a0, ZSR_FLUSH - beqz a0, noflush - mov a3, a1 -flushloop: - dhwb a3, 0 - addi a3, a3, XCHAL_DCACHE_LINESIZE - blt a3, a0, flushloop -noflush: -#endif - - /* Restore the A3 argument we spilled earlier (via the base - * save pointer pushed at the bottom of the stack) and set the - * stack to the "new" context out of the A2 spill slot. - */ - l32i a2, a1, 0 - l32i a3, a2, ___xtensa_irq_bsa_t_a3_OFFSET - s32i a1, a3, 0 - - /* Switch stack pointer and restore. The jump to - * _restore_context does not return as such, but we arrange - * for the restored "next" address to be immediately after for - * sanity. - */ - l32i a1, a2, ___xtensa_irq_bsa_t_a2_OFFSET - -#ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING - call4 z_thread_mark_switched_in -#endif - j _restore_context -_switch_restore_pc: - retw - -/* Define our entry handler to load the struct kernel_t from the - * MISC0 special register, and to find the nest and irq_stack values - * at the precomputed offsets. - */ -.align 4 -_handle_excint: - EXCINT_HANDLER ___cpu_t_nested_OFFSET, ___cpu_t_irq_stack_OFFSET - -/* Define the actual vectors for the hardware-defined levels with - * DEF_EXCINT. These load a C handler address and jump to our handler - * above. - */ - -DEF_EXCINT 1, _handle_excint, xtensa_excint1_c - -#if XCHAL_NMILEVEL >= 2 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 2)) -DEF_EXCINT 2, _handle_excint, xtensa_int2_c -#endif -#endif - -#if XCHAL_NMILEVEL >= 3 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 3)) -DEF_EXCINT 3, _handle_excint, xtensa_int3_c -#endif -#endif - -#if XCHAL_NMILEVEL >= 4 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 4)) -DEF_EXCINT 4, _handle_excint, xtensa_int4_c -#endif -#endif - -#if XCHAL_NMILEVEL >= 5 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 5)) -DEF_EXCINT 5, _handle_excint, xtensa_int5_c -#endif -#endif - -#if XCHAL_NMILEVEL >= 6 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 6)) -DEF_EXCINT 6, _handle_excint, xtensa_int6_c -#endif -#endif - -#if XCHAL_NMILEVEL >= 7 -#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 7)) -DEF_EXCINT 7, _handle_excint, xtensa_int7_c -#endif -#endif - -#if defined(CONFIG_GDBSTUB) -DEF_EXCINT XCHAL_DEBUGLEVEL, _handle_excint, xtensa_debugint_c -#endif - -/* The user exception vector is defined here, as we need to handle - * MOVSP exceptions in assembly (the result has to be to unspill the - * caller function of the code that took the exception, and that can't - * be done in C). A prototype exists which mucks with the stack frame - * from the C handler instead, but that would add a LARGE overhead to - * some alloca() calls (those whent he caller has been spilled) just - * to save these five cycles during other exceptions and L1 - * interrupts. Maybe revisit at some point, with better benchmarking. - * Note that _xt_alloca_exc is Xtensa-authored code which expects A0 - * to have been saved to EXCSAVE1, we've modified it to use the zsr.h - * API to get assigned a scratch register. - */ -.pushsection .UserExceptionVector.text, "ax" -.global _Level1RealVector -_Level1RealVector: - wsr a0, ZSR_ALLOCA - rsync - rsr.exccause a0 -#ifdef CONFIG_XTENSA_MMU - beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_user - addi a0, a0, -EXCCAUSE_DTLB_MISS - beqz a0, _handle_tlb_miss_user - rsr.exccause a0 -#endif /* CONFIG_XTENSA_MMU */ - bnei a0, EXCCAUSE_ALLOCA, _not_alloca - - j _xt_alloca_exc -_not_alloca: - rsr a0, ZSR_ALLOCA - j _Level1Vector -#ifdef CONFIG_XTENSA_MMU -_handle_tlb_miss_user: - /** - * Handle TLB miss by loading the PTE page: - * The way it works is, when we try to access an address that is not - * mapped, we will have a miss. The HW then will try to get the - * correspondent memory in the page table. As the page table is not - * mapped in memory we will have a second miss, which will trigger - * an exception. In the exception (here) what we do is to exploit - * this hardware capability just trying to load the page table - * (not mapped address), which will cause a miss, but then the hardware - * will automatically map it again from the page table. This time - * it will work since the page necessary to map the page table itself - * are wired map. - */ - rsr.ptevaddr a0 - l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA - rfe -#endif /* CONFIG_XTENSA_MMU */ -.popsection - -/* In theory you can have levels up to 15, but known hardware only uses 7. */ -#if XCHAL_NMILEVEL > 7 -#error More interrupts than expected. -#endif - -/* We don't actually use "kernel mode" currently. Populate the vector - * out of simple caution in case app code clears the UM bit by mistake. - */ -.pushsection .KernelExceptionVector.text, "ax" -.global _KernelExceptionVector -_KernelExceptionVector: -#ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA - rsr.exccause a0 - beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_kernel - addi a0, a0, -EXCCAUSE_DTLB_MISS - beqz a0, _handle_tlb_miss_kernel - rsr a0, ZSR_ALLOCA -#endif - j _Level1Vector -#ifdef CONFIG_XTENSA_MMU -_handle_tlb_miss_kernel: - /* The TLB miss handling is used only during z_xtensa_mmu_init() - * where vecbase is at a different address, as the offset used - * in the jump ('j') instruction will not jump to correct - * address (... remember the vecbase is moved). - * So we handle TLB misses in a very simple way here until - * we move back to using UserExceptionVector above. - */ - rsr.ptevaddr a0 - l32i a0, a0, 0 - rsr a0, ZSR_ALLOCA - rfe -#endif -.popsection - -#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR -.pushsection .DoubleExceptionVector.text, "ax" -.global _DoubleExceptionVector -_DoubleExceptionVector: -#ifdef CONFIG_XTENSA_MMU - wsr a0, ZSR_ALLOCA - rsync - - rsr.exccause a0 - addi a0, a0, -EXCCAUSE_DTLB_MISS - beqz a0, _handle_tlb_miss_dblexc - - rsr a0, ZSR_ALLOCA -#endif -#if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) -1: -/* Tell simulator to stop executing here, instead of trying to do - * an infinite loop (see below). Greatly help with using tracing in - * simulator so that traces will not have infinite iterations of - * jumps. - */ - movi a3, 1 - movi a2, SYS_exit - simcall -#elif XCHAL_HAVE_DEBUG -/* Signals an unhandled double exception */ -1: break 1, 4 -#else -1: -#endif - j 1b - -#ifdef CONFIG_XTENSA_MMU -_handle_tlb_miss_dblexc: - /* Handle all data TLB misses here. - * These data TLB misses are mostly caused by preloading - * page table entries in the level 1 exception handler. - * Failure to load the PTE will result in another exception - * with different failure (exccause), which can be handled - * when the CPU re-enters the double exception handler. - */ - rsr.ptevaddr a0 - l32i a0, a0, 0 - - rsr a0, ZSR_ALLOCA - rfde -#endif -.popsection - -#endif diff --git a/arch/xtensa/core/xtensa-asm2.c b/arch/xtensa/core/xtensa-asm2.c deleted file mode 100644 index c2371ac8f55..00000000000 --- a/arch/xtensa/core/xtensa-asm2.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include -#include -#include <_soc_inthandlers.h> -#include -#include -#include -#include - -LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); - -extern char xtensa_arch_except_epc[]; - -void *xtensa_init_stack(struct k_thread *thread, int *stack_top, - void (*entry)(void *, void *, void *), - void *arg1, void *arg2, void *arg3) -{ - void *ret; - _xtensa_irq_stack_frame_a11_t *frame; - - /* Not-a-cpu ID Ensures that the first time this is run, the - * stack will be invalidated. That covers the edge case of - * restarting a thread on a stack that had previously been run - * on one CPU, but then initialized on this one, and - * potentially run THERE and not HERE. - */ - thread->arch.last_cpu = -1; - - /* We cheat and shave 16 bytes off, the top four words are the - * A0-A3 spill area for the caller of the entry function, - * which doesn't exist. It will never be touched, so we - * arrange to enter the function with a CALLINC of 1 and a - * stack pointer 16 bytes above the top, so its ENTRY at the - * start will decrement the stack pointer by 16. - */ - const int bsasz = sizeof(*frame) - 16; - - frame = (void *)(((char *) stack_top) - bsasz); - - (void)memset(frame, 0, bsasz); - - frame->bsa.pc = (uintptr_t)z_thread_entry; - frame->bsa.ps = PS_WOE | PS_UM | PS_CALLINC(1); - -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) - frame->bsa.threadptr = thread->tls; -#endif - - /* Arguments to z_thread_entry(). Remember these start at A6, - * which will be rotated into A2 by the ENTRY instruction that - * begins the C function. And A4-A7 and A8-A11 are optional - * quads that live below the BSA! - */ - frame->a7 = (uintptr_t)arg1; /* a7 */ - frame->a6 = (uintptr_t)entry; /* a6 */ - frame->a5 = 0; /* a5 */ - frame->a4 = 0; /* a4 */ - - frame->a11 = 0; /* a11 */ - frame->a10 = 0; /* a10 */ - frame->a9 = (uintptr_t)arg3; /* a9 */ - frame->a8 = (uintptr_t)arg2; /* a8 */ - - /* Finally push the BSA pointer and return the stack pointer - * as the handle - */ - frame->ptr_to_bsa = (void *)&frame->bsa; - ret = &frame->ptr_to_bsa; - - return ret; -} - -void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack, - char *stack_ptr, k_thread_entry_t entry, - void *p1, void *p2, void *p3) -{ - thread->switch_handle = xtensa_init_stack(thread, - (int *)stack_ptr, entry, - p1, p2, p3); -#ifdef CONFIG_KERNEL_COHERENCE - __ASSERT((((size_t)stack) % XCHAL_DCACHE_LINESIZE) == 0, ""); - __ASSERT((((size_t)stack_ptr) % XCHAL_DCACHE_LINESIZE) == 0, ""); - sys_cache_data_flush_and_invd_range(stack, (char *)stack_ptr - (char *)stack); -#endif -} - -void z_irq_spurious(const void *arg) -{ - int irqs, ie; - - ARG_UNUSED(arg); - - __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); - __asm__ volatile("rsr.intenable %0" : "=r"(ie)); - LOG_ERR(" ** Spurious INTERRUPT(s) %p, INTENABLE = %p", - (void *)irqs, (void *)ie); - z_xtensa_fatal_error(K_ERR_SPURIOUS_IRQ, NULL); -} - -void z_xtensa_dump_stack(const z_arch_esf_t *stack) -{ - _xtensa_irq_stack_frame_raw_t *frame = (void *)stack; - _xtensa_irq_bsa_t *bsa = frame->ptr_to_bsa; - uintptr_t num_high_regs; - int reg_blks_remaining; - - /* Calculate number of high registers. */ - num_high_regs = (uint8_t *)bsa - (uint8_t *)frame + sizeof(void *); - num_high_regs /= sizeof(uintptr_t); - - /* And high registers are always comes in 4 in a block. */ - reg_blks_remaining = (int)num_high_regs / 4; - - LOG_ERR(" ** A0 %p SP %p A2 %p A3 %p", - (void *)bsa->a0, - (void *)((char *)bsa + sizeof(*bsa)), - (void *)bsa->a2, (void *)bsa->a3); - - if (reg_blks_remaining > 0) { - reg_blks_remaining--; - - LOG_ERR(" ** A4 %p A5 %p A6 %p A7 %p", - (void *)frame->blks[reg_blks_remaining].r0, - (void *)frame->blks[reg_blks_remaining].r1, - (void *)frame->blks[reg_blks_remaining].r2, - (void *)frame->blks[reg_blks_remaining].r3); - } - - if (reg_blks_remaining > 0) { - reg_blks_remaining--; - - LOG_ERR(" ** A8 %p A9 %p A10 %p A11 %p", - (void *)frame->blks[reg_blks_remaining].r0, - (void *)frame->blks[reg_blks_remaining].r1, - (void *)frame->blks[reg_blks_remaining].r2, - (void *)frame->blks[reg_blks_remaining].r3); - } - - if (reg_blks_remaining > 0) { - reg_blks_remaining--; - - LOG_ERR(" ** A12 %p A13 %p A14 %p A15 %p", - (void *)frame->blks[reg_blks_remaining].r0, - (void *)frame->blks[reg_blks_remaining].r1, - (void *)frame->blks[reg_blks_remaining].r2, - (void *)frame->blks[reg_blks_remaining].r3); - } - -#if XCHAL_HAVE_LOOPS - LOG_ERR(" ** LBEG %p LEND %p LCOUNT %p", - (void *)bsa->lbeg, - (void *)bsa->lend, - (void *)bsa->lcount); -#endif - - LOG_ERR(" ** SAR %p", (void *)bsa->sar); -} - -static inline unsigned int get_bits(int offset, int num_bits, unsigned int val) -{ - int mask; - - mask = BIT(num_bits) - 1; - val = val >> offset; - return val & mask; -} - -static ALWAYS_INLINE void usage_stop(void) -{ -#ifdef CONFIG_SCHED_THREAD_USAGE - z_sched_usage_stop(); -#endif -} - -#ifdef CONFIG_MULTITHREADING -void *z_arch_get_next_switch_handle(struct k_thread *interrupted) -{ - return _current_cpu->nested <= 1 ? - z_get_next_switch_handle(interrupted) : interrupted; -} -#else -void *z_arch_get_next_switch_handle(struct k_thread *interrupted) -{ - return interrupted; -} -#endif /* CONFIG_MULTITHREADING */ - -static inline void *return_to(void *interrupted) -{ - return z_arch_get_next_switch_handle(interrupted); -} - -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) -int arch_float_disable(struct k_thread *thread) -{ - /* xtensa always has FPU enabled so cannot be disabled */ - return -ENOTSUP; -} - -int arch_float_enable(struct k_thread *thread, unsigned int options) -{ - /* xtensa always has FPU enabled so nothing to do here */ - return 0; -} -#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */ - -/* The wrapper code lives here instead of in the python script that - * generates _xtensa_handle_one_int*(). Seems cleaner, still kind of - * ugly. - * - * This may be unused depending on number of interrupt levels - * supported by the SoC. - */ -#define DEF_INT_C_HANDLER(l) \ -__unused void *xtensa_int##l##_c(void *interrupted_stack) \ -{ \ - uint32_t irqs, intenable, m; \ - usage_stop(); \ - __asm__ volatile("rsr.interrupt %0" : "=r"(irqs)); \ - __asm__ volatile("rsr.intenable %0" : "=r"(intenable)); \ - irqs &= intenable; \ - while ((m = _xtensa_handle_one_int##l(irqs))) { \ - irqs ^= m; \ - __asm__ volatile("wsr.intclear %0" : : "r"(m)); \ - } \ - return return_to(interrupted_stack); \ -} - -#if XCHAL_NMILEVEL >= 2 -DEF_INT_C_HANDLER(2) -#endif - -#if XCHAL_NMILEVEL >= 3 -DEF_INT_C_HANDLER(3) -#endif - -#if XCHAL_NMILEVEL >= 4 -DEF_INT_C_HANDLER(4) -#endif - -#if XCHAL_NMILEVEL >= 5 -DEF_INT_C_HANDLER(5) -#endif - -#if XCHAL_NMILEVEL >= 6 -DEF_INT_C_HANDLER(6) -#endif - -#if XCHAL_NMILEVEL >= 7 -DEF_INT_C_HANDLER(7) -#endif - -static inline DEF_INT_C_HANDLER(1) - -/* C handler for level 1 exceptions/interrupts. Hooked from the - * DEF_EXCINT 1 vector declaration in assembly code. This one looks - * different because exceptions and interrupts land at the same - * vector; other interrupt levels have their own vectors. - */ -void *xtensa_excint1_c(int *interrupted_stack) -{ - int cause, vaddr; - _xtensa_irq_bsa_t *bsa = (void *)*(int **)interrupted_stack; - bool is_fatal_error = false; - uint32_t ps; - void *pc; - - __asm__ volatile("rsr.exccause %0" : "=r"(cause)); - -#ifdef CONFIG_XTENSA_MMU - /* TLB miss exception comes through level 1 interrupt also. - * We need to preserve execution context after we have handled - * the TLB miss, so we cannot unconditionally unmask interrupts. - * For other cause, we can unmask interrupts so this would act - * the same as if there is no MMU. - */ - switch (cause) { - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ - - /* Do not unmask interrupt while handling TLB misses. */ - break; - default: - /* For others, we can unmask interrupts. */ - bsa->ps &= ~PS_INTLEVEL_MASK; - break; - } -#endif /* CONFIG_XTENSA_MMU */ - - switch (cause) { - case EXCCAUSE_LEVEL1_INTERRUPT: - return xtensa_int1_c(interrupted_stack); - case EXCCAUSE_SYSCALL: - /* Just report it to the console for now */ - LOG_ERR(" ** SYSCALL PS %p PC %p", - (void *)bsa->ps, (void *)bsa->pc); - z_xtensa_dump_stack(interrupted_stack); - - /* Xtensa exceptions don't automatically advance PC, - * have to skip the SYSCALL instruction manually or - * else it will just loop forever - */ - bsa->pc += 3; - break; -#ifdef CONFIG_XTENSA_MMU - case EXCCAUSE_ITLB_MISS: - /* Instruction TLB miss */ - __fallthrough; - case EXCCAUSE_DTLB_MISS: - /* Data TLB miss */ - - /** - * The way it works is, when we try to access an address - * that is not mapped, we will have a miss. The HW then - * will try to get the correspondent memory in the page - * table. As the page table is not mapped in memory we will - * have a second miss, which will trigger an exception. - * In the exception (here) what we do is to exploit this - * hardware capability just trying to load the page table - * (not mapped address), which will cause a miss, but then - * the hardware will automatically map it again from - * the page table. This time it will work since the page - * necessary to map the page table itself are wired map. - */ - __asm__ volatile("wsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsr.ptevaddr a0\n\t" - "l32i a0, a0, 0\n\t" - "rsr a0, " ZSR_EXTRA0_STR "\n\t" - "rsync" - : : : "a0", "memory"); - - /* Since we are dealing with TLB misses, we will probably not - * want to switch to another thread. - */ - return interrupted_stack; -#endif /* CONFIG_XTENSA_MMU */ - default: - ps = bsa->ps; - pc = (void *)bsa->pc; - - __asm__ volatile("rsr.excvaddr %0" : "=r"(vaddr)); - - /* Default for exception */ - int reason = K_ERR_CPU_EXCEPTION; - - /* We need to distinguish between an ill in xtensa_arch_except, - * e.g for k_panic, and any other ill. For exceptions caused by - * xtensa_arch_except calls, we also need to pass the reason_p - * to z_xtensa_fatal_error. Since the ARCH_EXCEPT frame is in the - * BSA, the first arg reason_p is stored at the A2 offset. - * We assign EXCCAUSE the unused, reserved code 63; this may be - * problematic if the app or new boards also decide to repurpose - * this code. - */ - if ((pc == (void *) &xtensa_arch_except_epc) && (cause == 0)) { - cause = 63; - __asm__ volatile("wsr.exccause %0" : : "r"(cause)); - reason = bsa->a2; - } - - LOG_ERR(" ** FATAL EXCEPTION"); - LOG_ERR(" ** CPU %d EXCCAUSE %d (%s)", - arch_curr_cpu()->id, cause, - z_xtensa_exccause(cause)); - LOG_ERR(" ** PC %p VADDR %p", - pc, (void *)vaddr); - LOG_ERR(" ** PS %p", (void *)bsa->ps); - LOG_ERR(" ** (INTLEVEL:%d EXCM: %d UM:%d RING:%d WOE:%d OWB:%d CALLINC:%d)", - get_bits(0, 4, ps), get_bits(4, 1, ps), - get_bits(5, 1, ps), get_bits(6, 2, ps), - get_bits(18, 1, ps), - get_bits(8, 4, ps), get_bits(16, 2, ps)); - - /* FIXME: legacy xtensa port reported "HW" exception - * for all unhandled exceptions, which seems incorrect - * as these are software errors. Should clean this - * up. - */ - z_xtensa_fatal_error(reason, - (void *)interrupted_stack); - break; - } - - - switch (cause) { - case EXCCAUSE_SYSCALL: - case EXCCAUSE_LEVEL1_INTERRUPT: - case EXCCAUSE_ALLOCA: - case EXCCAUSE_ITLB_MISS: - case EXCCAUSE_DTLB_MISS: - is_fatal_error = false; - break; - default: - is_fatal_error = true; - break; - } - - if (is_fatal_error) { - uint32_t ignore; - - /* We are going to manipulate _current_cpu->nested manually. - * Since the error is fatal, for recoverable errors, code - * execution must not return back to the current thread as - * it is being terminated (via above z_xtensa_fatal_error()). - * So we need to prevent more interrupts coming in which - * will affect the nested value as we are going outside of - * normal interrupt handling procedure. - * - * Setting nested to 1 has two effects: - * 1. Force return_to() to choose a new thread. - * Since the current thread is being terminated, it will - * not be chosen again. - * 2. When context switches to the newly chosen thread, - * nested must be zero for normal code execution, - * as that is not in interrupt context at all. - * After returning from this function, the rest of - * interrupt handling code will decrement nested, - * resulting it being zero before switching to another - * thread. - */ - __asm__ volatile("rsil %0, %1" - : "=r" (ignore) : "i"(XCHAL_NMILEVEL)); - - _current_cpu->nested = 1; - } - - return return_to(interrupted_stack); -} - -#if defined(CONFIG_GDBSTUB) -void *xtensa_debugint_c(int *interrupted_stack) -{ - extern void z_gdb_isr(z_arch_esf_t *esf); - - z_gdb_isr((void *)interrupted_stack); - - return return_to(interrupted_stack); -} -#endif - -int z_xtensa_irq_is_enabled(unsigned int irq) -{ - uint32_t ie; - - __asm__ volatile("rsr.intenable %0" : "=r"(ie)); - - return (ie & (1 << irq)) != 0U; -} - -#ifdef CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS -/* Some compilers might "optimize out" (i.e. remove) continuous NOPs. - * So force no optimization to avoid that. - */ -__no_optimization -void arch_spin_relax(void) -{ -#define NOP1(_, __) __asm__ volatile("nop.n;"); - LISTIFY(CONFIG_XTENSA_NUM_SPIN_RELAX_NOPS, NOP1, (;)) -#undef NOP1 -} -#endif /* CONFIG_XTENSA_MORE_SPIN_RELAX_NOPS */ diff --git a/arch/xtensa/core/xtensa_asm2_util.S b/arch/xtensa/core/xtensa_asm2_util.S new file mode 100644 index 00000000000..5dabb39ea3a --- /dev/null +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2017, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) +#include +#endif + +/* + * xtensa_spill_reg_windows + * + * Spill all register windows. Not a C function, enter this via CALL0 + * (so you have to save off A0, but no other registers need to be + * spilled). On return, all registers not part of the current + * function will be spilled to memory. The WINDOWSTART SR will have a + * single 1 bit corresponding to the current frame at WINDOWBASE. + */ +.global xtensa_spill_reg_windows +.align 4 +xtensa_spill_reg_windows: + SPILL_ALL_WINDOWS + ret + +/* + * xtensa_save_high_regs + * + * Call with CALL0, with A2/A3 available as scratch. Pushes the high + * A4-A15 GPRs to the stack if needed (i.e. if those registers are not + * part of wrapped-around frames higher up the call stack), returning + * to the caller with the stack pointer HAVING BEEN MODIFIED to + * contain them. + */ +.global xtensa_save_high_regs +.align 4 +xtensa_save_high_regs: + /* Generate a rotated (modulo NREGS/4 bits!) WINDOWSTART in A2 + * by duplicating the bits twice and shifting down by WINDOWBASE + * bits. Now the LSB is the register quad at WINDOWBASE. + */ + rsr a2, WINDOWSTART + slli a3, a2, (XCHAL_NUM_AREGS / 4) + or a2, a2, a3 + rsr a3, WINDOWBASE + ssr a3 + srl a2, a2 + + mov a3, a1 /* Stash our original stack pointer */ + + /* For the next three bits in WINDOWSTART (which correspond to + * the A4-A7, A8-A11 and A12-A15 quads), if we find a one, + * that means that the quad is owned by a wrapped-around call + * in the registers, so we don't need to spill it or any + * further registers from the GPRs and can skip to the end. + */ + bbsi a2, 1, _high_gpr_spill_done + addi a1, a1, -16 + s32i a4, a1, 0 + s32i a5, a1, 4 + s32i a6, a1, 8 + s32i a7, a1, 12 + + bbsi a2, 2, _high_gpr_spill_done + addi a1, a1, -16 + s32i a8, a1, 0 + s32i a9, a1, 4 + s32i a10, a1, 8 + s32i a11, a1, 12 + + bbsi a2, 3, _high_gpr_spill_done + addi a1, a1, -16 + s32i a12, a1, 0 + s32i a13, a1, 4 + s32i a14, a1, 8 + s32i a15, a1, 12 + +_high_gpr_spill_done: + /* Push the original stack pointer so we know at restore + * time how many registers were spilled, then return, leaving the + * modified SP in A1. + */ + addi a1, a1, -4 + s32i a3, a1, 0 + + ret + +/* + * xtensa_restore_high_regs + * + * Does the inverse of xtensa_save_high_regs, taking a stack pointer + * in A1 that resulted and restoring the A4-A15 state (and the stack + * pointer) to the state they had at the earlier call. Call with + * CALL0, leaving A2/A3 available as scratch. + */ +.global xtensa_restore_high_regs +.align 4 +xtensa_restore_high_regs: + /* pop our "original" stack pointer into a2, stash in a3 also */ + l32i a2, a1, 0 + addi a1, a1, 4 + mov a3, a2 + + beq a1, a2, _high_restore_done + addi a2, a2, -16 + l32i a4, a2, 0 + l32i a5, a2, 4 + l32i a6, a2, 8 + l32i a7, a2, 12 + + beq a1, a2, _high_restore_done + addi a2, a2, -16 + l32i a8, a2, 0 + l32i a9, a2, 4 + l32i a10, a2, 8 + l32i a11, a2, 12 + + beq a1, a2, _high_restore_done + addi a2, a2, -16 + l32i a12, a2, 0 + l32i a13, a2, 4 + l32i a14, a2, 8 + l32i a15, a2, 12 + +_high_restore_done: + mov a1, a3 /* Original stack */ + ret + +/* + * _restore_context + * + * Arrive here via a jump. Enters into the restored context and does + * not return. A1 should have a context pointer in it as received + * from switch or an interrupt exit. Interrupts must be disabled, + * and register windows should have been spilled. + * + * Note that exit from the restore is done with the RFI instruction, + * using the EPCn/EPSn registers. Those will have been saved already + * by any interrupt entry so they are save to use. Note that EPC1 and + * RFE are NOT usable (they can't preserve PS). Per the ISA spec, all + * RFI levels do the same thing and differ only in the special + * registers used to hold PC/PS, but Qemu has been observed to behave + * strangely when RFI doesn't "return" to a INTLEVEL strictly lower + * than it started from. So we leverage the zsr.h framework to pick + * the highest level available for our specific platform. + */ +.global _restore_context +_restore_context: + call0 xtensa_restore_high_regs + + l32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET + wsr a0, ZSR_EPC + l32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET + wsr a0, ZSR_EPS + +#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) + FPU_REG_RESTORE +#endif + + l32i a0, a1, ___xtensa_irq_bsa_t_sar_OFFSET + wsr a0, SAR +#if XCHAL_HAVE_LOOPS + l32i a0, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET + wsr a0, LBEG + l32i a0, a1, ___xtensa_irq_bsa_t_lend_OFFSET + wsr a0, LEND + l32i a0, a1, ___xtensa_irq_bsa_t_lcount_OFFSET + wsr a0, LCOUNT +#endif +#if XCHAL_HAVE_S32C1I + l32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET + wsr a0, SCOMPARE1 +#endif +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) + l32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET + wur a0, THREADPTR +#endif + rsync + + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + l32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + l32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF + + rfi ZSR_RFI_LEVEL + +/* + * void xtensa_arch_except(int reason_p); + * + * Implements hardware exception for Xtensa ARCH_EXCEPT to save + * interrupted stack frame and reason_p for use in exception handler + * and coredump + */ +.global xtensa_arch_except +.global xtensa_arch_except_epc +.align 4 +xtensa_arch_except: + entry a1, 16 +xtensa_arch_except_epc: + ill + retw + +/* + * void xtensa_arch_kernel_oops(int reason_p, void *ssf); + * + * Simply to raise hardware exception for Kernel OOPS. + */ +.global xtensa_arch_kernel_oops +.global xtensa_arch_kernel_oops_epc +.align 4 +xtensa_arch_kernel_oops: + entry a1, 16 +xtensa_arch_kernel_oops_epc: + ill + retw + +/* + * void xtensa_switch(void *new, void **old_return); + * + * Context switches into the previously-saved "new" handle, placing + * the saved "old" handle into the address provided by old_return. + */ +.global xtensa_switch +.align 4 +xtensa_switch: + entry a1, 16 + SPILL_ALL_WINDOWS + addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF + + /* Stash our A0/2/3 and the shift/loop registers into the base + * save area so they get restored as they are now. A2/A3 + * don't actually get used post-restore, but they need to be + * stashed across the xtensa_save_high_regs call and this is a + * convenient place. + */ + s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + s32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + ODD_REG_SAVE + + /* Stash our PS register contents and a "restore" PC. */ + rsr a0, PS + s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET + movi a0, _switch_restore_pc + s32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET + + /* Now the high registers */ + call0 xtensa_save_high_regs + +#ifdef CONFIG_KERNEL_COHERENCE + /* Flush the stack. The top of stack was stored for us by + * arch_cohere_stacks(). It can be NULL for a dummy thread. + */ + rsr a0, ZSR_FLUSH + beqz a0, noflush + mov a3, a1 +flushloop: + dhwb a3, 0 + addi a3, a3, XCHAL_DCACHE_LINESIZE + blt a3, a0, flushloop +noflush: +#endif + + /* Restore the A3 argument we spilled earlier (via the base + * save pointer pushed at the bottom of the stack) and set the + * stack to the "new" context out of the A2 spill slot. + */ + l32i a2, a1, 0 + l32i a3, a2, ___xtensa_irq_bsa_t_a3_OFFSET + s32i a1, a3, 0 + +#ifdef CONFIG_USERSPACE + /* Switch page tables */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + call4 xtensa_swap_update_page_tables + + l32i a2, a3, 0 + l32i a2, a2, 0 +#endif + + /* Switch stack pointer and restore. The jump to + * _restore_context does not return as such, but we arrange + * for the restored "next" address to be immediately after for + * sanity. + */ + l32i a1, a2, ___xtensa_irq_bsa_t_a2_OFFSET + +#ifdef CONFIG_INSTRUMENT_THREAD_SWITCHING + call4 z_thread_mark_switched_in +#endif + j _restore_context +_switch_restore_pc: + retw + +/* Define our entry handler to load the struct kernel_t from the + * MISC0 special register, and to find the nest and irq_stack values + * at the precomputed offsets. + */ +.align 4 +_handle_excint: + EXCINT_HANDLER ___cpu_t_nested_OFFSET, ___cpu_t_irq_stack_OFFSET + +/* Define the actual vectors for the hardware-defined levels with + * DEF_EXCINT. These load a C handler address and jump to our handler + * above. + */ + +DEF_EXCINT 1, _handle_excint, xtensa_excint1_c + +#if XCHAL_NMILEVEL >= 2 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 2)) +DEF_EXCINT 2, _handle_excint, xtensa_int2_c +#endif +#endif + +#if XCHAL_NMILEVEL >= 3 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 3)) +DEF_EXCINT 3, _handle_excint, xtensa_int3_c +#endif +#endif + +#if XCHAL_NMILEVEL >= 4 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 4)) +DEF_EXCINT 4, _handle_excint, xtensa_int4_c +#endif +#endif + +#if XCHAL_NMILEVEL >= 5 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 5)) +DEF_EXCINT 5, _handle_excint, xtensa_int5_c +#endif +#endif + +#if XCHAL_NMILEVEL >= 6 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 6)) +DEF_EXCINT 6, _handle_excint, xtensa_int6_c +#endif +#endif + +#if XCHAL_NMILEVEL >= 7 +#if !(defined(CONFIG_GDBSTUB) && (XCHAL_DEBUGLEVEL == 7)) +DEF_EXCINT 7, _handle_excint, xtensa_int7_c +#endif +#endif + +#if defined(CONFIG_GDBSTUB) +DEF_EXCINT XCHAL_DEBUGLEVEL, _handle_excint, xtensa_debugint_c +#endif + +/* The user exception vector is defined here, as we need to handle + * MOVSP exceptions in assembly (the result has to be to unspill the + * caller function of the code that took the exception, and that can't + * be done in C). A prototype exists which mucks with the stack frame + * from the C handler instead, but that would add a LARGE overhead to + * some alloca() calls (those whent he caller has been spilled) just + * to save these five cycles during other exceptions and L1 + * interrupts. Maybe revisit at some point, with better benchmarking. + * Note that _xt_alloca_exc is Xtensa-authored code which expects A0 + * to have been saved to EXCSAVE1, we've modified it to use the zsr.h + * API to get assigned a scratch register. + */ +.pushsection .UserExceptionVector.text, "ax" +.global _Level1RealVector +_Level1RealVector: + wsr a0, ZSR_A0SAVE + rsync + rsr.exccause a0 +#ifdef CONFIG_XTENSA_MMU + beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_user +#ifdef CONFIG_USERSPACE + beqi a0, EXCCAUSE_SYSCALL, _syscall +#endif /* CONFIG_USERSPACE */ + addi a0, a0, -EXCCAUSE_DTLB_MISS + beqz a0, _handle_tlb_miss_user + rsr.exccause a0 +#endif /* CONFIG_XTENSA_MMU */ + bnei a0, EXCCAUSE_ALLOCA, _not_alloca + + j _xt_alloca_exc +_not_alloca: + rsr a0, ZSR_A0SAVE + j _Level1Vector +#ifdef CONFIG_XTENSA_MMU +_handle_tlb_miss_user: + /** + * Handle TLB miss by loading the PTE page: + * The way it works is, when we try to access an address that is not + * mapped, we will have a miss. The HW then will try to get the + * correspondent memory in the page table. As the page table is not + * mapped in memory we will have a second miss, which will trigger + * an exception. In the exception (here) what we do is to exploit + * this hardware capability just trying to load the page table + * (not mapped address), which will cause a miss, but then the hardware + * will automatically map it again from the page table. This time + * it will work since the page necessary to map the page table itself + * are wired map. + */ + rsr.ptevaddr a0 + l32i a0, a0, 0 + rsr a0, ZSR_A0SAVE + rfe +#ifdef CONFIG_USERSPACE +_syscall: + rsr a0, ZSR_A0SAVE + j xtensa_do_syscall +#endif /* CONFIG_USERSPACE */ +#endif /* CONFIG_XTENSA_MMU */ +.popsection + +/* In theory you can have levels up to 15, but known hardware only uses 7. */ +#if XCHAL_NMILEVEL > 7 +#error More interrupts than expected. +#endif + +/* We don't actually use "kernel mode" currently. Populate the vector + * out of simple caution in case app code clears the UM bit by mistake. + */ +.pushsection .KernelExceptionVector.text, "ax" +.global _KernelExceptionVector +_KernelExceptionVector: +#ifdef CONFIG_XTENSA_MMU + wsr a0, ZSR_A0SAVE + rsr.exccause a0 + beqi a0, EXCCAUSE_ITLB_MISS, _handle_tlb_miss_kernel + addi a0, a0, -EXCCAUSE_DTLB_MISS + beqz a0, _handle_tlb_miss_kernel + rsr a0, ZSR_A0SAVE +#endif + j _Level1Vector +#ifdef CONFIG_XTENSA_MMU +_handle_tlb_miss_kernel: + /* The TLB miss handling is used only during xtensa_mmu_init() + * where vecbase is at a different address, as the offset used + * in the jump ('j') instruction will not jump to correct + * address (... remember the vecbase is moved). + * So we handle TLB misses in a very simple way here until + * we move back to using UserExceptionVector above. + */ + rsr.ptevaddr a0 + l32i a0, a0, 0 + rsr a0, ZSR_A0SAVE + rfe +#endif +.popsection + +#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR +.pushsection .DoubleExceptionVector.text, "ax" +.global _DoubleExceptionVector +_DoubleExceptionVector: +#ifdef CONFIG_XTENSA_MMU + wsr a0, ZSR_DBLEXC + rsync + + rsr.exccause a0 + addi a0, a0, -EXCCAUSE_DTLB_MISS + beqz a0, _handle_tlb_miss_dblexc + + rsr a0, ZSR_DBLEXC + + j _Level1Vector +#else + +#if defined(CONFIG_SIMULATOR_XTENSA) || defined(XT_SIMULATOR) +1: +/* Tell simulator to stop executing here, instead of trying to do + * an infinite loop (see below). Greatly help with using tracing in + * simulator so that traces will not have infinite iterations of + * jumps. + */ + movi a3, 1 + movi a2, SYS_exit + simcall +#elif XCHAL_HAVE_DEBUG +/* Signals an unhandled double exception */ +1: break 1, 4 +#else +1: +#endif + j 1b +#endif /* CONFIG_XTENSA_MMU */ + +#ifdef CONFIG_XTENSA_MMU +_handle_tlb_miss_dblexc: + /* Handle all data TLB misses here. + * These data TLB misses are mostly caused by preloading + * page table entries in the level 1 exception handler. + * Failure to load the PTE will result in another exception + * with different failure (exccause), which can be handled + * when the CPU re-enters the double exception handler. + */ + rsr.ptevaddr a0 + l32i a0, a0, 0 + + rsr a0, ZSR_DBLEXC + rfde +#endif +.popsection + +#endif diff --git a/arch/xtensa/core/xtensa_backtrace.c b/arch/xtensa/core/xtensa_backtrace.c index e0abe09049b..5871a10c48f 100644 --- a/arch/xtensa/core/xtensa_backtrace.c +++ b/arch/xtensa/core/xtensa_backtrace.c @@ -16,7 +16,7 @@ #endif static int mask, cause; -static inline uint32_t z_xtensa_cpu_process_stack_pc(uint32_t pc) +static inline uint32_t xtensa_cpu_process_stack_pc(uint32_t pc) { if (pc & 0x80000000) { /* Top two bits of a0 (return address) specify window increment. @@ -34,7 +34,7 @@ static inline uint32_t z_xtensa_cpu_process_stack_pc(uint32_t pc) return pc - 3; } -static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) +static inline bool xtensa_stack_ptr_is_sane(uint32_t sp) { #if defined(CONFIG_SOC_SERIES_ESP32) return esp_stack_ptr_is_sane(sp); @@ -43,11 +43,11 @@ static inline bool z_xtensa_stack_ptr_is_sane(uint32_t sp) #elif defined(CONFIG_SOC_XTENSA_DC233C) return xtensa_dc233c_stack_ptr_is_sane(sp); #else -#warning "z_xtensa_stack_ptr_is_sane is not defined for this platform" +#warning "xtensa_stack_ptr_is_sane is not defined for this platform" #endif } -static inline bool z_xtensa_ptr_executable(const void *p) +static inline bool xtensa_ptr_executable(const void *p) { #if defined(CONFIG_SOC_SERIES_ESP32) return esp_ptr_executable(p); @@ -56,11 +56,11 @@ static inline bool z_xtensa_ptr_executable(const void *p) #elif defined(CONFIG_SOC_XTENSA_DC233C) return xtensa_dc233c_ptr_executable(p); #else -#warning "z_xtensa_ptr_executable is not defined for this platform" +#warning "xtensa_ptr_executable is not defined for this platform" #endif } -bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) +bool xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t *frame) { /* Use frame(i-1)'s BS area located below frame(i)'s * sp to get frame(i-1)'s sp and frame(i-2)'s pc @@ -79,12 +79,12 @@ bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) /* Return true if both sp and pc of frame(i-1) are sane, * false otherwise */ - return (z_xtensa_stack_ptr_is_sane(frame->sp) && - z_xtensa_ptr_executable((void *) - z_xtensa_cpu_process_stack_pc(frame->pc))); + return (xtensa_stack_ptr_is_sane(frame->sp) && + xtensa_ptr_executable((void *) + xtensa_cpu_process_stack_pc(frame->pc))); } -int z_xtensa_backtrace_print(int depth, int *interrupted_stack) +int xtensa_backtrace_print(int depth, int *interrupted_stack) { /* Check arguments */ if (depth <= 0) { @@ -92,9 +92,9 @@ int z_xtensa_backtrace_print(int depth, int *interrupted_stack) } /* Initialize stk_frame with first frame of stack */ - struct z_xtensa_backtrace_frame_t stk_frame; + struct xtensa_backtrace_frame_t stk_frame; - z_xtensa_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), + xtensa_backtrace_get_start(&(stk_frame.pc), &(stk_frame.sp), &(stk_frame.next_pc), interrupted_stack); __asm__ volatile("l32i a4, a3, 0"); __asm__ volatile("l32i a4, a4, 4"); @@ -104,22 +104,22 @@ int z_xtensa_backtrace_print(int depth, int *interrupted_stack) } printk("\r\n\r\nBacktrace:"); printk("0x%08x:0x%08x ", - z_xtensa_cpu_process_stack_pc(stk_frame.pc), + xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); /* Check if first frame is valid */ - bool corrupted = !(z_xtensa_stack_ptr_is_sane(stk_frame.sp) && - (z_xtensa_ptr_executable((void *) - z_xtensa_cpu_process_stack_pc(stk_frame.pc)) || + bool corrupted = !(xtensa_stack_ptr_is_sane(stk_frame.sp) && + (xtensa_ptr_executable((void *) + xtensa_cpu_process_stack_pc(stk_frame.pc)) || /* Ignore the first corrupted PC in case of InstrFetchProhibited */ cause == EXCCAUSE_INSTR_PROHIBITED)); while (depth-- > 0 && stk_frame.next_pc != 0 && !corrupted) { /* Get previous stack frame */ - if (!z_xtensa_backtrace_get_next_frame(&stk_frame)) { + if (!xtensa_backtrace_get_next_frame(&stk_frame)) { corrupted = true; } - printk("0x%08x:0x%08x ", z_xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + printk("0x%08x:0x%08x ", xtensa_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); } /* Print backtrace termination marker */ diff --git a/arch/xtensa/core/xtensa_mmu.c b/arch/xtensa/core/xtensa_mmu.c deleted file mode 100644 index e50c51a3848..00000000000 --- a/arch/xtensa/core/xtensa_mmu.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Fixed data TLB way to map the page table */ -#define MMU_PTE_WAY 7 - -/* Fixed data TLB way to map VECBASE */ -#define MMU_VECBASE_WAY 8 - -/* Level 1 contains page table entries - * necessary to map the page table itself. - */ -#define XTENSA_L1_PAGE_TABLE_ENTRIES 1024U - -/* Level 2 contains page table entries - * necessary to map the page table itself. - */ -#define XTENSA_L2_PAGE_TABLE_ENTRIES 1024U - -LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); - -BUILD_ASSERT(CONFIG_MMU_PAGE_SIZE == 0x1000, - "MMU_PAGE_SIZE value is invalid, only 4 kB pages are supported\n"); - -/* - * Level 1 page table has to be 4Kb to fit into one of the wired entries. - * All entries are initialized as INVALID, so an attempt to read an unmapped - * area will cause a double exception. - */ -uint32_t l1_page_table[XTENSA_L1_PAGE_TABLE_ENTRIES] __aligned(KB(4)); - -/* - * Each table in the level 2 maps a 4Mb memory range. It consists of 1024 entries each one - * covering a 4Kb page. - */ -static uint32_t l2_page_tables[CONFIG_XTENSA_MMU_NUM_L2_TABLES][XTENSA_L2_PAGE_TABLE_ENTRIES] - __aligned(KB(4)); - -/* - * This additional variable tracks which l2 tables are in use. This is kept separated from - * the tables to keep alignment easier. - */ -static ATOMIC_DEFINE(l2_page_tables_track, CONFIG_XTENSA_MMU_NUM_L2_TABLES); - -extern char _heap_end[]; -extern char _heap_start[]; -extern char __data_start[]; -extern char __data_end[]; -extern char _bss_start[]; -extern char _bss_end[]; - -/* - * Static definition of all code & data memory regions of the - * current Zephyr image. This information must be available & - * processed upon MMU initialization. - */ - -static const struct xtensa_mmu_range mmu_zephyr_ranges[] = { - /* - * Mark the zephyr execution regions (data, bss, noinit, etc.) - * cacheable, read / write and non-executable - */ - { - /* This includes .data, .bss and various kobject sections. */ - .start = (uint32_t)_image_ram_start, - .end = (uint32_t)_image_ram_end, -#ifdef CONFIG_XTENSA_RPO_CACHE - .attrs = Z_XTENSA_MMU_W, -#else - .attrs = Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, -#endif - .name = "data", - }, - /* System heap memory */ - { - .start = (uint32_t)_heap_start, - .end = (uint32_t)_heap_end, -#ifdef CONFIG_XTENSA_RPO_CACHE - .attrs = Z_XTENSA_MMU_W, -#else - .attrs = Z_XTENSA_MMU_W | Z_XTENSA_MMU_CACHED_WB, -#endif - .name = "heap", - }, - /* Mark text segment cacheable, read only and executable */ - { - .start = (uint32_t)__text_region_start, - .end = (uint32_t)__text_region_end, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, - .name = "text", - }, - /* Mark rodata segment cacheable, read only and non-executable */ - { - .start = (uint32_t)__rodata_region_start, - .end = (uint32_t)__rodata_region_end, - .attrs = Z_XTENSA_MMU_CACHED_WB, - .name = "rodata", - }, -}; - -static inline uint32_t *alloc_l2_table(void) -{ - uint16_t idx; - - for (idx = 0; idx < CONFIG_XTENSA_MMU_NUM_L2_TABLES; idx++) { - if (!atomic_test_and_set_bit(l2_page_tables_track, idx)) { - return (uint32_t *)&l2_page_tables[idx]; - } - } - - return NULL; -} - -static void map_memory_range(const uint32_t start, const uint32_t end, - const uint32_t attrs) -{ - uint32_t page, *table; - - for (page = start; page < end; page += CONFIG_MMU_PAGE_SIZE) { - uint32_t pte = Z_XTENSA_PTE(page, Z_XTENSA_KERNEL_RING, attrs); - uint32_t l2_pos = Z_XTENSA_L2_POS(page); - uint32_t l1_pos = page >> 22; - - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { - table = alloc_l2_table(); - - __ASSERT(table != NULL, "There is no l2 page table available to " - "map 0x%08x\n", page); - - l1_page_table[l1_pos] = - Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); - } - - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = pte; - } -} - -static void map_memory(const uint32_t start, const uint32_t end, - const uint32_t attrs) -{ - map_memory_range(start, end, attrs); - -#ifdef CONFIG_XTENSA_MMU_DOUBLE_MAP - if (arch_xtensa_is_ptr_uncached((void *)start)) { - map_memory_range(POINTER_TO_UINT(z_soc_cached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_cached_ptr((void *)end)), - attrs | Z_XTENSA_MMU_CACHED_WB); - } else if (arch_xtensa_is_ptr_cached((void *)start)) { - map_memory_range(POINTER_TO_UINT(z_soc_uncached_ptr((void *)start)), - POINTER_TO_UINT(z_soc_uncached_ptr((void *)end)), attrs); - } -#endif -} - -static void xtensa_init_page_tables(void) -{ - volatile uint8_t entry; - uint32_t page; - - for (page = 0; page < XTENSA_L1_PAGE_TABLE_ENTRIES; page++) { - l1_page_table[page] = Z_XTENSA_MMU_ILLEGAL; - } - - for (entry = 0; entry < ARRAY_SIZE(mmu_zephyr_ranges); entry++) { - const struct xtensa_mmu_range *range = &mmu_zephyr_ranges[entry]; - - map_memory(range->start, range->end, range->attrs); - } - -/** - * GCC complains about usage of the SoC MMU range ARRAY_SIZE - * (xtensa_soc_mmu_ranges) as the default weak declaration is - * an empty array, and any access to its element is considered - * out of bound access. However, we have a number of element - * variable to guard against this (... if done correctly). - * Besides, this will almost be overridden by the SoC layer. - * So tell GCC to ignore this. - */ -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" -#endif - for (entry = 0; entry < xtensa_soc_mmu_ranges_num; entry++) { - const struct xtensa_mmu_range *range = &xtensa_soc_mmu_ranges[entry]; - - map_memory(range->start, range->end, range->attrs); - } -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - sys_cache_data_flush_all(); -} - -__weak void arch_xtensa_mmu_post_init(bool is_core0) -{ - ARG_UNUSED(is_core0); -} - -static void xtensa_mmu_init(bool is_core0) -{ - volatile uint8_t entry; - uint32_t ps, vecbase; - - if (is_core0) { - /* This is normally done via arch_kernel_init() inside z_cstart(). - * However, before that is called, we go through the sys_init of - * INIT_LEVEL_EARLY, which is going to result in TLB misses. - * So setup whatever necessary so the exception handler can work - * properly. - */ - z_xtensa_kernel_init(); - xtensa_init_page_tables(); - } - - /* Set the page table location in the virtual address */ - xtensa_ptevaddr_set((void *)Z_XTENSA_PTEVADDR); - - /* Next step is to invalidate the tlb entry that contains the top level - * page table. This way we don't cause a multi hit exception. - */ - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, 6)); - - /* We are not using a flat table page, so we need to map - * only the top level page table (which maps the page table itself). - * - * Lets use one of the wired entry, so we never have tlb miss for - * the top level table. - */ - xtensa_dtlb_entry_write(Z_XTENSA_PTE((uint32_t)l1_page_table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY(Z_XTENSA_PAGE_TABLE_VADDR, MMU_PTE_WAY)); - - /* Before invalidate the text region in the TLB entry 6, we need to - * map the exception vector into one of the wired entries to avoid - * a page miss for the exception. - */ - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - xtensa_dtlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY( - Z_XTENSA_PTEVADDR + MB(4), 3)); - - /* Temporarily uses KernelExceptionVector for level 1 interrupts - * handling. This is due to UserExceptionVector needing to jump to - * _Level1Vector. The jump ('j') instruction offset is incorrect - * when we move VECBASE below. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps &= ~PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(Z_XTENSA_PTEVADDR + MB(4))); - - - /* Finally, lets invalidate all entries in way 6 as the page tables - * should have already mapped the regions we care about for boot. - */ - for (entry = 0; entry < BIT(XCHAL_ITLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("iitlb %[idx]\n\t" - "isync" - :: [idx] "a"((entry << 29) | 6)); - } - - for (entry = 0; entry < BIT(XCHAL_DTLB_ARF_ENTRIES_LOG2); entry++) { - __asm__ volatile("idtlb %[idx]\n\t" - "dsync" - :: [idx] "a"((entry << 29) | 6)); - } - - /* Map VECBASE to a fixed data TLB */ - xtensa_dtlb_entry_write( - Z_XTENSA_PTE((uint32_t)vecbase, - Z_XTENSA_KERNEL_RING, Z_XTENSA_MMU_CACHED_WB), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, MMU_VECBASE_WAY)); - - /* - * Pre-load TLB for vecbase so exception handling won't result - * in TLB miss during boot, and that we can handle single - * TLB misses. - */ - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_AUTOFILL_TLB_ENTRY(vecbase)); - - /* To finish, just restore vecbase and invalidate TLB entries - * used to map the relocated vecbase. - */ - __asm__ volatile("wsr.vecbase %0; rsync\n\t" - :: "a"(vecbase)); - - /* Restore PS_UM so that level 1 interrupt handling will go to - * UserExceptionVector. - */ - __asm__ volatile("rsr.ps %0" : "=r"(ps)); - ps |= PS_UM; - __asm__ volatile("wsr.ps %0; rsync" :: "a"(ps)); - - xtensa_dtlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - xtensa_itlb_entry_invalidate_sync(Z_XTENSA_TLB_ENTRY(Z_XTENSA_PTEVADDR + MB(4), 3)); - - arch_xtensa_mmu_post_init(is_core0); -} - -void z_xtensa_mmu_init(void) -{ - xtensa_mmu_init(true); -} - -void z_xtensa_mmu_smp_init(void) -{ - xtensa_mmu_init(false); -} - -#ifdef CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES -/* Zephyr's linker scripts for Xtensa usually puts - * something before z_mapped_start (aka .text), - * i.e. vecbase, so that we need to reserve those - * space or else k_mem_map() would be mapping those, - * resulting in faults. - */ -__weak void arch_reserved_pages_update(void) -{ - uintptr_t page; - struct z_page_frame *pf; - int idx; - - for (page = CONFIG_SRAM_BASE_ADDRESS, idx = 0; - page < (uintptr_t)z_mapped_start; - page += CONFIG_MMU_PAGE_SIZE, idx++) { - pf = &z_page_frames[idx]; - - pf->flags |= Z_PAGE_FRAME_RESERVED; - } -} -#endif /* CONFIG_ARCH_HAS_RESERVED_PAGE_FRAMES */ - -static bool l2_page_table_map(void *vaddr, uintptr_t phys, uint32_t flags) -{ - uint32_t l1_pos = (uint32_t)vaddr >> 22; - uint32_t pte = Z_XTENSA_PTE(phys, Z_XTENSA_KERNEL_RING, flags); - uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); - uint32_t *table; - - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { - table = alloc_l2_table(); - - if (table == NULL) { - return false; - } - - l1_page_table[l1_pos] = Z_XTENSA_PTE((uint32_t)table, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_CACHED_WT); - } - - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = pte; - - if ((flags & Z_XTENSA_MMU_X) == Z_XTENSA_MMU_X) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); - return true; -} - -void arch_mem_map(void *virt, uintptr_t phys, size_t size, uint32_t flags) -{ - uint32_t va = (uint32_t)virt; - uint32_t pa = (uint32_t)phys; - uint32_t rem_size = (uint32_t)size; - uint32_t xtensa_flags = 0; - int key; - - if (size == 0) { - LOG_ERR("Cannot map physical memory at 0x%08X: invalid " - "zero size", (uint32_t)phys); - k_panic(); - } - - switch (flags & K_MEM_CACHE_MASK) { - - case K_MEM_CACHE_WB: - xtensa_flags |= Z_XTENSA_MMU_CACHED_WB; - break; - case K_MEM_CACHE_WT: - xtensa_flags |= Z_XTENSA_MMU_CACHED_WT; - break; - case K_MEM_CACHE_NONE: - __fallthrough; - default: - break; - } - - if ((flags & K_MEM_PERM_RW) == K_MEM_PERM_RW) { - xtensa_flags |= Z_XTENSA_MMU_W; - } - if ((flags & K_MEM_PERM_EXEC) == K_MEM_PERM_EXEC) { - xtensa_flags |= Z_XTENSA_MMU_X; - } - - key = arch_irq_lock(); - - while (rem_size > 0) { - bool ret = l2_page_table_map((void *)va, pa, xtensa_flags); - - ARG_UNUSED(ret); - __ASSERT(ret, "Virtual address (%u) already mapped", (uint32_t)virt); - rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; - va += KB(4); - pa += KB(4); - } - - arch_irq_unlock(key); -} - -static void l2_page_table_unmap(void *vaddr) -{ - uint32_t l1_pos = (uint32_t)vaddr >> 22; - uint32_t l2_pos = Z_XTENSA_L2_POS((uint32_t)vaddr); - uint32_t *table; - uint32_t table_pos; - bool exec; - - if (l1_page_table[l1_pos] == Z_XTENSA_MMU_ILLEGAL) { - return; - } - - exec = l1_page_table[l1_pos] & Z_XTENSA_MMU_X; - - table = (uint32_t *)(l1_page_table[l1_pos] & Z_XTENSA_PTE_PPN_MASK); - table[l2_pos] = Z_XTENSA_MMU_ILLEGAL; - - for (l2_pos = 0; l2_pos < XTENSA_L2_PAGE_TABLE_ENTRIES; l2_pos++) { - if (table[l2_pos] != Z_XTENSA_MMU_ILLEGAL) { - goto end; - } - } - - l1_page_table[l1_pos] = Z_XTENSA_MMU_ILLEGAL; - table_pos = (table - (uint32_t *)l2_page_tables) / (XTENSA_L2_PAGE_TABLE_ENTRIES); - atomic_clear_bit(l2_page_tables_track, table_pos); - - /* Need to invalidate L2 page table as it is no longer valid. */ - xtensa_dtlb_vaddr_invalidate((void *)table); - -end: - if (exec) { - xtensa_itlb_vaddr_invalidate(vaddr); - } - xtensa_dtlb_vaddr_invalidate(vaddr); -} - -void arch_mem_unmap(void *addr, size_t size) -{ - uint32_t va = (uint32_t)addr; - uint32_t rem_size = (uint32_t)size; - int key; - - if (addr == NULL) { - LOG_ERR("Cannot unmap NULL pointer"); - return; - } - - if (size == 0) { - LOG_ERR("Cannot unmap virtual memory with zero size"); - return; - } - - key = arch_irq_lock(); - - while (rem_size > 0) { - l2_page_table_unmap((void *)va); - rem_size -= (rem_size >= KB(4)) ? KB(4) : rem_size; - va += KB(4); - } - - arch_irq_unlock(key); -} diff --git a/arch/xtensa/include/kernel_arch_func.h b/arch/xtensa/include/kernel_arch_func.h index 6427b306e62..f303a8a0c3a 100644 --- a/arch/xtensa/include/kernel_arch_func.h +++ b/arch/xtensa/include/kernel_arch_func.h @@ -20,12 +20,10 @@ extern "C" { #endif -extern void z_xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); - K_KERNEL_STACK_ARRAY_DECLARE(z_interrupt_stacks, CONFIG_MP_MAX_NUM_CPUS, CONFIG_ISR_STACK_SIZE); -static ALWAYS_INLINE void z_xtensa_kernel_init(void) +static ALWAYS_INLINE void arch_kernel_init(void) { _cpu_t *cpu0 = &_kernel.cpus[0]; @@ -51,20 +49,28 @@ static ALWAYS_INLINE void z_xtensa_kernel_init(void) * win. */ XTENSA_WSR(ZSR_CPU_STR, cpu0); -} -static ALWAYS_INLINE void arch_kernel_init(void) -{ -#ifndef CONFIG_XTENSA_MMU - /* This is called in z_xtensa_mmu_init() before z_cstart() - * so we do not need to call it again. +#ifdef CONFIG_INIT_STACKS + char *stack_start = Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]); + size_t stack_sz = K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0]); + char *stack_end = stack_start + stack_sz; + + uint32_t sp; + + __asm__ volatile("mov %0, sp" : "=a"(sp)); + + /* Only clear the interrupt stack if the current stack pointer + * is not within the interrupt stack. Or else we would be + * wiping the in-use stack. */ - z_xtensa_kernel_init(); + if (((uintptr_t)sp < (uintptr_t)stack_start) || + ((uintptr_t)sp >= (uintptr_t)stack_end)) { + memset(stack_start, 0xAA, stack_sz); + } #endif -#ifdef CONFIG_INIT_STACKS - memset(Z_KERNEL_STACK_BUFFER(z_interrupt_stacks[0]), 0xAA, - K_KERNEL_STACK_SIZEOF(z_interrupt_stacks[0])); +#ifdef CONFIG_XTENSA_MMU + xtensa_mmu_init(); #endif } diff --git a/arch/xtensa/include/offsets_short_arch.h b/arch/xtensa/include/offsets_short_arch.h index 34a4a5842cf..f19750dc0ac 100644 --- a/arch/xtensa/include/offsets_short_arch.h +++ b/arch/xtensa/include/offsets_short_arch.h @@ -2,4 +2,18 @@ * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ -/* Empty File */ +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ + +#define _thread_offset_to_flags \ + (___thread_t_arch_OFFSET + ___thread_arch_t_flags_OFFSET) + +#ifdef CONFIG_USERSPACE +#define _thread_offset_to_psp \ + (___thread_t_arch_OFFSET + ___thread_arch_t_psp_OFFSET) + +#define _thread_offset_to_ptables \ + (___thread_t_arch_OFFSET + ___thread_arch_t_ptables_OFFSET) +#endif /* CONFIG_USERSPACE */ + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ diff --git a/arch/xtensa/include/xtensa-asm2-s.h b/arch/xtensa/include/xtensa-asm2-s.h deleted file mode 100644 index f691dbc6cad..00000000000 --- a/arch/xtensa/include/xtensa-asm2-s.h +++ /dev/null @@ -1,655 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H -#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H - -#include -#include "xtensa-asm2-context.h" - -#include - -/* Assembler header! This file contains macros designed to be included - * only by the assembler. - */ - -/* - * SPILL_ALL_WINDOWS - * - * Spills all windowed registers (i.e. registers not visible as - * A0-A15) to their ABI-defined spill regions on the stack. - * - * Unlike the Xtensa HAL implementation, this code requires that the - * EXCM and WOE bit be enabled in PS, and relies on repeated hardware - * exception handling to do the register spills. The trick is to do a - * noop write to the high registers, which the hardware will trap - * (into an overflow exception) in the case where those registers are - * already used by an existing call frame. Then it rotates the window - * and repeats until all but the A0-A3 registers of the original frame - * are guaranteed to be spilled, eventually rotating back around into - * the original frame. Advantages: - * - * - Vastly smaller code size - * - * - More easily maintained if changes are needed to window over/underflow - * exception handling. - * - * - Requires no scratch registers to do its work, so can be used safely in any - * context. - * - * - If the WOE bit is not enabled (for example, in code written for - * the CALL0 ABI), this becomes a silent noop and operates compatibly. - * - * - In memory protection situations, this relies on the existing - * exception handlers (and thus their use of the L/S32E - * instructions) to execute stores in the protected space. AFAICT, - * the HAL routine does not handle this situation and isn't safe: it - * will happily write through the "stack pointers" found in - * registers regardless of where they might point. - * - * - Hilariously it's ACTUALLY FASTER than the HAL routine. And not - * just a little bit, it's MUCH faster. With a mostly full register - * file on an LX6 core (ESP-32) I'm measuring 145 cycles to spill - * registers with this vs. 279 (!) to do it with - * xthal_spill_windows(). Apparently Xtensa exception handling is - * really fast, and no one told their software people. - * - * Note that as with the Xtensa HAL spill routine, and unlike context - * switching code on most sane architectures, the intermediate states - * here will have an invalid stack pointer. That means that this code - * must not be preempted in any context (i.e. all Zephyr situations) - * where the interrupt code will need to use the stack to save the - * context. But unlike the HAL, which runs with exceptions masked via - * EXCM, this will not: hit needs the overflow handlers unmasked. Use - * INTLEVEL instead (which, happily, is what Zephyr's locking does - * anyway). - */ -.macro SPILL_ALL_WINDOWS -#if XCHAL_NUM_AREGS == 64 - and a12, a12, a12 - rotw 3 - and a12, a12, a12 - rotw 3 - and a12, a12, a12 - rotw 3 - and a12, a12, a12 - rotw 3 - and a12, a12, a12 - rotw 4 -#elif XCHAL_NUM_AREGS == 32 - and a12, a12, a12 - rotw 3 - and a12, a12, a12 - rotw 3 - and a4, a4, a4 - rotw 2 -#else -#error Unrecognized XCHAL_NUM_AREGS -#endif -.endm - -#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) -/* - * FPU_REG_SAVE - * - * Saves the Float Point Unit context registers in the base save - * area pointed to by the current stack pointer A1. The Floating-Point - * Coprocessor Option adds the FR register file and two User Registers - * called FCR and FSR.The FR register file consists of 16 registers of - * 32 bits each and is used for all data computation. - */ -.macro FPU_REG_SAVE - rur.fcr a0 - s32i a0, a1, ___xtensa_irq_bsa_t_fcr_OFFSET - rur.fsr a0 - s32i a0, a1, ___xtensa_irq_bsa_t_fsr_OFFSET - ssi f0, a1, ___xtensa_irq_bsa_t_fpu0_OFFSET - ssi f1, a1, ___xtensa_irq_bsa_t_fpu1_OFFSET - ssi f2, a1, ___xtensa_irq_bsa_t_fpu2_OFFSET - ssi f3, a1, ___xtensa_irq_bsa_t_fpu3_OFFSET - ssi f4, a1, ___xtensa_irq_bsa_t_fpu4_OFFSET - ssi f5, a1, ___xtensa_irq_bsa_t_fpu5_OFFSET - ssi f6, a1, ___xtensa_irq_bsa_t_fpu6_OFFSET - ssi f7, a1, ___xtensa_irq_bsa_t_fpu7_OFFSET - ssi f8, a1, ___xtensa_irq_bsa_t_fpu8_OFFSET - ssi f9, a1, ___xtensa_irq_bsa_t_fpu9_OFFSET - ssi f10, a1, ___xtensa_irq_bsa_t_fpu10_OFFSET - ssi f11, a1, ___xtensa_irq_bsa_t_fpu11_OFFSET - ssi f12, a1, ___xtensa_irq_bsa_t_fpu12_OFFSET - ssi f13, a1, ___xtensa_irq_bsa_t_fpu13_OFFSET - ssi f14, a1, ___xtensa_irq_bsa_t_fpu14_OFFSET - ssi f15, a1, ___xtensa_irq_bsa_t_fpu15_OFFSET -.endm - -.macro FPU_REG_RESTORE - l32i.n a0, a1, ___xtensa_irq_bsa_t_fcr_OFFSET - wur.fcr a0 - l32i.n a0, a1, ___xtensa_irq_bsa_t_fsr_OFFSET - wur.fsr a0 - lsi f0, a1, ___xtensa_irq_bsa_t_fpu0_OFFSET - lsi f1, a1, ___xtensa_irq_bsa_t_fpu1_OFFSET - lsi f2, a1, ___xtensa_irq_bsa_t_fpu2_OFFSET - lsi f3, a1, ___xtensa_irq_bsa_t_fpu3_OFFSET - lsi f4, a1, ___xtensa_irq_bsa_t_fpu4_OFFSET - lsi f5, a1, ___xtensa_irq_bsa_t_fpu5_OFFSET - lsi f6, a1, ___xtensa_irq_bsa_t_fpu6_OFFSET - lsi f7, a1, ___xtensa_irq_bsa_t_fpu7_OFFSET - lsi f8, a1, ___xtensa_irq_bsa_t_fpu8_OFFSET - lsi f9, a1, ___xtensa_irq_bsa_t_fpu9_OFFSET - lsi f10, a1, ___xtensa_irq_bsa_t_fpu10_OFFSET - lsi f11, a1, ___xtensa_irq_bsa_t_fpu11_OFFSET - lsi f12, a1, ___xtensa_irq_bsa_t_fpu12_OFFSET - lsi f13, a1, ___xtensa_irq_bsa_t_fpu13_OFFSET - lsi f14, a1, ___xtensa_irq_bsa_t_fpu14_OFFSET - lsi f15, a1, ___xtensa_irq_bsa_t_fpu15_OFFSET -.endm -#endif - -/* - * ODD_REG_SAVE - * - * Stashes the oddball shift/loop context registers in the base save - * area pointed to by the current stack pointer. On exit, A0 will - * have been modified but A2/A3 have not, and the shift/loop - * instructions can be used freely (though note loops don't work in - * exceptions for other reasons!). - * - * Does not populate or modify the PS/PC save locations. - */ -.macro ODD_REG_SAVE - rsr.SAR a0 - s32i a0, a1, ___xtensa_irq_bsa_t_sar_OFFSET -#if XCHAL_HAVE_LOOPS - rsr.LBEG a0 - s32i a0, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET - rsr.LEND a0 - s32i a0, a1, ___xtensa_irq_bsa_t_lend_OFFSET - rsr.LCOUNT a0 - s32i a0, a1, ___xtensa_irq_bsa_t_lcount_OFFSET -#endif - rsr.exccause a0 - s32i a0, a1, ___xtensa_irq_bsa_t_exccause_OFFSET -#if XCHAL_HAVE_S32C1I - rsr.SCOMPARE1 a0 - s32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET -#endif -#if XCHAL_HAVE_THREADPTR && defined(CONFIG_THREAD_LOCAL_STORAGE) - rur.THREADPTR a0 - s32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET -#endif -#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) - FPU_REG_SAVE -#endif -.endm - -#ifdef CONFIG_XTENSA_MMU -/* - * CALC_PTEVADDR_BASE - * - * This calculates the virtual address of the first PTE page - * (PTEVADDR base, the one mapping 0x00000000) so that we can - * use this to obtain the virtual address of the PTE page we are - * interested in. This can be obtained via - * (1 << CONFIG_XTENSA_MMU_PTEVADDR_SHIFT). - * - * Note that this is done this way is to avoid any TLB - * miss if we are to use l32r to load the PTEVADDR base. - * If the page containing the PTEVADDR base address is - * not in TLB, we will need to handle the TLB miss which - * we are trying to avoid here. - * - * @param ADDR_REG Register to store the calculated - * PTEVADDR base address. - * - * @note The content of ADDR_REG will be modified. - * Save and restore it around this macro usage. - */ -.macro CALC_PTEVADDR_BASE ADDR_REG - movi \ADDR_REG, 1 - slli \ADDR_REG, \ADDR_REG, CONFIG_XTENSA_MMU_PTEVADDR_SHIFT -.endm - -/* - * PRELOAD_PTEVADDR - * - * This preloads the page table entries for a 4MB region to avoid TLB - * misses. This 4MB region is mapped via a page (4KB) of page table - * entries (PTE). Each entry is 4 bytes mapping a 4KB region. Each page, - * then, has 1024 entries mapping a 4MB region. Filling TLB entries is - * automatically done via hardware, as long as the PTE page associated - * with a particular address is also in TLB. If the PTE page is not in - * TLB, an exception will be raised that must be handled. This TLB miss - * is problematic when we are in the middle of dealing with another - * exception or handling an interrupt. So we need to put the PTE page - * into TLB by simply do a load operation. - * - * @param ADDR_REG Register containing the target address - * @param PTEVADDR_BASE_REG Register containing the PTEVADDR base - * - * @note Both the content of ADDR_REG will be modified. - * Save and restore it around this macro usage. - */ -.macro PRELOAD_PTEVADDR ADDR_REG, PTEVADDR_BASE_REG - /* - * Calculate the offset to first PTE page of all memory. - * - * Every page (4KB) of page table entries contains - * 1024 entires (as each entry is 4 bytes). Each entry - * maps one 4KB page. So one page of entries maps 4MB of - * memory. - * - * 1. We need to find the virtual address of the PTE page - * having the page table entry mapping the address in - * register ADDR_REG. To do this, we first need to find - * the offset of this PTE page from the first PTE page - * (the one mapping memory 0x00000000): - * a. Find the beginning address of the 4KB page - * containing address in ADDR_REG. This can simply - * be done by discarding 11 bits (or shifting right - * and then left 12 bits). - * b. Since each PTE page contains 1024 entries, - * we divide the address obtained in step (a) by - * further dividing it by 1024 (shifting right and - * then left 10 bits) to obtain the offset of - * the PTE page. - * - * Step (a) and (b) can be obtained together so that - * we can shift right 22 bits, and then shift left - * 12 bits. - * - * 2. Once we have combine the results from step (1) and - * PTEVADDR_BASE_REG to get the virtual address of - * the PTE page. - * - * 3. Do a l32i to force the PTE page to be in TLB. - */ - - /* Step 1 */ - srli \ADDR_REG, \ADDR_REG, 22 - slli \ADDR_REG, \ADDR_REG, 12 - - /* Step 2 */ - add \ADDR_REG, \ADDR_REG, \PTEVADDR_BASE_REG - - /* Step 3 */ - l32i \ADDR_REG, \ADDR_REG, 0 -.endm -#endif /* CONFIG_XTENSA_MMU */ - -/* - * CROSS_STACK_CALL - * - * Sets the stack up carefully such that a "cross stack" call can spill - * correctly, then invokes an immediate handler. Note that: - * - * 0. When spilling a frame, functions find their callEE's stack pointer - * (to save A0-A3) from registers. But they find their - * already-spilled callER's stack pointer (to save higher GPRs) from - * their own stack memory. - * - * 1. The function that was interrupted ("interruptee") does not need to - * be spilled, because it already has been as part of the context - * save. So it doesn't need registers allocated for it anywhere. - * - * 2. Interruptee's caller needs to spill into the space below the - * interrupted stack frame, which means that the A1 register it finds - * below it needs to contain the old/interrupted stack and not the - * context saved one. - * - * 3. The ISR dispatcher (called "underneath" interruptee) needs to spill - * high registers into the space immediately above its own stack frame, - * so it needs to find a caller with the "new" stack pointer instead. - * - * We make this work by inserting TWO 4-register frames between - * "interruptee's caller" and "ISR dispatcher". The top one (which - * occupies the slot formerly held by "interruptee", whose registers - * were saved via external means) holds the "interrupted A1" and the - * bottom has the "top of the interrupt stack" which can be either the - * word above a new memory area (when handling an interrupt from user - * mode) OR the existing "post-context-save" stack pointer (when - * handling a nested interrupt). The code works either way. Because - * these are both only 4-registers, neither needs its own caller for - * spilling. - * - * The net cost is 32 wasted bytes on the interrupt stack frame to - * spill our two "phantom frames" (actually not quite, as we'd need a - * few of those words used somewhere for tracking the stack pointers - * anyway). But the benefit is that NO REGISTER FRAMES NEED TO BE - * SPILLED on interrupt entry. And if we return back into the same - * context we interrupted (a common case) no windows need to be - * explicitly spilled at all. And in fact in the case where the ISR - * uses significant depth on its own stack, the interrupted frames - * will be spilled naturally as a standard cost of a function call, - * giving register windows something like "zero cost interrupts". - * - * FIXME: a terrible awful really nifty idea to fix the stack waste - * problem would be to use a SINGLE frame between the two stacks, - * pre-spill it with one stack pointer for the "lower" call to see and - * leave the register SP in place for the "upper" frame to use. - * Would require modifying the Window{Over|Under}flow4 exceptions to - * know not to spill/fill these special frames, but that's not too - * hard, maybe... - * - * Enter this macro with a valid "context saved" pointer (i.e. SP - * should point to a stored pointer which points to one BSA below the - * interrupted/old stack) in A1, a handler function in A2, and a "new" - * stack pointer (i.e. a pointer to the word ABOVE the allocated stack - * area) in A3. Exceptions should be enabled via PS.EXCM, but - * PS.INTLEVEL must (!) be set such that no nested interrupts can - * arrive (we restore the natural INTLEVEL from the value in ZSR_EPS - * just before entering the call). On return A0/1 will be unchanged, - * A2 has the return value of the called function, and A3 is - * clobbered. A4-A15 become part of called frames and MUST NOT BE IN - * USE by the code that expands this macro. The called function gets - * the context save handle in A1 as it's first argument. - */ -.macro CROSS_STACK_CALL - mov a6, a3 /* place "new sp" in the next frame's A2 */ - mov a10, a1 /* pass "context handle" in 2nd frame's A2 */ - mov a3, a1 /* stash it locally in A3 too */ - mov a11, a2 /* handler in 2nd frame's A3, next frame's A7 */ - - /* Recover the interrupted SP from the BSA */ - l32i a1, a1, 0 - l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET - addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF - - call4 _xstack_call0_\@ - mov a1, a3 /* restore original SP */ - mov a2, a6 /* copy return value */ - j _xstack_returned_\@ -.align 4 -_xstack_call0_\@: - /* We want an ENTRY to set a bit in windowstart and do the - * rotation, but we want our own SP. After that, we are - * running in a valid frame, so re-enable interrupts. - */ - entry a1, 16 - mov a1, a2 - rsr.ZSR_EPS a2 - wsr.PS a2 - call4 _xstack_call1_\@ - mov a2, a6 /* copy return value */ - retw -.align 4 -_xstack_call1_\@: - /* Remember the handler is going to do our ENTRY, so the - * handler pointer is still in A6 (not A2) even though this is - * after the second CALL4. - */ - jx a7 -_xstack_returned_\@: -.endm - -/* Entry setup for all exceptions and interrupts. Arrive here with - * the stack pointer decremented across a base save area, A0-A3 and - * PS/PC already spilled to the stack in the BSA, and A2 containing a - * level-specific C handler function. - * - * This is a macro (to allow for unit testing) that expands to a - * handler body to which the vectors can jump. It takes two static - * (!) arguments: a special register name (which should be set up to - * point to some kind of per-CPU record struct) and offsets within - * that struct which contains an interrupt stack top and a "nest - * count" word. - */ -.macro EXCINT_HANDLER NEST_OFF, INTSTACK_OFF - /* A2 contains our handler function which will get clobbered - * by the save. Stash it into the unused "a1" slot in the - * BSA and recover it immediately after. Kind of a hack. - */ - s32i a2, a1, ___xtensa_irq_bsa_t_scratch_OFFSET - - ODD_REG_SAVE - call0 xtensa_save_high_regs - - l32i a2, a1, 0 - l32i a2, a2, ___xtensa_irq_bsa_t_scratch_OFFSET - - /* There's a gotcha with level 1 handlers: the INTLEVEL field - * gets left at zero and not set like high priority interrupts - * do. That works fine for exceptions, but for L1 interrupts, - * when we unmask EXCM below, the CPU will just fire the - * interrupt again and get stuck in a loop blasting save - * frames down the stack to the bottom of memory. It would be - * good to put this code into the L1 handler only, but there's - * not enough room in the vector without some work there to - * squash it some. Next choice would be to make this a macro - * argument and expand two versions of this handler. An - * optimization FIXME, I guess. - */ - rsr.PS a0 - movi a3, PS_INTLEVEL_MASK - and a0, a0, a3 - bnez a0, _not_l1 - rsr.PS a0 - movi a3, PS_INTLEVEL(1) - or a0, a0, a3 - wsr.PS a0 -_not_l1: - - /* Setting up the cross stack call below has states where the - * resulting frames are invalid/non-reentrant, so we can't - * allow nested interrupts. But we do need EXCM unmasked, as - * we use CALL/ENTRY instructions in the process and need to - * handle exceptions to spill caller/interruptee frames. Use - * PS.INTLEVEL at maximum to mask all interrupts and stash the - * current value in our designated EPS register (which is - * guaranteed unused across the call) - */ - rsil a0, 0xf - - /* Since we are unmasking EXCM, we need to set RING bits to kernel - * mode, otherwise we won't be able to run the exception handler in C. - */ - movi a3, ~(PS_EXCM_MASK) & ~(PS_RING_MASK) - and a0, a0, a3 - wsr.ZSR_EPS a0 - wsr.PS a0 - rsync - - /* A1 already contains our saved stack, and A2 our handler. - * So all that's needed for CROSS_STACK_CALL is to put the - * "new" stack into A3. This can be either a copy of A1 or an - * entirely new area depending on whether we find a 1 in our - * SR[off] macro argument. - */ - rsr.ZSR_CPU a3 - l32i a0, a3, \NEST_OFF - beqz a0, _switch_stacks_\@ - - /* Use the same stack, just copy A1 to A3 after incrementing NEST */ - addi a0, a0, 1 - s32i a0, a3, \NEST_OFF - mov a3, a1 - j _do_call_\@ - -_switch_stacks_\@: - addi a0, a0, 1 - s32i a0, a3, \NEST_OFF - l32i a3, a3, \INTSTACK_OFF - -_do_call_\@: - CROSS_STACK_CALL - - /* Mask interrupts (which have been unmasked during the handler - * execution) while we muck with the windows and decrement the nested - * count. The restore will unmask them correctly. - */ - rsil a0, XCHAL_NMILEVEL - - /* Decrement nest count */ - rsr.ZSR_CPU a3 - l32i a0, a3, \NEST_OFF - addi a0, a0, -1 - s32i a0, a3, \NEST_OFF - - /* Last trick: the called function returned the "next" handle - * to restore to in A6 (the call4'd function's A2). If this - * is not the same handle as we started with, we need to do a - * register spill before restoring, for obvious reasons. - * Remember to restore the A1 stack pointer as it existed at - * interrupt time so the caller of the interrupted function - * spills to the right place. - */ - beq a6, a1, _restore_\@ - l32i a1, a1, 0 - l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET - addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF -#ifndef CONFIG_KERNEL_COHERENCE - /* When using coherence, the registers of the interrupted - * context got spilled upstream in arch_cohere_stacks() - */ - SPILL_ALL_WINDOWS -#endif - mov a1, a6 - -_restore_\@: - j _restore_context -.endm - -/* Defines an exception/interrupt vector for a specified level. Saves - * off the interrupted A0-A3 registers and the per-level PS/PC - * registers to the stack before jumping to a handler (defined with - * EXCINT_HANDLER) to do the rest of the work. - * - * Arguments are a numeric interrupt level and symbol names for the - * entry code (defined via EXCINT_HANDLER) and a C handler for this - * particular level. - * - * Note that the linker sections for some levels get special names for - * no particularly good reason. Only level 1 has any code generation - * difference, because it is the legacy exception level that predates - * the EPS/EPC registers. It also lives in the "iram0.text" segment - * (which is linked immediately after the vectors) so that an assembly - * stub can be loaded into the vector area instead and reach this code - * with a simple jump instruction. - */ -.macro DEF_EXCINT LVL, ENTRY_SYM, C_HANDLER_SYM -#if defined(CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY) -.pushsection .iram.text, "ax" -.global _Level\LVL\()VectorHelper -_Level\LVL\()VectorHelper : -#else -.if \LVL == 1 -.pushsection .iram0.text, "ax" -.elseif \LVL == XCHAL_DEBUGLEVEL -.pushsection .DebugExceptionVector.text, "ax" -.elseif \LVL == XCHAL_NMILEVEL -.pushsection .NMIExceptionVector.text, "ax" -.else -.pushsection .Level\LVL\()InterruptVector.text, "ax" -.endif -.global _Level\LVL\()Vector -_Level\LVL\()Vector: -#endif -#ifdef CONFIG_XTENSA_MMU - wsr.ZSR_EXTRA0 a2 - wsr.ZSR_EXTRA1 a3 - rsync - - /* Calculations below will clobber registers used. - * So we make a copy of the stack pointer to avoid - * changing it. - */ - mov a3, a1 - - CALC_PTEVADDR_BASE a2 - - /* Preload PTE entry page of current stack. */ - PRELOAD_PTEVADDR a3, a2 - - /* Preload PTE entry page of new stack, where - * it will be used later (in EXCINT_HANDLER above). - */ - rsr.ZSR_CPU a3 - PRELOAD_PTEVADDR a3, a2 - - rsr.ZSR_EXTRA1 a3 - rsr.ZSR_EXTRA0 a2 -#endif /* CONFIG_XTENSA_MMU */ - addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF - s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET - s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET - s32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET - - /* Level "1" is the exception handler, which uses a different - * calling convention. No special register holds the - * interrupted PS, instead we just assume that the CPU has - * turned on the EXCM bit and set INTLEVEL. - */ -.if \LVL == 1 - rsr.PS a0 -#ifdef CONFIG_XTENSA_MMU - /* TLB misses also come through level 1 interrupts. - * We do not want to unconditionally unmask interrupts. - * Execution continues after a TLB miss is handled, - * and we need to preserve the interrupt mask. - * The interrupt mask will be cleared for non-TLB-misses - * level 1 interrupt later in the handler code. - */ - movi a2, ~PS_EXCM_MASK -#else - movi a2, ~(PS_EXCM_MASK | PS_INTLEVEL_MASK) -#endif - and a0, a0, a2 - s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET -.else - rsr.EPS\LVL a0 - s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET -.endif - - rsr.EPC\LVL a0 - s32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET - - /* What's happening with this jump is that the L32R - * instruction to load a full 32 bit immediate must use an - * offset that is negative from PC. Normally the assembler - * fixes this up for you by putting the "literal pool" - * somewhere at the start of the section. But vectors start - * at a fixed address in their own section, and don't (in our - * current linker setup) have anywhere "definitely before - * vectors" to place immediates. Some platforms and apps will - * link by dumb luck, others won't. We add an extra jump just - * to clear space we know to be legal. - * - * The right way to fix this would be to use a "literal_prefix" - * to put the literals into a per-vector section, then link - * that section into the PREVIOUS vector's area right after - * the vector code. Requires touching a lot of linker scripts - * though. - */ - j _after_imms\LVL\() -.align 4 -_handle_excint_imm\LVL: - .word \ENTRY_SYM -_c_handler_imm\LVL: - .word \C_HANDLER_SYM -_after_imms\LVL: - l32r a2, _c_handler_imm\LVL - l32r a0, _handle_excint_imm\LVL - jx a0 -.popsection - -#if defined(CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY) -.if \LVL == 1 -.pushsection .iram0.text, "ax" -.elseif \LVL == XCHAL_DEBUGLEVEL -.pushsection .DebugExceptionVector.text, "ax" -.elseif \LVL == XCHAL_NMILEVEL -.pushsection .NMIExceptionVector.text, "ax" -.else -.pushsection .Level\LVL\()InterruptVector.text, "ax" -.endif -.global _Level\LVL\()Vector -_Level\LVL\()Vector : -j _Level\LVL\()VectorHelper -.popsection -#endif - -.endm - -#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H */ diff --git a/arch/xtensa/include/xtensa-asm2.h b/arch/xtensa/include/xtensa-asm2.h deleted file mode 100644 index 25fbb2980ab..00000000000 --- a/arch/xtensa/include/xtensa-asm2.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2017, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ -#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ - -#include -#include "xtensa-asm2-context.h" - -/** - * Initializes a stack area such that it can be "restored" later and - * begin running with the specified function and three arguments. The - * entry function takes three arguments to match the signature of - * Zephyr's k_thread_entry_t. Thread will start with EXCM clear and - * INTLEVEL set to zero (i.e. it's a user thread, we don't start with - * anything masked, so don't assume that!). - */ -void *xtensa_init_stack(struct k_thread *thread, int *stack_top, - void (*entry)(void *, void *, void *), - void *arg1, void *arg2, void *arg3); - -#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_H_ */ diff --git a/arch/xtensa/include/xtensa-asm2-context.h b/arch/xtensa/include/xtensa_asm2_context.h similarity index 100% rename from arch/xtensa/include/xtensa-asm2-context.h rename to arch/xtensa/include/xtensa_asm2_context.h diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h new file mode 100644 index 00000000000..c075d42c3f0 --- /dev/null +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2017, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H +#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H + +#include +#include "xtensa_asm2_context.h" + +#include + +/* Assembler header! This file contains macros designed to be included + * only by the assembler. + */ + +/* + * SPILL_ALL_WINDOWS + * + * Spills all windowed registers (i.e. registers not visible as + * A0-A15) to their ABI-defined spill regions on the stack. + * + * Unlike the Xtensa HAL implementation, this code requires that the + * EXCM and WOE bit be enabled in PS, and relies on repeated hardware + * exception handling to do the register spills. The trick is to do a + * noop write to the high registers, which the hardware will trap + * (into an overflow exception) in the case where those registers are + * already used by an existing call frame. Then it rotates the window + * and repeats until all but the A0-A3 registers of the original frame + * are guaranteed to be spilled, eventually rotating back around into + * the original frame. Advantages: + * + * - Vastly smaller code size + * + * - More easily maintained if changes are needed to window over/underflow + * exception handling. + * + * - Requires no scratch registers to do its work, so can be used safely in any + * context. + * + * - If the WOE bit is not enabled (for example, in code written for + * the CALL0 ABI), this becomes a silent noop and operates compatibly. + * + * - In memory protection situations, this relies on the existing + * exception handlers (and thus their use of the L/S32E + * instructions) to execute stores in the protected space. AFAICT, + * the HAL routine does not handle this situation and isn't safe: it + * will happily write through the "stack pointers" found in + * registers regardless of where they might point. + * + * - Hilariously it's ACTUALLY FASTER than the HAL routine. And not + * just a little bit, it's MUCH faster. With a mostly full register + * file on an LX6 core (ESP-32) I'm measuring 145 cycles to spill + * registers with this vs. 279 (!) to do it with + * xthal_spill_windows(). Apparently Xtensa exception handling is + * really fast, and no one told their software people. + * + * Note that as with the Xtensa HAL spill routine, and unlike context + * switching code on most sane architectures, the intermediate states + * here will have an invalid stack pointer. That means that this code + * must not be preempted in any context (i.e. all Zephyr situations) + * where the interrupt code will need to use the stack to save the + * context. But unlike the HAL, which runs with exceptions masked via + * EXCM, this will not: hit needs the overflow handlers unmasked. Use + * INTLEVEL instead (which, happily, is what Zephyr's locking does + * anyway). + */ +.macro SPILL_ALL_WINDOWS +#if XCHAL_NUM_AREGS == 64 + and a12, a12, a12 + rotw 3 + and a12, a12, a12 + rotw 3 + and a12, a12, a12 + rotw 3 + and a12, a12, a12 + rotw 3 + and a12, a12, a12 + rotw 4 +#elif XCHAL_NUM_AREGS == 32 + and a12, a12, a12 + rotw 3 + and a12, a12, a12 + rotw 3 + and a4, a4, a4 + rotw 2 +#else +#error Unrecognized XCHAL_NUM_AREGS +#endif +.endm + +#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) +/* + * FPU_REG_SAVE + * + * Saves the Float Point Unit context registers in the base save + * area pointed to by the current stack pointer A1. The Floating-Point + * Coprocessor Option adds the FR register file and two User Registers + * called FCR and FSR.The FR register file consists of 16 registers of + * 32 bits each and is used for all data computation. + */ +.macro FPU_REG_SAVE + rur.fcr a0 + s32i a0, a1, ___xtensa_irq_bsa_t_fcr_OFFSET + rur.fsr a0 + s32i a0, a1, ___xtensa_irq_bsa_t_fsr_OFFSET + ssi f0, a1, ___xtensa_irq_bsa_t_fpu0_OFFSET + ssi f1, a1, ___xtensa_irq_bsa_t_fpu1_OFFSET + ssi f2, a1, ___xtensa_irq_bsa_t_fpu2_OFFSET + ssi f3, a1, ___xtensa_irq_bsa_t_fpu3_OFFSET + ssi f4, a1, ___xtensa_irq_bsa_t_fpu4_OFFSET + ssi f5, a1, ___xtensa_irq_bsa_t_fpu5_OFFSET + ssi f6, a1, ___xtensa_irq_bsa_t_fpu6_OFFSET + ssi f7, a1, ___xtensa_irq_bsa_t_fpu7_OFFSET + ssi f8, a1, ___xtensa_irq_bsa_t_fpu8_OFFSET + ssi f9, a1, ___xtensa_irq_bsa_t_fpu9_OFFSET + ssi f10, a1, ___xtensa_irq_bsa_t_fpu10_OFFSET + ssi f11, a1, ___xtensa_irq_bsa_t_fpu11_OFFSET + ssi f12, a1, ___xtensa_irq_bsa_t_fpu12_OFFSET + ssi f13, a1, ___xtensa_irq_bsa_t_fpu13_OFFSET + ssi f14, a1, ___xtensa_irq_bsa_t_fpu14_OFFSET + ssi f15, a1, ___xtensa_irq_bsa_t_fpu15_OFFSET +.endm + +.macro FPU_REG_RESTORE + l32i.n a0, a1, ___xtensa_irq_bsa_t_fcr_OFFSET + wur.fcr a0 + l32i.n a0, a1, ___xtensa_irq_bsa_t_fsr_OFFSET + wur.fsr a0 + lsi f0, a1, ___xtensa_irq_bsa_t_fpu0_OFFSET + lsi f1, a1, ___xtensa_irq_bsa_t_fpu1_OFFSET + lsi f2, a1, ___xtensa_irq_bsa_t_fpu2_OFFSET + lsi f3, a1, ___xtensa_irq_bsa_t_fpu3_OFFSET + lsi f4, a1, ___xtensa_irq_bsa_t_fpu4_OFFSET + lsi f5, a1, ___xtensa_irq_bsa_t_fpu5_OFFSET + lsi f6, a1, ___xtensa_irq_bsa_t_fpu6_OFFSET + lsi f7, a1, ___xtensa_irq_bsa_t_fpu7_OFFSET + lsi f8, a1, ___xtensa_irq_bsa_t_fpu8_OFFSET + lsi f9, a1, ___xtensa_irq_bsa_t_fpu9_OFFSET + lsi f10, a1, ___xtensa_irq_bsa_t_fpu10_OFFSET + lsi f11, a1, ___xtensa_irq_bsa_t_fpu11_OFFSET + lsi f12, a1, ___xtensa_irq_bsa_t_fpu12_OFFSET + lsi f13, a1, ___xtensa_irq_bsa_t_fpu13_OFFSET + lsi f14, a1, ___xtensa_irq_bsa_t_fpu14_OFFSET + lsi f15, a1, ___xtensa_irq_bsa_t_fpu15_OFFSET +.endm +#endif + +/* + * ODD_REG_SAVE + * + * Stashes the oddball shift/loop context registers in the base save + * area pointed to by the current stack pointer. On exit, A0 will + * have been modified but A2/A3 have not, and the shift/loop + * instructions can be used freely (though note loops don't work in + * exceptions for other reasons!). + * + * Does not populate or modify the PS/PC save locations. + */ +.macro ODD_REG_SAVE + rsr.sar a0 + s32i a0, a1, ___xtensa_irq_bsa_t_sar_OFFSET +#if XCHAL_HAVE_LOOPS + rsr.lbeg a0 + s32i a0, a1, ___xtensa_irq_bsa_t_lbeg_OFFSET + rsr.lend a0 + s32i a0, a1, ___xtensa_irq_bsa_t_lend_OFFSET + rsr.lcount a0 + s32i a0, a1, ___xtensa_irq_bsa_t_lcount_OFFSET +#endif + rsr.exccause a0 + s32i a0, a1, ___xtensa_irq_bsa_t_exccause_OFFSET +#if XCHAL_HAVE_S32C1I + rsr.scompare1 a0 + s32i a0, a1, ___xtensa_irq_bsa_t_scompare1_OFFSET +#endif +#if XCHAL_HAVE_THREADPTR && \ + (defined(CONFIG_USERSPACE) || defined(CONFIG_THREAD_LOCAL_STORAGE)) + rur.THREADPTR a0 + s32i a0, a1, ___xtensa_irq_bsa_t_threadptr_OFFSET +#endif +#if XCHAL_HAVE_FP && defined(CONFIG_CPU_HAS_FPU) && defined(CONFIG_FPU_SHARING) + FPU_REG_SAVE +#endif +.endm + +#ifdef CONFIG_XTENSA_MMU +/* + * CALC_PTEVADDR_BASE + * + * This calculates the virtual address of the first PTE page + * (PTEVADDR base, the one mapping 0x00000000) so that we can + * use this to obtain the virtual address of the PTE page we are + * interested in. This can be obtained via + * (1 << CONFIG_XTENSA_MMU_PTEVADDR_SHIFT). + * + * Note that this is done this way is to avoid any TLB + * miss if we are to use l32r to load the PTEVADDR base. + * If the page containing the PTEVADDR base address is + * not in TLB, we will need to handle the TLB miss which + * we are trying to avoid here. + * + * @param ADDR_REG Register to store the calculated + * PTEVADDR base address. + * + * @note The content of ADDR_REG will be modified. + * Save and restore it around this macro usage. + */ +.macro CALC_PTEVADDR_BASE ADDR_REG + movi \ADDR_REG, 1 + slli \ADDR_REG, \ADDR_REG, CONFIG_XTENSA_MMU_PTEVADDR_SHIFT +.endm + +/* + * PRELOAD_PTEVADDR + * + * This preloads the page table entries for a 4MB region to avoid TLB + * misses. This 4MB region is mapped via a page (4KB) of page table + * entries (PTE). Each entry is 4 bytes mapping a 4KB region. Each page, + * then, has 1024 entries mapping a 4MB region. Filling TLB entries is + * automatically done via hardware, as long as the PTE page associated + * with a particular address is also in TLB. If the PTE page is not in + * TLB, an exception will be raised that must be handled. This TLB miss + * is problematic when we are in the middle of dealing with another + * exception or handling an interrupt. So we need to put the PTE page + * into TLB by simply do a load operation. + * + * @param ADDR_REG Register containing the target address + * @param PTEVADDR_BASE_REG Register containing the PTEVADDR base + * + * @note Both the content of ADDR_REG will be modified. + * Save and restore it around this macro usage. + */ +.macro PRELOAD_PTEVADDR ADDR_REG, PTEVADDR_BASE_REG + /* + * Calculate the offset to first PTE page of all memory. + * + * Every page (4KB) of page table entries contains + * 1024 entires (as each entry is 4 bytes). Each entry + * maps one 4KB page. So one page of entries maps 4MB of + * memory. + * + * 1. We need to find the virtual address of the PTE page + * having the page table entry mapping the address in + * register ADDR_REG. To do this, we first need to find + * the offset of this PTE page from the first PTE page + * (the one mapping memory 0x00000000): + * a. Find the beginning address of the 4KB page + * containing address in ADDR_REG. This can simply + * be done by discarding 11 bits (or shifting right + * and then left 12 bits). + * b. Since each PTE page contains 1024 entries, + * we divide the address obtained in step (a) by + * further dividing it by 1024 (shifting right and + * then left 10 bits) to obtain the offset of + * the PTE page. + * + * Step (a) and (b) can be obtained together so that + * we can shift right 22 bits, and then shift left + * 12 bits. + * + * 2. Once we have combine the results from step (1) and + * PTEVADDR_BASE_REG to get the virtual address of + * the PTE page. + * + * 3. Do a l32i to force the PTE page to be in TLB. + */ + + /* Step 1 */ + srli \ADDR_REG, \ADDR_REG, 22 + slli \ADDR_REG, \ADDR_REG, 12 + + /* Step 2 */ + add \ADDR_REG, \ADDR_REG, \PTEVADDR_BASE_REG + + /* Step 3 */ + l32i \ADDR_REG, \ADDR_REG, 0 +.endm +#endif /* CONFIG_XTENSA_MMU */ + +/* + * CROSS_STACK_CALL + * + * Sets the stack up carefully such that a "cross stack" call can spill + * correctly, then invokes an immediate handler. Note that: + * + * 0. When spilling a frame, functions find their callEE's stack pointer + * (to save A0-A3) from registers. But they find their + * already-spilled callER's stack pointer (to save higher GPRs) from + * their own stack memory. + * + * 1. The function that was interrupted ("interruptee") does not need to + * be spilled, because it already has been as part of the context + * save. So it doesn't need registers allocated for it anywhere. + * + * 2. Interruptee's caller needs to spill into the space below the + * interrupted stack frame, which means that the A1 register it finds + * below it needs to contain the old/interrupted stack and not the + * context saved one. + * + * 3. The ISR dispatcher (called "underneath" interruptee) needs to spill + * high registers into the space immediately above its own stack frame, + * so it needs to find a caller with the "new" stack pointer instead. + * + * We make this work by inserting TWO 4-register frames between + * "interruptee's caller" and "ISR dispatcher". The top one (which + * occupies the slot formerly held by "interruptee", whose registers + * were saved via external means) holds the "interrupted A1" and the + * bottom has the "top of the interrupt stack" which can be either the + * word above a new memory area (when handling an interrupt from user + * mode) OR the existing "post-context-save" stack pointer (when + * handling a nested interrupt). The code works either way. Because + * these are both only 4-registers, neither needs its own caller for + * spilling. + * + * The net cost is 32 wasted bytes on the interrupt stack frame to + * spill our two "phantom frames" (actually not quite, as we'd need a + * few of those words used somewhere for tracking the stack pointers + * anyway). But the benefit is that NO REGISTER FRAMES NEED TO BE + * SPILLED on interrupt entry. And if we return back into the same + * context we interrupted (a common case) no windows need to be + * explicitly spilled at all. And in fact in the case where the ISR + * uses significant depth on its own stack, the interrupted frames + * will be spilled naturally as a standard cost of a function call, + * giving register windows something like "zero cost interrupts". + * + * FIXME: a terrible awful really nifty idea to fix the stack waste + * problem would be to use a SINGLE frame between the two stacks, + * pre-spill it with one stack pointer for the "lower" call to see and + * leave the register SP in place for the "upper" frame to use. + * Would require modifying the Window{Over|Under}flow4 exceptions to + * know not to spill/fill these special frames, but that's not too + * hard, maybe... + * + * Enter this macro with a valid "context saved" pointer (i.e. SP + * should point to a stored pointer which points to one BSA below the + * interrupted/old stack) in A1, a handler function in A2, and a "new" + * stack pointer (i.e. a pointer to the word ABOVE the allocated stack + * area) in A3. Exceptions should be enabled via PS.EXCM, but + * PS.INTLEVEL must (!) be set such that no nested interrupts can + * arrive (we restore the natural INTLEVEL from the value in ZSR_EPS + * just before entering the call). On return A0/1 will be unchanged, + * A2 has the return value of the called function, and A3 is + * clobbered. A4-A15 become part of called frames and MUST NOT BE IN + * USE by the code that expands this macro. The called function gets + * the context save handle in A1 as it's first argument. + */ +.macro CROSS_STACK_CALL + mov a6, a3 /* place "new sp" in the next frame's A2 */ + mov a10, a1 /* pass "context handle" in 2nd frame's A2 */ + mov a3, a1 /* stash it locally in A3 too */ + mov a11, a2 /* handler in 2nd frame's A3, next frame's A7 */ + + /* Recover the interrupted SP from the BSA */ + l32i a1, a1, 0 + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF + + call4 _xstack_call0_\@ + mov a1, a3 /* restore original SP */ + mov a2, a6 /* copy return value */ + j _xstack_returned_\@ +.align 4 +_xstack_call0_\@: + /* We want an ENTRY to set a bit in windowstart and do the + * rotation, but we want our own SP. After that, we are + * running in a valid frame, so re-enable interrupts. + */ + entry a1, 16 + mov a1, a2 + rsr.ZSR_EPS a2 + wsr.ps a2 + call4 _xstack_call1_\@ + mov a2, a6 /* copy return value */ + retw +.align 4 +_xstack_call1_\@: + /* Remember the handler is going to do our ENTRY, so the + * handler pointer is still in A6 (not A2) even though this is + * after the second CALL4. + */ + jx a7 +_xstack_returned_\@: +.endm + +/* Entry setup for all exceptions and interrupts. Arrive here with + * the stack pointer decremented across a base save area, A0-A3 and + * PS/PC already spilled to the stack in the BSA, and A2 containing a + * level-specific C handler function. + * + * This is a macro (to allow for unit testing) that expands to a + * handler body to which the vectors can jump. It takes two static + * (!) arguments: a special register name (which should be set up to + * point to some kind of per-CPU record struct) and offsets within + * that struct which contains an interrupt stack top and a "nest + * count" word. + */ +.macro EXCINT_HANDLER NEST_OFF, INTSTACK_OFF + /* A2 contains our handler function which will get clobbered + * by the save. Stash it into the unused "a1" slot in the + * BSA and recover it immediately after. Kind of a hack. + */ + s32i a2, a1, ___xtensa_irq_bsa_t_scratch_OFFSET + + ODD_REG_SAVE + call0 xtensa_save_high_regs + + l32i a2, a1, 0 + l32i a2, a2, ___xtensa_irq_bsa_t_scratch_OFFSET + +#if XCHAL_HAVE_THREADPTR && defined(CONFIG_USERSPACE) + /* Clear up the threadptr because it is used + * to check if a thread is runnig on user mode. Since + * we are in a interruption we don't want the system + * thinking it is possbly running in user mode. + */ + movi.n a0, 0 + wur.THREADPTR a0 +#endif /* XCHAL_HAVE_THREADPTR && CONFIG_USERSPACE */ + + /* There's a gotcha with level 1 handlers: the INTLEVEL field + * gets left at zero and not set like high priority interrupts + * do. That works fine for exceptions, but for L1 interrupts, + * when we unmask EXCM below, the CPU will just fire the + * interrupt again and get stuck in a loop blasting save + * frames down the stack to the bottom of memory. It would be + * good to put this code into the L1 handler only, but there's + * not enough room in the vector without some work there to + * squash it some. Next choice would be to make this a macro + * argument and expand two versions of this handler. An + * optimization FIXME, I guess. + */ + rsr.ps a0 + movi a3, PS_INTLEVEL_MASK + and a0, a0, a3 + bnez a0, _not_l1 + rsr.ps a0 + movi a3, PS_INTLEVEL(1) + or a0, a0, a3 + wsr.ps a0 +_not_l1: + + /* Setting up the cross stack call below has states where the + * resulting frames are invalid/non-reentrant, so we can't + * allow nested interrupts. But we do need EXCM unmasked, as + * we use CALL/ENTRY instructions in the process and need to + * handle exceptions to spill caller/interruptee frames. Use + * PS.INTLEVEL at maximum to mask all interrupts and stash the + * current value in our designated EPS register (which is + * guaranteed unused across the call) + */ + rsil a0, 0xf + + /* Since we are unmasking EXCM, we need to set RING bits to kernel + * mode, otherwise we won't be able to run the exception handler in C. + */ + movi a3, ~(PS_EXCM_MASK) & ~(PS_RING_MASK) + and a0, a0, a3 + wsr.ZSR_EPS a0 + wsr.ps a0 + rsync + + /* A1 already contains our saved stack, and A2 our handler. + * So all that's needed for CROSS_STACK_CALL is to put the + * "new" stack into A3. This can be either a copy of A1 or an + * entirely new area depending on whether we find a 1 in our + * SR[off] macro argument. + */ + rsr.ZSR_CPU a3 + l32i a0, a3, \NEST_OFF + beqz a0, _switch_stacks_\@ + + /* Use the same stack, just copy A1 to A3 after incrementing NEST */ + addi a0, a0, 1 + s32i a0, a3, \NEST_OFF + mov a3, a1 + j _do_call_\@ + +_switch_stacks_\@: + addi a0, a0, 1 + s32i a0, a3, \NEST_OFF + l32i a3, a3, \INTSTACK_OFF + +_do_call_\@: + CROSS_STACK_CALL + + /* Mask interrupts (which have been unmasked during the handler + * execution) while we muck with the windows and decrement the nested + * count. The restore will unmask them correctly. + */ + rsil a0, XCHAL_NMILEVEL + + /* Decrement nest count */ + rsr.ZSR_CPU a3 + l32i a0, a3, \NEST_OFF + addi a0, a0, -1 + s32i a0, a3, \NEST_OFF + + /* Last trick: the called function returned the "next" handle + * to restore to in A6 (the call4'd function's A2). If this + * is not the same handle as we started with, we need to do a + * register spill before restoring, for obvious reasons. + * Remember to restore the A1 stack pointer as it existed at + * interrupt time so the caller of the interrupted function + * spills to the right place. + */ + beq a6, a1, _restore_\@ + +#ifndef CONFIG_USERSPACE + l32i a1, a1, 0 + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF +#ifndef CONFIG_KERNEL_COHERENCE + /* When using coherence, the registers of the interrupted + * context got spilled upstream in arch_cohere_stacks() + */ + SPILL_ALL_WINDOWS +#endif + + /* Restore A1 stack pointer from "next" handle. */ + mov a1, a6 +#else + /* With userspace, we cannot simply restore A1 stack pointer + * at this pointer because we need to swap page tables to + * the incoming thread, and we do not want to call that + * function with thread's stack. So we stash the new stack + * pointer into A2 first, then move it to A1 after we have + * swapped the page table. + */ + mov a2, a6 + + /* Need to switch page tables because the "next" handle + * returned above is not the same handle as we started + * with. This means we are being restored to another + * thread. + */ + rsr a6, ZSR_CPU + l32i a6, a6, ___cpu_t_current_OFFSET + + call4 xtensa_swap_update_page_tables + l32i a1, a1, 0 + l32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + addi a1, a1, ___xtensa_irq_bsa_t_SIZEOF + + SPILL_ALL_WINDOWS + + /* Moved stashed stack pointer to A1 to restore stack. */ + mov a1, a2 +#endif + +_restore_\@: + j _restore_context +.endm + +/* Defines an exception/interrupt vector for a specified level. Saves + * off the interrupted A0-A3 registers and the per-level PS/PC + * registers to the stack before jumping to a handler (defined with + * EXCINT_HANDLER) to do the rest of the work. + * + * Arguments are a numeric interrupt level and symbol names for the + * entry code (defined via EXCINT_HANDLER) and a C handler for this + * particular level. + * + * Note that the linker sections for some levels get special names for + * no particularly good reason. Only level 1 has any code generation + * difference, because it is the legacy exception level that predates + * the EPS/EPC registers. It also lives in the "iram0.text" segment + * (which is linked immediately after the vectors) so that an assembly + * stub can be loaded into the vector area instead and reach this code + * with a simple jump instruction. + */ +.macro DEF_EXCINT LVL, ENTRY_SYM, C_HANDLER_SYM +#if defined(CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY) +.pushsection .iram.text, "ax" +.global _Level\LVL\()VectorHelper +_Level\LVL\()VectorHelper : +#else +.if \LVL == 1 +.pushsection .iram0.text, "ax" +.elseif \LVL == XCHAL_DEBUGLEVEL +.pushsection .DebugExceptionVector.text, "ax" +.elseif \LVL == XCHAL_NMILEVEL +.pushsection .NMIExceptionVector.text, "ax" +.else +.pushsection .Level\LVL\()InterruptVector.text, "ax" +.endif +.global _Level\LVL\()Vector +_Level\LVL\()Vector: +#endif + addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF + s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET + s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET + s32i a3, a1, ___xtensa_irq_bsa_t_a3_OFFSET + + /* Level "1" is the exception handler, which uses a different + * calling convention. No special register holds the + * interrupted PS, instead we just assume that the CPU has + * turned on the EXCM bit and set INTLEVEL. + */ +.if \LVL == 1 + rsr.ps a0 +#ifdef CONFIG_XTENSA_MMU + /* TLB misses also come through level 1 interrupts. + * We do not want to unconditionally unmask interrupts. + * Execution continues after a TLB miss is handled, + * and we need to preserve the interrupt mask. + * The interrupt mask will be cleared for non-TLB-misses + * level 1 interrupt later in the handler code. + */ + movi a2, ~PS_EXCM_MASK +#else + movi a2, ~(PS_EXCM_MASK | PS_INTLEVEL_MASK) +#endif + and a0, a0, a2 + s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET +.else + rsr.eps\LVL a0 + s32i a0, a1, ___xtensa_irq_bsa_t_ps_OFFSET +.endif + + rsr.epc\LVL a0 + s32i a0, a1, ___xtensa_irq_bsa_t_pc_OFFSET + + /* What's happening with this jump is that the L32R + * instruction to load a full 32 bit immediate must use an + * offset that is negative from PC. Normally the assembler + * fixes this up for you by putting the "literal pool" + * somewhere at the start of the section. But vectors start + * at a fixed address in their own section, and don't (in our + * current linker setup) have anywhere "definitely before + * vectors" to place immediates. Some platforms and apps will + * link by dumb luck, others won't. We add an extra jump just + * to clear space we know to be legal. + * + * The right way to fix this would be to use a "literal_prefix" + * to put the literals into a per-vector section, then link + * that section into the PREVIOUS vector's area right after + * the vector code. Requires touching a lot of linker scripts + * though. + */ + j _after_imms\LVL\() +.align 4 +_handle_excint_imm\LVL: + .word \ENTRY_SYM +_c_handler_imm\LVL: + .word \C_HANDLER_SYM +_after_imms\LVL: + l32r a2, _c_handler_imm\LVL + l32r a0, _handle_excint_imm\LVL + jx a0 +.popsection + +#if defined(CONFIG_XTENSA_SMALL_VECTOR_TABLE_ENTRY) +.if \LVL == 1 +.pushsection .iram0.text, "ax" +.elseif \LVL == XCHAL_DEBUGLEVEL +.pushsection .DebugExceptionVector.text, "ax" +.elseif \LVL == XCHAL_NMILEVEL +.pushsection .NMIExceptionVector.text, "ax" +.else +.pushsection .Level\LVL\()InterruptVector.text, "ax" +.endif +.global _Level\LVL\()Vector +_Level\LVL\()Vector : +j _Level\LVL\()VectorHelper +.popsection +#endif + +.endm + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_ASM2_S_H */ diff --git a/arch/xtensa/core/include/xtensa_backtrace.h b/arch/xtensa/include/xtensa_backtrace.h similarity index 87% rename from arch/xtensa/core/include/xtensa_backtrace.h rename to arch/xtensa/include/xtensa_backtrace.h index 2963836a4c6..069bdcb41ca 100644 --- a/arch/xtensa/core/include/xtensa_backtrace.h +++ b/arch/xtensa/include/xtensa_backtrace.h @@ -16,12 +16,17 @@ extern "C" { #include #include -/* +/** + * @ingroup xtensa_internal_apis + * @{ + */ + +/** * @brief Structure used for backtracing * * This structure stores the backtrace information of a particular stack frame * (i.e. the PC and SP). This structure is used iteratively with the - * z_xtensa_cpu_get_next_backtrace_frame() function to traverse each frame + * xtensa_cpu_get_next_backtrace_frame() function to traverse each frame * within a single stack. The next_pc represents the PC of the current * frame's caller, thus a next_pc of 0 indicates that the current frame * is the last frame on the stack. @@ -29,7 +34,7 @@ extern "C" { * @note Call esp_backtrace_get_start() to obtain initialization values for * this structure */ -struct z_xtensa_backtrace_frame_t { +struct xtensa_backtrace_frame_t { uint32_t pc; /* PC of the current frame */ uint32_t sp; /* SP of the current frame */ uint32_t next_pc; /* PC of the current frame's caller */ @@ -52,13 +57,13 @@ struct z_xtensa_backtrace_frame_t { * @param[out] next_pc PC of the first frame's caller * @param[in] interrupted_stack Pointer to interrupted stack */ -void z_xtensa_backtrace_get_start(uint32_t *pc, +void xtensa_backtrace_get_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc, int *interrupted_stack); /** - * Get the next frame on a stack for backtracing + * @brief Get the next frame on a stack for backtracing * * Given a stack frame(i), this function will obtain the next * stack frame(i-1) on the same call stack (i.e. the caller of frame(i)). @@ -77,7 +82,7 @@ void z_xtensa_backtrace_get_start(uint32_t *pc, * - True if the SP and PC of the next frame(i-1) are sane * - False otherwise */ -bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame); +bool xtensa_backtrace_get_next_frame(struct xtensa_backtrace_frame_t *frame); /** * @brief Print the backtrace of the current stack @@ -89,7 +94,11 @@ bool z_xtensa_backtrace_get_next_frame(struct z_xtensa_backtrace_frame_t *frame) * - 0 Backtrace successfully printed to completion or to depth limit * - -1 Backtrace is corrupted */ -int z_xtensa_backtrace_print(int depth, int *interrupted_stack); +int xtensa_backtrace_print(int depth, int *interrupted_stack); + +/** + * @} + */ #endif #ifdef __cplusplus diff --git a/arch/xtensa/include/xtensa_internal.h b/arch/xtensa/include/xtensa_internal.h new file mode 100644 index 00000000000..b97c109a994 --- /dev/null +++ b/arch/xtensa/include/xtensa_internal.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * Copyright (c) 2016 Cadence Design Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ +#define ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ + +#include + +#include +#include + +/** + * @ingroup xtensa_internal_apis + * @{ + */ + +/** + * @brief Dump and print out the stack frame content. + * + * This mainly prints out the registers stashed in the stack frame. + * + * @param stack Pointer to stack frame. + */ +void xtensa_dump_stack(const z_arch_esf_t *stack); + +/** + * @brief Get string description from an exception code. + * + * @param cause_code Exception code. + * + * @return String description. + */ +char *xtensa_exccause(unsigned int cause_code); + +/** + * @brief Called upon a fatal error. + * + * @param reason The reason for the fatal error + * @param esf Exception context, with details and partial or full register + * state when the error occurred. May in some cases be NULL. + */ +void xtensa_fatal_error(unsigned int reason, const z_arch_esf_t *esf); + +/** + * @brief Perform a one-way transition from supervisor to user mode. + * + * @see arch_user_mode_enter + */ +void xtensa_userspace_enter(k_thread_entry_t user_entry, + void *p1, void *p2, void *p3, + uintptr_t stack_end, + uintptr_t stack_start); + +/** + * @} + */ + +#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_XTENSA_INTERNAL_H_ */ diff --git a/arch/xtensa/include/xtensa_mmu_priv.h b/arch/xtensa/include/xtensa_mmu_priv.h new file mode 100644 index 00000000000..631760f03cb --- /dev/null +++ b/arch/xtensa/include/xtensa_mmu_priv.h @@ -0,0 +1,512 @@ +/* + * Xtensa MMU support + * + * Private data declarations + * + * Copyright (c) 2022 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ +#define ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ + +#include +#include +#include +#include + +/** + * @defgroup xtensa_mmu_internal_apis Xtensa Memory Management Unit (MMU) Internal APIs + * @ingroup xtensa_mmu_apis + * @{ + */ + +/** Mask for VPN in PTE */ +#define XTENSA_MMU_PTE_VPN_MASK 0xFFFFF000U + +/** Mask for PPN in PTE */ +#define XTENSA_MMU_PTE_PPN_MASK 0xFFFFF000U + +/** Mask for attributes in PTE */ +#define XTENSA_MMU_PTE_ATTR_MASK 0x0000000FU + +/** Mask for cache mode in PTE */ +#define XTENSA_MMU_PTE_ATTR_CACHED_MASK 0x0000000CU + +/** Mask used to figure out which L1 page table to use */ +#define XTENSA_MMU_L1_MASK 0x3FF00000U + +/** Mask used to figure out which L2 page table to use */ +#define XTENSA_MMU_L2_MASK 0x3FFFFFU + +#define XTENSA_MMU_PTEBASE_MASK 0xFFC00000 + +#define XTENSA_MMU_PTE(paddr, ring, attr) \ + (((paddr) & XTENSA_MMU_PTE_PPN_MASK) | \ + (((ring) << XTENSA_MMU_PTE_RING_SHIFT) & XTENSA_MMU_PTE_RING_MASK) | \ + ((attr) & XTENSA_MMU_PTE_ATTR_MASK)) + +/** Number of bits to shift for PPN in PTE */ +#define XTENSA_MMU_PTE_PPN_SHIFT 12U + +/** Mask for ring in PTE */ +#define XTENSA_MMU_PTE_RING_MASK 0x00000030U + +/** Number of bits to shift for ring in PTE */ +#define XTENSA_MMU_PTE_RING_SHIFT 4U + +/** Construct a page table entry (PTE) */ +#define XTENSA_MMU_PTE(paddr, ring, attr) \ + (((paddr) & XTENSA_MMU_PTE_PPN_MASK) | \ + (((ring) << XTENSA_MMU_PTE_RING_SHIFT) & XTENSA_MMU_PTE_RING_MASK) | \ + ((attr) & XTENSA_MMU_PTE_ATTR_MASK)) + +/** Get the attributes from a PTE */ +#define XTENSA_MMU_PTE_ATTR_GET(pte) \ + ((pte) & XTENSA_MMU_PTE_ATTR_MASK) + +/** Set the attributes in a PTE */ +#define XTENSA_MMU_PTE_ATTR_SET(pte, attr) \ + (((pte) & ~XTENSA_MMU_PTE_ATTR_MASK) | (attr)) + +/** Set the ring in a PTE */ +#define XTENSA_MMU_PTE_RING_SET(pte, ring) \ + (((pte) & ~XTENSA_MMU_PTE_RING_MASK) | \ + ((ring) << XTENSA_MMU_PTE_RING_SHIFT)) + +/** Get the ring from a PTE */ +#define XTENSA_MMU_PTE_RING_GET(pte) \ + (((pte) & ~XTENSA_MMU_PTE_RING_MASK) >> XTENSA_MMU_PTE_RING_SHIFT) + +/** Get the ASID from the RASID register corresponding to the ring in a PTE */ +#define XTENSA_MMU_PTE_ASID_GET(pte, rasid) \ + (((rasid) >> ((((pte) & XTENSA_MMU_PTE_RING_MASK) \ + >> XTENSA_MMU_PTE_RING_SHIFT) * 8)) & 0xFF) + +/** Calculate the L2 page table position from a virtual address */ +#define XTENSA_MMU_L2_POS(vaddr) \ + (((vaddr) & XTENSA_MMU_L2_MASK) >> 12U) + +/** Calculate the L1 page table position from a virtual address */ +#define XTENSA_MMU_L1_POS(vaddr) \ + ((vaddr) >> 22U) + +/** + * @def XTENSA_MMU_PAGE_TABLE_ATTR + * + * PTE attributes for entries in the L1 page table. Should never be + * writable, may be cached in non-SMP contexts only + */ +#if CONFIG_MP_MAX_NUM_CPUS == 1 +#define XTENSA_MMU_PAGE_TABLE_ATTR XTENSA_MMU_CACHED_WB +#else +#define XTENSA_MMU_PAGE_TABLE_ATTR 0 +#endif + +/** This ASID is shared between all domains and kernel. */ +#define XTENSA_MMU_SHARED_ASID 255 + +/** Fixed data TLB way to map the page table */ +#define XTENSA_MMU_PTE_WAY 7 + +/** Fixed data TLB way to map the vecbase */ +#define XTENSA_MMU_VECBASE_WAY 8 + +/** Kernel specific ASID. Ring field in the PTE */ +#define XTENSA_MMU_KERNEL_RING 0 + +/** User specific ASID. Ring field in the PTE */ +#define XTENSA_MMU_USER_RING 2 + +/** Ring value for MMU_SHARED_ASID */ +#define XTENSA_MMU_SHARED_RING 3 + +/** Number of data TLB ways [0-9] */ +#define XTENSA_MMU_NUM_DTLB_WAYS 10 + +/** Number of instruction TLB ways [0-6] */ +#define XTENSA_MMU_NUM_ITLB_WAYS 7 + +/** Number of auto-refill ways */ +#define XTENSA_MMU_NUM_TLB_AUTOREFILL_WAYS 4 + +/** Indicate PTE is illegal. */ +#define XTENSA_MMU_PTE_ILLEGAL (BIT(3) | BIT(2)) + +/** + * PITLB HIT bit. + * + * For more information see + * Xtensa Instruction Set Architecture (ISA) Reference Manual + * 4.6.5.7 Formats for Probing MMU Option TLB Entries + */ +#define XTENSA_MMU_PITLB_HIT BIT(3) + +/** + * PDTLB HIT bit. + * + * For more information see + * Xtensa Instruction Set Architecture (ISA) Reference Manual + * 4.6.5.7 Formats for Probing MMU Option TLB Entries + */ +#define XTENSA_MMU_PDTLB_HIT BIT(4) + +/** + * Virtual address where the page table is mapped + */ +#define XTENSA_MMU_PTEVADDR CONFIG_XTENSA_MMU_PTEVADDR + +/** + * Find the PTE entry address of a given vaddr. + * + * For example, assuming PTEVADDR in 0xE0000000, + * the page spans from 0xE0000000 - 0xE03FFFFF + * + * address 0x00 is in 0xE0000000 + * address 0x1000 is in 0xE0000004 + * ..... + * address 0xE0000000 (where the page is) is in 0xE0380000 + * + * Generalizing it, any PTE virtual address can be calculated this way: + * + * PTE_ENTRY_ADDRESS = PTEVADDR + ((VADDR / 4096) * 4) + */ +#define XTENSA_MMU_PTE_ENTRY_VADDR(base, vaddr) \ + ((base) + (((vaddr) / KB(4)) * 4)) + +/** + * Get ASID for a given ring from RASID register. + * + * RASID contains four 8-bit ASIDs, one per ring. + */ +#define XTENSA_MMU_RASID_ASID_GET(rasid, ring) \ + (((rasid) >> ((ring) * 8)) & 0xff) + +/** + * @brief Set RASID register. + * + * @param rasid Value to be set. + */ +static ALWAYS_INLINE void xtensa_rasid_set(uint32_t rasid) +{ + __asm__ volatile("wsr %0, rasid\n\t" + "isync\n" : : "a"(rasid)); +} + +/** + * @brief Get RASID register. + * + * @return Register value. + */ +static ALWAYS_INLINE uint32_t xtensa_rasid_get(void) +{ + uint32_t rasid; + + __asm__ volatile("rsr %0, rasid" : "=a"(rasid)); + return rasid; +} + +/** + * @brief Set a ring in RASID register to be particular value. + * + * @param asid ASID to be set. + * @param ring ASID of which ring to be manipulated. + */ +static ALWAYS_INLINE void xtensa_rasid_asid_set(uint8_t asid, uint8_t ring) +{ + uint32_t rasid = xtensa_rasid_get(); + + rasid = (rasid & ~(0xff << (ring * 8))) | ((uint32_t)asid << (ring * 8)); + + xtensa_rasid_set(rasid); +} + +/** + * @brief Invalidate a particular instruction TLB entry. + * + * @param entry Entry to be invalidated. + */ +static ALWAYS_INLINE void xtensa_itlb_entry_invalidate(uint32_t entry) +{ + __asm__ volatile("iitlb %0\n\t" + : : "a" (entry)); +} + +/** + * @brief Synchronously invalidate of a particular instruction TLB entry. + * + * @param entry Entry to be invalidated. + */ +static ALWAYS_INLINE void xtensa_itlb_entry_invalidate_sync(uint32_t entry) +{ + __asm__ volatile("iitlb %0\n\t" + "isync\n\t" + : : "a" (entry)); +} + +/** + * @brief Synchronously invalidate of a particular data TLB entry. + * + * @param entry Entry to be invalidated. + */ +static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate_sync(uint32_t entry) +{ + __asm__ volatile("idtlb %0\n\t" + "dsync\n\t" + : : "a" (entry)); +} + +/** + * @brief Invalidate a particular data TLB entry. + * + * @param entry Entry to be invalidated. + */ +static ALWAYS_INLINE void xtensa_dtlb_entry_invalidate(uint32_t entry) +{ + __asm__ volatile("idtlb %0\n\t" + : : "a" (entry)); +} + +/** + * @brief Synchronously write to a particular data TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ +static ALWAYS_INLINE void xtensa_dtlb_entry_write_sync(uint32_t pte, uint32_t entry) +{ + __asm__ volatile("wdtlb %0, %1\n\t" + "dsync\n\t" + : : "a" (pte), "a"(entry)); +} + +/** + * @brief Write to a particular data TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ +static ALWAYS_INLINE void xtensa_dtlb_entry_write(uint32_t pte, uint32_t entry) +{ + __asm__ volatile("wdtlb %0, %1\n\t" + : : "a" (pte), "a"(entry)); +} + +/** + * @brief Synchronously write to a particular instruction TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ +static ALWAYS_INLINE void xtensa_itlb_entry_write(uint32_t pte, uint32_t entry) +{ + __asm__ volatile("witlb %0, %1\n\t" + : : "a" (pte), "a"(entry)); +} + +/** + * @brief Synchronously write to a particular instruction TLB entry. + * + * @param pte Value to be written. + * @param entry Entry to be written. + */ +static ALWAYS_INLINE void xtensa_itlb_entry_write_sync(uint32_t pte, uint32_t entry) +{ + __asm__ volatile("witlb %0, %1\n\t" + "isync\n\t" + : : "a" (pte), "a"(entry)); +} + +/** + * @brief Invalidate all autorefill DTLB and ITLB entries. + * + * This should be used carefully since all refill entries in the data + * and instruction TLB. At least two pages, the current code page and + * the current stack, will be repopulated by this code as it returns. + * + * This needs to be called in any circumstance where the mappings for + * a previously-used page table change. It does not need to be called + * on context switch, where ASID tagging isolates entries for us. + */ +static inline void xtensa_tlb_autorefill_invalidate(void) +{ + uint8_t way, i, entries; + + entries = BIT(MAX(XCHAL_ITLB_ARF_ENTRIES_LOG2, + XCHAL_DTLB_ARF_ENTRIES_LOG2)); + + for (way = 0; way < XTENSA_MMU_NUM_TLB_AUTOREFILL_WAYS; way++) { + for (i = 0; i < entries; i++) { + uint32_t entry = way + (i << XTENSA_MMU_PTE_PPN_SHIFT); + + xtensa_dtlb_entry_invalidate(entry); + xtensa_itlb_entry_invalidate(entry); + } + } + __asm__ volatile("isync"); +} + +/** + * @brief Set the page tables. + * + * The page tables is set writing ptevaddr address. + * + * @param ptables The page tables address (virtual address) + */ +static ALWAYS_INLINE void xtensa_ptevaddr_set(void *ptables) +{ + __asm__ volatile("wsr.ptevaddr %0" : : "a"((uint32_t)ptables)); +} + +/** + * @brief Get the current page tables. + * + * The page tables is obtained by reading ptevaddr address. + * + * @return ptables The page tables address (virtual address) + */ +static ALWAYS_INLINE void *xtensa_ptevaddr_get(void) +{ + uint32_t ptables; + + __asm__ volatile("rsr.ptevaddr %0" : "=a" (ptables)); + + return (void *)(ptables & XTENSA_MMU_PTEBASE_MASK); +} + +/** + * @brief Get the virtual address associated with a particular data TLB entry. + * + * @param entry TLB entry to be queried. + */ +static ALWAYS_INLINE void *xtensa_dtlb_vaddr_read(uint32_t entry) +{ + uint32_t vaddr; + + __asm__ volatile("rdtlb0 %0, %1\n\t" : "=a" (vaddr) : "a" (entry)); + return (void *)(vaddr & XTENSA_MMU_PTE_VPN_MASK); +} + +/** + * @brief Get the physical address associated with a particular data TLB entry. + * + * @param entry TLB entry to be queried. + */ +static ALWAYS_INLINE uint32_t xtensa_dtlb_paddr_read(uint32_t entry) +{ + uint32_t paddr; + + __asm__ volatile("rdtlb1 %0, %1\n\t" : "=a" (paddr) : "a" (entry)); + return (paddr & XTENSA_MMU_PTE_PPN_MASK); +} + +/** + * @brief Get the virtual address associated with a particular instruction TLB entry. + * + * @param entry TLB entry to be queried. + */ +static ALWAYS_INLINE void *xtensa_itlb_vaddr_read(uint32_t entry) +{ + uint32_t vaddr; + + __asm__ volatile("ritlb0 %0, %1\n\t" : "=a" (vaddr), "+a" (entry)); + return (void *)(vaddr & XTENSA_MMU_PTE_VPN_MASK); +} + +/** + * @brief Get the physical address associated with a particular instruction TLB entry. + * + * @param entry TLB entry to be queried. + */ +static ALWAYS_INLINE uint32_t xtensa_itlb_paddr_read(uint32_t entry) +{ + uint32_t paddr; + + __asm__ volatile("ritlb1 %0, %1\n\t" : "=a" (paddr), "+a" (entry)); + return (paddr & XTENSA_MMU_PTE_PPN_MASK); +} + +/** + * @brief Probe for instruction TLB entry from a virtual address. + * + * @param vaddr Virtual address. + * + * @return Return of the PITLB instruction. + */ +static ALWAYS_INLINE uint32_t xtensa_itlb_probe(void *vaddr) +{ + uint32_t ret; + + __asm__ __volatile__("pitlb %0, %1\n\t" : "=a" (ret) : "a" ((uint32_t)vaddr)); + return ret; +} + +/** + * @brief Probe for data TLB entry from a virtual address. + * + * @param vaddr Virtual address. + * + * @return Return of the PDTLB instruction. + */ +static ALWAYS_INLINE uint32_t xtensa_dtlb_probe(void *vaddr) +{ + uint32_t ret; + + __asm__ __volatile__("pdtlb %0, %1\n\t" : "=a" (ret) : "a" ((uint32_t)vaddr)); + return ret; +} + +/** + * @brief Invalidate an instruction TLB entry associated with a virtual address. + * + * This invalidated an instruction TLB entry associated with a virtual address + * if such TLB entry exists. Otherwise, do nothing. + * + * @param vaddr Virtual address. + */ +static inline void xtensa_itlb_vaddr_invalidate(void *vaddr) +{ + uint32_t entry = xtensa_itlb_probe(vaddr); + + if (entry & XTENSA_MMU_PITLB_HIT) { + xtensa_itlb_entry_invalidate_sync(entry); + } +} + +/** + * @brief Invalidate a data TLB entry associated with a virtual address. + * + * This invalidated a data TLB entry associated with a virtual address + * if such TLB entry exists. Otherwise, do nothing. + * + * @param vaddr Virtual address. + */ +static inline void xtensa_dtlb_vaddr_invalidate(void *vaddr) +{ + uint32_t entry = xtensa_dtlb_probe(vaddr); + + if (entry & XTENSA_MMU_PDTLB_HIT) { + xtensa_dtlb_entry_invalidate_sync(entry); + } +} + +/** + * @brief Tell hardware to use a page table very first time after boot. + * + * @param l1_page Pointer to the page table to be used. + */ +void xtensa_init_paging(uint32_t *l1_page); + +/** + * @brief Switch to a new page table. + * + * @param asid The ASID of the memory domain associated with the incoming page table. + * @param l1_page Page table to be switched to. + */ +void xtensa_set_paging(uint32_t asid, uint32_t *l1_page); + +/** + * @} + */ + +#endif /* ZEPHYR_ARCH_XTENSA_XTENSA_MMU_PRIV_H_ */ diff --git a/boards/arc/emsdp/emsdp.yaml b/boards/arc/emsdp/emsdp.yaml index b6fa38fb515..c5a9afc8da4 100644 --- a/boards/arc/emsdp/emsdp.yaml +++ b/boards/arc/emsdp/emsdp.yaml @@ -1,5 +1,5 @@ identifier: emsdp -name: EM Software Development Platform +name: EM Software Development Platform (EM11D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em4.yaml b/boards/arc/emsdp/emsdp_em4.yaml index a146eb72bff..9be5bbca31b 100644 --- a/boards/arc/emsdp/emsdp_em4.yaml +++ b/boards/arc/emsdp/emsdp_em4.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em4 -name: EM Software Development Platform +name: EM Software Development Platform (EM4) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em5d.yaml b/boards/arc/emsdp/emsdp_em5d.yaml index d0117790975..80cbc08e066 100644 --- a/boards/arc/emsdp/emsdp_em5d.yaml +++ b/boards/arc/emsdp/emsdp_em5d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em5d -name: EM Software Development Platform +name: EM Software Development Platform (EM5D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em6.yaml b/boards/arc/emsdp/emsdp_em6.yaml index 2584fb8a953..ce15754d7be 100644 --- a/boards/arc/emsdp/emsdp_em6.yaml +++ b/boards/arc/emsdp/emsdp_em6.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em6 -name: EM Software Development Platform +name: EM Software Development Platform (EM6) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d.yaml b/boards/arc/emsdp/emsdp_em7d.yaml index 57f78c3c7e7..e3591d300f5 100644 --- a/boards/arc/emsdp/emsdp_em7d.yaml +++ b/boards/arc/emsdp/emsdp_em7d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d -name: EM Software Development Platform +name: EM Software Development Platform (EM7D) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em7d_esp.yaml b/boards/arc/emsdp/emsdp_em7d_esp.yaml index e3387d64798..2b8cc296bb8 100644 --- a/boards/arc/emsdp/emsdp_em7d_esp.yaml +++ b/boards/arc/emsdp/emsdp_em7d_esp.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em7d_esp -name: EM Software Development Platform +name: EM Software Development Platform (EM7D_ESP) type: mcu arch: arc toolchain: diff --git a/boards/arc/emsdp/emsdp_em9d.yaml b/boards/arc/emsdp/emsdp_em9d.yaml index 7bdf0340232..f20f29d18d0 100644 --- a/boards/arc/emsdp/emsdp_em9d.yaml +++ b/boards/arc/emsdp/emsdp_em9d.yaml @@ -1,5 +1,5 @@ identifier: emsdp_em9d -name: EM Software Development Platform +name: EM Software Development Platform (EM9D) type: mcu arch: arc toolchain: diff --git a/boards/arc/nsim/haps_arcv3_init.c b/boards/arc/nsim/haps_arcv3_init.c index 78dfc37f6c7..c29392643f8 100644 --- a/boards/arc/nsim/haps_arcv3_init.c +++ b/boards/arc/nsim/haps_arcv3_init.c @@ -1,48 +1,23 @@ /* - * Copyright (c) 2022 Synopsys + * Copyright (c) 2022-2023 Synopsys * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include -#define ARC_CLN_MST_NOC_0_0_ADDR 292 -#define ARC_CLN_MST_NOC_0_0_SIZE 293 - -#define ARC_CLN_MST_NOC_0_1_ADDR 2560 -#define ARC_CLN_MST_NOC_0_1_SIZE 2561 - -#define ARC_CLN_MST_NOC_0_2_ADDR 2562 -#define ARC_CLN_MST_NOC_0_2_SIZE 2563 - -#define ARC_CLN_MST_NOC_0_3_ADDR 2564 -#define ARC_CLN_MST_NOC_0_3_SIZE 2565 - -#define ARC_CLN_MST_NOC_0_4_ADDR 2566 -#define ARC_CLN_MST_NOC_0_4_SIZE 2567 - -#define ARC_CLN_PER0_BASE 2688 -#define ARC_CLN_PER0_SIZE 2689 - -#define AUX_CLN_ADDR 0x640 -#define AUX_CLN_DATA 0x641 - +#define DT_SRAM_NODE_ADDR (DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) / (1024 * 1024)) +#define DT_SRAM_NODE_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) / (1024 * 1024)) static int haps_arcv3_init(void) { + arc_cln_write_reg_nolock(ARC_CLN_PER0_BASE, 0xF00); + arc_cln_write_reg_nolock(ARC_CLN_PER0_SIZE, 1); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_PER0_BASE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, 0xF00); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_PER0_SIZE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, 1); - - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_MST_NOC_0_0_ADDR); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, (DT_REG_ADDR(DT_CHOSEN(zephyr_sram)) / (1024 * 1024))); - z_arc_v2_aux_reg_write(AUX_CLN_ADDR, ARC_CLN_MST_NOC_0_0_SIZE); - z_arc_v2_aux_reg_write(AUX_CLN_DATA, (DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) / (1024 * 1024))); - + arc_cln_write_reg_nolock(ARC_CLN_MST_NOC_0_0_ADDR, DT_SRAM_NODE_ADDR); + arc_cln_write_reg_nolock(ARC_CLN_MST_NOC_0_0_SIZE, DT_SRAM_NODE_SIZE); return 0; } diff --git a/boards/arc/nsim/nsim_em11d_defconfig b/boards/arc/nsim/nsim_em11d_defconfig index 49b4b4be58d..494ff760838 100644 --- a/boards/arc/nsim/nsim_em11d_defconfig +++ b/boards/arc/nsim/nsim_em11d_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_em7d_v22.yaml b/boards/arc/nsim/nsim_em7d_v22.yaml index 036e9b37bae..bd2069c8359 100644 --- a/boards/arc/nsim/nsim_em7d_v22.yaml +++ b/boards/arc/nsim/nsim_em7d_v22.yaml @@ -1,5 +1,5 @@ identifier: nsim_em7d_v22 -name: EM Nsim simulator +name: EM nSIM simulator (EM7D_v22) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_em7d_v22_defconfig b/boards/arc/nsim/nsim_em7d_v22_defconfig index 6f44addd50b..0a6d7ad5e4c 100644 --- a/boards/arc/nsim/nsim_em7d_v22_defconfig +++ b/boards/arc/nsim/nsim_em7d_v22_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_em_defconfig b/boards/arc/nsim/nsim_em_defconfig index f55dce20517..263c5b27af5 100644 --- a/boards/arc/nsim/nsim_em_defconfig +++ b/boards/arc/nsim/nsim_em_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS=y diff --git a/boards/arc/nsim/nsim_hs3x_hostlink_defconfig b/boards/arc/nsim/nsim_hs3x_hostlink_defconfig index 92ca6763a59..eddd5076c65 100644 --- a/boards/arc/nsim/nsim_hs3x_hostlink_defconfig +++ b/boards/arc/nsim/nsim_hs3x_hostlink_defconfig @@ -11,5 +11,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs5x_defconfig b/boards/arc/nsim/nsim_hs5x_defconfig index f87e1dfdcba..03c5f678869 100644 --- a/boards/arc/nsim/nsim_hs5x_defconfig +++ b/boards/arc/nsim/nsim_hs5x_defconfig @@ -12,4 +12,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml index 416dcd2133d..f7f9fa1ec72 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs5x_smp_12cores -name: Multi-core HS5x nSIM simulator +name: Multi-core HS5x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig b/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig index 1d146abff7f..c27e5d81ede 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_12cores_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=12 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs5x_smp_defconfig b/boards/arc/nsim/nsim_hs5x_smp_defconfig index c801fe9430e..ac6baba1858 100644 --- a/boards/arc/nsim/nsim_hs5x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs5x_smp_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs6x_defconfig b/boards/arc/nsim/nsim_hs6x_defconfig index 4db6e16b61e..dfb41bf2215 100644 --- a/boards/arc/nsim/nsim_hs6x_defconfig +++ b/boards/arc/nsim/nsim_hs6x_defconfig @@ -12,4 +12,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml index 3113b84e8d6..9abea29aabc 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs6x_smp_12cores -name: Multi-core HS6x nSIM simulator +name: Multi-core HS6x nSIM simulator (12 cores) type: sim simulation: mdb-nsim simulation_exec: mdb diff --git a/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig b/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig index 86793a594c7..2e14a87ed40 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_12cores_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=12 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs6x_smp_defconfig b/boards/arc/nsim/nsim_hs6x_smp_defconfig index 43085894396..c34a380d1d0 100644 --- a/boards/arc/nsim/nsim_hs6x_smp_defconfig +++ b/boards/arc/nsim/nsim_hs6x_smp_defconfig @@ -12,7 +12,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs_defconfig b/boards/arc/nsim/nsim_hs_defconfig index 92ca6763a59..eddd5076c65 100644 --- a/boards/arc/nsim/nsim_hs_defconfig +++ b/boards/arc/nsim/nsim_hs_defconfig @@ -11,5 +11,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs_flash_xip.yaml b/boards/arc/nsim/nsim_hs_flash_xip.yaml index 02da85f5864..eabe0c9cd84 100644 --- a/boards/arc/nsim/nsim_hs_flash_xip.yaml +++ b/boards/arc/nsim/nsim_hs_flash_xip.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_flash_xip -name: HS nSIM simulator +name: HS nSIM simulator (FLASH XIP) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs_flash_xip_defconfig b/boards/arc/nsim/nsim_hs_flash_xip_defconfig index bc6104c8a12..e4124a3ed69 100644 --- a/boards/arc/nsim/nsim_hs_flash_xip_defconfig +++ b/boards/arc/nsim/nsim_hs_flash_xip_defconfig @@ -11,6 +11,5 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_HARVARD=n CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_hs_mpuv6_defconfig b/boards/arc/nsim/nsim_hs_mpuv6_defconfig index 33b9af526d6..4f57122f208 100644 --- a/boards/arc/nsim/nsim_hs_mpuv6_defconfig +++ b/boards/arc/nsim/nsim_hs_mpuv6_defconfig @@ -12,4 +12,3 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/nsim/nsim_hs_smp_defconfig b/boards/arc/nsim/nsim_hs_smp_defconfig index b07bc87ed41..1b0d663da8d 100644 --- a/boards/arc/nsim/nsim_hs_smp_defconfig +++ b/boards/arc/nsim/nsim_hs_smp_defconfig @@ -11,7 +11,6 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_SMP=y CONFIG_MP_MAX_NUM_CPUS=2 CONFIG_TICKET_SPINLOCKS=y diff --git a/boards/arc/nsim/nsim_hs_sram.yaml b/boards/arc/nsim/nsim_hs_sram.yaml index 7a99a91ceff..cfbf02d6023 100644 --- a/boards/arc/nsim/nsim_hs_sram.yaml +++ b/boards/arc/nsim/nsim_hs_sram.yaml @@ -1,5 +1,5 @@ identifier: nsim_hs_sram -name: HS nSIM simulator +name: HS nSIM simulator (SRAM) type: sim simulation: nsim simulation_exec: nsimdrv diff --git a/boards/arc/nsim/nsim_hs_sram_defconfig b/boards/arc/nsim/nsim_hs_sram_defconfig index 9b60f760e62..8c4032b2054 100644 --- a/boards/arc/nsim/nsim_hs_sram_defconfig +++ b/boards/arc/nsim/nsim_hs_sram_defconfig @@ -11,6 +11,5 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_HARVARD=n CONFIG_ARC_MPU_ENABLE=y diff --git a/boards/arc/nsim/nsim_sem_defconfig b/boards/arc/nsim/nsim_sem_defconfig index 2ec15d063f5..c6be9e45d58 100644 --- a/boards/arc/nsim/nsim_sem_defconfig +++ b/boards/arc/nsim/nsim_sem_defconfig @@ -12,5 +12,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml index 45949212a00..13a48179fd5 100644 --- a/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml +++ b/boards/arc/nsim/nsim_sem_mpu_stack_guard.yaml @@ -1,5 +1,5 @@ identifier: nsim_sem_mpu_stack_guard -name: SEM Nsim simulator +name: SEM nSIM simulator (stack guard) type: sim arch: arc simulation: nsim diff --git a/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig b/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig index 56e4a729daf..4f846b18d61 100644 --- a/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig +++ b/boards/arc/nsim/nsim_sem_mpu_stack_guard_defconfig @@ -13,5 +13,4 @@ CONFIG_ARC_MPU_ENABLE=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_SECURE=y diff --git a/boards/arc/nsim/nsim_vpx5_defconfig b/boards/arc/nsim/nsim_vpx5_defconfig index 4107bf940ee..83fdaa12a7d 100644 --- a/boards/arc/nsim/nsim_vpx5_defconfig +++ b/boards/arc/nsim/nsim_vpx5_defconfig @@ -11,4 +11,3 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y diff --git a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml index 5346dbc1251..ed5425cc565 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs6x.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs6x.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs6x -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS6x type: qemu simulation: qemu arch: arc diff --git a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml index 829045078d2..4f7b9cee45d 100644 --- a/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml +++ b/boards/arc/qemu_arc/qemu_arc_hs_xip.yaml @@ -1,5 +1,5 @@ identifier: qemu_arc_hs_xip -name: QEMU Emulation for ARC HS +name: QEMU Emulation for ARC HS (XIP) type: qemu simulation: qemu arch: arc diff --git a/boards/arm/96b_aerocore2/96b_aerocore2.dts b/boards/arm/96b_aerocore2/96b_aerocore2.dts index 4a4e8672f7f..dd5f8d8a895 100644 --- a/boards/arm/96b_aerocore2/96b_aerocore2.dts +++ b/boards/arm/96b_aerocore2/96b_aerocore2.dts @@ -42,6 +42,10 @@ }; +&clk_lsi { + status = "okay"; +}; + &clk_hse { clock-frequency = ; status = "okay"; @@ -180,6 +184,12 @@ zephyr_udc0: &usbotg_fs { status = "okay"; }; +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + &rng { status = "okay"; }; diff --git a/boards/arm/adafruit_grand_central_m4_express/Kconfig.board b/boards/arm/adafruit_grand_central_m4_express/Kconfig.board new file mode 100644 index 00000000000..4ca7a712697 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/Kconfig.board @@ -0,0 +1,8 @@ +# Adafruit Grand Central M4 Express board configuration + +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS + bool "Adafruit Grand Central M4 Express" + depends on SOC_PART_NUMBER_SAMD51P20A diff --git a/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig b/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig new file mode 100644 index 00000000000..72266e97bac --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Adafruit Grand Central M4 Express board configuration + +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "adafruit_grand_central_m4_express" + depends on BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi new file mode 100644 index 00000000000..6dcd448bebd --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express-pinctrl.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Lukas Jung + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + sercom0_uart_default: sercom0_uart_default { + group1 { + pinmux = , + ; + }; + }; + + sercom2_spi_default: sercom2_spi_default { + group1 { + pinmux = , + , + ; + }; + }; + + sercom3_i2c_default: sercom3_i2c_default { + group1 { + pinmux = , + ; + }; + }; + + sercom7_spi_default: sercom7_spi_default { + group1 { + pinmux = , + , + ; + }; + }; + + usb_dc_default: usb_dc_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts new file mode 100644 index 00000000000..5cc038332b1 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.dts @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 Lukas Jung + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "adafruit_grand_central_m4_express-pinctrl.dtsi" + +/ { + model = "Adafruit Grand Central M4 Express"; + compatible = "adafruit,grand-central-m4-express"; + + chosen { + zephyr,console = &sercom0; + zephyr,shell-uart = &sercom0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &code_partition; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &led0; + sdhc0 = &sdhc0; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&portb 1 0>; + label = "LED"; + }; + }; +}; + +&cpu0 { + clock-frequency = <120000000>; +}; + +&sercom0 { + status = "okay"; + compatible = "atmel,sam0-uart"; + current-speed = <115200>; + rxpo = <1>; + txpo = <0>; + + pinctrl-0 = <&sercom0_uart_default>; + pinctrl-names = "default"; +}; + +&sercom2 { + status = "okay"; + compatible = "atmel,sam0-spi"; + dipo = <3>; + dopo = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom2_spi_default>; + pinctrl-names = "default"; + + cs-gpios = <&portb 28 GPIO_ACTIVE_LOW>; + + /* microSD Card */ + sdhc0: sdhc@0 { + status = "okay"; + compatible = "zephyr,sdhc-spi-slot"; + reg = <0>; + spi-max-frequency = <20000000>; + mmc { + status = "okay"; + compatible = "zephyr,sdmmc-disk"; + }; + }; +}; + +&sercom3 { + status = "okay"; + compatible = "atmel,sam0-i2c"; + clock-frequency = ; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom3_i2c_default>; + pinctrl-names = "default"; +}; + +&sercom7 { + status = "okay"; + compatible = "atmel,sam0-spi"; + dipo = <3>; + dopo = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&sercom7_spi_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usb0 { + status = "okay"; + + pinctrl-0 = <&usb_dc_default>; + pinctrl-names = "default"; +}; + +&dmac { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "uf2"; + reg = <0x00000000 DT_SIZE_K(16)>; + read-only; + }; + + code_partition: partition@4000 { + label = "code"; + reg = <0x4000 DT_SIZE_K(1024-16)>; + read-only; + }; + }; +}; diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml new file mode 100644 index 00000000000..0afd44c0af8 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express.yaml @@ -0,0 +1,17 @@ +identifier: adafruit_grand_central_m4_express +name: Adafruit Grand Central M4 Express +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb +supported: + - dma + - gpio + - i2c + - spi + - uart + - usb_device + - watchdog diff --git a/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig new file mode 100644 index 00000000000..b5bfafe5b18 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_SAMD51=y +CONFIG_SOC_PART_NUMBER_SAMD51P20A=y +CONFIG_BOARD_ADAFRUIT_GRAND_CENTRAL_M4_EXPRESS=y +CONFIG_SOC_ATMEL_SAMD5X_XOSC32K=y +CONFIG_SOC_ATMEL_SAMD5X_XOSC32K_AS_MAIN=y +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_SERIAL=y +CONFIG_GPIO=y + +CONFIG_BOOTLOADER_BOSSA=y +CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/boards/arm/adafruit_grand_central_m4_express/board.cmake b/boards/arm/adafruit_grand_central_m4_express/board.cmake new file mode 100644 index 00000000000..c5e25934fa5 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/board.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Lukas Jung +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/bossac.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp b/boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp new file mode 100644 index 00000000000..33e0a97394a Binary files /dev/null and b/boards/arm/adafruit_grand_central_m4_express/doc/img/adafruit_grand_central_m4_express.webp differ diff --git a/boards/arm/adafruit_grand_central_m4_express/doc/index.rst b/boards/arm/adafruit_grand_central_m4_express/doc/index.rst new file mode 100644 index 00000000000..a5dba70f617 --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/doc/index.rst @@ -0,0 +1,195 @@ +.. _adafruit_grand_central_m4_express: + +Adafruit Grand Central M4 Express +################################# + +Overview +******** + +The Adafruit Grand Central M4 Express is an ARM development board with the +form factor of an Arduino Mega. +It features 70 GPIO pins, a microSDHC slot and 8MiB of QSPI Flash. + +.. figure:: img/adafruit_grand_central_m4_express.webp + :width: 800px + :align: center + :alt: Adafruit Grand Central M4 Express + + Adafruit Grand Central M4 Express (Credit: Kattni Rembor / Adafruit) + +Hardware +******** + +- ATSAMD51P20A ARM Cortex-M4F processor at 120 MHz +- 1024 KiB of flash memory and 256 KiB of RAM +- 8 MiB of QSPI flash +- A red user LED +- A RGB "NeoPixel" / WS2812B LED +- A microSDHC slot (connected via SPI) +- Native USB port + +Supported Features +================== + +The adafruit_grand_central_m4_express board configuration supports the following +hardware features: + ++-----------+------------+------------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+==========================================+ +| NVIC | on-chip | Nested vector interrupt controller | ++-----------+------------+------------------------------------------+ +| SYSTICK | on-chip | SysTick | ++-----------+------------+------------------------------------------+ +| WDT | on-chip | Watchdog | ++-----------+------------+------------------------------------------+ +| GPIO | on-chip | I/O ports, User LED | ++-----------+------------+------------------------------------------+ +| UART | on-chip | Serial ports, Console | ++-----------+------------+------------------------------------------+ +| SPI | on-chip | SPI ports, microSDHC slot | ++-----------+------------+------------------------------------------+ +| TRNG | on-chip | True Random Number Generator | ++-----------+------------+------------------------------------------+ +| RTC | on-chip | Real-Time Counter | ++-----------+------------+------------------------------------------+ +| USB | on-chip | USB device | ++-----------+------------+------------------------------------------+ +| WDT | on-chip | Watchdog Timer | ++-----------+------------+------------------------------------------+ + +Other hardware features are not currently supported by Zephyr. + +The default configuration can be found in the Kconfig file +:zephyr_file:`boards/arm/adafruit_grand_central_m4_express/adafruit_grand_central_m4_express_defconfig`. + +Connections and IOs +=================== + +The `Adafruit Learning System`_ has detailed information about +the board including `pinouts`_ and the `schematics`_. + +System Clock +============ + +The SAMD51 MCU is configured to use the 32.768 kHz external oscillator +with the on-chip PLL generating the 120 MHz system clock. + +Serial Port +=========== + +The SAMD51 MCU has 8 SERCOM based UARTs. On the Grand Central, SERCOM0 is +the Zephyr console and is available on RX(PB25) and TX(PB24). + +SPI Port +======== + +The SAMD51 MCU has 8 SERCOM based SPIs. On the Grand Central, SERCOM7 has been +set into SPI mode to connect to devices over the SCK(PD09), MOSI(PD08), and MISO(PD11) pins. +Additionally SERCOM2 has been configured as SPI to access the microSDHC card. + +I2C Port +======== + +The SAMD51 MCU has 8 SERCOM based I2Cs. On the Grand Central, SERCOM3 has been +configured as I2C to connect to devices over the SCL(PB21) and SDA(PB20) pins. + +USB Device Port +=============== + +The SAMD51 MCU has a USB device port that can be used to communicate +with a host PC. See the :ref:`usb-samples` sample applications for +more, such as the :zephyr:code-sample:`usb-cdc-acm` sample which sets up a virtual +serial port that echos characters back to the host PC. + +Programming and Debugging +************************* + +The Grand Central ships with a BOSSA compatible UF2 bootloader. +The bootloader can be entered by quickly tapping the reset button twice. + +Flashing +======== + +#. Build the Zephyr kernel and the :ref:`hello_world` sample application: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_grand_central_m4_express + :goals: build + :compact: + +#. Connect the Grand Central to your host computer using USB. + +#. Connect a 3.3 V USB to serial adapter to the board and to the + host. See the `Serial Port`_ section above for the board's pin + connections. + +#. Run your favorite terminal program to listen for output. Under Linux the + terminal should be :code:`/dev/ttyUSB0`. For example: + + .. code-block:: console + + $ minicom -D /dev/ttyUSB0 -o + + The -o option tells minicom not to send the modem initialization + string. Connection should be configured as follows: + + - Speed: 115200 + - Data: 8 bits + - Parity: None + - Stop bits: 1 + +#. Tap the reset button twice quickly to enter bootloader mode + +#. Flash the image: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_grand_central_m4_express + :goals: flash + :compact: + + You should see "Hello World! adafruit_grand_central_m4_express" in your terminal. + +Debugging +========= + +In addition to the built-in bootloader, the Grand Central can be flashed and +debugged using a SWD probe such as the Segger J-Link. + +#. Connect the probe to the board using the 10-pin SWD interface. + +#. Flash the image: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_grand_central_m4_express + :goals: flash + :flash-args: -r openocd + :compact: + +#. Start debugging: + + .. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adafruit_grand_central_m4_express + :goals: debug + :compact: + +References +********** + +.. target-notes:: + +.. _Adafruit Learning System: + https://learn.adafruit.com/adafruit-grand-central + +.. _pinouts: + https://learn.adafruit.com/adafruit-grand-central/pinouts + +.. _schematics: + https://learn.adafruit.com/adafruit-grand-central/downloads + +.. _J-Link: + https://www.segger.com/products/debug-probes/j-link/technology/interface-description/ diff --git a/boards/arm/adafruit_grand_central_m4_express/support/openocd.cfg b/boards/arm/adafruit_grand_central_m4_express/support/openocd.cfg new file mode 100644 index 00000000000..f3f767cf79d --- /dev/null +++ b/boards/arm/adafruit_grand_central_m4_express/support/openocd.cfg @@ -0,0 +1,18 @@ +source [find interface/jlink.cfg] + +transport select swd + +set CHIPNAME atsamd51p20a +source [find target/atsame5x.cfg] + +reset_config srst_only + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi index 5ae00a45cde..cf1289acedc 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040-pinctrl.dtsi @@ -47,4 +47,13 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; + + ws2812_pio0_default: ws2812_pio0_default { + ws2812 { + pinmux = ; + }; + }; }; diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts index 2d9c815f578..c17700aa8fa 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.dts +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.dts @@ -11,6 +11,7 @@ #include "adafruit_kb2040-pinctrl.dtsi" #include "sparkfun_pro_micro_connector.dtsi" #include +#include / { chosen { @@ -24,12 +25,7 @@ aliases { watchdog0 = &wdt0; - }; - - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; + led-strip = &ws2812; }; }; @@ -60,6 +56,11 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + &uart0 { current-speed = <115200>; status = "okay"; @@ -95,6 +96,29 @@ pinctrl-names = "default"; }; +&pio0 { + status = "okay"; + + pio-ws2812 { + compatible = "worldsemi,ws2812-rpi_pico-pio"; + status = "okay"; + pinctrl-0 = <&ws2812_pio0_default>; + pinctrl-names = "default"; + bit-waveform = <3>, <3>, <4>; + + ws2812: ws2812 { + status = "okay"; + output-pin = <17>; + chain-length = <1>; + color-mapping = ; + reset-delay = <280>; + frequency = <800000>; + }; + }; +}; + zephyr_udc0: &usbd { status = "okay"; }; diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml index 51dd75d58d9..40511a77633 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040.yaml @@ -19,3 +19,5 @@ supported: - pwm - flash - dma + - counter + - clock diff --git a/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig b/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig index 735148fbce2..6ce0691032d 100644 --- a/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig +++ b/boards/arm/adafruit_kb2040/adafruit_kb2040_defconfig @@ -17,6 +17,9 @@ CONFIG_UART_CONSOLE=y # Enable reset by default CONFIG_RESET=y +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + # Code partition needed to target the correct flash range CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/adafruit_kb2040/doc/index.rst b/boards/arm/adafruit_kb2040/doc/index.rst index 98c2bacf9e3..09d5bfb0960 100644 --- a/boards/arm/adafruit_kb2040/doc/index.rst +++ b/boards/arm/adafruit_kb2040/doc/index.rst @@ -79,6 +79,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` diff --git a/boards/arm/adafruit_qt_py_rp2040/Kconfig.board b/boards/arm/adafruit_qt_py_rp2040/Kconfig.board new file mode 100644 index 00000000000..f2c8db2c341 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2022 Kelly Lord +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADAFRUIT_QT_PY_RP2040 + bool "Adafruit QT Py RP2040 Board" + depends on SOC_RP2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig b/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig new file mode 100644 index 00000000000..705a49ac152 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/Kconfig.defconfig @@ -0,0 +1,22 @@ +# Copyright (c) 2022 Peter Johanson +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADAFRUIT_QT_PY_RP2040 + +config BOARD + default "adafruit_qt_py_rp2040" + +config RP2_FLASH_W25Q080 + default y + +if I2C_DW + +config I2C_DW_CLOCK_SPEED + default 125 + +endif #I2C_DW + +config USB_SELF_POWERED + default n + +endif # BOARD_ADAFRUIT_QT_PY_RP2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi new file mode 100644 index 00000000000..d2e84ae41f8 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040-pinctrl.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * Copyright (c) 2022, Peter Johanson + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = ; + input-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + group3 { + pinmux = ; + }; + }; + + adc_default: adc_default { + group1 { + pinmux = , , , ; + input-enable; + }; + }; + + clocks_default: clocks_default { + }; + + ws2812_pio1_default: ws2812_pio1_default { + ws2812 { + pinmux = ; + }; + }; +}; diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts new file mode 100644 index 00000000000..7e8448aec0a --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.dts @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * Copyright (c) 2022 Peter Johanson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "adafruit_qt_py_rp2040-pinctrl.dtsi" +#include "seeed_xiao_connector.dtsi" +#include +#include + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &ssi; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,code-partition = &code_partition; + }; + + aliases { + watchdog0 = &wdt0; + led-strip = &ws2812; + }; +}; + +&flash0 { + reg = <0x10000000 DT_SIZE_M(8)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 8MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(8) - 0x100)>; + read-only; + }; + }; +}; + +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + +&uart1 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; + + /* + * Unlike some of the other Adafruit boards, the neopixel on this board has + * its positive side hooked up to a GPIO pin rather than a positive voltage + * rail to save on power. This will enable the LED on board initialization. + */ + neopixel-power-enable { + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + }; +}; + +&i2c0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&spi0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; +}; + +&timer { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&adc { + status = "okay"; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; +}; + +&pio0 { + status = "okay"; +}; + +&pio1 { + status = "okay"; + + /* + * Need to put this on PIO1 as having this on PIO0 causes the GPIO hog to + * not work. + */ + pio-ws2812 { + compatible = "worldsemi,ws2812-rpi_pico-pio"; + status = "okay"; + pinctrl-0 = <&ws2812_pio1_default>; + pinctrl-names = "default"; + bit-waveform = <3>, <3>, <4>; + + ws2812: ws2812 { + status = "okay"; + output-pin = <12>; + chain-length = <1>; + color-mapping = ; + reset-delay = <280>; + frequency = <800000>; + }; + }; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&vreg { + regulator-always-on; + regulator-allowed-modes = ; +}; diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml new file mode 100644 index 00000000000..2348e9cec55 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040.yaml @@ -0,0 +1,23 @@ +identifier: adafruit_qt_py_rp2040 +name: Adafruit QT Py RP2040 +type: mcu +arch: arm +flash: 8192 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart + - gpio + - adc + - i2c + - spi + - hwinfo + - watchdog + - pwm + - flash + - dma + - counter + - clock diff --git a/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig new file mode 100644 index 00000000000..d0987d6025f --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/adafruit_qt_py_rp2040_defconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_BOARD_ADAFRUIT_QT_PY_RP2040=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 + +# enable uart driver +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable reset by default +CONFIG_RESET=y + +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + +# Code partition needed to target the correct flash range +CONFIG_USE_DT_CODE_PARTITION=y + +# Output UF2 by default, native bootloader supports it. +CONFIG_BUILD_OUTPUT_UF2=y diff --git a/boards/arm/adafruit_qt_py_rp2040/board.cmake b/boards/arm/adafruit_qt_py_rp2040/board.cmake new file mode 100644 index 00000000000..affc290a869 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 TOKITA Hiroshi + +board_runner_args(uf2 "--board-id=RPI-RP2") + +include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) diff --git a/boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg b/boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg new file mode 100644 index 00000000000..c1a7ab1dc28 Binary files /dev/null and b/boards/arm/adafruit_qt_py_rp2040/doc/img/qtpy_rp2040.jpg differ diff --git a/boards/arm/adafruit_qt_py_rp2040/doc/index.rst b/boards/arm/adafruit_qt_py_rp2040/doc/index.rst new file mode 100644 index 00000000000..19b5a832223 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/doc/index.rst @@ -0,0 +1,129 @@ +.. _adafruit_qt_py_rp2040: + +Adafruit QT Py RP2040 +##################### + +Overview +******** + +The Adafruit QT Py RP2040 is a small, low-cost, versatile board from +Adafruit. It is equipped with an RP2040 SoC, an on-board RGB Neopixel, +a USB connector, and a STEMMA QT connector. The USB bootloader allows +it to be flashed without any adapter, in a drag-and-drop manner. + +Hardware +******** +- Dual core Arm Cortex-M0+ processor running up to 133MHz +- 264KB on-chip SRAM +- 8MB on-board QSPI flash with XIP capabilities +- 11 GPIO pins +- 4 Analog inputs +- 2 UART peripherals +- 2 SPI controllers +- 2 I2C controllers (one via STEMMA QT connector) +- 16 PWM channels +- USB 1.1 controller (host/device) +- 8 Programmable I/O (PIO) for custom peripherals +- On-board RGB LED +- 1 Watchdog timer peripheral + + +.. figure:: img/qtpy_rp2040.jpg + :align: center + :alt: Adafruit QT Py RP2040 + + Adafruit QT Py RP2040 (Image courtesy of Adafruit) + +Supported Features +================== + +The adafruit_qt_py_rp2040 board configuration supports the following +hardware features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - NVIC + - N/A + - :dtcompatible:`arm,v6m-nvic` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`raspberrypi,pico-gpio` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`raspberrypi,pico-adc` + * - I2C + - :kconfig:option:`CONFIG_I2C` + - :dtcompatible:`snps,designware-i2c` + * - SPI + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi` + * - USB Device + - :kconfig:option:`CONFIG_USB_DEVICE_STACK` + - :dtcompatible:`raspberrypi,pico-usbd` + * - HWINFO + - :kconfig:option:`CONFIG_HWINFO` + - N/A + * - Watchdog Timer (WDT) + - :kconfig:option:`CONFIG_WATCHDOG` + - :dtcompatible:`raspberrypi,pico-watchdog` + * - PWM + - :kconfig:option:`CONFIG_PWM` + - :dtcompatible:`raspberrypi,pico-pwm` + * - Flash + - :kconfig:option:`CONFIG_FLASH` + - :dtcompatible:`raspberrypi,pico-flash` + * - UART (PIO) + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart-pio` + +Pin Mapping +=========== + +The peripherals of the RP2040 SoC can be routed to various pins on the board. +The configuration of these routes can be modified through DTS. Please refer to +the datasheet to see the possible routings for each peripheral. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART1_TX : P20 +- UART1_RX : P5 +- I2C0_SDA : P24 +- I2C0_SCL : P25 +- I2C1_SDA : P22 +- I2C1_SCL : P23 +- SPI0_RX : P4 +- SPI0_SCK : P6 +- SPI0_TX : P3 + +Programming and Debugging +************************* + +Flashing +======== + +Using UF2 +--------- + +Since it doesn't expose the SWD pins, you must flash the Adafruit QT Py RP2040 with +a UF2 file. By default, building an app for this board will generate a +`build/zephyr/zephyr.uf2` file. If the QT Py RP2040 is powered on with the `BOOTSEL` +button pressed, it will appear on the host as a mass storage device. The +UF2 file should be drag-and-dropped to the device, which will flash the QT Py RP2040. + +.. target-notes:: + +.. _Getting Started with Raspberry Pi Pico: + https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf + +.. _Primary Guide\: Adafruit QT Py RP2040: + https://learn.adafruit.com/adafruit-qt-py-2040 diff --git a/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi b/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi new file mode 100644 index 00000000000..69e21b54c12 --- /dev/null +++ b/boards/arm/adafruit_qt_py_rp2040/seeed_xiao_connector.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + xiao_d: connector { + compatible = "seeed,xiao-gpio"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 29 0>, /* D0 */ + <1 0 &gpio0 28 0>, /* D1 */ + <2 0 &gpio0 27 0>, /* D2 */ + <3 0 &gpio0 26 0>, /* D3 */ + <4 0 &gpio0 24 0>, /* D4 */ + <5 0 &gpio0 25 0>, /* D5 */ + <6 0 &gpio0 20 0>, /* D6 */ + <7 0 &gpio0 5 0>, /* D7 */ + <8 0 &gpio0 6 0>, /* D8 */ + <9 0 &gpio0 4 0>, /* D9 */ + <10 0 &gpio0 3 0>; /* D10 */ + }; +}; + +xiao_spi: &spi0 {}; +xiao_i2c: &i2c0 {}; +xiao_serial: &uart1 {}; diff --git a/boards/arm/adi_eval_adin1110ebz/Kconfig.board b/boards/arm/adi_eval_adin1110ebz/Kconfig.board new file mode 100644 index 00000000000..29f1e3b8dbc --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/Kconfig.board @@ -0,0 +1,8 @@ +# ADI EVAL-ADIN1110EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_EVAL_ADIN1110EBZ + bool "ADI EVAL-ADIN1110EBZ evaulation board" + depends on SOC_STM32L4S5XX diff --git a/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig b/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig new file mode 100644 index 00000000000..79e309af4cd --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/Kconfig.defconfig @@ -0,0 +1,33 @@ +# ADI EVAL-ADIN1110EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_EVAL_ADIN1110EBZ + +config BOARD + default "adi_eval_adin1110ebz" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +config MDIO_INIT_PRIORITY + default 81 + depends on MDIO + +config PHY_INIT_PRIORITY + default 82 + depends on NET_L2_ETHERNET && ETH_DRIVER + +config MEMC + default y + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +endif # BOARD_ADI_EVAL_ADIN1110EBZ diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts new file mode 100644 index 00000000000..d87eefa0619 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.dts @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "Analog Devices Inc. EVAL-ADIN1110EBZ board"; + compatible = "adi,eval-adin1110ebz"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,flash-controller = &mx25r6435f; + }; + + ram0: psram@60000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + device_type = "memory"; + reg = <0x60000000 DT_SIZE_M(8)>; + zephyr,memory-region = "RAM0"; + }; + + leds { /* Respecting pcb silkscreen naming */ + compatible = "gpio-leds"; + green_led: led_uC0 { + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + label = "Status uC0"; + }; + red_led: led_uC1 { + gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + label = "Status uC1 "; + }; + yellow_led: led_uC2 { + gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + label = "Status uC2"; + }; + blue_led: led_uC3 { + gpios = <&gpiog 15 GPIO_ACTIVE_HIGH>; + label = "Status uC3"; + }; + }; + + aliases { + led0 = &green_led; + watchdog0 = &iwdg; + spi-flash0 = &mx25r6435f; + }; + + soc { + fmc: memory-controller@a0000000 { + compatible = "st,stm32-fmc"; + reg = <0xa0000000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00000001>; + + sram { + compatible = "st,stm32-fmc-nor-psram"; + + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div-m = <4>; + mul-n = <40>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* + * The flash starting at offset 0x10000 and ending at + * offset 0x1ffff is reserved for use by the application. + */ + + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(432)>; + }; + slot1_partition: partition@8c000 { + label = "image-1"; + reg = <0x0008C000 DT_SIZE_K(432)>; + }; + scratch_partition: partition@f8000 { + label = "image-scratch"; + reg = <0x000F8000 DT_SIZE_K(16)>; + }; + + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; + +&usart1 { /* USB FT232 */ + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&uart4 { /* ARDUINO P405 1 & 2 */ + pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pa1>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pg14 &i2c1_sda_pg13>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&i2c3 { + pinctrl-0 = <&i2c3_scl_pg7 &i2c3_sda_pg8>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; + + adt7420@48 { + compatible = "adi,adt7420"; + reg = <0x48>; + }; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + adin1110: adin1110@0 { + compatible = "adi,adin1110"; + reg = <0x0>; + spi-max-frequency = <25000000>; + int-gpios = <&gpiob 11 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpioc 7 GPIO_ACTIVE_LOW>; + + port1 { + local-mac-address = [ 00 E0 22 FE DA C8 ]; + }; + mdio { + compatible = "adi,adin2111-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@1 { + reg = <0x1>; + compatible = "adi,adin2111-phy"; + }; + }; + }; +}; + +&spi3 { + pinctrl-0 = <&spi3_sck_pc10 &spi3_miso_pc11 &spi3_mosi_pc12>; + pinctrl-names = "default"; + status = "okay"; +}; + +&timers2 { + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch1_pa15>; + pinctrl-names = "default"; + }; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12 + &usb_otg_fs_id_pa10>; + pinctrl-names = "default"; + status = "okay"; +}; + +&octospi1 { + pinctrl-0 = <&octospim_p1_clk_pa3 &octospim_p1_ncs_pa4 + &octospim_p1_io0_pb1 &octospim_p1_io1_pb0 + &octospim_p1_io2_pa7 &octospim_p1_io3_pa6>; + pinctrl-names = "default"; + dmas = <&dma1 0 40 0x480>; /* request 40 for OCTOSPI1 */ + dma-names = "tx_rx"; + + status = "okay"; + + mx25r6435f: ospi-nor-flash@0 { + compatible = "st,stm32-ospi-nor"; + reg = <0>; + ospi-max-frequency = ; /* for Voltage Range 2 */ + size = ; /* 64 Megabits */ + spi-bus-width = ; + data-rate = ; + writeoc="PP_1_4_4"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + store_partition: partition@0 { + label = "store"; + reg = <0x00000000 DT_SIZE_M(8)>; + }; + }; + }; +}; + +&fmc { + pinctrl-0 = <&fmc_nbl0_pe0 &fmc_nbl1_pe1 + &fmc_nce_pd7 &fmc_nwe_pd5 &fmc_noe_pd4 + &fmc_a0_pf0 &fmc_a1_pf1 &fmc_a2_pf2 &fmc_a3_pf3 + &fmc_a4_pf4 &fmc_a5_pf5 &fmc_a6_pf12 &fmc_a7_pf13 + &fmc_a8_pf14 &fmc_a9_pf15 &fmc_a10_pg0 &fmc_a11_pg1 + &fmc_a12_pg2 &fmc_a13_pg3 &fmc_a14_pg4 &fmc_a15_pg5 + &fmc_a16_pd11 &fmc_a17_pd12 &fmc_a18_pd13 &fmc_a19_pe3 + &fmc_a20_pe4 &fmc_a21_pe5 + &fmc_d0_pd14 &fmc_d1_pd15 &fmc_d2_pd0 &fmc_d3_pd1 + &fmc_d4_pe7 &fmc_d5_pe8 &fmc_d6_pe9 &fmc_d7_pe10 + &fmc_d8_pe11 &fmc_d9_pe12 &fmc_d10_pe13 &fmc_d11_pe14 + &fmc_d12_pe15 &fmc_d13_pd8 &fmc_d14_pd9 &fmc_d15_pd10>; + pinctrl-names = "default"; + + sram { + bank@0 { + reg = <0x0>; + st,control = ; + st,timing = <4 2 3 0 16 17 STM32_FMC_ACCESS_MODE_A>; + }; + }; +}; diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml new file mode 100644 index 00000000000..c7e9a79567a --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz.yaml @@ -0,0 +1,21 @@ +identifier: adi_eval_adin1110ebz +name: ADI EVAL-ADIN1110EBZ evaulation board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 2048 +supported: + - arduino_gpio + - arduino_i2c + - arduino_spi + - gpio + - i2c + - spi + - watchdog + - memc + - octospi +vendor: adi diff --git a/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig new file mode 100644 index 00000000000..15174238c66 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ADI_EVAL_ADIN1110EBZ=y +CONFIG_SOC_SERIES_STM32L4X=y +CONFIG_SOC_STM32L4S5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi b/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..ffea9d90e48 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/arduino_r3_connector.dtsi @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioc 0 0>, /* A0/D14 */ + <1 0 &gpioc 1 0>, /* A1/D15 */ + <2 0 &gpioc 2 0>, /* A2/D16 */ + <3 0 &gpioc 3 0>, /* A3/D17 */ + <4 0 &gpioc 4 0>, /* A4/D18 */ + <5 0 &gpioc 5 0>, /* A5/D19 */ + <6 0 &gpioa 0 0>, /* D0 */ + <7 0 &gpioa 1 0>, /* D1 */ + <8 0 &gpioa 2 0>, /* D2 */ + <9 0 &gpiod 2 0>, /* D3 */ + <10 0 &gpiod 6 0>, /* D4 */ + <11 0 &gpiob 7 0>, /* D5 */ + <12 0 &gpiob 8 0>, /* D6 */ + <13 0 &gpiob 9 0>, /* D7 */ + <14 0 &gpiob 6 0>, /* D8 */ + <15 0 &gpiob 5 0>, /* D9 */ + <16 0 &gpiog 12 0>, /* D10 */ + <17 0 &gpioc 12 0>, /* D11 */ + <18 0 &gpioc 11 0>, /* D12 */ + <19 0 &gpioc 10 0>, /* D13 */ + <20 0 &gpioc 0 0>, /* D14 */ + <21 0 &gpioc 1 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi3 {}; +arduino_serial: &uart4 {}; diff --git a/boards/arm/adi_eval_adin1110ebz/board.cmake b/boards/arm/adi_eval_adin1110ebz/board.cmake new file mode 100644 index 00000000000..4e81b2fb988 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32L4S5QI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp b/boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp new file mode 100644 index 00000000000..e999019268d Binary files /dev/null and b/boards/arm/adi_eval_adin1110ebz/doc/img/adi_eval_adin1110ebz.webp differ diff --git a/boards/arm/adi_eval_adin1110ebz/doc/index.rst b/boards/arm/adi_eval_adin1110ebz/doc/index.rst new file mode 100644 index 00000000000..3bcc3167596 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/doc/index.rst @@ -0,0 +1,183 @@ +.. _adi_eval_adin1110ebz: + +ADI EVAL-ADIN1110EVB Evaluation board +##################################### + +Overview +******** + +The EVAL-ADIN1110EBZ is a flexible platform enabling quick evaluation of the ADIN1110, robust, +low power 10BASE-T1L MAC-PHY. It provides 10Mbit per second Single Pair Ethernet (SPE) connections +with devices across 1.7km of cable. + +The evaluation board offers two modes of operation for maximum flexibility. Connected to a PC +via USB port, the full set of ADIN1110 register settings and features such as link quality +monitoring and diagnostics can be accessed over the USB using serial command interface. +The board also provides an Arduino interface. + +Alternatively, the board can operate in stand-alone mode where it is configured by setting hardware +configuration links and switches. On-board LEDs provide status indication. + +The SPI interface provides configuration and data access to the ADIN1110. + +A small prototyping area and test points are provided for experimentation with alternative cable +connection topologies including isolation transformers and/or power coupling inductors. + +.. figure:: img/adi_eval_adin1110ebz.webp + :align: center + :alt: ADI EVAL-ADIN1110EBZ + + ADI EVAL-ADIN1110EBZ (Credit: Analog Devices, Inc.) + +.. important:: + + S201 DIP switches are shipped in Open Alliance SPI mode. The current Zephyr + default board configuration is set to work as "Generic SPI, CRC enabled", + so the S201 DIP switches must be set as ``SPI_CFG0 OFF`` and ``SPI_CFG1 ON``. + An inconsistent S201 DIP switches configuration will halt the boot. + +Hardware +******** + +The ADI EVAL-ADIN1110EBZ hardware features list is available here: + +https://wiki.analog.com/resources/eval/user-guides/eval-adin1110ebz-user-guide + + +Supported Features +================== + +The ADI adi_eval_adin1110ebz board configuration supports the +following hardware features: + ++--------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++==============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++--------------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++--------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++--------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++--------------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++--------------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++--------------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++--------------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++--------------+------------+-------------------------------------+ +| ADIN1110 | spi | adin1110 10BASE-T1L mac/phy | ++--------------+------------+-------------------------------------+ +| FT232 | uart | usb-uart | ++--------------+------------+-------------------------------------+ +| ADT7422 | i2c | temperature sensor | ++--------------+------------+-------------------------------------+ +| ISS66WVE4M16 | fmc | 8MB PSRAM | ++--------------+------------+-------------------------------------+ + + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_eval_adin1110ebz/adi_eval_adin1110ebz_defconfig`` + + +Connections and IOs +=================== + +ADI ADIN1110EBZ evaluation board has 7 GPIO controllers (from A to G). These controllers are +responsible for pin muxing, input/output, pull-up, etc. + +For mode details please refer to `EVAL-ADIN1110EBZ User Guide `_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_1 TX/RX : PA9/PA10 (UART to FT232) +- UART_4 TX/RX : PA0/PA1 (Arduino Serial) +- I2C1 SCL/SDA : PG14/PG13 (Arduino I2C) +- I2C3 SCL/SDA : PG7/PG8 (Sensor I2C bus) +- SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Simple SPI to nor Flash) +- SPI2 SCK/MISO/MOSI : PB13/PB14/PB15 (ADIN1110) +- SPI3 SCK/MISO/MOSI : PC10/PC11/PC12 (Arduino SPI) +- LD1 : PC13 (Green LED) +- LD2 : PE2 (Red LED) +- LD3 : PE6 (Yellow LED) +- LD4 : PG15 (Blue LED) +- PSRAM : PE0/PE1/PF0-PF15/PG0-PG5/PD11-PD13/PE3/PE4 + PD14/PD15/PD9/PD1/PE7-PE15/PD8-PD10 + + +System Clock +------------ + +EVAL-ADIN1110EBZ System Clock could be driven by an internal or external oscillator, as well as +the main PLL clock. By default the System clock is driven by the PLL clock at 80MHz, driven by the +16MHz high speed internal oscillator. + +Serial Port +----------- + +EVAL-ADIN1110EBZ has 2 U(S)ARTs. The Zephyr console output is assigned to UART1 that is connected +to a FT232, so available through Micro USB connector. Default settings are 115200 8N1. + + +Programming and Debugging +************************* + +Flashing +======== + +EVAL-ADIN1110EBZ includes an ST-LINK/V2-1 JTAG/SWD 10 or 20 pin connector. This interface is +supported by the openocd version included in Zephyr SDK. + +Flashing an application to Discovery kit +----------------------------------------- + +Connect the EVAL-ADIN1110EBZ to your host computer using the USB port, then run a serial host +program to connect with your ADI board. For example: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ADI_EVAL-ADIN1110EBZ_AVAS_XXXXXX-if00-port0 + +where XXXXXX is the serial number of the connected device. +Then, build and flash in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin1110ebz + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_eval_adin1110ebz + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin1110ebz + :maybe-skip-config: + :goals: debug + +.. _EVAL-ADIN1110EBZ evaluation board website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html + +.. _EVAL-ADIN1110EBZ board User Guide: + https://wiki.analog.com/resources/eval/user-guides/eval-adin1110ebz-user-guide + +.. _ADIN1110 Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/adin1110.pdf + +.. _STM32L4S5QII3P reference manual: + https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake b/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake new file mode 100644 index 00000000000..394b73d0d23 --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/pre_dt_board.cmake @@ -0,0 +1,2 @@ +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") +list(APPEND EXTRA_DTC_FLAGS "-Wno-simple_bus_reg") diff --git a/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg b/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg new file mode 100644 index 00000000000..295299f2fbe --- /dev/null +++ b/boards/arm/adi_eval_adin1110ebz/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/stm32l4discovery.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/boards/arm/adi_eval_adin2111ebz/Kconfig.board b/boards/arm/adi_eval_adin2111ebz/Kconfig.board new file mode 100644 index 00000000000..f173947c39b --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/Kconfig.board @@ -0,0 +1,8 @@ +# ADI EVAL-ADIN2111EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_EVAL_ADIN2111EBZ + bool "ADI EVAL-ADIN2111EBZ evaulation board" + depends on SOC_STM32L4S5XX diff --git a/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig b/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig new file mode 100644 index 00000000000..41dd579738c --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/Kconfig.defconfig @@ -0,0 +1,37 @@ +# ADI EVAL-ADIN2111EBZ board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_EVAL_ADIN2111EBZ + +config BOARD + default "adi_eval_adin2111ebz" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +config MDIO_INIT_PRIORITY + default 81 + depends on MDIO + +config PHY_INIT_PRIORITY + default 82 + depends on NET_L2_ETHERNET && ETH_DRIVER + +if NETWORKING + +config NET_L2_ETHERNET + default y + +if ETH_ADIN2111 + +config NET_IF_MAX_IPV4_COUNT + default 2 + +endif # ETH_ADIN2111 + +endif # NETWORKING + +endif # BOARD_ADI_EVAL_ADIN2111EBZ diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts new file mode 100644 index 00000000000..5602afab008 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.dts @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include + +/ { + model = "Analog Devices Inc. EVAL-ADIN2111EBZ board"; + compatible = "adi,eval-adin2111ebz"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + blue_led: uC_led1 { + gpios = <&gpiob 6 GPIO_ACTIVE_HIGH>; + label = "Debug led uC1"; + }; + net_red_led: led_NET1 { + gpios = <&gpiob 10 GPIO_ACTIVE_HIGH>; + label = "NET led 1"; + }; + net_green_led: led_NET2 { + gpios = <&gpiob 11 GPIO_ACTIVE_HIGH>; + label = "NET led 2"; + }; + mod_red_led: led_MOD1 { + gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + label = "Mod led 1"; + }; + mod_green_led: led_MOD2 { + gpios = <&gpioe 6 GPIO_ACTIVE_HIGH>; + label = "Mod led 2"; + }; + }; + + aliases { + led0 = &blue_led; + watchdog0 = &iwdg; + spi-flash0 = &flash_ext; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hsi { + status = "okay"; +}; + +&pll { + div-m = <4>; + mul-n = <40>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hsi>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* + * The flash starting at offset 0x10000 and ending at + * offset 0x1ffff is reserved for use by the application. + */ + + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(432)>; + }; + slot1_partition: partition@8c000 { + label = "image-1"; + reg = <0x0008C000 DT_SIZE_K(432)>; + }; + scratch_partition: partition@f8000 { + label = "image-scratch"; + reg = <0x000F8000 DT_SIZE_K(16)>; + }; + + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; + }; + }; +}; + +&iwdg { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&dma1 { + status = "okay"; +}; + +&dmamux1 { + status = "okay"; +}; + +&usart1 { /* USB FT232 */ + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + flash_ext: flash@0 { + compatible = "issi,is25lp128", "jedec,spi-nor"; + size = <134217728>; + jedec-id = [96 60 18]; + reg = <0>; + spi-max-frequency = <133000000>; + status = "okay"; + }; +}; + +&spi2 { + pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>; + pinctrl-names = "default"; + cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + + adin2111: adin2111@0 { + compatible = "adi,adin2111"; + reg = <0x0>; + spi-max-frequency = <25000000>; + int-gpios = <&gpioa 12 GPIO_ACTIVE_LOW>; + status = "okay"; + + port1 { + local-mac-address = [ 00 E0 22 FE DA C9 ]; + }; + port2 { + local-mac-address = [ 00 E0 22 FE DA D9 ]; + }; + mdio { + compatible = "adi,adin2111-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@1 { + reg = <0x1>; + compatible = "adi,adin2111-phy"; + status = "okay"; + }; + ethernet-phy@2 { + reg = <0x2>; + compatible = "adi,adin2111-phy"; + status = "okay"; + }; + }; + }; +}; diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml new file mode 100644 index 00000000000..bddea6e4a76 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz.yaml @@ -0,0 +1,15 @@ +identifier: adi_eval_adin2111ebz +name: ADI EVAL-ADIN2111EBZ evaulation board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 640 +flash: 2048 +supported: + - gpio + - spi + - watchdog +vendor: adi diff --git a/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig new file mode 100644 index 00000000000..f7e4d9c4ab3 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_ADI_EVAL_ADIN2111EBZ=y +CONFIG_SOC_SERIES_STM32L4X=y +CONFIG_SOC_STM32L4S5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_eval_adin2111ebz/board.cmake b/boards/arm/adi_eval_adin2111ebz/board.cmake new file mode 100644 index 00000000000..4e81b2fb988 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32L4S5QI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp b/boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp new file mode 100644 index 00000000000..0b37432ac84 Binary files /dev/null and b/boards/arm/adi_eval_adin2111ebz/doc/img/adi_eval_adin2111ebz.webp differ diff --git a/boards/arm/adi_eval_adin2111ebz/doc/index.rst b/boards/arm/adi_eval_adin2111ebz/doc/index.rst new file mode 100644 index 00000000000..ac9d33aa285 --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/doc/index.rst @@ -0,0 +1,184 @@ +.. _adi_eval_adin2111ebz: + +ADI EVAL-ADIN2111EVB Evaluation board +##################################### + +Overview +******** + +The EVAL-ADIN2111EBZ is a flexible platform enabling quick evaluation of the ADIN2111, robust, +low power 10BASE-T1L 2-Port Ethernet switch. The evaluation board provides 2 10BASE-T1L channels +with 10Mbit per second Single Pair Ethernet (SPE) connections reaching up to 1.7km of link distance. + +The ADIN2111 internal switch can be configured in store and forward mode between the two 10BASE-T1L +channels and the SPI host. Cut through mode is also available between Port 1 and Port 2 and can +be used without the need of the SPI host (unmanaged configuration). + +The evaluation board offers two modes of operation for maximum flexibility: Connected to a PC +via USB port, the full set of ADIN2111 register settings and features such as link quality +monitoring and diagnostics can be accessed over the USB using the serial command interface +implemented in the evaluation firmware. + +Alternatively, the board can operate in cut-through mode between Port 1 and Port 2 (unmanaged +configuration without firmware) where the EVAL-ADIN2111EBZ acts as a network switch forwarding +packets between the 2x 10BASE-T1L ports. The 2x links are configured by setting the ADIN2111 +hardware configuration pins jumper and switches. The 2x On-board Activity LEDs provide Link +activity status indication for each port. + +Custom firmware can also be developed and the ADIN2111 driver support package includes simple +project examples to start a custom implementation. + +The SPI interface provides access to the management registers required for the switch configuration, +the 2 PHYs configuration and data exchange between SPI host and ports. + +.. important:: + + S1 DIP switches are shipped in Open Alliance SPI mode. The current Zephyr + default board configuration is set to work as "Generic SPI, CRC enabled", + so the S1 DIP switches must be set as ``SPI_CFG0 OFF and SPI_CFG1 OFF``. + An inconsistent S1 DIP switches configuration will halt the boot. + +.. figure:: img/adi_eval_adin2111ebz.webp + :align: center + :alt: ADI EVAL-ADIN2111EBZ + + ADI EVAL-ADIN2111EBZ (Credit: Analog Devices, Inc.) + +Hardware +******** + +The ADI EVAL-ADIN2111EBZ hardware features list is available here: + +https://wiki.analog.com/resources/eval/user-guides/eval-adin2111ebz-user-guide + + +Supported Features +================== + +The ADI adi_eval_adin2111ebz board configuration supports the +following hardware features: + ++--------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++==============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++--------------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++--------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++--------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++--------------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++--------------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++--------------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++--------------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++--------------+------------+-------------------------------------+ +| ADIN2111 | spi | adin2111 10BASE-T1L mac/phy | ++--------------+------------+-------------------------------------+ +| FT232 | uart | usb-uart | ++--------------+------------+-------------------------------------+ + + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_eval_adin2111ebz/adi_eval_adin2111ebz_defconfig`` + + +Connections and IOs +=================== + +ADI ADIN2111EBZ evaluation board has 7 GPIO controllers (from A to G). +These controllers are responsible for pin muxing, input/output, pull-up, etc. + +For mode details please refer to `EVAL-ADIN2111EBZ User Guide `_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_1 TX/RX : PA9/PA10 (UART to FT232, console) +- SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (SPI to external nor flash IS25LP128) +- SPI2 SCK/MISO/MOSI : PB13/PB14/PB15 (SPI to external ADIN2111) +- LED1 : POWER (Green LED) +- UC_LED1 : PB6 (Blue LED) +- MOD LED1 : PE2 (SR LED) +- MOD LED2 : PE6 (BG LED) +- NET LED1 : PB10 (SR LED) +- NET LED2 : PB11 (BG LED) + + +System Clock +------------ + +EVAL-ADIN2111EBZ System Clock could be driven by an internal or external oscillator, as well as the +main PLL clock. By default the System clock is driven by the PLL clock at 80MHz, driven by the +16MHz high speed internal oscillator. + +Serial Port +----------- + +EVAL-ADIN2111EBZ has 1 U(S)ART. The Zephyr console output is assigned to UART1 that is connected +to a FT232, available through Micro USB connector. Default settings are 115200 8N1. +Same UART1 TX and RX cmos signals are available before the FT232, at P9 connector. + + +Programming and Debugging +************************* + +Flashing +======== + +EVAL-ADIN2111EBZ includes an ST-LINK/V2-1 JTAG/SWD 10 or 20 pin connector. This interface is +supported by the openocd version included in Zephyr SDK. + +Flashing an application to Discovery kit +----------------------------------------- + +Connect the EVAL-ADIN2111EBZ to your host computer using the USB port, then run a serial host +program to connect with your ADI board. For example: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ADI_EVAL-ADIN2111EBZ_XXXXXX-12-if00-port0 + +where XXXXXX is the serial number of the connected device. +Then, build and flash in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin2111ebz + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_eval_adin2111ebz + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_eval_adin2111ebz + :maybe-skip-config: + :goals: debug + +.. _EVAL-ADIN2111EBZ evaluation board website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin2111.html + +.. _EVAL-ADIN2111EBZ board User Guide: + https://wiki.analog.com/resources/eval/user-guides/eval-adin2111ebz-user-guide + +.. _ADIN2111 Datasheet: + https://www.analog.com/media/en/technical-documentation/data-sheets/adin2111.pdf + +.. _STM32L4S5QII3P reference manual: + https://www.st.com/resource/en/reference_manual/rm0432-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf diff --git a/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake b/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake new file mode 100644 index 00000000000..44653c797ad --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/pre_dt_board.cmake @@ -0,0 +1 @@ +list(APPEND EXTRA_DTC_FLAGS "-Wno-simple_bus_reg") diff --git a/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg b/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg new file mode 100644 index 00000000000..295299f2fbe --- /dev/null +++ b/boards/arm/adi_eval_adin2111ebz/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/stm32l4discovery.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/boards/arm/adi_sdp_k1/Kconfig.board b/boards/arm/adi_sdp_k1/Kconfig.board new file mode 100644 index 00000000000..8aa4b969d61 --- /dev/null +++ b/boards/arm/adi_sdp_k1/Kconfig.board @@ -0,0 +1,8 @@ +# ADI SDP-K1 board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ADI_SDP_K1 + bool "ADI SDP-K1 Controller Board" + depends on SOC_STM32F469XX diff --git a/boards/arm/adi_sdp_k1/Kconfig.defconfig b/boards/arm/adi_sdp_k1/Kconfig.defconfig new file mode 100644 index 00000000000..03e3bd4cdeb --- /dev/null +++ b/boards/arm/adi_sdp_k1/Kconfig.defconfig @@ -0,0 +1,15 @@ +# ADI SDP-K1 board configuration + +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ADI_SDP_K1 + +config BOARD + default "adi_sdp_k1" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_ADI_SDP_K1 diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1.dts b/boards/arm/adi_sdp_k1/adi_sdp_k1.dts new file mode 100644 index 00000000000..91aea8c60df --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1.dts @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "arduino_r3_connector.dtsi" + +/ { + model = "Analog Devices Inc. SDP-K1 board"; + compatible = "adi,sdp-k1"; + + chosen { + zephyr,console = &uart5; + zephyr,shell-uart = &uart5; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,ccm = &ccm0; + }; + + leds { + compatible = "gpio-leds"; + status_led: led_ds3 { + gpios = <&gpiok 4 GPIO_ACTIVE_HIGH>; + label = "Status DS3"; + }; + green_led_1: led_ds4 { + gpios = <&gpiok 5 GPIO_ACTIVE_HIGH>; + label = "User LD1"; + }; + orange_led_2: led_ds5 { + gpios = <&gpiok 6 GPIO_ACTIVE_HIGH>; + label = "User LD2"; + }; + red_led_3: led_ds6 { + gpios = <&gpiok 7 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + }; + + aliases { + led0 = &status_led; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&pll { + div-m = <8>; + mul-n = <336>; + div-p = <2>; + div-q = <7>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <4>; + apb2-prescaler = <2>; +}; + +&uart5 { + pinctrl-0 = <&uart5_tx_pc12 &uart5_rx_pd2>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml b/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml new file mode 100644 index 00000000000..800bedab7de --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1.yaml @@ -0,0 +1,13 @@ +identifier: adi_sdp_k1 +name: ADI SDP-K1 +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 384 +flash: 2048 +supported: + - gpio +vendor: adi diff --git a/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig b/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig new file mode 100644 index 00000000000..94a8f52809e --- /dev/null +++ b/boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32F4X=y +CONFIG_SOC_STM32F469XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi b/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..53c9a871173 --- /dev/null +++ b/boards/arm/adi_sdp_k1/arduino_r3_connector.dtsi @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 BayLibre + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 2 0>, /* A0 */ + <1 0 &gpioa 4 0>, /* A1 */ + <2 0 &gpioa 6 0>, /* A2 */ + <3 0 &gpioc 1 0>, /* A3 */ + <4 0 &gpioc 4 0>, /* A4 */ + <5 0 &gpioc 5 0>, /* A5 */ + <6 0 &gpioa 1 0>, /* D0 */ + <7 0 &gpioa 0 0>, /* D1 */ + <8 0 &gpiog 7 0>, /* D2 */ + <9 0 &gpiod 12 0>, /* D3 */ + <10 0 &gpiog 9 0>, /* D4 */ + <11 0 &gpioa 11 0>, /* D5 */ + <12 0 &gpioa 10 0>, /* D6 */ + <13 0 &gpiog 10 0>, /* D7 */ + <14 0 &gpiog 11 0>, /* D8 */ + <15 0 &gpiob 15 0>, /* D9 */ + <16 0 &gpioa 15 0>, /* D10 */ + <17 0 &gpioa 7 0>, /* D11 */ + <18 0 &gpiob 4 0>, /* D12 */ + <19 0 &gpiob 3 0>, /* D13 */ + <20 0 &gpiob 7 0>, /* D14 */ + <21 0 &gpiob 8 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; +arduino_serial: &usart2 {}; diff --git a/boards/arm/adi_sdp_k1/board.cmake b/boards/arm/adi_sdp_k1/board.cmake new file mode 100644 index 00000000000..8a8885e9a95 --- /dev/null +++ b/boards/arm/adi_sdp_k1/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32F469NI" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp new file mode 100644 index 00000000000..ea8add4d7d7 Binary files /dev/null and b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1.webp differ diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp new file mode 100644 index 00000000000..a3729bcf6f4 Binary files /dev/null and b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_120pin.webp differ diff --git a/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp new file mode 100644 index 00000000000..5712fb6f595 Binary files /dev/null and b/boards/arm/adi_sdp_k1/doc/img/adi_sdp_k1_arduino.webp differ diff --git a/boards/arm/adi_sdp_k1/doc/index.rst b/boards/arm/adi_sdp_k1/doc/index.rst new file mode 100644 index 00000000000..177f7bf3550 --- /dev/null +++ b/boards/arm/adi_sdp_k1/doc/index.rst @@ -0,0 +1,184 @@ +.. _adi_sdp_k1: + +ADI SDP-K1 +########## + +Overview +******** + +The EVAL-SDP-CK1Z (SDP-K1) controller board is a system demonstration platform +(SDP) from Analog Devices designed to connect to evaluation shields containing +ADI components. + +- STM32 microcontroller in BGA216 package +- USB 2.0 device with USB-C connector +- USB debug interface supporting CMSIS-DAP through a NXP Freescale + microcontroller +- Flexible board power supply + - USB VBUS 5 V max. 500 mA + - 5.5mm DC power jack 7 - 12 V min. 300 mA + - VIN from Arduino* compatible connectors + - VIN from 120-pin connector 5 V min. 300 mA +- 3 color LEDs (green, orange, red) and 1 status LED +- One push-buttons: RESET +- 16MB SDRAM +- Arduino UNO and 120-pin SDP connectors + +.. figure:: img/adi_sdp_k1.webp + :align: center + :alt: ADI SDP-K1 + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +More information about the board can be found on the `ADI SDP-K1 website`_. + +Hardware +******** + +ADI SDP-K1 provides the following hardware components: + +- STM32F469NIH6 in BGA216 package +- ARM |reg| 32-bit Cortex |reg| -M4 CPU with FPU +- 180 MHz max CPU frequency +- VDD of 1.8 V or 3.3 V +- 2 MB Flash +- 384 KB SRAM +- GPIO with external interrupt capability +- LCD parallel interface, 8080/6800 modes +- LCD TFT controller supporting up to XGA resolution +- MIPI |reg| DSI host controller supporting up to 720p 30Hz resolution +- 3x12-bit ADC with 24 channels +- 2x12-bit D/A converters +- RTC +- Advanced-control Timer +- General Purpose Timers (17) +- Watchdog Timers (2) +- USART/UART (8) +- I2C (3) +- SPI (6) +- 1xSAI (serial audio interface) +- SDIO +- 2xCAN +- USB 2.0 OTG FS with on-chip PHY +- USB 2.0 OTG HS/FS with dedicated DMA, on-chip full-speed PHY and ULPI +- 10/100 Ethernet MAC with dedicated DMA +- 8- to 14-bit parallel camera +- CRC calculation unit +- True random number generator +- DMA Controller + +More information about STM32F469NI can be found here: + - `STM32F469NI product page`_ + - `STM32F469 reference manual`_ + +Supported Features +================== + +The Zephyr stm32f469i_disco board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration can be found in the defconfig file: + + ``boards/arm/adi_sdp_k1/adi_sdp_k1_defconfig`` + +Pin Mapping +=========== + +For more details please refer to `EVAL-SDP-CK1Z User Guide`_. + +Arduino UNO headers +------------------- + +.. figure:: img/adi_sdp_k1_arduino.webp + :align: center + :alt: ADI SDP-K1 Arduino UNO headers pinout + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +120-pin SDP connector +--------------------- + +.. figure:: img/adi_sdp_k1_120pin.webp + :align: center + :alt: ADI SDP-K1 120-pin SDP connector pinout + + ADI SDP-K1 (Credit: Analog Devices, Inc.) + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_5 TX/RX : P2 (DAPLink USB-C) +- UART_5 TX/RX : P8 (DAPLink two position through hole) +- LED1 : DS6 (Red) +- LED2 : DS5 (Orange) +- LED3 : DS4 (Green) +- LED4 : DS4 (Status) + +Programming and Debugging +************************* + +The ADI SDP-K1 be programmed over USB using the DAPLink firmware running on an +embedded NXP Freescale microcontroller or a 10-pin ``DEBUG`` header connected +to a STLINK debugger. + +DAPLink exposes a storage device, as well as USB HID and CDC Endpoints, to the +host. For more details please refer to the `Official DAPLink website`_. + +Flashing +======== + +Flashing an application with a STLINK debugger +---------------------------------------------- + +First, connect the STLINK debugger to your host computer using the Micro-USB port. +Then attach the debugger to the 10-pin ``DEBUG`` header on the SDP-K1. Finally +connect the SDP-K1 to your host computer using the USB-C port. + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D /dev/serial/by-id/usb-ARM_DAPLink_CMSIS-DAP_<...> + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: adi_sdp_k1 + :goals: build flash + +You should see the following message on the console: + +.. code-block:: console + + Hello World! adi_sdp_k1 + +Debugging +========= + +.. _ADI SDP-K1 website: + https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/sdp-k1.html + +.. _EVAL-SDP-CK1Z User Guide: + https://www.analog.com/media/en/technical-documentation/user-guides/EVAL-SDP-CK1Z-UG-1539.pdf + +.. _STM32F469NI product page: + https://www.st.com/en/microcontrollers/stm32f469ni.html + +.. _STM32F469 reference manual: + https://www.st.com/resource/en/reference_manual/dm00127514.pdf + +.. _Official DAPLink website: + https://daplink.io/ diff --git a/boards/arm/adi_sdp_k1/revision.cmake b/boards/arm/adi_sdp_k1/revision.cmake new file mode 100644 index 00000000000..b82df11ae6a --- /dev/null +++ b/boards/arm/adi_sdp_k1/revision.cmake @@ -0,0 +1,8 @@ +# Copyright (c) 2024 BayLibre +# SPDX-License-Identifier: Apache-2.0 + +board_check_revision( + FORMAT LETTER + DEFAULT_REVISION E + VALID_REVISIONS B E +) diff --git a/boards/arm/adi_sdp_k1/support/openocd.cfg b/boards/arm/adi_sdp_k1/support/openocd.cfg new file mode 100644 index 00000000000..d1426b667d5 --- /dev/null +++ b/boards/arm/adi_sdp_k1/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/st_nucleo_f4.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig b/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig index f14c801d3b3..1edc7b5581b 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig +++ b/boards/arm/apollo4p_blue_kxr_evb/Kconfig.defconfig @@ -5,3 +5,34 @@ config BOARD default "apollo4p_blue_kxr_evb" depends on BOARD_APOLLO4P_BLUE_KXR_EVB + +if BT + +config MAIN_STACK_SIZE + default 2048 + +choice BT_HCI_BUS_TYPE + default BT_AMBIQ_HCI +endchoice + +config BT_BUF_ACL_TX_COUNT + default 14 + +config BT_BUF_CMD_TX_SIZE + default 255 + +config BT_BUF_EVT_RX_SIZE + default 255 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_BUF_ACL_RX_SIZE + default 251 + +# L2CAP SDU/PDU TX MTU +# BT_L2CAP_RX_MTU = CONFIG_BT_BUF_ACL_RX_SIZE - BT_L2CAP_HDR_SIZE +config BT_L2CAP_TX_MTU + default 247 + +endif # BT diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts index 68e0195056c..f9aa3c11c31 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.dts @@ -6,6 +6,7 @@ / { model = "Ambiq Apollo4 Blue Plus KXR evaluation board"; compatible = "ambiq,apollo4p_blue_kxr_evb"; + chosen { zephyr,itcm = &tcm; zephyr,sram = &sram0; @@ -15,10 +16,43 @@ zephyr,uart-pipe = &uart0; zephyr,flash-controller = &flash; }; + aliases { watchdog0 = &wdt0; + led0 = &led0; + led1 = &led1; + led2 = &led2; + sw0 = &button0; + sw1 = &button1; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0_31 30 GPIO_ACTIVE_LOW>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio0_31 16 GPIO_ACTIVE_LOW>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio64_95 27 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; }; + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 17 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN1"; + }; + }; }; &uart0 { @@ -48,7 +82,13 @@ compatible = "ambiq,spi"; pinctrl-0 = <&spi1_default>; pinctrl-names = "default"; - clock-frequency = <1000000>; + clock-frequency = ; + status = "okay"; +}; + +&iom4 { + pinctrl-0 = <&spi4_default>; + pinctrl-names = "default"; status = "okay"; }; @@ -86,3 +126,19 @@ pinctrl-names = "default"; status = "okay"; }; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; + +&gpio64_95 { + status = "okay"; +}; + +&gpio96_127 { + status = "okay"; +}; diff --git a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml index bbdf0477a36..d9e9f244d86 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml +++ b/boards/arm/apollo4p_blue_kxr_evb/apollo4p_blue_kxr_evb.yaml @@ -9,6 +9,14 @@ toolchain: - gnuarmemb supported: - uart + - watchdog + - counter + - gpio + - spi + - i2c + - clock_control + - ble testing: ignore_tags: - net +vendor: ambiq diff --git a/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst b/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst index 35592c0b911..75aa74ac34e 100644 --- a/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst +++ b/boards/arm/apollo4p_blue_kxr_evb/doc/index.rst @@ -49,6 +49,12 @@ The Apollo4 Blue Plus KXR EVB board configuration supports the following hardwar +-----------+------------+-------------------------------------+ | WDT | on-chip | watchdog | +-----------+------------+-------------------------------------+ +| SPI(M) | on-chip | spi | ++-----------+------------+-------------------------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+-------------------------------------+ | RADIO | on-chip | bluetooth | +-----------+------------+-------------------------------------+ diff --git a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi index abc9f9c9c54..b7b285d6ad8 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi +++ b/boards/arm/apollo4p_evb/apollo4p_evb-pinctrl.dtsi @@ -5,6 +5,7 @@ */ #include +#include "apollo4p_evb_connector.dtsi" &pinctrl { uart0_default: uart0_default { @@ -97,6 +98,7 @@ }; group2 { pinmux = ; + drive-strength = "0.5"; drive-push-pull; ambiq,iom-nce-module = <4>; }; diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.dts b/boards/arm/apollo4p_evb/apollo4p_evb.dts index 059b880388d..8b87f96ac68 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.dts +++ b/boards/arm/apollo4p_evb/apollo4p_evb.dts @@ -6,6 +6,7 @@ / { model = "Ambiq Apollo4 Plus evaluation board"; compatible = "ambiq,apollo4p_evb"; + chosen { zephyr,itcm = &tcm; zephyr,sram = &sram0; @@ -14,8 +15,42 @@ zephyr,shell-uart = &uart0; zephyr,uart-pipe = &uart0; }; + aliases { watchdog0 = &wdt0; + led0 = &led0; + led1 = &led1; + led2 = &led2; + sw0 = &button0; + sw1 = &button1; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0_31 30 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "LED 0"; + }; + led1: led_1 { + gpios = <&gpio64_95 26 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "LED 1"; + }; + led2: led_2 { + gpios = <&gpio96_127 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "LED 2"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0_31 18 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN0"; + }; + button1: button_1 { + gpios = <&gpio0_31 19 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "BTN1"; + }; }; }; @@ -34,7 +69,7 @@ status = "okay"; }; -&iom0 { +&iom0_i2c { compatible = "ambiq,i2c"; pinctrl-0 = <&i2c0_default>; pinctrl-names = "default"; @@ -42,7 +77,7 @@ status = "okay"; }; -&iom1 { +&iom1_spi { compatible = "ambiq,spi"; pinctrl-0 = <&spi1_default>; pinctrl-names = "default"; @@ -55,3 +90,31 @@ pinctrl-names = "default"; status = "okay"; }; + +&mspi1 { + pinctrl-0 = <&mspi1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&mspi2 { + pinctrl-0 = <&mspi2_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0_31 { + status = "okay"; +}; + +&gpio32_63 { + status = "okay"; +}; + +&gpio64_95 { + status = "okay"; +}; + +&gpio96_127 { + status = "okay"; +}; diff --git a/boards/arm/apollo4p_evb/apollo4p_evb.yaml b/boards/arm/apollo4p_evb/apollo4p_evb.yaml index b2c0ecd954b..1aa0fbf75d4 100644 --- a/boards/arm/apollo4p_evb/apollo4p_evb.yaml +++ b/boards/arm/apollo4p_evb/apollo4p_evb.yaml @@ -9,6 +9,11 @@ toolchain: - gnuarmemb supported: - uart + - watchdog + - counter + - gpio + - spi + - i2c testing: ignore_tags: - net diff --git a/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi new file mode 100644 index 00000000000..e083db991e2 --- /dev/null +++ b/boards/arm/apollo4p_evb/apollo4p_evb_connector.dtsi @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + ambiq_header: connector { + compatible = "ambiq-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffff80>; + gpio-map-pass-thru = <0 0x7f>; + gpio-map = <0 0 &gpio0_31 0 0>, /* IOS_SPI_SCK, IOS_I2C_SCL, MSPI2_CE0 */ + <1 0 &gpio0_31 1 0>, /* IOS_SPI_MOSI, IOS_I2C_SDA, MSPI0_CE0 */ + <2 0 &gpio0_31 2 0>, /* IOS_SPI_MISO */ + <3 0 &gpio0_31 3 0>, /* IOS_CE */ + <4 0 &gpio0_31 4 0>, /* IOS_INT */ + <5 0 &gpio0_31 5 0>, /* IOM0_SPI_SCK, IOM0_I2C_SCL */ + <6 0 &gpio0_31 6 0>, /* IOM0_SPI_MOSI, IOM0_I2C_SDA */ + <7 0 &gpio0_31 7 0>, /* See am_hal_pins.h file for further info */ + <8 0 &gpio0_31 8 0>, /* IOM1_SPI_SCK, IOM1_I2C_SCL */ + <9 0 &gpio0_31 9 0>, /* IOM1_SPI_MOSI, IOM1_I2C_SDA */ + <10 0 &gpio0_31 10 0>, /* IOM1_SPI_MISO */ + <11 0 &gpio0_31 11 0>, /* UART2_RX, IOM1_CS, I2S0_CLK */ + <12 0 &gpio0_31 12 0>, /* ADCSE7, UART1_TX, I2S0_DATA, I2S0_SDOUT */ + <13 0 &gpio0_31 13 0>, /* ADCSE6, UART2_TX, I2S0_WS */ + <14 0 &gpio0_31 14 0>, /* ADCSE5, UART1_RX, I2S0_SDIN */ + <15 0 &gpio0_31 15 0>, /* ADCSE4 */ + <16 0 &gpio0_31 16 0>, /* ADCSE3, I2S1_CLK */ + <17 0 &gpio0_31 17 0>, /* ADCSE2, UART3_RTS, I2S1_DATA */ + <18 0 &gpio0_31 18 0>, /* BUTTON0, ADCSE1, I2S1_WS */ + <19 0 &gpio0_31 19 0>, /* BUTTON1, ADCSE0, UART3_CTS, I2S1_SDIN */ + <20 0 &gpio0_31 19 0>, /* SWDCK */ + <21 0 &gpio0_31 19 0>, /* SWDIO */ + <22 0 &gpio0_31 22 0>, /* IOM7_SPI_SCK, IOM7_I2C_SCL */ + <23 0 &gpio0_31 23 0>, /* IOM7_SPI_MOSI, IOM7_I2C_SDA */ + <24 0 &gpio0_31 24 0>, /* IOM7_SPI_MISO */ + <25 0 &gpio0_31 25 0>, /* IOM2_SPI_SCK, IOM2_I2C_SCL */ + <26 0 &gpio0_31 26 0>, /* IOM2_SPI_MOSI, IOM2_I2C_SDA */ + <27 0 &gpio0_31 27 0>, /* IOM2_SPI_MISO */ + <28 0 &gpio0_31 28 0>, /* ITM_SWO */ + <29 0 &gpio0_31 29 0>, /* See am_hal_pins.h file for further info */ + <30 0 &gpio0_31 30 0>, /* LED1, IOM6_CS */ + <31 0 &gpio0_31 31 0>, /* IOM3_SPI_SCK, IOM3_I2C_SCL */ + <32 0 &gpio32_63 0 0>, /* IOM3_SPI_MOSI, IOM3_I2C_SDA */ + <33 0 &gpio32_63 1 0>, /* IOM3_SPI_MISO */ + <34 0 &gpio32_63 2 0>, /* IOM4_SPI_SCK, IOM4_I2C_SCL */ + <35 0 &gpio32_63 3 0>, /* IOM4_SPI_MOSI, IOM4_I2C_SDA */ + <36 0 &gpio32_63 4 0>, /* IOM4_SPI_MISO */ + <37 0 &gpio32_63 5 0>, /* IOM2_CS, MSPI1_D0, X16SPI_D8 */ + <38 0 &gpio32_63 6 0>, /* MSPI1_D1, X16SPI_D9 */ + <39 0 &gpio32_63 7 0>, /* MSPI1_D2, X16SPI_D10 */ + <40 0 &gpio32_63 8 0>, /* MSPI1_D3, X16SPI_D11 */ + <41 0 &gpio32_63 9 0>, /* MSPI1_D4, X16SPI_D12 */ + <42 0 &gpio32_63 10 0>, /* MSPI1_D5, X16SPI_D13 */ + <43 0 &gpio32_63 11 0>, /* MSPI1_D6, X16SPI_D14 */ + <44 0 &gpio32_63 12 0>, /* MSPI1_D7, X16SPI_D15 */ + <45 0 &gpio32_63 13 0>, /* MSPI1_SCK, X16SPI_DQS1DM1 */ + <46 0 &gpio32_63 14 0>, /* MSPI1_DQSDM */ + <47 0 &gpio32_63 15 0>, /* COM_UART_RX, IOM5_SPI_SCK, IOM5_I2C_SCL */ + <48 0 &gpio32_63 16 0>, /* IOM5_SPI_MOSI, IOM5_I2C_SDA */ + <49 0 &gpio32_63 17 0>, /* UART1_RTS, IOM5_SPI_MISO */ + <50 0 &gpio32_63 18 0>, /* UART2_RTS, ETM_TRACECLK, PDM0_CLK */ + <51 0 &gpio32_63 19 0>, /* UART1_CTS, EMT_TRACE0, PDM0_DATA */ + <52 0 &gpio32_63 20 0>, /* UART2_CTS, MSPI0_CE1, ETM_TRACE1, PDM1_CLK */ + <53 0 &gpio32_63 21 0>, /* ETM_TRACE2, PDM1_DATA */ + <54 0 &gpio32_63 22 0>, /* ETM_TRACE3, PDM2_CLK */ + <55 0 &gpio32_63 23 0>, /* ETM_TRACECTL, PDM2_DATA */ + <56 0 &gpio32_63 24 0>, /* PDM3_CLK */ + <57 0 &gpio32_63 25 0>, /* PDM3_DATA */ + <58 0 &gpio32_63 26 0>, /* COM_UART_RTS, UART0_RTS */ + <59 0 &gpio32_63 27 0>, /* COM_UART_CTS, UART0_CTS */ + <60 0 &gpio32_63 28 0>, /* COM_UART_TX, UART0_TX, IOM5_CS */ + <61 0 &gpio32_63 29 0>, /* UART3_TX, IOM6_SPI_SCK, IOM6_I2C_SCL */ + <62 0 &gpio32_63 30 0>, /* IOM6_SPI_MOSI, IOM6_I2C_SDA */ + <63 0 &gpio32_63 31 0>, /* UART3_RX, IOM6_SPI_MISO */ + <64 0 &gpio64_95 0 0>, /* MSPI0_D0, X16SPI_D0 */ + <65 0 &gpio64_95 1 0>, /* MSPI0_D1, X16SPI_D1 */ + <66 0 &gpio64_95 2 0>, /* MSPI0_D2, X16SPI_D2 */ + <67 0 &gpio64_95 3 0>, /* MSPI0_D3, X16SPI_D3 */ + <68 0 &gpio64_95 4 0>, /* MSPI0_D4, X16SPI_D4 */ + <69 0 &gpio64_95 5 0>, /* MSPI0_D5, X16SPI_D5 */ + <70 0 &gpio64_95 6 0>, /* MSPI0_D6, X16SPI_D6 */ + <71 0 &gpio64_95 7 0>, /* MSPI0_D7, X16SPI_D7 */ + <72 0 &gpio64_95 8 0>, /* IOM0_CS, MSPI0_SCK, X16SPI_SCK */ + <73 0 &gpio64_95 9 0>, /* MSPI0_DQSDM, X16SPI_DQSDM */ + <74 0 &gpio64_95 10 0>, /* MSPI2_D0 */ + <75 0 &gpio64_95 11 0>, /* MSPI2_D1 */ + <76 0 &gpio64_95 12 0>, /* MSPI2_D2 */ + <77 0 &gpio64_95 13 0>, /* MSPI2_D3 */ + <78 0 &gpio64_95 14 0>, /* MSPI2_D4 */ + <79 0 &gpio64_95 15 0>, /* IOM4_CS, MSPI2_D5, SDIF_DAT4 */ + <80 0 &gpio64_95 16 0>, /* MSPI2_D6, SDIF_DAT5 */ + <81 0 &gpio64_95 17 0>, /* MSPI2_D7, SDIF_DAT6 */ + <82 0 &gpio64_95 18 0>, /* MSPI2_D8, SDIF_DAT7 */ + <83 0 &gpio64_95 19 0>, /* MSPI2_DQSDM, SDIF_CMD */ + <84 0 &gpio64_95 20 0>, /* SDIF_DAT0 */ + <85 0 &gpio64_95 21 0>, /* IOM3_CS, SDIF_DAT1 */ + <86 0 &gpio64_95 22 0>, /* MSPI2_CE1, SDIF_DAT2 */ + <87 0 &gpio64_95 23 0>, /* SDIF_DAT3 */ + <88 0 &gpio64_95 24 0>, /* IOM7_CS, SDIF_CLKOUT */ + <89 0 &gpio64_95 25 0>, /* MSPI1_CE0, X16SPI_CE0, X16SPI_CE1 */ + <90 0 &gpio64_95 26 0>, /* LED0 */ + <91 0 &gpio64_95 27 0>, /* MSPI1_CE1, */ + <92 0 &gpio64_95 28 0>, /* See am_hal_pins.h file for further info */ + <93 0 &gpio64_95 29 0>, /* See am_hal_pins.h file for further info */ + <94 0 &gpio64_95 30 0>, /* See am_hal_pins.h file for further info */ + <95 0 &gpio64_95 31 0>, /* See am_hal_pins.h file for further info */ + <96 0 &gpio96_127 0 0>, /* See am_hal_pins.h file for further info */ + <97 0 &gpio96_127 1 0>, /* See am_hal_pins.h file for further info */ + <98 0 &gpio96_127 2 0>, /* See am_hal_pins.h file for further info */ + <99 0 &gpio96_127 3 0>, /* See am_hal_pins.h file for further info */ + <100 0 &gpio96_127 4 0>, /* See am_hal_pins.h file for further info */ + <101 0 &gpio96_127 5 0>, /* VDDUSB0P9_SWITCH */ + <102 0 &gpio96_127 6 0>, /* See am_hal_pins.h file for further info */ + <103 0 &gpio96_127 7 0>, /* VDDUSB33_SWITCH */ + <104 0 &gpio96_127 8 0>; /* VDD18_SWITCH */ + }; +}; + +spi1: &iom1_spi {}; diff --git a/boards/arm/apollo4p_evb/doc/index.rst b/boards/arm/apollo4p_evb/doc/index.rst index 21b967893e1..42f0f360329 100644 --- a/boards/arm/apollo4p_evb/doc/index.rst +++ b/boards/arm/apollo4p_evb/doc/index.rst @@ -46,6 +46,12 @@ The Apollo4P EVB board configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | UART | on-chip | serial | +-----------+------------+-------------------------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+-------------------------------------+ +| SPI(M) | on-chip | spi | ++-----------+------------+-------------------------------------+ +| I2C(M) | on-chip | i2c | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: ``boards/arm/apollo4p_evb/apollo4p_evb_defconfig``. diff --git a/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi b/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi index ee7eb1229fc..d0e8863967e 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1.dtsi @@ -38,3 +38,7 @@ d2ppre2 = <2>; d3ppre = <2>; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts index ef3544ef958..4459780243b 100644 --- a/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts +++ b/boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts @@ -139,6 +139,8 @@ status = "okay"; pinctrl-0 = <&fdcan2_tx_pb13 &fdcan2_rx_pb5>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; bus-speed = <125000>; bus-speed-data = <1000000>; }; @@ -169,11 +171,10 @@ pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/arduino_giga_r1/board.cmake b/boards/arm/arduino_giga_r1/board.cmake index 74efbc12411..849f9f933f1 100644 --- a/boards/arm/arduino_giga_r1/board.cmake +++ b/boards/arm/arduino_giga_r1/board.cmake @@ -2,8 +2,12 @@ if(CONFIG_BOARD_ARDUINO_GIGA_R1_M7) board_runner_args(jlink "--device=STM32H747XI_M7" "--speed=4000") +board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_arduino_giga_r1_m7.cfg") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) elseif(CONFIG_BOARD_ARDUINO_GIGA_R1_M4) board_runner_args(jlink "--device=STM32H747XI_M4" "--speed=4000") +board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_arduino_giga_r1_m4.cfg") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu1) endif() board_runner_args(dfu-util "--pid=2341:0366" "--alt=0" "--dfuse") board_runner_args(blackmagicprobe "--connect-rst") @@ -11,3 +15,4 @@ board_runner_args(blackmagicprobe "--connect-rst") include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg new file mode 100644 index 00000000000..ddceef92cb1 --- /dev/null +++ b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m4.cfg @@ -0,0 +1,12 @@ + +source [find interface/stlink.cfg] + +transport select hla_swd + +set DUAL_BANK 1 + +set DUAL_CORE 1 + +source [find target/stm32h7x.cfg] + +reset_config srst_only srst_nogate connect_assert_srst diff --git a/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg new file mode 100644 index 00000000000..75d441d1809 --- /dev/null +++ b/boards/arm/arduino_giga_r1/support/openocd_arduino_giga_r1_m7.cfg @@ -0,0 +1,28 @@ + +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32h7x.cfg] + +# Use connect_assert_srst here to be able to program +# even when core is in sleep mode +reset_config srst_only srst_nogate connect_assert_srst + +$_CHIPNAME.cpu0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + gdb_breakpoint_override hard +} + +$_CHIPNAME.cpu0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +# Due to the use of connect_assert_srst, running gdb requires +# to reset halt just after openocd init. +rename init old_init +proc init {} { + old_init + reset halt +} diff --git a/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi b/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi index 200db7f94c7..3d31ede313f 100644 --- a/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi +++ b/boards/arm/arduino_nano_33_ble/arduino_nano_33_ble-common.dtsi @@ -189,6 +189,10 @@ arduino_spi: &spi2 { status = "okay"; }; +&gpiote { + status = "okay"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; diff --git a/boards/arm/arduino_opta_m4/Kconfig.board b/boards/arm/arduino_opta_m4/Kconfig.board new file mode 100644 index 00000000000..cce1cd6337a --- /dev/null +++ b/boards/arm/arduino_opta_m4/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ARDUINO_OPTA_M4 + bool "Arduino OPTA Programmable Logic Controller M4 Core" + depends on SOC_STM32H747XX + select CPU_CORTEX_M4 diff --git a/boards/arm/arduino_opta_m4/Kconfig.defconfig b/boards/arm/arduino_opta_m4/Kconfig.defconfig new file mode 100644 index 00000000000..be17c009555 --- /dev/null +++ b/boards/arm/arduino_opta_m4/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ARDUINO_OPTA_M4 + +config BOARD + default "arduino_opta_m4" + +endif # BOARD_ARDUINO_OPTA_M4 diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4.dts b/boards/arm/arduino_opta_m4/arduino_opta_m4.dts new file mode 100644 index 00000000000..bc74a2691f4 --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4.dts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Felipe Neves + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "Arduino OPTA M4 core Programmable Logic Controller"; + compatible = "arduino,opta-m4"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + status_led_1: led_1 { + gpios = <&gpioi 0 GPIO_ACTIVE_LOW>; + }; + status_led_2: led_2 { + gpios = <&gpioi 1 GPIO_ACTIVE_LOW>; + }; + status_led_3: led_3 { + gpios = <&gpioi 3 GPIO_ACTIVE_LOW>; + }; + status_led_4: led_4 { + gpios = <&gpioh 15 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + user_button: button { + gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + sw0 = &user_button; + led0 = &status_led_1; + }; +}; + +&flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@80000 { + label = "image-0"; + reg = <0x00080000 DT_SIZE_K(512)>; + }; + }; +}; + +&rcc { + d1cpre = <1>; + hpre = <2>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; + clock-frequency = ; +}; diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml b/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml new file mode 100644 index 00000000000..4030cb402f6 --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4.yaml @@ -0,0 +1,21 @@ +identifier: arduino_opta_m4 +name: ARDUINO OPTA (M4) +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 288 +flash: 512 +supported: + - gpio +testing: + ignore_tags: + - mpu + - nfc + - net + - flash + - input + - mcumgr +vendor: arduino diff --git a/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig b/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig new file mode 100644 index 00000000000..bcf01ccabfb --- /dev/null +++ b/boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Felipe Neves +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H747XX=y + +CONFIG_BOARD_ARDUINO_OPTA_M4=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y + +# Use zephyr,code-partition as flash offset +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/arduino_opta_m4/board.cmake b/boards/arm/arduino_opta_m4/board.cmake new file mode 100644 index 00000000000..029ae806f4d --- /dev/null +++ b/boards/arm/arduino_opta_m4/board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(dfu-util "--pid=2341:0364" "--alt=0" "--dfuse") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) diff --git a/boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg b/boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg new file mode 100644 index 00000000000..4b3a8e54d57 Binary files /dev/null and b/boards/arm/arduino_opta_m4/doc/img/arduino_opta.jpeg differ diff --git a/boards/arm/arduino_opta_m4/doc/index.rst b/boards/arm/arduino_opta_m4/doc/index.rst new file mode 100644 index 00000000000..90f9497db33 --- /dev/null +++ b/boards/arm/arduino_opta_m4/doc/index.rst @@ -0,0 +1,177 @@ +.. _arduino_opta_m4_board: + +Arduino OPTA M4-Core +####################### + +Overview +******** + +The Arduino™ Opta® is a secure micro Programmable Logic Controller (PLC) +with Industrial Internet of Things (IoT) capabilities. + +Developed in partnership with Finder®, this device supports both the Arduino +programming language and standard IEC-61131-3 PLC programming languages, +such as Ladder Diagram (LD), Sequential Function Chart (SFC), +Function Block Diagram (FBD), Structured Text (ST), and Instruction List (IL), +making it an ideal device for automation engineers. + +For Zephyr RTOS, only the M4 is supported for now, making the M7 run the PLC +tasks while the M4 core under Zephyr acts as a coprocessor. + +Additionally, the device features: + +- Ethernet compliant with IEEE802.3-2002 +- 16MB QSPI Flash +- 4 x green color status LEDs +- 1 x user push-button +- 1 x reset push-button accessible via pinhole +- 8 x analog inputs +- 4 x isolated relay outputs + +.. image:: img/arduino_opta.jpeg + :align: center + :alt: ARDUINO-OPTA + +More information about the board can be found at the `ARDUINO-OPTA website`_. +More information about STM32H747XIH6 can be found here: + +- `STM32H747XI on www.st.com`_ +- `STM32H747xx reference manual`_ +- `STM32H747xx datasheet`_ + +Supported Features +================== + +The current Zephyr arduino_opta_m4 board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| IPM | on-chip | virtual mailbox based on HSEM | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration per core can be found in the defconfig files: +``boards/arm/arduino_opta_m4/arduino_opta_m4_defconfig`` + +Pin Mapping +=========== + +ARDUINO OPTA M4 has access to the 9 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +For more details please refer to `ARDUINO-OPTA website`_. + +Default Zephyr Peripheral Mapping +--------------------------------- + +- Status LED1 : PI0 +- Status LED2 : PI1 +- Status LED3 : PI3 +- Status LED4 : PH15 +- User button : PE4 + +System Clock +============ + +The STM32H747I System Clock can be driven by an internal or external oscillator, +as well as by the main PLL clock. By default, the CPU2 (Cortex-M4) System clock +is driven at 240MHz. PLL clock is fed by a 25MHz high speed external clock. + +Resources sharing +================= + +The dual core nature of STM32H747 SoC requires sharing HW resources between the +two cores. This is done in 3 ways: + +- **Compilation**: Clock configuration is only accessible to M7 core. M4 core only + has access to bus clock activation and deactivation. +- **Static pre-compilation assignment**: Peripherals such as a UART are assigned in + devicetree before compilation. The user must ensure peripherals are not assigned + to both cores at the same time. +- **Run time protection**: Interrupt-controller and GPIO configurations could be + accessed by both cores at run time. Accesses are protected by a hardware semaphore + to avoid potential concurrent access issues. + +Programming and Debugging +************************* + +Applications for the ``arduino_opta_m4`` use the regular Zephyr build commands. +See :ref:`build_an_application` for more information about application builds. + +Flashing +======== + +Flashing operation will depend on the target to be flashed and the SoC +option bytes configuration. The OPTA has a DFU capable bootloader which +can be accessed by connecting the device to the USB, and then pressing +the RESET button shortly twice, the RESET-LED on the board will fade +indicating the board is in bootloader mode. + +By default: + + - CPU2 (Cortex-M4) boot address is set to 0x08180000 (OB: BOOT_CM4_ADD0) + +Zephyr flash configuration has been set to meet these default settings. + +Flashing an application to ARDUINO OPTA M4 +------------------------------------------ + +First, connect the device to your host computer using +the USB port to prepare it for flashing. Then build and flash your application. + +Here is an example for the :zephyr:code-sample:`blinky` application on M4 core. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: arduino_opta_m4 + :goals: build flash + +Starting the application on the ARDUINO OPTA M4 +----------------------------------------------- + +Make sure the option bytes are set to prevent the M4 from auto-starting, and +that the M7 side starts the M4 at the correct Flash address. + +This can be done by selecting in the Arduino IDE's "Tools" / "Flash Split" +menu the "1.5MB M7 + 0.5MB M4" option, and loading a sketch that contains +at least the following code: + + .. code-block:: cpp + + #include + + void setup() { + RPC.begin(); + } + + void loop() { } + +Debugging +========= + +Debugging is not yet supported by this board, since the debug port does +not have an easy access. + +.. _ARDUINO-OPTA website: + https://docs.arduino.cc/hardware/opta + +.. _STM32H747XI on www.st.com: + https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-high-performance-mcus/stm32h7-series/stm32h747-757/stm32h747xi.html + +.. _STM32H747xx reference manual: + https://www.st.com/resource/en/reference_manual/dm00176879.pdf + +.. _STM32H747xx datasheet: + https://www.st.com/resource/en/datasheet/stm32h747xi.pdf diff --git a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi index 653812e3e6a..87d85f27263 100644 --- a/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi +++ b/boards/arm/arduino_portenta_h7/arduino_portenta_h7-common.dtsi @@ -105,6 +105,8 @@ &fdcan1 { pinctrl-0 = <&fdcan1_rx_pb8 &fdcan1_tx_ph13>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; }; &rtc { @@ -116,3 +118,7 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "disabled"; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig index 8d44c120b3e..57abb934998 100644 --- a/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig +++ b/boards/arm/arduino_uno_r4/arduino_uno_r4_minima_defconfig @@ -10,6 +10,7 @@ CONFIG_BUILD_OUTPUT_HEX=y # enable uart driver CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y # enable console CONFIG_CONSOLE=y diff --git a/boards/arm/arty/arty_a7_arm_designstart_m3.dts b/boards/arm/arty/arty_a7_arm_designstart_m3.dts index 59a5ed88fa8..4191febff6e 100644 --- a/boards/arm/arty/arty_a7_arm_designstart_m3.dts +++ b/boards/arm/arty/arty_a7_arm_designstart_m3.dts @@ -25,7 +25,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/ast1030_evb/ast1030_evb_defconfig b/boards/arm/ast1030_evb/ast1030_evb_defconfig index 6a0e696b39b..62278d44213 100644 --- a/boards/arm/ast1030_evb/ast1030_evb_defconfig +++ b/boards/arm/ast1030_evb/ast1030_evb_defconfig @@ -5,7 +5,6 @@ CONFIG_SOC_SERIES_AST10X0=y CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=200000000 CONFIG_MAIN_STACK_SIZE=4096 -CONFIG_BOOTLOADER_SRAM_SIZE=0 CONFIG_FLASH_SIZE=0 CONFIG_FLASH_BASE_ADDRESS=0x0 CONFIG_XIP=n diff --git a/boards/arm/atsamc21n_xpro/doc/index.rst b/boards/arm/atsamc21n_xpro/doc/index.rst index bb060fe32a4..e7d7d2d5852 100644 --- a/boards/arm/atsamc21n_xpro/doc/index.rst +++ b/boards/arm/atsamc21n_xpro/doc/index.rst @@ -86,7 +86,7 @@ Pin Mapping The SAM C21N Xplained Pro evaluation kit has 4 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM C21 Family Datasheet`_ and the `SAM C21N +For more details please refer to `SAM C21 Family Datasheet`_ and the `SAM C21N Xplained Pro Schematic`_. Default Zephyr Peripheral Mapping: diff --git a/boards/arm/atsamd21_xpro/atsamd21_xpro.dts b/boards/arm/atsamd21_xpro/atsamd21_xpro.dts index e48e5afd467..d65d773a66f 100644 --- a/boards/arm/atsamd21_xpro/atsamd21_xpro.dts +++ b/boards/arm/atsamd21_xpro/atsamd21_xpro.dts @@ -75,7 +75,7 @@ compatible = "atmel,sam0-uart"; current-speed = <9600>; rxpo = <3>; - txpo = <2>; + txpo = <1>; pinctrl-0 = <&sercom0_uart_default>; pinctrl-names = "default"; diff --git a/boards/arm/atsamd21_xpro/doc/index.rst b/boards/arm/atsamd21_xpro/doc/index.rst index 9732c84d6fb..78ed6da63ff 100644 --- a/boards/arm/atsamd21_xpro/doc/index.rst +++ b/boards/arm/atsamd21_xpro/doc/index.rst @@ -87,7 +87,7 @@ Pin Mapping The SAM D21 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM D21 Family Datasheet`_ and the `SAM D21 +For more details please refer to `SAM D21 Family Datasheet`_ and the `SAM D21 Xplained Pro Schematic`_. .. image:: img/ATSAMD21-XPRO-pinout.jpg diff --git a/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi b/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi index eb96b72e339..102e6b2253e 100644 --- a/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi +++ b/boards/arm/atsaml21_xpro/atsaml21_xpro-pinctrl.dtsi @@ -56,4 +56,11 @@ ; }; }; + + usb0_default: usb0_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/arm/atsaml21_xpro/atsaml21_xpro.dts b/boards/arm/atsaml21_xpro/atsaml21_xpro.dts index 0e03a7e96f4..ee800d7ae95 100644 --- a/boards/arm/atsaml21_xpro/atsaml21_xpro.dts +++ b/boards/arm/atsaml21_xpro/atsaml21_xpro.dts @@ -141,4 +141,7 @@ zephyr_udc0: &usb0 { status = "okay"; + + pinctrl-0 = <&usb0_default>; + pinctrl-names = "default"; }; diff --git a/boards/arm/atsaml21_xpro/doc/index.rst b/boards/arm/atsaml21_xpro/doc/index.rst index 2051b9efa18..5c55f23d587 100644 --- a/boards/arm/atsaml21_xpro/doc/index.rst +++ b/boards/arm/atsaml21_xpro/doc/index.rst @@ -81,7 +81,7 @@ Pin Mapping The SAM L21 Xplained Pro evaluation kit has 2 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM L21 Family Datasheet`_ and the `SAM L21 +For more details please refer to `SAM L21 Family Datasheet`_ and the `SAM L21 Xplained Pro Schematic`_. .. image:: img/atsaml21-xpro-pinout.jpg diff --git a/boards/arm/atsamr21_xpro/doc/index.rst b/boards/arm/atsamr21_xpro/doc/index.rst index da9cb14a437..60d2c36ea32 100644 --- a/boards/arm/atsamr21_xpro/doc/index.rst +++ b/boards/arm/atsamr21_xpro/doc/index.rst @@ -64,7 +64,7 @@ Pin Mapping The SAM R21 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM R21 Family Datasheet`_ and the `SAM R21 +For more details please refer to `SAM R21 Family Datasheet`_ and the `SAM R21 Xplained Pro Schematic`_. .. image:: img/ATSAMR21-XPRO-pinout.jpg diff --git a/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi b/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi index 81cfb6a7bca..e7e01a22536 100644 --- a/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi +++ b/boards/arm/atsamr34_xpro/atsamr34_xpro-pinctrl.dtsi @@ -34,4 +34,11 @@ ; }; }; + + usb0_default: usb0_default { + group1 { + pinmux = , + ; + }; + }; }; diff --git a/boards/arm/atsamr34_xpro/atsamr34_xpro.dts b/boards/arm/atsamr34_xpro/atsamr34_xpro.dts index aba04a1b3e6..fe0ae80ae35 100644 --- a/boards/arm/atsamr34_xpro/atsamr34_xpro.dts +++ b/boards/arm/atsamr34_xpro/atsamr34_xpro.dts @@ -121,4 +121,7 @@ zephyr_udc0: &usb0 { status = "okay"; + + pinctrl-0 = <&usb0_default>; + pinctrl-names = "default"; }; diff --git a/boards/arm/atsamr34_xpro/doc/index.rst b/boards/arm/atsamr34_xpro/doc/index.rst index 051245c5d39..6347b50dedb 100644 --- a/boards/arm/atsamr34_xpro/doc/index.rst +++ b/boards/arm/atsamr34_xpro/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping The SAM R34 Xplained Pro evaluation kit has 3 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SAM R34 Family Datasheet`_ and the `SAM R34 +For more details please refer to `SAM R34 Family Datasheet`_ and the `SAM R34 Xplained Pro Schematic`_. .. image:: img/atsamr34-xpro-pinout.jpg diff --git a/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts b/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts index 13b641719ee..4c77535ce21 100644 --- a/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts +++ b/boards/arm/az3166_iotdevkit/az3166_iotdevkit.dts @@ -205,3 +205,9 @@ pinctrl-names = "default"; }; }; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; diff --git a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts index d5dc048b48a..1eb84827718 100644 --- a/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts +++ b/boards/arm/b_g474e_dpow1/b_g474e_dpow1.dts @@ -95,7 +95,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/b_g474e_dpow1/doc/index.rst b/boards/arm/b_g474e_dpow1/doc/index.rst index 1959ab6ad68..75d99572fbf 100644 --- a/boards/arm/b_g474e_dpow1/doc/index.rst +++ b/boards/arm/b_g474e_dpow1/doc/index.rst @@ -99,7 +99,7 @@ Default Zephyr Peripheral Mapping: - UCPD CC2 : PB4 - UCPD CC1 : PB6 -For mode details please refer to `B-G474E-DPOW1 Discovery board User Manual`_. +For more details please refer to `B-G474E-DPOW1 Discovery board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig b/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig index 61d4c1167ad..059f36907a2 100644 --- a/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig +++ b/boards/arm/b_l4s5i_iot01a/Kconfig.defconfig @@ -34,9 +34,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts index 9f8900921f6..c5116181432 100644 --- a/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts +++ b/boards/arm/b_l4s5i_iot01a/b_l4s5i_iot01a.dts @@ -148,16 +148,15 @@ pinctrl-names = "default"; status = "okay"; - cs-gpios = <&gpiod 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + cs-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>, <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; diff --git a/boards/arm/b_l4s5i_iot01a/doc/index.rst b/boards/arm/b_l4s5i_iot01a/doc/index.rst index 14d9480707b..d5b11c8b30b 100644 --- a/boards/arm/b_l4s5i_iot01a/doc/index.rst +++ b/boards/arm/b_l4s5i_iot01a/doc/index.rst @@ -144,7 +144,7 @@ Connections and IOs B_L4S5I_IOT01A Discovery kit has 9 GPIO controllers (from A to I). These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `B L47S5I IOT01A board User Manual`_. +For more details please refer to `B L47S5I IOT01A board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/b_u585i_iot02a/CMakeLists.txt b/boards/arm/b_u585i_iot02a/CMakeLists.txt index dde73804665..f6ca91f1a73 100644 --- a/boards/arm/b_u585i_iot02a/CMakeLists.txt +++ b/boards/arm/b_u585i_iot02a/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/b_u585i_iot02a/Kconfig.defconfig b/boards/arm/b_u585i_iot02a/Kconfig.defconfig index 6b3b72554ff..bc10deca7a2 100644 --- a/boards/arm/b_u585i_iot02a/Kconfig.defconfig +++ b/boards/arm/b_u585i_iot02a/Kconfig.defconfig @@ -27,4 +27,12 @@ config TFM_DUMMY_PROVISIONING endif # BUILD_WITH_TFM +# Disable Flow control +if BT + +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + endif # BOARD_B_U585I_IOT02A diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi index b9b07348f3c..ccbb4cea402 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a-common.dtsi @@ -73,7 +73,7 @@ apb3-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; @@ -131,11 +131,10 @@ status = "okay"; - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@70000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - size = ; /* 64 MBytes */ spi-bus-width = ; data-rate = ; four-byte-opcodes; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts index f8a826b1b6e..33093d701b7 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a.dts @@ -17,6 +17,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,bt-uart=&uart4; }; aliases { @@ -64,3 +65,10 @@ &gpdma1 { status = "okay"; }; + +&uart4 { + pinctrl-0 = <&uart4_tx_pc10 &uart4_rx_pc11>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig index d84deca3fe0..c034f717771 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_defconfig @@ -18,6 +18,3 @@ CONFIG_UART_CONSOLE=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig index 473e6e2fbb0..4b6f6ba7f5c 100644 --- a/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig +++ b/boards/arm/b_u585i_iot02a/b_u585i_iot02a_ns_defconfig @@ -22,6 +22,3 @@ CONFIG_PINCTRL=y CONFIG_ARM_TRUSTZONE_M=y CONFIG_RUNTIME_NMI=y CONFIG_TRUSTED_EXECUTION_NONSECURE=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/b_u585i_iot02a/doc/index.rst b/boards/arm/b_u585i_iot02a/doc/index.rst index 3c794b4de79..3121cfc5471 100644 --- a/boards/arm/b_u585i_iot02a/doc/index.rst +++ b/boards/arm/b_u585i_iot02a/doc/index.rst @@ -195,6 +195,8 @@ The Zephyr b_u585i_iot02a board configuration supports the following hardware fe +-----------+------------+-------------------------------------+ | AES | on-chip | crypto | +-----------+------------+-------------------------------------+ +| RADIO | STM32WB5MMG| Bluetooth Low Energy (BLE) | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: @@ -245,7 +247,7 @@ Connections and IOs B_U585I_IOT02A Discovery kit has 9 GPIO controllers (from A to I). These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `B U585I IOT02A board User Manual`_. +For more details please refer to `B U585I IOT02A board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -346,14 +348,14 @@ can be generated using ``b_u585i_iot02a_ns`` as build target. $ west build -b b_u585i_iot02a_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. .. code-block:: bash - $ build/tfm/regression.sh + $ build/tfm/api_ns/regression.sh Finally, to flash the board, run: diff --git a/boards/arm/b_u585i_iot02a/pre_dt_board.cmake b/boards/arm/b_u585i_iot02a/pre_dt_board.cmake new file mode 100644 index 00000000000..812d18cdf6c --- /dev/null +++ b/boards/arm/b_u585i_iot02a/pre_dt_board.cmake @@ -0,0 +1,3 @@ + +# SPI is implemented via octospi so node name isn't spi@... +list(APPEND EXTRA_DTC_FLAGS "-Wno-spi_bus_bridge") diff --git a/boards/arm/bbc_microbit/Kconfig.defconfig b/boards/arm/bbc_microbit/Kconfig.defconfig index 5bf0c28c9cf..17decdb0abe 100644 --- a/boards/arm/bbc_microbit/Kconfig.defconfig +++ b/boards/arm/bbc_microbit/Kconfig.defconfig @@ -11,9 +11,6 @@ config BOARD config BT_CTLR default BT -config LOG_BUFFER_SIZE - default 128 if LOG - if FXOS8700 choice FXOS8700_MODE diff --git a/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi b/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi index a91c7674688..d61a30d944b 100644 --- a/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi +++ b/boards/arm/bbc_microbit_v2/bbc_microbit_v2-pinctrl.dtsi @@ -34,4 +34,17 @@ }; }; + pwm1_default: pwm1_default { + group1 { + psels = ; + nordic,invert; + }; + }; + + pwm1_sleep: pwm1_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; }; diff --git a/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts b/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts index d802907c973..f123d003217 100644 --- a/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts +++ b/boards/arm/bbc_microbit_v2/bbc_microbit_v2.dts @@ -113,6 +113,14 @@ status = "okay"; }; +&pwm1 { + /* buzzer */ + status = "okay"; + pinctrl-0 = <&pwm1_default>; + pinctrl-1 = <&pwm1_sleep>; + pinctrl-names = "default", "sleep"; +}; + &uart0 { compatible = "nordic,nrf-uart"; status = "okay"; diff --git a/boards/arm/beagle_bcf/beagleconnect_freedom.dts b/boards/arm/beagle_bcf/beagleconnect_freedom.dts index 7fd8341e89b..9f8c84df956 100644 --- a/boards/arm/beagle_bcf/beagleconnect_freedom.dts +++ b/boards/arm/beagle_bcf/beagleconnect_freedom.dts @@ -64,6 +64,18 @@ #size-cells = <0>; controller = <&i2c0>; gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + + light: opt3001-light@44 { + status = "okay"; + compatible = "ti,opt3001"; + reg = <0x44>; + }; + + humidity: hdc2010-humidity@41 { + status = "okay"; + compatible = "ti,hdc2010"; + reg = <0x41>; + }; }; }; @@ -126,18 +138,6 @@ compatible = "beagle,usbbridge"; reg = <0x4>; }; - - light: opt3001-light@44 { - status = "okay"; - compatible = "ti,opt3001"; - reg = <0x44>; - }; - - humidity: hdc2010-humidity@41 { - status = "okay"; - compatible = "ti,hdc2010"; - reg = <0x41>; - }; }; &spi0 { diff --git a/boards/arm/beagle_bcf/board.cmake b/boards/arm/beagle_bcf/board.cmake index 84d7457e7b1..480bb68aaa3 100644 --- a/boards/arm/beagle_bcf/board.cmake +++ b/boards/arm/beagle_bcf/board.cmake @@ -3,7 +3,9 @@ # # SPDX-License-Identifier: Apache-2.0 -# Download cc2538-bsl.py from https://git.beagleboard.org/beagleconnect/zephyr/cc2538-bsl/-/tags/2.1-bcf +# Download cc1352-flasher (https://pypi.org/project/cc1352-flasher/) using the following command: +# pip3 install cc1352-flasher +find_program(CC1352_FLASHER NAMES cc1352_flasher) board_set_flasher_ifnset(misc-flasher) -board_finalize_runner_args(misc-flasher $ENV{ZEPHYR_BASE}/boards/arm/beagle_bcf/cc2538-bsl.py -w) +board_finalize_runner_args(misc-flasher ${CC1352_FLASHER} --bcf) diff --git a/boards/arm/beagle_bcf/doc/index.rst b/boards/arm/beagle_bcf/doc/index.rst index c208d41e431..43a237d0317 100644 --- a/boards/arm/beagle_bcf/doc/index.rst +++ b/boards/arm/beagle_bcf/doc/index.rst @@ -137,6 +137,19 @@ Connections and IOs | DIO30 | REF_SW_CTRL2 | Antenna mux SubG enable | +-------+--------------+-------------------------------------+ +System requirements +=================== + +Prerequisites +------------- + +BeagleConnect Freedom requires `CC1352 Flasher `_ for +flashing Zephyr firmware using ``west flash``. + +.. code-block:: console + + pip3 install cc1352-flasher + References ********** diff --git a/boards/arm/bl5340_dvk/CMakeLists.txt b/boards/arm/bl5340_dvk/CMakeLists.txt index 541334195dd..863c8bb599e 100644 --- a/boards/arm/bl5340_dvk/CMakeLists.txt +++ b/boards/arm/bl5340_dvk/CMakeLists.txt @@ -9,7 +9,7 @@ zephyr_library_sources(bl5340_dvk_cpunet_reset.c) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/boards/arm/bl5340_dvk/Kconfig.defconfig b/boards/arm/bl5340_dvk/Kconfig.defconfig index 798f331efc3..d87d6d75f37 100644 --- a/boards/arm/bl5340_dvk/Kconfig.defconfig +++ b/boards/arm/bl5340_dvk/Kconfig.defconfig @@ -78,7 +78,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC config BT_HCI_VS diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi index 5020c9a7af9..a5d9b72b62e 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common-pinctrl.dtsi @@ -89,6 +89,25 @@ }; }; + uart1_default: uart1_default { + group1 { + psels = , + , + , + ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + , + , + ; + low-power-enable; + }; + }; + pwm0_default: pwm0_default { group1 { psels = ; diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi index 78d1f2debf7..5a748b1bf9d 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_common.dtsi @@ -107,6 +107,25 @@ bbram0 = &extrtc0; spi-flash0 = &mx25r64; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + dc-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi2>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + mipi-max-frequency = <32000000>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &adc { @@ -224,16 +243,6 @@ pinctrl-0 = <&spi4_default>; pinctrl-1 = <&spi4_sleep>; pinctrl-names = "default", "sleep"; - ili9340: ili9340@0 { - compatible = "ilitek,ili9340"; - reg = <0>; - spi-max-frequency = <32000000>; - reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; - cmd-data-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; - rotation = <270>; - width = <320>; - height = <240>; - }; }; &uart0 { @@ -244,6 +253,13 @@ pinctrl-names = "default", "sleep"; }; +&uart1 { + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; diff --git a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts index b943c5bdfbf..9fdcba5f0e3 100644 --- a/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts +++ b/boards/arm/bl5340_dvk/bl5340_dvk_cpuapp_ns.dts @@ -17,23 +17,9 @@ zephyr,flash = &flash0; zephyr,code-partition = &slot0_ns_partition; }; - - /* Aliases for deleted nodes must be removed */ - aliases { - /delete-property/ spi-flash0; - }; }; zephyr_udc0: &usbd { compatible = "nordic,nrf-usbd"; status = "okay"; }; - -&qspi { - status = "disabled"; - - /* Drop the flash and partitions to avoid the config being used for DFU - * samples. - */ - /delete-node/ mx25r6435f@0; -}; diff --git a/boards/arm/bl654_usb/bl654_usb.dts b/boards/arm/bl654_usb/bl654_usb.dts index 80600290dbf..fa814f4b80e 100644 --- a/boards/arm/bl654_usb/bl654_usb.dts +++ b/boards/arm/bl654_usb/bl654_usb.dts @@ -59,6 +59,10 @@ status = "okay"; }; +&gpiote { + status = "okay"; +}; + &pwm0 { status = "okay"; pinctrl-0 = <&pwm0_default>; diff --git a/boards/arm/bt610/bt610.dts b/boards/arm/bt610/bt610.dts index 489401a5fb3..c6b9bad9910 100644 --- a/boards/arm/bt610/bt610.dts +++ b/boards/arm/bt610/bt610.dts @@ -77,6 +77,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; mag1: mag_1 { diff --git a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig index ba117ace665..0ed2d372835 100644 --- a/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig +++ b/boards/arm/cy8cproto_062_4343w/Kconfig.defconfig @@ -49,7 +49,8 @@ endchoice endif # BT # Heap Pool Size -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 15000 if WIFI default 4096 diff --git a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml index b6d56577209..8300a160c5a 100644 --- a/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml +++ b/boards/arm/cy8cproto_062_4343w/cy8cproto_062_4343w.yaml @@ -7,7 +7,7 @@ identifier: cy8cproto_062_4343w name: CY8CPROTO-062-4343W PSoC 6 Wi-Fi BT Prototyping Kit type: mcu arch: arm -ram: 288 +ram: 1024 flash: 2048 toolchain: - zephyr diff --git a/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml index 1bb6100e339..bc55d5ada4d 100644 --- a/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml +++ b/boards/arm/da14695_dk_usb/da14695_dk_usb.yaml @@ -10,6 +10,7 @@ toolchain: supported: - arduino_gpio - gpio + - hwinfo - watchdog - i2c - spi diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index e31a2749002..4d35304c622 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -11,6 +11,7 @@ supported: - arduino_gpio - counter - gpio + - hwinfo - watchdog - i2c - spi diff --git a/boards/arm/disco_l475_iot1/Kconfig.defconfig b/boards/arm/disco_l475_iot1/Kconfig.defconfig index 847c9ec0878..3a53147decf 100644 --- a/boards/arm/disco_l475_iot1/Kconfig.defconfig +++ b/boards/arm/disco_l475_iot1/Kconfig.defconfig @@ -34,9 +34,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts index a37b801b3e4..81beca8e7c0 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1.dts +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1.dts @@ -187,16 +187,15 @@ pinctrl-0 = <&spi3_sck_pc10 &spi3_miso_pc11 &spi3_mosi_pc12>; pinctrl-names = "default"; - cs-gpios = <&gpiod 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>, + cs-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>, <&gpioe 0 GPIO_ACTIVE_LOW>; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&gpioa 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; irq-gpios = <&gpioe 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; @@ -262,7 +261,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; @@ -322,12 +321,10 @@ zephyr_udc0: &usbotg_fs { status = "okay"; - mx25r6435f: qspi-nor-flash@0 { + mx25r6435f: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <50000000>; - /* 64 Megabits = 8 Megabytes */ - size = <0x4000000>; status = "okay"; partitions { diff --git a/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig b/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig index 072929abda8..a25b1eff645 100644 --- a/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig +++ b/boards/arm/disco_l475_iot1/disco_l475_iot1_defconfig @@ -26,6 +26,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi new file mode 100644 index 00000000000..71d20205691 --- /dev/null +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts index 1ff034899db..5dcae30fbee 100644 --- a/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts +++ b/boards/arm/efm32gg_sltb009a/efm32gg_sltb009a.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efm32gg_sltb009a-pinctrl.dtsi" / { model = "Silicon Labs EFM32GG SLTB009A board"; @@ -57,8 +58,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi new file mode 100644 index 00000000000..24b51c33612 --- /dev/null +++ b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a-pinctrl.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* configuration for usart0 device, default state - operating as UART */ + usart0_default: usart0_default { + group1 { + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi index cb0209f8e4a..6611bee4956 100644 --- a/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi +++ b/boards/arm/efm32pg_stk3401a/efm32pg_stk3401a_common.dtsi @@ -5,6 +5,7 @@ */ #include +#include "efm32pg_stk3401a-pinctrl.dtsi" / { model = "Silicon Labs EFM32PG STK3401A board"; @@ -60,8 +61,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efr32_radio/Kconfig.board b/boards/arm/efr32_radio/Kconfig.board index 6104a3884f0..bbae554ae69 100644 --- a/boards/arm/efr32_radio/Kconfig.board +++ b/boards/arm/efr32_radio/Kconfig.board @@ -17,6 +17,12 @@ config BOARD_EFR32_RADIO_BRD4170A select BOARD_EFR32_RADIO select SOC_PART_NUMBER_EFR32MG12P433F1024GM68 +config BOARD_EFR32_RADIO_BRD4161A + bool "Silicon Labs BRD4161A (Mighty Gecko Radio Board)" + depends on SOC_SERIES_EFR32MG12P + select BOARD_EFR32_RADIO + select SOC_PART_NUMBER_EFR32MG12P432F1024GL125 + config BOARD_EFR32_RADIO_BRD4250B bool "Silicon Labs BRD4250B (Flex Gecko Radio Board)" depends on SOC_SERIES_EFR32FG1P diff --git a/boards/arm/efr32_radio/Kconfig.defconfig b/boards/arm/efr32_radio/Kconfig.defconfig index 39c4b9ff695..b91aa627b70 100644 --- a/boards/arm/efr32_radio/Kconfig.defconfig +++ b/boards/arm/efr32_radio/Kconfig.defconfig @@ -9,6 +9,7 @@ if BOARD_EFR32_RADIO config BOARD default "efr32_radio_brd4104a" if BOARD_EFR32_RADIO_BRD4104A default "efr32_radio_brd4170a" if BOARD_EFR32_RADIO_BRD4170A + default "efr32_radio_brd4161a" if BOARD_EFR32_RADIO_BRD4161A default "efr32_radio_brd4250b" if BOARD_EFR32_RADIO_BRD4250B default "efr32_radio_brd4180a" if BOARD_EFR32_RADIO_BRD4180A default "efr32_radio_brd4187c" if BOARD_EFR32_RADIO_BRD4187C diff --git a/boards/arm/efr32_radio/board.cmake b/boards/arm/efr32_radio/board.cmake index 95eaa403fcb..d684946143e 100644 --- a/boards/arm/efr32_radio/board.cmake +++ b/boards/arm/efr32_radio/board.cmake @@ -8,6 +8,8 @@ elseif(CONFIG_BOARD_EFR32_RADIO_BRD4250B) board_runner_args(jlink "--device=EFR32FG1PxxxF256") elseif(CONFIG_BOARD_EFR32_RADIO_BRD4170A) board_runner_args(jlink "--device=EFR32MG12PxxxF1024") +elseif(CONFIG_BOARD_EFR32_RADIO_BRD4161A) +board_runner_args(jlink "--device=EFR32MG12PxxxF1024") elseif(CONFIG_BOARD_EFR32_RADIO_BRD4180A) board_runner_args(jlink "--device=EFR32MG21AxxxF1024") elseif(CONFIG_BOARD_EFR32_RADIO_BRD4187C) diff --git a/boards/arm/efr32_radio/doc/brd4161a.rst b/boards/arm/efr32_radio/doc/brd4161a.rst new file mode 100644 index 00000000000..f51d54b5f3d --- /dev/null +++ b/boards/arm/efr32_radio/doc/brd4161a.rst @@ -0,0 +1,109 @@ +.. _efr32_radio_brd4161a: + +EFR32 BRD4161A (SLWRB4161A) +########################### + +Overview +******** + +The EFR32MG12 Mighty Gecko Radio Board contains a Wireless System-On-Chip +from the EFR32MG12 family built on an ARM Cortex®-M4F processor with excellent +low power capabilities. + +.. figure:: efr32mg12-slwrb4161a.jpeg + :align: center + :alt: SLWRB4161A Mighty Gecko Radio Board + + SLWRB4161A (image courtesy of Silicon Labs) + +The BRD4161A a.k.a. SLWRB4161A radio board plugs into the Wireless Starter Kit +Mainboard BRD4001A and is supported as one of :ref:`efr32_radio`. + +Hardware +******** + +- EFR32MG12P432F1024GL125 Mighty Gecko SoC +- CPU core: ARM Cortex®-M4 with FPU +- Flash memory: 1024 kB +- RAM: 256 kB +- Transmit power: up to +19 dBm +- Operation frequency: 2.4 GHz and Sub-Ghz +- Crystals for LFXO (32.768 kHz) and HFXO (38.4 MHz). + +For more information about the EFR32MG12 SoC and BRD4170A board, refer to these +documents: + +- `EFR32MG12 Website`_ +- `EFR32MG12 Datasheet`_ +- `EFR32xG12 Reference Manual`_ +- `BRD4161A User Guide`_ + +Supported Features +================== + +Please refer to +:ref:`EFR32 Radio Board Supported Features ` +for details of the configuration and common features supported by the +efr32_radio_brd4161a board. + +The default configuration can be found in the defconfig file: + + ``boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig`` + +System Clock +============ + +The EFR32MG12P SoC is configured to use the 38.4 MHz external oscillator on the +board. + +Serial Port +=========== + +The EFR32MG12P SoC has four USARTs and one Low Energy UARTs (LEUART). +USART0 is connected to the board controller and is used for the console. + +Programming and Debugging +************************* + +Please refer to +:ref:`Programming and Debugging EFR32 Radio Board ` +for details on the supported debug interfaces. + +Flashing +======== + +Connect the BRD4001A board with a mounted BRD4170A radio module to your host +computer using the USB port. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: efr32_radio_brd4161a + :goals: flash + +Open a serial terminal (minicom, putty, etc.) with the following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and you should see the following message in the terminal: + +.. code-block:: console + + Hello World! efr32_radio_brd4161a + + +.. _EFR32MG12 Website: + https://www.silabs.com/wireless/zigbee/efr32mg12-series-1-socs + +.. _EFR32MG12 Datasheet: + https://www.silabs.com/documents/public/data-sheets/efr32mg12-datasheet.pdf + +.. _EFR32xG12 Reference Manual: + https://www.silabs.com/documents/public/reference-manuals/efr32xg12-rm.pdf + +.. _BRD4161A User Guide: + https://www.silabs.com/documents/public/user-guides/ug260-brd4161a-user-guide.pdf diff --git a/boards/arm/efr32_radio/doc/efr32mg12-slwrb4161a.jpeg b/boards/arm/efr32_radio/doc/efr32mg12-slwrb4161a.jpeg new file mode 100644 index 00000000000..eb912df1e30 Binary files /dev/null and b/boards/arm/efr32_radio/doc/efr32mg12-slwrb4161a.jpeg differ diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a.dts b/boards/arm/efr32_radio/efr32_radio_brd4161a.dts new file mode 100644 index 00000000000..6f1cba19b5c --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a.dts @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Piotr Mienkowski + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "efr32_radio.dtsi" + +/ { + model = "Silicon Labs BRD4161A (Mighty Gecko Radio Board)"; + compatible = "silabs,efr32_radio_brd4161a", "silabs,efr32mg12p"; + + aliases { + spi-flash0 = &mx25r80; + }; +}; + +&cpu0 { + clock-frequency = <38400000>; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 32 kB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 0x00008000>; + read-only; + }; + + /* Reserve 220 kB for the application in slot 0 */ + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 0x00037000>; + }; + + /* Reserve 220 kB for the application in slot 1 */ + slot1_partition: partition@3f000 { + label = "image-1"; + reg = <0x0003f000 0x00037000>; + }; + + /* Reserve 32 kB for the scratch partition */ + scratch_partition: partition@76000 { + label = "image-scratch"; + reg = <0x00076000 0x00008000>; + }; + + /* Set 8Kb of storage at the end of the 512KB of flash */ + storage_partition: partition@7e000 { + label = "storage"; + reg = <0x0007e000 0x00002000>; + }; + + }; +}; + +&usart0 { + current-speed = <115200>; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml b/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml new file mode 100644 index 00000000000..108d6f16c0f --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a.yaml @@ -0,0 +1,21 @@ +identifier: efr32_radio_brd4161a +name: BRD4161A +type: mcu +arch: arm +ram: 256 +flash: 1024 +toolchain: + - zephyr + - gnuarmemb +supported: + - counter + - gpio + - nvs + - spi + - uart + - watchdog +testing: + ignore_tags: + - net + - bluetooth +vendor: silabs diff --git a/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig b/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig new file mode 100644 index 00000000000..fbf7cf38325 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4161a_defconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM_MPU=y +CONFIG_SOC_SERIES_EFR32MG12P=y +CONFIG_BOARD_EFR32_RADIO_BRD4161A=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_GPIO=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=38400000 +CONFIG_CMU_HFCLK_HFXO=y +CONFIG_SOC_GECKO_EMU_DCDC=y +CONFIG_SOC_GECKO_EMU_DCDC_MODE_ON=y diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi new file mode 100644 index 00000000000..74723695d86 --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + psels = , + , + ; + }; + }; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts index 0687b206adb..43f4290ff84 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4180a.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4180a.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efr32_radio_brd4180a-pinctrl.dtsi" / { model = "Silicon Labs BRD4180A (Mighty Gecko Radio Board)"; @@ -65,8 +66,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi b/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi new file mode 100644 index 00000000000..0ea520ce13f --- /dev/null +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c-pinctrl.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&pinctrl { + usart0_default: usart0_default { + group1 { + psels = , + , + ; + }; + }; +}; diff --git a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts index 1f065fb15b1..6e8703fabbe 100644 --- a/boards/arm/efr32_radio/efr32_radio_brd4187c.dts +++ b/boards/arm/efr32_radio/efr32_radio_brd4187c.dts @@ -7,6 +7,7 @@ /dts-v1/; #include #include +#include "efr32_radio_brd4187c-pinctrl.dtsi" / { model = "Silicon Labs BRD4187C (Mighty Gecko Radio Board)"; @@ -67,8 +68,8 @@ &usart0 { current-speed = <115200>; - location-rx = ; - location-tx = ; + pinctrl-0 = <&usart0_default>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/boards/arm/ev11l78a/ev11l78a_defconfig b/boards/arm/ev11l78a/ev11l78a_defconfig index 51b5780ea70..5d9a8a9d651 100644 --- a/boards/arm/ev11l78a/ev11l78a_defconfig +++ b/boards/arm/ev11l78a/ev11l78a_defconfig @@ -11,3 +11,16 @@ CONFIG_GPIO=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_UART_INTERRUPT_DRIVEN=y + +# Kernel Options due to Low Memory (4k) +CONFIG_LOG_BUFFER_SIZE=256 +CONFIG_MAIN_STACK_SIZE=640 +CONFIG_IDLE_STACK_SIZE=200 +CONFIG_ISR_STACK_SIZE=512 +CONFIG_USBC_STACK_SIZE=512 +# Prevent Interrupt Vector Table in RAM +CONFIG_SRAM_VECTOR_TABLE=n + +# This board only supports the sink role, so +# no need to ever implement source for it. +CONFIG_USBC_CSM_SINK_ONLY=y diff --git a/boards/arm/fk7b0m1_vbt6/Kconfig.board b/boards/arm/fk7b0m1_vbt6/Kconfig.board new file mode 100644 index 00000000000..0b46551e95e --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/Kconfig.board @@ -0,0 +1,8 @@ +# STM32H7B0VBT FK7B0M1_VBT6 board + +# Copyright (c) 2023 Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_FK7B0M1_VBT6 + bool "FANKE FK7B0M1-VBT6 board" + depends on SOC_STM32H7B0XX diff --git a/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig b/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig new file mode 100644 index 00000000000..39de99eb5f8 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32H7B0VBT board configuration + +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_FK7B0M1_VBT6 + +config BOARD + default "fk7b0m1_vbt6" + +endif # BOARD_FK7B0M1_VBT6 diff --git a/boards/arm/fk7b0m1_vbt6/board.cmake b/boards/arm/fk7b0m1_vbt6/board.cmake new file mode 100644 index 00000000000..f709513c711 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(jlink "--device=STM32H7B0VB" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp new file mode 100644 index 00000000000..68faf96b859 Binary files /dev/null and b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6.webp differ diff --git a/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp new file mode 100644 index 00000000000..5a67a58fcbd Binary files /dev/null and b/boards/arm/fk7b0m1_vbt6/doc/img/fk7b0m1_vbt6_pins.webp differ diff --git a/boards/arm/fk7b0m1_vbt6/doc/index.rst b/boards/arm/fk7b0m1_vbt6/doc/index.rst new file mode 100644 index 00000000000..2af182bc041 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/doc/index.rst @@ -0,0 +1,179 @@ +.. _fk7b0m1_vbt6: + +FANKE FK7B0M1-VBT6 +################## + +Overview +******** + +The FK7B0M1-VBT6 core board by FANKE Technology Co., Ltd. is an advanced microcontroller +platform based on the STMicroelectronics Arm® Cortex®-M7 core STM32H7B0VBT6 microcontroller. +This board is an ideal solution for developers looking to create high-performance +applications, especially in the field of Human-Machine Interface (HMI), leveraging its +robust capabilities and support for sophisticated display and touch technologies. + +The FK7B0M1-VBT6 is designed as a reference design for user application development before +transitioning to the final product, significantly simplifying the development process. +Its wide range of hardware features, including advanced display and touch capabilities, +make it exceptionally suitable for HMI applications, allowing for comprehensive evaluation +and testing of peripherals and functionalities. + +.. figure:: img/fk7b0m1_vbt6.webp + :width: 600px + :align: center + :alt: FK7B0M1-VBT6 + + FK7B0M1-VBT6 (Credit: FANKE Technology Co., Ltd) + +Hardware +******** + +FK7B0M1-VBT6 provides the following hardware components: + +- STM32H7B6VB in LQFP100 package +- ARM 32-bit Cortex-M7 CPU with FPU +- 280 MHz max CPU frequency +- VDD from 1.62 V to 3.6 V +- 128 KB Flash +- ~1.4 MB SRAM max (1.18 Mbytes user SRAM + 64 Kbytes ITCM RAM + 128 Kbytes DTCM RAM + 4 Kbytes SRAM in Backup domain) +- Main clock: External 25MHz crystal oscillator. +- RTC: 32.768kHz crystal oscillator. +- 32-bit timers(2) +- 16-bit timers(12) +- 1 reset button, 1 user button, and 1 BOOT button +- 1 user LED +- External 64-Mbit QSPI (W25Q64) NOR Flash memory. +- External 64-Mbit SPI (W25Q64) NOR Flash memory. +- USB OTG Full Speed and High Speed(1) +- 1 micro SD card +- 1 RGB LCD interface +- SWD and serial port accessibility through a pin header +- Bring out 39 IO ports + +More information about STM32H7B0VB can be found here: + +- `STM32H7B0VB on www.st.com`_ + +Supported Features +================== + +The Zephyr nucleo_h723zg board configuration supports the following hardware +features: + ++-------------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++=============+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-------------+------------+-------------------------------------+ +| UART | on-chip | serial port | ++-------------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-------------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-------------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-------------+------------+-------------------------------------+ +| Backup SRAM | on-chip | Backup SRAM | ++-------------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration per core can be found in the defconfig files: +``boards/arm/fk7b0m1-vbt6/fk7b0m1_vbt6_defconfig`` + +Connections and IOs +=================== + +Available pins: +--------------- + +Nucleo FK7B0M1-VBT6 board has 6 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +.. figure:: img/fk7b0m1_vbt6_pins.webp + :width: 600px + :align: center + :alt: FK7B0M1-VBT6 + + FK7B0M1-VBT6 (Credit: FANKE Technology Co., Ltd) + +LED +--- + +- User LED (blue) = PC1 + +Push buttons +------------------------- + +- BOOT = SW1 = BOOT0 +- RESET = SW2 = NRST +- User button = SW3 = PC13 + +UART +----- + +- TX device = USART1 PA9 +- RX device = USART1 PA10 + +USB +--- + +- USB D- = PA11 +- USB D+ = PA12 + +System Clock +============ + +The FK7B0M1-VBT6 System Clock could be driven by an internal or external oscillator, +as well as by the main PLL clock. By default the system clock is driven by the PLL clock at 280MHz, +driven by an 25MHz external crystal oscillator. + +Serial Port +=========== + +The Zephyr console output is assigned to UART1. The default communication settings are 115200 8N1. + +Programming and Debugging +************************* + +The FK7B0M1-VBT6 board does not include an on-board debugger. As a result, it requires +an external debugger, such as ST-Link, for programming and debugging purposes. + +The board provides header pins for the Serial Wire Debug (SWD) interface. + +Flashing +======== + +To begin, connect the ST-Link Debug Programmer to the FK7B0M1-VBT6 board using the SWD +interface. Next, connect the ST-Link to your host computer via a USB port. +Once this setup is complete, you can proceed to build and flash your application to the board + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: fk7b0m1_vbt6 + :goals: build flash + +Run a serial host program to connect with your board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 -b 115200 + +Then, press the RESET button, you should see the following message: + +.. code-block:: console + + Hello World! fk7b0m1_vbt6 + +Debugging +========= + +This current Zephyr port does not support debugging. + +References +********** + +.. target-notes:: +.. _STM32H7B0VB on www.st.com: https://www.st.com/en/microcontrollers/stm32h7b0vb.html diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts new file mode 100644 index 00000000000..536c7b6e780 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Charles Dias + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "FANKE FK7B0M1-VBT6 board"; + compatible = "fanke,fk7b0m1-vbt6"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_0 { + gpios = <&gpioc 1 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button_0 { + label = "User PB"; + gpios = <&gpioc 13 (GPIO_PULL_UP | GPIO_ACTIVE_HIGH)>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &user_led; + sw0 = &user_button; + }; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +/* PLL1P is used for system clock (280 MHz) */ +&pll { + div-m = <5>; + mul-n = <112>; + div-p = <2>; + div-q = <2>; + div-r = <2>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + d1cpre = <1>; + hpre = <1>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pa9 &usart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&backup_sram { + status = "okay"; +}; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pa11 &usb_otg_hs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rng { + status = "okay"; +}; diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml new file mode 100644 index 00000000000..f847d49f450 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6.yaml @@ -0,0 +1,14 @@ +identifier: fk7b0m1_vbt6 +name: FANKE FK7B0M1-VBT6 board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 1376 +flash: 128 +supported: + - uart + - gpio +vendor: fanke diff --git a/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig new file mode 100644 index 00000000000..72587a3a897 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/fk7b0m1_vbt6_defconfig @@ -0,0 +1,27 @@ +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H7B0XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART +CONFIG_SERIAL=y + +# Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable Pinctrl +CONFIG_PINCTRL=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clocks +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/fk7b0m1_vbt6/support/openocd.cfg b/boards/arm/fk7b0m1_vbt6/support/openocd.cfg new file mode 100644 index 00000000000..ce4f15c9979 --- /dev/null +++ b/boards/arm/fk7b0m1_vbt6/support/openocd.cfg @@ -0,0 +1,25 @@ +# Copyright (c) Charles Dias +# SPDX-License-Identifier: Apache-2.0 + +source [find interface/stlink-dap.cfg] +transport select "dapdirect_swd" + +set WORKAREASIZE 0x8000 + +set CHIPNAME STM32H7B0VB +set BOARDNAME FK7B0M1-VBT6 + +source [find target/stm32h7x.cfg] + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 diff --git a/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi b/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi index 6249cc554df..14d6fe7d021 100644 --- a/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi +++ b/boards/arm/frdm_k22f/frdm_k22f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK22FN512VLH12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_k22f/frdm_k22f.dts b/boards/arm/frdm_k22f/frdm_k22f.dts index 7804af1056d..e11db24edfc 100644 --- a/boards/arm/frdm_k22f/frdm_k22f.dts +++ b/boards/arm/frdm_k22f/frdm_k22f.dts @@ -205,27 +205,20 @@ zephyr_udc0: &usbotg { reg = <0x00000000 0x00010000>; read-only; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 0x00020000>; + reg = <0x00010000 0x00028800>; }; - slot1_partition: partition@30000 { + slot1_partition: partition@38800 { label = "image-1"; - reg = <0x00030000 0x00020000>; - }; - scratch_partition: partition@50000 { - label = "image-scratch"; - reg = <0x00050000 0x00010000>; + reg = <0x00038800 0x00028000>; }; - - /* - * The flash starting at 0x00060000 and ending at - * 0x0007ffff (sectors 16-31) is reserved for use - * by the application. - */ - storage_partition: partition@60000 { + storage_partition: partition@60800 { label = "storage"; - reg = <0x00060000 0x00020000>; + reg = <0x00060800 0x0001f800>; }; }; diff --git a/boards/arm/frdm_k64f/board.cmake b/boards/arm/frdm_k64f/board.cmake index a7302350a26..d2fafeb4a00 100644 --- a/boards/arm/frdm_k64f/board.cmake +++ b/boards/arm/frdm_k64f/board.cmake @@ -1,8 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 board_runner_args(jlink "--device=MK64FN1M0xxx12") +board_runner_args(linkserver "--device=MK64FN1M0xxx12:FRDM-K64F") + board_runner_args(pyocd "--target=k64f") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/frdm_k64f/doc/index.rst b/boards/arm/frdm_k64f/doc/index.rst index 6d9c86a5714..acbf2260561 100644 --- a/boards/arm/frdm_k64f/doc/index.rst +++ b/boards/arm/frdm_k64f/doc/index.rst @@ -246,11 +246,23 @@ instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. .. group-tab:: OpenSDA DAPLink Onboard (Recommended) - Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search - path. + Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the default CMSIS-DAP firmware included in + the on-board debugger. + + Linkserver is the default for this board, ``west flash`` and ``west debug`` will + call the linkserver runner. + + .. code-block:: console + + west flash + + Alternatively, pyOCD can be used to flash and debug the board by using the + ``-r pyocd`` option with West. pyOCD is installed when you complete the + :ref:`gs_python_deps` step in the Getting Started Guide. The runners supported + by NXP are LinkServer and JLink. pyOCD is another potential option, but NXP + does not test or support the pyOCD runner. - Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program - the `OpenSDA DAPLink FRDM-K64F Firmware`_. .. group-tab:: OpenSDA JLink Onboard @@ -269,7 +281,7 @@ instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. Add the arguments ``-DBOARD_FLASH_RUNNER=jlink`` and ``-DBOARD_DEBUG_RUNNER=jlink`` when you invoke ``west build`` to override the - default runner from pyOCD to J-Link: + default runner to J-Link: .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -378,3 +390,13 @@ of pyocd commands: .. _OpenSDA Serial and Debug Adapter: https://www.nxp.com/design/microcontrollers-developer-resources/ides-for-kinetis-mcus/opensda-serial-and-debug-adapter:OPENSDA#FRDM-K64F + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay b/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..9dfc07e9b08 --- /dev/null +++ b/boards/arm/frdm_k64f/dts/nxp,enet-experimental.overlay @@ -0,0 +1,108 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + +/ { + soc { + /delete-node/ ethernet@400c0000; + + enet: ethernet@400c0000 { + compatible = "nxp,enet"; + reg = <0x400c0000 0x620>; + clocks = <&sim KINETIS_SIM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <83 0>, <84 0>, <85 0>; + interrupt-names = "TX", "RX", "ERR"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <82 0>; + interrupt-names = "IEEE1588_TMR"; + status = "disabled"; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,interface-type = "rmii-25MHz"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + +&pinctrl { + /delete-node/ ptp_default; + /delete-node/ enet_default; + + pinmux_enet: pinmux_enet { + group1 { + pinmux = , + , + , + , + , + , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = ; + drive-strength = "low"; + drive-open-drain; + bias-pull-up; + slew-rate = "fast"; + }; + group1 { + pinmux = ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = , + , + ; + drive-strength = "low"; + slew-rate = "fast"; + }; + }; +}; diff --git a/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi b/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi index 5ac35405bdd..70af2305ce8 100644 --- a/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi +++ b/boards/arm/frdm_k64f/frdm_k64f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK64FN1M0VLL12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_k64f/frdm_k64f.dts b/boards/arm/frdm_k64f/frdm_k64f.dts index 5b0e26fb039..a5affc02797 100644 --- a/boards/arm/frdm_k64f/frdm_k64f.dts +++ b/boards/arm/frdm_k64f/frdm_k64f.dts @@ -234,28 +234,20 @@ zephyr_udc0: &usbotg { reg = <0x00000000 0x00010000>; read-only; }; - - /* - * The flash starting at 0x00010000 and ending at - * 0x0001ffff (sectors 16-31) is reserved for use - * by the application. + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm */ - storage_partition: partition@1e000 { - label = "storage"; - reg = <0x0001e000 0x00002000>; - }; - - slot0_partition: partition@20000 { + slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00020000 0x00060000>; + reg = <0x00010000 0x00069000>; }; - slot1_partition: partition@80000 { + slot1_partition: partition@79000 { label = "image-1"; - reg = <0x00080000 0x00060000>; + reg = <0x00079000 0x00068000>; }; - scratch_partition: partition@e0000 { - label = "image-scratch"; - reg = <0x000e0000 0x00020000>; + storage_partition: partition@e1000 { + label = "storage"; + reg = <0x000e1000 0x0001f000>; }; }; }; diff --git a/boards/arm/frdm_k64f/frdm_k64f.yaml b/boards/arm/frdm_k64f/frdm_k64f.yaml index a9e99911776..b4de8b219e1 100644 --- a/boards/arm/frdm_k64f/frdm_k64f.yaml +++ b/boards/arm/frdm_k64f/frdm_k64f.yaml @@ -2,7 +2,7 @@ identifier: frdm_k64f name: NXP FRDM-K64F type: mcu arch: arm -ram: 256 +ram: 192 flash: 1024 toolchain: - zephyr diff --git a/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi b/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi index d09e5bcaa37..41fd7d9d210 100644 --- a/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi +++ b/boards/arm/frdm_k82f/frdm_k82f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK82FN256VLL15/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_k82f/frdm_k82f.dts b/boards/arm/frdm_k82f/frdm_k82f.dts index a60a32d01d8..53eed0cd28b 100644 --- a/boards/arm/frdm_k82f/frdm_k82f.dts +++ b/boards/arm/frdm_k82f/frdm_k82f.dts @@ -161,21 +161,20 @@ label = "mcuboot"; reg = <0x0 DT_SIZE_K(48)>; }; - storage_partition: partition@c000 { - label = "storage"; - reg = <0xc000 DT_SIZE_K(32)>; - }; - slot0_partition: partition@14000 { + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ + slot0_partition: partition@c000 { label = "image-0"; - reg = <0x14000 DT_SIZE_K(80)>; + reg = <0xc000 DT_SIZE_K(100)>; }; - slot1_partition: partition@28000 { + slot1_partition: partition@25000 { label = "image-1"; - reg = <0x28000 DT_SIZE_K(80)>; + reg = <0x25000 DT_SIZE_K(96)>; }; - scratch_partition: partition@3c000 { - label = "image-scratch"; - reg = <0x3c000 DT_SIZE_K(16)>; + storage_partition: partition@3d000 { + label = "storage"; + reg = <0x3d000 DT_SIZE_K(12)>; }; }; }; diff --git a/boards/arm/frdm_kl25z/board.cmake b/boards/arm/frdm_kl25z/board.cmake index 7f7a37db23f..d711b305325 100644 --- a/boards/arm/frdm_kl25z/board.cmake +++ b/boards/arm/frdm_kl25z/board.cmake @@ -1,7 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 board_runner_args(jlink "--device=MKL25Z128xxx4") +board_runner_args(linkserver "--device=MKL25Z128xxx4:FRDM-KL25Z") board_runner_args(pyocd "--target=kl25z") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/frdm_kl25z/doc/index.rst b/boards/arm/frdm_kl25z/doc/index.rst index 333f686f640..22261a26e57 100644 --- a/boards/arm/frdm_kl25z/doc/index.rst +++ b/boards/arm/frdm_kl25z/doc/index.rst @@ -130,14 +130,21 @@ Early versions of this board have an outdated version of the OpenSDA bootloader and require an update. Please see the `DAPLink Bootloader Update`_ page for instructions to update from the CMSIS-DAP bootloader to the DAPLink bootloader. -Option 1: :ref:`opensda-daplink-onboard-debug-probe` (Recommended) ------------------------------------------------------------------- +Option 1: Linkserver: :ref:`opensda-daplink-onboard-debug-probe` (Recommended) +------------------------------------------------------------------------------ -Install the :ref:`pyocd-debug-host-tools` and make sure they are in your search -path. + Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the CMSIS-DAP debug firmware. Please follow the + instructions on :ref:`opensda-daplink-onboard-debug-probe` and select the latest revision + of the firmware image. + + Linkserver is the default for this board, ``west flash`` and ``west debug`` will + call the linkserver runner. + + .. code-block:: console -Follow the instructions in :ref:`opensda-daplink-onboard-debug-probe` to program -the `OpenSDA DAPLink FRDM-KL25Z Firmware`_. + west flash + west debug Option 2: :ref:`opensda-jlink-onboard-debug-probe` -------------------------------------------------- @@ -158,6 +165,12 @@ default runner from pyOCD to J-Link: :gen-args: -DBOARD_FLASH_RUNNER=jlink -DBOARD_DEBUG_RUNNER=jlink :goals: build +Note: +----- + +The runners supported by NXP are LinkServer and JLink. pyOCD is another potential option, +but NXP does not test or support the pyOCD runner. + Configuring a Console ===================== diff --git a/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi b/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi index 925aaf7fafe..d4326c422a2 100644 --- a/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi +++ b/boards/arm/frdm_kl25z/frdm_kl25z-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKL25Z128VLK4/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi b/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi index 2377304c5c1..af7cbf8f26e 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi +++ b/boards/arm/frdm_kw41z/frdm_kw41z-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKW41Z512VHT4/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/frdm_kw41z/frdm_kw41z.yaml b/boards/arm/frdm_kw41z/frdm_kw41z.yaml index 72c7cb4abf3..63cffff2786 100644 --- a/boards/arm/frdm_kw41z/frdm_kw41z.yaml +++ b/boards/arm/frdm_kw41z/frdm_kw41z.yaml @@ -2,7 +2,7 @@ identifier: frdm_kw41z name: NXP FRDM-KW41Z type: mcu arch: arm -ram: 128 +ram: 96 flash: 512 toolchain: - zephyr diff --git a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml index 08d01e51ec4..0ecd14f9076 100644 --- a/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml +++ b/boards/arm/fvp_baser_aemv8r_aarch32/fvp_baser_aemv8r_aarch32_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_aarch32_smp -name: FVP Emulation FVP_BaseR_AEMv8R AArch32 +name: FVP Emulation FVP_BaseR_AEMv8R AArch32 (SMP) arch: arm type: sim toolchain: diff --git a/boards/arm/gd32a503v_eval/gd32a503v_eval.dts b/boards/arm/gd32a503v_eval/gd32a503v_eval.dts index f5f79267c16..dc6e0325452 100644 --- a/boards/arm/gd32a503v_eval/gd32a503v_eval.dts +++ b/boards/arm/gd32a503v_eval/gd32a503v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32a503v_eval-pinctrl.dtsi" / { diff --git a/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml b/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml index 396e68d24b6..e2e2145d9af 100644 --- a/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml +++ b/boards/arm/gd32a503v_eval/gd32a503v_eval.yaml @@ -16,6 +16,7 @@ supported: - counter - dac - dma + - flash - gpio - pwm - spi diff --git a/boards/arm/gd32e103v_eval/gd32e103v_eval.dts b/boards/arm/gd32e103v_eval/gd32e103v_eval.dts index 1811736fb04..c4aa7403591 100644 --- a/boards/arm/gd32e103v_eval/gd32e103v_eval.dts +++ b/boards/arm/gd32e103v_eval/gd32e103v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e103v_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32e507v_start/gd32e507v_start.dts b/boards/arm/gd32e507v_start/gd32e507v_start.dts index 4da44f66ff5..5c287ed51fe 100644 --- a/boards/arm/gd32e507v_start/gd32e507v_start.dts +++ b/boards/arm/gd32e507v_start/gd32e507v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e507v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg b/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg deleted file mode 100644 index f09658eb7b8..00000000000 Binary files a/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.jpg and /dev/null differ diff --git a/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp b/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp new file mode 100644 index 00000000000..bad1bd26a4f Binary files /dev/null and b/boards/arm/gd32e507z_eval/doc/img/gd32e507z_eval.webp differ diff --git a/boards/arm/gd32e507z_eval/doc/index.rst b/boards/arm/gd32e507z_eval/doc/index.rst index 9e7aef4dcd4..c3484d8beec 100644 --- a/boards/arm/gd32e507z_eval/doc/index.rst +++ b/boards/arm/gd32e507z_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32E507ZE features a single-core ARM Cortex-M33 MCU which can run up to 180 MHz with flash accesses zero wait states, 512kiB of Flash, 128kiB of SRAM and 112 GPIOs. -.. image:: img/gd32e507z_eval.jpg +.. image:: img/gd32e507z_eval.webp :align: center :alt: gd32e507z_eval diff --git a/boards/arm/gd32e507z_eval/gd32e507z_eval.dts b/boards/arm/gd32e507z_eval/gd32e507z_eval.dts index 6f7140ca17f..9f9be821e41 100644 --- a/boards/arm/gd32e507z_eval/gd32e507z_eval.dts +++ b/boards/arm/gd32e507z_eval/gd32e507z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32e507z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.jpg b/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.jpg deleted file mode 100644 index 528d07470dd..00000000000 Binary files a/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.jpg and /dev/null differ diff --git a/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.webp b/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.webp new file mode 100644 index 00000000000..bfa7112f343 Binary files /dev/null and b/boards/arm/gd32f350r_eval/doc/img/gd32f350r_eval.webp differ diff --git a/boards/arm/gd32f350r_eval/doc/index.rst b/boards/arm/gd32f350r_eval/doc/index.rst index 35971620c17..8a2317da68e 100644 --- a/boards/arm/gd32f350r_eval/doc/index.rst +++ b/boards/arm/gd32f350r_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32F350RBT6 features a single-core ARM Cortex-M4F MCU which can run up to 108-MHz with flash accesses zero wait states, 128kB of Flash, 16kB of SRAM and 55 GPIOs. -.. image:: img/gd32f350r_eval.jpg +.. image:: img/gd32f350r_eval.webp :align: center :alt: gd32f350r_eval diff --git a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts index c3f721c4beb..84133e75e4e 100644 --- a/boards/arm/gd32f350r_eval/gd32f350r_eval.dts +++ b/boards/arm/gd32f350r_eval/gd32f350r_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f350r_eval-pinctrl.dtsi" / { diff --git a/boards/arm/gd32f403z_eval/Kconfig b/boards/arm/gd32f403z_eval/Kconfig deleted file mode 100644 index 5630f4bbf05..00000000000 --- a/boards/arm/gd32f403z_eval/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021 ATL-Electronics -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_INIT_PRIORITY - int "Board initialization priority" - default 50 - help - Board initialization priority. diff --git a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts index f2ff8bd1efc..fe96f6832a0 100644 --- a/boards/arm/gd32f403z_eval/gd32f403z_eval.dts +++ b/boards/arm/gd32f403z_eval/gd32f403z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f403z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.jpg b/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.jpg deleted file mode 100644 index efa51338401..00000000000 Binary files a/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.jpg and /dev/null differ diff --git a/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp b/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp new file mode 100644 index 00000000000..1badefd1e38 Binary files /dev/null and b/boards/arm/gd32f407v_start/doc/img/gd32f407v_start.webp differ diff --git a/boards/arm/gd32f407v_start/doc/index.rst b/boards/arm/gd32f407v_start/doc/index.rst index fd24ffb5d64..cd67921e59e 100644 --- a/boards/arm/gd32f407v_start/doc/index.rst +++ b/boards/arm/gd32f407v_start/doc/index.rst @@ -13,7 +13,7 @@ The GD32F407VE features a single-core ARM Cortex-M4 MCU which can run up to 168 MHz with flash accesses zero wait states, 3072kiB of Flash, 192kiB of SRAM and 82 GPIOs. -.. image:: img/gd32f407v_start.jpg +.. image:: img/gd32f407v_start.webp :align: center :alt: gd32f407v_start diff --git a/boards/arm/gd32f407v_start/gd32f407v_start.dts b/boards/arm/gd32f407v_start/gd32f407v_start.dts index f8df275d830..1b36e5cfdbd 100644 --- a/boards/arm/gd32f407v_start/gd32f407v_start.dts +++ b/boards/arm/gd32f407v_start/gd32f407v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f407v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450i_eval/Kconfig b/boards/arm/gd32f450i_eval/Kconfig deleted file mode 100644 index ec5800eae97..00000000000 --- a/boards/arm/gd32f450i_eval/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021 Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_INIT_PRIORITY - int "Board initialization priority" - default 50 - help - Board initialization priority. diff --git a/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg b/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg deleted file mode 100644 index 032905d9842..00000000000 Binary files a/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.jpg and /dev/null differ diff --git a/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.webp b/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.webp new file mode 100644 index 00000000000..2721d8bffbd Binary files /dev/null and b/boards/arm/gd32f450i_eval/doc/img/gd32f450i_eval.webp differ diff --git a/boards/arm/gd32f450i_eval/doc/index.rst b/boards/arm/gd32f450i_eval/doc/index.rst index 56017e4aef5..59e9d258975 100644 --- a/boards/arm/gd32f450i_eval/doc/index.rst +++ b/boards/arm/gd32f450i_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32F450IK features a single-core ARM Cortex-M4F MCU which can run up to 200 MHz with flash accesses zero wait states, 3072kiB of Flash, 256kiB of SRAM and 140 GPIOs. -.. image:: img/gd32f450i_eval.jpg +.. image:: img/gd32f450i_eval.webp :align: center :alt: gd32f450i_eval diff --git a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts index 01dd5ff86de..4e2f87c4015 100644 --- a/boards/arm/gd32f450i_eval/gd32f450i_eval.dts +++ b/boards/arm/gd32f450i_eval/gd32f450i_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450i_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg b/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg deleted file mode 100644 index f2b3f48fbca..00000000000 Binary files a/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.jpg and /dev/null differ diff --git a/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp b/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp new file mode 100644 index 00000000000..f76c58206b3 Binary files /dev/null and b/boards/arm/gd32f450v_start/doc/img/gd32f450v_start.webp differ diff --git a/boards/arm/gd32f450v_start/doc/index.rst b/boards/arm/gd32f450v_start/doc/index.rst index d3166c8ab64..e45f05a58a6 100644 --- a/boards/arm/gd32f450v_start/doc/index.rst +++ b/boards/arm/gd32f450v_start/doc/index.rst @@ -13,7 +13,7 @@ The GD32F450VK features a single-core ARM Cortex-M4F MCU which can run up to 200 MHz with flash accesses zero wait states, 3072kiB of Flash, 256kiB of SRAM and 82 GPIOs. -.. image:: img/gd32f450v_start.jpg +.. image:: img/gd32f450v_start.webp :align: center :alt: gd32f450v_start diff --git a/boards/arm/gd32f450v_start/gd32f450v_start.dts b/boards/arm/gd32f450v_start/gd32f450v_start.dts index 803ff1a9709..20500889670 100644 --- a/boards/arm/gd32f450v_start/gd32f450v_start.dts +++ b/boards/arm/gd32f450v_start/gd32f450v_start.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450v_start-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.jpg b/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.jpg deleted file mode 100644 index 7fca7753646..00000000000 Binary files a/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.jpg and /dev/null differ diff --git a/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp b/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp new file mode 100644 index 00000000000..be33bd01263 Binary files /dev/null and b/boards/arm/gd32f450z_eval/doc/img/gd32f450z_eval.webp differ diff --git a/boards/arm/gd32f450z_eval/doc/index.rst b/boards/arm/gd32f450z_eval/doc/index.rst index 179886cd0db..0e31f262db3 100644 --- a/boards/arm/gd32f450z_eval/doc/index.rst +++ b/boards/arm/gd32f450z_eval/doc/index.rst @@ -13,7 +13,7 @@ The GD32F450ZK features a single-core ARM Cortex-M4F MCU which can run up to 200 MHz with flash accesses zero wait states, 3072kiB of Flash, 256kiB of SRAM and 114 GPIOs. -.. image:: img/gd32f450z_eval.jpg +.. image:: img/gd32f450z_eval.webp :align: center :alt: gd32f450z_eval diff --git a/boards/arm/gd32f450z_eval/gd32f450z_eval.dts b/boards/arm/gd32f450z_eval/gd32f450z_eval.dts index b40cbb54c79..c636a5647c7 100644 --- a/boards/arm/gd32f450z_eval/gd32f450z_eval.dts +++ b/boards/arm/gd32f450z_eval/gd32f450z_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f450z_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f470i_eval/gd32f470i_eval.dts b/boards/arm/gd32f470i_eval/gd32f470i_eval.dts index 792533b63ac..306d190b3d4 100644 --- a/boards/arm/gd32f470i_eval/gd32f470i_eval.dts +++ b/boards/arm/gd32f470i_eval/gd32f470i_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32f470i_eval-pinctrl.dtsi" #include diff --git a/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml b/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml index 868e4907f3f..9537f9aef30 100644 --- a/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml +++ b/boards/arm/gd32f470i_eval/gd32f470i_eval.yaml @@ -14,6 +14,7 @@ toolchain: supported: - counter - dac + - flash - gpio - i2c - pwm diff --git a/boards/arm/gd32l233r_eval/gd32l233r_eval.dts b/boards/arm/gd32l233r_eval/gd32l233r_eval.dts index 31348d14920..5ee22563bd0 100644 --- a/boards/arm/gd32l233r_eval/gd32l233r_eval.dts +++ b/boards/arm/gd32l233r_eval/gd32l233r_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32l233r_eval-pinctrl.dtsi" #include diff --git a/boards/arm/google_dragonclaw/google_dragonclaw.dts b/boards/arm/google_dragonclaw/google_dragonclaw.dts index ff8dadacfa4..579adf4026f 100644 --- a/boards/arm/google_dragonclaw/google_dragonclaw.dts +++ b/boards/arm/google_dragonclaw/google_dragonclaw.dts @@ -37,6 +37,7 @@ mul-n = <192>; /* 16MHz * 192/8 = 384MHz VCO clock */ div-p = <4>; /* 96MHz PLL general clock output */ div-q = <8>; /* 48MHz PLL output for USB, SDIO, RNG */ + div-r = <7>; /* I2S - lowest possible frequency to save power */ clocks = <&clk_hsi>; status = "okay"; }; @@ -92,12 +93,38 @@ }; /* - * The board uses STM32F412CG in UFQFPN48 package in which gpio[c-h] is not + * Set flags of unused pins as GPIO_ACTIVE_HIGH (0 << 0), which will be + * interpreted by GPIO driver as GPIO_DISCONNECTED, without setting the gpio as + * either input or output. The STM32 GPIO driver will set these pins as analog + * to reduce power consumption. + */ +&gpiob { + unused { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>, <5 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpioc { + unused { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>, <14 GPIO_ACTIVE_HIGH>, + <15 GPIO_ACTIVE_HIGH>; + }; +}; + +&gpioh { + unused { + gpio-hog; + gpios = <0 GPIO_ACTIVE_HIGH>, <1 GPIO_ACTIVE_HIGH>; + }; +}; + +/* + * The board uses STM32F412CG in UFQFPN48 package in which gpio[d-g] is not * exposed, so disable it. */ -&gpioc {status = "disabled";}; &gpiod {status = "disabled";}; &gpioe {status = "disabled";}; &gpiof {status = "disabled";}; &gpiog {status = "disabled";}; -&gpioh {status = "disabled";}; diff --git a/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi b/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi index 255e1df3942..a776221cc32 100644 --- a/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi +++ b/boards/arm/hexiwear_k64/hexiwear_k64-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK64FN1M0VDC12/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi b/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi index 86e0e71a4ca..30ccd75c81a 100644 --- a/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi +++ b/boards/arm/ip_k66f/ip_k66f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK66FN2M0VMD18/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts index 268573de547..02602825712 100644 --- a/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts +++ b/boards/arm/lora_e5_dev_board/lora_e5_dev_board.dts @@ -17,7 +17,7 @@ zephyr,shell-uart = &usart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { @@ -79,7 +79,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { status = "okay"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; @@ -176,6 +176,19 @@ grove_i2c: &i2c2 {}; #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(32)>; + read-only; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 DT_SIZE_K(104)>; + }; + slot1_partition: partition@22000 { + label = "image-1"; + reg = <0x00022000 DT_SIZE_K(104)>; + }; /* 16KB (8x2kB pages) of storage at the end of the flash */ storage_partition: partition@3c000 { label = "storage"; diff --git a/boards/arm/lora_e5_mini/Kconfig.board b/boards/arm/lora_e5_mini/Kconfig.board new file mode 100644 index 00000000000..1b4e30a54c4 --- /dev/null +++ b/boards/arm/lora_e5_mini/Kconfig.board @@ -0,0 +1,8 @@ +# LoRa-E5 mini configuration + +# Copyright (c) 2023 Marcin Niestroj +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_LORA_E5_MINI + bool "LoRa E5 mini" + depends on SOC_STM32WLE5XX diff --git a/boards/arm/lora_e5_mini/Kconfig.defconfig b/boards/arm/lora_e5_mini/Kconfig.defconfig new file mode 100644 index 00000000000..ca35c4321a0 --- /dev/null +++ b/boards/arm/lora_e5_mini/Kconfig.defconfig @@ -0,0 +1,11 @@ +# LoRa-E5 mini configuration + +# Copyright (c) 2023 Marcin Niestroj +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_LORA_E5_MINI + +config BOARD + default "lora_e5_mini" + +endif # BOARD_LORA_E5_MINI diff --git a/boards/arm/lora_e5_mini/board.cmake b/boards/arm/lora_e5_mini/board.cmake new file mode 100644 index 00000000000..ac24f811559 --- /dev/null +++ b/boards/arm/lora_e5_mini/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(pyocd "--target=stm32wle5jcix") +board_runner_args(pyocd "--flash-opt=-O reset_type=hw") +board_runner_args(pyocd "--flash-opt=-O connect_mode=under-reset") +board_runner_args(jlink "--device=STM32WLE5JC" "--speed=4000" "--reset-after-load") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +board_runner_args(blackmagicprobe "--connect-rst") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg b/boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg new file mode 100644 index 00000000000..8b22ba96ea6 Binary files /dev/null and b/boards/arm/lora_e5_mini/doc/img/lora_e5_mini.jpg differ diff --git a/boards/arm/lora_e5_mini/doc/img/lora_e5_mini_pinout.jpg b/boards/arm/lora_e5_mini/doc/img/lora_e5_mini_pinout.jpg new file mode 100644 index 00000000000..2cc0f5e17eb Binary files /dev/null and b/boards/arm/lora_e5_mini/doc/img/lora_e5_mini_pinout.jpg differ diff --git a/boards/arm/lora_e5_mini/doc/index.rst b/boards/arm/lora_e5_mini/doc/index.rst new file mode 100644 index 00000000000..6e6be186dd7 --- /dev/null +++ b/boards/arm/lora_e5_mini/doc/index.rst @@ -0,0 +1,226 @@ +.. _lora_e5_mini: + +Seeed Studio LoRa-E5 mini +######################### + +Overview +******** + +LoRa-E5 mini is a compacted-sized development board suitable for the rapid +testing and building of small-sized LoRa device, exposing all capabilities of +Seeed Studio LoRa-E5 STM32WLE5JC module. + +.. image:: img/lora_e5_mini.jpg + :align: center + :alt: LoRa-E5 mini + +Hardware +******** + +The boards' LoRa-E5 Module packages a STM32WLE5JC SOC, a 32MHz TCXO, +and a 32.768kHz crystal oscillator in a 28-pin SMD package. +This STM32WLEJC SOC is powered by ARM Cortex-M4 core and integrates Semtech +SX126X LoRa IP to support (G)FSK, BPSK, (G)MSK, and LoRa modulations. + +- LoRa-E5 STM32WLE5JC Module with STM32WLE5JC multiprotocol LPWAN single-core + 32-bit microcontroller (Arm® Cortex®-M4 at 48 MHz) in 28-pin SMD package + featuring: + + - Ultra-low-power MCU + - RF transceiver (150 MHz to 960 MHz frequency range) supporting LoRa®, + (G)FSK, (G)MSK, and BPSK modulations + - 256-Kbyte Flash memory and 64-Kbyte SRAM + - Hardware encryption AES256-bit and a True random number generator + +- 1 user LED +- 2 serial communication (RX/TX) LEDs +- 1 boot/user and 1 reset push-button +- 32.768 kHz LSE crystal oscillator +- 32 MHz HSE oscillator +- Board connectors: + + - USB Type-C connector + - +/- (battery) power input pins (3-5V) + - SMA-K and IPEX antenna connectors + +- Delivered with SMA antenna (per default IPEX connector is disconnected) +- Flexible power-supply options: USB Type C or 3-5V battery soldered to +/- pins +- Suitable for rapid prototyping of end nodes based on LoRaWAN, Sigfox, wM-Bus, + and many other proprietary protocols +- All GPIOs led out from the LoRa-E5 STM32WLE5JC module +- 4x M2 mounting holes + +More information about the board can be found at the `LoRa-E5 mini Wiki`_. + +More information about LoRa-E5 STM32WLE5JC Module can be found here: + +- `LoRa-E5 STM32WLE5JC Module Wiki`_ +- `LoRa-E5 STM32WLE5JC Module datasheet`_ +- `STM32WLE5JC datasheet`_ +- `STM32WLE5JC reference manual`_ +- `STM32WLE5JC on www.st.com`_ + +Supported Features +================== + +The Zephyr LoRa-E5 mini configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| AES | on-chip | crypto | ++-----------+------------+-------------------------------------+ +| COUNTER | on-chip | rtc | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| FLASH | on-chip | flash | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+-------------------------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | LoRa | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig and dts files: + +- :zephyr_file:`boards/arm/lora_e5_mini/lora_e5_mini_defconfig` +- :zephyr_file:`boards/arm/lora_e5_mini/lora_e5_mini.dts` + + +Connections and IOs +=================== + +LoRa-E5 mini has 4 GPIO controllers. These controllers are responsible for pin +muxing, input/output, pull-up, etc. + +Available pins: +--------------- + +.. image:: img/lora_e5_mini_pinout.jpg + :align: center + :alt: LoRa-E5 mini Pinout + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- USART_1 TX : PB6 +- USART_1 RX : PB7 +- I2C_2_SCL : PB15 +- I2C_2_SDA : PA15 +- BOOT_PB : PB13 +- LED_1 : PB5 + +System Clock +------------ + +LoRa-E5 mini board System Clock could be driven by the low-power internal (MSI), +High-speed internal (HSI) or High-speed external (HSE) oscillator, as well as +main PLL clock. By default System clock is driven by the MSI clock at 48MHz. + +Programming and Debugging +************************* + +Applications for the ``lora_e5_mini`` board configuration can be built the +usual way (see :ref:`build_an_application`). + +In the factory the module is flashed with an DFU bootloader, an AT command +firmware, and the read protection level 1 is enabled. +So before you can program a Zephyr application to the module for the first time +you have to reset the read protection to level 0. +In case you use an st-link debugger you can use the STM32CubeProgrammer GUI to +set the RDP option byte to ``AA``, +or use the STM32_Programmer_CLI passing the ``--readunprotect`` command +to perform this read protection regression. +The RDP level 1 to RDP level 0 regression will erase the factory programmed AT +firmware, from which seeed has neither released the source code nor a binary. +Also, note that on the module the ``BOOT0`` pin of the SOC is not accessible, +so the system bootloader will only be executed if configured in the option bytes. + +Flashing +======== + +The LoRa-E5 mini does not include a on-board debug probe. +But the module can be debugged by connecting an external debug probe to the +2.54mm header. +Depending on the external probe used, ``openocd``, the ``stm32cubeprogrammer``, +``pyocd``, ``blackmagic``, or ``jlink`` runner can be used to flash the board. +Additional notes: + +- Pyocd: For STM32WL support Pyocd needs additional target information, which + can be installed by adding "pack" support with the following pyocd command: + +.. code-block:: console + + $ pyocd pack --update + $ pyocd pack --install stm32wl + +Flashing an application to LoRa-E5 mini +--------------------------------------- + +Connect the LoRa-E5 to your host computer using the external debug probe. +Then build and flash an application. Here is an example for the +:ref:`hello_world` application. + +Run a serial host program to connect with your board: +Per default the console on ``usart1`` is available on the USB Type C connector +via the built-in USB to UART converter. + +.. code-block:: console + + $ picocom --baud 115200 /dev/ttyACM0 + +Then build and flash the application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: lora_e5_mini + :goals: build flash + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: lora_e5_mini + :maybe-skip-config: + :goals: debug + +.. _LoRa-E5 mini Wiki: + https://wiki.seeedstudio.com/LoRa_E5_mini/ + +.. _LoRa-E5 STM32WLE5JC Module Wiki: + https://wiki.seeedstudio.com/LoRa-E5_STM32WLE5JC_Module/ + +.. _LoRa-E5 STM32WLE5JC Module datasheet: + https://files.seeedstudio.com/products/317990687/res/LoRa-E5%20module%20datasheet_V1.0.pdf + +.. _STM32WLE5JC on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wle5jc.html + +.. _STM32WLE5JC datasheet: + https://www.st.com/resource/en/datasheet/stm32wle5jc.pdf + +.. _STM32WLE5JC reference manual: + https://www.st.com/resource/en/reference_manual/dm00530369-stm32wlex-advanced-armbased-32bit-mcus-with-subghz-radio-solution-stmicroelectronics.pdf diff --git a/boards/arm/lora_e5_mini/lora_e5_mini.dts b/boards/arm/lora_e5_mini/lora_e5_mini.dts new file mode 100644 index 00000000000..e65572c6e35 --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini.dts @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023 Marcin Niestroj + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include + +/ { + model = "Seeed Studio LoRa-E5 mini"; + compatible = "seeed,lora-e5-mini"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + leds { + compatible = "gpio-leds"; + red_led_1: led_1 { + gpios = <&gpiob 5 GPIO_ACTIVE_LOW>; + label = "User LED1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + boot_button: button_0 { + label = "SW1"; + gpios = <&gpiob 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &red_led_1; + sw0 = &boot_button; + lora0 = &lora; + watchdog0 = &iwdg; + }; +}; + +stm32_lp_tick_source: &lptim1 { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, + <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_msi { + status = "okay"; + msi-range = <11>; +}; + +&rcc { + clocks = <&clk_msi>; + clock-frequency = ; + cpu1-prescaler = <1>; + ahb3-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pb15 &i2c2_sda_pa15>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00000400>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&aes { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(96)>; + }; + slot1_partition: partition@24000 { + label = "image-1"; + reg = <0x00024000 DT_SIZE_K(96)>; + }; + + /* 16KB (8x2kB pages) of storage at the end of the flash */ + storage_partition: partition@3c000 { + label = "storage"; + reg = <0x0003c000 DT_SIZE_K(16)>; + }; + }; +}; diff --git a/boards/arm/lora_e5_mini/lora_e5_mini.yaml b/boards/arm/lora_e5_mini/lora_e5_mini.yaml new file mode 100644 index 00000000000..144ee2275ad --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini.yaml @@ -0,0 +1,19 @@ +identifier: lora_e5_mini +name: Seeedstudio LoRa-E5 mini +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 64 +flash: 256 +supported: + - counter + - gpio + - i2c + - nvs + - uart + - watchdog + - lora +vendor: seeed diff --git a/boards/arm/lora_e5_mini/lora_e5_mini_defconfig b/boards/arm/lora_e5_mini/lora_e5_mini_defconfig new file mode 100644 index 00000000000..5e6649fe25a --- /dev/null +++ b/boards/arm/lora_e5_mini/lora_e5_mini_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WLX=y +CONFIG_SOC_STM32WLE5XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/lora_e5_mini/support/openocd.cfg b/boards/arm/lora_e5_mini/support/openocd.cfg new file mode 100644 index 00000000000..f4902698c63 --- /dev/null +++ b/boards/arm/lora_e5_mini/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wlx.cfg] + +reset_config srst_only diff --git a/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml b/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml index e59360c084b..192ca797f62 100644 --- a/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml +++ b/boards/arm/lpcxpresso11u68/lpcxpresso11u68.yaml @@ -2,6 +2,8 @@ identifier: lpcxpresso11u68 name: NXP LPCxpresso 11U68 type: mcu arch: arm +ram: 32 +flash: 256 toolchain: - zephyr supported: diff --git a/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi b/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi index a99ee0b6018..da944a569f5 100644 --- a/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi +++ b/boards/arm/lpcxpresso51u68/lpcxpresso51u68-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso51U68.mex */ diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi b/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi index 7647f98ad44..b648cd94c4f 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso54114.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s06/Kconfig.defconfig b/boards/arm/lpcxpresso55s06/Kconfig.defconfig index 57d53c1489a..48340c5f589 100644 --- a/boards/arm/lpcxpresso55s06/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s06/Kconfig.defconfig @@ -8,4 +8,11 @@ if BOARD_LPCXPRESSO55S06 config BOARD default "lpcxpresso55s06" +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S06 diff --git a/boards/arm/lpcxpresso55s06/board.cmake b/boards/arm/lpcxpresso55s06/board.cmake index 305ed963f21..a6df50bba73 100644 --- a/boards/arm/lpcxpresso55s06/board.cmake +++ b/boards/arm/lpcxpresso55s06/board.cmake @@ -8,5 +8,5 @@ board_runner_args(linkserver "--device=LPC55S06:LPCXpresso55S06") board_runner_args(jlink "--device=LPC55S06" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi b/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi index 3f4ed27b488..a6be7665a10 100644 --- a/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s06/lpcxpresso55s06-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S06.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s16/Kconfig.defconfig b/boards/arm/lpcxpresso55s16/Kconfig.defconfig index 49ed6830ed2..2979ac8808d 100644 --- a/boards/arm/lpcxpresso55s16/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s16/Kconfig.defconfig @@ -12,4 +12,11 @@ config FXOS8700_DRDY_INT1 default y depends on FXOS8700_TRIGGER +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S16 diff --git a/boards/arm/lpcxpresso55s16/board.cmake b/boards/arm/lpcxpresso55s16/board.cmake index 45ca5dcfe1c..f1a6370b01f 100644 --- a/boards/arm/lpcxpresso55s16/board.cmake +++ b/boards/arm/lpcxpresso55s16/board.cmake @@ -9,6 +9,6 @@ board_runner_args(linkserver "--device=LPC55S16:LPCXpresso55S16") board_runner_args(jlink "--device=LPC55S16" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s16") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi b/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi index c0b2c76c540..5da72450523 100644 --- a/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s16/lpcxpresso55s16-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S16.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s28/Kconfig.defconfig b/boards/arm/lpcxpresso55s28/Kconfig.defconfig index 40e95c1b388..ee3fd9685c4 100644 --- a/boards/arm/lpcxpresso55s28/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s28/Kconfig.defconfig @@ -37,4 +37,11 @@ config FLASH_LOAD_SIZE default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION)) depends on BOARD_LPCXPRESSO55S28 && TRUSTED_EXECUTION_SECURE +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S28 diff --git a/boards/arm/lpcxpresso55s28/board.cmake b/boards/arm/lpcxpresso55s28/board.cmake index 9cd2296a404..933e3815a8c 100644 --- a/boards/arm/lpcxpresso55s28/board.cmake +++ b/boards/arm/lpcxpresso55s28/board.cmake @@ -4,8 +4,10 @@ # SPDX-License-Identifier: Apache-2.0 # +board_runner_args(linkserver "--device=LPC55S28:LPCXpresso55S28") board_runner_args(pyocd "--target=lpc55s28") board_runner_args(jlink "--device=LPC55S28" "--reset-after-load") -include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi b/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi index a8955d2a034..dbf467f3c16 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S28.mex * * Copyright 2022 NXP diff --git a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts index 7f311be98db..a71ffb15157 100644 --- a/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts +++ b/boards/arm/lpcxpresso55s28/lpcxpresso55s28.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Lemonbeat GmbH + * Copyright 2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,9 +26,11 @@ chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,console = &flexcomm0; zephyr,shell-uart = &flexcomm0; zephyr,entropy = &rng; + zephyr,flash-controller = &iap; }; gpio_keys { @@ -95,22 +98,27 @@ }; &flash0 { - /* - * LPC flash controller requires minimum 512 byte write to flash, - * so MCUBoot is not supported. Just provide storage and code partition. - */ partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; - slot0_partition: partition@0 { + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 DT_SIZE_K(32)>; + }; + slot0_partition: partition@8000 { label = "image-0"; - reg = <0x00000000 DT_SIZE_K(448)>; + reg = <0x00008000 DT_SIZE_K(208)>; + }; + slot1_partition: partition@3C000 { + label = "image-1"; + reg = <0x0003C000 DT_SIZE_K(208)>; }; storage_partition: partition@70000 { label = "storage"; - reg = <0x00070000 DT_SIZE_K(64)>; + reg = <0x00070000 DT_SIZE_K(52)>; }; + /* The last 12KBs are reserved for PFR. */ }; }; diff --git a/boards/arm/lpcxpresso55s36/Kconfig.defconfig b/boards/arm/lpcxpresso55s36/Kconfig.defconfig index 3f3b1305bf7..fd3ea5cd189 100644 --- a/boards/arm/lpcxpresso55s36/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s36/Kconfig.defconfig @@ -8,4 +8,11 @@ if BOARD_LPCXPRESSO55S36 config BOARD default "lpcxpresso55s36" +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S36 diff --git a/boards/arm/lpcxpresso55s36/board.cmake b/boards/arm/lpcxpresso55s36/board.cmake index b1e16906bd5..d1a92d0164d 100644 --- a/boards/arm/lpcxpresso55s36/board.cmake +++ b/boards/arm/lpcxpresso55s36/board.cmake @@ -8,6 +8,6 @@ board_runner_args(linkserver "--device=LPC55S36:LPCXpresso55S36") board_runner_args(jlink "--device=LPC55S36" "--reset-after-load") board_runner_args(pyocd "--target=lpc55s36") -include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi b/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi index 8ca6f659f2e..619b275b593 100644 --- a/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s36/lpcxpresso55s36-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPC55S36.mex * * Copyright 2022-2023 NXP diff --git a/boards/arm/lpcxpresso55s69/Kconfig.defconfig b/boards/arm/lpcxpresso55s69/Kconfig.defconfig index 7c98507e35c..c8bc5421e09 100644 --- a/boards/arm/lpcxpresso55s69/Kconfig.defconfig +++ b/boards/arm/lpcxpresso55s69/Kconfig.defconfig @@ -55,4 +55,11 @@ choice TFM_PROFILE_TYPE default TFM_PROFILE_TYPE_MEDIUM endchoice +if BOOTLOADER_MCUBOOT +choice MCUBOOT_BOOTLOADER_MODE + # Board only supports MCUBoot via "upgrade only" method: + default MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY +endchoice +endif #BOOTLOADER_MCUBOOT + endif # BOARD_LPCXPRESSO55S69_CPU0 || BOARD_LPCXPRESSO55S69_CPU1 diff --git a/boards/arm/lpcxpresso55s69/board.cmake b/boards/arm/lpcxpresso55s69/board.cmake index 21ed8e82672..ed9aedf4f4e 100644 --- a/boards/arm/lpcxpresso55s69/board.cmake +++ b/boards/arm/lpcxpresso55s69/board.cmake @@ -19,6 +19,10 @@ endif() board_runner_args(pyocd "--target=lpc55s69") +if(CONFIG_BUILD_WITH_TFM) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex) +endif() + include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) diff --git a/boards/arm/lpcxpresso55s69/doc/index.rst b/boards/arm/lpcxpresso55s69/doc/index.rst index 408cd18aa91..1f8d46cef48 100644 --- a/boards/arm/lpcxpresso55s69/doc/index.rst +++ b/boards/arm/lpcxpresso55s69/doc/index.rst @@ -101,6 +101,8 @@ configuration supports the following hardware features: +-----------+------------+-------------------------------------+ | SDIF | on-chip | sdhc | +-----------+------------+-------------------------------------+ +| DMA | on-chip | dma (on CPU0) | ++-----------+------------+-------------------------------------+ Targets available ================== @@ -256,7 +258,7 @@ Dual Core samples System Clock ============ -The LPC55S69 SoC is configured to use PLL1 clocked from the external 24MHz +The LPC55S69 SoC is configured to use PLL1 clocked from the external 16MHz crystal, running at 144MHz as a source for the system clock. When the flash controller is enabled, the core clock will be reduced to 96MHz. The application may reconfigure clocks after initialization, provided that the core clock is diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi b/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi index 5842f1f7eb2..96997936388 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S69.mex * * Copyright 2022 NXP diff --git a/boards/arm/mercury_xu/board.c b/boards/arm/mercury_xu/board.c index 8204b29ae90..db436299a9c 100644 --- a/boards/arm/mercury_xu/board.c +++ b/boards/arm/mercury_xu/board.c @@ -6,24 +6,9 @@ #include #include -#define MIO_PIN_18 0xff180048 -#define MIO_PIN_19 0xff18004c -#define MIO_PIN_38 0xff180098 -#define MIO_PIN_39 0xff18009c - -#define MIO_DEFAULT 0x0 -#define MIO_UART0 0xc0 static int mercury_xu_init(void) { - /* pinmux settings for uart */ - sys_write32(MIO_UART0, MIO_PIN_38); - sys_write32(MIO_UART0, MIO_PIN_39); - - /* disable misleading pinmux */ - sys_write32(MIO_DEFAULT, MIO_PIN_18); - sys_write32(MIO_DEFAULT, MIO_PIN_19); - return 0; } diff --git a/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi new file mode 100644 index 00000000000..3bc31ad3c74 --- /dev/null +++ b/boards/arm/mercury_xu/mercury_xu-pinctrl.dtsi @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + }; + }; + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + }; + }; + +}; diff --git a/boards/arm/mercury_xu/mercury_xu.dts b/boards/arm/mercury_xu/mercury_xu.dts index c58e48e31f9..df51ab470c5 100644 --- a/boards/arm/mercury_xu/mercury_xu.dts +++ b/boards/arm/mercury_xu/mercury_xu.dts @@ -6,6 +6,7 @@ /dts-v1/; #include +#include "mercury_xu-pinctrl.dtsi" / { model = "Mercury XU"; @@ -13,6 +14,7 @@ chosen { zephyr,console = &uart0; + zephyr,shell-uart = &uart0; zephyr,sram = &sram0; zephyr,flash = &flash0; }; @@ -27,9 +29,20 @@ status = "okay"; current-speed = <115200>; clock-frequency = <99999901>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&uart1 { + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; }; &ttc0 { status = "okay"; clock-frequency = <5000000>; }; + +&psgpio { + status = "okay"; +}; diff --git a/boards/arm/mercury_xu/mercury_xu_defconfig b/boards/arm/mercury_xu/mercury_xu_defconfig index 6655cf9a442..d01d7082f94 100644 --- a/boards/arm/mercury_xu/mercury_xu_defconfig +++ b/boards/arm/mercury_xu/mercury_xu_defconfig @@ -11,3 +11,5 @@ CONFIG_UART_CONSOLE=y # enable timer CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 + +CONFIG_PINCTRL=y diff --git a/boards/arm/mg100/mg100.dts b/boards/arm/mg100/mg100.dts index 1bbaa146dd6..67f4b3677a5 100644 --- a/boards/arm/mg100/mg100.dts +++ b/boards/arm/mg100/mg100.dts @@ -65,6 +65,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts b/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts index 60f270855a7..e9d3b46d3b4 100644 --- a/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts +++ b/boards/arm/mikroe_mini_m4_for_stm32/mikroe_mini_m4_for_stm32.dts @@ -38,6 +38,10 @@ }; }; +&clk_lsi { + status = "okay"; +}; + &clk_hse { clock-frequency = ; status = "okay"; @@ -99,3 +103,9 @@ zephyr_udc0: &usbotg_fs { &cryp { status = "okay"; }; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; diff --git a/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi b/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi index c345742bc7e..c7b1943810e 100644 --- a/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mm_evk/mimx8mm_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from MIMX8MM-EVK-REV-C.mex */ diff --git a/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml b/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml index 8854d16ac55..4c1779778ba 100644 --- a/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml +++ b/boards/arm/mimx8mm_evk/mimx8mm_evk.yaml @@ -8,8 +8,8 @@ identifier: mimx8mm_evk name: NXP i.MX8M Mini EVK type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml b/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml index ee0fd50bf5f..399336291f9 100644 --- a/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml +++ b/boards/arm/mimx8mm_phyboard_polis/mimx8mm_phyboard_polis.yaml @@ -8,8 +8,8 @@ identifier: mimx8mm_phyboard_polis name: Phyboard Polis i.MX8M Mini type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi b/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi index f9ca5de1ff2..a690f201ba1 100644 --- a/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mp_evk/mimx8mp_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from MIMX8MP-EVK-REV-A.mex */ diff --git a/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi b/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi index 62e3944f73c..c29fdcc7d28 100644 --- a/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi +++ b/boards/arm/mimx8mq_evk/mimx8mq_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from fsl-imx8mq-evk.mex */ diff --git a/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml b/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml index 580b8cef0f3..f5fee9cea2f 100644 --- a/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml +++ b/boards/arm/mimx8mq_evk/mimx8mq_evk_cm4.yaml @@ -8,8 +8,8 @@ identifier: mimx8mq_evk_cm4 name: NXP i.MX8MQ EVK CM4 type: mcu arch: arm -ram: 32 -flash: 32 +ram: 128 +flash: 128 toolchain: - zephyr - gnuarmemb diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi b/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi index 65b31812349..9d190081e32 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1010_evk.mex */ diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts index 71f755bacde..330de94d692 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.dts @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 TiaC Systems - * Copyright (c) 2019, NXP + * Copyright 2019,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,9 +23,12 @@ chosen { zephyr,sram = &ocram; zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; + zephyr,flash-controller = &at25sf128a; + zephyr,code-partition = &slot0_partition; }; leds { @@ -93,6 +96,30 @@ arduino_serial: &lpuart1 {}; spi-max-frequency = <133000000>; status = "okay"; jedec-id = [1f 89 01]; + erase-block-size = <4096>; + write-block-size = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(7)>; + }; + slot1_partition: partition@710000 { + label = "image-1"; + reg = <0x00710000 DT_SIZE_M(7)>; + }; + storage_partition: partition@E10000 { + label = "storage"; + reg = <0x00E10000 DT_SIZE_K(1984)>; + }; + }; }; }; diff --git a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml index 302b3c64d80..e611af6c798 100644 --- a/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml +++ b/boards/arm/mimxrt1010_evk/mimxrt1010_evk.yaml @@ -13,7 +13,7 @@ toolchain: - zephyr - gnuarmemb - xtools -ram: 32 +ram: 64 flash: 16384 supported: - arduino_gpio diff --git a/boards/arm/mimxrt1015_evk/board.cmake b/boards/arm/mimxrt1015_evk/board.cmake index be9b7ba10e1..442bf1b43e2 100644 --- a/boards/arm/mimxrt1015_evk/board.cmake +++ b/boards/arm/mimxrt1015_evk/board.cmake @@ -1,10 +1,13 @@ # -# Copyright (c) 2019, NXP +# Copyright (c) 2019, 2024 NXP # # SPDX-License-Identifier: Apache-2.0 # board_runner_args(pyocd "--target=mimxrt1015") board_runner_args(jlink "--device=MIMXRT1015") +board_runner_args(linkserver "--device=MIMXRT1015xxxxx:EVK-MIMXRT1015") + +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/mimxrt1015_evk/doc/index.rst b/boards/arm/mimxrt1015_evk/doc/index.rst index d3e44a5b040..f7d6bc1db6e 100644 --- a/boards/arm/mimxrt1015_evk/doc/index.rst +++ b/boards/arm/mimxrt1015_evk/doc/index.rst @@ -168,13 +168,26 @@ Configuring a Debug Probe ========================= A debug probe is used for both flashing and debugging the board. This board is -configured by default to use the :ref:`opensda-daplink-onboard-debug-probe`, -however the :ref:`pyocd-debug-host-tools` do not yet support programming the -external flashes on this board so you must reconfigure the board for one of the -following debug probes instead. +configured by default to use the :ref:`opensda-daplink-onboard-debug-probe`. -:ref:`jlink-external-debug-probe` -------------------------------------------- +Using LinkServer: :ref:`opensda-daplink-onboard-debug-probe` +------------------------------------------------------------ + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + + +External JLink: :ref:`jlink-external-debug-probe` +------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. diff --git a/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi b/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi index 412eeeb0e4c..b77d1ee424e 100644 --- a/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1015_evk/mimxrt1015_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1015_evk.mex */ diff --git a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts index a3df588c9af..0a28acc04ca 100644 --- a/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts +++ b/boards/arm/mimxrt1015_evk/mimxrt1015_evk.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, NXP + * Copyright 2019,2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,11 +20,14 @@ }; chosen { - zephyr,sram = &dtcm; + zephyr,sram = &ocram; zephyr,itcm = &itcm; + zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; zephyr,flash = &at25sf128a; + zephyr,flash-controller = &at25sf128a; + zephyr,code-partition = &slot0_partition; }; leds { @@ -81,14 +84,39 @@ arduino_serial: &lpuart4 { }; &flexspi { + status = "okay"; reg = <0x402a8000 0x4000>, <0x60000000 DT_SIZE_M(16)>; at25sf128a: at25sf128a@0 { compatible = "nxp,imx-flexspi-nor"; - size = <134217728>; + size = ; reg = <0>; spi-max-frequency = <133000000>; status = "okay"; jedec-id = [1f 89 01]; + erase-block-size = <4096>; + write-block-size = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(7)>; + }; + slot1_partition: partition@710000 { + label = "image-1"; + reg = <0x00710000 DT_SIZE_M(7)>; + }; + storage_partition: partition@E10000 { + label = "storage"; + reg = <0x00E10000 DT_SIZE_K(1984)>; + }; + }; }; }; diff --git a/boards/arm/mimxrt1020_evk/board.cmake b/boards/arm/mimxrt1020_evk/board.cmake index f3c9ac623ed..cfab4278fb4 100644 --- a/boards/arm/mimxrt1020_evk/board.cmake +++ b/boards/arm/mimxrt1020_evk/board.cmake @@ -6,6 +6,8 @@ board_runner_args(pyocd "--target=mimxrt1020") board_runner_args(jlink "--device=MIMXRT1021xxx5A") +board_runner_args(linkserver "--device=MIMXRT1021xxxxx:EVK-MIMXRT1020") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/mimxrt1020_evk/doc/index.rst b/boards/arm/mimxrt1020_evk/doc/index.rst index 40f45565a6e..751ec16687b 100644 --- a/boards/arm/mimxrt1020_evk/doc/index.rst +++ b/boards/arm/mimxrt1020_evk/doc/index.rst @@ -231,8 +231,23 @@ however the :ref:`pyocd-debug-host-tools` do not yet support programming the external flashes on this board so you must reconfigure the board for one of the following debug probes instead. -Option 1: :ref:`opensda-jlink-onboard-debug-probe` (Recommended) ----------------------------------------------------------------- +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + +JLink (on-board): :ref:`opensda-jlink-onboard-debug-probe` +---------------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -242,8 +257,8 @@ the `OpenSDA J-Link MIMXRT1020-EVK Firmware`_. Check that jumpers J27 and J28 are **on** (they are on by default when boards ship from the factory) to ensure SWD signals are connected to the OpenSDA microcontroller. -Option 2: :ref:`jlink-external-debug-probe` -------------------------------------------- +External JLink: :ref:`jlink-external-debug-probe` +------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. diff --git a/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi b/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi index 8da66d34084..9fe3a42bf9f 100644 --- a/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1020_evk/mimxrt1020_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1020_evk.mex */ diff --git a/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts b/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts index 4f8d3b803c6..e873a0f2167 100644 --- a/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts +++ b/boards/arm/mimxrt1020_evk/mimxrt1020_evk.dts @@ -112,21 +112,20 @@ arduino_serial: &lpuart2 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1024_evk/Kconfig.defconfig b/boards/arm/mimxrt1024_evk/Kconfig.defconfig index 704743ded71..db0a2eb1fed 100644 --- a/boards/arm/mimxrt1024_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1024_evk/Kconfig.defconfig @@ -27,9 +27,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING endif # BOARD_MIMXRT1024_EVK diff --git a/boards/arm/mimxrt1024_evk/doc/index.rst b/boards/arm/mimxrt1024_evk/doc/index.rst index 303dad37538..c04a3f5d090 100644 --- a/boards/arm/mimxrt1024_evk/doc/index.rst +++ b/boards/arm/mimxrt1024_evk/doc/index.rst @@ -299,3 +299,13 @@ should see the following message in the terminal: .. _i.MX RT1024 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT1024RM + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1024_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1024_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..2229b2a9b70 --- /dev/null +++ b/boards/arm/mimxrt1024_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,135 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_b0_08_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_b0_09_enet_rx_data1>, + <&iomuxc_gpio_ad_b0_11_enet_rx_en>, + <&iomuxc_gpio_ad_b0_14_enet_tx_data0>, + <&iomuxc_gpio_ad_b0_15_enet_tx_data1>, + <&iomuxc_gpio_ad_b0_13_enet_tx_en>, + <&iomuxc_gpio_ad_b0_12_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_b0_10_enet_rx_data0>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdio>, + <&iomuxc_gpio_emc_41_enet_mdc>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + group1 { + pinmux = <&iomuxc_gpio_ad_b1_06_gpio1_io22>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + group2 { + pinmux = <&iomuxc_gpio_ad_b0_04_gpio1_io04>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "100-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + /* Intentionally empty */ + }; +}; diff --git a/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi b/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi index 3e27286cc23..1090e394381 100644 --- a/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1024_evk/mimxrt1024_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1024_evk.mex */ diff --git a/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts b/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts index 164e7cdb654..7377cd0f1d8 100644 --- a/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts +++ b/boards/arm/mimxrt1024_evk/mimxrt1024_evk.dts @@ -70,25 +70,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; - + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_K(1920)>; + reg = <0x00010000 DT_SIZE_K(1924)>; }; - - slot1_partition: partition@1f0000 { + slot1_partition: partition@1f1000 { label = "image-1"; - reg = <0x001F0000 DT_SIZE_K(1920)>; + reg = <0x001F1000 DT_SIZE_K(1920)>; }; - - storage_partition: partition@3d0000 { + storage_partition: partition@3d1000 { label = "storage"; - reg = <0x003D0000 DT_SIZE_K(128)>; - }; - - scratch_partition: partition@3f0000 { - label = "image-scratch"; - reg = <0x003f0000 DT_SIZE_K(64)>; + reg = <0x003D1000 DT_SIZE_K(188)>; }; }; }; diff --git a/boards/arm/mimxrt1040_evk/board.cmake b/boards/arm/mimxrt1040_evk/board.cmake index 54d459f5c08..10e09bc1405 100644 --- a/boards/arm/mimxrt1040_evk/board.cmake +++ b/boards/arm/mimxrt1040_evk/board.cmake @@ -5,5 +5,9 @@ # board_runner_args(jlink "--device=MIMXRT1042XXX6B") +board_runner_args(linkserver "--device=MIMXRT1042xxxxB:MIMXRT1040-EVK") +board_runner_args(pyocd "--target=MIMXRT1042XJM5B") include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/mimxrt1040_evk/doc/index.rst b/boards/arm/mimxrt1040_evk/doc/index.rst index f5ca4ed99cd..651a0aebff9 100644 --- a/boards/arm/mimxrt1040_evk/doc/index.rst +++ b/boards/arm/mimxrt1040_evk/doc/index.rst @@ -291,6 +291,13 @@ should see the following message in the terminal: Troubleshooting =============== +USER_LED D8 +----------- +The MIMXRT1040-EVK board ships with the wireless module in the M.2 connector, +and with jumper J80 shorted. This causes a conflict with the USER_LED D8, +and the LED will not turn off. Samples and applications using USER_LED D8, +like blinky, require removal of J80 jumper. + Boot Header ----------- @@ -347,7 +354,7 @@ flashing or debugging it, or remove jumper J80. https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1040-evaluation-kit:MIMXRT1040-EVK .. _MIMXRT1040-EVK User Guide: - https://www.nxp.com/docs/en/user-manual/MIMXRT1040-EVKUM.pdf + https://www.nxp.com/webapp/Download?colCode=MIMXRT1040-EVKUM .. _MIMXRT1040-EVK Design Files: https://www.nxp.com/webapp/Download?colCode=MIMXRT1040-EVK-DESIGNFILES @@ -356,7 +363,7 @@ flashing or debugging it, or remove jumper J80. https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/i-mx-rt-crossover-mcus/i-mx-rt1040-crossover-mcu-with-arm-cortex-m7-core:i.MX-RT1040 .. _i.MX RT1040 Datasheet: - https://www.nxp.com/docs/en/data-sheet/IMXRT1040CECDS.pdf + https://www.nxp.com/docs/en/data-sheet/IMXRT1040CEC.pdf .. _i.MX RT1040 Reference Manual: https://www.nxp.com/webapp/Download?colCode=IMXRT1040RM diff --git a/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi b/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi index 2ddc0771bb0..ad26eeecc3f 100644 --- a/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1040_evk/mimxrt1040_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2023, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1040_evk.mex */ diff --git a/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts b/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts index 6e9a9c4c2bb..5beae5ffc40 100644 --- a/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts +++ b/boards/arm/mimxrt1040_evk/mimxrt1040_evk.dts @@ -21,12 +21,14 @@ }; chosen { - zephyr,flash = &w25q64jvssiq; zephyr,sram = &sdram0; zephyr,itcm = &itcm; zephyr,dtcm = &dtcm; zephyr,console = &lpuart1; zephyr,shell-uart = &lpuart1; + zephyr,flash = &w25q64jvssiq; + zephyr,flash-controller = &w25q64jvssiq; + zephyr,code-partition = &slot0_partition; }; sdram0: memory@80000000 { @@ -95,6 +97,27 @@ jedec-id = [ef 40 17]; erase-block-size = <4096>; write-block-size = <1>; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_M(3)>; + }; + slot1_partition: partition@310000 { + label = "image-1"; + reg = <0x00310000 DT_SIZE_M(3)>; + }; + storage_partition: partition@610000 { + label = "storage"; + reg = <0x00610000 DT_SIZE_K(1984)>; + }; + }; }; }; diff --git a/boards/arm/mimxrt1050_evk/Kconfig.defconfig b/boards/arm/mimxrt1050_evk/Kconfig.defconfig index 104c6d77100..79660c08e78 100644 --- a/boards/arm/mimxrt1050_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1050_evk/Kconfig.defconfig @@ -46,9 +46,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1050_evk/board.cmake b/boards/arm/mimxrt1050_evk/board.cmake index e7a3230af94..265ce1cd5f8 100644 --- a/boards/arm/mimxrt1050_evk/board.cmake +++ b/boards/arm/mimxrt1050_evk/board.cmake @@ -10,6 +10,8 @@ if(${CONFIG_BOARD_MIMXRT1050_EVK_QSPI}) board_runner_args(pyocd "--target=mimxrt1050_quadspi") else() board_runner_args(pyocd "--target=mimxrt1050_hyperflash") + board_runner_args(linkserver "--device=MIMXRT1052xxxxB:EVKB-IMXRT1050") + include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) endif() include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/mimxrt1050_evk/doc/index.rst b/boards/arm/mimxrt1050_evk/doc/index.rst index 5d48e823f79..de225ae56f3 100644 --- a/boards/arm/mimxrt1050_evk/doc/index.rst +++ b/boards/arm/mimxrt1050_evk/doc/index.rst @@ -322,8 +322,23 @@ however the :ref:`pyocd-debug-host-tools` do not yet support programming the external flashes on this board so you must reconfigure the board for one of the following debug probes instead. -Option 1: :ref:`opensda-jlink-onboard-debug-probe` (Recommended) ----------------------------------------------------------------- +Using LinkServer +---------------- + +Install the :ref:`linkserver-debug-host-tools` and make sure they are in your +search path. LinkServer works with the default CMSIS-DAP firmware included in +the on-board debugger. + +Linkserver is the default runner. You may also se the ``-r linkserver`` option +with West to use the LinkServer runner. + +.. code-block:: console + + west flash + west debug + +JLink (on-board): :ref:`opensda-jlink-onboard-debug-probe` +---------------------------------------------------------- Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -337,8 +352,8 @@ Follow the instructions in `Enable QSPI flash support in SEGGER JLink`_ in order to support your EVK if you have modified it to boot from QSPI NOR flash as specified by NXP AN12108. -Option 2: :ref:`jlink-external-debug-probe` -------------------------------------------- +External JLink :ref:`jlink-external-debug-probe` +------------------------------------------------ Install the :ref:`jlink-debug-host-tools` and make sure they are in your search path. @@ -472,3 +487,13 @@ Current Zephyr build supports the new MIMXRT1050-EVKB .. _Enable QSPI flash support in SEGGER JLink: https://wiki.segger.com/i.MXRT1050#QSPI_flash + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1050_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1050_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1050_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi b/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi index 27e48b64ae8..1b73a7453a9 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1050_evk.mex */ diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts index 5068bc674e4..d1e8da5834b 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts @@ -154,21 +154,20 @@ arduino_serial: &lpuart3 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(256)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@40000 { label = "image-0"; - reg = <0x00040000 DT_SIZE_M(3)>; + reg = <0x00040000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@340000 { + slot1_partition: partition@341000 { label = "image-1"; - reg = <0x00340000 DT_SIZE_M(3)>; + reg = <0x00341000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@641000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(57)>; + reg = <0x00641000 (DT_SIZE_M(57) + DT_SIZE_K(764))>; }; }; }; diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts index 46f78275a0c..27542b88bfd 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk_qspi.dts @@ -41,21 +41,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1060_evk/Kconfig.defconfig b/boards/arm/mimxrt1060_evk/Kconfig.defconfig index aef6f37c03b..b3b325805fa 100644 --- a/boards/arm/mimxrt1060_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1060_evk/Kconfig.defconfig @@ -49,9 +49,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1060_evk/doc/index.rst b/boards/arm/mimxrt1060_evk/doc/index.rst index 45d10009570..cfd546e5b37 100644 --- a/boards/arm/mimxrt1060_evk/doc/index.rst +++ b/boards/arm/mimxrt1060_evk/doc/index.rst @@ -472,3 +472,13 @@ connected to the EVK properly. See :ref:`Using J-Link RT1060` for more details. .. _Using J-Link with MIMXRT1060-EVKB: https://community.nxp.com/t5/i-MX-RT-Knowledge-Base/Using-J-Link-with-MIMXRT1060-EVKB/ta-p/1452717 + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1060_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1060_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1060_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi b/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi index 7d2ff7a43e4..f41f92ba1ee 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1060_evk.mex */ diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts index 998e942e5a2..42782b40454 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk.dts @@ -143,21 +143,20 @@ arduino_serial: &lpuart3 { label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_M(3)>; + reg = <0x00010000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@310000 { + slot1_partition: partition@311000 { label = "image-1"; - reg = <0x00310000 DT_SIZE_M(3)>; + reg = <0x00311000 DT_SIZE_M(3)>; }; - scratch_partition: partition@610000 { - label = "image-scratch"; - reg = <0x00610000 DT_SIZE_K(128)>; - }; - storage_partition: partition@630000 { + storage_partition: partition@611000 { label = "storage"; - reg = <0x00630000 DT_SIZE_K(1856)>; + reg = <0x00611000 DT_SIZE_K(1980)>; }; }; }; diff --git a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts index a920010688b..efdf5e2ff22 100644 --- a/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts +++ b/boards/arm/mimxrt1060_evk/mimxrt1060_evk_hyperflash.dts @@ -53,21 +53,20 @@ label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(256)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@40000 { label = "image-0"; - reg = <0x00040000 DT_SIZE_M(3)>; + reg = <0x00040000 (DT_SIZE_M(3) + DT_SIZE_K(4))>; }; - slot1_partition: partition@340000 { + slot1_partition: partition@341000 { label = "image-1"; - reg = <0x00340000 DT_SIZE_M(3)>; + reg = <0x00341000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@641000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(57)>; + reg = <0x00641000 (DT_SIZE_M(57) + DT_SIZE_K(764))>; }; }; }; diff --git a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts index c3af13f1f0d..ff6f1bf6827 100644 --- a/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts +++ b/boards/arm/mimxrt1062_fmurt6/mimxrt1062_fmurt6.dts @@ -223,13 +223,9 @@ label = "image-1"; reg = <0x00340000 DT_SIZE_M(3)>; }; - scratch_partition: partition@640000 { - label = "image-scratch"; - reg = <0x00640000 DT_SIZE_K(768)>; - }; - storage_partition: partition@700000 { + storage_partition: partition@640000 { label = "storage"; - reg = <0x00700000 DT_SIZE_M(557)>; + reg = <0x00640000 (DT_SIZE_M(557) + DT_SIZE_K(768))>; }; }; }; diff --git a/boards/arm/mimxrt1064_evk/Kconfig.defconfig b/boards/arm/mimxrt1064_evk/Kconfig.defconfig index 9ebf3eaa71b..e0604d39621 100644 --- a/boards/arm/mimxrt1064_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1064_evk/Kconfig.defconfig @@ -33,9 +33,13 @@ if NETWORKING config NET_L2_ETHERNET default y +if ETH_MCUX + config ETH_MCUX_PHY_RESET default y +endif # ETH_MCUX + endif # NETWORKING if LVGL diff --git a/boards/arm/mimxrt1064_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1064_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..7fe69f0d52e --- /dev/null +++ b/boards/arm/mimxrt1064_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,122 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@402d8000; + + enet: enet@402d8000 { + compatible = "nxp,enet"; + reg = <0x402D8000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <114 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + phy-connection-type = "rmii"; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <115 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_b1_10_enet_ref_clk>; + bias-disable; + drive-strength = "r0-6"; + slew-rate = "fast"; + nxp,speed = "50-mhz"; + input-enable; + }; + group1 { + pinmux = <&iomuxc_gpio_b1_04_enet_rx_data0>, + <&iomuxc_gpio_b1_05_enet_rx_data1>, + <&iomuxc_gpio_b1_06_enet_rx_en>, + <&iomuxc_gpio_b1_07_enet_tx_data0>, + <&iomuxc_gpio_b1_08_enet_tx_data1>, + <&iomuxc_gpio_b1_09_enet_tx_en>, + <&iomuxc_gpio_b1_11_enet_rx_er>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_emc_40_enet_mdc>, + <&iomuxc_gpio_emc_41_enet_mdio>, + <&iomuxc_gpio_ad_b0_10_gpio1_io10>, + <&iomuxc_gpio_ad_b0_09_gpio1_io09>; + drive-strength = "r0-5"; + bias-pull-up; + bias-pull-up-value = "100k"; + slew-rate = "fast"; + nxp,speed = "200-mhz"; + }; + }; + + pinmux_ptp: pinmux_ptp { + group0 { + pinmux = <&iomuxc_gpio_ad_b1_02_enet_1588_event2_out>, + <&iomuxc_gpio_ad_b1_03_enet_1588_event2_in>; + drive-strength = "r0-6"; + slew-rate = "slow"; + nxp,speed = "100-mhz"; + }; + }; +}; diff --git a/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi b/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi index 043b421dcfb..d8be3020998 100644 --- a/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1064_evk/mimxrt1064_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by imx_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1064_evk.mex */ diff --git a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts index ebd88badcb6..f6b6d5c74b2 100644 --- a/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts +++ b/boards/arm/mimxrt1064_evk/mimxrt1064_evk.dts @@ -207,17 +207,16 @@ arduino_i2c: &lpi2c1 {}; label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; + /* Note slot 0 has one additional sector, + * this is intended for use with the swap move algorithm + */ slot0_partition: partition@10000 { label = "image-0"; - reg = <0x00010000 DT_SIZE_K(1984)>; + reg = <0x00010000 DT_SIZE_K(2016)>; }; - slot1_partition: partition@200000 { + slot1_partition: partition@208000 { label = "image-1"; - reg = <0x00200000 DT_SIZE_K(1984)>; - }; - scratch_partition: partition@3f0000 { - label = "image-scratch"; - reg = <0x003f0000 DT_SIZE_K(64)>; + reg = <0x00208000 DT_SIZE_K(2012)>; }; }; }; diff --git a/boards/arm/mimxrt1160_evk/doc/index.rst b/boards/arm/mimxrt1160_evk/doc/index.rst index d3ee99ad731..2449429a891 100644 --- a/boards/arm/mimxrt1160_evk/doc/index.rst +++ b/boards/arm/mimxrt1160_evk/doc/index.rst @@ -354,3 +354,13 @@ should see the following message in the terminal: .. _AN13264: https://www.nxp.com/docs/en/application-note/AN13264.pdf + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..58b8a801622 --- /dev/null +++ b/boards/arm/mimxrt1160_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,123 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@40424000; + + enet: ethernet@40424000 { + compatible = "nxp,enet"; + reg = <0x40424000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <137 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <138 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio12 12 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio9 11 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_12_gpio9_io11>, + <&iomuxc_gpio_disp_b2_08_enet_rx_en>, + <&iomuxc_gpio_disp_b2_09_enet_rx_er>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group1 { + pinmux = <&iomuxc_gpio_disp_b2_06_enet_rdata00>, + <&iomuxc_gpio_disp_b2_07_enet_rdata01>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + input-enable; + }; + group2 { + pinmux = <&iomuxc_lpsr_gpio_lpsr_12_gpio12_io12>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + group3 { + pinmux = <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + <&iomuxc_gpio_disp_b2_03_enet_tdata01>, + <&iomuxc_gpio_disp_b2_04_enet_tx_en>; + drive-strength = "high"; + slew-rate = "fast"; + }; + group4 { + pinmux = <&iomuxc_gpio_disp_b2_05_enet_ref_clk>; + drive-strength = "high"; + slew-rate = "slow"; + input-enable; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, + <&iomuxc_gpio_ad_33_enet_mdio>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + }; +}; diff --git a/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi b/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi index f2a3c4ff9dd..1f17d8d62de 100644 --- a/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1160_evk/mimxrt1160_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1160_evk.mex */ diff --git a/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi b/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi index 02d09138e75..93e1c3452fa 100644 --- a/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi +++ b/boards/arm/mimxrt1160_evk/mimxrt1160_evk.dtsi @@ -119,13 +119,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/doc/index.rst b/boards/arm/mimxrt1170_evk/doc/index.rst index 15a66875d31..faff1975ca8 100644 --- a/boards/arm/mimxrt1170_evk/doc/index.rst +++ b/boards/arm/mimxrt1170_evk/doc/index.rst @@ -442,3 +442,13 @@ should see the following message in the terminal: .. _NXP MCUXpresso for Visual Studio Code: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-for-visual-studio-code:MCUXPRESSO-VSC + +Experimental ENET Driver +======================== + +Current default ethernet driver is eth_mcux, with binding `nxp,kinetis-ethernet`. There is a new +driver with binding `nxp,enet`, which is experimental and undergoing development, but will have +enhanced capability, such as not hardcoding code for only one phy in the driver like eth_mcux. + +To build for this EVK with the new driver, include the experimental overlay to west build with +the option `-DEXTRA_DTC_OVERLAY_FILE=nxp,enet-experimental.overlay`. diff --git a/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay b/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay new file mode 100644 index 00000000000..58b8a801622 --- /dev/null +++ b/boards/arm/mimxrt1170_evk/dts/nxp,enet-experimental.overlay @@ -0,0 +1,123 @@ +/* + * Copyright 2023 NXP + * + * Experimental ENET binding overlay + */ + + +/ { + soc { + /delete-node/ ethernet@40424000; + + enet: ethernet@40424000 { + compatible = "nxp,enet"; + reg = <0x40424000 0x628>; + clocks = <&ccm IMX_CCM_ENET_CLK 0 0>; + enet_mac: ethernet { + compatible = "nxp,enet-mac"; + interrupts = <137 0>; + interrupt-names = "COMMON"; + nxp,mdio = <&enet_mdio>; + nxp,ptp-clock = <&enet_ptp_clock>; + status = "disabled"; + }; + enet_mdio: mdio { + compatible = "nxp,enet-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + enet_ptp_clock: ptp_clock { + compatible = "nxp,enet-ptp-clock"; + interrupts = <138 0>; + status = "disabled"; + clocks = <&ccm IMX_CCM_ENET_PLL 0 0>; + }; + }; + }; +}; + +&enet_mac { + status = "okay"; + pinctrl-0 = <&pinmux_enet>; + pinctrl-names = "default"; + phy-handle = <&phy>; + phy-connection-type = "rmii"; +}; + +&enet_mdio { + status = "okay"; + pinctrl-0 = <&pinmux_enet_mdio>; + pinctrl-names = "default"; + phy: phy@0 { + compatible = "microchip,ksz8081"; + reg = <0>; + status = "okay"; + mc,reset-gpio = <&gpio12 12 GPIO_ACTIVE_HIGH>; + mc,interrupt-gpio = <&gpio9 11 GPIO_ACTIVE_HIGH>; + mc,interface-type = "rmii"; + }; +}; + +&enet_ptp_clock { + status = "okay"; + pinctrl-0 = <&pinmux_ptp>; + pinctrl-names = "default"; +}; + + + +&pinctrl { + /delete-node/ pinmux_ptp; + /delete-node/ pinmux_enet; + + pinmux_enet: pinmux_enet { + group0 { + pinmux = <&iomuxc_gpio_ad_12_gpio9_io11>, + <&iomuxc_gpio_disp_b2_08_enet_rx_en>, + <&iomuxc_gpio_disp_b2_09_enet_rx_er>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + }; + group1 { + pinmux = <&iomuxc_gpio_disp_b2_06_enet_rdata00>, + <&iomuxc_gpio_disp_b2_07_enet_rdata01>; + drive-strength = "high"; + bias-pull-down; + slew-rate = "fast"; + input-enable; + }; + group2 { + pinmux = <&iomuxc_lpsr_gpio_lpsr_12_gpio12_io12>; + drive-strength = "high"; + bias-pull-up; + slew-rate = "fast"; + }; + group3 { + pinmux = <&iomuxc_gpio_disp_b2_02_enet_tdata00>, + <&iomuxc_gpio_disp_b2_03_enet_tdata01>, + <&iomuxc_gpio_disp_b2_04_enet_tx_en>; + drive-strength = "high"; + slew-rate = "fast"; + }; + group4 { + pinmux = <&iomuxc_gpio_disp_b2_05_enet_ref_clk>; + drive-strength = "high"; + slew-rate = "slow"; + input-enable; + }; + }; + + pinmux_enet_mdio: pinmux_enet_mdio { + group0 { + pinmux = <&iomuxc_gpio_ad_32_enet_mdc>, + <&iomuxc_gpio_ad_33_enet_mdio>; + drive-strength = "high"; + slew-rate = "fast"; + }; + }; + + pinmux_ptp: pinmux_ptp { + }; +}; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi index 41a5607e728..35e7c521532 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mimxrt1170_evk.mex */ diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi index 4d3b193e5dc..9e59e733ebc 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evk.dtsi @@ -193,13 +193,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts index 5700b77837c..79725d1ac35 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm4.dts @@ -58,13 +58,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts index e93f701cd87..feceb9eaa30 100644 --- a/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts +++ b/boards/arm/mimxrt1170_evk/mimxrt1170_evkb_cm7.dts @@ -59,13 +59,9 @@ label = "image-1"; reg = <0x00321000 0x300000>; }; - scratch_partition: partition@621000 { - label = "image-scratch"; - reg = <0x00621000 DT_SIZE_K(128)>; - }; - storage_partition: partition@641000 { + storage_partition: partition@621000 { label = "storage"; - reg = <0x00641000 DT_SIZE_K(1856)>; + reg = <0x00621000 DT_SIZE_K(1984)>; }; }; }; diff --git a/boards/arm/mimxrt595_evk/CMakeLists.txt b/boards/arm/mimxrt595_evk/CMakeLists.txt index 51294dec288..002c6976545 100644 --- a/boards/arm/mimxrt595_evk/CMakeLists.txt +++ b/boards/arm/mimxrt595_evk/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library() zephyr_library_sources(board.c) +zephyr_library_include_directories(.) if(CONFIG_NXP_IMX_RT5XX_BOOT_HEADER) if(NOT DEFINED CONFIG_BOARD_MIMXRT595_EVK) diff --git a/boards/arm/mimxrt595_evk/Kconfig.defconfig b/boards/arm/mimxrt595_evk/Kconfig.defconfig index 3a4580a3603..96779115e14 100644 --- a/boards/arm/mimxrt595_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt595_evk/Kconfig.defconfig @@ -23,8 +23,9 @@ if DMA_MCUX_LPC # Memory from the heap pool is used to allocate DMA descriptors for # channels that use multiple blocks for a DMA transfer. -# Adjust HEAP_MEM_POOL_SIZE in case you need more memory. -config HEAP_MEM_POOL_SIZE +# Adjust HEAP_MEM_POOL_MIN_SIZE in case you need more memory. +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 endif # DMA_MCUX_LPC diff --git a/boards/arm/mimxrt595_evk/board.c b/boards/arm/mimxrt595_evk/board.c index fce50f4c23d..dd2cb36354c 100644 --- a/boards/arm/mimxrt595_evk/board.c +++ b/boards/arm/mimxrt595_evk/board.c @@ -6,19 +6,45 @@ #include #include "fsl_power.h" #include +#include "board.h" + +#ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP +#include "flash_clock_setup.h" +#endif + +/* OTP fuse index. */ +#define FRO_192MHZ_SC_TRIM 0x2C +#define FRO_192MHZ_RD_TRIM 0x2B +#define FRO_96MHZ_SC_TRIM 0x2E +#define FRO_96MHZ_RD_TRIM 0x2D + +#define OTP_FUSE_READ_API ((void (*)(uint32_t addr, uint32_t *data))0x1300805D) + +#define PMIC_MODE_BOOT 0U +#define PMIC_MODE_DEEP_SLEEP 1U +#define PMIC_MODE_FRO192M_900MV 2U +#define PMIC_MODE_FRO96M_800MV 3U + +#define PMIC_SETTLING_TIME 2000U /* in micro-seconds */ + +static uint32_t sc_trim_192, rd_trim_192, sc_trim_96, rd_trim_96; #if CONFIG_REGULATOR #include +#define NODE_PCA9420 DT_NODELABEL(pca9420) #define NODE_SW1 DT_NODELABEL(pca9420_sw1) #define NODE_SW2 DT_NODELABEL(pca9420_sw2) #define NODE_LDO1 DT_NODELABEL(pca9420_ldo1) #define NODE_LDO2 DT_NODELABEL(pca9420_ldo2) +static const struct device *pca9420 = DEVICE_DT_GET(NODE_PCA9420); static const struct device *sw1 = DEVICE_DT_GET(NODE_SW1); static const struct device *sw2 = DEVICE_DT_GET(NODE_SW2); static const struct device *ldo1 = DEVICE_DT_GET(NODE_LDO1); static const struct device *ldo2 = DEVICE_DT_GET(NODE_LDO2); +static int current_power_profile; + #define MEGA (1000000U) /* Core frequency levels number. */ @@ -93,7 +119,148 @@ static int board_config_pmic(void) return ret; } -#endif + +static int board_pmic_change_mode(uint8_t pmic_mode) +{ + int ret; + + if (pmic_mode >= 4) { + return -ERANGE; + } + + ret = regulator_parent_dvs_state_set(pca9420, pmic_mode); + if (ret != -EPERM) { + return ret; + } + + POWER_SetPmicMode(pmic_mode, kCfg_Run); + k_busy_wait(PMIC_SETTLING_TIME); + + return 0; +} + +/* Changes power-related config to preset profiles, like clocks and VDDCORE voltage */ +__ramfunc int32_t power_manager_set_profile(uint32_t power_profile) +{ + bool voltage_changed = false; + int32_t current_uv, future_uv; + int ret; + + if (power_profile == current_power_profile) { + return 0; + } + + /* Confirm valid power_profile, and read the new VDDCORE voltage */ + switch (power_profile) { + case POWER_PROFILE_AFTER_BOOT: + future_uv = DT_PROP(NODE_SW1, nxp_mode0_microvolt); + break; + + case POWER_PROFILE_FRO192M_900MV: + future_uv = DT_PROP(NODE_SW1, nxp_mode2_microvolt); + break; + + case POWER_PROFILE_FRO96M_800MV: + future_uv = DT_PROP(NODE_SW1, nxp_mode3_microvolt); + break; + + default: + return -EINVAL; + } + + if (current_power_profile == POWER_PROFILE_AFTER_BOOT) { + /* One-Time optimization after boot */ + + POWER_DisableLVD(); + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + /* Other clock optimizations */ + #ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP + flexspi_setup_clock(FLEXSPI0, 0U, 1U); /* main_clk div by 1 */ + #endif + /* Disable the PFDs of SYSPLL */ + CLKCTL0->SYSPLL0PFD |= CLKCTL0_SYSPLL0PFD_PFD0_CLKGATE_MASK | + CLKCTL0_SYSPLL0PFD_PFD1_CLKGATE_MASK | + CLKCTL0_SYSPLL0PFD_PFD2_CLKGATE_MASK; + + POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_LDO); + POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_ANA); + POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_LDO); + POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_ANA); + POWER_EnablePD(kPDRUNCFG_PD_SYSXTAL); + + /* Configure MCU that PMIC supplies will be powered in all + * PMIC modes + */ + PMC->PMICCFG = 0xFF; + + } + + /* Get current and future PMIC voltages to determine DVFS sequence */ + ret = regulator_get_voltage(sw1, ¤t_uv); + if (ret) { + return ret; + } + + if (power_profile == POWER_PROFILE_FRO192M_900MV) { + /* check if voltage or frequency change is first */ + if (future_uv > current_uv) { + /* Increase voltage first before frequencies */ + ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV); + if (ret) { + return ret; + } + + voltage_changed = true; + } + + /* Trim FRO to 192MHz */ + CLKCTL0->FRO_SCTRIM = sc_trim_192; + CLKCTL0->FRO_RDTRIM = rd_trim_192; + /* Reset the EXP_COUNT. */ + CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK; + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + if (voltage_changed == false) { + ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV); + if (ret) { + return ret; + } + } + + } else if (power_profile == POWER_PROFILE_FRO96M_800MV) { + /* This PMIC mode is the lowest voltage used for DVFS, + * Reduce frequency first, and then reduce voltage + */ + + /* Trim the FRO to 96MHz */ + CLKCTL0->FRO_SCTRIM = sc_trim_96; + CLKCTL0->FRO_RDTRIM = rd_trim_96; + /* Reset the EXP_COUNT. */ + CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK; + + CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK); + /* Set SYSCPUAHBCLKDIV divider to value 1 */ + CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U); + + ret = board_pmic_change_mode(PMIC_MODE_FRO96M_800MV); + if (ret) { + return ret; + } + } + + current_power_profile = power_profile; + + return 0; +} + +#endif /* CONFIG_REGULATOR */ static int mimxrt595_evk_init(void) { @@ -153,6 +320,28 @@ static int mimxrt595_evk_init(void) */ OCOTP0->OTP_SHADOW[97] = 0x164000; #endif /* CONFIG_REBOOT */ + + /* Read 192M FRO clock Trim settings from fuses. + * NOTE: Reading OTP fuses requires a VDDCORE voltage of at least 1.0V + */ + OTP_FUSE_READ_API(FRO_192MHZ_SC_TRIM, &sc_trim_192); + OTP_FUSE_READ_API(FRO_192MHZ_RD_TRIM, &rd_trim_192); + + /* Read 96M FRO clock Trim settings from fuses. */ + OTP_FUSE_READ_API(FRO_96MHZ_SC_TRIM, &sc_trim_96); + OTP_FUSE_READ_API(FRO_96MHZ_RD_TRIM, &rd_trim_96); + + /* Check if the 96MHz fuses have been programmed. + * Production devices have 96M trim values programmed in OTP fuses. + * However, older EVKs may have pre-production silicon. + */ + if ((rd_trim_96 == 0) && (sc_trim_96 == 0)) { + /* If not programmed then use software to calculate the trim values */ + CLOCK_FroTuneToFreq(96000000u); + rd_trim_96 = CLKCTL0->FRO_RDTRIM; + sc_trim_96 = sc_trim_192; + } + return 0; } diff --git a/boards/arm/mimxrt595_evk/board.h b/boards/arm/mimxrt595_evk/board.h new file mode 100644 index 00000000000..f30095651f9 --- /dev/null +++ b/boards/arm/mimxrt595_evk/board.h @@ -0,0 +1,10 @@ +/* + * Copyright 2023 NXP + * SPDX-License-Identifier: Apache-2.0 + */ + +#define POWER_PROFILE_FRO192M_900MV 0xFF +#define POWER_PROFILE_FRO96M_800MV 0x1 +#define POWER_PROFILE_AFTER_BOOT 0x0 + +__ramfunc int32_t power_manager_set_profile(uint32_t power_profile); diff --git a/boards/arm/mimxrt595_evk/doc/index.rst b/boards/arm/mimxrt595_evk/doc/index.rst index a82735ba278..8bdbd864a4e 100644 --- a/boards/arm/mimxrt595_evk/doc/index.rst +++ b/boards/arm/mimxrt595_evk/doc/index.rst @@ -113,6 +113,8 @@ already supported, which can also be re-used on this mimxrt595_evk board: | | | :ref:`rk055hdmipi4ma0`, and | | | | :ref:`g1120b0mipi` display shields | +-----------+------------+-------------------------------------+ +| DMIC | on-chip | dmic | ++-----------+------------+-------------------------------------+ The default configuration can be found in the defconfig file: diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi index 4073475446b..3f1bb622689 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from MIMXRT595-EVK.mex * * Copyright 2022, NXP @@ -46,6 +46,16 @@ }; }; + pinmux_dmic0: pinmux_dmic0 { + group0 { + pinmux = , , + ; + slew-rate = "normal"; + drive-strength = "normal"; + input-enable; + }; + }; + pinmux_flexcomm4_i2c: pinmux_flexcomm4_i2c { group0 { pinmux = , diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts index b91a45f5008..f32420304df 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.dts @@ -28,6 +28,7 @@ accel0 = &fxos8700; sdhc0 = &usdhc0; pwm-0 = &sc_timer; + dmic-dev = &dmic0; }; chosen { @@ -238,7 +239,8 @@ arduino_serial: &flexcomm12 { regulator-boot-on; nxp,mode0-microvolt = <1100000>; nxp,mode1-microvolt = <600000>; - nxp,mode2-microvolt = <0>; + nxp,mode2-microvolt = <900000>; + nxp,mode3-microvolt = <800000>; }; pca9420_sw2: BUCK2 { @@ -246,7 +248,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <1800000>; nxp,mode1-microvolt = <1800000>; nxp,mode2-microvolt = <1800000>; - + nxp,mode3-microvolt = <1800000>; }; pca9420_ldo1: LDO1 { @@ -254,6 +256,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <1800000>; nxp,mode1-microvolt = <1800000>; nxp,mode2-microvolt = <1800000>; + nxp,mode3-microvolt = <1800000>; }; pca9420_ldo2: LDO2 { @@ -261,6 +264,7 @@ arduino_serial: &flexcomm12 { nxp,mode0-microvolt = <3300000>; nxp,mode1-microvolt = <3300000>; nxp,mode2-microvolt = <3300000>; + nxp,mode3-microvolt = <3300000>; }; }; }; @@ -479,6 +483,30 @@ zephyr_udc0: &usbhs { dma-names = "smartdma"; }; +&dmic0 { + status = "okay"; + pinctrl-0 = <&pinmux_dmic0>; + pinctrl-names = "default"; + use2fs; +}; + +/* Configure pdm channels 0 and 1 with gain, and cutoff settings + * appropriate for the attached MEMS microphones. + */ +&pdmc0 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; +}; + +&pdmc1 { + status = "okay"; + gainshift = <3>; + dc-cutoff = "155hz"; + dc-gain = <1>; +}; + &mrt_channel0 { status = "okay"; }; diff --git a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml index 6e35595c078..95b17cb059f 100644 --- a/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml +++ b/boards/arm/mimxrt595_evk/mimxrt595_evk_cm33.yaml @@ -28,4 +28,5 @@ supported: - sdhc - pwm - i2s + - dmic vendor: nxp diff --git a/boards/arm/mimxrt685_evk/board.cmake b/boards/arm/mimxrt685_evk/board.cmake index a399d5f6398..79e6f768dd1 100644 --- a/boards/arm/mimxrt685_evk/board.cmake +++ b/boards/arm/mimxrt685_evk/board.cmake @@ -5,5 +5,7 @@ # board_runner_args(jlink "--device=MIMXRT685S_M33" "--reset-after-load") +board_runner_args(linkserver "--device=MIMXRT685S:EVK-MIMXRT685") +include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/mimxrt685_evk/doc/index.rst b/boards/arm/mimxrt685_evk/doc/index.rst index f0236e3a64f..579cd1e4087 100644 --- a/boards/arm/mimxrt685_evk/doc/index.rst +++ b/boards/arm/mimxrt685_evk/doc/index.rst @@ -227,6 +227,20 @@ configured by default to use the LPC-Link2. .. tabs:: + .. group-tab:: LinkServer CMSIS-DAP + + 1. Install the :ref:`linkserver-debug-host-tools` and make sure they are in your + search path. LinkServer works with the default CMSIS-DAP firmware included in + the on-board debugger. + 2. Make sure the jumpers JP17, JP18 and JP19 are installed. + + linkserver is the default runner for this board + + .. code-block:: console + + west flash + west debug + .. group-tab:: LPCLink2 JLink Onboard @@ -236,6 +250,11 @@ configured by default to use the LPC-Link2. 3. Follow the instructions in :ref:`lpclink2-jlink-onboard-debug-probe` to program the J-Link firmware. Please make sure you have the latest firmware for this board. + .. code-block:: console + + west flash -r jlink + west debug -r jlink + .. group-tab:: JLink External @@ -248,6 +267,11 @@ configured by default to use the LPC-Link2. See :ref:`jlink-external-debug-probe` for more information. + .. code-block:: console + + west flash -r jlink + west debug -r jlink + Configuring a Console ===================== @@ -263,7 +287,7 @@ Flashing ======== Here is an example for the :ref:`hello_world` application. This example uses the -:ref:`jlink-debug-host-tools` as default. +:ref:`linkserver-debug-host-tools` as default. .. zephyr-app-commands:: :zephyr-app: samples/hello_world @@ -282,7 +306,7 @@ Debugging ========= Here is an example for the :ref:`hello_world` application. This example uses the -:ref:`jlink-debug-host-tools` as default. +:ref:`linkserver-debug-host-tools` as default. .. zephyr-app-commands:: :zephyr-app: samples/hello_world diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi index ef48a752ef5..63febf90fce 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: File generated by lpc_cfg_utils.py + * NOTE: File generated by gen_board_pinctrl.py * from MIMXRT685-EVK.mex * * Copyright 2022, NXP diff --git a/boards/arm/mm_feather/mm_feather-pinctrl.dtsi b/boards/arm/mm_feather/mm_feather-pinctrl.dtsi index f16de683d36..4a8c410bce9 100644 --- a/boards/arm/mm_feather/mm_feather-pinctrl.dtsi +++ b/boards/arm/mm_feather/mm_feather-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mm_feather.mex */ diff --git a/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi b/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi index 1a385a3babc..1a9b44a01c0 100644 --- a/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi +++ b/boards/arm/mm_swiftio/mm_swiftio-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from mm_swiftio.mex */ diff --git a/boards/arm/mps2_an385/doc/index.rst b/boards/arm/mps2_an385/doc/index.rst index 1f9d1a59e23..ac27e70e593 100644 --- a/boards/arm/mps2_an385/doc/index.rst +++ b/boards/arm/mps2_an385/doc/index.rst @@ -226,7 +226,7 @@ Peripheral Mapping: - I2C_4_SDA : D40 - I2C_4_SCL : D41 -For mode details please refer to `MPS2 Technical Reference Manual (TRM)`_. +For more details please refer to `MPS2 Technical Reference Manual (TRM)`_. System Clock ============ diff --git a/boards/arm/mps2_an385/mps2_an385.yaml b/boards/arm/mps2_an385/mps2_an385.yaml index fec9dfc0fa8..0236f2a137d 100644 --- a/boards/arm/mps2_an385/mps2_an385.yaml +++ b/boards/arm/mps2_an385/mps2_an385.yaml @@ -13,6 +13,4 @@ supported: - gpio testing: default: true - ignore_tags: - - net vendor: arm diff --git a/boards/arm/mps2_an521/board.cmake b/boards/arm/mps2_an521/board.cmake index 806f4ac7052..51e09ba282d 100644 --- a/boards/arm/mps2_an521/board.cmake +++ b/boards/arm/mps2_an521/board.cmake @@ -12,6 +12,9 @@ set(QEMU_FLAGS_${ARCH} ) board_set_debugger_ifnset(qemu) +board_runner_args(pyocd "--target=mps2_an521") + +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) # To enable a host tty switch between serial and pty # -chardev serial,path=/dev/ttyS0,id=hostS0 list(APPEND QEMU_EXTRA_FLAGS -chardev pty,id=hostS0 -serial chardev:hostS0) diff --git a/boards/arm/mps2_an521/doc/index.rst b/boards/arm/mps2_an521/doc/index.rst index 1cd049ec8f9..e8789e72e18 100644 --- a/boards/arm/mps2_an521/doc/index.rst +++ b/boards/arm/mps2_an521/doc/index.rst @@ -331,7 +331,7 @@ Peripheral Mapping: - I2C_4_SDA : D40 - I2C_4_SCL : D41 -For mode details refer to `MPS2+ AN521 Technical Reference Manual (TRM)`_. +For more details refer to `MPS2+ AN521 Technical Reference Manual (TRM)`_. LED ============ diff --git a/boards/arm/mps2_an521/mps2_an521.dts b/boards/arm/mps2_an521/mps2_an521.dts index d69228b235a..2bb956645ca 100644 --- a/boards/arm/mps2_an521/mps2_an521.dts +++ b/boards/arm/mps2_an521/mps2_an521.dts @@ -79,7 +79,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps2_an521/mps2_an521_ns.dts b/boards/arm/mps2_an521/mps2_an521_ns.dts index 80e235244a1..e2b24cd9ba5 100644 --- a/boards/arm/mps2_an521/mps2_an521_ns.dts +++ b/boards/arm/mps2_an521/mps2_an521_ns.dts @@ -71,7 +71,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps2_an521/mps2_an521_remote.dts b/boards/arm/mps2_an521/mps2_an521_remote.dts index a52b88ff447..311694ca399 100644 --- a/boards/arm/mps2_an521/mps2_an521_remote.dts +++ b/boards/arm/mps2_an521/mps2_an521_remote.dts @@ -71,7 +71,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps3_an547/doc/index.rst b/boards/arm/mps3_an547/doc/index.rst index 002c4210f52..b5f383d546a 100644 --- a/boards/arm/mps3_an547/doc/index.rst +++ b/boards/arm/mps3_an547/doc/index.rst @@ -111,7 +111,7 @@ features. The default configuration can be found in the defconfig file: ``boards/arm/mps3_an547/mps3_an547_defconfig``. -For mode details refer to `MPS3 AN547 Technical Reference Manual (TRM)`_. +For more details refer to `MPS3 AN547 Technical Reference Manual (TRM)`_. Serial Port =========== diff --git a/boards/arm/mps3_an547/mps3_an547.dts b/boards/arm/mps3_an547/mps3_an547.dts index 53168a4de2d..50700e8278e 100644 --- a/boards/arm/mps3_an547/mps3_an547.dts +++ b/boards/arm/mps3_an547/mps3_an547.dts @@ -118,7 +118,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8.1m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mps3_an547/mps3_an547_ns.dts b/boards/arm/mps3_an547/mps3_an547_ns.dts index ac6531441eb..dd8c9c4571c 100644 --- a/boards/arm/mps3_an547/mps3_an547_ns.dts +++ b/boards/arm/mps3_an547/mps3_an547_ns.dts @@ -70,7 +70,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8.1m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/boards/arm/mr_canhubk3/Kconfig.defconfig b/boards/arm/mr_canhubk3/Kconfig.defconfig index 6cf6f085492..53e554da88f 100644 --- a/boards/arm/mr_canhubk3/Kconfig.defconfig +++ b/boards/arm/mr_canhubk3/Kconfig.defconfig @@ -13,6 +13,19 @@ config UART_CONSOLE endif # SERIAL +if SPI + +config SPI_INIT_PRIORITY + default 50 + +if WDT_NXP_FS26 + +config WDT_NXP_FS26_INIT_PRIORITY + default 51 + +endif # WDT_NXP_FS26 +endif # SPI + if CAN config GPIO @@ -25,6 +38,9 @@ if NETWORKING config NET_L2_ETHERNET default y if !NET_LOOPBACK && !NET_TEST +config MDIO + default y if NET_L2_ETHERNET + endif # NETWORKING endif # BOARD_MR_CANHUBK3 diff --git a/boards/arm/mr_canhubk3/doc/index.rst b/boards/arm/mr_canhubk3/doc/index.rst index 63dbb36666b..711ee43a0ca 100644 --- a/boards/arm/mr_canhubk3/doc/index.rst +++ b/boards/arm/mr_canhubk3/doc/index.rst @@ -31,7 +31,7 @@ Hardware - Console UART - 6x CAN FD - 100Base-T1 Ethernet - - DroneCode standard JST-GH connectors and I/O headers for I2C, SPI, GPIO, + - JST-GH connectors and I/O headers for I2C, SPI, GPIO, PWM, etc. More information about the hardware and design resources can be found at @@ -57,6 +57,7 @@ ADC SAR on-chip adc LPSPI on-chip spi WDT FS26 SBC watchdog EMAC on-chip ethernet + mdio eMIOS on-chip pwm EDMA on-chip dma ============ ========== ================================ @@ -252,9 +253,9 @@ Ethernet This board has a single instance of Ethernet Media Access Controller (EMAC) interfacing with a `NXP TJA1103`_ 100Base-T1 Ethernet PHY. Currently, there is -no driver for this PHY and this board default pin strapping configuration for +limited driver for this PHY that allows for overiding the default pin strapping configuration for the PHY (RMII, master, autonomous mode enabled, polarity correction enabled) -allows to use it without software configuration. +to slave mode. The 100Base-T1 signals are available in connector ``P9`` and can be converted to 100Base-T using a Ethernet media converter such as `RDDRONE-T1ADAPT`_. diff --git a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi index 1c3ff008508..49c4d164c81 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi +++ b/boards/arm/mr_canhubk3/mr_canhubk3-pinctrl.dtsi @@ -9,7 +9,7 @@ &pinctrl { eirq0_default: eirq0_default { group1 { - pinmux = , , ; + pinmux = , , , ; input-enable; }; }; @@ -270,12 +270,23 @@ }; }; + mdio0_default: mdio0_default { + group1 { + pinmux = <(PTD16_EMAC_MII_RMII_MDIO_O | PTD16_EMAC_MII_RMII_MDIO_I)>; + input-enable; + output-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; + emios0_default: emios0_default { group1 { pinmux = , , , , , , - , , ; output-enable; }; @@ -288,4 +299,14 @@ output-enable; }; }; + + qdec_s32: qdec_s32 { + group1 { + pinmux = , + , + , + ; + input-enable; + }; + }; }; diff --git a/boards/arm/mr_canhubk3/mr_canhubk3.dts b/boards/arm/mr_canhubk3/mr_canhubk3.dts index ec5eb1ece43..b0866f7073a 100644 --- a/boards/arm/mr_canhubk3/mr_canhubk3.dts +++ b/boards/arm/mr_canhubk3/mr_canhubk3.dts @@ -11,6 +11,7 @@ #include #include #include "mr_canhubk3-pinctrl.dtsi" +#include / { model = "NXP MR-CANHUBK3"; @@ -42,6 +43,7 @@ green-pwm-led = &user_led1_green_pwm; blue-pwm-led = &user_led1_blue_pwm; pwm-led0 = &user_led1_blue_pwm; + qdec0 = &qdec0; }; leds { @@ -77,6 +79,39 @@ }; }; + qdec0: qdec0 { + compatible = "nxp,qdec-s32"; + pinctrl-0 = <&qdec_s32>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + status = "okay"; + trgmux = <&trgmux>; + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + lcu = <&lcu1>; + lcu-input-idx = + ; + lcu-mux-sel = + ; + lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + emios = <&emios0>; + /* + * eMios channel numbers for qdec should be beyond the channel numbers + * used by the emios pwm + */ + emios-channels = <6 7>; + }; + gpio_keys { compatible = "gpio-keys"; user_button_1: button_0 { @@ -408,11 +443,21 @@ pinctrl-names = "default"; phy-connection-type = "rmii"; local-mac-address = [02 04 9f aa bb cc]; + phy-handle = <&phy>; + status = "okay"; +}; + +&mdio0 { + pinctrl-0 = <&mdio0_default>; + pinctrl-names = "default"; status = "okay"; - fixed-link { - speed = <100>; - full-duplex; + phy: ethernet-phy@12 { + compatible = "nxp,tja1103"; + status = "okay"; + reg = <0x12>; + int-gpios = <&gpiod_l 5 GPIO_ACTIVE_LOW>; + master-slave = "slave"; }; }; @@ -493,24 +538,6 @@ polarity = "ACTIVE_HIGH"; }; - pwm_6 { - channel = <6>; - pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; - prescaler = <8>; - polarity = "ACTIVE_HIGH"; - }; - - pwm_7 { - channel = <7>; - pwm-mode = "OPWFMB"; - period = <65535>; - duty-cycle = <0>; - prescaler = <8>; - polarity = "ACTIVE_HIGH"; - }; - rgb_red { channel = <19>; master-bus = <&emios0_bus_a>; @@ -568,6 +595,14 @@ }; }; +&lcu1 { + status = "okay"; +}; + +&trgmux { + status = "okay"; +}; + &edma0 { status = "okay"; }; diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt index c950fd91724..fa1c1ba14d9 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt +++ b/boards/arm/nrf5340_audio_dk_nrf5340/CMakeLists.txt @@ -8,7 +8,7 @@ if ((CONFIG_BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP OR CONFIG_BOARD_NRF5340_AUDIO_ if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig index eaa56252095..685ebc49b63 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340_audio_dk_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP || BOARD_NRF5340_AUDIO_DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c index 4368ca303fc..f9082e6ca40 100644 --- a/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c +++ b/boards/arm/nrf5340_audio_dk_nrf5340/nrf5340_audio_dk_cpunet_reset.c @@ -10,8 +10,7 @@ #include #include - -#include +#include LOG_MODULE_REGISTER(nrf5340_audio_dk_nrf5340_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); @@ -25,11 +24,11 @@ static int core_config(void) { nrf_gpiote_latency_t latency; - latency = nrfx_gpiote_latency_get(); + latency = nrf_gpiote_latency_get(NRF_GPIOTE); if (latency != NRF_GPIOTE_LATENCY_LOWPOWER) { LOG_DBG("Setting gpiote latency to low power"); - nrfx_gpiote_latency_set(NRF_GPIOTE_LATENCY_LOWPOWER); + nrf_gpiote_latency_set(NRF_GPIOTE, NRF_GPIOTE_LATENCY_LOWPOWER); } return 0; diff --git a/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt b/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt index 8ba3238c40b..5128462d70c 100644 --- a/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt +++ b/boards/arm/nrf5340dk_nrf5340/CMakeLists.txt @@ -8,7 +8,7 @@ zephyr_library_sources(nrf5340_cpunet_reset.c) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig index 9006846dccb..84f19365cc5 100644 --- a/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig +++ b/boards/arm/nrf5340dk_nrf5340/Kconfig.defconfig @@ -70,7 +70,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_NRF5340DK_NRF5340_CPUAPP || BOARD_NRF5340DK_NRF5340_CPUAPP_NS diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml index 545a41e9cd6..6ed15a5d7ef 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp.yaml @@ -18,4 +18,5 @@ supported: - usb_device - netif:openthread - gpio + - spi vendor: nordic diff --git a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml index 9519f50f3e9..90abc04b119 100644 --- a/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml +++ b/boards/arm/nrf5340dk_nrf5340/nrf5340dk_nrf5340_cpuapp_ns.yaml @@ -16,4 +16,5 @@ supported: - usb_device - netif:openthread - gpio + - spi vendor: nordic diff --git a/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board new file mode 100644 index 00000000000..b76cfce6800 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54H20PDK_NRF54H20_CPUAPP + bool "nRF54H20 PDK nRF54H20 Application MCU" + depends on SOC_NRF54H20_ENGA_CPUAPP + +config BOARD_NRF54H20PDK_NRF54H20_CPURAD + bool "nRF54H20 PDK nRF54H20 Radio MCU" + depends on SOC_NRF54H20_ENGA_CPURAD diff --git a/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig new file mode 100644 index 00000000000..954276ec829 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "nrf54h20pdk_nrf54h20_cpuapp" if BOARD_NRF54H20PDK_NRF54H20_CPUAPP + default "nrf54h20pdk_nrf54h20_cpurad" if BOARD_NRF54H20PDK_NRF54H20_CPURAD + +if BOARD_NRF54H20PDK_NRF54H20_CPUAPP || BOARD_NRF54H20PDK_NRF54H20_CPURAD + +# Data cache is disabled due to a HW issue in the EngA SoC revision. +config DCACHE + default n + +endif # BOARD_NRF54H20PDK_NRF54H20_CPUAPP || BOARD_NRF54H20PDK_NRF54H20_CPURAD diff --git a/boards/arm/nrf54h20pdk_nrf54h20/board.cmake b/boards/arm/nrf54h20pdk_nrf54h20/board.cmake new file mode 100644 index 00000000000..4c63f1dd05e --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp b/boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp new file mode 100644 index 00000000000..bcda6b0732b Binary files /dev/null and b/boards/arm/nrf54h20pdk_nrf54h20/doc/img/nrf54h20pdk_nrf54h20.webp differ diff --git a/boards/arm/nrf54h20pdk_nrf54h20/doc/index.rst b/boards/arm/nrf54h20pdk_nrf54h20/doc/index.rst new file mode 100644 index 00000000000..985e8d36d88 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/doc/index.rst @@ -0,0 +1,148 @@ +.. _nrf54h20pdk_nrf54h20: + +nRF54H20 PDK +############ + +Overview +******** + +The nRF54H20 PDK is a single-board preview development kit for evaluation +and development on the Nordic nRF54H20 System-on-Chip (SoC). + +The nRF54H20 is a multicore SoC with: + +* an Arm Cortex-M33 core with DSP instructions, FPU, and Armv8-M Security + Extensions, running at up to 320 MHz, referred to as the **application core** +* an Arm Cortex-M33 core with DSP instructions, FPU, and Armv8-M Security + Extensions, running at up to 256 MHz, referred to as the **radio core**. + +The ``nrf54h20pdk_nrf54h20_cpuapp`` build target provides support for +the application core on the nRF54H20 SoC. +The ``nrf54h20pdk_nrf54h20_cpurad`` build target provides support for +the radio core on the nRF54H20 SoC. + +nRF54H20 SoC provides support for the following devices: + +* :abbr:`ADC (Analog to Digital Converter)` +* CLOCK +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`GPIOTE (General Purpose Input Output tasks and events)` +* :abbr:`GRTC (Global real-time counter)` +* :abbr:`I2C (Inter-Integrated Circuit)` +* MRAM +* :abbr:`PWM (Pulse Width Modulation)` +* RADIO (Bluetooth Low Energy and 802.15.4) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UART (Universal asynchronous receiver-transmitter)` +* :abbr:`USB (Universal Serial Bus)` +* :abbr:`WDT (Watchdog Timer)` + +.. figure:: img/nrf54h20pdk_nrf54h20.webp + :align: center + :alt: nRF54H20 PDK + + nRF54H20 PDK (Credit: Nordic Semiconductor) + +Hardware +******** + +nRF54H20 PDK has two crystal oscillators: + +* High-frequency 32 MHz crystal oscillator (HFXO) +* Low-frequency 32.768 kHz crystal oscillator (LFXO) + +Supported Features +================== + +The nrf54h20pdk_nrf54h20_cpuapp board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| GPIOTE | on-chip | gpio | ++-----------+------------+----------------------+ +| GRTC | on-chip | system clock | ++-----------+------------+----------------------+ +| UART | on-chip | serial | ++-----------+------------+----------------------+ + +The nrf54h20pdk_nrf54h20_cpurad board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| GPIOTE | on-chip | gpio | ++-----------+------------+----------------------+ +| GRTC | on-chip | system clock | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. + +Connections and IOs +=================== + +LEDs +---- + +* LED1 (green) = P9.0 +* LED2 (green) = P9.1 +* LED3 (green) = P9.2 +* LED4 (green) = P9.3 + +Push buttons +------------ + +* BUTTON1 = P0.8 +* BUTTON2 = P0.9 +* BUTTON3 = P0.10 +* BUTTON4 = P0.11 +* RESET (SW1) + +Programming and Debugging +************************* + +Applications for both the ``nrf54h20pdk_nrf54h20_cpuapp`` and +``nrf54h20pdk_nrf54h20_cpurad`` targets can be built, flashed, +and debugged in the usual way. See :ref:`build_an_application` +and :ref:`application_run` for more details on building and running. + +Flashing +======== + +As an example, this section shows how to build and flash the :ref:`hello_world` +application. + +Follow the instructions in the :ref:`nordic_segger` page to install +and configure all the necessary software. Further information can be +found in :ref:`nordic_segger_flashing`. + +To build and program the sample to the nRF54H20 PDK, complete the following steps: + +First, connect the nRF54H20 PDK to you computer using the IMCU USB port on the PDK. +Next, build the sample by running the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf54h20pdk_nrf54h20_cpuapp + :goals: build flash + +Testing the LEDs and buttons in the nRF54H20 PDK +************************************************ + +There are 2 samples that allow you to test that the buttons (switches) and LEDs +on the board are working properly with Zephyr: + +* :zephyr:code-sample:`blinky` +* :zephyr:code-sample:`button` + +You can build and flash the examples to make sure Zephyr is running correctly on +your board. The button and LED definitions can be found in +:zephyr_file:`boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts`. diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-memory_map.dtsi b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-memory_map.dtsi new file mode 100644 index 00000000000..00f28fad9f1 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-memory_map.dtsi @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + reserved-memory { + cpuppr_ram3x_region: memory@2fc00000 { + compatible = "nordic,owned-memory"; + reg = <0x2fc00000 DT_SIZE_K(28)>; + status = "disabled"; + perm-read; + perm-write; + perm-execute; + }; + + ram3x_dma_region: memory@2fc07000 { + compatible = "nordic,owned-memory"; + reg = <0x2fc07000 DT_SIZE_K(4)>; + status = "disabled"; + perm-read; + perm-write; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x2fc07000 0x1000>; + + cpuapp_dma_region: memory@680 { + compatible = "zephyr,memory-region"; + reg = <0x680 DT_SIZE_K(2)>; + status = "disabled"; + #memory-region-cells = <0>; + zephyr,memory-region = "DMA_RAM3x_APP"; + }; + + cpurad_dma_region: memory@e80 { + compatible = "zephyr,memory-region"; + reg = <0xe80 0x80>; + status = "disabled"; + #memory-region-cells = <0>; + zephyr,memory-region = "DMA_RAM3x_RAD"; + }; + }; + }; +}; + +&mram1x { + cpurad_rx_partitions: cpurad-rx-partitions { + compatible = "nordic,owned-partitions", "fixed-partitions"; + status = "disabled"; + perm-read; + perm-execute; + perm-secure; + #address-cells = <1>; + #size-cells = <1>; + + cpurad_slot0_partition: partition@66000 { + reg = <0x66000 DT_SIZE_K(256)>; + }; + }; + + cpuapp_rx_partitions: cpuapp-rx-partitions { + compatible = "nordic,owned-partitions", "fixed-partitions"; + status = "disabled"; + perm-read; + perm-execute; + perm-secure; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_slot0_partition: partition@a6000 { + reg = <0xa6000 DT_SIZE_K(512)>; + }; + + cpuppr_code_partition: partition@126000 { + reg = <0x126000 DT_SIZE_K(28)>; + }; + }; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi new file mode 100644 index 00000000000..d3b79120322 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20-pinctrl.dtsi @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + /omit-if-no-ref/ uart135_default: uart135_default { + group1 { + psels = , + ; + }; + + group2 { + bias-pull-up; + psels = , + ; + }; + }; + + /omit-if-no-ref/ uart135_sleep: uart135_sleep { + group1 { + low-power-enable; + psels = , + , + , + ; + }; + }; + + /omit-if-no-ref/ uart136_default: uart136_default { + group1 { + psels = , + ; + }; + + group2 { + bias-pull-up; + psels = , + ; + }; + }; + + /omit-if-no-ref/ uart136_sleep: uart136_sleep { + group1 { + low-power-enable; + psels = , + , + , + ; + }; + }; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts new file mode 100644 index 00000000000..359c1f84307 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.dts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpuapp"; + model = "Nordic nRF54H20 PDK nRF54H20 Application MCU"; + + chosen { + zephyr,console = &uart136; + zephyr,code-partition = &cpuapp_slot0_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpuapp_ram0; + }; + + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + }; + + buttons { + compatible = "gpio-keys"; + + button0: button_0 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 0"; + zephyr,code = ; + }; + + button1: button_1 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + + button2: button_2 { + gpios = <&gpio0 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + + button3: button_3 { + gpios = <&gpio0 11 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpio9 0 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + + led1: led_1 { + gpios = <&gpio9 1 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + + led2: led_2 { + gpios = <&gpio9 2 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + + led3: led_3 { + gpios = <&gpio9 3 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; +}; + +&ram3x_dma_region { + status = "okay"; +}; + +&cpuapp_dma_region { + status = "okay"; +}; + +&cpuapp_rx_partitions { + status = "okay"; +}; + +&cpuppr_vpr { + source-memory = <&cpuppr_code_partition>; + execution-memory = <&cpuppr_ram3x_region>; +}; + +&gpiote130 { + status = "okay"; + owned-channels = <0 1 2 3 4 5 6 7>; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio9 { + status = "okay"; +}; + +&grtc { + status = "okay"; + child-owned-channels = <5 6>; + nonsecure-channels = <5 6>; + owned-channels = <4 5 6>; +}; + +&uart135 { + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + status = "okay"; + memory-regions = <&cpuapp_dma_region>; + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml new file mode 100644 index 00000000000..a364c2863d3 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpuapp +name: nRF54H20-PDK-nRF54H20-Application +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 32 +flash: 368 +supported: + - gpio diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig new file mode 100644 index 00000000000..1f7ef38a7fc --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuapp_defconfig @@ -0,0 +1,33 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPUAPP=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPUAPP=y + +CONFIG_USE_DT_CODE_PARTITION=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot be applied +# as the (0x0 - 0x400) region is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts new file mode 100644 index 00000000000..02213d88645 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpurad"; + model = "Nordic nRF54H20 PDK nRF54H20 Radio MCU"; + + chosen { + zephyr,console = &uart135; + zephyr,code-partition = &cpurad_slot0_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpurad_ram0; + }; +}; + +&ram3x_dma_region { + status = "okay"; +}; + +&cpurad_dma_region { + status = "okay"; +}; + +&cpurad_rx_partitions { + status = "okay"; +}; + +&grtc { + status = "okay"; + child-owned-channels = <8 9 10 11 12>; + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>, + <108 NRF_DEFAULT_IRQ_PRIORITY>; + nonsecure-channels = <8 9 10 11 12>; + owned-channels = <7 8 9 10 11 12 13 14>; +}; + +&uart135 { + status = "okay"; + memory-regions = <&cpurad_dma_region>; + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml new file mode 100644 index 00000000000..d1c8548d07d --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpurad +name: nRF54H20-PDK-nRF54H20-Radio +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 32 +flash: 368 +supported: + - gpio diff --git a/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig new file mode 100644 index 00000000000..254d8656e61 --- /dev/null +++ b/boards/arm/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpurad_defconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPURAD=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPURAD=y + +CONFIG_USE_DT_CODE_PARTITION=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot be applied +# as the (0x0 - 0x400) region is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board new file mode 100644 index 00000000000..d95fe51009f --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54L15PDK_NRF54L15_CPUAPP + bool "nRF54L15 PDK nRF54L15 Application MCU" + depends on SOC_NRF54L15_ENGA_CPUAPP diff --git a/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig new file mode 100644 index 00000000000..532ea07c859 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/Kconfig.defconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NRF54L15PDK_NRF54L15_CPUAPP + +config BOARD + default "nrf54l15pdk_nrf54l15_cpuapp" + +config BT_CTLR + default BT + +endif # BOARD_NRF54L15PDK_NRF54L15_CPUAPP diff --git a/boards/arm/nrf54l15pdk_nrf54l15/board.cmake b/boards/arm/nrf54l15pdk_nrf54l15/board.cmake new file mode 100644 index 00000000000..378b7bcdb57 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/board.cmake @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp b/boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp new file mode 100644 index 00000000000..80fb2060a07 Binary files /dev/null and b/boards/arm/nrf54l15pdk_nrf54l15/doc/img/nrf54l15pdk_nrf54l15.webp differ diff --git a/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst b/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst new file mode 100644 index 00000000000..fa896f98398 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/doc/index.rst @@ -0,0 +1,134 @@ +.. _nrf54l15pdk_nrf54l15: + +nRF54L15 PDK +############ + +Overview +******** + +The nRF54L15 Preview Development Kit hardware provides +support for the Nordic Semiconductor nRF54L15 Arm Cortex-M33 CPU and +the following devices: + +* :abbr:`SAADC (Successive Approximation Analog to Digital Converter)` +* CLOCK +* RRAM +* :abbr:`GPIO (General Purpose Input Output)` +* :abbr:`TWIM (I2C-compatible two-wire interface master with EasyDMA)` +* :abbr:`MPU (Memory Protection Unit)` +* :abbr:`NVIC (Nested Vectored Interrupt Controller)` +* :abbr:`PWM (Pulse Width Modulation)` +* :abbr:`GRTC (Global real-time counter)` +* Segger RTT (RTT Console) +* :abbr:`SPI (Serial Peripheral Interface)` +* :abbr:`UARTE (Universal asynchronous receiver-transmitter)` +* :abbr:`WDT (Watchdog Timer)` + +.. figure:: img/nrf54l15pdk_nrf54l15.webp + :align: center + :alt: nRF54L15 PDK + + nRF54L15 PDK (Credit: Nordic Semiconductor) + +Hardware +******** + +nRF54L15 PDK has two crystal oscillators: + +* High-frequency 32 MHz crystal oscillator (HFXO) +* Low-frequency 32.768 kHz crystal oscillator (LFXO) + +The crystal oscillators can be configured to use either +internal or external capacitors. + +Supported Features +================== + +The nrf54l15pdk_nrf54l15 board configuration supports the following +hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| SAADC | on-chip | adc | ++-----------+------------+----------------------+ +| CLOCK | on-chip | clock_control | ++-----------+------------+----------------------+ +| RRAM | on-chip | flash | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| TWIM | on-chip | i2c | ++-----------+------------+----------------------+ +| MPU | on-chip | arch/arm | ++-----------+------------+----------------------+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| PWM | on-chip | pwm | ++-----------+------------+----------------------+ +| GRTC | on-chip | counter | ++-----------+------------+----------------------+ +| RTT | Segger | console | ++-----------+------------+----------------------+ +| SPI(M/S) | on-chip | spi | ++-----------+------------+----------------------+ +| SPU | on-chip | system protection | ++-----------+------------+----------------------+ +| UARTE | on-chip | serial | ++-----------+------------+----------------------+ +| WDT | on-chip | watchdog | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. + +Programming and Debugging +************************* + +Applications for the ``nrf54l15pdk_nrf54l15_cpuapp`` board can be +built, flashed, and debugged in the usual way. See +:ref:`build_an_application` and :ref:`application_run` for more details on +building and running. + +Flashing +======== + +As an example, this section shows how to build and flash the :ref:`hello_world` +application. + +.. warning:: + + When programming the device, you might get an error similar to the following message:: + + ERROR: The operation attempted is unavailable due to readback protection in + ERROR: your device. Please use --recover to unlock the device. + + This error occurs when readback protection is enabled. + To disable the readback protection, you must *recover* your device. + + Enter the following command to recover the core:: + + west flash --recover + + The ``--recover`` command erases the flash memory and then writes a small binary into + the recovered flash memory. + This binary prevents the readback protection from enabling itself again after a pin + reset or power cycle. + +Follow the instructions in the :ref:`nordic_segger` page to install +and configure all the necessary software. Further information can be +found in :ref:`nordic_segger_flashing`. + +To build and program the sample to the nRF54L15 PDK, complete the following steps: + +First, connect the nRF54L15 PDK to you computer using the IMCU USB port on the PDK. +Next, build the sample by running the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nrf54l15pdk_nrf54l15_cpuapp + :goals: build flash + +Testing the LEDs and buttons in the nRF54L15 PDK +************************************************ + +Test the nRF54L15 PDK with a :zephyr:code-sample:`blinky` sample. diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi new file mode 100644 index 00000000000..02b02bc8171 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart20_default: uart20_default { + group1 { + psels = , + ; + }; + }; + + uart20_sleep: uart20_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + uart30_default: uart30_default { + group1 { + psels = , + ; + }; + }; + + uart30_sleep: uart30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts new file mode 100644 index 00000000000..1e0245f6cc3 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.dts @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "nrf54l15pdk_nrf54l15_cpuapp-pinctrl.dtsi" +#include + +/ { + model = "Nordic nRF54L15 PDK nRF54L15 Application MCU"; + compatible = "nordic,nrf54l15pdk_nrf54l15-cpuapp"; + + chosen { + zephyr,console = &uart20; + zephyr,shell-uart = &uart20; + zephyr,sram = &sram0; + zephyr,flash = &rram0; + zephyr,code-partition = &slot0_partition; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + label = "Green LED 0"; + }; + led1: led_1 { + gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + label = "Green LED 1"; + }; + led2: led_2 { + gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + label = "Green LED 2"; + }; + led3: led_3 { + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; + label = "Green LED 3"; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 0"; + zephyr,code = ; + }; + button1: button_1 { + gpios = <&gpio1 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 1"; + zephyr,code = ; + }; + button2: button_2 { + gpios = <&gpio2 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 2"; + zephyr,code = ; + }; + button3: button_3 { + gpios = <&gpio2 10 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Push button 3"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &led0; + led1 = &led1; + led2 = &led2; + led3 = &led3; + watchdog0 = &wdt30; + sw0 = &button0; + sw1 = &button1; + sw2 = &button2; + sw3 = &button3; + }; +}; + +&lfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15500>; +}; + +&hfxo { + load-capacitors = "internal"; + load-capacitance-femtofarad = <15000>; +}; + +&uart20 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart20_default>; + pinctrl-1 = <&uart20_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart30 { + current-speed = <115200>; + pinctrl-0 = <&uart30_default>; + pinctrl-1 = <&uart30_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&grtc { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&gpio2 { + status = "okay"; +}; + +&gpiote20 { + status = "okay"; +}; + +&gpiote30 { + status = "okay"; +}; + +&rram0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x0 DT_SIZE_K(64)>; + }; + storage_partition: partition@f2000 { + label = "storage"; + reg = <0xf2000 DT_SIZE_K(24)>; + }; + }; +}; + +&clock { + status = "okay"; +}; diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml new file mode 100644 index 00000000000..de5ce29d162 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54l15pdk_nrf54l15_cpuapp +name: nRF54l15-PDK-nRF54l15-Application +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 256 +flash: 1536 +supported: + - gpio + - i2c + - spi + - watchdog + - i2s diff --git a/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig new file mode 100644 index 00000000000..bc74c3eeb33 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/nrf54l15pdk_nrf54l15_cpuapp_defconfig @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54LX=y +CONFIG_SOC_NRF54L15_ENGA_CPUAPP=y +CONFIG_BOARD_NRF54L15PDK_NRF54L15_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot +# be applied as the (0x0 - 0x400) is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable Cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +CONFIG_UART_CONSOLE=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y + +# Enable GPIO +CONFIG_GPIO=y + +CONFIG_SOC_NRF_FORCE_CONSTLAT=y + +# Start SYSCOUNTER on driver init +CONFIG_NRF_GRTC_START_SYSCOUNTER=y diff --git a/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake b/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake new file mode 100644 index 00000000000..4fe5b260db3 --- /dev/null +++ b/boards/arm/nrf54l15pdk_nrf54l15/revision.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +board_check_revision(FORMAT MAJOR.MINOR.PATCH + VALID_REVISIONS 0.2.0 + DEFAULT_REVISION 0.2.0) diff --git a/boards/arm/nrf9131ek_nrf9131/doc/index.rst b/boards/arm/nrf9131ek_nrf9131/doc/index.rst index a72cd1526e3..57473c631ed 100644 --- a/boards/arm/nrf9131ek_nrf9131/doc/index.rst +++ b/boards/arm/nrf9131ek_nrf9131/doc/index.rst @@ -6,7 +6,8 @@ nRF9131 EK Overview ******** -The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP for LTE-M and NB-IoT. +The nRF9131 EK (PCA10165) is a single-board evaluation kit for the nRF9131 SiP +for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9131ek_nrf9131 board configuration provides support for the Nordic Semiconductor nRF9131 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: diff --git a/boards/arm/nrf9161dk_nrf9161/doc/index.rst b/boards/arm/nrf9161dk_nrf9161/doc/index.rst index 559288b06aa..18b214a7fde 100644 --- a/boards/arm/nrf9161dk_nrf9161/doc/index.rst +++ b/boards/arm/nrf9161dk_nrf9161/doc/index.rst @@ -7,7 +7,7 @@ Overview ******** The nRF9161 DK (PCA10153) is a single-board development kit for evaluation and -development on the nRF9161 SiP for LTE-M and NB-IoT. The nrf9161dk_nrf9161 +development on the nRF9161 SiP for DECT NR+ and LTE-M/NB-IoT with GNSS. The nrf9161dk_nrf9161 board configuration provides support for the Nordic Semiconductor nRF9161 ARM Cortex-M33F CPU with ARMv8-M Security Extension and the following devices: diff --git a/boards/arm/nucleo_c031c6/doc/index.rst b/boards/arm/nucleo_c031c6/doc/index.rst index fcf134f497e..3e28230cba2 100644 --- a/boards/arm/nucleo_c031c6/doc/index.rst +++ b/boards/arm/nucleo_c031c6/doc/index.rst @@ -110,7 +110,7 @@ Default Zephyr Peripheral Mapping: - UART_2 TX/RX : PA2/PA3 (ST-Link Virtual Port Com) - LD4 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f030r8/doc/index.rst b/boards/arm/nucleo_f030r8/doc/index.rst index 821470b20c0..a6f104398c7 100644 --- a/boards/arm/nucleo_f030r8/doc/index.rst +++ b/boards/arm/nucleo_f030r8/doc/index.rst @@ -129,7 +129,7 @@ Default Zephyr Peripheral Mapping: - ADC : PA0 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f031k6/doc/index.rst b/boards/arm/nucleo_f031k6/doc/index.rst index b7adddf6509..ccfb1540f26 100644 --- a/boards/arm/nucleo_f031k6/doc/index.rst +++ b/boards/arm/nucleo_f031k6/doc/index.rst @@ -98,7 +98,7 @@ Default Zephyr Peripheral Mapping: - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f042k6/doc/index.rst b/boards/arm/nucleo_f042k6/doc/index.rst index a9676350eb4..66ad80adeed 100644 --- a/boards/arm/nucleo_f042k6/doc/index.rst +++ b/boards/arm/nucleo_f042k6/doc/index.rst @@ -98,7 +98,7 @@ Default Zephyr Peripheral Mapping: - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f042k6/nucleo_f042k6.dts b/boards/arm/nucleo_f042k6/nucleo_f042k6.dts index d3afe9e59e3..ac1659dfc39 100644 --- a/boards/arm/nucleo_f042k6/nucleo_f042k6.dts +++ b/boards/arm/nucleo_f042k6/nucleo_f042k6.dts @@ -30,7 +30,7 @@ pwmleds { compatible = "pwm-leds"; green_pwm_led: green_pwm_led { - pwms = <&pwm3 32 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + pwms = <&pwm3 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>; }; }; @@ -66,6 +66,7 @@ &timers3 { status = "okay"; + st,prescaler = <10000>; pwm3: pwm { status = "okay"; diff --git a/boards/arm/nucleo_f070rb/doc/index.rst b/boards/arm/nucleo_f070rb/doc/index.rst index 5d7e214bd1b..50a96e3fed4 100644 --- a/boards/arm/nucleo_f070rb/doc/index.rst +++ b/boards/arm/nucleo_f070rb/doc/index.rst @@ -126,7 +126,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD1 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f091rc/doc/index.rst b/boards/arm/nucleo_f091rc/doc/index.rst index f1f0df58e10..9ff09e28770 100644 --- a/boards/arm/nucleo_f091rc/doc/index.rst +++ b/boards/arm/nucleo_f091rc/doc/index.rst @@ -143,7 +143,7 @@ Default Zephyr Peripheral Mapping: - DAC_OUT1 : PA4 - PWM_2_CH1 : PA5 (might conflict with SPI1) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f103rb/doc/index.rst b/boards/arm/nucleo_f103rb/doc/index.rst index b717c75b58a..8f67b04ad62 100644 --- a/boards/arm/nucleo_f103rb/doc/index.rst +++ b/boards/arm/nucleo_f103rb/doc/index.rst @@ -133,7 +133,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD1 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f334r8/doc/index.rst b/boards/arm/nucleo_f334r8/doc/index.rst index d44ee9e51d7..64824e787eb 100644 --- a/boards/arm/nucleo_f334r8/doc/index.rst +++ b/boards/arm/nucleo_f334r8/doc/index.rst @@ -123,7 +123,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD2 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_f401re/doc/index.rst b/boards/arm/nucleo_f401re/doc/index.rst index c844ef9ab9c..aa01b1ad3ad 100644 --- a/boards/arm/nucleo_f401re/doc/index.rst +++ b/boards/arm/nucleo_f401re/doc/index.rst @@ -109,7 +109,7 @@ Available pins: :align: center :alt: Nucleo F401RE Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f410rb/doc/index.rst b/boards/arm/nucleo_f410rb/doc/index.rst index c5702552ca8..23c979e49aa 100644 --- a/boards/arm/nucleo_f410rb/doc/index.rst +++ b/boards/arm/nucleo_f410rb/doc/index.rst @@ -120,7 +120,7 @@ Available pins: :align: center :alt: Nucleo F410RB Morpho connectors (top right) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f411re/doc/index.rst b/boards/arm/nucleo_f411re/doc/index.rst index ee7d652d1c5..908dfbf9a2a 100644 --- a/boards/arm/nucleo_f411re/doc/index.rst +++ b/boards/arm/nucleo_f411re/doc/index.rst @@ -107,7 +107,7 @@ Available pins: :align: center :alt: Nucleo F411RE Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f413zh/doc/index.rst b/boards/arm/nucleo_f413zh/doc/index.rst index b00213ced7e..7979171472e 100644 --- a/boards/arm/nucleo_f413zh/doc/index.rst +++ b/boards/arm/nucleo_f413zh/doc/index.rst @@ -117,7 +117,7 @@ Available pins: :align: center :alt: Nucleo F413ZH Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f429zi/doc/index.rst b/boards/arm/nucleo_f429zi/doc/index.rst index 3b20f6a7a0c..e65e9194ad4 100644 --- a/boards/arm/nucleo_f429zi/doc/index.rst +++ b/boards/arm/nucleo_f429zi/doc/index.rst @@ -139,7 +139,7 @@ Available pins: :align: center :alt: Nucleo F429ZI Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f446re/doc/index.rst b/boards/arm/nucleo_f446re/doc/index.rst index a835d963d2b..37d62c04310 100644 --- a/boards/arm/nucleo_f446re/doc/index.rst +++ b/boards/arm/nucleo_f446re/doc/index.rst @@ -118,7 +118,7 @@ Available pins: :align: center :alt: Nucleo F446RE Morpho connectors (top right) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f446re/nucleo_f446re.dts b/boards/arm/nucleo_f446re/nucleo_f446re.dts index e03b91c0ad9..6afc2996acc 100644 --- a/boards/arm/nucleo_f446re/nucleo_f446re.dts +++ b/boards/arm/nucleo_f446re/nucleo_f446re.dts @@ -31,6 +31,13 @@ }; }; + pwmleds { + compatible = "pwm-leds"; + green_pwm_led: green_pwm_led { + pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + gpio_keys { compatible = "gpio-keys"; user_button: button { @@ -42,6 +49,7 @@ aliases { led0 = &green_led_2; + pwm-led0 = &green_pwm_led; sw0 = &user_button; }; }; @@ -115,6 +123,16 @@ status = "okay"; }; +&timers2 { + status = "okay"; + + pwm2: pwm { + status = "okay"; + pinctrl-0 = <&tim2_ch1_pa5>; + pinctrl-names = "default"; + }; +}; + &rtc { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, <&rcc STM32_SRC_LSI RTC_SEL(2)>; diff --git a/boards/arm/nucleo_f446ze/doc/index.rst b/boards/arm/nucleo_f446ze/doc/index.rst index b0a8f431462..697324e84fa 100644 --- a/boards/arm/nucleo_f446ze/doc/index.rst +++ b/boards/arm/nucleo_f446ze/doc/index.rst @@ -129,7 +129,7 @@ Available pins: :align: center :alt: Nucleo F446ZE Morpho connectors (right) -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f722ze/Kconfig.board b/boards/arm/nucleo_f722ze/Kconfig.board new file mode 100644 index 00000000000..f15e218e161 --- /dev/null +++ b/boards/arm/nucleo_f722ze/Kconfig.board @@ -0,0 +1,8 @@ +# STM32F722ZE Nucleo board configuration + +# Copyright (c) 2023 Evan Perry Grove +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NUCLEO_F722ZE + bool "Nucleo F722ZE Development Board" + depends on SOC_STM32F722XX diff --git a/boards/arm/nucleo_f722ze/Kconfig.defconfig b/boards/arm/nucleo_f722ze/Kconfig.defconfig new file mode 100644 index 00000000000..1dfff0c9d44 --- /dev/null +++ b/boards/arm/nucleo_f722ze/Kconfig.defconfig @@ -0,0 +1,15 @@ +# STM32F722ZE Nucleo board configuration +# +# Copyright (c) 2023 Evan Perry Grove +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NUCLEO_F722ZE + +config BOARD + default "nucleo_f722ze" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_NUCLEO_F722ZE diff --git a/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi b/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..9072fa91476 --- /dev/null +++ b/boards/arm/nucleo_f722ze/arduino_r3_connector.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Tom Owen + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 3 0>, /* A0 */ + <1 0 &gpioc 0 0>, /* A1 */ + <2 0 &gpioc 3 0>, /* A2 */ + <3 0 &gpiof 3 0>, /* A3 */ + <4 0 &gpiof 5 0>, /* A4 */ + <5 0 &gpiof 10 0>, /* A5 */ + <6 0 &gpiog 9 0>, /* D0 */ + <7 0 &gpiog 14 0>, /* D1 */ + <8 0 &gpiof 15 0>, /* D2 */ + <9 0 &gpioe 13 0>, /* D3 */ + <10 0 &gpiof 14 0>, /* D4 */ + <11 0 &gpioe 11 0>, /* D5 */ + <12 0 &gpioe 9 0>, /* D6 */ + <13 0 &gpiof 13 0>, /* D7 */ + <14 0 &gpiof 12 0>, /* D8 */ + <15 0 &gpiod 15 0>, /* D9 */ + <16 0 &gpiod 14 0>, /* D10 */ + <17 0 &gpioa 7 0>, /* D11 */ + <18 0 &gpioa 6 0>, /* D12 */ + <19 0 &gpioa 5 0>, /* D13 */ + <20 0 &gpiob 9 0>, /* D14 */ + <21 0 &gpiob 8 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; +arduino_serial: &usart6 {}; diff --git a/boards/arm/nucleo_f722ze/board.cmake b/boards/arm/nucleo_f722ze/board.cmake new file mode 100644 index 00000000000..6335e34584a --- /dev/null +++ b/boards/arm/nucleo_f722ze/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32F722ZE" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg b/boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg new file mode 100644 index 00000000000..0778ea20cfd Binary files /dev/null and b/boards/arm/nucleo_f722ze/doc/img/nucleo_f722ze.jpg differ diff --git a/boards/arm/nucleo_f722ze/doc/index.rst b/boards/arm/nucleo_f722ze/doc/index.rst new file mode 100644 index 00000000000..f0c40595f3a --- /dev/null +++ b/boards/arm/nucleo_f722ze/doc/index.rst @@ -0,0 +1,243 @@ +.. _nucleo_f722ze_board: + +ST Nucleo F722ZE +################ + +Overview +******** + +The Nucleo F722ZE board features an ARM Cortex-M7 based STM32F722ZE MCU. + +Key Features: + +- STM32 microcontroller in LQFP144 package +- USB full-speed/high-speed device +- 3 user LEDs +- 1 user button and 1 reset button +- 32.768 kHz crystal oscillator +- Board connectors: + - USB Micro-AB + - SWD + - ST Zio connector (Arduino Uno R3 compatible) + - ST Morpho connector +- On-board ST-LINK debugger/programmer +- Flexible power supply options, including ST-LINK VBUS and external sources. + +.. image:: img/nucleo_f722ze.jpg + :width: 800px + :align: center + :alt: Nucleo F722ZE + +Hardware +******** + +Nucleo F722ZE provides the following hardware components: + +- STM32F722ZET6 microcontroller in LQFP144 package +- ARM |reg| Cortex |reg|-M4 with FPU +- Adaptive Real-Time Accelerator (ART Accelerator) +- 216MHz max CPU frequency +- 512 KB flash +- 256 KB RAM +- I2C (3) +- USART/UART (4) +- SPI (5) +- I2S (3) +- SAI (2) +- USB OTG Full-speed (1) +- USB OTG Full-speed/high-speed (1) +- SDMMC (2) +- CAN (1) +- Dual mode Quad-SPI +- Random number generator (RNG) +- 3x 12-bit ADC, up to 2.4 MSPS with 24 channels or 7.2 MSPS in triple-interleaved mode +- 2x 12-bit DAC +- 16-channel DMA controller +- 16-bit timers (13) with PWM, pulse counter, and quadrature features +- 32-bit timers (2) with PWM, pulse counter, and quadrature features +- CRC +- 96-bit unique ID +- Die temperature + +Supported Features +================== + ++---------------+------------+-------------------------------+ +| Interface | Controller | Driver/Component | ++===============+============+===============================+ +| NVIC | on-chip | arch/arm | ++---------------+------------+-------------------------------+ +| MPU | on-chip | arch/arm | ++---------------+------------+-------------------------------+ +| ADC | on-chip | adc | ++---------------+------------+-------------------------------+ +| CAN | on-chip | can | ++---------------+------------+-------------------------------+ +| USART/UART | on-chip | console, serial | ++---------------+------------+-------------------------------+ +| TIMER | on-chip | counter, pwm, timer | ++---------------+------------+-------------------------------+ +| DAC | on-chip | dac | ++---------------+------------+-------------------------------+ +| DMA | on-chip | dma | ++---------------+------------+-------------------------------+ +| GPIO | on-chip | gpio | ++---------------+------------+-------------------------------+ +| HWINFO | on-chip | hwinfo | ++---------------+------------+-------------------------------+ +| I2C | on-chip | i2c | ++---------------+------------+-------------------------------+ +| EXTI | on-chip | interrupt_controller | ++---------------+------------+-------------------------------+ +| BACKUP_SRAM | on-chip | memory | ++---------------+------------+-------------------------------+ +| QUADSPI | on-chip | memory | ++---------------+------------+-------------------------------+ +| PINMUX | on-chip | pinctrl | ++---------------+------------+-------------------------------+ +| RCC | on-chip | reset | ++---------------+------------+-------------------------------+ +| RTC | on-chip | rtc | ++---------------+------------+-------------------------------+ +| DIE_TEMP | on-chip | sensor | ++---------------+------------+-------------------------------+ +| VREF | on-chip | sensor | ++---------------+------------+-------------------------------+ +| VBAT | on-chip | sensor | ++---------------+------------+-------------------------------+ +| SPI | on-chip | spi | ++---------------+------------+-------------------------------+ +| USBOTG_HS | on-chip | usb | ++---------------+------------+-------------------------------+ +| USBOTG_FS | on-chip | usb | ++---------------+------------+-------------------------------+ +| IWDG | on-chip | watchdog | ++---------------+------------+-------------------------------+ +| WWDG | on-chip | watchdog | ++---------------+------------+-------------------------------+ + +Connections and IOs +=================== + +- SDMMC1: Pins marked as "SDMMC" on the ST Zio connector. + - D0: PC8 (CN8 pin 2) + - D1: PC9 (CN8 pin 4) + - D2: PC10 (CN8 pin 6) + - D3: PC11 (CN8 pin 8) + - CK: PC12 (CN8 pin 10) + - CMD: PD2 (CN8 pin 12) +- ADC1: + - IN3: PA3 (CN9 pin 1, Arduino A0) + - IN10: PC0 (CN9 pin 3, Arduino A1) +- DAC1: + - OUT1: PA4 (CN7 pin 17) +- I2C2: Pins marked as "I2C" on the ST Zio connector. + - SCL: PF1 (CN9 pin 19) + - SDA: PF0 (CN9 pin 21) +- CAN1: Pins marked as "CAN" on the ST Zio connector. + - RX: PD0 (CN9 pin 25) + - TX: PD1 (CN9 pin 27) +- USART2: Pins marked as "USART" on the ST Zio connector. + - RX: PD6 (CN9 pin 4) + - TX: PD5 (CN9 pin 6) + - RTS: PD4 (CN9 pin 8) + - CTS: PD3 (CN9 pin 10) +- PWM1: Uses TIMER1. + - PE13 (CN10 pin 10, Arduino D3) + - PE11 (CN10 pin 6, Arduino D5) +- USART3: Connected to ST-Link virtual COM port. + - TX: PD8 + - RX: PD9 +- USART6: Arduino UART port. + - RX: PG9 (CN10 pin 16, Arduino D0) + - TX: PG14 (CN10 pin 14, Arduino D1) +- USBOTG_FS: Connected to USB Micro-AB connector (CN13) + - DM: PA11 + - DP: PA12 + - ID: PA10 +- QUADSPI: Pins marked as "QSPI" on the ST Zio connector. + - CS: PB6 (CN10 pin 13) + - CLK: PB2 (CN10 pin 15) + - IO3: PD13 (CN10 pin 19) + - IO1: PD12 (CN10 pin 21) + - IO0: PD11 (CN10 pin 23) + - IO2: PE2 (CN10 pin 25) + +System Clock +------------ + +By default, the system clock is driven by the external clock supplied by +the ST-LINK interface. Nucleo F722ZE system clock can be driven by internal +or external sources. + +Serial Port +----------- + +Zephyr console is assigned to UART3 (ST-Link Virtual COM Port) by default, +using 115200 8N1. + +Programming and Debugging +************************* + +The ``nucleo_f722ze`` can be flashed and debugged in the typical manner. +The Nucleo F722ZE board includes an ST-LINK V2-1 debugger, which can be used +with the OpenOCD version provided with the Zephyr SDK. Refer to +:ref:`build_an_application` and :ref:`application_run` for detailed +instructions. + +Flashing +======== + +Build the :ref:`hello_world` application and flash it using the on-board +ST-LINK interface: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nucleo_f722ze + :goals: build flash + +Debugging +========= + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: nucleo_f722ze + :maybe-skip-config: + :goals: debug + +J-Link OB Firmware +------------------ + +Like many other STM32 evaluation boards, the Nucleo F722ZE's on-board ST-LINK +debug interface may be flashed with `SEGGER J-Link OB firmware`_. This +firmware turns the ST-LINK into a J-Link probe. If the on-board debugger has +been re-flashed with J-Link OB firmware, simply append ``--runner jlink`` to +all flashing/debugging commands. + +References +********** + +More information about the STM32F722ZE: + +- `STM32F722ZE on www.st.com`_ +- `STM32F722ZE Reference Manual (RM0431)`_ (PDF) + +More information about Nucleo F722ZE: + +- `Nucleo F722ZE on www.st.com`_ +- `STM32 Nucleo-144 User Manual (UM1974)`_ (PDF) + +.. _SEGGER J-Link OB firmware: + https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/ + +.. _STM32F722ZE on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32f722ze.html + +.. _STM32F722ZE Reference Manual (RM0431): + https://www.st.com/resource/en/reference_manual/rm0431-stm32f72xxx-and-stm32f73xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _Nucleo F722ZE on www.st.com: + https://www.st.com/en/evaluation-tools/nucleo-f722ze.html + +.. _STM32 Nucleo-144 User Manual (UM1974): + https://www.st.com/resource/en/user_manual/um1974-stm32-nucleo144-boards-mb1137-stmicroelectronics.pdf diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze.dts b/boards/arm/nucleo_f722ze/nucleo_f722ze.dts new file mode 100644 index 00000000000..e3a2e65ad3b --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze.dts @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "STMicroelectronics STM32F722ZE-NUCLEO board"; + compatible = "st,stm32f722ze-nucleo"; + + chosen { + zephyr,console = &usart3; + zephyr,shell-uart = &usart3; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,dtcm = &dtcm; + zephyr,canbus = &can1; + }; + + leds { + compatible = "gpio-leds"; + green_led: led_1 { + gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>; + label = "User LD1"; + }; + blue_led: led_2 { + gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>; + label = "User LD2"; + }; + red_led: led_3 { + gpios = <&gpiob 14 GPIO_ACTIVE_HIGH>; + label = "User LD3"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &blue_led; + led2 = &red_led; + sw0 = &user_button; + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + }; +}; + +&clk_hse { + clock-frequency = ; + status = "okay"; +}; + +&clk_hsi { + status = "disabled"; +}; + +&pll { + div-m = <4>; + mul-n = <216>; + div-p = <2>; + div-q = <9>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + ahb-prescaler = <1>; + apb1-prescaler = <4>; + apb2-prescaler = <2>; +}; + +&sdmmc1 { + status = "okay"; + pinctrl-0 = <&sdmmc1_d0_pc8 &sdmmc1_d1_pc9 &sdmmc1_d2_pc10 + &sdmmc1_d3_pc11 &sdmmc1_ck_pc12 &sdmmc1_cmd_pd2>; + pinctrl-names = "default"; + cd-gpios = <&gpioi 15 GPIO_ACTIVE_LOW>; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pa3 &adc1_in10_pc0>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <2>; + status = "okay"; +}; + +&dac1 { + pinctrl-0 = <&dac_out1_pa4>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c2 { + pinctrl-0 = <&i2c2_scl_pf1 &i2c2_sda_pf0>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&can1 { + pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>; + pinctrl-names = "default"; + bus-speed = <125000>; + status = "okay"; +}; + +&usart2 { + pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6 &usart2_rts_pd4 &usart2_cts_pd3>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pd8 &usart3_rx_pd9>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb8 &i2c1_sda_pb9>; + pinctrl-names = "default"; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; + pinctrl-names = "default"; + cs-gpios = <&gpiod 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; +}; + +&timers1 { + status = "okay"; + + pwm1: pwm { + status = "okay"; + pinctrl-0 = <&tim1_ch2_pe11 &tim1_ch3_pe13>; + pinctrl-names = "default"; + }; +}; + +&usart6 { + pinctrl-0 = <&usart6_tx_pg14 &usart6_rx_pg9>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +zephyr_udc0: &usbotg_fs { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12 &usb_otg_fs_id_pa10>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rtc { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + status = "okay"; +}; + +&die_temp { + status = "okay"; +}; + +&dma2 { + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +&vref { + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&backup_sram { + status = "okay"; +}; + +&quadspi { + pinctrl-names = "default"; + pinctrl-0 = <&quadspi_clk_pb2 &quadspi_bk1_ncs_pb6 + &quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pd12 + &quadspi_bk1_io2_pe2 &quadspi_bk1_io3_pd13>; + flash-id = <1>; + status = "okay"; +}; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* sectors 0-3 */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + /* sector 4 */ + storage_partition: partition@10000 { + label = "storage"; + reg = <0x00010000 DT_SIZE_K(64)>; + }; + + /* sector 5 */ + slot0_partition: partition@20000 { + label = "image-0"; + reg = <0x00020000 DT_SIZE_K(128)>; + }; + + /* sector 6 */ + slot1_partition: partition@40000 { + label = "image-1"; + reg = <0x00040000 DT_SIZE_K(128)>; + }; + + /* sector 7 */ + scratch_partition: partition@60000 { + label = "image-scratch"; + reg = <0x00060000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml b/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml new file mode 100644 index 00000000000..94cdcb73914 --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze.yaml @@ -0,0 +1,25 @@ +identifier: nucleo_f722ze +name: ST Nucleo F722ZE +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - arduino_gpio + - arduino_i2c + - arduino_spi + - backup_sram + - can + - counter + - dac + - gpio + - i2c + - quadspi + - spi + - usb_device +ram: 256 +flash: 512 +vendor: st diff --git a/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig b/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig new file mode 100644 index 00000000000..345694efd80 --- /dev/null +++ b/boards/arm/nucleo_f722ze/nucleo_f722ze_defconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32F7X=y +CONFIG_SOC_STM32F722XX=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# Enable UART +CONFIG_SERIAL=y + +# Enable console (use UART by default) +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable GPIO +CONFIG_GPIO=y + +# Enable clocks +CONFIG_CLOCK_CONTROL=y + +# Enable pinctrl +CONFIG_PINCTRL=y diff --git a/boards/arm/nucleo_f722ze/support/openocd.cfg b/boards/arm/nucleo_f722ze/support/openocd.cfg new file mode 100644 index 00000000000..599f7e84012 --- /dev/null +++ b/boards/arm/nucleo_f722ze/support/openocd.cfg @@ -0,0 +1,12 @@ +source [find board/st_nucleo_f7.cfg] + +$_TARGETNAME configure -event gdb-attach { + echo "Debugger attaching: halting execution" + reset halt + gdb_breakpoint_override hard +} + +$_TARGETNAME configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} diff --git a/boards/arm/nucleo_f746zg/doc/index.rst b/boards/arm/nucleo_f746zg/doc/index.rst index ef9fdf9d20e..8bc083bcc3f 100644 --- a/boards/arm/nucleo_f746zg/doc/index.rst +++ b/boards/arm/nucleo_f746zg/doc/index.rst @@ -128,7 +128,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f746zg/nucleo_f746zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f756zg/doc/index.rst b/boards/arm/nucleo_f756zg/doc/index.rst index 2616a3b6dcc..aa13ddb7f20 100644 --- a/boards/arm/nucleo_f756zg/doc/index.rst +++ b/boards/arm/nucleo_f756zg/doc/index.rst @@ -118,7 +118,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f756zg/nucleo_f756zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_f767zi/doc/index.rst b/boards/arm/nucleo_f767zi/doc/index.rst index bed503e2609..7eca2af1eda 100644 --- a/boards/arm/nucleo_f767zi/doc/index.rst +++ b/boards/arm/nucleo_f767zi/doc/index.rst @@ -135,7 +135,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_f767zi/nucleo_f767zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_g031k8/doc/index.rst b/boards/arm/nucleo_g031k8/doc/index.rst index 6f933b08546..93a10b553ab 100644 --- a/boards/arm/nucleo_g031k8/doc/index.rst +++ b/boards/arm/nucleo_g031k8/doc/index.rst @@ -105,7 +105,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PB3/PB4/PB5 (Arduino SPI) - LD3 : PC6 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g070rb/doc/index.rst b/boards/arm/nucleo_g070rb/doc/index.rst index 056bb298c4f..8908ed5ce43 100644 --- a/boards/arm/nucleo_g070rb/doc/index.rst +++ b/boards/arm/nucleo_g070rb/doc/index.rst @@ -138,7 +138,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g071rb/doc/index.rst b/boards/arm/nucleo_g071rb/doc/index.rst index f6aebe8f12b..424f1ade9f7 100644 --- a/boards/arm/nucleo_g071rb/doc/index.rst +++ b/boards/arm/nucleo_g071rb/doc/index.rst @@ -142,7 +142,7 @@ Default Zephyr Peripheral Mapping: - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts index 76b2369280e..9c510e49864 100644 --- a/boards/arm/nucleo_g071rb/nucleo_g071rb.dts +++ b/boards/arm/nucleo_g071rb/nucleo_g071rb.dts @@ -170,7 +170,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_g0b1re/doc/index.rst b/boards/arm/nucleo_g0b1re/doc/index.rst index 0ad60852627..9627b094fc0 100644 --- a/boards/arm/nucleo_g0b1re/doc/index.rst +++ b/boards/arm/nucleo_g0b1re/doc/index.rst @@ -108,6 +108,8 @@ The Zephyr nucleo_g0b1re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| FDCAN | on-chip | CAN controller | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported in this Zephyr port. @@ -137,8 +139,10 @@ Default Zephyr Peripheral Mapping: - ADC1 IN0 : PA0 - ADC1 IN1 : PA1 - DAC1_OUT1 : PA4 +- FDCAN1 RX/TX: PA11/PA12 +- FDCAN2 RX/TX: PB0/PB1 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts index 17d22e5e9d4..337d73ebe89 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.dts @@ -187,6 +187,16 @@ zephyr_udc0: &usb { status = "okay"; }; +&fdcan2 { + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>, + <&rcc STM32_SRC_PLL_Q FDCAN_SEL(1)>; + pinctrl-0 = <&fdcan2_rx_pb0 &fdcan2_tx_pb1>; + pinctrl-names = "default"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + status = "okay"; +}; + &flash0 { partitions { compatible = "fixed-partitions"; @@ -214,7 +224,7 @@ zephyr_udc0: &usb { }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml index bc267274401..e2389efdbb7 100644 --- a/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml +++ b/boards/arm/nucleo_g0b1re/nucleo_g0b1re.yaml @@ -14,6 +14,7 @@ supported: - arduino_i2c - arduino_spi - arduino_serial + - can - uart - gpio - i2c diff --git a/boards/arm/nucleo_g431rb/doc/index.rst b/boards/arm/nucleo_g431rb/doc/index.rst index 7d60b8c5426..0359a29b231 100644 --- a/boards/arm/nucleo_g431rb/doc/index.rst +++ b/boards/arm/nucleo_g431rb/doc/index.rst @@ -134,7 +134,7 @@ Connections and IOs Nucleo G431RB Board has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32G4 Nucleo-64 board User Manual`_. +For more details please refer to `STM32G4 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_g431rb/nucleo_g431rb.dts b/boards/arm/nucleo_g431rb/nucleo_g431rb.dts index 0bdf2b7d301..9303087c1dc 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb.dts +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb.dts @@ -148,7 +148,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig b/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig index 25dcaf3dfb7..92c2363d2d8 100644 --- a/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig +++ b/boards/arm/nucleo_g431rb/nucleo_g431rb_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_g474re/doc/index.rst b/boards/arm/nucleo_g474re/doc/index.rst index 437668ed42e..87fca388905 100644 --- a/boards/arm/nucleo_g474re/doc/index.rst +++ b/boards/arm/nucleo_g474re/doc/index.rst @@ -127,6 +127,8 @@ The Zephyr nucleo_g474re board configuration supports the following hardware fea +-----------+------------+-------------------------------------+ | die-temp | on-chip | die temperature sensor | +-----------+------------+-------------------------------------+ +| FDCAN1 | on-chip | CAN controller | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on this Zephyr port. @@ -140,7 +142,7 @@ Connections and IOs Nucleo G474RE Board has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32G4 Nucleo-64 board User Manual`_. +For more details please refer to `STM32G4 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -171,6 +173,8 @@ Default Zephyr Peripheral Mapping: - LD2 : PA5 - ADC1_IN1 : PA0 - DAC1_OUT1 : PA4 +- FDCAN1_RX: PA11 +- FDCAN1_TX: PA12 System Clock ------------ diff --git a/boards/arm/nucleo_g474re/nucleo_g474re.dts b/boards/arm/nucleo_g474re/nucleo_g474re.dts index 33c071d0adb..8a87f6e0d01 100644 --- a/boards/arm/nucleo_g474re/nucleo_g474re.dts +++ b/boards/arm/nucleo_g474re/nucleo_g474re.dts @@ -152,7 +152,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_h563zi/doc/index.rst b/boards/arm/nucleo_h563zi/doc/index.rst index 9b6f880ac4c..7d1ac5c5b5a 100644 --- a/boards/arm/nucleo_h563zi/doc/index.rst +++ b/boards/arm/nucleo_h563zi/doc/index.rst @@ -206,7 +206,7 @@ Connections and IOs Nucleo H563ZI Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H5 Nucleo-144 board User Manual`_. +For more details please refer to `STM32H5 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h723zg/Kconfig.defconfig b/boards/arm/nucleo_h723zg/Kconfig.defconfig index 7b5c327e97d..26f4491a7ad 100644 --- a/boards/arm/nucleo_h723zg/Kconfig.defconfig +++ b/boards/arm/nucleo_h723zg/Kconfig.defconfig @@ -15,4 +15,8 @@ config NET_L2_ETHERNET endif # NETWORKING +config USB_DC_HAS_HS_SUPPORT + default y + depends on USB_DC_STM32 + endif # BOARD_NUCLEO_H723ZG diff --git a/boards/arm/nucleo_h723zg/doc/index.rst b/boards/arm/nucleo_h723zg/doc/index.rst index 09b71835f67..44a87bb5129 100644 --- a/boards/arm/nucleo_h723zg/doc/index.rst +++ b/boards/arm/nucleo_h723zg/doc/index.rst @@ -121,7 +121,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration per core can be found in the defconfig files: ``boards/arm/nucleo_h723zg/nucleo_h723zg_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h743zi/doc/index.rst b/boards/arm/nucleo_h743zi/doc/index.rst index c401e3ab098..e6cb6e242cd 100644 --- a/boards/arm/nucleo_h743zi/doc/index.rst +++ b/boards/arm/nucleo_h743zi/doc/index.rst @@ -135,7 +135,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h743zi/nucleo_h743zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h743zi/nucleo_h743zi.dts b/boards/arm/nucleo_h743zi/nucleo_h743zi.dts index f93964479e2..ad88d87f059 100644 --- a/boards/arm/nucleo_h743zi/nucleo_h743zi.dts +++ b/boards/arm/nucleo_h743zi/nucleo_h743zi.dts @@ -170,6 +170,8 @@ zephyr_udc0: &usbotg_fs { &fdcan1 { pinctrl-0 = <&fdcan1_rx_pd0 &fdcan1_tx_pd1>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; bus-speed = <125000>; bus-speed-data = <1000000>; status = "okay"; diff --git a/boards/arm/nucleo_h745zi_q/doc/index.rst b/boards/arm/nucleo_h745zi_q/doc/index.rst index 60f86f2ab81..36c4b80bc58 100644 --- a/boards/arm/nucleo_h745zi_q/doc/index.rst +++ b/boards/arm/nucleo_h745zi_q/doc/index.rst @@ -122,7 +122,7 @@ The default configuration per core can be found in the defconfig files: ``boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7_defconfig`` and ``boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m4_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi index 93d42155499..b9a0407bf47 100644 --- a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi +++ b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q.dtsi @@ -39,3 +39,7 @@ d2ppre2 = <2>; d3ppre = <2>; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts index d63b4ff8a58..184232867bb 100644 --- a/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts +++ b/boards/arm/nucleo_h745zi_q/nucleo_h745zi_q_m7.dts @@ -6,7 +6,6 @@ /dts-v1/; #include -#include #include "nucleo_h745zi_q.dtsi" /* @@ -63,7 +62,7 @@ div-m = <1>; mul-n = <120>; div-p = <2>; - div-q = <2>; + div-q = <8>; div-r = <2>; clocks = <&clk_hse>; status = "okay"; diff --git a/boards/arm/nucleo_h753zi/doc/index.rst b/boards/arm/nucleo_h753zi/doc/index.rst index 058cbc67c9f..eab88c9952a 100644 --- a/boards/arm/nucleo_h753zi/doc/index.rst +++ b/boards/arm/nucleo_h753zi/doc/index.rst @@ -129,7 +129,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h753zi/nucleo_h753zi_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig b/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig index 922423e3669..ec43ace7dcb 100644 --- a/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig +++ b/boards/arm/nucleo_h7a3zi_q/Kconfig.defconfig @@ -8,4 +8,8 @@ if BOARD_NUCLEO_H7A3ZI_Q config BOARD default "nucleo_h7a3zi_q" +config USB_DC_HAS_HS_SUPPORT + default y + depends on USB_DC_STM32 + endif # BOARD_NUCLEO_H7A3ZI_Q diff --git a/boards/arm/nucleo_h7a3zi_q/doc/index.rst b/boards/arm/nucleo_h7a3zi_q/doc/index.rst index 7b107733510..1144f13e731 100644 --- a/boards/arm/nucleo_h7a3zi_q/doc/index.rst +++ b/boards/arm/nucleo_h7a3zi_q/doc/index.rst @@ -117,7 +117,7 @@ Other hardware features are not yet supported on this Zephyr port. The default configuration can be found in the defconfig file: ``boards/arm/nucleo_h7a3zi_q/nucleo_h7a3zi_q_defconfig`` -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l011k4/doc/index.rst b/boards/arm/nucleo_l011k4/doc/index.rst index 9b815ede4de..04fc12c53f3 100644 --- a/boards/arm/nucleo_l011k4/doc/index.rst +++ b/boards/arm/nucleo_l011k4/doc/index.rst @@ -113,7 +113,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Arduino SPI) - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l031k6/doc/index.rst b/boards/arm/nucleo_l031k6/doc/index.rst index eb1f6e25387..da0fcaa271e 100644 --- a/boards/arm/nucleo_l031k6/doc/index.rst +++ b/boards/arm/nucleo_l031k6/doc/index.rst @@ -106,7 +106,7 @@ Default Zephyr Peripheral Mapping: - SPI1 SCK/MISO/MOSI : PA5/PA6/PA7 (Arduino SPI) - LD2 : PB3 -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l053r8/doc/index.rst b/boards/arm/nucleo_l053r8/doc/index.rst index 33f84b14e6c..ba448176fca 100644 --- a/boards/arm/nucleo_l053r8/doc/index.rst +++ b/boards/arm/nucleo_l053r8/doc/index.rst @@ -122,7 +122,7 @@ Default Zephyr Peripheral Mapping: - USER_PB : PC13 - LD2 : PA5 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l073rz/doc/index.rst b/boards/arm/nucleo_l073rz/doc/index.rst index de662f5b14f..a828a5b70eb 100644 --- a/boards/arm/nucleo_l073rz/doc/index.rst +++ b/boards/arm/nucleo_l073rz/doc/index.rst @@ -136,7 +136,7 @@ Default Zephyr Peripheral Mapping: - DAC : PA4 - PWM_2_CH1 : PA5 (might conflict with SPI1) -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts index b5cf07203a6..93571670b7d 100644 --- a/boards/arm/nucleo_l073rz/nucleo_l073rz.dts +++ b/boards/arm/nucleo_l073rz/nucleo_l073rz.dts @@ -89,7 +89,11 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { + /* + * LSI freq is 37KHz but stm32_lptim driver is using 32000Hz + * resulting in time running 1.13 faster than reality + */ clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_l152re/doc/index.rst b/boards/arm/nucleo_l152re/doc/index.rst index 2595144e730..020beb6583f 100644 --- a/boards/arm/nucleo_l152re/doc/index.rst +++ b/boards/arm/nucleo_l152re/doc/index.rst @@ -130,7 +130,7 @@ Default Zephyr Peripheral Mapping: - DAC : PA4 - PWM_3_CH1 : PA6 -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/nucleo_l412rb_p/doc/index.rst b/boards/arm/nucleo_l412rb_p/doc/index.rst index 007ae04379d..3485d01cba1 100644 --- a/boards/arm/nucleo_l412rb_p/doc/index.rst +++ b/boards/arm/nucleo_l412rb_p/doc/index.rst @@ -176,7 +176,7 @@ Available pins: :align: center :alt: Nucleo L412RB-P -For mode details please refer to `ST Nucleo L412RB-P User Manual`_. +For more details please refer to `ST Nucleo L412RB-P User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l432kc/doc/index.rst b/boards/arm/nucleo_l432kc/doc/index.rst index 94d6f6f20f0..b054c472f22 100644 --- a/boards/arm/nucleo_l432kc/doc/index.rst +++ b/boards/arm/nucleo_l432kc/doc/index.rst @@ -137,7 +137,7 @@ Available pins: :align: center :alt: Nucleo L432KC Arduino connectors -For mode details please refer to `STM32 Nucleo-32 board User Manual`_. +For more details please refer to `STM32 Nucleo-32 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l433rc_p/doc/index.rst b/boards/arm/nucleo_l433rc_p/doc/index.rst index da2660417c0..6e86a44cee0 100644 --- a/boards/arm/nucleo_l433rc_p/doc/index.rst +++ b/boards/arm/nucleo_l433rc_p/doc/index.rst @@ -140,7 +140,7 @@ Available pins: :align: center :alt: Nucleo L433RC-P -For mode details please refer to `ST Nucleo L433RC-P User Manual`_. +For more details please refer to `ST Nucleo L433RC-P User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l476rg/doc/index.rst b/boards/arm/nucleo_l476rg/doc/index.rst index cfbf949df57..10dff333643 100644 --- a/boards/arm/nucleo_l476rg/doc/index.rst +++ b/boards/arm/nucleo_l476rg/doc/index.rst @@ -145,7 +145,7 @@ Available pins: :align: center :alt: Nucleo L476RG Morpho connectors -For mode details please refer to `STM32 Nucleo-64 board User Manual`_. +For more details please refer to `STM32 Nucleo-64 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts index b39a87345e5..573c121dfd1 100644 --- a/boards/arm/nucleo_l476rg/nucleo_l476rg.dts +++ b/boards/arm/nucleo_l476rg/nucleo_l476rg.dts @@ -75,7 +75,7 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/nucleo_l496zg/doc/index.rst b/boards/arm/nucleo_l496zg/doc/index.rst index 43f6e1fdb4c..49d011b8846 100644 --- a/boards/arm/nucleo_l496zg/doc/index.rst +++ b/boards/arm/nucleo_l496zg/doc/index.rst @@ -142,7 +142,7 @@ Connections and IOs Nucleo L496ZG Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l4a6zg/doc/index.rst b/boards/arm/nucleo_l4a6zg/doc/index.rst index 79c7caca7bb..7e61d9f8907 100644 --- a/boards/arm/nucleo_l4a6zg/doc/index.rst +++ b/boards/arm/nucleo_l4a6zg/doc/index.rst @@ -147,7 +147,7 @@ Connections and IOs Nucleo L4A6ZG Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/nucleo_l4r5zi/board.cmake b/boards/arm/nucleo_l4r5zi/board.cmake index 037f4a5fd14..0def9a56111 100644 --- a/boards/arm/nucleo_l4r5zi/board.cmake +++ b/boards/arm/nucleo_l4r5zi/board.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") board_runner_args(jlink "--device=STM32L4R5ZI" "--speed=4000") +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/nucleo_l4r5zi/doc/index.rst b/boards/arm/nucleo_l4r5zi/doc/index.rst index 9adb38a2c59..b132403ce2a 100644 --- a/boards/arm/nucleo_l4r5zi/doc/index.rst +++ b/boards/arm/nucleo_l4r5zi/doc/index.rst @@ -160,7 +160,7 @@ Available pins: :align: center :alt: Nucleo L4R5ZI Arduino connectors -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -219,9 +219,23 @@ Ethernet over USB is configured as the default network interface (EEM) Programming and Debugging ************************* +The NUCLEO-L4R5ZI board includes a ST-LINK/V2 embedded debug tool interface. + +The board is configured to be flashed using west `STM32CubeProgrammer`_ runner, +so its installation is required to be able to flash the board. + +Alternatively, openocd (provided in Zephyr SDK) or JLink can also be used to +flash the board using the ``--runner`` (or ``-r``) option: + +.. code-block:: console + + $ west flash --runner openocd + $ west flash --runner jlink + Connect the Nucleo L4R5ZI to your host computer using the USB port. -Then build and flash an application. Here is an example for the -:ref:`hello_world` application. +Then build and flash an application. + +Here is an example for the :ref:`hello_world` application. Run a serial host program to connect with your Nucleo board: @@ -256,3 +270,6 @@ You should see the following message on the console: .. _STM32 ST-LINK utility: https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-link004.html + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html diff --git a/boards/arm/nucleo_l552ze_q/CMakeLists.txt b/boards/arm/nucleo_l552ze_q/CMakeLists.txt index d170d283e99..260ecca2707 100644 --- a/boards/arm/nucleo_l552ze_q/CMakeLists.txt +++ b/boards/arm/nucleo_l552ze_q/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst index 51675477af4..65a2df527a9 100644 --- a/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst +++ b/boards/arm/nucleo_l552ze_q/doc/nucleol552ze_q.rst @@ -234,7 +234,7 @@ Available pins: :align: center :alt: Nucleo L552ZE Q Zio right connector -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -338,7 +338,7 @@ can be generated using ``nucleo_l552ze_q_ns`` as build target. $ west build -b nucleo_l552ze_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/nucleo_u575zi_q/doc/index.rst b/boards/arm/nucleo_u575zi_q/doc/index.rst index 0de2c364ecf..bbb547130d8 100644 --- a/boards/arm/nucleo_u575zi_q/doc/index.rst +++ b/boards/arm/nucleo_u575zi_q/doc/index.rst @@ -185,7 +185,7 @@ Connections and IOs Nucleo U575ZI Q Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -308,7 +308,7 @@ can be generated using ``nucleo_u575zi_q_ns`` as build target. $ west build -b nucleo_u575zi_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt b/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt index c79a4b7b4e7..7c2da293e20 100644 --- a/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt +++ b/boards/arm/nucleo_u5a5zj_q/CMakeLists.txt @@ -9,6 +9,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/nucleo_u5a5zj_q/doc/index.rst b/boards/arm/nucleo_u5a5zj_q/doc/index.rst index f877be5c168..f6e96c63517 100644 --- a/boards/arm/nucleo_u5a5zj_q/doc/index.rst +++ b/boards/arm/nucleo_u5a5zj_q/doc/index.rst @@ -219,7 +219,7 @@ Connections and IOs Nucleo U5A5ZJ Q Board has 10 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32 Nucleo-144 board User Manual`_. +For more details please refer to `STM32 Nucleo-144 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -342,7 +342,7 @@ can be generated using ``nucleo_u5a5zj_q_ns`` as build target. $ west build -b nucleo_u5a5zj_q_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/nucleo_wb55rg/board.cmake b/boards/arm/nucleo_wb55rg/board.cmake index 83fd477865f..75762ef577e 100644 --- a/boards/arm/nucleo_wb55rg/board.cmake +++ b/boards/arm/nucleo_wb55rg/board.cmake @@ -2,6 +2,6 @@ board_runner_args(pyocd "--target=stm32wb55rgvx") board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) -include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) diff --git a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts index eed2cef9368..21806ca24af 100644 --- a/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts +++ b/boards/arm/nucleo_wb55rg/nucleo_wb55rg.dts @@ -186,7 +186,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig b/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig index 88f9da2ff18..9fdd732848e 100644 --- a/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig +++ b/boards/arm/nucleo_wb55rg/nucleo_wb55rg_defconfig @@ -22,6 +22,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_wba52cg/board.cmake b/boards/arm/nucleo_wba52cg/board.cmake index 50f543d4e6a..27c19f19b00 100644 --- a/boards/arm/nucleo_wba52cg/board.cmake +++ b/boards/arm/nucleo_wba52cg/board.cmake @@ -1,3 +1,7 @@ board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") +set(OPENOCD "/local/mcu/tools/openocd/src/openocd" CACHE FILEPATH "" FORCE) +set(OPENOCD_DEFAULT_PATH /local/mcu/tools/openocd/tcl) + include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts index df2707f4eeb..67bc009bd8a 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg.dts @@ -59,6 +59,10 @@ status = "okay"; }; +&clk_hsi { + status = "okay"; +}; + &pll1 { div-m = <8>; mul-n = <48>; @@ -125,7 +129,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; diff --git a/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig index ffadf13e845..9b917b0fc69 100644 --- a/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig +++ b/boards/arm/nucleo_wba52cg/nucleo_wba52cg_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/nucleo_wba52cg/support/openocd.cfg b/boards/arm/nucleo_wba52cg/support/openocd.cfg index 10647e20ad8..7c785bec412 100644 --- a/boards/arm/nucleo_wba52cg/support/openocd.cfg +++ b/boards/arm/nucleo_wba52cg/support/openocd.cfg @@ -22,5 +22,3 @@ set CLOCK_FREQ 8000 reset_config srst_only srst_nogate source [find target/stm32wbax.cfg] - -gdb_memory_map disable diff --git a/boards/arm/nucleo_wba55cg/Kconfig.board b/boards/arm/nucleo_wba55cg/Kconfig.board new file mode 100644 index 00000000000..44bb0e5dcd8 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WBA55CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NUCLEO_WBA55CG + bool "Nucleo WBA55CG Development Board" + depends on SOC_STM32WBA55XX diff --git a/boards/arm/nucleo_wba55cg/Kconfig.defconfig b/boards/arm/nucleo_wba55cg/Kconfig.defconfig new file mode 100644 index 00000000000..ed24776ee4e --- /dev/null +++ b/boards/arm/nucleo_wba55cg/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WBA52CG Nucleo board configuration + +# Copyright (c) 2023 STMicroelectronics + +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NUCLEO_WBA55CG + +config BOARD + default "nucleo_wba55cg" + +config SPI_STM32_INTERRUPT + default y + depends on SPI + +endif # BOARD_NUCLEO_WBA55CG diff --git a/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi b/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..619cebea62a --- /dev/null +++ b/boards/arm/nucleo_wba55cg/arduino_r3_connector.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioa 7 0>, /* A0 */ + <1 0 &gpioa 6 0>, /* A1 */ + <2 0 &gpioa 2 0>, /* A2 */ + <3 0 &gpioa 1 0>, /* A3 */ + <4 0 &gpioa 5 0>, /* A4 */ + <5 0 &gpioa 0 0>, /* A5 */ + <6 0 &gpioa 10 0>, /* D0 */ + <7 0 &gpiob 5 0>, /* D1 */ + <8 0 &gpiob 7 0>, /* D2 */ + <9 0 &gpiob 6 0>, /* D3 */ + <10 0 &gpiob 13 0>, /* D4 */ + <11 0 &gpiob 14 0>, /* D5 */ + <12 0 &gpiob 0 0>, /* D6 */ + <13 0 &gpiob 9 0>, /* D7 */ + <14 0 &gpiob 15 0>, /* D8 */ + <15 0 &gpioa 9 0>, /* D9 */ + <16 0 &gpioa 12 0>, /* D10 */ + <17 0 &gpioa 15 0>, /* D11 */ + <18 0 &gpiob 3 0>, /* D12 */ + <19 0 &gpiob 4 0>, /* D13 */ + <20 0 &gpiob 1 0>, /* D14 */ + <21 0 &gpiob 2 0>; /* D15 */ + }; +}; + +arduino_i2c: &i2c1 {}; +arduino_spi: &spi1 {}; diff --git a/boards/arm/nucleo_wba55cg/board.cmake b/boards/arm/nucleo_wba55cg/board.cmake new file mode 100644 index 00000000000..50f543d4e6a --- /dev/null +++ b/boards/arm/nucleo_wba55cg/board.cmake @@ -0,0 +1,3 @@ +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) diff --git a/boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg b/boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg new file mode 100644 index 00000000000..67c7d351e99 Binary files /dev/null and b/boards/arm/nucleo_wba55cg/doc/img/nucleowba55cg.jpg differ diff --git a/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst new file mode 100644 index 00000000000..2ea660da1f1 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/doc/nucleo_wba55cg.rst @@ -0,0 +1,307 @@ +.. _nucleo_wba55cg_board: + +ST Nucleo WBA55CG +################# + +Overview +******** + +NUCLEO-WBA55CG is a Bluetooth® Low Energy wireless and ultra-low-power board +embedding a powerful and ultra-low-power radio compliant with the Bluetooth® +Low Energy SIG specification v5.3. + +The ARDUINO® Uno V3 connectivity support and the ST morpho headers allow the +easy expansion of the functionality of the STM32 Nucleo open development +platform with a wide choice of specialized shields. + +- Ultra-low-power wireless STM32WBA55CG microcontroller based on the Arm® + Cortex®‑M33 core, featuring 1 Mbyte of flash memory and 128 Kbytes of SRAM in + a UFQFPN48 package + +- MCU RF board (MB1863): + + - 2.4 GHz RF transceiver supporting Bluetooth® specification v5.3 + - Arm® Cortex® M33 CPU with TrustZone®, MPU, DSP, and FPU + - Integrated PCB antenna + +- Three user LEDs +- Three user and one reset push-buttons + +- Board connectors: + + - USB Micro-B + - ARDUINO® Uno V3 expansion connector + - ST morpho headers for full access to all STM32 I/Os + +- Flexible power-supply options: ST-LINK USB VBUS or external sources +- On-board STLINK-V3MODS debugger/programmer with USB re-enumeration capability: + mass storage, Virtual COM port, and debug port + +.. image:: img/nucleowba55cg.jpg + :align: center + :alt: Nucleo WBA55CG + +Hardware +******** + +The STM32WBA55xx multiprotocol wireless and ultralow power devices embed a +powerful and ultralow power radio compliant with the Bluetooth® SIG Low Energy +specification 5.3. They contain a high-performance Arm Cortex-M33 32-bit RISC +core. They operate at a frequency of up to 100 MHz. + +- Includes ST state-of-the-art patented technology + +- Ultra low power radio: + + - 2.4 GHz radio + - RF transceiver supporting Bluetooth® Low Energy 5.3 specification + - Proprietary protocols + - RX sensitivity: -96 dBm (Bluetooth® Low Energy at 1 Mbps) + - Programmable output power, up to +10 dBm with 1 dB steps + - Integrated balun to reduce BOM + - Suitable for systems requiring compliance with radio frequency regulations + ETSI EN 300 328, EN 300 440, FCC CFR47 Part 15 and ARIB STD-T66 + +- Ultra low power platform with FlexPowerControl: + + - 1.71 to 3.6 V power supply + - - 40 °C to 85 °C temperature range + - Autonomous peripherals with DMA, functional down to Stop 1 mode + - 140 nA Standby mode (16 wake-up pins) + - 200 nA Standby mode with RTC + - 2.4 µA Standby mode with 64 KB SRAM + - 16.3 µA Stop mode with 64 KB SRAM + - 45 µA/MHz Run mode at 3.3 V + - Radio: Rx 7.4 mA / Tx at 0 dBm 10.6 mA + +- Core: Arm® 32-bit Cortex®-M33 CPU with TrustZone®, MPU, DSP, and FPU +- ART Accelerator™: 8-Kbyte instruction cache allowing 0-wait-state execution + from flash memory (frequency up to 100 MHz, 150 DMIPS) +- Power management: embedded regulator LDO supporting voltage scaling + +- Benchmarks: + + - 1.5 DMIPS/MHz (Drystone 2.1) + - 407 CoreMark® (4.07 CoreMark/MHz) + +- Clock sources: + + - 32 MHz crystal oscillator + - 32 kHz crystal oscillator (LSE) + - Internal low-power 32 kHz (±5%) RC + - Internal 16 MHz factory trimmed RC (±1%) + - PLL for system clock and ADC + +- Memories: + + - 1 MB flash memory with ECC, including 256 Kbytes with 100 cycles + - 128 KB SRAM, including 64 KB with parity check + - 512-byte (32 rows) OTP + +- Rich analog peripherals (independent supply): + + - 12-bit ADC 2.5 Msps with hardware oversampling + +- Communication peripherals: + + - Three UARTs (ISO 7816, IrDA, modem) + - Two SPIs + - Two I2C Fm+ (1 Mbit/s), SMBus/PMBus® + +- System peripherals: + + - Touch sensing controller, up to 20 sensors, supporting touch key, linear, + rotary touch sensors + - One 16-bit, advanced motor control timer + - Three 16-bit timers + - One 32-bit timer + - Two low-power 16-bit timers (available in Stop mode) + - Two Systick timers + - Two watchdogs + - 8-channel DMA controller, functional in Stop mode + +- Security and cryptography: + + - Arm® TrustZone® and securable I/Os, memories, and peripherals + - Flexible life cycle scheme with RDP and password protected debug + - Root of trust thanks to unique boot entry and secure hide protection area (HDP) + - SFI (secure firmware installation) thanks to embedded RSS (root secure services) + - Secure data storage with root hardware unique key (RHUK) + - Secure firmware upgrade support with TF-M + - Two AES co-processors, including one with DPA resistance + - Public key accelerator, DPA resistant + - HASH hardware accelerator + - True random number generator, NIST SP800-90B compliant + - 96-bit unique ID + - Active tampers + - CRC calculation unit + +- Up to 35 I/Os (most of them 5 V-tolerant) with interrupt capability + +- Development support: + + - Serial wire debug (SWD), JTAG + +- ECOPACK2 compliant package + +More information about STM32WBA series can be found here: + +- `STM32WBA Series on www.st.com`_ + +Supported Features +================== + +The Zephyr nucleo_wba55cg board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| RNG | on-chip | True Random number generator | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | Bluetooth Low Energy | ++-----------+------------+-------------------------------------+ + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig file: +``boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig`` + +Bluetooh support +---------------- + +BLE support is enabled on nucleo_wba55cg. To build a zephyr sample using this board +you first need to install Bluetooth Controller libraries available in Zephyr as binary +blobs. + +To fetch Binary Blobs: + +.. code-block:: console + + west blobs fetch stm32 + +Connections and IOs +=================== + +Nucleo WBA55CG Board has 4 GPIO controllers. These controllers are responsible for pin muxing, +input/output, pull-up, etc. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- USART_1 TX/RX : PB12/PA8 +- I2C_1_SCL : PB2 +- I2C_1_SDA : PB1 +- USER_PB : PC13 +- LD1 : PB4 +- SPI_1_NSS : PA12 (arduino_spi) +- SPI_1_SCK : PB4 (arduino_spi) +- SPI_1_MISO : PB3 (arduino_spi) +- SPI_1_MOSI : PA15 (arduino_spi) + +System Clock +------------ + +Nucleo WBA55CG System Clock could be driven by internal or external oscillator, +as well as main PLL clock. By default System clock is driven by HSE+PLL clock at 100MHz. + +Serial Port +----------- + +Nucleo WBA55CG board has 1 U(S)ARTs. The Zephyr console output is assigned to USART1. +Default settings are 115500 8N1. + + +Programming and Debugging +************************* + +Nucleo WBA55CG board includes an ST-LINK/V3 embedded debug tool interface. +It could be used for flash and debug using either OpenOCD or STM32Cube ecosystem tools. + +OpenOCD Support +=============== + +For now, openocd support is available only on upstream OpenOCD. You can check +`OpenOCD official Github mirror`_. +In order to use it, you should clone and compile it following usual README +guidelines. +Once it is done, you can set the OPENOCD and OPENOCD_DEFAULT_PATH variables in +:zephyr_file:`boards/arm/nucleo_wba55cg/board.cmake` to point the build +to the paths of the OpenOCD binary and its scripts, before +including the common openocd.board.cmake file: + + .. code-block:: none + + set(OPENOCD "/src/openocd" CACHE FILEPATH "" FORCE) + set(OPENOCD_DEFAULT_PATH /tcl) + include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) + +Flashing +======== + +STM32CubeProgrammer is configured as flashing tool by default. +If available OpenOCD could be used. Same process applies with both tools. + +Flashing an application to Nucleo WBA55CG +----------------------------------------- + +Here is an example for the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: nucleo_wba55cg + :goals: build flash + +You will see the LED blinking every second. + +Debugging +========= + +Debugging using OpenOCD +----------------------- + +You can debug an application in the usual way using OpenOCD. Here is an example for the +:zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: nucleo_wba55cg + :maybe-skip-config: + :goals: debug + +Debugging using STM32CubeIDE +---------------------------- + +You can debug an application using a STM32WBA compatible version of STM32CubeIDE. +For that: +- Create an empty STM32WBA project by going to File > New > STM32 project +- Select your MCU, click Next, and select an Empty project. +- Right click on your project name, select Debug as > Debug configurations +- In the new window, create a new target in STM32 Cortex-M C/C++ Application +- Select the new target and enter the path to zephyr.elf file in the C/C++ Application field +- Check Disable auto build +- Run debug + +.. _STM32WBA Series on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wba-series.html + +.. _OpenOCD official Github mirror: + https://github.com/openocd-org/openocd/commit/870769b0ba9f4dae6ada9d8b1a40d75bd83aaa06 diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts new file mode 100644 index 00000000000..3a2ad07c1b0 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +/* Todo: Once available, use wba55 dedicated pinctrl.dtsi */ +#include +#include "arduino_r3_connector.dtsi" +#include + +/ { + model = "STMicroelectronics STM32WBA55CG-NUCLEO board"; + compatible = "st,stm32wba55cg-nucleo"; + + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds: leds { + compatible = "gpio-leds"; + blue_led_1: led_1 { + gpios = <&gpiob 4 GPIO_ACTIVE_LOW>; + label = "User LD1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &blue_led_1; + sw0 = &user_button; + }; +}; + +&clk_lsi { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hse { + status = "okay"; + hse-div2; +}; + +&clk_hsi { + status = "okay"; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + ahb-prescaler = <1>; + ahb5-prescaler = <2>; + apb1-prescaler = <1>; + apb2-prescaler = <2>; + apb7-prescaler = <1>; +}; + +&iwdg { + status = "okay"; +}; + +&rtc { + status = "okay"; + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00200000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + prescaler = <32768>; +}; + +&usart1 { + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; + pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; + pinctrl-1 = <&analog_pb12 &analog_pa8>; + pinctrl-names = "default", "sleep"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pb5 &lpuart1_rx_pa10>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&spi1 { + pinctrl-0 = <&spi1_nss_pa12 &spi1_sck_pb4 + &spi1_miso_pb3 &spi1_mosi_pa15>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_scl_pb2 &i2c1_sda_pb1>; + pinctrl-names = "default"; + status = "okay"; + clock-frequency = ; +}; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +stm32_lp_tick_source: &lptim1 { + clocks = <&rcc STM32_CLOCK_BUS_APB7 0x00000800>, + <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; + status = "okay"; +}; + +&rng { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Last 16K of flash: Min 2 sectors */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 DT_SIZE_K(16)>; + }; + + }; +}; diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml new file mode 100644 index 00000000000..0f435e29c75 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.yaml @@ -0,0 +1,21 @@ +identifier: nucleo_wba55cg +name: ST Nucleo WBA55CG +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - i2c + - spi + - adc + - watchdog + - rng + - arduino_gpio + - arduino_i2c + - arduino_spi + - counter +ram: 128 +flash: 1024 +vendor: st diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig new file mode 100644 index 00000000000..2c523d88019 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg_defconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 STMicroelectronics + +CONFIG_SOC_SERIES_STM32WBAX=y +CONFIG_SOC_STM32WBA55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable clock +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y + +# Enable the internal SMPS regulator +CONFIG_POWER_SUPPLY_DIRECT_SMPS=y diff --git a/boards/arm/nucleo_wba55cg/support/openocd.cfg b/boards/arm/nucleo_wba55cg/support/openocd.cfg new file mode 100644 index 00000000000..247de974f39 --- /dev/null +++ b/boards/arm/nucleo_wba55cg/support/openocd.cfg @@ -0,0 +1,26 @@ +# Note: Using OpenOCD using nucloe_wba52cg requires using openocd fork. +# See board documentation for more information + +source [find interface/stlink-dap.cfg] + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 8000 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate + +source [find target/stm32wbax.cfg] + +gdb_memory_map disable diff --git a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts index deff3a96cdc..e83f45452dd 100644 --- a/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts +++ b/boards/arm/nucleo_wl55jc/nucleo_wl55jc.dts @@ -20,7 +20,7 @@ zephyr,shell-uart = &lpuart1; zephyr,sram = &sram0; zephyr,flash = &flash0; - zephyr,code-partition = &flash0; + zephyr,code-partition = &slot0_partition; }; leds: leds { @@ -75,7 +75,7 @@ status = "okay"; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; @@ -191,6 +191,20 @@ #address-cells = <1>; #size-cells = <1>; + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(32)>; + read-only; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 DT_SIZE_K(104)>; + }; + slot1_partition: partition@22000 { + label = "image-1"; + reg = <0x00022000 DT_SIZE_K(104)>; + }; + /* * Set 16kB of storage (8x2kB pages) at the end of the 256kB of * flash. diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi index b6b8f3eb508..48d1bf58b81 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467-pinctrl.dtsi @@ -49,4 +49,14 @@ ; }; }; + + /* USBD multi-function pins for VBUS, D+, D-, and ID pins */ + usbd_default: usbd_default { + group0 { + pinmux = , + , + , + ; + }; + }; }; diff --git a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts index da3350d9494..28db9b9265a 100644 --- a/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts +++ b/boards/arm/numaker_pfm_m467/numaker_pfm_m467.dts @@ -123,3 +123,10 @@ pinctrl-names = "default"; status = "okay"; }; + +/* On enabled, 'core-clock', as above, is required to to be 192MHz. */ +zephyr_udc0: &usbd { + pinctrl-0 = <&usbd_default>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts b/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts index b24649edb71..6d26b7c3f19 100644 --- a/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts +++ b/boards/arm/olimex_lora_stm32wl_devkit/olimex_lora_stm32wl_devkit.dts @@ -45,7 +45,7 @@ }; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSI LPTIM1_SEL(1)>; status = "okay"; diff --git a/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi b/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi index de1bd72e6d0..d8e520eda35 100644 --- a/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi +++ b/boards/arm/pan1770_evb/pan1770_evb-pinctrl.dtsi @@ -30,18 +30,18 @@ uart1_default: uart1_default { group1 { - psels = ; + psels = ; bias-pull-up; }; group2 { - psels = ; + psels = ; }; }; uart1_sleep: uart1_sleep { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; diff --git a/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi b/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi index 4643c740884..03ebb8bf8e2 100644 --- a/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi +++ b/boards/arm/pan1780_evb/pan1780_evb-pinctrl.dtsi @@ -29,18 +29,18 @@ uart1_default: uart1_default { group1 { - psels = ; + psels = ; bias-pull-up; }; group2 { - psels = ; + psels = ; }; }; uart1_sleep: uart1_sleep { group1 { - psels = , - ; + psels = , + ; low-power-enable; }; }; diff --git a/boards/arm/pan1783/CMakeLists.txt b/boards/arm/pan1783/CMakeLists.txt new file mode 100644 index 00000000000..a582b3cc819 --- /dev/null +++ b/boards/arm/pan1783/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +if((CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) + zephyr_library() + zephyr_library_sources(pan1783_cpunet_reset.c) +endif() diff --git a/boards/arm/pan1783/Kconfig b/boards/arm/pan1783/Kconfig new file mode 100644 index 00000000000..e4f58398459 --- /dev/null +++ b/boards/arm/pan1783/Kconfig @@ -0,0 +1,56 @@ +# PAN1783 EVB board configuration + +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP + +config BOARD_ENABLE_DCDC_APP + bool "Application MCU DCDC converter" + select SOC_DCDC_NRF53X_APP + default y + +config BOARD_ENABLE_DCDC_NET + bool "Network MCU DCDC converter" + select SOC_DCDC_NRF53X_NET + default y + +config BOARD_ENABLE_DCDC_HV + bool "High Voltage DCDC converter" + select SOC_DCDC_NRF53X_HV + default y + +config BOARD_ENABLE_CPUNET + bool "NRF53 Network MCU" + select SOC_NRF_GPIO_FORWARDER_FOR_NRF5340 if \ + $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GPIO_FORWARDER)) + help + This option enables releasing the Network 'force off' signal, which + as a consequence will power up the Network MCU during system boot. + Additionally, the option allocates GPIO pins that will be used by UARTE + of the Network MCU. + default y if (BT || NRF_802154_SER_HOST) + +config DOMAIN_CPUNET_BOARD + string + default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUAPP + default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUAPP + default "pan1783a_pa_evb_cpunet" if BOARD_PAN1783A_PA_EVB_CPUAPP + depends on BOARD_ENABLE_CPUNET + help + The board which will be used for CPUNET domain when creating a multi + image application where one or more images should be located on + another board. For example hci_ipc on the nRF5340_cpunet for + Bluetooth applications. + +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP + +config DOMAIN_CPUAPP_BOARD + string + default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUNET + default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUNET + default "pan1783a_pa_evb_cpuapp" if BOARD_PAN1783A_PA_EVB_CPUNET + help + The board which will be used for CPUAPP domain when creating a multi + image application where one or more images should be located on + another board. diff --git a/boards/arm/pan1783/Kconfig.board b/boards/arm/pan1783/Kconfig.board new file mode 100644 index 00000000000..3fcaaf39e56 --- /dev/null +++ b/boards/arm/pan1783/Kconfig.board @@ -0,0 +1,28 @@ +# PAN1783 EVB board configuration + +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_PAN1783_EVB_CPUAPP + bool "PAN1783 EVB (nRF5340) Application MCU" + depends on SOC_NRF5340_CPUAPP_QKAA + +config BOARD_PAN1783A_EVB_CPUAPP + bool "PAN1783A EVB (nRF5340) Application MCU" + depends on SOC_NRF5340_CPUAPP_QKAA + +config BOARD_PAN1783A_PA_EVB_CPUAPP + bool "PAN1783A-PA EVB (nRF5340) Application MCU" + depends on SOC_NRF5340_CPUAPP_QKAA + +config BOARD_PAN1783_EVB_CPUNET + bool "PAN1783 EVB (NRF5340) Network MCU" + depends on SOC_NRF5340_CPUNET_QKAA + +config BOARD_PAN1783A_EVB_CPUNET + bool "PAN1783A EVB (NRF5340) Network MCU" + depends on SOC_NRF5340_CPUNET_QKAA + +config BOARD_PAN1783A_PA_EVB_CPUNET + bool "PAN1783A-PA EVB (NRF5340) Network MCU" + depends on SOC_NRF5340_CPUNET_QKAA diff --git a/boards/arm/pan1783/Kconfig.defconfig b/boards/arm/pan1783/Kconfig.defconfig new file mode 100644 index 00000000000..47c02a95b7f --- /dev/null +++ b/boards/arm/pan1783/Kconfig.defconfig @@ -0,0 +1,34 @@ +# PAN1783 EVB board configuration + +# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUAPP + default "pan1783a_evb_cpuapp" if BOARD_PAN1783A_EVB_CPUAPP + default "pan1783a_pa_evb_cpuapp" if BOARD_PAN1783A_PA_EVB_CPUAPP + default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUNET + default "pan1783a_evb_cpunet" if BOARD_PAN1783A_EVB_CPUNET + default "pan1783a_pa_evb_cpunet" if BOARD_PAN1783A_PA_EVB_CPUNET + +config MBOX_NRFX_IPC + default MBOX + +if BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP + +choice BT_HCI_BUS_TYPE + default BT_HCI_IPC if BT +endchoice + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 4096 if BT_HCI_IPC + +endif # BOARD_PAN1783_EVB_CPUAPP || BOARD_PAN1783A_EVB_CPUAPP || BOARD_PAN1783A_PA_EVB_CPUAPP + +if BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET || BOARD_PAN1783A_PA_EVB_CPUNET + +config BT_CTLR + default y if BT + +endif # BOARD_PAN1783_EVB_CPUNET || BOARD_PAN1783A_EVB_CPUNET || BOARD_PAN1783A_PA_EVB_CPUNET diff --git a/boards/arm/pan1783/board.cmake b/boards/arm/pan1783/board.cmake new file mode 100644 index 00000000000..e8a33e8c7bf --- /dev/null +++ b/boards/arm/pan1783/board.cmake @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_BOARD_PAN1783_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_EVB_CPUAPP OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) + board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") +endif() + +if(CONFIG_BOARD_PAN1783_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_EVB_CPUNET OR CONFIG_BOARD_PAN1783A_PA_EVB_CPUNET) + board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") +endif() + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/pan1783/doc/img/pan1783_evb.webp b/boards/arm/pan1783/doc/img/pan1783_evb.webp new file mode 100644 index 00000000000..314252de239 Binary files /dev/null and b/boards/arm/pan1783/doc/img/pan1783_evb.webp differ diff --git a/boards/arm/pan1783/doc/index.rst b/boards/arm/pan1783/doc/index.rst new file mode 100644 index 00000000000..95b8b94444b --- /dev/null +++ b/boards/arm/pan1783/doc/index.rst @@ -0,0 +1,73 @@ +.. _pan1783_evb: + +PAN1783, PAN1783A and PAN1783A-PA Evaluation Boards +################################################### + +Overview +******** + +The PAN1783, PAN1783A and PAN1783A-PA Evaluation Boards (pan1783_evb, +pan1783a_evb, pan1783a_pa_evb) are development tools for the PAN1783, +PAN1783A and PAN1783A-PA Modules which are based on the nRF5340 chipset +from Nordic Semiconductor. + +More information about the PAN1783, PAN1783A, PAN1783A-PA Modules and +Evaluation Boards can be found on the `product website`_. + +PAN1783 EVB +*********** + +.. figure:: img/pan1783_evb.webp + :align: center + :alt: PAN1783 EVB + + PAN1783 EVB (Credit: Panasonic) + +PAN1783A EVB +************ + +The PAN1783A EVB essentially looks like a PAN1783 EVB, except that it is +equipped with a UFL connector on X4. + +PAN1783A-PA EVB +*************** + +The PAN1783A-PA EVB essentially resembles a PAN1783 EVB, with the addition +of a UFL connector on X4 and a power amplifier. + +Usage +***** + +For detailed information, you can find the +`pan1783_evb user guide`_ / `pan1783a_evb user guide`_ / `pan1783a_pa_evb user guide`_ +for the Evaluation Boards in the `Panasonic Wireless Connectivity Development Hub`_. + +The User Guide contains (amongst other things) detailed information about + +* pin mapping +* powering options +* breakout pin header interface +* current consumption measurement +* software development + +The schematics for the PAN1783/PAN1783A/PAN1783A-PA Evaluation Boards are +available in the `download section PAN1783`_ / `download section PAN1783A`_ / `download section PAN1783A-PA`_ +of the `Panasonic Wireless Connectivity Development Hub`_. + +Programming and Debugging +************************* + +Please use the ``pan1783_evb_cpuapp``, ``pan1783a_evb_cpuapp`` or +``pan1783a_pa_evb_cpuapp`` for application core and ``pan1783_evb_cpunet``, +``pan1783a_evb_cpunet`` or ``pan1783a_pa_evb_cpunet`` board configuration +for network core when :ref:`build_an_application` and :ref:`application_run`. + +.. target-notes:: +.. _product website: https://industry.panasonic.eu/products/devices/wireless-connectivity/bluetooth-low-energy-modules +.. _Panasonic Wireless Connectivity Development Hub: https://pideu.panasonic.de/development-hub/ +.. _pan1783_evb user guide: https://pideu.panasonic.de/development-hub/pan1783/evaluation_board/user_guide/ +.. _pan1783a_evb user guide: https://pideu.panasonic.de/development-hub/pan1783a/evaluation_board/user_guide/ +.. _pan1783a_pa_evb user guide: https://pideu.panasonic.de/development-hub/pan1783a_pa/evaluation_board/user_guide/ +.. _download section PAN1783: https://pideu.panasonic.de/development-hub/pan1783/downloads/ +.. _download section PAN1783A: https://pideu.panasonic.de/development-hub/pan1783a/downloads/ +.. _download section PAN1783A-PA: https://pideu.panasonic.de/development-hub/pan1783a_pa/downloads/ diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_common-pinctrl.dtsi rename to boards/arm/pan1783/pan1783_cpuapp_common-pinctrl.dtsi diff --git a/boards/arm/pan1783/pan1783_cpuapp_common.dtsi b/boards/arm/pan1783/pan1783_cpuapp_common.dtsi new file mode 100644 index 00000000000..77d093a5d40 --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpuapp_common.dtsi @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "pan1783_cpuapp_common-pinctrl.dtsi" +#include + +/ { + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + evb_led1: evb_led_1 { + gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + label = "LED1 on EVB"; + }; + evb_led2: evb_led_2 { + gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; + label = "LED2 on EVB"; + }; + evb_led3: evb_led_3 { + gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + label = "LED3 on EVB"; + }; + evb_led4: evb_led_4 { + gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; + label = "LED4 on EVB"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_evb_led1: pwm_evb_led_1 { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + }; + }; + + buttons { + compatible = "gpio-keys"; + evb_sw1: evb_sw_1 { + gpios = <&gpio0 23 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW1 on EVB"; + zephyr,code = ; + }; + evb_sw2: evb_sw_2 { + gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2 on EVB"; + zephyr,code = ; + }; + evb_sw3: evb_sw_3 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW3 on EVB"; + zephyr,code = ; + }; + evb_sw4: evb_sw_4 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW4 on EVB"; + zephyr,code = ; + }; + }; + + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio1 12 0>, /* CS */ + <3 0 &gpio1 15 0>, /* SCK */ + <4 0 &gpio1 14 0>, /* MISO */ + <5 0 &gpio1 13 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 7 0>, /* PWM */ + <7 0 &gpio1 4 0>, /* INT */ + <8 0 &gpio1 0 0>, /* RX */ + <9 0 &gpio1 1 0>, /* TX */ + <10 0 &gpio1 3 0>, /* SCL */ + <11 0 &gpio1 2 0>; /* SDA */ + /* +5V */ + /* GND */ + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* A0 */ + <1 0 &gpio0 5 0>, /* A1 */ + <2 0 &gpio0 6 0>, /* A2 */ + <3 0 &gpio0 7 0>, /* A3 */ + <4 0 &gpio0 25 0>, /* A4 */ + <5 0 &gpio0 26 0>, /* A5 */ + <6 0 &gpio1 0 0>, /* D0 */ + <7 0 &gpio1 1 0>, /* D1 */ + <8 0 &gpio1 4 0>, /* D2 */ + <9 0 &gpio1 5 0>, /* D3 */ + <10 0 &gpio1 6 0>, /* D4 */ + <11 0 &gpio1 7 0>, /* D5 */ + <12 0 &gpio1 8 0>, /* D6 */ + <13 0 &gpio1 9 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 11 0>, /* D9 */ + <16 0 &gpio1 12 0>, /* D10 */ + <17 0 &gpio1 13 0>, /* D11 */ + <18 0 &gpio1 14 0>, /* D12 */ + <19 0 &gpio1 15 0>, /* D13 */ + <20 0 &gpio1 2 0>, /* D14 */ + <21 0 &gpio1 3 0>; /* D15 */ + }; + + arduino_adc: analog-connector { + compatible = "arduino,uno-adc"; + #io-channel-cells = <1>; + io-channel-map = <0 &adc 0>, /* A0 = P0.4 = AIN0 */ + <1 &adc 1>, /* A1 = P0.5 = AIN1 */ + <2 &adc 2>, /* A2 = P0.6 = AIN2 */ + <3 &adc 3>, /* A3 = P0.7 = AIN3 */ + <4 &adc 4>, /* A4 = P0.25 = AIN4 */ + <5 &adc 5>; /* A5 = P0.26 = AIN5 */ + }; + + gpio_fwd: nrf-gpio-forwarder { + compatible = "nordic,nrf-gpio-forwarder"; + status = "disabled"; + uart { + gpios = <&gpio0 20 0>, <&gpio0 22 0>, <&gpio0 11 0>, <&gpio0 10 0>; + }; + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &evb_led1; + led1 = &evb_led2; + led2 = &evb_led3; + led3 = &evb_led4; + pwm-led0 = &pwm_evb_led1; + sw0 = &evb_sw1; + sw1 = &evb_sw2; + sw2 = &evb_sw3; + sw3 = &evb_sw4; + bootloader-led0 = &evb_led1; + mcuboot-button0 = &evb_sw1; + mcuboot-led0 = &evb_led1; + watchdog0 = &wdt0; + spi-flash0 = &mx25r64; + }; +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c1 { + compatible = "nordic,nrf-twim"; + status = "okay"; + pinctrl-0 = <&i2c1_default>; + pinctrl-1 = <&i2c1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&qspi { + status = "okay"; + pinctrl-0 = <&qspi_default>; + pinctrl-1 = <&qspi_sleep>; + pinctrl-names = "default", "sleep"; + mx25r64: mx25r6435f@0 { + compatible = "nordic,qspi-nor"; + reg = <0>; + /* MX25R64 supports only pp and pp4io */ + writeoc = "pp4io"; + /* MX25R64 supports all readoc options */ + readoc = "read4io"; + sck-frequency = <8000000>; + jedec-id = [ c2 28 17 ]; + sfdp-bfp = [ + e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb + ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 + 10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44 + 30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff + ]; + size = <67108864>; + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <35000>; + }; +}; + +arduino_serial: &uart1 { + compatible = "nordic,nrf-uarte"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_i2c: &i2c1 {}; + +arduino_spi: &spi4 { + compatible = "nordic,nrf-spim"; + status = "okay"; + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ + pinctrl-0 = <&spi4_default>; + pinctrl-1 = <&spi4_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&flash0 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + }; + slot1_partition: partition@80000 { + label = "image-1"; + }; + /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; +}; + +/ { + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram0_image: image@20000000 { + /* Zephyr image(s) memory */ + }; + + sram0_s: image_s@20000000 { + /* Secure image memory */ + }; + }; +}; + +/* Include partition configuration file */ +#include "pan1783_cpuapp_partition_conf.dtsi" diff --git a/boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi b/boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi new file mode 100644 index 00000000000..6eb6792c996 --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpuapp_partition_conf.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Default Flash planning for pan1783_evb CPUAPP (Application MCU). + * + * Secure image will be placed, by default, in flash0 + * (or in slot0, if MCUboot is present). + * Secure image will use sram0 for system memory. + * + */ + +&slot0_partition { + reg = <0x00010000 0x40000>; +}; + +&slot1_partition { + reg = <0x00080000 0x40000>; +}; + +/* Default SRAM planning when building for nRF5340 + * - Lowest 448 kB SRAM allocated to Secure image (sram0_s) + * - Upper 64 kB SRAM allocated as Shared memory (sram0_shared) + * (see shared_sram_planning_conf.dtsi) + */ +&sram0_image { + reg = <0x20000000 DT_SIZE_K(448)>; +}; + +&sram0_s { + reg = <0x20000000 0x70000>; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet-pinctrl.dtsi b/boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet-pinctrl.dtsi rename to boards/arm/pan1783/pan1783_cpunet-pinctrl.dtsi diff --git a/boards/arm/pan1783/pan1783_cpunet_common.dtsi b/boards/arm/pan1783/pan1783_cpunet_common.dtsi new file mode 100644 index 00000000000..5b5e7735e4a --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpunet_common.dtsi @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "pan1783_cpunet-pinctrl.dtsi" +#include + +/ { + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; + zephyr,ieee802154 = &ieee802154; + }; + + leds { + compatible = "gpio-leds"; + evb_led1: evb_led_1 { + gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; + label = "LED1 on EVB"; + }; + evb_led2: evb_led_2 { + gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; + label = "LED2 on EVB"; + }; + evb_led3: evb_led_3 { + gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + label = "LED3 on EVB"; + }; + evb_led4: evb_led_4 { + gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; + label = "LED4 on EVB"; + }; + }; + + buttons { + compatible = "gpio-keys"; + evb_sw1: evb_sw_1 { + gpios = <&gpio0 23 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW1 on EVB"; + zephyr,code = ; + }; + evb_sw2: evb_sw_2 { + gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW2 on EVB"; + zephyr,code = ; + }; + evb_sw3: evb_sw_3 { + gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW3 on EVB"; + zephyr,code = ; + }; + evb_sw4: evb_sw_4 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "SW4 on EVB"; + zephyr,code = ; + }; + }; + + mikrobus_header: mikrobus-connector { + compatible = "mikro-bus"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* AN */ + /* Not a GPIO*/ /* RST */ + <2 0 &gpio1 12 0>, /* CS */ + <3 0 &gpio1 15 0>, /* SCK */ + <4 0 &gpio1 14 0>, /* MISO */ + <5 0 &gpio1 13 0>, /* MOSI */ + /* +3.3V */ + /* GND */ + <6 0 &gpio1 7 0>, /* PWM */ + <7 0 &gpio1 4 0>, /* INT */ + <8 0 &gpio1 0 0>, /* RX */ + <9 0 &gpio1 1 0>, /* TX */ + <10 0 &gpio1 3 0>, /* SCL */ + <11 0 &gpio1 2 0>; /* SDA */ + /* +5V */ + /* GND */ + }; + + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 4 0>, /* A0 */ + <1 0 &gpio0 5 0>, /* A1 */ + <2 0 &gpio0 6 0>, /* A2 */ + <3 0 &gpio0 7 0>, /* A3 */ + <4 0 &gpio0 25 0>, /* A4 */ + <5 0 &gpio0 26 0>, /* A5 */ + <6 0 &gpio1 0 0>, /* D0 */ + <7 0 &gpio1 1 0>, /* D1 */ + <8 0 &gpio1 4 0>, /* D2 */ + <9 0 &gpio1 5 0>, /* D3 */ + <10 0 &gpio1 6 0>, /* D4 */ + <11 0 &gpio1 7 0>, /* D5 */ + <12 0 &gpio1 8 0>, /* D6 */ + <13 0 &gpio1 9 0>, /* D7 */ + <14 0 &gpio1 10 0>, /* D8 */ + <15 0 &gpio1 11 0>, /* D9 */ + <16 0 &gpio1 12 0>, /* D10 */ + <17 0 &gpio1 13 0>, /* D11 */ + <18 0 &gpio1 14 0>, /* D12 */ + <19 0 &gpio1 15 0>, /* D13 */ + <20 0 &gpio1 2 0>, /* D14 */ + <21 0 &gpio1 3 0>; /* D15 */ + }; + + /* These aliases are provided for compatibility with samples */ + aliases { + led0 = &evb_led1; + led1 = &evb_led2; + led2 = &evb_led3; + led3 = &evb_led4; + sw0 = &evb_sw1; + sw1 = &evb_sw2; + sw2 = &evb_sw3; + sw3 = &evb_sw4; + bootloader-led0 = &evb_led1; + mcuboot-button0 = &evb_sw1; + mcuboot-led0 = &evb_led1; + watchdog0 = &wdt0; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&uart0 { + status = "disabled"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_serial: &uart0 {}; + +arduino_i2c: &i2c0 { + compatible = "nordic,nrf-twim"; + /* Cannot be used together with uart0. */ + /* status = "okay"; */ + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +arduino_spi: &spi0 { + compatible = "nordic,nrf-spim"; + /* Cannot be used together with uart0. */ + /* status = "okay"; */ + cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ + pinctrl-0 = <&spi0_default>; + pinctrl-1 = <&spi0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&flash1 { + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0xc000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x17000>; + }; + slot1_partition: partition@23000 { + label = "image-1"; + reg = <0x00023000 0x17000>; + }; + storage_partition: partition@3a000 { + label = "storage"; + reg = <0x0003a000 0x6000>; + }; + }; +}; + +&ieee802154 { + status = "okay"; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783/pan1783_cpunet_reset.c b/boards/arm/pan1783/pan1783_cpunet_reset.c new file mode 100644 index 00000000000..529051ec629 --- /dev/null +++ b/boards/arm/pan1783/pan1783_cpunet_reset.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +#if defined(CONFIG_BOARD_PAN1783_EVB_CPUAPP) +LOG_MODULE_REGISTER(pan1783_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#elif defined(CONFIG_BOARD_PAN1783A_EVB_CPUAPP) +LOG_MODULE_REGISTER(pan1783a_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#elif defined(CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP) +LOG_MODULE_REGISTER(pan1783a_pa_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); +#else +#error "No board selected!" +#endif + +#if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) +#include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h> +#else +#define DEBUG_SETUP() +#endif + +static void remoteproc_mgr_config(void) +{ + /* Route Bluetooth Controller Debug Pins */ + DEBUG_SETUP(); + + /* Retain nRF5340 Network MCU */ + NRF_SPU->EXTDOMAIN[0].PERM = 1 << 4; +} + +static int remoteproc_mgr_boot(void) +{ + /* Configure permissions for the Network MCU. */ + remoteproc_mgr_config(); + + /* Release the Network MCU, 'Release force off signal' */ + nrf_reset_network_force_off(NRF_RESET, false); + + LOG_DBG("Network MCU released."); + + return 0; +} + +SYS_INIT(remoteproc_mgr_boot, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp.dts b/boards/arm/pan1783/pan1783_evb_cpuapp.dts similarity index 91% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp.dts rename to boards/arm/pan1783/pan1783_evb_cpuapp.dts index 3adae69badb..54f71dd87d5 100644 --- a/boards/arm/pan1783_evb/pan1783_evb_cpuapp.dts +++ b/boards/arm/pan1783/pan1783_evb_cpuapp.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include "pan1783_evb_cpuapp_common.dtsi" +#include "pan1783_cpuapp_common.dtsi" / { model = "Panasonic PAN1783 EVB (NRF5340) Application"; diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783_evb_cpuapp.yaml similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp.yaml rename to boards/arm/pan1783/pan1783_evb_cpuapp.yaml diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783_evb_cpuapp_defconfig similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpuapp_defconfig rename to boards/arm/pan1783/pan1783_evb_cpuapp_defconfig diff --git a/boards/arm/pan1783/pan1783_evb_cpunet.dts b/boards/arm/pan1783/pan1783_evb_cpunet.dts new file mode 100644 index 00000000000..7063e53af46 --- /dev/null +++ b/boards/arm/pan1783/pan1783_evb_cpunet.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783 EVB (NRF5340) Network"; + compatible = "panasonic,pan1783-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet.yaml b/boards/arm/pan1783/pan1783_evb_cpunet.yaml similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet.yaml rename to boards/arm/pan1783/pan1783_evb_cpunet.yaml diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783_evb_cpunet_defconfig similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_cpunet_defconfig rename to boards/arm/pan1783/pan1783_evb_cpunet_defconfig diff --git a/boards/arm/pan1783_evb/pan1783_evb_shared_sram_planning_conf.dtsi b/boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi similarity index 100% rename from boards/arm/pan1783_evb/pan1783_evb_shared_sram_planning_conf.dtsi rename to boards/arm/pan1783/pan1783_shared_sram_planning_conf.dtsi diff --git a/boards/arm/pan1783/pan1783a_evb_cpuapp.dts b/boards/arm/pan1783/pan1783a_evb_cpuapp.dts new file mode 100644 index 00000000000..29f0dcb796c --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpuapp.dts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpuapp_common.dtsi" + +/ { + model = "Panasonic PAN1783A EVB (NRF5340) Application"; + compatible = "panasonic,pan1783a-evb-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + }; +}; diff --git a/boards/arm/pan1783/pan1783a_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783a_evb_cpuapp.yaml new file mode 100644 index 00000000000..2a89c3f1f37 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpuapp.yaml @@ -0,0 +1,21 @@ +identifier: pan1783a_evb_cpuapp +name: PAN1783A-EVB-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usb_cdc + - usb_device + - netif:openthread + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783a_evb_cpuapp_defconfig new file mode 100644 index 00000000000..2f624e1db0c --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpuapp_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUAPP_QKAA=y +CONFIG_BOARD_PAN1783A_EVB_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783/pan1783a_evb_cpunet.dts b/boards/arm/pan1783/pan1783a_evb_cpunet.dts new file mode 100644 index 00000000000..9cd0409a432 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpunet.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783A EVB (NRF5340) Network"; + compatible = "panasonic,pan1783a-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783/pan1783a_evb_cpunet.yaml b/boards/arm/pan1783/pan1783a_evb_cpunet.yaml new file mode 100644 index 00000000000..2dd985f61ff --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: pan1783a_evb_cpunet +name: PAN1783A-EVB-network-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 64 +flash: 256 +supported: + - watchdog + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783a_evb_cpunet_defconfig new file mode 100644 index 00000000000..3e44ff7338c --- /dev/null +++ b/boards/arm/pan1783/pan1783a_evb_cpunet_defconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUNET_QKAA=y +CONFIG_BOARD_PAN1783A_EVB_CPUNET=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts new file mode 100644 index 00000000000..aba6e9281e2 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpuapp_common.dtsi" + +/ { + model = "Panasonic PAN1783A-PA EVB (NRF5340) Application"; + compatible = "panasonic,pan1783a_pa-evb-cpuapp"; + + chosen { + zephyr,sram = &sram0_image; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + zephyr,sram-secure-partition = &sram0_s; + }; +}; + +&gpio_fwd { + /delete-node/ uart; + + status = "okay"; + fem { + gpios = <&gpio0 19 0>, <&gpio0 21 0>; + }; +}; diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml new file mode 100644 index 00000000000..0bc70dab273 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp.yaml @@ -0,0 +1,21 @@ +identifier: pan1783a_pa_evb_cpuapp +name: PAN1783A-PA-EVB-application-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 448 +flash: 1024 +supported: + - gpio + - i2c + - i2s + - pwm + - watchdog + - usb_cdc + - usb_device + - netif:openthread + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig new file mode 100644 index 00000000000..f58bdce8bfc --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpuapp_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUAPP_QKAA=y +CONFIG_BOARD_PAN1783A_PA_EVB_CPUAPP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable uart driver +CONFIG_SERIAL=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts new file mode 100644 index 00000000000..1b345aaa945 --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.dts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include "pan1783_cpunet_common.dtsi" + +/ { + model = "Panasonic PAN1783A-PA EVB (NRF5340) Network"; + compatible = "panasonic,pan1783a_pa-evb-cpunet"; + + chosen { + zephyr,sram = &sram1; + zephyr,flash = &flash1; + zephyr,code-partition = &slot0_partition; + }; + + nrf_radio_fem: fem_node { + compatible = "skyworks,sky66407-11", "generic-fem-two-ctrl-pins"; + ctx-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; + crx-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + }; +}; + +&radio { + fem = <&nrf_radio_fem>; +}; + +/* Include shared RAM configuration file */ +#include "pan1783_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml new file mode 100644 index 00000000000..98a2f2908de --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet.yaml @@ -0,0 +1,14 @@ +identifier: pan1783a_pa_evb_cpunet +name: PAN1783A-PA-EVB-network-MCU +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +ram: 64 +flash: 256 +supported: + - watchdog + - gpio +vendor: panasonic diff --git a/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig b/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig new file mode 100644 index 00000000000..3ba18cd433a --- /dev/null +++ b/boards/arm/pan1783/pan1783a_pa_evb_cpunet_defconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF53X=y +CONFIG_SOC_NRF5340_CPUNET_QKAA=y +CONFIG_BOARD_PAN1783A_PA_EVB_CPUNET=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable GPIO +CONFIG_GPIO=y + +# clock config +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n diff --git a/boards/arm/pan1783_evb/pre_dt_board.cmake b/boards/arm/pan1783/pre_dt_board.cmake similarity index 100% rename from boards/arm/pan1783_evb/pre_dt_board.cmake rename to boards/arm/pan1783/pre_dt_board.cmake diff --git a/boards/arm/pan1783_evb/CMakeLists.txt b/boards/arm/pan1783_evb/CMakeLists.txt deleted file mode 100644 index f8bc359b603..00000000000 --- a/boards/arm/pan1783_evb/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH -# SPDX-License-Identifier: Apache-2.0 - -if ((CONFIG_BOARD_PAN1783_EVB_CPUAPP) AND (CONFIG_BOARD_ENABLE_CPUNET)) -zephyr_library() -zephyr_library_sources(pan1783_evb_cpunet_reset.c) -endif() diff --git a/boards/arm/pan1783_evb/Kconfig b/boards/arm/pan1783_evb/Kconfig deleted file mode 100644 index b9c84ba66ff..00000000000 --- a/boards/arm/pan1783_evb/Kconfig +++ /dev/null @@ -1,53 +0,0 @@ -# PAN1783 EVB board configuration - -# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH -# SPDX-License-Identifier: Apache-2.0 - -if BOARD_PAN1783_EVB_CPUAPP - -config BOARD_ENABLE_DCDC_APP - bool "Application MCU DCDC converter" - select SOC_DCDC_NRF53X_APP - default y - -config BOARD_ENABLE_DCDC_NET - bool "Network MCU DCDC converter" - select SOC_DCDC_NRF53X_NET - default y - -config BOARD_ENABLE_DCDC_HV - bool "High Voltage DCDC converter" - select SOC_DCDC_NRF53X_HV - default y - -config BOARD_ENABLE_CPUNET - bool "NRF53 Network MCU" - select SOC_NRF_GPIO_FORWARDER_FOR_NRF5340 if \ - $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GPIO_FORWARDER)) - help - This option enables releasing the Network 'force off' signal, which - as a consequence will power up the Network MCU during system boot. - Additionally, the option allocates GPIO pins that will be used by UARTE - of the Network MCU. - default y if (BT || NRF_802154_SER_HOST) - -config DOMAIN_CPUNET_BOARD - string - default "pan1783_evb_cpunet" - depends on BOARD_ENABLE_CPUNET - help - The board which will be used for CPUNET domain when creating a multi - image application where one or more images should be located on - another board. For example hci_ipc on the nRF5340_cpunet for - Bluetooth applications. - -endif # BOARD_PAN1783_EVB_CPUAPP - -config DOMAIN_CPUAPP_BOARD - string - default "pan1783_evb_cpuapp" - depends on BOARD_PAN1783_EVB_CPUNET - help - The board which will be used for CPUAPP domain when creating a multi - image application where one or more images should be located on - another board. diff --git a/boards/arm/pan1783_evb/Kconfig.board b/boards/arm/pan1783_evb/Kconfig.board deleted file mode 100644 index d66c99aac36..00000000000 --- a/boards/arm/pan1783_evb/Kconfig.board +++ /dev/null @@ -1,12 +0,0 @@ -# PAN1783 EVB board configuration - -# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_PAN1783_EVB_CPUAPP - bool "PAN1783 EVB (nRF5340) Application MCU" - depends on SOC_NRF5340_CPUAPP_QKAA - -config BOARD_PAN1783_EVB_CPUNET - bool "PAN1783 EVB (NRF5340) Network MCU" - depends on SOC_NRF5340_CPUNET_QKAA diff --git a/boards/arm/pan1783_evb/Kconfig.defconfig b/boards/arm/pan1783_evb/Kconfig.defconfig deleted file mode 100644 index b26b4970d84..00000000000 --- a/boards/arm/pan1783_evb/Kconfig.defconfig +++ /dev/null @@ -1,31 +0,0 @@ -# PAN1783 EVB board configuration - -# Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH -# SPDX-License-Identifier: Apache-2.0 - -config BOARD - default "pan1783_evb_cpuapp" if BOARD_PAN1783_EVB_CPUAPP - -config BOARD - default "pan1783_evb_cpunet" if BOARD_PAN1783_EVB_CPUNET - -config MBOX_NRFX_IPC - default MBOX - -if BOARD_PAN1783_EVB_CPUAPP - -choice BT_HCI_BUS_TYPE - default BT_HCI_IPC if BT -endchoice - -config HEAP_MEM_POOL_SIZE - default 4096 if BT_HCI_IPC - -endif # BOARD_PAN1783_EVB_CPUAPP - -if BOARD_PAN1783_EVB_CPUNET - -config BT_CTLR - default y if BT - -endif # BOARD_PAN1783_EVB_CPUNET diff --git a/boards/arm/pan1783_evb/board.cmake b/boards/arm/pan1783_evb/board.cmake deleted file mode 100644 index f75151ecb94..00000000000 --- a/boards/arm/pan1783_evb/board.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if(CONFIG_BOARD_PAN1783_EVB_CPUAPP) -board_runner_args(jlink "--device=nrf5340_xxaa_app" "--speed=4000") -endif() - -if(CONFIG_BOARD_PAN1783_EVB_CPUNET) -board_runner_args(jlink "--device=nrf5340_xxaa_net" "--speed=4000") -endif() - -include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) -include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/pan1783_evb/doc/img/pan1783_evb.jpg b/boards/arm/pan1783_evb/doc/img/pan1783_evb.jpg deleted file mode 100644 index 273253cfcf9..00000000000 Binary files a/boards/arm/pan1783_evb/doc/img/pan1783_evb.jpg and /dev/null differ diff --git a/boards/arm/pan1783_evb/doc/index.rst b/boards/arm/pan1783_evb/doc/index.rst deleted file mode 100644 index 39fe7fdff8f..00000000000 --- a/boards/arm/pan1783_evb/doc/index.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. _pan1783_evb: - -PAN1783 Evaluation Board -######################## - -Overview -******** - -The PAN1783 Evaluation Board (pan1783_evb) is a development tool for the -PAN1783 Module which is based on the nRF5340 chipset from Nordic Semiconductor. - -You can find more information about the PAN1783 Module and Evaluation Board -on the `product website`_. - -.. figure:: img/pan1783_evb.jpg - :align: center - :alt: PAN1783 EVB - - PAN1783 EVB (Credit: Panasonic) - -The PAN1783 Evaluation Board is closely linked to these other evaluation -boards: - -* pan1783a_evb -* pan1783a_pa_evb - -Usage -***** - -For detailed information, you can find the `user guide`_ for the PAN1783 -Evaluation Board in the `Panasonic Wireless Connectivity Development Hub`_. - -The User Guide contains (amongst other things) detailed information about - -* pin mapping -* powering options -* breakout pin header interface -* current consumption measurement -* software development - -The schematics for the PAN1783 Evaluation Board are available in the -`download section`_ of the `Panasonic Wireless Connectivity Development Hub`_. - -Programming and Debugging -************************* - -Please use the ``pan1783_evb_cpuapp`` for application core or -``pan1783_evb_cpunet`` board configuration for network core -when :ref:`build_an_application` and :ref:`application_run`. - -.. target-notes:: -.. _product website: https://industry.panasonic.eu/products/devices/wireless-connectivity/bluetooth-low-energy-modules/pan1783-nrf5340 -.. _Panasonic Wireless Connectivity Development Hub: https://pideu.panasonic.de/development-hub/ -.. _user guide: https://pideu.panasonic.de/development-hub/pan1783/evaluation_board/user_guide/ -.. _download section: https://pideu.panasonic.de/development-hub/pan1783/downloads/ diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi b/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi deleted file mode 100644 index 175475f5b0e..00000000000 --- a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_common.dtsi +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include "pan1783_evb_cpuapp_common-pinctrl.dtsi" -#include - -/ { - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - zephyr,bt-mon-uart = &uart0; - zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-ipc = &ipc0; - nordic,802154-spinel-ipc = &ipc0; - zephyr,ieee802154 = &ieee802154; - }; - - leds { - compatible = "gpio-leds"; - evb_led1: evb_led_1 { - gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; - label = "LED1 on EVB"; - }; - evb_led2: evb_led_2 { - gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; - label = "LED2 on EVB"; - }; - evb_led3: evb_led_3 { - gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; - label = "LED3 on EVB"; - }; - evb_led4: evb_led_4 { - gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; - label = "LED4 on EVB"; - }; - }; - - pwmleds { - compatible = "pwm-leds"; - pwm_evb_led1: pwm_evb_led_1 { - pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; - }; - }; - - buttons { - compatible = "gpio-keys"; - evb_sw1: evb_sw_1 { - gpios = <&gpio0 23 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW1 on EVB"; - zephyr,code = ; - }; - evb_sw2: evb_sw_2 { - gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW2 on EVB"; - zephyr,code = ; - }; - evb_sw3: evb_sw_3 { - gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW3 on EVB"; - zephyr,code = ; - }; - evb_sw4: evb_sw_4 { - gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW4 on EVB"; - zephyr,code = ; - }; - }; - - mikrobus_header: mikrobus-connector { - compatible = "mikro-bus"; - #gpio-cells = <2>; - gpio-map-mask = <0xffffffff 0xffffffc0>; - gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 4 0>, /* AN */ - /* Not a GPIO*/ /* RST */ - <2 0 &gpio1 12 0>, /* CS */ - <3 0 &gpio1 15 0>, /* SCK */ - <4 0 &gpio1 14 0>, /* MISO */ - <5 0 &gpio1 13 0>, /* MOSI */ - /* +3.3V */ - /* GND */ - <6 0 &gpio1 7 0>, /* PWM */ - <7 0 &gpio1 4 0>, /* INT */ - <8 0 &gpio1 0 0>, /* RX */ - <9 0 &gpio1 1 0>, /* TX */ - <10 0 &gpio1 3 0>, /* SCL */ - <11 0 &gpio1 2 0>; /* SDA */ - /* +5V */ - /* GND */ - }; - - arduino_header: connector { - compatible = "arduino-header-r3"; - #gpio-cells = <2>; - gpio-map-mask = <0xffffffff 0xffffffc0>; - gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 4 0>, /* A0 */ - <1 0 &gpio0 5 0>, /* A1 */ - <2 0 &gpio0 6 0>, /* A2 */ - <3 0 &gpio0 7 0>, /* A3 */ - <4 0 &gpio0 25 0>, /* A4 */ - <5 0 &gpio0 26 0>, /* A5 */ - <6 0 &gpio1 0 0>, /* D0 */ - <7 0 &gpio1 1 0>, /* D1 */ - <8 0 &gpio1 4 0>, /* D2 */ - <9 0 &gpio1 5 0>, /* D3 */ - <10 0 &gpio1 6 0>, /* D4 */ - <11 0 &gpio1 7 0>, /* D5 */ - <12 0 &gpio1 8 0>, /* D6 */ - <13 0 &gpio1 9 0>, /* D7 */ - <14 0 &gpio1 10 0>, /* D8 */ - <15 0 &gpio1 11 0>, /* D9 */ - <16 0 &gpio1 12 0>, /* D10 */ - <17 0 &gpio1 13 0>, /* D11 */ - <18 0 &gpio1 14 0>, /* D12 */ - <19 0 &gpio1 15 0>, /* D13 */ - <20 0 &gpio1 2 0>, /* D14 */ - <21 0 &gpio1 3 0>; /* D15 */ - }; - - arduino_adc: analog-connector { - compatible = "arduino,uno-adc"; - #io-channel-cells = <1>; - io-channel-map = <0 &adc 0>, /* A0 = P0.4 = AIN0 */ - <1 &adc 1>, /* A1 = P0.5 = AIN1 */ - <2 &adc 2>, /* A2 = P0.6 = AIN2 */ - <3 &adc 3>, /* A3 = P0.7 = AIN3 */ - <4 &adc 4>, /* A4 = P0.25 = AIN4 */ - <5 &adc 5>; /* A5 = P0.26 = AIN5 */ - }; - - gpio_fwd: nrf-gpio-forwarder { - compatible = "nordic,nrf-gpio-forwarder"; - status = "disabled"; - uart { - gpios = <&gpio0 20 0>, <&gpio0 22 0>, <&gpio0 11 0>, <&gpio0 10 0>; - }; - }; - - /* These aliases are provided for compatibility with samples */ - aliases { - led0 = &evb_led1; - led1 = &evb_led2; - led2 = &evb_led3; - led3 = &evb_led4; - pwm-led0 = &pwm_evb_led1; - sw0 = &evb_sw1; - sw1 = &evb_sw2; - sw2 = &evb_sw3; - sw3 = &evb_sw4; - bootloader-led0 = &evb_led1; - mcuboot-button0 = &evb_sw1; - mcuboot-led0 = &evb_led1; - watchdog0 = &wdt0; - spi-flash0 = &mx25r64; - }; -}; - -&adc { - status = "okay"; -}; - -&gpiote { - status = "okay"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -&i2c1 { - compatible = "nordic,nrf-twim"; - status = "okay"; - pinctrl-0 = <&i2c1_default>; - pinctrl-1 = <&i2c1_sleep>; - pinctrl-names = "default", "sleep"; -}; - -&uart0 { - status = "okay"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-1 = <&uart0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -&pwm0 { - status = "okay"; - pinctrl-0 = <&pwm0_default>; - pinctrl-1 = <&pwm0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -&qspi { - status = "okay"; - pinctrl-0 = <&qspi_default>; - pinctrl-1 = <&qspi_sleep>; - pinctrl-names = "default", "sleep"; - mx25r64: mx25r6435f@0 { - compatible = "nordic,qspi-nor"; - reg = <0>; - /* MX25R64 supports only pp and pp4io */ - writeoc = "pp4io"; - /* MX25R64 supports all readoc options */ - readoc = "read4io"; - sck-frequency = <8000000>; - jedec-id = [ c2 28 17 ]; - sfdp-bfp = [ - e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb - ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 - 10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44 - 30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff - ]; - size = <67108864>; - has-dpd; - t-enter-dpd = <10000>; - t-exit-dpd = <35000>; - }; -}; - -arduino_serial: &uart1 { - compatible = "nordic,nrf-uarte"; - current-speed = <115200>; - pinctrl-0 = <&uart1_default>; - pinctrl-1 = <&uart1_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_i2c: &i2c1 {}; - -arduino_spi: &spi4 { - compatible = "nordic,nrf-spim"; - status = "okay"; - cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - pinctrl-0 = <&spi4_default>; - pinctrl-1 = <&spi4_sleep>; - pinctrl-names = "default", "sleep"; -}; - -&flash0 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x00010000>; - }; - slot0_partition: partition@10000 { - label = "image-0"; - }; - slot1_partition: partition@80000 { - label = "image-1"; - }; - /* 0xf0000 to 0xf7fff reserved for TF-M partitions */ - storage_partition: partition@f8000 { - label = "storage"; - reg = <0x000f8000 0x00008000>; - }; - }; -}; - -&ieee802154 { - status = "okay"; -}; - -zephyr_udc0: &usbd { - compatible = "nordic,nrf-usbd"; - status = "okay"; -}; - -/ { - - reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - ranges; - - sram0_image: image@20000000 { - /* Zephyr image(s) memory */ - }; - - sram0_s: image_s@20000000 { - /* Secure image memory */ - }; - }; -}; - -/* Include partition configuration file */ -#include "pan1783_evb_cpuapp_partition_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi b/boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi deleted file mode 100644 index 50e32748bec..00000000000 --- a/boards/arm/pan1783_evb/pan1783_evb_cpuapp_partition_conf.dtsi +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * Default Flash planning for pan1783_evb CPUAPP (Application MCU). - * - * Secure image will be placed, by default, in flash0 - * (or in slot0, if MCUboot is present). - * Secure image will use sram0 for system memory. - * - */ - -&slot0_partition { - reg = <0x00010000 0x40000>; -}; - -&slot1_partition { - reg = <0x00080000 0x40000>; -}; - -/* Default SRAM planning when building for nRF5340 - * - Lowest 448 kB SRAM allocated to Secure image (sram0_s) - * - Upper 64 kB SRAM allocated as Shared memory (sram0_shared) - * (see pan1783_evb_shared_sram_planning_conf.dts) - */ -&sram0_image { - reg = <0x20000000 DT_SIZE_K(448)>; -}; - -&sram0_s { - reg = <0x20000000 0x70000>; -}; - -/* Include shared RAM configuration file */ -#include "pan1783_evb_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet.dts b/boards/arm/pan1783_evb/pan1783_evb_cpunet.dts deleted file mode 100644 index 6506c46aeed..00000000000 --- a/boards/arm/pan1783_evb/pan1783_evb_cpunet.dts +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/dts-v1/; -#include -#include "pan1783_evb_cpunet-pinctrl.dtsi" -#include - -/ { - model = "Panasonic PAN1783 EVB (NRF5340) Network"; - compatible = "panasonic,pan1783-evb-cpunet"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - zephyr,bt-mon-uart = &uart0; - zephyr,bt-c2h-uart = &uart0; - zephyr,bt-hci-ipc = &ipc0; - nordic,802154-spinel-ipc = &ipc0; - zephyr,sram = &sram1; - zephyr,flash = &flash1; - zephyr,code-partition = &slot0_partition; - zephyr,ieee802154 = &ieee802154; - }; - - leds { - compatible = "gpio-leds"; - evb_led1: evb_led_1 { - gpios = <&gpio0 28 GPIO_ACTIVE_LOW>; - label = "LED1 on EVB"; - }; - evb_led2: evb_led_2 { - gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; - label = "LED2 on EVB"; - }; - evb_led3: evb_led_3 { - gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; - label = "LED3 on EVB"; - }; - evb_led4: evb_led_4 { - gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; - label = "LED4 on EVB"; - }; - }; - - buttons { - compatible = "gpio-keys"; - evb_sw1: evb_sw_1 { - gpios = <&gpio0 23 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW1 on EVB"; - zephyr,code = ; - }; - evb_sw2: evb_sw_2 { - gpios = <&gpio0 24 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW2 on EVB"; - zephyr,code = ; - }; - evb_sw3: evb_sw_3 { - gpios = <&gpio0 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW3 on EVB"; - zephyr,code = ; - }; - evb_sw4: evb_sw_4 { - gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; - label = "SW4 on EVB"; - zephyr,code = ; - }; - }; - - mikrobus_header: mikrobus-connector { - compatible = "mikro-bus"; - #gpio-cells = <2>; - gpio-map-mask = <0xffffffff 0xffffffc0>; - gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 4 0>, /* AN */ - /* Not a GPIO*/ /* RST */ - <2 0 &gpio1 12 0>, /* CS */ - <3 0 &gpio1 15 0>, /* SCK */ - <4 0 &gpio1 14 0>, /* MISO */ - <5 0 &gpio1 13 0>, /* MOSI */ - /* +3.3V */ - /* GND */ - <6 0 &gpio1 7 0>, /* PWM */ - <7 0 &gpio1 4 0>, /* INT */ - <8 0 &gpio1 0 0>, /* RX */ - <9 0 &gpio1 1 0>, /* TX */ - <10 0 &gpio1 3 0>, /* SCL */ - <11 0 &gpio1 2 0>; /* SDA */ - /* +5V */ - /* GND */ - }; - - arduino_header: connector { - compatible = "arduino-header-r3"; - #gpio-cells = <2>; - gpio-map-mask = <0xffffffff 0xffffffc0>; - gpio-map-pass-thru = <0 0x3f>; - gpio-map = <0 0 &gpio0 4 0>, /* A0 */ - <1 0 &gpio0 5 0>, /* A1 */ - <2 0 &gpio0 6 0>, /* A2 */ - <3 0 &gpio0 7 0>, /* A3 */ - <4 0 &gpio0 25 0>, /* A4 */ - <5 0 &gpio0 26 0>, /* A5 */ - <6 0 &gpio1 0 0>, /* D0 */ - <7 0 &gpio1 1 0>, /* D1 */ - <8 0 &gpio1 4 0>, /* D2 */ - <9 0 &gpio1 5 0>, /* D3 */ - <10 0 &gpio1 6 0>, /* D4 */ - <11 0 &gpio1 7 0>, /* D5 */ - <12 0 &gpio1 8 0>, /* D6 */ - <13 0 &gpio1 9 0>, /* D7 */ - <14 0 &gpio1 10 0>, /* D8 */ - <15 0 &gpio1 11 0>, /* D9 */ - <16 0 &gpio1 12 0>, /* D10 */ - <17 0 &gpio1 13 0>, /* D11 */ - <18 0 &gpio1 14 0>, /* D12 */ - <19 0 &gpio1 15 0>, /* D13 */ - <20 0 &gpio1 2 0>, /* D14 */ - <21 0 &gpio1 3 0>; /* D15 */ - }; - - /* These aliases are provided for compatibility with samples */ - aliases { - led0 = &evb_led1; - led1 = &evb_led2; - led2 = &evb_led3; - led3 = &evb_led4; - sw0 = &evb_sw1; - sw1 = &evb_sw2; - sw2 = &evb_sw3; - sw3 = &evb_sw4; - bootloader-led0 = &evb_led1; - mcuboot-button0 = &evb_sw1; - mcuboot-led0 = &evb_led1; - watchdog0 = &wdt0; - }; -}; - -&gpiote { - status = "okay"; -}; - -&gpio0 { - status = "okay"; -}; - -&gpio1 { - status = "okay"; -}; - -&uart0 { - status = "disabled"; - current-speed = <115200>; - pinctrl-0 = <&uart0_default>; - pinctrl-1 = <&uart0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_serial: &uart0{}; - -arduino_i2c: &i2c0 { - compatible = "nordic,nrf-twim"; - /* Cannot be used together with uart0. */ - /* status = "okay"; */ - pinctrl-0 = <&i2c0_default>; - pinctrl-1 = <&i2c0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -arduino_spi: &spi0 { - compatible = "nordic,nrf-spim"; - /* Cannot be used together with uart0. */ - /* status = "okay"; */ - cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - pinctrl-0 = <&spi0_default>; - pinctrl-1 = <&spi0_sleep>; - pinctrl-names = "default", "sleep"; -}; - -&flash1 { - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0xc000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x17000>; - }; - slot1_partition: partition@23000 { - label = "image-1"; - reg = <0x00023000 0x17000>; - }; - storage_partition: partition@3a000 { - label = "storage"; - reg = <0x0003a000 0x6000>; - }; - }; -}; - -&ieee802154 { - status = "okay"; -}; - -/* Include shared RAM configuration file */ -#include "pan1783_evb_shared_sram_planning_conf.dtsi" diff --git a/boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c b/boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c deleted file mode 100644 index 5b30492a1f9..00000000000 --- a/boards/arm/pan1783_evb/pan1783_evb_cpunet_reset.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023 Panasonic Industrial Devices Europe GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include -#include - -LOG_MODULE_REGISTER(pan1783_evb_cpuapp, CONFIG_LOG_DEFAULT_LEVEL); - -#if defined(CONFIG_BT_CTLR_DEBUG_PINS_CPUAPP) -#include <../subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/debug.h> -#else -#define DEBUG_SETUP() -#endif - -static void remoteproc_mgr_config(void) -{ - /* Route Bluetooth Controller Debug Pins */ - DEBUG_SETUP(); - - /* Retain nRF5340 Network MCU */ - NRF_SPU->EXTDOMAIN[0].PERM = 1 << 4; -} - -static int remoteproc_mgr_boot(void) -{ - /* Configure permissions for the Network MCU. */ - remoteproc_mgr_config(); - - /* Release the Network MCU, 'Release force off signal' */ - nrf_reset_network_force_off(NRF_RESET, false); - - LOG_DBG("Network MCU released."); - - return 0; -} - -SYS_INIT(remoteproc_mgr_boot, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/boards/arm/pandora_stm32l475/doc/index.rst b/boards/arm/pandora_stm32l475/doc/index.rst index 62a903faf78..76da038e9ec 100644 --- a/boards/arm/pandora_stm32l475/doc/index.rst +++ b/boards/arm/pandora_stm32l475/doc/index.rst @@ -136,7 +136,7 @@ Connections and IOs STM32L475 Pandora Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L475 Pandora board User Manual`_. +For more details please refer to `STM32L475 Pandora board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts index 67d7124dcb0..1c28f6c8176 100644 --- a/boards/arm/pandora_stm32l475/pandora_stm32l475.dts +++ b/boards/arm/pandora_stm32l475/pandora_stm32l475.dts @@ -79,11 +79,10 @@ pinctrl-names = "default"; status = "okay"; - w25q128jv: qspi-nor-flash@0 { + w25q128jv: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <80000000>; - size = <0x8000000>; jedec-id = [ef 40 18]; spi-bus-width = <4>; status = "okay"; diff --git a/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts b/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts index 19f9e6ff41e..b50c526be4c 100644 --- a/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts +++ b/boards/arm/pinnacle_100_dvk/pinnacle_100_dvk.dts @@ -81,6 +81,7 @@ mcuboot-button0 = &button1; mcuboot-led0 = &led1; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/qemu_cortex_m0/Kconfig.defconfig b/boards/arm/qemu_cortex_m0/Kconfig.defconfig index 8aa63a89a57..3f203f2adbc 100644 --- a/boards/arm/qemu_cortex_m0/Kconfig.defconfig +++ b/boards/arm/qemu_cortex_m0/Kconfig.defconfig @@ -17,7 +17,4 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC config SYS_CLOCK_TICKS_PER_SEC default 100 -config LOG_BUFFER_SIZE - default 128 if LOG - endif # BOARD_QEMU_CORTEX_M0 diff --git a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig index f179e667d6b..fb5a6b85630 100644 --- a/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53_db_40_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53_DB_40_NRF5340_CPUAPP_NS diff --git a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig index 10f4373b352..fd3e5210d28 100644 --- a/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig +++ b/boards/arm/raytac_mdbt53v_db_40_nrf5340/Kconfig.defconfig @@ -73,7 +73,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC endif # BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP || BOARD_RAYTAC_MDBT53V_DB_40_NRF5340_CPUAPP_NS diff --git a/boards/arm/rcar_spider/Kconfig.board b/boards/arm/rcar_spider/Kconfig.board new file mode 100644 index 00000000000..1ff4c7e794d --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RCAR_SPIDER_CR52 + bool "Cortex-R52 for Renesas Spider" + depends on SOC_R8A779F0 diff --git a/boards/arm/rcar_spider/Kconfig.defconfig b/boards/arm/rcar_spider/Kconfig.defconfig new file mode 100644 index 00000000000..b2a590250f9 --- /dev/null +++ b/boards/arm/rcar_spider/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_RCAR_SPIDER_CR52 + +config BOARD + default "rcar_spider_cr52" + +endif # BOARD_RCAR_SPIDER_CR52 diff --git a/boards/arm/rcar_spider/board.cmake b/boards/arm/rcar_spider/board.cmake new file mode 100644 index 00000000000..b106c562c54 --- /dev/null +++ b/boards/arm/rcar_spider/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(openocd "--use-elf") +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg b/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg new file mode 100644 index 00000000000..76bda515cfb Binary files /dev/null and b/boards/arm/rcar_spider/doc/img/rcar_s4_block_diagram.jpg differ diff --git a/boards/arm/rcar_spider/doc/img/rcar_s4_spider_full.jpg b/boards/arm/rcar_spider/doc/img/rcar_s4_spider_full.jpg new file mode 100644 index 00000000000..7956f18c44d Binary files /dev/null and b/boards/arm/rcar_spider/doc/img/rcar_s4_spider_full.jpg differ diff --git a/boards/arm/rcar_spider/doc/rcar_spider.rst b/boards/arm/rcar_spider/doc/rcar_spider.rst new file mode 100644 index 00000000000..33deb1f27a8 --- /dev/null +++ b/boards/arm/rcar_spider/doc/rcar_spider.rst @@ -0,0 +1,200 @@ +.. _rcar_spider_boards: + +Renesas R-Car Spider +#################### + +Overview +******** + +| R-Car S4 enables the launch of Car Server/CoGW with high performance, high-speed networking, +| high security and high functional safety levels that are required as E/E architectures +| evolve into domains and zones. + +| The R-Car S4 solution allows designers to re-use up to 88 percent of software code developed +| for 3rd generation R-Car SoCs and RH850 MCU applications.\ +| The software package supports the real-time cores with various drivers and basic software +| such as Linux BSP and hypervisors. + +The Renesas R-Car Spider board is the Renesas R-Car S4 reference board and is designed for +evaluating features and performance of this SoC. + +.. figure:: img/rcar_s4_spider_full.jpg + :align: center + :alt: R-Car S4 Spider + +More information about the board can be found at `Renesas R-Car S4 Spider`_ website. + +Hardware +******** + +Hardware capabilities for the S4 Spider board can be found on the `eLinux S4 Spider`_ page. + +.. figure:: img/rcar_s4_block_diagram.jpg + :align: center + :alt: R-Car S4 Spider block diagram + +.. note:: We support Zephyr running on the CR52 processor that is provided for RTOS purpose. + +More information about the SoC that equips the board can be found here: + +- `Renesas R-Car S4 chip`_ + +Supported Features +================== + +Here are the current supported features when running Zephyr Project on the R-Car S4 Spider CR52: + ++-----------+------------------------------+--------------------------------+ +| Interface | Driver/components | Support level | ++===========+==============================+================================+ +| PINMUX | pinmux | | ++-----------+------------------------------+--------------------------------+ +| CLOCK | clock_control | | ++-----------+------------------------------+--------------------------------+ +| GPIO | gpio | | ++-----------+------------------------------+--------------------------------+ +| UART | uart | serial port-polling | ++ + + + +| | FT232RQ | serial port-interrupt | ++-----------+------------------------------+--------------------------------+ +| I2C | i2c | interrupt driven | ++-----------+------------------------------+--------------------------------+ +| PWM | pwm | All channels | ++-----------+------------------------------+--------------------------------+ + +It is also currently possible to write on the ram console. + +More features will be supported soon. + +Connections and IOs +=================== + +| The "Spider board" consists of a CPU board and a Breakout board. +| The CPU board is stuck on top of the Breakout board. + +Here are the official IOs figures from eLinux for S4 board: + +`S4 Spider CPU board IOs`_ + +`S4 Spider breakout board IOs`_ + +GPIO +---- + +By running Zephyr on S4 Spider, the software controllable LED 'LED8' can be used as output. + +UART +---- + +Here is information about both serial ports provided on the S4 Spider board : + ++--------------------+----------+--------------------+-------------+------------------------+ +| Physical Interface | Location | Software Interface | Converter | Further Information | ++====================+==========+====================+=============+========================+ +| CN20 USB Port | CPU Board| SCIF0/HSCIF1 | FT232HQ | Default Zephyr serial | ++--------------------+----------+--------------------+-------------+------------------------+ +| CN21 USB Port | CPU Board| SCIF3/HSCIF0 | FT2232H-56Q | Used by U-BOOT & Linux | ++--------------------+----------+--------------------+-------------+------------------------+ + +.. note:: + The Zephyr console output is assigned to SCIF0 (CN20 USB Port) with settings: + 115200 8N1 without hardware flow control by default. + +I2C +--- + +I2C is mainly used to manage and power-on some onboard chips on the S4 Spider board. + +Embedded I2C devices and I/O expanders are not yet supported. +The current I2C support therefore does not make any devices available to the user at this time. + +Programming and Debugging +************************* + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +Supported Debug Probe +===================== + +| The "Olimex ARM-USB-OCD-H" probe is the only officially supported probe. +| This probe is supported by OpenOCD that is shipped with the Zephyr SDK. + +The "Olimex ARM-USB-OCD-H" probe needs to be connected with a "Coresight 20 pins" +adapter to CN1 connector on Spider board. + +Configuring a Console +===================== + +Connect a USB cable from your PC to CN20 USB port of your Spider board. + +Use the following settings with your serial terminal of choice (minicom, putty, +etc.): + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Flashing +======== + +First of all, open your serial terminal. + +Applications for the ``rcar_spider_cr52`` board configuration can be built in the +usual way (see :ref:`build_an_application` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: flash + +You should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +Debugging +========= + +First of all, open your serial terminal. + +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: rcar_spider_cr52 + :goals: debug + +You will then get access to a GDB session for debugging. + +By continuing the app, you should see the following message in the terminal: + +.. code-block:: console + + *** Booting Zephyr OS build v3.3.0-rc2 *** + Hello World! rcar_spider_cr52 + +References +********** + +- `Renesas R-Car S4 Spider`_ +- `Renesas R-Car S4 chip`_ +- `eLinux S4 Spider`_ + +.. _Renesas R-Car S4 Spider: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/rtp8a779f0askb0sp2s-r-car-s4-reference-boardspider + +.. _Renesas R-Car S4 chip: + https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway + +.. _eLinux S4 Spider: + https://elinux.org/R-Car/Boards/Spider + +.. _S4 Spider CPU board IOs: + https://elinux.org/images/6/6d/Rcar_s4_spider_cpu_board.jpg + +.. _S4 Spider breakout board IOs: + https://elinux.org/images/2/29/Rcar_s4_spider_breakout_board.jpg diff --git a/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi new file mode 100644 index 00000000000..b164961271a --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52-pinctrl.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pfc { + scif0_data_tx_default: scif0_data_tx_default { + pin = ; + }; + + scif0_data_rx_default: scif0_data_rx_default { + pin = ; + }; + + scif3_data_tx_default: scif3_data_tx_default { + pin = ; + }; + + scif3_data_rx_default: scif3_data_rx_default { + pin = ; + }; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.dts b/boards/arm/rcar_spider/rcar_spider_cr52.dts new file mode 100644 index 00000000000..6d89b3ede94 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.dts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/dts-v1/; +#include +#include "rcar_spider_cr52-pinctrl.dtsi" +#include + +/ { + model = "Renesas Spider board"; + compatible = "renesas,spider-cr52"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &scif0; + zephyr,shell-uart = &scif0; + }; + + leds { + compatible = "gpio-leds"; + user_led: led_8 { + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + label = "User LED"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: sw10 { + gpios = <&gpio4 13 GPIO_ACTIVE_LOW>; + label = "User switch"; + zephyr,code = ; + }; + }; + + aliases { + led0 = &user_led; + sw0 = &user_button; + }; +}; + +&scif0 { + pinctrl-0 = <&scif0_data_tx_default &scif0_data_rx_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio4 { + status = "okay"; +}; diff --git a/boards/arm/rcar_spider/rcar_spider_cr52.yaml b/boards/arm/rcar_spider/rcar_spider_cr52.yaml new file mode 100644 index 00000000000..6dea2b344b7 --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52.yaml @@ -0,0 +1,11 @@ +identifier: rcar_spider_cr52 +name: Cortex r52 for Renesas Spider +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio + - clock_control + - uart diff --git a/boards/arm/rcar_spider/rcar_spider_cr52_defconfig b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig new file mode 100644 index 00000000000..7eea72fd80a --- /dev/null +++ b/boards/arm/rcar_spider/rcar_spider_cr52_defconfig @@ -0,0 +1,13 @@ +CONFIG_SOC_R8A779F0=y +CONFIG_SOC_SERIES_RCAR_GEN4=y +CONFIG_BOARD_RCAR_SPIDER_CR52=y +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=12500000 +CONFIG_CONSOLE=y +CONFIG_RAM_CONSOLE=y +CONFIG_FLASH_SIZE=0 +CONFIG_FLASH_BASE_ADDRESS=0 +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_GPIO=y diff --git a/boards/arm/rcar_spider/support/openocd.cfg b/boards/arm/rcar_spider/support/openocd.cfg new file mode 100644 index 00000000000..518b63c7f48 --- /dev/null +++ b/boards/arm/rcar_spider/support/openocd.cfg @@ -0,0 +1,27 @@ +# Renesas R-Car Spider S4 Cortex-R52 Board Config + +source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg] +source [find target/renesas_rcar_reset_common.cfg] + +set _CHIPNAME r8a779f0 +set _CORE_NAME r52 +set _TARGETNAME $_CHIPNAME.$_CORE_NAME +set _CTINAME $_TARGETNAME.cti +set _DAPNAME $_CHIPNAME.dap +set DAP_TAPID 0x5ba00477 + +set CR52_DBGBASE 0x80c10000 +set CR52_CTIBASE 0x80c20000 + +adapter srst delay 1000 +adapter speed 20000 +global $_CHIPNAME +transport select jtag + +jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $DAP_TAPID +dap create $_DAPNAME -chain-position $_CHIPNAME.cpu + +cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $CR52_CTIBASE +target create $_TARGETNAME armv8r -dap $_DAPNAME -ap-num 1 -dbgbase $CR52_DBGBASE -cti $_CTINAME + +$_TARGETNAME configure -rtos auto diff --git a/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi b/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi index e1b4c3f971a..5d560f26154 100644 --- a/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi +++ b/boards/arm/rddrone_fmuk66/rddrone_fmuk66-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MK66FN2M0VMD18/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/rpi_pico/board.cmake b/boards/arm/rpi_pico/board.cmake index 07a128fad7b..e9cd4edc18f 100644 --- a/boards/arm/rpi_pico/board.cmake +++ b/boards/arm/rpi_pico/board.cmake @@ -27,8 +27,10 @@ board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 2000") board_runner_args(jlink "--device=RP2040_M0_0") board_runner_args(uf2 "--board-id=RPI-RP2") +board_runner_args(pyocd "--target=rp2040") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst index c94698f14fe..f535d85506a 100644 --- a/boards/arm/rpi_pico/doc/index.rst +++ b/boards/arm/rpi_pico/doc/index.rst @@ -89,6 +89,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` diff --git a/boards/arm/rpi_pico/rpi_pico-common.dtsi b/boards/arm/rpi_pico/rpi_pico-common.dtsi index 54f12e53843..95a27d3a009 100644 --- a/boards/arm/rpi_pico/rpi_pico-common.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-common.dtsi @@ -23,12 +23,6 @@ zephyr,code-partition = &code_partition; }; - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; - }; - aliases { watchdog0 = &wdt0; }; @@ -94,6 +88,11 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + &uart0 { current-speed = <115200>; status = "okay"; @@ -112,6 +111,13 @@ pinctrl-names = "default"; }; +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "disabled"; + clock-frequency = ; +}; + &spi0 { clock-frequency = ; status = "okay"; @@ -149,3 +155,5 @@ zephyr_udc0: &usbd { }; pico_spi: &spi0 {}; +pico_i2c0: &i2c0 {}; +pico_i2c1: &i2c1 {}; diff --git a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi index 93790191e6e..761354420c6 100644 --- a/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi +++ b/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi @@ -24,6 +24,14 @@ }; }; + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + spi0_default: spi0_default { group1 { pinmux = , , ; @@ -46,4 +54,7 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; }; diff --git a/boards/arm/rpi_pico/rpi_pico.yaml b/boards/arm/rpi_pico/rpi_pico.yaml index 485cfde0db5..ada56d84480 100644 --- a/boards/arm/rpi_pico/rpi_pico.yaml +++ b/boards/arm/rpi_pico/rpi_pico.yaml @@ -20,3 +20,4 @@ supported: - flash - dma - counter + - clock diff --git a/boards/arm/rpi_pico/rpi_pico_defconfig b/boards/arm/rpi_pico/rpi_pico_defconfig index 2a276892119..111edceb147 100644 --- a/boards/arm/rpi_pico/rpi_pico_defconfig +++ b/boards/arm/rpi_pico/rpi_pico_defconfig @@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y CONFIG_BUILD_OUTPUT_HEX=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/rpi_pico/rpi_pico_w.yaml b/boards/arm/rpi_pico/rpi_pico_w.yaml index 32bf9ef078f..d0acab19cc6 100644 --- a/boards/arm/rpi_pico/rpi_pico_w.yaml +++ b/boards/arm/rpi_pico/rpi_pico_w.yaml @@ -20,3 +20,5 @@ supported: - flash - dma - pio + - counter + - clock diff --git a/boards/arm/rpi_pico/rpi_pico_w_defconfig b/boards/arm/rpi_pico/rpi_pico_w_defconfig index a0355614197..9b3868541d1 100644 --- a/boards/arm/rpi_pico/rpi_pico_w_defconfig +++ b/boards/arm/rpi_pico/rpi_pico_w_defconfig @@ -11,3 +11,4 @@ CONFIG_BUILD_OUTPUT_UF2=y CONFIG_BUILD_OUTPUT_HEX=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/rzt2m_starterkit/doc/index.rst b/boards/arm/rzt2m_starterkit/doc/index.rst index e965585f6cb..72dc6615f64 100644 --- a/boards/arm/rzt2m_starterkit/doc/index.rst +++ b/boards/arm/rzt2m_starterkit/doc/index.rst @@ -1,7 +1,7 @@ .. _rzt2m_starterkit: Renesas Starter Kit+ for RZ/T2M -=============================== +############################### Overview ******** @@ -22,6 +22,7 @@ Hardware The board utilizes the SoC of part no. R9A07G075M24GBG, with 2MB of RAM. It has several on-board memory components: + * SDRAM (256MBit), * NOR Flash (256MBit), * Octa Flash (512MBit), @@ -30,6 +31,7 @@ It has several on-board memory components: * I2C EEPROM (32Kbit). The communication interfaces include: + * Debug interfaces (J-Link, MIPI-10, MIPI-20), * Ethernet, * CAN, @@ -62,6 +64,7 @@ Connections and IOs =================== By default, the board is configured for use with: + * UART0 connected to the USB serial port (pins K18, K19), * UART3 connected to the PMOD Header (J25, pins H16, G20), * LEDs defined as `led0`, `led1`, `led2` and `led3`, diff --git a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts index 2568a542b5e..6b87455aafe 100644 --- a/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts +++ b/boards/arm/rzt2m_starterkit/rzt2m_starter_kit.dts @@ -6,7 +6,7 @@ /dts-v1/; #include -#include +#include / { model = "RZT/2M Starter Kit"; diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml index 063ea90c351..481ce3e63b2 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu0_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu0_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU0 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml index 70a37261c8e..9f0a55547c1 100644 --- a/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml +++ b/boards/arm/s32z270dc2_r52/s32z270dc2_rtu1_r52_D.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: s32z270dc2_rtu1_r52@D -name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores +name: NXP X-S32Z270-DC (DC2) on RTU1 Cortex-R52 cores (rev. D) type: mcu arch: arm ram: 1024 diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi b/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi index 2007cbe95b8..e41db2f1c55 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained-pinctrl.dtsi @@ -83,6 +83,27 @@ }; }; + tc1_qdec_default: tc1_qdec_default { + group1 { + pinmux = , + ; + }; + }; + + tc2_qdec_default: tc2_qdec_default { + group1 { + pinmux = , + ; + }; + }; + + tc3_qdec_default: tc3_qdec_default { + group1 { + pinmux = , + ; + }; + }; + twihs0_default: twihs0_default { group1 { pinmux = , diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts index 968b19e7562..ee002c846fa 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained.dts +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained.dts @@ -23,3 +23,27 @@ pinctrl-0 = <&tc0_qdec_default>; pinctrl-names = "default"; }; + +&tc1 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc1_qdec_default>; + pinctrl-names = "default"; +}; + +&tc2 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc2_qdec_default>; + pinctrl-names = "default"; +}; + +&tc3 { + status = "disabled"; + compatible = "atmel,sam-tc-qdec"; + + pinctrl-0 = <&tc3_qdec_default>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/scobc_module1/scobc_module1.dts b/boards/arm/scobc_module1/scobc_module1.dts index 1cfa73bc91b..3f704e1113d 100644 --- a/boards/arm/scobc_module1/scobc_module1.dts +++ b/boards/arm/scobc_module1/scobc_module1.dts @@ -31,7 +31,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/scobc_module1/scobc_module1_defconfig b/boards/arm/scobc_module1/scobc_module1_defconfig index 8ec2b679557..ecadcfc07bd 100644 --- a/boards/arm/scobc_module1/scobc_module1_defconfig +++ b/boards/arm/scobc_module1/scobc_module1_defconfig @@ -14,4 +14,3 @@ CONFIG_UART_CONSOLE=y CONFIG_XIP=n CONFIG_FLASH_SIZE=0 CONFIG_FLASH_BASE_ADDRESS=0x0 -CONFIG_BOOTLOADER_SRAM_SIZE=0 diff --git a/boards/arm/sensortile_box/Kconfig.defconfig b/boards/arm/sensortile_box/Kconfig.defconfig index 4287849bf31..1f3d19b39ca 100644 --- a/boards/arm/sensortile_box/Kconfig.defconfig +++ b/boards/arm/sensortile_box/Kconfig.defconfig @@ -8,11 +8,27 @@ if BOARD_SENSORTILE_BOX config BOARD default "sensortile_box" -if SPI +if BT -config SPI_STM32_INTERRUPT +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI default y +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n +config BT_HCI_VS_EXT + default n -endif # SPI +endif # BT + +config SPI_STM32_INTERRUPT + default y + depends on SPI endif # BOARD_SENSORTILE_BOX diff --git a/boards/arm/sensortile_box/sensortile_box.dts b/boards/arm/sensortile_box/sensortile_box.dts index e622d5c190f..4c5a9654b3d 100644 --- a/boards/arm/sensortile_box/sensortile_box.dts +++ b/boards/arm/sensortile_box/sensortile_box.dts @@ -161,6 +161,23 @@ }; }; +&spi2 { + pinctrl-0 = <&spi2_sck_pd1 &spi2_miso_pd3 &spi2_mosi_pc3>; + pinctrl-names = "default"; + status = "okay"; + cs-gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; + spbtle_1s_sensortile_box: spbtle-1s@0 { + compatible = "st,hci-spi-v2"; + reg = <0>; + reset-gpios = <&gpioa 8 GPIO_ACTIVE_LOW>; + irq-gpios = <&gpiod 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + spi-max-frequency = ; + spi-cpha; + spi-hold-cs; + reset-assert-duration-ms = <6>; + }; +}; + &spi3 { pinctrl-0 = <&spi3_nss_pa15 &spi3_sck_pb3 &spi3_miso_pb4 &spi3_mosi_pb5>; diff --git a/boards/arm/sensortile_box/sensortile_box.yaml b/boards/arm/sensortile_box/sensortile_box.yaml index e67e105021b..aaa655bf84c 100644 --- a/boards/arm/sensortile_box/sensortile_box.yaml +++ b/boards/arm/sensortile_box/sensortile_box.yaml @@ -9,6 +9,7 @@ toolchain: supported: - pwm - spi + - ble - i2c - gpio - usb device diff --git a/boards/arm/sensortile_box_pro/Kconfig.defconfig b/boards/arm/sensortile_box_pro/Kconfig.defconfig index e37f5e4f5bf..48b55275be3 100644 --- a/boards/arm/sensortile_box_pro/Kconfig.defconfig +++ b/boards/arm/sensortile_box_pro/Kconfig.defconfig @@ -8,6 +8,24 @@ if BOARD_SENSORTILE_BOX_PRO config BOARD default "sensortile_box_pro" +if BT + +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI + default y + +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + config SPI_STM32_INTERRUPT default y depends on SPI diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts index 485ec6b6e7d..8c159eb831f 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.dts +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.dts @@ -130,7 +130,7 @@ apb3-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; @@ -158,10 +158,28 @@ }; &spi1 { - pinctrl-0 = <&spi1_nss_pe12 &spi1_sck_pe13 - &spi1_miso_pe14 &spi1_mosi_pe15>; + pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>; pinctrl-names = "default"; + cs-gpios = <&gpioa 2 GPIO_ACTIVE_LOW>; status = "okay"; + + bluenrg-lp@0 { + compatible = "st,hci-spi-v2"; + reg = <0>; + irq-gpios = <&gpiod 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; + reset-gpios = <&gpiod 4 GPIO_ACTIVE_LOW>; + spi-cpol; + spi-cpha; + spi-hold-cs; + spi-max-frequency = ; + controller-data-delay-us = <0>; + reset-assert-duration-ms = <6>; + }; +}; + +&spi1_sck_pa5 { + /delete-property/ bias-pull-down; + bias-pull-up; /* Idle state for the clock pin is high-level due to SPI mode 3 */ }; &spi2 { @@ -169,17 +187,27 @@ pinctrl-names = "default"; status = "okay"; - cs-gpios = <&gpioi 5 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpioi 5 GPIO_ACTIVE_LOW>, <&gpioi 7 GPIO_ACTIVE_LOW>; lsm6dsv16x: lsm6dsv16x@0 { compatible = "st,lsm6dsv16x"; - spi-max-frequency = ; /* 10 MHz */ + spi-max-frequency = ; reg = <0>; int1-gpios = <&gpioa 4 GPIO_ACTIVE_HIGH>; int2-gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>; drdy-pin = <2>; }; + + lis2du12: lis2du12@1 { + compatible = "st,lis2du12"; + spi-max-frequency = ; + reg = <1>; + int1-gpios = <&gpiof 2 GPIO_ACTIVE_HIGH>; + int2-gpios = <&gpiof 15 GPIO_ACTIVE_HIGH>; + + drdy-pin = <2>; + }; }; &timers4 { diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml index da81ee182e1..14624c77f7d 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro.yaml @@ -9,6 +9,7 @@ toolchain: supported: - pwm - spi + - ble - i2c - gpio - usb device diff --git a/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig index a75aad1dad5..7a91dc1c195 100644 --- a/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig +++ b/boards/arm/sensortile_box_pro/sensortile_box_pro_defconfig @@ -32,6 +32,3 @@ CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst b/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst index 1999d64def7..3fa4fe40b71 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst +++ b/boards/arm/sparkfun_pro_micro_rp2040/doc/index.rst @@ -79,6 +79,9 @@ hardware features: * - Flash - :kconfig:option:`CONFIG_FLASH` - :dtcompatible:`raspberrypi,pico-flash` + * - Clock controller + - :kconfig:option:`CONFIG_CLOCK_CONTROL` + - :dtcompatible:`raspberrypi,pico-clock-controller` * - UART (PIO) - :kconfig:option:`CONFIG_SERIAL` - :dtcompatible:`raspberrypi,pico-uart-pio` diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi index 64f3ab61e5f..3bca8b4f384 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040-pinctrl.dtsi @@ -46,4 +46,7 @@ input-enable; }; }; + + clocks_default: clocks_default { + }; }; diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts index 1bd5e226e2a..1d92bcf1cba 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.dts @@ -23,12 +23,6 @@ aliases { watchdog0 = &wdt0; }; - - xtal_clk: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <12000000>; - #clock-cells = <0>; - }; }; &flash0 { @@ -62,6 +56,10 @@ }; }; +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; &uart0 { current-speed = <115200>; diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml index d5993798ff4..a2a8932d78f 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040.yaml @@ -19,3 +19,5 @@ supported: - pwm - flash - dma + - counter + - clock diff --git a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig index 4ec1c6cad43..36aba349204 100644 --- a/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig +++ b/boards/arm/sparkfun_pro_micro_rp2040/sparkfun_pro_micro_rp2040_defconfig @@ -15,6 +15,9 @@ CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y +# Enable clock control by default +CONFIG_CLOCK_CONTROL=y + # Code partition needed to target the correct flash range CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/arm/stm32f072_eval/doc/index.rst b/boards/arm/stm32f072_eval/doc/index.rst index 4872f85785b..49b6577935c 100644 --- a/boards/arm/stm32f072_eval/doc/index.rst +++ b/boards/arm/stm32f072_eval/doc/index.rst @@ -110,7 +110,7 @@ Pin Mapping STM32F072-EVAL Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to STM32F072-EVAL board User Manual. +For more details please refer to STM32F072-EVAL board User Manual. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f072b_disco/doc/index.rst b/boards/arm/stm32f072b_disco/doc/index.rst index 3756926ec4c..a2c51e51cdd 100644 --- a/boards/arm/stm32f072b_disco/doc/index.rst +++ b/boards/arm/stm32f072b_disco/doc/index.rst @@ -108,7 +108,7 @@ Pin Mapping STM32F072B-DISCO Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F072B-DISCO board User Manual`_. +For more details please refer to `STM32F072B-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f0_disco/doc/index.rst b/boards/arm/stm32f0_disco/doc/index.rst index e2910793d72..daf0e1f06d3 100644 --- a/boards/arm/stm32f0_disco/doc/index.rst +++ b/boards/arm/stm32f0_disco/doc/index.rst @@ -89,7 +89,7 @@ Default Zephyr Peripheral Mapping: - UART_2_TX : PA2 - UART_2_RX : PA3 -For mode details please refer to `STM32F0DISCOVERY board User Manual`_. +For more details please refer to `STM32F0DISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32f3_disco/doc/index.rst b/boards/arm/stm32f3_disco/doc/index.rst index a94083fa2c7..5a0dc214e06 100644 --- a/boards/arm/stm32f3_disco/doc/index.rst +++ b/boards/arm/stm32f3_disco/doc/index.rst @@ -123,7 +123,7 @@ Pin Mapping STM32F3DISCOVERY Discovery kit has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F3DISCOVERY board User Manual`_. +For more details please refer to `STM32F3DISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f3_seco_d23/Kconfig.board b/boards/arm/stm32f3_seco_d23/Kconfig.board index d745a9ce8d0..94536f8f05e 100644 --- a/boards/arm/stm32f3_seco_d23/Kconfig.board +++ b/boards/arm/stm32f3_seco_d23/Kconfig.board @@ -1,8 +1,8 @@ -# SECO SBC-D23 board configuration +# SECO SBC-3.5-PX30 board configuration # Copyright (c) 2022, SECO Spa # SPDX-License-Identifier: Apache-2.0 config BOARD_STM32F3_SECO_D23 - bool "SECO JUNO SBC-D23 (STM32F302VC) Board" + bool "SECO SBC-3.5-PX30 (STM32F302VC) Board" depends on SOC_STM32F302XC diff --git a/boards/arm/stm32f3_seco_d23/Kconfig.defconfig b/boards/arm/stm32f3_seco_d23/Kconfig.defconfig index f83d9615416..4af3bbc0022 100644 --- a/boards/arm/stm32f3_seco_d23/Kconfig.defconfig +++ b/boards/arm/stm32f3_seco_d23/Kconfig.defconfig @@ -1,4 +1,4 @@ -# SECO SBC-D23 board configuration +# SECO SBC-3.5-PX30 board configuration # Copyright (c) 2022, SECO Spa # SPDX-License-Identifier: Apache-2.0 diff --git a/boards/arm/stm32f3_seco_d23/doc/index.rst b/boards/arm/stm32f3_seco_d23/doc/index.rst index 9b500e372ff..90981205b5b 100644 --- a/boards/arm/stm32f3_seco_d23/doc/index.rst +++ b/boards/arm/stm32f3_seco_d23/doc/index.rst @@ -1,12 +1,12 @@ .. _stm32f3_seco_d23_board: -SECO JUNO SBC-D23 (STM32F302) -############################# +SECO SBC-3.5-PX30 (JUNO - D23) (STM32F302) +########################################## Overview ******** -JUNO (SBC-D23) is a Single Board Computer based on embedded Rockchip PX30 +SBC-3.5-PX30 (JUNO - D23) is a Single Board Computer based on embedded Rockchip PX30 Processor, featuring Quad-Core ARM Cortex-A35 processor. The processor integrates a Mali-G31 GPU with High performance dedicated 2D processor, supporting OpenGL ES 1.1 / 2.0 / 3.2, Vulkan 1.0, OpenCL 2.0 and Open VG 1.1. @@ -18,20 +18,20 @@ HDMI are supported. The RMII interface and Micrel KSZ8091 Ethernet Transceiver allow the implementation of a Fast Ethernet interface. The networking capabilities can be extended by WiFi+BT M.2 module and external modem module. The audio functionalities are managed by the AudioCodec embedded in the RK-809 -PMIC. The JUNO board is completed by a series of connectors with various +PMIC. SBC-3.5-PX30 board is completed by a series of connectors with various interfaces (UART, SPI, I2C) managed by the microcontroller STM32F302VCT6. .. image:: img/stm32f3_seco_d23.jpg :align: center - :alt: SECO JUNO + :alt: SECO SBC-3.5-PX30 More information about the board can be found at the -`SECO JUNO SBC-D23 website`_. +`SECO SBC-3.5-PX30 website`_. Hardware ******** -SECO JUNO SBC-D23 provides the following hardware components: +SECO SBC-3.5-PX30 provides the following hardware components: - STM32F302VCT6 - ARM |reg| 32-bit Cortex |reg| -M4 CPU with FPU @@ -93,10 +93,10 @@ Other hardware features are not yet supported on Zephyr porting. Pin Mapping =========== -SECO-D23 has 6 GPIO controllers. These controllers are +SBC-3.5-PX30 has 6 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `SECO JUNO SBC-D23 board User Manual`_. +For more details please refer to `SECO SBC-3.5-PX30 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -142,14 +142,14 @@ Default Zephyr Peripheral Mapping: System Clock ============ -SECO SBC-D23 System Clock could be driven by internal or external +SECO SBC-3.5-PX30 System Clock could be driven by internal or external oscillator, as well as main PLL clock. By default System clock is driven by PLL clock at 72 MHz, driven by an external oscillator at 8 MHz. Serial Port =========== -SECO SBC-D23 has up to 4 U(S)ARTs. The Zephyr console output +SECO SBC-3.5-PX30 has up to 4 U(S)ARTs. The Zephyr console output is assigned to UART1. Default settings are 115200 8N1. In debug configuration UART1 is connected to the flashing connector CN56. @@ -161,22 +161,22 @@ UART1 (in alternate config) and UART5 are connected to CN32. I2C === -SECO SBC-D23 has up to 2 I2Cs. Both are present in connector CN33. +SECO SBC-3.5-PX30 has up to 2 I2Cs. Both are present in connector CN33. I2C2 is available only on boards where DEBUG serial is not connected. USB === -SECO SBC-D23 has a USB 2.0 full-speed device interface available through +SECO SBC-3.5-PX30 has a USB 2.0 full-speed device interface available through its connector CN31. CAN === -SECO SBC-D23 has an onboard CAN transceiver (TJA1051T), and it is +SECO SBC-3.5-PX30 has an onboard CAN transceiver (TJA1051T), and it is connected to both CN29 and CN30. PD0 is connected to EC_CAN_STBY. SPI === -SECO SBC-D23 has two SPI lines: SPI1 is an internal SPI line connected to the +SECO SBC-3.5-PX30 has two SPI lines: SPI1 is an internal SPI line connected to the main processor (Rockchip PX30) and SPI2 is connected to CN39. Programming and Debugging @@ -189,10 +189,10 @@ Applications for the ``stm32f3_seco_d23`` board configuration can be built and flashed in the usual way (see :ref:`build_an_application` and :ref:`application_run` for more details). -Flashing an application to SECO SBC-D23 -------------------------------------------- +Flashing an application to SECO SBC-3.5-PX30 +-------------------------------------------- -First, connect the SECO SBC-D23 to your host computer using +First, connect the SECO SBC-3.5-PX30 to your host computer using CN56 connector to an ST-Link. The pinout is (1-8): - VDD @@ -219,7 +219,7 @@ Run a serial host program to connect with your board. $ minicom -D /dev/ -Replace with the port where the SBC-D23 board can be +Replace with the port where the SBC-3.5-PX30 board can be found. You should see the following message on the console: @@ -229,10 +229,10 @@ You should see the following message on the console: Hello World! stm32f3_seco_d23 -.. _SECO JUNO SBC-D23 website: - https://edge.seco.com/juno.html +.. _SECO SBC-3.5-PX30 website: + https://edge.seco.com/sbc-3-5-px30.html -.. _SECO JUNO SBC-D23 board User Manual: +.. _SECO SBC-3.5-PX30 board User Manual: https://www.seco.com/Manuals/SBC-D23_Manual.pdf .. _STM32F302VC on www.st.com: diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts index dd100b28865..79577593ddb 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.dts @@ -9,7 +9,7 @@ #include / { - model = "SECO JUNO SBC-D23 board (STM32F302VCT6)"; + model = "SECO SBC-3.5-PX30 board (STM32F302VCT6)"; compatible = "seco,stm32f3-d23"; chosen { diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml index 8ca0b339122..469523eadc2 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23.yaml @@ -1,5 +1,5 @@ identifier: stm32f3_seco_d23 -name: SECO JUNO SBC-D23 (STM32F302) +name: SECO SBC-3.5-PX30 (STM32F302) type: mcu arch: arm toolchain: diff --git a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig index c8038a6da72..344746567ad 100644 --- a/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig +++ b/boards/arm/stm32f3_seco_d23/stm32f3_seco_d23_defconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# SECO SBC-D23 board defconfig +# SECO SBC-3.5-PX30 board defconfig # # Copyright (c) 2022, SECO Spa diff --git a/boards/arm/stm32f3_seco_d23/support/openocd.cfg b/boards/arm/stm32f3_seco_d23/support/openocd.cfg index 69be74a0766..8d66962a35f 100644 --- a/boards/arm/stm32f3_seco_d23/support/openocd.cfg +++ b/boards/arm/stm32f3_seco_d23/support/openocd.cfg @@ -1,4 +1,4 @@ -# SECO JUNO SBC-D23 board with a single STM32F302VCT6 chip +# SECO SBC-3.5-PX30 board with a single STM32F302VCT6 chip # Flashing is possible by connecting the board to an ST-Link via SWD # https://edge.seco.com/juno.html diff --git a/boards/arm/stm32f411e_disco/doc/index.rst b/boards/arm/stm32f411e_disco/doc/index.rst index d15dc7728c7..12a057ff1ad 100644 --- a/boards/arm/stm32f411e_disco/doc/index.rst +++ b/boards/arm/stm32f411e_disco/doc/index.rst @@ -96,7 +96,7 @@ Pin Mapping STM32F411E-DISCO Discovery kit has 5 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F411EDISCOVERY board User Manual`_. +For more details please refer to `32F411EDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f412g_disco/doc/index.rst b/boards/arm/stm32f412g_disco/doc/index.rst index b79f9b18a0a..8bd0bd588f1 100644 --- a/boards/arm/stm32f412g_disco/doc/index.rst +++ b/boards/arm/stm32f412g_disco/doc/index.rst @@ -113,7 +113,7 @@ Pin Mapping STM32F412G-DISCO Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F412GDISCOVERY board User Manual`_. +For more details please refer to `32F412GDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts index e3089dc9d39..a929e3ebe09 100644 --- a/boards/arm/stm32f412g_disco/stm32f412g_disco.dts +++ b/boards/arm/stm32f412g_disco/stm32f412g_disco.dts @@ -147,11 +147,10 @@ pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; }; }; diff --git a/boards/arm/stm32f429i_disc1/board.cmake b/boards/arm/stm32f429i_disc1/board.cmake index 7e8103a64b0..402b28d32c0 100644 --- a/boards/arm/stm32f429i_disc1/board.cmake +++ b/boards/arm/stm32f429i_disc1/board.cmake @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 +board_runner_args(stm32cubeprogrammer "--erase" "--port=swd" "--reset-mode=hw") board_runner_args(jlink "--device=STM32F429ZI" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32f429i_disc1/doc/index.rst b/boards/arm/stm32f429i_disc1/doc/index.rst index 1a8defe5340..9b90abf0dbb 100644 --- a/boards/arm/stm32f429i_disc1/doc/index.rst +++ b/boards/arm/stm32f429i_disc1/doc/index.rst @@ -97,6 +97,8 @@ The Zephyr stm32f429i_disc1 board configuration supports the following hardware +-----------+------------+-------------------------------------+ | FMC | on-chip | memc (SDRAM) | +-----------+------------+-------------------------------------+ +| OTG_HS | on-chip | usbotg_hs | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. @@ -111,7 +113,7 @@ Pin Mapping The STM32F429I-DISC1 Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F429I-DISC1 board User Manual`_. +For more details please refer to `STM32F429I-DISC1 board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -130,6 +132,9 @@ Default Zephyr Peripheral Mapping: - SPI_5_SCK : PF7 - SPI_5_MISO : PF8 - SPI_5_MOSI : PF9 +- OTG_HS_ID : PB12 +- OTG_HS_DM : PB14 +- OTG_HS_DP : PB15 System Clock ============ @@ -144,6 +149,12 @@ Serial Port The STM32F429I-DISC1 Discovery kit has up to 8 UARTs. The Zephyr console output is assigned to UART1. The default communication settings are 115200 8N1. +USB Port +=========== + +The STM32F429I-DISC1 Discovery kit has a USB FS capable Micro-B port. It is connected to the on-chip +OTG_HS peripheral, but operates in FS mode only since no HS PHY is present. The board supports device +and host OTG operation, but only device mode has been tested with Zephyr at this time. Programming and Debugging ************************* @@ -161,6 +172,14 @@ This interface is supported by the openocd version included in Zephyr SDK. Flashing an application to STM32F429I-DISC1 ------------------------------------------- +The board is configured to be flashed using west OpenOCD runner. +Alternatively, you can use `STM32CubeProgrammer`_ (after installing it) using the ``--runner`` +(or ``-r``) option: + +.. code-block:: console + + $ west flash --runner stm32cubeprogrammer + First, connect the STM32F429I-DISC1 Discovery kit to your host computer using the USB port to prepare it for flashing. Then build and flash your application. @@ -206,3 +225,6 @@ You can debug an application in the usual way. Here is an example for the .. _STM32F429 Reference Manual: https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf + +.. _STM32CubeProgrammer: + https://www.st.com/en/development-tools/stm32cubeprog.html diff --git a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts index 60b8c2874f9..cbcc551a716 100644 --- a/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/arm/stm32f429i_disc1/stm32f429i_disc1.dts @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,7 +21,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,ccm = &ccm0; - zephyr,display = &ili9341; + zephyr,display = <dc; }; sdram2: sdram@d0000000 { @@ -62,6 +63,43 @@ invert-x; invert-y; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + spi-dev = <&spi5>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <5625000>; + reg = <0>; + width = <240>; + height = <320>; + rotation = <180>; + pixel-format = ; + pwctrla = [39 2c 00 34 02]; + pwctrlb = [00 c1 30]; + timctrla = [85 00 78]; + timctrlb = [00 00]; + pwseqctrl = [64 03 12 81]; + pumpratioctrl = [20]; + disctrl = [08 82 27 04]; + vmctrl1 = [45 15]; + vmctrl2 = [90]; + enable3g = [00]; + ifctl = [01 00 06]; + ifmode = [c2]; + gamset = [01]; + frmctr1 = [00 1b]; + pwctrl1 = [10]; + pwctrl2 = [10]; + pgamctrl = [0F 29 24 0c 0e 09 4e 78 3c 09 13 05 17 11 00]; + ngamctrl = [00 16 1b 04 11 07 31 33 42 05 0c 0a 28 2f 0f]; + }; + }; }; &clk_lsi { @@ -147,34 +185,6 @@ pinctrl-names = "default"; status = "okay"; cs-gpios = <&gpioc 2 GPIO_ACTIVE_LOW>; - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <5625000>; - reg = <0>; - cmd-data-gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; - width = <240>; - height = <320>; - rotation = <180>; - pixel-format = ; - pwctrla = [39 2c 00 34 02]; - pwctrlb = [00 c1 30]; - timctrla = [85 00 78]; - timctrlb = [00 00]; - pwseqctrl = [64 03 12 81]; - pumpratioctrl = [20]; - disctrl = [08 82 27 04]; - vmctrl1 = [45 15]; - vmctrl2 = [90]; - enable3g = [00]; - ifctl = [01 00 06]; - ifmode = [c2]; - gamset = [01]; - frmctr1 = [00 1b]; - pwctrl1 = [10]; - pwctrl2 = [10]; - pgamctrl = [0F 29 24 0c 0e 09 4e 78 3c 09 13 05 17 11 00]; - ngamctrl = [00 16 1b 04 11 07 31 33 42 05 0c 0a 28 2f 0f]; - }; }; &fmc { @@ -225,6 +235,7 @@ <dc_hsync_pc6 <dc_vsync_pa4>; pinctrl-names = "default"; ext-sdram = <&sdram2>; + display-controller = <&ili9341>; status = "okay"; width = <240>; @@ -247,3 +258,9 @@ def-back-color-green = <0xFF>; def-back-color-blue = <0xFF>; }; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pb14 &usb_otg_hs_dp_pb15 &usb_otg_hs_id_pb12>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/boards/arm/stm32f429i_disc1/support/openocd.cfg b/boards/arm/stm32f429i_disc1/support/openocd.cfg index d1426b667d5..98fed0614df 100644 --- a/boards/arm/stm32f429i_disc1/support/openocd.cfg +++ b/boards/arm/stm32f429i_disc1/support/openocd.cfg @@ -1,4 +1,11 @@ -source [find board/st_nucleo_f4.cfg] +source [find interface/stlink-dap.cfg] + +transport select "dapdirect_swd" + +set CHIPNAME STM32F429ZITx +set BOARDNAME STM32F429I-DISC1 + +source [find target/stm32f4x.cfg] $_TARGETNAME configure -event gdb-attach { echo "Debugger attaching: halting execution" diff --git a/boards/arm/stm32f469i_disco/doc/index.rst b/boards/arm/stm32f469i_disco/doc/index.rst index 7ba1d7c71e3..658f2a7b75e 100644 --- a/boards/arm/stm32f469i_disco/doc/index.rst +++ b/boards/arm/stm32f469i_disco/doc/index.rst @@ -113,7 +113,7 @@ Pin Mapping STM32F469I-DISCO Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F469IDISCOVERY board User Manual`_. +For more details please refer to `32F469IDISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f4_disco/doc/index.rst b/boards/arm/stm32f4_disco/doc/index.rst index 8ea4ef9893c..15dadab7fbf 100644 --- a/boards/arm/stm32f4_disco/doc/index.rst +++ b/boards/arm/stm32f4_disco/doc/index.rst @@ -114,7 +114,7 @@ Pin Mapping STM32F4DISCOVERY Discovery kit has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32F4DISCOVERY board User Manual`_. +For more details please refer to `STM32F4DISCOVERY board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f723e_disco/doc/index.rst b/boards/arm/stm32f723e_disco/doc/index.rst index 5ebcc65c392..c6e34cbbe91 100644 --- a/boards/arm/stm32f723e_disco/doc/index.rst +++ b/boards/arm/stm32f723e_disco/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping STM32F723E Discovery kit has 7 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F723E-DISCO board User Manual`_. +For more details please refer to `32F723E-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f723e_disco/stm32f723e_disco.dts b/boards/arm/stm32f723e_disco/stm32f723e_disco.dts index eed706057f8..4c6641c7f2c 100644 --- a/boards/arm/stm32f723e_disco/stm32f723e_disco.dts +++ b/boards/arm/stm32f723e_disco/stm32f723e_disco.dts @@ -124,11 +124,10 @@ flash-id = <1>; status = "okay"; - mx25r512: qspi-nor-flash@0 { + mx25r512: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <8000000>; - size = ; /* 64 MBytes */ status = "okay"; spi-bus-width = <4>; writeoc = "PP_1_4_4"; diff --git a/boards/arm/stm32f746g_disco/doc/index.rst b/boards/arm/stm32f746g_disco/doc/index.rst index c9b77967be9..714a627ec4a 100644 --- a/boards/arm/stm32f746g_disco/doc/index.rst +++ b/boards/arm/stm32f746g_disco/doc/index.rst @@ -130,7 +130,7 @@ Pin Mapping STM32F746G Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F746G-DISCO board User Manual`_. +For more details please refer to `32F746G-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts index e81172d381b..6250c4e8e80 100644 --- a/boards/arm/stm32f746g_disco/stm32f746g_disco.dts +++ b/boards/arm/stm32f746g_disco/stm32f746g_disco.dts @@ -187,11 +187,10 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/stm32f7508_dk/doc/index.rst b/boards/arm/stm32f7508_dk/doc/index.rst index a3f39f37e5e..699285fcd90 100644 --- a/boards/arm/stm32f7508_dk/doc/index.rst +++ b/boards/arm/stm32f7508_dk/doc/index.rst @@ -125,7 +125,7 @@ Pin Mapping STM32F7508-DK Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F7508-DK board User Manual`_. +For more details please refer to `32F7508-DK board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts index 8102e002863..b98cf5aeed9 100644 --- a/boards/arm/stm32f7508_dk/stm32f7508_dk.dts +++ b/boards/arm/stm32f7508_dk/stm32f7508_dk.dts @@ -183,11 +183,10 @@ zephyr_udc0: &usbotg_fs { pinctrl-names = "default"; status = "okay"; - n25q128a1: qspi-nor-flash@0 { + n25q128a1: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(16)>; /* 128 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { diff --git a/boards/arm/stm32f769i_disco/doc/index.rst b/boards/arm/stm32f769i_disco/doc/index.rst index d2183087b95..203beb6f48a 100644 --- a/boards/arm/stm32f769i_disco/doc/index.rst +++ b/boards/arm/stm32f769i_disco/doc/index.rst @@ -132,7 +132,7 @@ Pin Mapping STM32F769I Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `32F769I-DISCO board User Manual`_. +For more details please refer to `32F769I-DISCO board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts index 0548cf06bd8..feb0f2f11a2 100644 --- a/boards/arm/stm32f769i_disco/stm32f769i_disco.dts +++ b/boards/arm/stm32f769i_disco/stm32f769i_disco.dts @@ -172,11 +172,10 @@ arduino_serial: &usart6 {}; pinctrl-names = "default"; status = "okay"; - mx25l51245g: qspi-nor-flash@0 { + mx25l51245g: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; status = "okay"; partitions { @@ -186,7 +185,7 @@ arduino_serial: &usart6 {}; slot1_partition: partition@0 { label = "image-1"; - reg = <0x00000000 DT_SIZE_K(1664)>; + reg = <0x00000000 DT_SIZE_K(16)>; }; storage_partition: partition@1a0000 { diff --git a/boards/arm/stm32g071b_disco/doc/index.rst b/boards/arm/stm32g071b_disco/doc/index.rst index d7071c3d3d2..2c9cbea3176 100644 --- a/boards/arm/stm32g071b_disco/doc/index.rst +++ b/boards/arm/stm32g071b_disco/doc/index.rst @@ -109,7 +109,7 @@ Default Zephyr Peripheral Mapping: - RDCC1 : PB12 (Enable Door Sense on CC1) -For mode details please refer to `STM32G0 Discovery board User Manual`_. +For more details please refer to `STM32G0 Discovery board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32g081b_eval/doc/index.rst b/boards/arm/stm32g081b_eval/doc/index.rst index 3e2268446c3..970ec32dd0a 100644 --- a/boards/arm/stm32g081b_eval/doc/index.rst +++ b/boards/arm/stm32g081b_eval/doc/index.rst @@ -147,7 +147,7 @@ Default Zephyr Peripheral Mapping: - LED3 : PD8 - LED4 : PD9 -For mode details please refer to `STM32G0 Evaluation board User Manual`_. +For more details please refer to `STM32G0 Evaluation board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32h573i_dk/doc/index.rst b/boards/arm/stm32h573i_dk/doc/index.rst index f7806f52dde..a41a12f0c82 100644 --- a/boards/arm/stm32h573i_dk/doc/index.rst +++ b/boards/arm/stm32h573i_dk/doc/index.rst @@ -17,7 +17,7 @@ the STM32H573I-DK Discovery board: - USB Type-C |trade| Host and device with USB power-delivery controller - SAI Audio DAC stereo with one audio jacks for input/output, - ST MEMS digital microphone with PDM interface -- Octo-SPI interface connected to 152Mbit Octo-SPI NORFlash memory device (MX25LM51245GXDI00 from MACRONIX) +- Octo-SPI interface connected to 512Mbit Octo-SPI NORFlash memory device (MX25LM51245GXDI00 from MACRONIX) - 10/100-Mbit Ethernet, - microSD |trade| - A Wi‑Fi® add-on board @@ -223,7 +223,7 @@ Connections and IOs STM32H573I-DK Discovery Board has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H573I-DK Discovery board User Manual`_. +For more details please refer to `STM32H573I-DK Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h735g_disco/doc/index.rst b/boards/arm/stm32h735g_disco/doc/index.rst index 210756e1567..e4bf324650b 100644 --- a/boards/arm/stm32h735g_disco/doc/index.rst +++ b/boards/arm/stm32h735g_disco/doc/index.rst @@ -65,7 +65,15 @@ The current Zephyr stm32h735g_disco board configuration supports the following h +-----------+------------+-------------------------------------+ | ADC | on-chip | ADC Controller | +-----------+------------+-------------------------------------+ - +| FDCAN1 | on-chip | CAN-FD Controller | ++-----------+------------+-------------------------------------+ +| FDCAN2 | on-chip | CAN-FD Controller | ++-----------+------------+-------------------------------------+ +| FDCAN2 | on-chip | CAN-FD Controller (disabled by | +| | | default. Solder bridges SB29 and | +| | | SB30 need to be closed for FDCAN3 | +| | | to work) | ++-----------+------------+-------------------------------------+ Other hardware features are not yet supported on Zephyr porting. @@ -75,7 +83,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32H735G-DISCO website`_. +For more details please refer to `STM32H735G-DISCO website`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -84,6 +92,7 @@ Default Zephyr Peripheral Mapping: - UART_7 TX/RX : PF7/PF6 (Arduino Serial) - LD1 : PC2 - LD2 : PC3 +- FDCAN1 : CAN System Clock ============ diff --git a/boards/arm/stm32h735g_disco/stm32h735g_disco.dts b/boards/arm/stm32h735g_disco/stm32h735g_disco.dts index 29eef0e5326..8443c222abd 100644 --- a/boards/arm/stm32h735g_disco/stm32h735g_disco.dts +++ b/boards/arm/stm32h735g_disco/stm32h735g_disco.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &usart3; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,canbus = &fdcan1; }; leds { @@ -77,6 +78,16 @@ status = "okay"; }; +&pll2 { + div-m = <5>; + mul-n = <80>; + div-p = <5>; + div-q = <5>; + div-r = <5>; + clocks = <&clk_hse>; + status = "okay"; +}; + &rcc { clocks = <&pll>; clock-frequency = ; @@ -189,3 +200,46 @@ &vbat { status = "okay"; }; + +&fdcan1 { + pinctrl-0 = <&fdcan1_rx_ph14 &fdcan1_tx_ph13>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + status = "okay"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; + +&fdcan2 { + pinctrl-0 = <&fdcan2_rx_pb5 &fdcan2_tx_pb6>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + status = "okay"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; + +&fdcan3 { + pinctrl-0 = <&fdcan3_rx_pf6 &fdcan3_tx_pf7>; + pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL2_Q FDCAN_SEL(2)>; + /* Solder bridges SB29 and SB30 need to be closed for this to work */ + status = "disabled"; + bus-speed = <125000>; + bus-speed-data = <1000000>; + + can-transceiver { + max-bitrate = <8000000>; + }; +}; diff --git a/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml b/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml index a679deb18d4..c0983f46f4f 100644 --- a/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml +++ b/boards/arm/stm32h735g_disco/stm32h735g_disco.yaml @@ -15,4 +15,5 @@ supported: - memc - adc - counter + - can vendor: st diff --git a/boards/arm/stm32h747i_disco/CMakeLists.txt b/boards/arm/stm32h747i_disco/CMakeLists.txt new file mode 100644 index 00000000000..2f480bd7966 --- /dev/null +++ b/boards/arm/stm32h747i_disco/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright 2023 BrainCo Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Add custom linker section to relocate framebuffers to PSRAM +zephyr_linker_sources_ifdef(CONFIG_LV_Z_VBD_CUSTOM_SECTION + SECTIONS dc_ram.ld) diff --git a/boards/arm/stm32h747i_disco/board.cmake b/boards/arm/stm32h747i_disco/board.cmake index ac0e473e57d..00da755afb0 100644 --- a/boards/arm/stm32h747i_disco/board.cmake +++ b/boards/arm/stm32h747i_disco/board.cmake @@ -9,6 +9,8 @@ board_runner_args(jlink "--device=STM32H747ZI_M4") board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_stm32h747i_disco_m4.cfg") board_runner_args(openocd --target-handle=_CHIPNAME.cpu1) endif() +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32h747i_disco/dc_ram.ld b/boards/arm/stm32h747i_disco/dc_ram.ld new file mode 100644 index 00000000000..bd1565960d5 --- /dev/null +++ b/boards/arm/stm32h747i_disco/dc_ram.ld @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(sdram2), okay) +GROUP_START(SDRAM2) + + SECTION_PROLOGUE(_STM32_SDRAM2_SECTION_NAME, (NOLOAD),) + { + *(.lvgl_buf) + } GROUP_LINK_IN(SDRAM2) + +GROUP_END(SDRAM2) +#endif diff --git a/boards/arm/stm32h747i_disco/doc/index.rst b/boards/arm/stm32h747i_disco/doc/index.rst index d020a3ed94e..fa668e964c7 100644 --- a/boards/arm/stm32h747i_disco/doc/index.rst +++ b/boards/arm/stm32h747i_disco/doc/index.rst @@ -99,7 +99,7 @@ Pin Mapping STM32H747I Discovery kit has 9 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32H747I-DISCO website`_. +For more details please refer to `STM32H747I-DISCO website`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -172,6 +172,10 @@ command, for example: :shield: st_b_lcd40_dsi1_mb1166 :goals: build flash +.. note:: + Currently only the older version MB1166-A03 is supported by Zephyr. + The newer version MB1166-A09 does not get initialized correctly (see :github:`60888`). + Resources sharing ================= @@ -226,6 +230,13 @@ automatically. Zephyr flash configuration has been set to meet these default settings. +Alternatively, west `STM32CubeProgrammer`_ runner can be used, after installing +it, to flash applications for both cores. The target core is detected automatically. + +.. code-block:: console + + $ west flash --runner stm32cubeprogrammer + Flashing an application to STM32H747I M7 Core --------------------------------------------- diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi b/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi index fb620065c34..f27b2503873 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco.dtsi @@ -118,3 +118,7 @@ &spi5_miso_pj11 &spi5_mosi_pj10>; pinctrl-names = "default"; }; + +&mailbox { + status = "okay"; +}; diff --git a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts index 514047c8a55..8f27eb0f836 100644 --- a/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts +++ b/boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts @@ -232,11 +232,10 @@ zephyr_udc0: &usbotg_hs { pinctrl-names = "default"; status = "okay"; - mt25ql512ab1: qspi-nor-flash-1@0 { + mt25ql512ab1: qspi-nor-flash-1@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; /* 64 MBytes */ spi-bus-width = <4>; status = "okay"; @@ -251,11 +250,10 @@ zephyr_udc0: &usbotg_hs { }; }; - mt25ql512ab2: qspi-nor-flash-2@0 { + mt25ql512ab2: qspi-nor-flash-2@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ qspi-max-frequency = <72000000>; - size = ; /* 64 MBytes */ status = "okay"; }; }; diff --git a/boards/arm/stm32h750b_dk/Kconfig.board b/boards/arm/stm32h750b_dk/Kconfig.board new file mode 100644 index 00000000000..afa01489528 --- /dev/null +++ b/boards/arm/stm32h750b_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32H735G Discovery board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32H750B_DK + bool "STM32H750B Discovery Kit" + depends on SOC_STM32H750XX diff --git a/boards/arm/stm32h750b_dk/Kconfig.defconfig b/boards/arm/stm32h750b_dk/Kconfig.defconfig new file mode 100644 index 00000000000..48576f5706d --- /dev/null +++ b/boards/arm/stm32h750b_dk/Kconfig.defconfig @@ -0,0 +1,11 @@ +# STM32H750B DK board configuration + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32H750B_DK + +config BOARD + default "stm32h750b_dk" + +endif # BOARD_STM32H750B_DK diff --git a/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi b/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi new file mode 100644 index 00000000000..d5b1e520459 --- /dev/null +++ b/boards/arm/stm32h750b_dk/arduino_r3_connector.dtsi @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + arduino_header: connector { + compatible = "arduino-header-r3"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpioc 0 0>, /* A0 */ + <1 0 &gpiof 8 0>, /* A1 */ + <2 0 &gpioa 0 0>, /* A2 */ + <3 0 &gpioa 1 0>, /* A3 */ + <4 0 &gpioc 2 0>, /* A4 */ + <5 0 &gpioc 3 0>, /* A5 */ + <6 0 &gpiob 7 0>, /* D0 */ + <7 0 &gpiob 6 0>, /* D1 */ + <8 0 &gpiog 3 0>, /* D2 */ + <9 0 &gpioa 6 0>, /* D3 */ + <10 0 &gpiok 1 0>, /* D4 */ + <11 0 &gpioa 8 0>, /* D5 */ + <12 0 &gpioe 6 0>, /* D6 */ + <13 0 &gpioi 8 0>, /* D7 */ + <14 0 &gpioe 3 0>, /* D8 */ + <15 0 &gpioh 15 0>, /* D9 */ + <16 0 &gpiob 4 0>, /* D10 */ + <17 0 &gpiob 15 0>, /* D11 */ + <18 0 &gpioi 2 0>, /* D12 */ + <19 0 &gpiod 3 0>, /* D13 */ + <20 0 &gpiod 13 0>, /* D14 */ + <21 0 &gpiod 12 0>; /* D15 */ + }; +}; diff --git a/boards/arm/stm32h750b_dk/board.cmake b/boards/arm/stm32h750b_dk/board.cmake new file mode 100644 index 00000000000..6500e7b1a4a --- /dev/null +++ b/boards/arm/stm32h750b_dk/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink "--device=STM32H735IG" "--speed=4000") +board_runner_args(openocd --target-handle=_CHIPNAME.cpu0) + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png b/boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png new file mode 100644 index 00000000000..7a016515240 Binary files /dev/null and b/boards/arm/stm32h750b_dk/doc/img/stm32h750b_dk.png differ diff --git a/boards/arm/stm32h750b_dk/doc/index.rst b/boards/arm/stm32h750b_dk/doc/index.rst new file mode 100644 index 00000000000..6ac1aa15d34 --- /dev/null +++ b/boards/arm/stm32h750b_dk/doc/index.rst @@ -0,0 +1,145 @@ +.. _stm32h750b_dk_board: + +ST STM32H750B Discovery Kit +########################### + +Overview +******** + +The STM32H750B-DK Discovery kit is a complete demonstration and development +platform for Arm® Cortex®-M7 core-based STM32H750XBH6 microcontroller, with +128Kbytes of Flash memory and 1 Mbytes of SRAM. + +The STM32H750B-DK Discovery kit is used as a reference design for user +application development before porting to the final product, thus simplifying +the application development. + +The full range of hardware features available on the board helps users to enhance +their application development by an evaluation of all the peripherals (such as +USB OTG FS, Ethernet, microSD™ card, USART, CAN FD, SAI audio DAC stereo with +audio jack input and output, MEMS digital microphone, HyperRAM™, +Octo-SPI Flash memory, RGB interface LCD with capacitive touch panel, and others). +ARDUINO® Uno V3, Pmod™ and STMod+ connectors provide easy connection to extension +shields or daughterboards for specific applications. + +STLINK-V3E is integrated into the board, as the embedded in-circuit debugger and +programmer for the STM32 MCU and USB Virtual COM port bridge. STM32H750B-DK board +comes with the STM32CubeH7 MCU Package, which provides an STM32 comprehensive +software HAL library as well as various software examples. + +.. image:: img/stm32h750b_dk.png + :align: center + :alt: STM32H750B-DK + +More information about the board can be found at the `STM32H750B-DK website`_. +More information about STM32H750 can be found here: + +- `STM32H750 on www.st.com`_ +- `STM32H750xx reference manual`_ +- `STM32H750xx datasheet`_ + +Supported Features +================== + +The current Zephyr stm32h750b_dk board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ + + +Other hardware features are not yet supported on Zephyr porting. + +The default configuration per core can be found in the defconfig file: +``boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig`` + +Pin Mapping +=========== + +For more details please refer to `STM32H750B-DK website`_. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +- UART_3 TX/RX : PB10/PB11 (ST-Link Virtual Port Com) +- LD1 : PJ2 +- LD2 : PI13 + +System Clock +============ + +The STM32H750B System Clock can be driven by an internal or external oscillator, +as well as by the main PLL clock. By default, the System clock +is driven by the PLL clock at 480MHz. PLL clock is feed by a 25MHz high speed external clock. + +Serial Port +=========== + +The STM32H750B Discovery kit has up to 6 UARTs. +The Zephyr console output is assigned to UART3 which connected to the onboard ST-LINK/V3.0. Virtual +COM port interface. Default communication settings are 115200 8N1. + + +Programming and Debugging +************************* + +See :ref:`build_an_application` for more information about application builds. + + +Flashing +======== + +Connect the STM32H750B-DK to your host computer using the ST-LINK +USB port, then run a serial host program to connect with the board. For example: + +.. code-block:: console + + $ minicom -b 115200 -D /dev/ttyACM0 + +You can then build and flash applications in the usual way. +Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h750b_dk + :goals: build flash + +You should see the following message in the serial host program: + +.. code-block:: console + + $ Hello World! stm32h750b_dk + + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h750b_dk + :goals: debug + + +.. _STM32H750B-DK website: + https://www.st.com/en/evaluation-tools/stm32h750b-dk.html + +.. _STM32H750 on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32h750-value-line.html + +.. _STM32H750xx reference manual: + https://www.st.com/resource/en/reference_manual/rm0433-stm32h742-stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + +.. _STM32H750xx datasheet: + https://www.st.com/resource/en/datasheet/stm32h750ib.pdf diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.dts b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts new file mode 100644 index 00000000000..143b4b8416b --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.dts @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32H750B DISCOVERY KIT"; + compatible = "st,stm32h750b-dk"; + + chosen { + zephyr,console = &usart3; + zephyr,shell-uart = &usart3; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &mt25ql512ab1; + }; + + sdram2: sdram@d0000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + device_type = "memory"; + reg = <0xd0000000 DT_SIZE_M(16)>; /* 128Mbit */ + zephyr,memory-region = "SDRAM2"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_1 { + gpios = <&gpioi 13 GPIO_ACTIVE_LOW>; + label = "USER1 LD6"; + }; + green_led: led_2 { + gpios = <&gpioj 2 GPIO_ACTIVE_LOW>; + label = "USER2 LD7"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button: button { + label = "User"; + gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + }; + + aliases { + led0 = &green_led; + led1 = &red_led; + sw0 = &user_button; + spi-flash0 = &mt25ql512ab1; + }; +}; + +&clk_hse { + clock-frequency = ; + hse-bypass; + status = "okay"; +}; + +&pll { + div-m = <5>; + mul-n = <192>; + div-p = <2>; + div-q = <4>; + div-r = <4>; + clocks = <&clk_hse>; + status = "okay"; +}; + +&rcc { + clocks = <&pll>; + clock-frequency = ; + d1cpre = <1>; + hpre = <2>; + d1ppre = <2>; + d2ppre1 = <2>; + d2ppre2 = <2>; + d3ppre = <2>; +}; + +&usart3 { + pinctrl-0 = <&usart3_tx_pb10 &usart3_rx_pb11>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&quadspi { + pinctrl-names = "default"; + pinctrl-0 = <&quadspi_clk_pf10 &quadspi_bk1_ncs_pg6 + &quadspi_bk1_io0_pd11 &quadspi_bk1_io1_pf9 + &quadspi_bk1_io2_pf7 &quadspi_bk1_io3_pf6 + &quadspi_bk2_io0_ph2 &quadspi_bk2_io1_ph3 + &quadspi_bk2_io2_pg9 &quadspi_bk2_io3_pg14>; + flash-id = <1>; + status = "okay"; + + mt25ql512ab1: qspi-nor-flash-1@90000000 { + compatible = "st,stm32-qspi-nor"; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ + qspi-max-frequency = <72000000>; + spi-bus-width = <4>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + reg = <0x0 DT_SIZE_M(64)>; + }; + }; + }; + + mt25ql512ab2: qspi-nor-flash-2@90000000 { + compatible = "st,stm32-qspi-nor"; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ + qspi-max-frequency = <72000000>; + size = ; /* 64 MBytes */ + status = "okay"; + }; +}; + +&fmc { + pinctrl-0 = <&fmc_nbl0_pe0 &fmc_nbl1_pe1 + &fmc_sdclk_pg8 &fmc_sdnwe_ph5 &fmc_sdcke1_ph7 + &fmc_sdne1_ph6 &fmc_sdnras_pf11 &fmc_sdncas_pg15 + &fmc_a0_pf0 &fmc_a1_pf1 &fmc_a2_pf2 &fmc_a3_pf3 &fmc_a4_pf4 + &fmc_a5_pf5 &fmc_a6_pf12 &fmc_a7_pf13 &fmc_a8_pf14 + &fmc_a9_pf15 &fmc_a10_pg0 &fmc_a11_pg1 + &fmc_a14_pg4 &fmc_a15_pg5 &fmc_d0_pd14 &fmc_d1_pd15 + &fmc_d2_pd0 &fmc_d3_pd1 &fmc_d4_pe7 &fmc_d5_pe8 &fmc_d6_pe9 + &fmc_d7_pe10 &fmc_d8_pe11 &fmc_d9_pe12 &fmc_d10_pe13 + &fmc_d11_pe14 &fmc_d12_pe15 &fmc_d13_pd8 &fmc_d14_pd9 + &fmc_d15_pd10>; + pinctrl-names = "default"; + status = "okay"; + + sdram { + status = "okay"; + power-up-delay = <100>; + num-auto-refresh = <8>; + mode-register = <0x220>; + refresh-rate = <0x603>; + bank@1 { + reg = <1>; + st,sdram-control = ; + st,sdram-timing = <2 7 4 7 2 2 2>; + }; + }; +}; diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml b/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml new file mode 100644 index 00000000000..126376b1464 --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk.yaml @@ -0,0 +1,15 @@ +identifier: stm32h750b_dk +name: ST STM32H750B Discovery Kit +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 1024 +flash: 128 +supported: + - arduino_gpio + - gpio + - dma +vendor: st diff --git a/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig b/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig new file mode 100644 index 00000000000..64cab9ff714 --- /dev/null +++ b/boards/arm/stm32h750b_dk/stm32h750b_dk_defconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_STM32H7X=y +CONFIG_SOC_STM32H750XX=y + +# Enable the internal SMPS regulator +CONFIG_POWER_SUPPLY_LDO=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +CONFIG_SERIAL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# enable GPIO +CONFIG_GPIO=y + +# Enable Clocks +CONFIG_CLOCK_CONTROL=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32h750b_dk/support/openocd.cfg b/boards/arm/stm32h750b_dk/support/openocd.cfg new file mode 100644 index 00000000000..e77a5dbb76c --- /dev/null +++ b/boards/arm/stm32h750b_dk/support/openocd.cfg @@ -0,0 +1,30 @@ +source [find interface/stlink-dap.cfg] +transport select dapdirect_swd + +set WORKAREASIZE 0x2000 +set CHIPNAME STM32H750XB +set BOARDNAME STM23H750B_DK + +source [find target/stm32h7x.cfg] + +# Use connect_assert_srst here to be able to program +# even when core is in sleep mode +reset_config srst_only srst_nogate connect_assert_srst + +$_CHIPNAME.cpu0 configure -event gdb-attach { + echo "Debugger attaching: halting execution" + gdb_breakpoint_override hard +} + +$_CHIPNAME.cpu0 configure -event gdb-detach { + echo "Debugger detaching: resuming execution" + resume +} + +# Due to the use of connect_assert_srst, running gdb requires +# to reset halt just after openocd init. +rename init old_init +proc init {} { + old_init + reset halt +} diff --git a/boards/arm/stm32h7b3i_dk/doc/index.rst b/boards/arm/stm32h7b3i_dk/doc/index.rst index 549594bb3cc..83d18858426 100644 --- a/boards/arm/stm32h7b3i_dk/doc/index.rst +++ b/boards/arm/stm32h7b3i_dk/doc/index.rst @@ -74,7 +74,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32H7B3I-DK website`_. +For more details please refer to `STM32H7B3I-DK website`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts index 35470174123..b8b781b3fa1 100644 --- a/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts +++ b/boards/arm/stm32h7b3i_dk/stm32h7b3i_dk.dts @@ -152,6 +152,8 @@ &fdcan1 { pinctrl-0 = <&fdcan1_rx_pa11 &fdcan1_tx_pa12>; pinctrl-names = "default"; + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; phys = <&transceiver0>; bus-speed = <125000>; bus-speed-data = <1000000>; diff --git a/boards/arm/stm32l1_disco/doc/index.rst b/boards/arm/stm32l1_disco/doc/index.rst index 65bb4bc028f..a968cebc792 100644 --- a/boards/arm/stm32l1_disco/doc/index.rst +++ b/boards/arm/stm32l1_disco/doc/index.rst @@ -125,7 +125,7 @@ Default Zephyr Peripheral Mapping: - SPI2_MISO : PB14 - SPI2_MOSI : PB15 -For mode details please refer to `STM32L1DISCOVERY board User Manual`_. +For more details please refer to `STM32L1DISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32l476g_disco/doc/index.rst b/boards/arm/stm32l476g_disco/doc/index.rst index bd4b2a5a6d5..65eef57c609 100644 --- a/boards/arm/stm32l476g_disco/doc/index.rst +++ b/boards/arm/stm32l476g_disco/doc/index.rst @@ -135,7 +135,7 @@ Connections and IOs STM32L476G Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L476G Discovery board User Manual`_. +For more details please refer to `STM32L476G Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32l496g_disco/doc/index.rst b/boards/arm/stm32l496g_disco/doc/index.rst index 0bd31e72c38..e8bc81f092b 100644 --- a/boards/arm/stm32l496g_disco/doc/index.rst +++ b/boards/arm/stm32l496g_disco/doc/index.rst @@ -164,7 +164,7 @@ Connections and IOs STM32L496G Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L496G Discovery board User Manual`_. +For more details please refer to `STM32L496G Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts index 977e70142ef..e2a70f6163d 100644 --- a/boards/arm/stm32l496g_disco/stm32l496g_disco.dts +++ b/boards/arm/stm32l496g_disco/stm32l496g_disco.dts @@ -201,11 +201,10 @@ zephyr_udc0: &usbotg_fs { flash-id = <1>; status = "okay"; - mx25r6435: qspi-nor-flash@0 { + mx25r6435: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <8000000>; - size = ; /* 8 MBytes */ status = "okay"; spi-bus-width = <4>; writeoc = "PP_1_4_4"; diff --git a/boards/arm/stm32l4r9i_disco/doc/index.rst b/boards/arm/stm32l4r9i_disco/doc/index.rst index a8f7798f840..0f651e2b9ff 100644 --- a/boards/arm/stm32l4r9i_disco/doc/index.rst +++ b/boards/arm/stm32l4r9i_disco/doc/index.rst @@ -71,7 +71,7 @@ The default configuration can be found in the defconfig file: Pin Mapping =========== -For mode details, please refer to `STM32L4R9I-DISCOVERY website`_. +For more details, please refer to `STM32L4R9I-DISCOVERY website`_. System Clock ============ diff --git a/boards/arm/stm32l562e_dk/CMakeLists.txt b/boards/arm/stm32l562e_dk/CMakeLists.txt index dde73804665..f6ca91f1a73 100644 --- a/boards/arm/stm32l562e_dk/CMakeLists.txt +++ b/boards/arm/stm32l562e_dk/CMakeLists.txt @@ -10,6 +10,6 @@ endif() if(CONFIG_BUILD_WITH_TFM) set_property(GLOBAL APPEND PROPERTY extra_post_build_commands #Execute post build script postbuild.sh - COMMAND $/postbuild.sh ${COMPILER_FULL_PATH} + COMMAND $/api_ns/postbuild.sh ${COMPILER_FULL_PATH} ) endif() diff --git a/boards/arm/stm32l562e_dk/Kconfig.defconfig b/boards/arm/stm32l562e_dk/Kconfig.defconfig index bec20b338f5..3a81889dc71 100644 --- a/boards/arm/stm32l562e_dk/Kconfig.defconfig +++ b/boards/arm/stm32l562e_dk/Kconfig.defconfig @@ -17,9 +17,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y diff --git a/boards/arm/stm32l562e_dk/doc/index.rst b/boards/arm/stm32l562e_dk/doc/index.rst index 5a4f5845617..16af6cb242b 100644 --- a/boards/arm/stm32l562e_dk/doc/index.rst +++ b/boards/arm/stm32l562e_dk/doc/index.rst @@ -251,7 +251,7 @@ Connections and IOs STM32L562E-DK Discovery Board has 8 GPIO controllers. These controllers are responsible for pin muxing, input/output, pull-up, etc. -For mode details please refer to `STM32L562E-DK Discovery board User Manual`_. +For more details please refer to `STM32L562E-DK Discovery board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- @@ -340,7 +340,7 @@ can be generated using ``stm32l562e_dk_ns`` as build target. $ west build -b stm32l562e_dk_ns path/to/source/directory -Note: When building the ``*_ns`` image with TF-M, ``build/tfm/postbuild.sh`` bash script +Note: When building the ``*_ns`` image with TF-M, ``build/tfm/api_ns/postbuild.sh`` bash script is run automatically in a post-build step to make some required flash layout changes. Once the build is completed, run the following script to initialize the option bytes. diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi index 5bb8c567ee6..ccd74b46ece 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_common.dtsi @@ -71,7 +71,7 @@ apb2-prescaler = <1>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; status = "okay"; @@ -111,16 +111,15 @@ &spi1 { pinctrl-0 = <&spi1_sck_pg2 &spi1_miso_pg3 &spi1_mosi_pg4>; pinctrl-names = "default"; - cs-gpios = <&gpiog 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + cs-gpios = <&gpiog 5 GPIO_ACTIVE_LOW>; status = "okay"; spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "st,hci-spi-v1"; reg = <0>; irq-gpios = <&gpiog 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; - reset-gpios = <&gpiog 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + reset-gpios = <&gpiog 8 GPIO_ACTIVE_LOW>; + spi-max-frequency = ; spi-hold-cs; }; }; @@ -136,11 +135,10 @@ status = "okay"; - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@90000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(64)>; /* 512 Mbits */ ospi-max-frequency = ; - size = ; /* 64 MBytes */ spi-bus-width = ; data-rate = ; four-byte-opcodes; diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig b/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig index c5537972912..6646832e7ef 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_defconfig @@ -24,6 +24,3 @@ CONFIG_HW_STACK_PROTECTION=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig index 289f8d82131..c28424d306a 100644 --- a/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig +++ b/boards/arm/stm32l562e_dk/stm32l562e_dk_ns_defconfig @@ -25,6 +25,3 @@ CONFIG_TRUSTED_EXECUTION_NONSECURE=y # enable pin controller CONFIG_PINCTRL=y - -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y diff --git a/boards/arm/stm32u5a9j_dk/doc/index.rst b/boards/arm/stm32u5a9j_dk/doc/index.rst index 6e3e44c5942..23859666df7 100644 --- a/boards/arm/stm32u5a9j_dk/doc/index.rst +++ b/boards/arm/stm32u5a9j_dk/doc/index.rst @@ -92,7 +92,7 @@ The default configuration per core can be found in the defconfig file: Pin Mapping =========== -For mode details please refer to `STM32U5A9J-DK board User Manual`_. +For more details please refer to `STM32U5A9J-DK board User Manual`_. Default Zephyr Peripheral Mapping: ---------------------------------- diff --git a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts index f236354c6f2..6f80a4061a4 100644 --- a/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts +++ b/boards/arm/stm32u5a9j_dk/stm32u5a9j_dk.dts @@ -37,7 +37,7 @@ compatible = "gpio-keys"; user_button: button_0 { label = "User"; - gpios = <&gpioc 13 GPIO_ACTIVE_LOW>; + gpios = <&gpioc 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; zephyr,code = ; }; }; diff --git a/boards/arm/stm32vl_disco/doc/index.rst b/boards/arm/stm32vl_disco/doc/index.rst index 006c8854bb4..7819200bafb 100644 --- a/boards/arm/stm32vl_disco/doc/index.rst +++ b/boards/arm/stm32vl_disco/doc/index.rst @@ -119,7 +119,7 @@ Default Zephyr Peripheral Mapping: - I2C2_SCL : PB10 - I2C2_SDA : PB11 -For mode details please refer to `STM32VLDISCOVERY board User Manual`_. +For more details please refer to `STM32VLDISCOVERY board User Manual`_. Programming and Debugging ************************* diff --git a/boards/arm/stm32wb5mm_dk/Kconfig.board b/boards/arm/stm32wb5mm_dk/Kconfig.board new file mode 100644 index 00000000000..28ca74d81a9 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WB5MM-DK Discovery Development board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32WB5MM_DK + bool "stm32wb5mm-dk Discovery Development Board" + depends on SOC_STM32WB55XX diff --git a/boards/arm/stm32wb5mm_dk/Kconfig.defconfig b/boards/arm/stm32wb5mm_dk/Kconfig.defconfig new file mode 100644 index 00000000000..5ce31881bd0 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WB5MM-DK Discovery Development board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32WB5MM_DK + +config BOARD + default "stm32wb5mm_dk" + +choice BT_HCI_BUS_TYPE + default BT_STM32_IPM + depends on BT +endchoice + +endif # BOARD_STM32WB5MM_DK diff --git a/boards/arm/stm32wb5mm_dk/board.cmake b/boards/arm/stm32wb5mm_dk/board.cmake new file mode 100644 index 00000000000..47fc12f1308 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(pyocd "--target=stm32wb55vgyx") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg b/boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg new file mode 100644 index 00000000000..0e9cc26ac20 Binary files /dev/null and b/boards/arm/stm32wb5mm_dk/doc/img/STM32WB5MM_DK.jpg differ diff --git a/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst b/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst new file mode 100644 index 00000000000..61b70106601 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/doc/stm32wb5mm_dk.rst @@ -0,0 +1,232 @@ +.. _stm32wb5mm_dk_discovery_kit: + +ST STM32WB5MM-DK +################ + +Overview +******** + +The STM32WB5MM-DK Discovery kit is designed as a complete demonstration +and development platform for the STMicroelectronics STM32W5MMG module based +on the Arm |reg| Cortex |reg|-M4 and Arm |reg| Cortex |reg|-M0+ cores. +The STM32 device is a multi-protocol wireless and ultra-low-power device +embedding a powerful and ultra-low-power radio compliant with the +Bluetooth |reg| Low Energy (BLE) SIG specification v5.2 and with +IEEE 802.15.4-2011. + + +STM32WB5MM-DK supports the following features: + +* STM32WB5MMG (1-Mbyte Flash memory, 256-Kbyte SRAM) + - Dual-core 32‑bit (Arm |reg| Cortex |reg|-M4 and M0+) + - 2.4 GHz RF transceiver + - 0.96-inch 128x64 OLED display + - 128-Mbit Quad-SPI NOR Flash Memory + - Temperature sensor + - Accelerometer/gyroscope sensor + - Time-of-Flight and gesture-detection sensor + - Digital microphone + - RGB LED + - Infrared LED + - 3 push-buttons (2 users and 1 reset) and 1 touch key button + +* Board connectors: + - STMod+ + - ARDUINO |reg| Uno V3 expansion connector + - USB user with Micro-B connector + - TAG10 10-pin footprint + +* Flexible power-supply options: + - ST-LINK/V2-1 USB connector, + - 5 V delivered by: + - ARDUINO |reg|, + - external connector, + - USB charger, or USB power + +* On-board ST-LINK/V2-1 debugger/programmer with USB re-enumeration + - Virtual COM port and debug port + + +.. image:: img/STM32WB5MM_DK.jpg + :align: center + :alt: STM32WB5MM-DK + +More information about the board can be found in `STM32WB5MM-DK on www.st.com`_. + +Hardware +******** + +STM32WB5MMG is an ultra-low-power and small form factor certified 2.4 GHz +wireless module. It supports Bluetooth |reg| Low Energy 5.4, Zigbee |reg| 3.0, +OpenThread, dynamic, and static concurrent modes, and 802.15.4 proprietary +protocols. + +Based on the STMicroelectronics STM32WB55VGY wireless microcontroller, +STM32WB5MMG provides best-in-class RF performance thanks to its high +receiver sensitivity and output power signal. Its low-power features +enable extended battery life, small coin-cell batteries, and energy harvesting. + +- Ultra-low-power with FlexPowerControl +- Core: ARM |reg| 32-bit Cortex |reg|-M4 CPU with FPU +- Radio: + + - 2.4GHz + - RF transceiver supporting: + + - Bluetooth |reg| 5.4 specification, + - IEEE 802.15.4-2011 PHY and MAC, + - Zigbee |reg| 3.0 + + - RX sensitivity: + + - -96 dBm (Bluetooth |reg| Low Energy at 1 Mbps), + - -100 dBm (802.15.4) + + - Programmable output power up to +6 dBm with 1 dB steps + - Integrated balun to reduce BOM + - Support for 2 Mbps + - Support GATT caching + - Support EATT (enhanced ATT) + - Support advertising extension + - Accurate RSSI to enable power control + +- Clock Sources: + + - 32 MHz crystal oscillator with integrated + trimming capacitors (Radio and CPU clock) + - 32 kHz crystal oscillator for RTC (LSE) + - Internal low-power 32 kHz (±5%) RC (LSI1) + - Internal low-power 32 kHz (stability + ±500 ppm) RC (LSI2) + - Internal multispeed 100 kHz to 48 MHz + oscillator, auto-trimmed by LSE (better than + ±0.25% accuracy) + - High speed internal 16 MHz factory + trimmed RC (±1%) + - 2x PLL for system clock, USB, SAI, ADC + +More information about STM32WB55RG can be found here: + +- `STM32WB5MM-DK on www.st.com`_ +- `STM32WB5MMG datasheet`_ + +Supported Features +================== + +The Zephyr STM32WB5MM-DK board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ + + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig file: +``boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig`` + +Bluetooth and compatibility with STM32WB Copro Wireless Binaries +================================================================ + +To operate bluetooth on STM32WB5MMG, Cortex-M0 core should be flashed with +a valid STM32WB Coprocessor binaries (either 'Full stack' or 'HCI Layer'). +These binaries are delivered in STM32WB Cube packages, under +``Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/``. + +For compatibility information with the various versions of these binaries, +please check `modules/hal/stm32/lib/stm32wb/hci/README`_ +in the ``hal_stm32`` repo. + +Note that since STM32WB Cube package V1.13.2, `"full stack"` binaries are not +compatible anymore for a use in Zephyr and only `"HCI Only"` versions should be +used on the M0 side. + +Connections and IOs +=================== + + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART_1 TX/RX : PB7/PB6 ( Connected to ST-Link VCP) +- LPUART_1 TX/RX : PA3/PA2 +- USB : PA11/PA12 +- SWD : PA13/PA14 + +System Clock +------------ + +STM32WB5MMG System Clock could be driven by internal or external oscillator, +as well as main PLL clock. By default System clock is driven by HSE clock at 32MHz. + +Serial Port +----------- + +STM32WB5MM-DK board has 2 (LP)U(S)ARTs. The Zephyr console output is assigned to USART1. +Default settings are ``115200 8N1``. + + +Programming and Debugging +************************* + +Applications for the ``stm32wb5mm_dk`` board configuration can be built the +usual way (see :ref:`build_an_application`). + +Flashing +======== + +STM32WB5MM-DK has an on-board ST-Link to flash and debug the firmware on the +module. + + +Flashing ``hello_world`` application to STM32WB5MM-DK +------------------------------------------------------ + +Connect the STM32WB5MM-DK to your host computer using the USB port (CN11). +Then build and flash an application. Here is an example for the ``hello_world`` +application. + +Run a serial host program to connect with your STM32WB5MM-DK board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 + +Then first build and flash the application for the STM32WB5MM-DK board. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32wb5mm_dk + :goals: build flash + +Reset the board and you should see the following messages on the console: + +.. code-block:: console + + Hello World! stm32w5mm_dk + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +`Hello_World`_ application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32wb5mm_dk + :maybe-skip-config: + :goals: debug + +.. _STM32WB5MM-DK on www.st.com: + https://www.st.com/en/evaluation-tools/stm32wb5mm-dk.html +.. _STM32WB5MMG datasheet: + https://www.st.com/resource/en/datasheet/stm32wb5mmg.pdf +.. _modules/hal/stm32/lib/stm32wb/hci/README: + https://github.com/zephyrproject-rtos/hal_stm32/blob/main/lib/stm32wb/hci/README +.. _Hello_World: + https://docs.zephyrproject.org/latest/samples/hello_world/README.html diff --git a/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.dts b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.dts new file mode 100644 index 00000000000..4f4fb99cea0 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.dts @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024 Javad Rahimipetroudi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32WB5MM Discovery Development Kit"; + compatible = "st,stm32wb5mm-dk"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,bt-mon-uart = &lpuart1; + zephyr,bt-c2h-uart = &lpuart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + aliases { + watchdog0 = &iwdg; + die-temp0 = &die_temp; + volt-sensor0 = &vref; + volt-sensor1 = &vbat; + }; +}; + +&die_temp { + status = "okay"; +}; + +&clk_hse { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk48 { + /* Node is disabled by default as default source is HSI48 */ + /* To select another clock, enable the node */ + clocks = <&rcc STM32_SRC_HSI48 CLK48_SEL(0)>; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + cpu1-prescaler = <1>; + cpu2-prescaler = <1>; + ahb4-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +&iwdg { + status = "okay"; +}; + +zephyr_udc0: &usb { + status = "okay"; + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; +}; + +&aes1 { + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Configure partitions while leaving space for M0 BLE f/w + * Since STM32WBCube release V1.13.2, only _HCIOnly_ f/w are supported. + * These FW are expected to be located not before 0x080DB000 + * Current partition is using the first 876K of the flash for M4 + */ + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(400)>; + }; + slot1_partition: partition@70000 { + label = "image-1"; + reg = <0x00070000 DT_SIZE_K(400)>; + }; + scratch_partition: partition@d4000 { + label = "image-scratch"; + reg = <0x000d4000 DT_SIZE_K(16)>; + }; + storage_partition: partition@d8000 { + label = "storage"; + reg = <0x000d8000 DT_SIZE_K(8)>; + }; + + }; +}; + +&vref { + status = "okay"; +}; + +&vbat { + status = "okay"; +}; diff --git a/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml new file mode 100644 index 00000000000..63c75d4473f --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk.yaml @@ -0,0 +1,14 @@ +identifier: stm32wb5mm_dk +name: ST STM32WB5MM-DK Discovery Development Board +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 256 +flash: 1024 +supported: + - gpio + - uart +vendor: st diff --git a/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig new file mode 100644 index 00000000000..9fdd732848e --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/stm32wb5mm_dk_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WBX=y +CONFIG_SOC_STM32WB55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# enable clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32wb5mm_dk/support/openocd.cfg b/boards/arm/stm32wb5mm_dk/support/openocd.cfg new file mode 100644 index 00000000000..2ad58270368 --- /dev/null +++ b/boards/arm/stm32wb5mm_dk/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wbx.cfg] + +reset_config srst_only diff --git a/boards/arm/stm32wb5mmg/Kconfig.board b/boards/arm/stm32wb5mmg/Kconfig.board new file mode 100644 index 00000000000..4fe8c22fd7c --- /dev/null +++ b/boards/arm/stm32wb5mmg/Kconfig.board @@ -0,0 +1,8 @@ +# STM32WB5MMG Bluetooth module board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_STM32WB5MMG + bool "stm32wb5mmg ultra low power Bluetooth module" + depends on SOC_STM32WB55XX diff --git a/boards/arm/stm32wb5mmg/Kconfig.defconfig b/boards/arm/stm32wb5mmg/Kconfig.defconfig new file mode 100644 index 00000000000..cedb62395be --- /dev/null +++ b/boards/arm/stm32wb5mmg/Kconfig.defconfig @@ -0,0 +1,16 @@ +# STM32WB5MMG Bluetooth module board configuration + +# Copyright (c) 2024 Javad Rahimipetroudi +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_STM32WB5MMG + +config BOARD + default "stm32wb5mmg" + +choice BT_HCI_BUS_TYPE + default BT_STM32_IPM + depends on BT +endchoice + +endif # BOARD_STM32WB5MMG diff --git a/boards/arm/stm32wb5mmg/board.cmake b/boards/arm/stm32wb5mmg/board.cmake new file mode 100644 index 00000000000..47fc12f1308 --- /dev/null +++ b/boards/arm/stm32wb5mmg/board.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +board_runner_args(pyocd "--target=stm32wb55vgyx") +board_runner_args(stm32cubeprogrammer "--port=swd" "--reset-mode=hw") + +include(${ZEPHYR_BASE}/boards/common/stm32cubeprogrammer.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg b/boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg new file mode 100644 index 00000000000..6def853b748 Binary files /dev/null and b/boards/arm/stm32wb5mmg/doc/img/STM32WB5MMG.jpg differ diff --git a/boards/arm/stm32wb5mmg/doc/stm32wb5mmg.rst b/boards/arm/stm32wb5mmg/doc/stm32wb5mmg.rst new file mode 100644 index 00000000000..90561ee1275 --- /dev/null +++ b/boards/arm/stm32wb5mmg/doc/stm32wb5mmg.rst @@ -0,0 +1,304 @@ +.. _stm32wb5mmg_bluetooth_module: + +ST STM32WB5MMG +################ + +Overview +******** + +STM32WB5MMG is an ultra-low-power and small form factor certified 2.4 GHz +wireless module. It supports Bluetooth|reg| Low Energy 5.4, Zigbee|reg| 3.0, +OpenThread, dynamic, and static concurrent modes, and 802.15.4 proprietary +protocols. This board support is added in order to make it possible use this +module on other boards as HCI layer (Specefically B-U585I-IOT02A Development board). + +STM32WB5MMG supports the following features: + +- Bluetooth module in SiP-LGA86 package +- Integrated chip antenna +- Bluetooth|reg| Low Energy 5.4, Zigbee|reg| 3.0, OpenThread certified + Dynamic and static concurrent modes +- IEEE 802.15.4-2011 MAC PHY Supports 2 Mbits/s +- Frequency band 2402-2480 MHz +- Advertising extension +- Tx output power up to +6 dBm +- Rx sensitivity: -96 dBm (Bluetooth|reg| Low Energy at 1 Mbps), -100 dBm (802.15.4) +- Range: up to 75 meters +- Dedicated Arm|reg| Cortex|reg|-M0+ CPU for radio and security tasks +- Dedicated Arm|reg| Cortex|reg|-M4 CPU with FPU and ART (adaptive real-time accelerator) up to 64 MHz speed +- 1-Mbyte flash memory, 256-Kbyte SRAM +- Fully integrated BOM, including 32 MHz radio and 32 kHz RTC crystals +- Integrated SMPS +- Ultra-low-power modes for battery longevity +- 68 GPIOs +- SWD, JTAG + +.. image:: img/STM32WB5MMG.jpg + :align: center + :alt: STM32WB5MMG + +More information about the board can be found at the `` `STM32WB5MMG on www.st.com`_. + +Hardware +******** + +STM32WB5MMG is an ultra-low-power and small form factor certified 2.4 GHz +wireless module. It supportsBluetooth|reg| Low Energy 5.4, Zigbee|reg| 3.0, OpenThread, +dynamic, and static concurrent modes, and 802.15.4proprietary protocols. Based +on the STMicroelectronics STM32WB55VGY wireless microcontroller,STM32WB5MMG +provides best-in-class RF performance thanks to its high receiver sensitivity +and output power signal. Its low-power features enable extended battery life, +small coin-cell batteries, and energy harvesting. STM32WB5MMG revision Y is +based on cut 2.1 of the STM32WB55VGY microcontroller. Revision X is based on +cut 2.2. + +- Ultra-low-power with FlexPowerControl (down to 600 nA Standby mode with RTC and 32KB RAM) +- Core: ARM |reg| 32-bit Cortex |reg|-M4 CPU with FPU, frequency up to 64 MHz +- Radio: + + - 2.4GHz + - RF transceiver supporting Bluetooth|reg| 5.4 + specification, IEEE 802.15.4-2011 PHY + and MAC, supporting Thread 1.3 and + - Zigbee|reg| 3.0 + - RX sensitivity: -96 dBm (Bluetooth |reg| Low + Energy at 1 Mbps), -100 dBm (802.15.4) + - Programmable output power up to +6 dBm + with 1 dB steps + - Integrated balun to reduce BOM + - Support for 2 Mbps + - Support GATT caching + - Support EATT (enhanced ATT) + - Support advertising extension + - Dedicated Arm|reg| 32-bit Cortex|reg| M0+ CPU + for real-time Radio layer + - Accurate RSSI to enable power control + - Suitable for systems requiring compliance + with radio frequency regulations ETSI EN + 300 328, EN 300 440, FCC CFR47 Part 15 + and ARIB STD-T66 + + +- Clock Sources: + + - 32 MHz crystal oscillator with integrated + trimming capacitors (Radio and CPU clock) + - 32 kHz crystal oscillator for RTC (LSE) + - Internal low-power 32 kHz (±5%) RC (LSI1) + - Internal low-power 32 kHz (stability + ±500 ppm) RC (LSI2) + - Internal multispeed 100 kHz to 48 MHz + oscillator, auto-trimmed by LSE (better than + ±0.25% accuracy) + - High speed internal 16 MHz factory + trimmed RC (±1%) + - 2x PLL for system clock, USB, SAI, ADC + +- 2x DMA controllers (seven channels each) supporting ADC, SPI, I2C, USART, QSPI, SAI, AES, timers +- 1x USART (ISO 7816, IrDA, SPI master, Modbus and Smartcard mode) +- 1x LPUART (low power) +- Two SPI running at 32 Mbit/s +- 2x I2C (SMBus/PMBus) +- 1x SAI (dual channel high quality audio) +- 1x USB 2.0 FS device, crystal-less, BCD and LPM +- 1x Touch sensing controller, up to 18 sensors +- 1x LCD 8x40 with step-up converter +- 1x 16-bit, four channels advanced timer +- 2x 16-bit, two channels timers +- 1x 32-bit, four channels timer +- 2x 16-bit ultra-low-power timers +- 1x independent Systick +- 1x independent watchdog +- 1x window watchdog +- Up to 72 fast I/Os, 70 of them 5 V-tolerant + +- Memories + + - Up to 1 MB flash memory with sector + protection (PCROP) against R/W + operations, enabling radio stack and + application + - Up to 256 KB SRAM, including 64 KB with + hardware parity check + - 20x 32-bit backup register + - Boot loader supporting USART, SPI, I2C + and USB interfaces + - OTA (over the air) Bluetooth® Low Energy + and 802.15.4 update + - Quad SPI memory interface with XIP + - 1 Kbyte (128 double words) OTP + +- 4x digital filters for sigma delta modulator +- Rich analog peripherals (down to 1.62 V) + +- 12-bit ADC 4.26 Msps, up to 16-bit with + hardware oversampling, 200 μA/Msps +- 2x ultra-low-power comparator +- Accurate 2.5 V or 2.048 V reference + voltage buffered output + + +- Security and ID + + - Secure firmware installation (SFI) for + Bluetooth|reg| Low Energy and 802.15.4 SW stack + - 3x hardware encryption AES maximum 256-bit for + the application, the Bluetooth|reg| + - Low Energy and IEEE802.15.4 + - Customer key storage/manager services + - HW public key authority (PKA) + - Cryptographic algorithms: RSA, Diffie-Helman, ECC over GF(p) + - True random number generator (RNG) + - Sector protection against R/W operation (PCROP) + - CRC calculation unit + - Die information: 96-bit unique ID + - IEEE 64-bit unique ID, possibility to derive 802.15.4 64-bit + and Bluetooth|reg| Low Energy + - 48-bit EUI + +More information about STM32WB55RG can be found here: + +- `STM32WB5MMG on www.st.com`_ +- `STM32WB5MMG datasheet`_ + +Supported Features +================== + +The Zephyr STM32WB5MMG board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| RADIO | on-chip | Bluetooth Low Energy | ++-----------+------------+-------------------------------------+ + + +Other hardware features are not yet supported on this Zephyr port. + +The default configuration can be found in the defconfig file: +``boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig`` + +Bluetooth and compatibility with STM32WB Copro Wireless Binaries +================================================================ + +To operate bluetooth on STM32WB5MMG, Cortex-M0 core should be flashed with +a valid STM32WB Coprocessor binaries (either 'Full stack' or 'HCI Layer'). +These binaries are delivered in STM32WB Cube packages, under +Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x/ +For compatibility information with the various versions of these binaries, +please check `modules/hal/stm32/lib/stm32wb/hci/README`_ +in the hal_stm32 repo. +Note that since STM32WB Cube package V1.13.2, "full stack" binaries are not compatible +anymore for a use in Zephyr and only "HCI Only" versions should be used on the M0 +side. + +Connections and IOs +=================== + + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART_1 TX/RX : PB7/PB6 +- LPUART_1 TX/RX : PA3/PA2 +- USB : PA11/PA12 +- SWD : PA13/PA14 + +System Clock +------------ + +STM32WB5MMG System Clock could be driven by internal or external oscillator, +as well as main PLL clock. By default System clock is driven by HSE clock at 32MHz. + +Serial Port +----------- + +STM32WB5MMG board has 2 (LP)U(S)ARTs. LPUART1 is connected to the main U585I +microcontroller that is used as HCI controller port. USART1 is not connected +to any external pinout, so it is not possible to debug the module directly. +Rather, users can use the available USB port (CN12) to run virtual com port +(VCP) USB stack for the debugging. + + +Programming and Debugging +************************* + +Applications for the ``stm32wb5mmg`` board configuration can be built the +usual way (see :ref:`build_an_application`). + +Flashing the module +=================== + +The onboard ST-Link on the ``b_u585i_iot02a`` board can be used to flash the +STM32WB5MMG module. To do this you should put SW4 on OFF and SW5 on ON mode. +In this case the firmware will be uploaded on the STM32WB5MMG module. + + +Flashing `hci_uart` application to STM32WB5MMG +---------------------------------------------- + +Connect the B-U585I-IOT02A to your host computer using the USB port. Put +the SW4 (MCU SWD) in OFF mode and SW5 (SWD BLE) in ON mode. Then build +and flash an application. Here is an example for the +:ref:`hci_uart ` application. + +Run a serial host program to connect with your B-U585I-IOT02A board: + +.. code-block:: console + + $ minicom -D /dev/ttyACM0 + +Then build and flash the application for the STM32WB5MMG module. + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/hci_uart + :board: stm32wb5mmg + :goals: build flash + +Next, reverse back the buttons to default mode (SW4 on ON and SW5 +on OFF) mode. In this case we will upload the Bluetooth sample on the +main microcontroller.Then, build the bluetooth +:zephyr_file:`samples/bluetooth/observer` demo application for +B-U585I-IOT02A board: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/observer + :board: b_u585i_iot02a + :goals: build flash + +Rest the board and you should see the following messages on the console: + +.. code-block:: console + + Starting Observer Demo + Started scanning... + Exiting main thread. + Device found: 2C:98:F3:64:58:06 (random) (RSSI -82), type 3, AD data len 31 + Device found: CE:5B:9A:87:69:4F (random) (RSSI -80), type 3, AD data len 8 + Device found: 7B:1E:DD:38:23:E1 (random) (RSSI -85), type 0, AD data len 17 + + +Debugging +========= + +You can debug an application in the usual way. Here is an example for the +:ref:`hci_uart ` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/observer + :board: b_u585i_iot02a + :maybe-skip-config: + :goals: debug + +.. _STM32WB5MMG on www.st.com: + https://www.st.com/en/microcontrollers-microprocessors/stm32wb5mmg.html + +.. _STM32WB5MMG datasheet: + https://www.st.com/resource/en/datasheet/stm32wb5mmg.pdf +.. _modules/hal/stm32/lib/stm32wb/hci/README: + https://github.com/zephyrproject-rtos/hal_stm32/blob/main/lib/stm32wb/hci/README diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg.dts b/boards/arm/stm32wb5mmg/stm32wb5mmg.dts new file mode 100644 index 00000000000..d494b7024dc --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg.dts @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024 Javad Rahimipetroudi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "STMicroelectronics STM32WB5MMG Bluetooth module"; + compatible = "st,stm32wb5mmgh6"; + + chosen { + zephyr,console = &usart1; + zephyr,shell-uart = &usart1; + zephyr,bt-mon-uart = &lpuart1; + zephyr,bt-c2h-uart = &lpuart1; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&clk_hse { + status = "okay"; +}; + +&clk_lse { + status = "okay"; +}; + +&clk_hsi48 { + status = "okay"; +}; + +&clk48 { + /* Node is disabled by default as default source is HSI48 */ + /* To select another clock, enable the node */ + clocks = <&rcc STM32_SRC_HSI48 CLK48_SEL(0)>; +}; + +&rcc { + clocks = <&clk_hse>; + clock-frequency = ; + cpu1-prescaler = <1>; + cpu2-prescaler = <1>; + ahb4-prescaler = <1>; + apb1-prescaler = <1>; + apb2-prescaler = <1>; +}; + +&usart1 { + pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_tx_pa2 &lpuart1_rx_pa3>; + pinctrl-names = "default"; + current-speed = <100000>; + status = "okay"; +}; + +&adc1 { + pinctrl-0 = <&adc1_in3_pc2>; + pinctrl-names = "default"; + st,adc-clock-source = ; + st,adc-prescaler = <4>; + status = "okay"; +}; + +zephyr_udc0: &usb { + status = "okay"; + pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; + pinctrl-names = "default"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * Configure partitions while leaving space for M0 BLE f/w + * Since STM32WBCube release V1.13.2, only _HCIOnly_ f/w are supported. + * These FW are expected to be located not before 0x080DB000 + * Current partition is using the first 876K of the flash for M4 + */ + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(48)>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000c000 DT_SIZE_K(400)>; + }; + + }; +}; diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml b/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml new file mode 100644 index 00000000000..2e3667f18d5 --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg.yaml @@ -0,0 +1,16 @@ +identifier: stm32wb5mmg +name: ST STM32WB5MMG Ultra-low-power Module +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 256 +flash: 1024 +supported: + - gpio + - dma + - uart + - usb_device +vendor: st diff --git a/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig b/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig new file mode 100644 index 00000000000..9fdd732848e --- /dev/null +++ b/boards/arm/stm32wb5mmg/stm32wb5mmg_defconfig @@ -0,0 +1,24 @@ +CONFIG_SOC_SERIES_STM32WBX=y +CONFIG_SOC_STM32WB55XX=y + +# enable uart driver +CONFIG_SERIAL=y + +# enable GPIO +CONFIG_GPIO=y + +# enable clocks +CONFIG_CLOCK_CONTROL=y + +# console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable HW stack protection +CONFIG_HW_STACK_PROTECTION=y + +# enable pin controller +CONFIG_PINCTRL=y diff --git a/boards/arm/stm32wb5mmg/support/openocd.cfg b/boards/arm/stm32wb5mmg/support/openocd.cfg new file mode 100644 index 00000000000..2ad58270368 --- /dev/null +++ b/boards/arm/stm32wb5mmg/support/openocd.cfg @@ -0,0 +1,7 @@ +source [find interface/stlink.cfg] + +transport select hla_swd + +source [find target/stm32wbx.cfg] + +reset_config srst_only diff --git a/boards/arm/teensy4/teensy4-pinctrl.dtsi b/boards/arm/teensy4/teensy4-pinctrl.dtsi index 87e1e7ded41..4d9964bb521 100644 --- a/boards/arm/teensy4/teensy4-pinctrl.dtsi +++ b/boards/arm/teensy4/teensy4-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright (c) 2022, NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from teensy4.mex */ diff --git a/boards/arm/thingy53_nrf5340/Kconfig.defconfig b/boards/arm/thingy53_nrf5340/Kconfig.defconfig index 45869075487..2c5dfa46d9c 100644 --- a/boards/arm/thingy53_nrf5340/Kconfig.defconfig +++ b/boards/arm/thingy53_nrf5340/Kconfig.defconfig @@ -68,7 +68,8 @@ choice BT_HCI_BUS_TYPE default BT_HCI_IPC if BT endchoice -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC config BT_HAS_HCI_VS diff --git a/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi b/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi index 4e8f4849f75..d16cb81f896 100644 --- a/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi +++ b/boards/arm/twr_ke18f/twr_ke18f-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_cfg_utils.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKE18F512VLL16/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi b/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi index 2495acc5e41..06e2deaf3d4 100644 --- a/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi +++ b/boards/arm/twr_kv58f220m/twr_kv58f220m-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKV58F1M0VLQ24/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml b/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml index 810d96c2ae6..6118c0c0b11 100644 --- a/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml +++ b/boards/arm/twr_kv58f220m/twr_kv58f220m.yaml @@ -6,7 +6,7 @@ toolchain: - zephyr - gnuarmemb - xtools -ram: 256 +ram: 128 flash: 1024 supported: - i2c diff --git a/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts b/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts index 070730c69d2..d06986a8afa 100644 --- a/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts +++ b/boards/arm/ubx_bmd340eval_nrf52840/ubx_bmd340eval_nrf52840.dts @@ -129,6 +129,7 @@ sw2 = &button2; sw3 = &button3; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts b/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts index 68b3755123b..ef145eabe54 100644 --- a/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts +++ b/boards/arm/ubx_bmd345eval_nrf52840/ubx_bmd345eval_nrf52840.dts @@ -141,6 +141,7 @@ mcuboot-button0 = &button0; mcuboot-led0 = &led0; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts b/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts index d7a21c98b44..404678ad952 100644 --- a/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts +++ b/boards/arm/ubx_bmd380eval_nrf52840/ubx_bmd380eval_nrf52840.dts @@ -90,6 +90,7 @@ sw2 = &button2; sw3 = &button3; watchdog0 = &wdt0; + spi-flash0 = &mx25r64; }; }; diff --git a/boards/arm/ucans32k1sic/Kconfig.board b/boards/arm/ucans32k1sic/Kconfig.board new file mode 100644 index 00000000000..314c7f98d5e --- /dev/null +++ b/boards/arm/ucans32k1sic/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_UCANS32K1SIC + bool "ucans32k1sic" + depends on SOC_SERIES_S32K1XX + select SOC_PART_NUMBER_FS32K146UAT0VLHT diff --git a/boards/arm/ucans32k1sic/Kconfig.defconfig b/boards/arm/ucans32k1sic/Kconfig.defconfig new file mode 100644 index 00000000000..044df50c0c5 --- /dev/null +++ b/boards/arm/ucans32k1sic/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_UCANS32K1SIC + +config BOARD + default "ucans32k1sic" + +if SERIAL + +config UART_CONSOLE + default y + +endif # SERIAL + +if CAN + +config GPIO + default y + +endif # CAN + +endif # BOARD_UCANS32K1SIC diff --git a/boards/arm/ucans32k1sic/board.cmake b/boards/arm/ucans32k1sic/board.cmake new file mode 100644 index 00000000000..5cb17a1b6c2 --- /dev/null +++ b/boards/arm/ucans32k1sic/board.cmake @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +board_runner_args(jlink + "--device=S32K146" + "--speed=4000" + "--iface=swd" + "--reset" +) + +board_runner_args(trace32 + "--startup-args" "elfFile=${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}" +) +if(${CONFIG_XIP}) + board_runner_args(trace32 "loadTo=flash") +else() + board_runner_args(trace32 "loadTo=sram") +endif() + +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/trace32.board.cmake) diff --git a/boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp b/boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp new file mode 100644 index 00000000000..ddd2bdafb8f Binary files /dev/null and b/boards/arm/ucans32k1sic/doc/img/ucans32k1sic_top.webp differ diff --git a/boards/arm/ucans32k1sic/doc/index.rst b/boards/arm/ucans32k1sic/doc/index.rst new file mode 100644 index 00000000000..66138b44a00 --- /dev/null +++ b/boards/arm/ucans32k1sic/doc/index.rst @@ -0,0 +1,197 @@ +.. _ucans32k1sic: + +NXP UCANS32K1SIC +################ + +Overview +******** + +`NXP UCANS32K1SIC`_ is a CAN signal improvement capability (SIC) evaluation +board designed for both automotive and industrial applications. The UCANS32K1SIC +provides two CAN SIC interfaces and is based on the 32-bit Arm Cortex-M4F +`NXP S32K146`_ microcontroller. + +.. image:: img/ucans32k1sic_top.webp + :align: center + :alt: NXP UCANS32K1SIC (TOP) + +Hardware +******** + +- NXP S32K146 + - Arm Cortex-M4F @ up to 112 Mhz + - 1 MB Flash + - 128 KB SRAM + - up to 127 I/Os + - 3x FlexCAN with 2x FD + - eDMA, 12-bit ADC, MPU, ECC and more. + +- Interfaces: + - DCD-LZ debug interface with SWD + Console / UART + - Dual CAN FD PHYs with dual connectors for daisy chain operation + - JST-GH DroneCode compliant standard connectors and I/O headers + - user RGB LED and button. + +More information about the hardware and design resources can be found at +`NXP UCANS32K1SIC`_ website. + +Supported Features +================== + +The ``ucans32k1sic`` board configuration supports the following hardware features: + +============ ========== ================================ +Interface Controller Driver/Component +============ ========== ================================ +SYSMPU on-chip mpu +PORT on-chip pinctrl +GPIO on-chip gpio +LPUART on-chip serial +LPI2C on-chip i2c +LPSPI on-chip spi +FTM on-chip pwm +FlexCAN on-chip can +Watchdog on-chip watchdog +RTC on-chip counter +============ ========== ================================ + +The default configuration can be found in the Kconfig file +:zephyr_file:`boards/arm/ucans32k1sic/ucans32k1sic_defconfig`. + +Connections and IOs +=================== + +This board has 5 GPIO ports named from ``gpioa`` to ``gpioe``. + +Pin control can be further configured from your application overlay by adding +children nodes with the desired pinmux configuration to the singleton node +``pinctrl``. Supported properties are described in +:zephyr_file:`dts/bindings/pinctrl/nxp,kinetis-pinctrl.yaml`. + +LEDs +---- + +The UCANS32K1SIC board has one user RGB LED that can be used either as a GPIO +LED or as a PWM LED. + +.. table:: RGB LED as GPIO LED + :widths: auto + + =============== ================ =============== ===== + Devicetree node Devicetree alias Label Pin + =============== ================ =============== ===== + led1_red led0 LED1_RGB_RED PTD15 + led1_green led1 LED1_RGB_GREEN PTD16 + led1_blue led2 LED1_RGB_BLUE PTD0 + =============== ================ =============== ===== + +.. table:: RGB LED as PWM LED + :widths: auto + + =============== ======================== ================== ================ + Devicetree node Devicetree alias Label Pin + =============== ======================== ================== ================ + led1_red_pwm pwm-led0 / red-pwm-led LED1_RGB_RED_PWM PTD15 / FTM0_CH0 + led1_green_pwm pwm-led1 / green-pwm-led LED1_RGB_GREEN_PWM PTD16 / FTM0_CH1 + led1_blue_pwm pwm-led2 / blue-pwm-led LED1_RGB_BLUE_PWM PTD0 / FTM0_CH2 + =============== ======================== ================== ================ + +The user can control the LEDs in any way. An output of ``0`` illuminates the LED. + +Buttons +------- + +The UCANS32K1SIC board has one user button: + +======================= ============== ===== +Devicetree node Label Pin +======================= ============== ===== +sw0 / button_3 SW3 PTD15 +======================= ============== ===== + +Serial Console +============== + +The serial console is provided via ``lpuart1`` on the 7-pin DCD-LZ debug +connector ``P6``. + +========= ===== ============ +Connector Pin Pin Function +========= ===== ============ +P6.2 PTC7 LPUART1_TX +P6.3 PTC6 LPUART1_RX +========= ===== ============ + +System Clock +============ + +The Arm Cortex-M4F core is configured to run at 80 MHz (RUN mode). + +Programming and Debugging +************************* + +Applications for the ``ucans32k1sic`` board can be built in the usual way as +documented in :ref:`build_an_application`. + +This board configuration supports `Lauterbach TRACE32`_ and `SEGGER J-Link`_ +West runners for flashing and debugging applications. Follow the steps described +in :ref:`lauterbach-trace32-debug-host-tools` and :ref:`jlink-debug-host-tools`, +to setup the flash and debug host tools for these runners, respectively. The +default runner is J-Link. + +Flashing +======== + +Run the ``west flash`` command to flash the application using SEGGER J-Link. +Alternatively, run ``west flash -r trace32`` to use Lauterbach TRACE32. + +The Lauterbach TRACE32 runner supports additional options that can be passed +through command line: + +.. code-block:: console + + west flash -r trace32 --startup-args elfFile= loadTo= + eraseFlash= verifyFlash= + +Where: + +- ```` is the path to the Zephyr application ELF in the output + directory +- ``loadTo=flash`` loads the application to the SoC internal program flash + (:kconfig:option:`CONFIG_XIP` must be set), and ``loadTo=sram`` load the + application to SRAM. The default is ``flash``. +- ``eraseFlash=yes`` erases the whole content of SoC internal flash before the + application is downloaded to either Flash or SRAM. This routine takes time to + execute. The default is ``no``. +- ``verifyFlash=yes`` verify the SoC internal flash content after programming + (use together with ``loadTo=flash``). The default is ``no``. + +For example, to erase and verify flash content: + +.. code-block:: console + + west flash -r trace32 --startup-args elfFile=build/zephyr/zephyr.elf loadTo=flash eraseFlash=yes verifyFlash=yes + +Debugging +========= + +Run the ``west debug`` command to start a GDB session using SEGGER J-Link. +Alternatively, run ``west debug -r trace32`` to launch the Lauterbach TRACE32 +software debugging interface. + +References +********** + +.. target-notes:: + +.. _NXP UCANS32K1SIC: + https://www.nxp.com/design/development-boards/analog-toolbox/can-sic-evaluation-board:UCANS32K1SIC + +.. _NXP S32K146: + https://www.nxp.com/products/processors-and-microcontrollers/s32-automotive-platform/s32k-auto-general-purpose-mcus/s32k1-microcontrollers-for-automotive-general-purpose:S32K1 + +.. _Lauterbach TRACE32: + https://www.lauterbach.com + +.. _SEGGER J-Link: + https://wiki.segger.com/S32Kxxx diff --git a/boards/arm/ucans32k1sic/support/debug.cmm b/boards/arm/ucans32k1sic/support/debug.cmm new file mode 100644 index 00000000000..d2c30dc5661 --- /dev/null +++ b/boards/arm/ucans32k1sic/support/debug.cmm @@ -0,0 +1,13 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach TRACE32 start-up script for debugging ucans32k1sic * +; * +;******************************************************************************* + +ENTRY %LINE &args + +DO ~~~~/startup.cmm command=debug &args + +ENDDO diff --git a/boards/arm/ucans32k1sic/support/flash.cmm b/boards/arm/ucans32k1sic/support/flash.cmm new file mode 100644 index 00000000000..941d2c03954 --- /dev/null +++ b/boards/arm/ucans32k1sic/support/flash.cmm @@ -0,0 +1,13 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach TRACE32 start-up script for flashing ucans32k1sic * +; * +;******************************************************************************* + +ENTRY %LINE &args + +DO ~~~~/startup.cmm command=flash &args + +ENDDO diff --git a/boards/arm/ucans32k1sic/support/startup.cmm b/boards/arm/ucans32k1sic/support/startup.cmm new file mode 100644 index 00000000000..db901876f1d --- /dev/null +++ b/boards/arm/ucans32k1sic/support/startup.cmm @@ -0,0 +1,128 @@ +;******************************************************************************* +; Copyright 2023 NXP * +; SPDX-License-Identifier: Apache-2.0 * +; * +; Lauterbach Trace32 start-up script for S32K146 / Cortex-M4F * +; * +; Parameters: * +; - command operation to execute * +; valid values: flash, debug * +; - elfFile filepath of ELF to load * +; - loadTo if "flash", the application will be downloaded to SoC * +; program flash by a flash programming routine; if "sram" it * +; will be downloaded to SoC SRAM. * +; valid values: flash, sram * +; default: flash * +; - eraseFlash if set to "yes", the whole content in Flash device will be * +; erased before the application is downloaded to either Flash * +; or SRAM. This routine takes time to execute * +; default: "no" * +; - verifyFlash if set to "yes", verify after program application to Flash * +; default: "no" * +;******************************************************************************* + +ENTRY %LINE &args + +&command=STRing.SCANAndExtract("&args","command=","") +&elfFile=STRing.SCANAndExtract("&args","elfFile=","") +&loadTo=STRing.SCANAndExtract("&args","loadTo=","flash") +&eraseFlash=STRing.SCANAndExtract("&args","eraseFlash=","no") +&verifyFlash=STRing.SCANAndExtract("&args","verifyFlash=","no") + +IF ("&elfFile"=="") +( + AREA.view + PRINT %ERROR "Missing ELF file path" + PLIST + STOP + ENDDO +) + +; Initialize debugger +RESet +SYStem.RESet +SYStem.CPU S32K146 +SYStem.CONFIG.DEBUGPORTTYPE SWD +SYStem.Option DUALPORT ON +SYStem.MemAccess DAP +SYStem.JtagClock CTCK 10MHz +Trace.DISable +SYStem.Up + +GOSUB DisableBootrom + +; Only declares flash, does not execute flash programming +DO ~~/demo/arm/flash/s32k.cmm PREPAREONLY + +IF ("&eraseFlash"=="yes") +( + FLASH.Erase ALL +) + +IF ("&loadTo"=="flash") +( + ; Switch target flash to reprogramming state, erase virtual flash programming memory, + ; all target non-empty flash sectors are marked as pending, to be reprogrammed. + FLASH.ReProgram ALL /Erase + + ; Write contents of the file to virtual Flash programming memory + Data.LOAD.Elf &elfFile + + ; Program only changed sectors to target flash and erase obsolete code + FLASH.ReProgram off + + IF ("&verifyFlash"=="yes") + ( + Data.LOAD.Elf &elfFile /DIFF + + IF FOUND() + ( + AREA.view + PRINT %ERROR "Failed to download the code to flash" + Data.LOAD.Elf &elfFile /ComPare + ENDDO + ) + ) + + ; Reset the processor again + SYStem.Up + GOSUB DisableBootrom +) +ELSE +( + ; Load program to SRAM + Data.LOAD.Elf &elfFile +) + +IF ("&command"=="flash") +( + ; Execute the application and quit + Go + QUIT +) +ELSE IF ("&command"=="debug") +( + ; Setup minimal debug environment + WinCLEAR + SETUP.Var.%SpotLight + WinPOS 0. 0. 120. 30. + List.auto + WinPOS 125. 0. 80. 10. + Frame.view + WinPOS 125. 18. + Register.view /SpotLight +) +ELSE +( + AREA.view + PRINT %ERROR "Invalid command: &command" +) + +ENDDO + +DisableBootrom: +( + Data.Set SD:0x4007F010 %LE %Long 0x6 + Data.Set SD:0x4007F014 %LE %Long 0x0 + RETURN +) diff --git a/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi new file mode 100644 index 00000000000..2bb216e63ae --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic-pinctrl.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + lpuart0_default: lpuart0_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + lpuart1_default: lpuart1_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + lpi2c0_default: lpi2c0_default { + group1 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + lpspi0_default: lpspi0_default { + group0 { + pinmux = , + , + , + ; + drive-strength = "low"; + }; + }; + + ftm0_default: ftm0_default { + group0 { + pinmux = , + , + ; + drive-strength = "low"; + }; + }; + + ftm1_default: ftm1_default { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; + + ftm2_default: ftm2_default { + group0 { + pinmux = ; + drive-strength = "low"; + }; + }; + + flexcan0_default: flexcan0_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; + + flexcan1_default: flexcan1_default { + group0 { + pinmux = , ; + drive-strength = "low"; + }; + }; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.dts b/boards/arm/ucans32k1sic/ucans32k1sic.dts new file mode 100644 index 00000000000..6996a12d6d0 --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic.dts @@ -0,0 +1,193 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include +#include "ucans32k1sic-pinctrl.dtsi" + +/ { + model = "NXP UCANS32K1SIC"; + compatible = "nxp,ucans32k1sic"; + + chosen { + zephyr,sram = &sram_l; + zephyr,flash = &flash0; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + zephyr,uart-pipe = &lpuart1; + zephyr,canbus = &flexcan0; + }; + + aliases { + led0 = &led1_red; + led1 = &led1_green; + led2 = &led1_blue; + pwm-led0 = &led1_red_pwm; + pwm-led1 = &led1_green_pwm; + pwm-led2 = &led1_blue_pwm; + red-pwm-led = &led1_red_pwm; + green-pwm-led = &led1_green_pwm; + blue-pwm-led = &led1_blue_pwm; + pwm-0 = &ftm0; + sw0 = &button_3; + i2c-0 = &lpi2c0; + }; + + leds { + compatible = "gpio-leds"; + + led1_red: led_0 { + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_RED"; + }; + led1_green: led_1 { + gpios = <&gpiod 16 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_GREEN"; + }; + led1_blue: led_2 { + gpios = <&gpiod 0 GPIO_ACTIVE_LOW>; + label = "LED1_RGB_BLUE"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + + led1_red_pwm: led_pwm_0 { + pwms = <&ftm0 0 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_RED_PWM"; + }; + led1_green_pwm: led_pwm_1 { + pwms = <&ftm0 1 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_GREEN_PWM"; + }; + led1_blue_pwm: led_pwm_2 { + pwms = <&ftm0 2 PWM_MSEC(20) PWM_POLARITY_INVERTED>; + label = "LED1_RGB_BLUE_PWM"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + button_3: button_0 { + label = "SW3"; + gpios = <&gpioc 14 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; + + can_phy0: can-phy0 { + compatible = "nxp,tja1463", "nxp,tja1443", "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; + + can_phy1: can-phy1 { + compatible = "nxp,tja1463", "nxp,tja1443", "nxp,tja1153", "can-transceiver-gpio"; + enable-gpios = <&gpioe 2 GPIO_ACTIVE_HIGH>; + max-bitrate = <8000000>; + #phy-cells = <0>; + }; +}; + +&gpioa { + status = "okay"; +}; + +&gpiob { + status = "okay"; +}; + +&gpioc { + status = "okay"; +}; + +&gpiod { + status = "okay"; +}; + +&gpioe { + status = "okay"; +}; + +&lpuart0 { + pinctrl-0 = <&lpuart0_default>; + pinctrl-names = "default"; + current-speed = <115200>; +}; + +&lpuart1 { + pinctrl-0 = <&lpuart1_default>; + pinctrl-names = "default"; + current-speed = <115200>; + status = "okay"; +}; + +&lpi2c0 { + pinctrl-0 = <&lpi2c0_default>; + pinctrl-names = "default"; + scl-gpios = <&gpioa 3 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpioa 2 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&lpspi0 { + pinctrl-0 = <&lpspi0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&ftm0 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm0_default>; + pinctrl-names = "default"; + prescaler = <128>; + #pwm-cells = <3>; + status = "okay"; +}; + +&ftm1 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm1_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "okay"; +}; + +&ftm2 { + compatible = "nxp,kinetis-ftm-pwm"; + pinctrl-0 = <&ftm2_default>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "okay"; +}; + +&flexcan0 { + pinctrl-0 = <&flexcan0_default>; + pinctrl-names = "default"; + phys = <&can_phy0>; + bus-speed = <125000>; + sample-point = <875>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + status = "okay"; +}; + +&flexcan1 { + pinctrl-0 = <&flexcan1_default>; + pinctrl-names = "default"; + phys = <&can_phy1>; + bus-speed = <125000>; + sample-point = <875>; + bus-speed-data = <1000000>; + sample-point-data = <875>; + status = "okay"; +}; diff --git a/boards/arm/ucans32k1sic/ucans32k1sic.yaml b/boards/arm/ucans32k1sic/ucans32k1sic.yaml new file mode 100644 index 00000000000..798c1096409 --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic.yaml @@ -0,0 +1,23 @@ +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +identifier: ucans32k1sic +name: NXP UCANS32K1SIC +vendor: nxp +type: mcu +arch: arm +ram: 124 +flash: 1024 +toolchain: + - zephyr +supported: + - mpu + - gpio + - uart + - pinctrl + - i2c + - spi + - pwm + - can + - watchdog + - counter diff --git a/boards/arm/ucans32k1sic/ucans32k1sic_defconfig b/boards/arm/ucans32k1sic/ucans32k1sic_defconfig new file mode 100644 index 00000000000..8580c7155cb --- /dev/null +++ b/boards/arm/ucans32k1sic/ucans32k1sic_defconfig @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_UCANS32K1SIC=y +CONFIG_SOC_SERIES_S32K1XX=y +CONFIG_SOC_S32K146=y +CONFIG_BUILD_OUTPUT_HEX=y + +# Use Systick as system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=80000000 + +# Run from internal program flash +CONFIG_XIP=y + +# Enable MPU +CONFIG_ARM_MPU=y + +CONFIG_PINCTRL=y +CONFIG_SERIAL=y +CONFIG_CONSOLE=y diff --git a/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi b/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi index 143c28cff93..fd067dbf840 100644 --- a/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi +++ b/boards/arm/usb_kw24d512/usb_kw24d512-pinctrl.dtsi @@ -1,5 +1,5 @@ /* - * NOTE: Autogenerated file by kinetis_signal2dts.py + * NOTE: Autogenerated file by gen_board_pinctrl.py * for MKW24D512VHA5/signal_configuration.xml * * Copyright (c) 2022, NXP diff --git a/boards/arm/v2m_beetle/doc/index.rst b/boards/arm/v2m_beetle/doc/index.rst index 80e7af563fc..7673e510ebf 100644 --- a/boards/arm/v2m_beetle/doc/index.rst +++ b/boards/arm/v2m_beetle/doc/index.rst @@ -190,7 +190,7 @@ Peripheral Mapping: - I2C_1_SDA : D22 - I2C_1_SCL : D23 -For mode details please refer to `Beetle Technical Reference Manual (TRM)`_. +For more details please refer to `Beetle Technical Reference Manual (TRM)`_. System Clock ============ diff --git a/boards/arm/v2m_musca_b1/doc/index.rst b/boards/arm/v2m_musca_b1/doc/index.rst index f36ae79dbb4..0f0c261460a 100644 --- a/boards/arm/v2m_musca_b1/doc/index.rst +++ b/boards/arm/v2m_musca_b1/doc/index.rst @@ -205,7 +205,7 @@ Peripheral Mapping: - I2C_0_SDA : D14 - I2C_0_SCL : D15 -For mode details please refer to `Musca B1 Technical Reference Manual (TRM)`_. +For more details please refer to `Musca B1 Technical Reference Manual (TRM)`_. RGB LED diff --git a/boards/arm/v2m_musca_b1/v2m_musca_b1.dts b/boards/arm/v2m_musca_b1/v2m_musca_b1.dts index 2c260552f07..e5bf38ec422 100644 --- a/boards/arm/v2m_musca_b1/v2m_musca_b1.dts +++ b/boards/arm/v2m_musca_b1/v2m_musca_b1.dts @@ -56,7 +56,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts b/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts index a54a2829cd7..4aef3b4c066 100644 --- a/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts +++ b/boards/arm/v2m_musca_b1/v2m_musca_b1_ns.dts @@ -37,7 +37,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_s1/doc/index.rst b/boards/arm/v2m_musca_s1/doc/index.rst index 4c8f4fcc0c1..8a1c4b221bd 100644 --- a/boards/arm/v2m_musca_s1/doc/index.rst +++ b/boards/arm/v2m_musca_s1/doc/index.rst @@ -199,7 +199,7 @@ Peripheral Mapping: - I2C_0_SDA : D14 - I2C_0_SCL : D15 -For mode details please refer to `Musca-S1 Technical Reference Manual (TRM)`_. +For more details please refer to `Musca-S1 Technical Reference Manual (TRM)`_. RGB LED diff --git a/boards/arm/v2m_musca_s1/v2m_musca_s1.dts b/boards/arm/v2m_musca_s1/v2m_musca_s1.dts index 619d63eb60e..5f60afdddb5 100644 --- a/boards/arm/v2m_musca_s1/v2m_musca_s1.dts +++ b/boards/arm/v2m_musca_s1/v2m_musca_s1.dts @@ -56,7 +56,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts b/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts index 23e75ab03aa..5ea0bde7748 100644 --- a/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts +++ b/boards/arm/v2m_musca_s1/v2m_musca_s1_ns.dts @@ -37,7 +37,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi index 3f27e5c3a33..d25bffa04c5 100644 --- a/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi +++ b/boards/arm/vmu_rt1170/vmu_rt1170-pinctrl.dtsi @@ -2,7 +2,7 @@ * Copyright 2023 NXP * SPDX-License-Identifier: Apache-2.0 * - * Note: File generated by rt_cfg_utils.py + * Note: File generated by gen_board_pinctrl.py * from vmu_rt1170.mex */ @@ -38,8 +38,9 @@ group3 { pinmux = <&iomuxc_gpio_disp_b1_11_enet_1g_ref_clk1>; drive-strength = "high"; - slew-rate = "slow"; + slew-rate = "fast"; input-enable; + bias-pull-down; }; }; diff --git a/boards/arm/w5500_evb_pico/Kconfig.board b/boards/arm/w5500_evb_pico/Kconfig.board new file mode 100644 index 00000000000..9c863d899dc --- /dev/null +++ b/boards/arm/w5500_evb_pico/Kconfig.board @@ -0,0 +1,7 @@ +# Copyright (c) 2021 Yonatan Schachter +# Copyright (c) 2023 Ian Wakely +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_W5500_EVB_PICO + bool "Wiznet W5500 Evaluation Board" + depends on SOC_RP2040 diff --git a/boards/arm/w5500_evb_pico/Kconfig.defconfig b/boards/arm/w5500_evb_pico/Kconfig.defconfig new file mode 100644 index 00000000000..5e569b40cc9 --- /dev/null +++ b/boards/arm/w5500_evb_pico/Kconfig.defconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2021 Yonatan Schachter +# Copyright (c) 2023 Ian Wakely +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_W5500_EVB_PICO + +config BOARD + default "w5500_evb_pico" if BOARD_W5500_EVB_PICO + +config RP2_FLASH_W25Q080 + default y + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +if I2C_DW + +config I2C_DW_CLOCK_SPEED + default 125 + +endif #I2C_DW + +config USB_SELF_POWERED + default n + +endif # BOARD_W5500_EVB_PICO diff --git a/boards/arm/w5500_evb_pico/board.cmake b/boards/arm/w5500_evb_pico/board.cmake new file mode 100644 index 00000000000..e95d4d3767f --- /dev/null +++ b/boards/arm/w5500_evb_pico/board.cmake @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: Apache-2.0 + +# This configuration allows selecting what debug adapter debugging w5500_evb_pico +# by a command-line argument. +# It is mainly intended to support both the 'picoprobe' and 'raspberrypi-swd' +# adapter described in "Getting started with Raspberry Pi Pico". +# And any other SWD debug adapter might also be usable with this configuration. + +# Set RPI_PICO_DEBUG_ADAPTER to select debug adapter by command-line arguments. +# e.g.) west build -b w5500_evb_pico -- -DRPI_PICO_DEBUG_ADAPTER=raspberrypi-swd +# The value is treated as a part of an interface file name that +# the debugger's configuration file. +# The value must be the 'stem' part of the name of one of the files +# in the openocd interface configuration file. +# The setting is store to CMakeCache.txt. +if ("${RPI_PICO_DEBUG_ADAPTER}" STREQUAL "") + set(RPI_PICO_DEBUG_ADAPTER "cmsis-dap") +endif() + +board_runner_args(openocd --cmd-pre-init "source [find interface/${RPI_PICO_DEBUG_ADAPTER}.cfg]") +board_runner_args(openocd --cmd-pre-init "transport select swd") +board_runner_args(openocd --cmd-pre-init "source [find target/rp2040.cfg]") + +# The adapter speed is expected to be set by interface configuration. +# But if not so, set 2000 to adapter speed. +board_runner_args(openocd --cmd-pre-init "set_adapter_speed_if_not_set 2000") + +board_runner_args(jlink "--device=RP2040_M0_0") +board_runner_args(uf2 "--board-id=RPI-RP2") +board_runner_args(pyocd "--target=rp2040") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +include(${ZEPHYR_BASE}/boards/common/uf2.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake) diff --git a/boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png b/boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png new file mode 100644 index 00000000000..d592fd2c85f Binary files /dev/null and b/boards/arm/w5500_evb_pico/doc/img/w5500_evb_pico_side.png differ diff --git a/boards/arm/w5500_evb_pico/doc/index.rst b/boards/arm/w5500_evb_pico/doc/index.rst new file mode 100644 index 00000000000..63d63370f76 --- /dev/null +++ b/boards/arm/w5500_evb_pico/doc/index.rst @@ -0,0 +1,293 @@ +.. _w5500_evb_pico: + +Wiznet W5500 Evaluation Pico +############################ + +Overview +******** + +W5500-EVB-Pico is a microcontroller evaluation board based on the Raspberry +Pi RP2040 and fully hardwired TCP/IP controller W5500 - and basically works +the same as Raspberry Pi Pico board but with additional Ethernet via W5500. +The USB bootloader allows the ability to flash without any adapter, in a +drag-and-drop manner. It is also possible to flash and debug the boards with +their SWD interface, using an external adapter. + +Hardware +******** +- Dual core Arm Cortex-M0+ processor running up to 133MHz +- 264KB on-chip SRAM +- 16MB on-board QSPI flash with XIP capabilities +- 26 GPIO pins +- 3 Analog inputs +- 2 UART peripherals +- 2 SPI controllers +- 2 I2C controllers +- 16 PWM channels +- USB 1.1 controller (host/device) +- 8 Programmable I/O (PIO) for custom peripherals +- On-board LED +- 1 Watchdog timer peripheral +- Wiznet W5500 Ethernet MAC/PHY + + +.. figure:: img/w5500_evb_pico_side.png + :align: center + :alt: W5500 Evaluation Board + + Wiznet W5500_EVB_PICO evaluation board (Image courtesy of Wiznet) + +Supported Features +================== + +The w5500_evb_pico board configuration supports the following +hardware features: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - NVIC + - N/A + - :dtcompatible:`arm,v6m-nvic` + * - UART + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` + - :dtcompatible:`raspberrypi,pico-gpio` + * - ADC + - :kconfig:option:`CONFIG_ADC` + - :dtcompatible:`raspberrypi,pico-adc` + * - I2C + - :kconfig:option:`CONFIG_I2C` + - :dtcompatible:`snps,designware-i2c` + * - SPI + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi` + * - USB Device + - :kconfig:option:`CONFIG_USB_DEVICE_STACK` + - :dtcompatible:`raspberrypi,pico-usbd` + * - HWINFO + - :kconfig:option:`CONFIG_HWINFO` + - N/A + * - Watchdog Timer (WDT) + - :kconfig:option:`CONFIG_WATCHDOG` + - :dtcompatible:`raspberrypi,pico-watchdog` + * - PWM + - :kconfig:option:`CONFIG_PWM` + - :dtcompatible:`raspberrypi,pico-pwm` + * - Flash + - :kconfig:option:`CONFIG_FLASH` + - :dtcompatible:`raspberrypi,pico-flash` + * - UART (PIO) + - :kconfig:option:`CONFIG_SERIAL` + - :dtcompatible:`raspberrypi,pico-uart-pio` + * - SPI (PIO) + - :kconfig:option:`CONFIG_SPI` + - :dtcompatible:`raspberrypi,pico-spi-pio` + * - W5500 Ethernet + - :kconfig:option:`CONFIG_NETWORKING` + - :dtcompatible:`wiznet,w5500` + +Pin Mapping +=========== + +The peripherals of the RP2040 SoC can be routed to various pins on the board. +The configuration of these routes can be modified through DTS. Please refer to +the datasheet to see the possible routings for each peripheral. + +External pin mapping on the W5500_EVB_PICO is identical to the Raspberry Pi +Pico. Since GPIO 25 is routed to the on-board LED on, similar to the Raspberry +Pi Pico, the blinky example works as intended. The W5500 is routed to the SPI0 +(P16-P19), with the reset and interrupt signal for the W5500 routed to P20 and +P21, respectively. All of these are shared with the edge connector on the +board. + +Refer to `W55500 Evaluation Board Documentation`_ for a board schematic and +other certifications. + +Default Zephyr Peripheral Mapping: +---------------------------------- + +.. rst-class:: rst-columns + +- UART0_TX : P0 +- UART0_RX : P1 +- I2C0_SDA : P4 +- I2C0_SCL : P5 +- I2C1_SDA : P14 +- I2C1_SCL : P15 +- SPI0_RX : P16 +- SPI0_CSN : P17 +- SPI0_SCK : P18 +- SPI0_TX : P19 +- W5500 Reset : P20 +- W5500 Interrupt : P21 +- ADC_CH0 : P26 +- ADC_CH1 : P27 +- ADC_CH2 : P28 +- ADC_CH3 : P29 + +Programming and Debugging +************************* + +Flashing +======== + +Using SEGGER JLink +------------------ + +You can Flash the w5500_evb_pico with a SEGGER JLink debug probe as described in +:ref:`Building, Flashing and Debugging `. + +Here is an example of building and flashing the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :goals: build + +.. code-block:: bash + + west flash --runner jlink + +Using OpenOCD +------------- + +To use PicoProbe, You must configure **udev**. + +Create a file in /etc/udev.rules.d with any name, and write the line below. + +.. code-block:: bash + + ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", MODE="660", GROUP="plugdev", TAG+="uaccess" + +This example is valid for the case that the user joins to `plugdev` groups. + +The Raspberry Pi Pico, and thus the W55500 Evaluation Board, has an SWD +interface that can be used to program and debug the on board RP2040. This +interface can be utilized by OpenOCD. To use it with the RP2040, OpenOCD +version 0.12.0 or later is needed. + +If you are using a Debian based system (including RaspberryPi OS, Ubuntu. and +more), using the `pico_setup.sh`_ script is a convenient way to set up the +forked version of OpenOCD. + +Depending on the interface used (such as JLink), you might need to +checkout to a branch that supports this interface, before proceeding. +Build and install OpenOCD as described in the README. + +Here is an example of building and flashing the :zephyr:code-sample:`blinky` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :goals: build flash + :gen-args: -DOPENOCD=/usr/local/bin/openocd -DOPENOCD_DEFAULT_PATH=/usr/local/share/openocd/scripts -DRPI_PICO_DEBUG_ADAPTER=picoprobe + +Set the environment variables **OPENOCD** to `/usr/local/bin/openocd` and +**OPENOCD_DEFAULT_PATH** to `/usr/local/share/openocd/scripts`. This should +work with the OpenOCD that was installed with the default configuration. This +configuration also works with an environment that is set up by the +`pico_setup.sh`_ script. + +**RPI_PICO_DEBUG_ADAPTER** specifies what debug adapter is used for debugging. + +If **RPI_PICO_DEBUG_ADAPTER** was not assigned, `picoprobe` is used by default. +The other supported adapters are `raspberrypi-swd`, `jlink` and +`blackmagicprobe`. How to connect `picoprobe` and `raspberrypi-swd` is +described in `Getting Started with Raspberry Pi Pico`_. Any other SWD debug +adapter maybe also work with this configuration. + +The value of **RPI_PICO_DEBUG_ADAPTER** is cached, so it can be omitted from +`west flash` and `west debug` if it was previously set while running +`west build`. + +**RPI_PICO_DEBUG_ADAPTER** is used in an argument to OpenOCD as +`"source [find interface/${RPI_PICO_DEBUG_ADAPTER}.cfg]"`. Thus, +**RPI_PICO_DEBUG_ADAPTER** needs to be assigned the file name of the debug +adapter. + +You can also flash the board with the following +command that directly calls OpenOCD (assuming a SEGGER JLink adapter is used): + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' -c 'program path/to/zephyr.elf verify reset exit' + +Using UF2 +--------- + +If you don't have an SWD adapter, you can flash the Raspberry Pi Pico with +a UF2 file. By default, building an app for this board will generate a +`build/zephyr/zephyr.uf2` file. If the Pico is powered on with the `BOOTSEL` +button pressed, it will appear on the host as a mass storage device. The +UF2 file should be drag-and-dropped to the device, which will flash the Pico. + +Debugging +========= + +The SWD interface can also be used to debug the board. To achieve this, you can +either use SEGGER JLink or OpenOCD. + +Using SEGGER JLink +------------------ + +Use a SEGGER JLink debug probe and follow the instruction in +:ref:`Building, Flashing and Debugging`. + + +Using OpenOCD +------------- + +Install OpenOCD as described for flashing the board. + +Here is an example for debugging the :zephyr:code-sample:`blinky` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/basic/blinky + :board: w5500_evb_pico + :maybe-skip-config: + :goals: debug + :gen-args: -DOPENOCD=/usr/local/bin/openocd -DOPENOCD_DEFAULT_PATH=/usr/local/share/openocd/scripts -DRPI_PICO_DEBUG_ADAPTER=raspberrypi-swd + +As with flashing, you can specify the debug adapter by specifying +**RPI_PICO_DEBUG_ADAPTER** at `west build` time. No needs to specify it at +`west debug` time. + +You can also debug with OpenOCD and gdb launching from command-line. +Run the following command: + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -c 'transport select swd' -f target/rp2040.cfg -c "adapter speed 2000" -c 'targets rp2040.core0' + +On another terminal, run: + +.. code-block:: console + + $ gdb-multiarch + +Inside gdb, run: + +.. code-block:: console + + (gdb) tar ext :3333 + (gdb) file path/to/zephyr.elf + +You can then start debugging the board. + +.. target-notes:: + +.. _pico_setup.sh: + https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh + +.. _Getting Started with Raspberry Pi Pico: + https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf + +.. _W55500 Evaluation Board Documentation: + https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico diff --git a/boards/arm/w5500_evb_pico/support/openocd.cfg b/boards/arm/w5500_evb_pico/support/openocd.cfg new file mode 100644 index 00000000000..a9918980457 --- /dev/null +++ b/boards/arm/w5500_evb_pico/support/openocd.cfg @@ -0,0 +1,11 @@ +# Copyright (c) 2022 Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +# Checking and set 'adapter speed'. +# Set adapter speed that assigned by argument if not be seted. +proc set_adapter_speed_if_not_set { speed } { + puts "checking adapter speed..." + if { [catch {adapter speed} ret] } { + adapter speed $speed + } +} diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi b/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi new file mode 100644 index 00000000000..761354420c6 --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico-pinctrl.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , ; + input-enable; + input-schmitt-enable; + }; + }; + + spi0_default: spi0_default { + group1 { + pinmux = , , ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + pwm_ch4b_default: pwm_ch4b_default { + group1 { + pinmux = ; + }; + }; + + adc_default: adc_default { + group1 { + pinmux = , , , ; + input-enable; + }; + }; + + clocks_default: clocks_default { + }; +}; diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico.dts b/boards/arm/w5500_evb_pico/w5500_evb_pico.dts new file mode 100644 index 00000000000..c14cb0b7d64 --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico.dts @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 Yonatan Schachter + * Copyright (c) 2023 Ian Wakely + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +#include +#include "w5500_evb_pico-pinctrl.dtsi" +#include + +#include + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,flash-controller = &ssi; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,code-partition = &code_partition; + }; + + pico_header: connector { + compatible = "raspberrypi,pico-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 0 0>, /* GP0 */ + <1 0 &gpio0 1 0>, /* GP1 */ + <2 0 &gpio0 2 0>, /* GP2 */ + <3 0 &gpio0 3 0>, /* GP3 */ + <4 0 &gpio0 4 0>, /* GP4 */ + <5 0 &gpio0 5 0>, /* GP5 */ + <6 0 &gpio0 6 0>, /* GP6 */ + <7 0 &gpio0 7 0>, /* GP7 */ + <8 0 &gpio0 8 0>, /* GP8 */ + <9 0 &gpio0 9 0>, /* GP9 */ + <10 0 &gpio0 10 0>, /* GP10 */ + <11 0 &gpio0 11 0>, /* GP11 */ + <12 0 &gpio0 12 0>, /* GP12 */ + <13 0 &gpio0 13 0>, /* GP13 */ + <14 0 &gpio0 14 0>, /* GP14 */ + <15 0 &gpio0 15 0>, /* GP15 */ + <16 0 &gpio0 16 0>, /* GP16 */ + <17 0 &gpio0 17 0>, /* GP17 */ + <18 0 &gpio0 18 0>, /* GP18 */ + <19 0 &gpio0 19 0>, /* GP19 */ + <20 0 &gpio0 20 0>, /* GP20 */ + <21 0 &gpio0 21 0>, /* GP21 */ + <22 0 &gpio0 22 0>, /* GP22 */ + <26 0 &gpio0 26 0>, /* GP26 */ + <27 0 &gpio0 27 0>, /* GP27 */ + <28 0 &gpio0 28 0>; /* GP28 */ + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; + label = "LED"; + }; + }; + + pwm_leds { + compatible = "pwm-leds"; + status = "disabled"; + pwm_led0: pwm_led_0 { + pwms = <&pwm 9 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + label = "PWM_LED"; + }; + }; + + aliases { + led0 = &led0; + pwm-led0 = &pwm_led0; + watchdog0 = &wdt0; + }; +}; + +&flash0 { + /* 16MB of flash minus the 0x100 used for + * the second stage bootloader + */ + reg = <0x10000000 DT_SIZE_M(16)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + /* + * Usable flash. Starts at 0x100, after the bootloader. The partition + * size is 16MB minus the 0x100 bytes taken by the bootloader. + */ + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (DT_SIZE_M(16) - 0x100)>; + read-only; + }; + }; +}; + +&clocks { + pinctrl-0 = <&clocks_default>; + pinctrl-names = "default"; +}; + +&uart0 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&i2c0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "disabled"; + clock-frequency = ; +}; + +&spi0 { + clock-frequency = ; + status = "okay"; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + + ethernet: w5500@0 { + compatible = "wiznet,w5500"; + reg = <0x0>; + spi-max-frequency = <50000000>; + int-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; + local-mac-address = [00 00 00 01 02 03]; + status = "okay"; + }; +}; + +&timer { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&adc { + status = "okay"; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&pwm { + pinctrl-0 = <&pwm_ch4b_default>; + pinctrl-names = "default"; + divider-int-0 = <255>; +}; + +&vreg { + regulator-always-on; + regulator-allowed-modes = ; +}; + +pico_spi: &spi0 {}; +pico_i2c0: &i2c0 {}; +pico_i2c1: &i2c1 {}; diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml b/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml new file mode 100644 index 00000000000..85246c0ef1d --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico.yaml @@ -0,0 +1,23 @@ +identifier: w5500_evb_pico +name: Wiznet W5500 Evaluation Board +type: mcu +arch: arm +flash: 16384 +ram: 264 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - uart + - gpio + - adc + - i2c + - spi + - hwinfo + - watchdog + - pwm + - flash + - dma + - counter + - clock diff --git a/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig b/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig new file mode 100644 index 00000000000..ec36f85040c --- /dev/null +++ b/boards/arm/w5500_evb_pico/w5500_evb_pico_defconfig @@ -0,0 +1,14 @@ +CONFIG_SOC_SERIES_RP2XXX=y +CONFIG_SOC_RP2040=y +CONFIG_BOARD_W5500_EVB_PICO=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000 +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_RESET=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts index cdfe959b3fd..ca6dfcf6569 100644 --- a/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core.dts @@ -119,7 +119,7 @@ <&rcc STM32_SRC_LSE RTC_SEL(1)>; }; -&lptim1 { +stm32_lp_tick_source: &lptim1 { status = "okay"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>, <&rcc STM32_SRC_LSE LPTIM1_SEL(3)>; diff --git a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig index aa9e67db821..0c9d0e2a185 100644 --- a/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig +++ b/boards/arm/weact_stm32g431_core/weact_stm32g431_core_defconfig @@ -10,9 +10,6 @@ CONFIG_SOC_STM32G431XX=y CONFIG_CLOCK_CONTROL=y CONFIG_PINCTRL=y -# LSE defined as LPTIM clock source by the DTS -CONFIG_STM32_LPTIM_CLOCK_LSE=y - CONFIG_ARM_MPU=y CONFIG_HW_STACK_PROTECTION=y diff --git a/boards/arm/wio_terminal/wio_terminal.dts b/boards/arm/wio_terminal/wio_terminal.dts index 2e2fe7500a0..a88eeee9e94 100644 --- a/boards/arm/wio_terminal/wio_terminal.dts +++ b/boards/arm/wio_terminal/wio_terminal.dts @@ -48,7 +48,7 @@ }; /* Buttons */ - gpio_keys { + buttons: buttons { compatible = "gpio-keys"; user_button_0: button_0 { label = "User Button 0"; @@ -65,6 +65,13 @@ gpios = <&portc 28 GPIO_ACTIVE_LOW>; zephyr,code = ; }; + }; + + /* Joystick */ + joystick: joystick { + compatible = "gpio-keys"; + polling-mode; + debounce-interval-ms = <100>; joy_sel: joystick_selection { label = "joystick selection"; gpios = <&portd 10 GPIO_ACTIVE_LOW>; @@ -116,6 +123,27 @@ regulator-name = "usb_power_5v_en"; enable-gpios = <&porta 27 GPIO_ACTIVE_LOW>; }; + + /* LCD */ + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&portc 6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&portc 7 GPIO_ACTIVE_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + spi-dev = <&sercom7>; + write-only; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <24000000>; + reg = <0>; + pixel-format = ; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &cpu0 { @@ -264,19 +292,6 @@ pinctrl-0 = <&sercom7_spi_default>; pinctrl-names = "default"; cs-gpios = <&portb 21 GPIO_ACTIVE_LOW>; - - /* LCD */ - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <24000000>; - reg = <0>; - cmd-data-gpios = <&portc 6 GPIO_ACTIVE_LOW>; - reset-gpios = <&portc 7 GPIO_ACTIVE_LOW>; - pixel-format = ; - rotation = <270>; - width = <320>; - height = <240>; - }; }; /* USB */ diff --git a/boards/arm/xmc45_relax_kit/Kconfig.defconfig b/boards/arm/xmc45_relax_kit/Kconfig.defconfig index e6f0add4859..0296bc64ff7 100644 --- a/boards/arm/xmc45_relax_kit/Kconfig.defconfig +++ b/boards/arm/xmc45_relax_kit/Kconfig.defconfig @@ -8,4 +8,15 @@ if BOARD_XMC45_RELAX_KIT config BOARD default "xmc45_relax_kit" +if NETWORKING + +config NET_L2_ETHERNET + default y +config MDIO + default y +config TEST_RANDOM_GENERATOR + default y + +endif # NETWORKING + endif # BOARD_XMC45_RELAX_KIT diff --git a/boards/arm/xmc45_relax_kit/doc/index.rst b/boards/arm/xmc45_relax_kit/doc/index.rst index 7a54abfe37a..6d75146046e 100644 --- a/boards/arm/xmc45_relax_kit/doc/index.rst +++ b/boards/arm/xmc45_relax_kit/doc/index.rst @@ -57,6 +57,12 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | WATCHDOG | on-chip | watchdog | +-----------+------------+-----------------------+ +| MDIO | on-chip | mdio | ++-----------+------------+-----------------------+ +| ETHERNET | on-chip | ethernet | ++-----------+------------+-----------------------+ +| PTP | on-chip | ethernet | ++-----------+------------+-----------------------+ More details about the supported peripherals are available in `XMC4500 TRM`_ Other hardware features are not currently supported by the Zephyr kernel. diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi b/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi index 04156e2890c..936733ea02a 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit-pinctrl.dtsi @@ -27,3 +27,61 @@ drive-push-pull; hwctrl = "disabled"; }; + +ð_p2_0_mdo { + drive-strength = "strong-sharp-edge"; + output-low; +}; + +ð_p2_7_mdc { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_5_tx_en { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_8_txd0 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_9_txd1 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_4_rxer { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_2_rxd0{ + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_3_rxd1 { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_8_clk_rmii { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_9_crs_dv { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts index cebeb2deffe..6b1519a4553 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.dts @@ -133,3 +133,32 @@ pinctrl-0 = <&pwm_out_p1_0_ccu40_ch3 &pwm_out_p1_1_ccu40_ch2>; pinctrl-names = "default"; }; + +ð { + status = "okay"; + pinctrl-0 = <ð_p2_4_rxer ð_p2_2_rxd0 ð_p2_3_rxd1 + ð_p15_8_clk_rmii ð_p15_9_crs_dv ð_p2_5_tx_en + ð_p2_8_txd0 ð_p2_9_txd1>; + pinctrl-names = "default"; + + rxer-port-ctrl = "P2_4"; + rxd0-port-ctrl = "P2_2"; + rxd1-port-ctrl = "P2_3"; + rmii-rx-clk-port-ctrl = "P15_8"; + crs-rx-dv-port-ctrl = "P15_9"; + + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; + +&mdio { + status = "okay"; + mdi-port-ctrl = "P2_0"; + pinctrl-0 = <ð_p2_0_mdo ð_p2_7_mdc>; + pinctrl-names = "default"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + }; +}; diff --git a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml index b84e29973a7..031d9dc5a6c 100644 --- a/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml +++ b/boards/arm/xmc45_relax_kit/xmc45_relax_kit.yaml @@ -13,6 +13,7 @@ supported: - spi - uart - watchdog + - netif:eth ram: 160 flash: 1024 vendor: infineon diff --git a/boards/arm/xmc47_relax_kit/Kconfig.defconfig b/boards/arm/xmc47_relax_kit/Kconfig.defconfig index da18e0230b1..98978ffd540 100644 --- a/boards/arm/xmc47_relax_kit/Kconfig.defconfig +++ b/boards/arm/xmc47_relax_kit/Kconfig.defconfig @@ -7,4 +7,15 @@ if BOARD_XMC47_RELAX_KIT config BOARD default "xmc47_relax_kit" +if NETWORKING + +config NET_L2_ETHERNET + default y +config MDIO + default y +config TEST_RANDOM_GENERATOR + default y + +endif # NETWORKING + endif diff --git a/boards/arm/xmc47_relax_kit/doc/index.rst b/boards/arm/xmc47_relax_kit/doc/index.rst index cbf5eb7a5f3..8fb2ce9997a 100644 --- a/boards/arm/xmc47_relax_kit/doc/index.rst +++ b/boards/arm/xmc47_relax_kit/doc/index.rst @@ -60,6 +60,12 @@ The Relax Kit development board configuration supports the following hardware fe +-----------+------------+-----------------------+ | WATCHDOG | on-chip | watchdog | +-----------+------------+-----------------------+ +| MDIO | on-chip | mdio | ++-----------+------------+-----------------------+ +| ETHERNET | on-chip | ethernet | ++-----------+------------+-----------------------+ +| PTP | on-chip | ethernet | ++-----------+------------+-----------------------+ More details about the supported peripherals are available in `XMC4700 TRM`_ Other hardware features are not currently supported by the Zephyr kernel. diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi index 83d92d7ee51..e6688a7ebb2 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit-pinctrl.dtsi @@ -67,3 +67,72 @@ drive-open-drain; hwctrl = "disabled"; }; + +ð_p2_0_mdo { + drive-strength = "strong-sharp-edge"; + output-low; +}; + +ð_p2_7_mdc { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_5_tx_en { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_8_txd0 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_9_txd1 { + drive-strength = "strong-medium-edge"; + drive-push-pull; + output-low; + hwctrl = "disabled"; +}; + +ð_p2_4_rxer { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_2_rxd0{ + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p2_3_rxd1 { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_8_clk_rmii { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +ð_p15_9_crs_dv { + drive-strength = "strong-medium-edge"; + hwctrl = "disabled"; +}; + +&can_tx_p1_12_node1 { + drive-strength = "strong-soft-edge"; + drive-push-pull; + hwctrl = "disabled"; +}; + +&can_rx_p1_13_node1 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts index 7f1b8f68a38..19cad242f1f 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.dts @@ -48,24 +48,20 @@ }; chosen { - zephyr,sram = &psram1; + zephyr,sram = &dsram_joined; zephyr,flash = &flash0; zephyr,console = &usic0ch0; zephyr,shell-uart = &usic0ch0; zephyr,flash-controller = &flash_controller; zephyr,code-partition = &code_partition; + zephyr,canbus = &can_node1; }; }; -&dsram1 { +&psram1 { compatible = "zephyr,memory-region", "mmio-sram"; - zephyr,memory-region = "DSRAM1"; -}; - -&dsram2 { - compatible = "zephyr,memory-region", "mmio-sram"; - zephyr,memory-region = "DSRAM2"; + zephyr,memory-region = "PSRAM1"; }; &cpu0 { @@ -175,3 +171,45 @@ pinctrl-0 = <&pwm_out_p5_9_ccu80_ch4_high &pwm_out_p5_8_ccu80_ch0_low>; pinctrl-names = "default"; }; + +ð { + status = "okay"; + pinctrl-0 = <ð_p2_4_rxer ð_p2_2_rxd0 ð_p2_3_rxd1 + ð_p15_8_clk_rmii ð_p15_9_crs_dv ð_p2_5_tx_en + ð_p2_8_txd0 ð_p2_9_txd1>; + pinctrl-names = "default"; + + rxer-port-ctrl = "P2_4"; + rxd0-port-ctrl = "P2_2"; + rxd1-port-ctrl = "P2_3"; + rmii-rx-clk-port-ctrl = "P15_8"; + crs-rx-dv-port-ctrl = "P15_9"; + + phy-connection-type = "rmii"; + phy-handle = <&phy>; +}; + +&mdio { + status = "okay"; + mdi-port-ctrl = "P2_0"; + pinctrl-0 = <ð_p2_0_mdo ð_p2_7_mdc>; + pinctrl-names = "default"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + }; +}; + +&can { + clock-prescaler = <6>; +}; + +&can_node1 { + status = "okay"; + bus-speed = <125000>; + sample-point = <875>; + input-src = "RXDC"; + pinctrl-0 = <&can_tx_p1_12_node1 &can_rx_p1_13_node1>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml index d88826ab4ef..72fa356ef0c 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -15,6 +15,7 @@ supported: - arduino_spi - arduino_serial - watchdog + - netif:eth ram: 352 flash: 2048 vendor: infineon diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig b/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig index 8059b39fe90..c8271b2ff0e 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig +++ b/boards/arm64/fvp_base_revc_2xaemv8a/Kconfig @@ -14,5 +14,6 @@ # This doesn't necessarily include the Interrupt Translation Table, which are # 256bytes aligned tables, for reference a 32 ITEs table needs 256bytes. # With 11x64K HEAP, up to 116 ITT tables of 32 ITEs can be allocated. -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 720896 if GIC_V3_ITS diff --git a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml index 68ef6a664e8..b6e39f0dab3 100644 --- a/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml +++ b/boards/arm64/fvp_base_revc_2xaemv8a/fvp_base_revc_2xaemv8a_smp_ns.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_base_revc_2xaemv8a_smp_ns -name: FVP Emulation FVP_Base_RevC-2xAEMvA +name: FVP Emulation FVP_Base_RevC-2xAEMvA (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml index 1e0dfa4a9b2..ed63f35d101 100644 --- a/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml +++ b/boards/arm64/fvp_baser_aemv8r/fvp_baser_aemv8r_smp.yaml @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 identifier: fvp_baser_aemv8r_smp -name: FVP Emulation FVP_BaseR_AEMv8R +name: FVP Emulation FVP_BaseR_AEMv8R (SMP) arch: arm64 type: sim toolchain: diff --git a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts index 4bc1e1ce9f2..701401f569b 100644 --- a/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts +++ b/boards/arm64/intel_socfpga_agilex5_socdk/intel_socfpga_agilex5_socdk.dts @@ -21,6 +21,15 @@ }; }; +&sdmmc { + status = "okay"; + mmc { + /*SD Disk Access */ + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; +}; + &uart0 { status = "okay"; current-speed = <115200>; diff --git a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi index 83070adf93f..31e35907f86 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi +++ b/boards/arm64/mimx93_evk/mimx93_evk-pinctrl.dtsi @@ -26,4 +26,61 @@ drive-strength = "x5"; }; }; + + i2c1_default: i2c1_default { + group0 { + pinmux = <&iomuxc1_i2c1_scl_lpi2c_scl_lpi2c1_scl>, + <&iomuxc1_i2c1_sda_lpi2c_sda_lpi2c1_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c2_default: i2c2_default { + group0 { + pinmux = <&iomuxc1_i2c2_scl_lpi2c_scl_lpi2c2_scl>, + <&iomuxc1_i2c2_sda_lpi2c_sda_lpi2c2_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c3_default: i2c3_default { + group0 { + pinmux = <&iomuxc1_gpio_io01_lpi2c_scl_lpi2c3_scl>, + <&iomuxc1_gpio_io00_lpi2c_sda_lpi2c3_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + i2c4_default: i2c4_default { + group0 { + pinmux = <&iomuxc1_gpio_io03_lpi2c_scl_lpi2c4_scl>, + <&iomuxc1_gpio_io02_lpi2c_sda_lpi2c4_sda>; + drive-strength = "x5"; + drive-open-drain; + slew-rate = "fast"; + input-enable; + }; + }; + + spi3_default: spi3_default { + group0 { + pinmux = <&iomuxc1_gpio_io07_lpspi_pcs_lpspi3_pcs1>, + <&iomuxc1_gpio_io08_lpspi_pcs_lpspi3_pcs0>, + <&iomuxc1_gpio_io09_lpspi_sin_lpspi3_sin>, + <&iomuxc1_gpio_io10_lpspi_sout_lpspi3_sout>, + <&iomuxc1_gpio_io11_lpspi_sck_lpspi3_sck>; + slew-rate = "fast"; + drive-strength = "x5"; + }; + }; + }; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts index 375bb2f7a0e..421ad5e3c71 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.dts +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.dts @@ -28,6 +28,41 @@ sram0: memory@c0000000 { reg = <0xc0000000 DT_SIZE_M(1)>; }; + + aliases { + led0 = &led_r; + sw0 = &btn_1; + }; + + leds { + compatible = "gpio-leds"; + led_r: led_r { + label = "LED_R"; + gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>; + }; + led_g: led_g { + label = "LED_G"; + gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; + }; + led_b: led_b { + label = "LED_B"; + gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + btn_1: btn_1{ + label = "BTN1"; + gpios = <&gpio2 23 GPIO_ACTIVE_LOW>; + }; + + btn_2: btn_2{ + label = "BTN2"; + gpios = <&gpio2 24 GPIO_ACTIVE_LOW>; + }; + }; }; &lpuart1 { @@ -45,3 +80,41 @@ pinctrl-0 = <&uart2_default>; pinctrl-names = "default"; }; + + +&lpi2c1{ + status = "disabled"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&lpi2c2{ + status = "disabled"; + clock-frequency = ; + pinctrl-0 = <&i2c2_default>; + pinctrl-names = "default"; +}; + +&lpspi3 { + status = "disabled"; + clock-frequency = <1000000>; + pinctrl-0 = <&spi3_default>; + pinctrl-names = "default"; +}; + +&gpio1{ + status = "okay"; +}; + +&gpio2{ + status = "okay"; +}; + +&gpio3{ + status = "okay"; +}; + +&gpio4{ + status = "okay"; +}; diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml index 72e4c677fc0..d4fc0bc7ae6 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55.yaml @@ -6,6 +6,11 @@ toolchain: - zephyr - cross-compile ram: 1024 +supported: + - gpio + - uart + - i2c + - spi testing: ignore_tags: - net diff --git a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig index 53cb74f825c..fb60fdfd9bb 100644 --- a/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig +++ b/boards/arm64/mimx93_evk/mimx93_evk_a55_defconfig @@ -22,6 +22,7 @@ CONFIG_BOARD_MIMX93_EVK_A55=y # Zephyr Kernel Configuration CONFIG_XIP=n +CONFIG_KERNEL_DIRECT_MAP=y # Serial Drivers CONFIG_SERIAL=y diff --git a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig index a312d33601a..3995ececf44 100644 --- a/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig +++ b/boards/arm64/rcar_h3ulcb_ca57/rcar_h3ulcb_ca57_defconfig @@ -12,6 +12,7 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 CONFIG_XIP=n CONFIG_MAX_XLAT_TABLES=24 +CONFIG_ARMV8_A_NS=y # Enable console CONFIG_CONSOLE=y diff --git a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig index 3dca6448ac4..a6eb4060d39 100644 --- a/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig +++ b/boards/arm64/rcar_salvator_xs_m3/rcar_salvator_xs_m3_defconfig @@ -12,6 +12,7 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=8300000 CONFIG_XIP=n CONFIG_MAX_XLAT_TABLES=24 +CONFIG_ARMV8_A_NS=y # Enable console CONFIG_CONSOLE=y diff --git a/boards/common/intel_adsp.board.cmake b/boards/common/intel_adsp.board.cmake deleted file mode 100644 index 813ece3fb99..00000000000 --- a/boards/common/intel_adsp.board.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -board_runner_args(intel_adsp "--default-key=${RIMAGE_SIGN_KEY}") - -board_finalize_runner_args(intel_adsp) diff --git a/boards/common/linkserver.board.cmake b/boards/common/linkserver.board.cmake index 743eef57399..74de78449c6 100644 --- a/boards/common/linkserver.board.cmake +++ b/boards/common/linkserver.board.cmake @@ -1,4 +1,6 @@ # Copyright 2023 NXP # SPDX-License-Identifier: Apache-2.0 +board_set_flasher_ifnset(linkserver) +board_set_debugger_ifnset(linkserver) board_finalize_runner_args(linkserver "--dt-flash=y") diff --git a/boards/deprecated.cmake b/boards/deprecated.cmake index f238347203a..270d5f5e1a9 100644 --- a/boards/deprecated.cmake +++ b/boards/deprecated.cmake @@ -8,16 +8,4 @@ # To add a board rename, add a line in following format: # set(_DEPRECATED ) -set(bl5340_dvk_cpuappns_DEPRECATED bl5340_dvk_cpuapp_ns) -set(bt6x0_DEPRECATED bt610) -set(mps2_an521_nonsecure_DEPRECATED mps2_an521_ns) -set(musca_b1_nonsecure_DEPRECATED musca_b1_ns) -set(musca_s1_nonsecure_DEPRECATED musca_s1_ns) -set(nrf5340dk_nrf5340_cpuappns_DEPRECATED nrf5340dk_nrf5340_cpuapp_ns) -set(nrf9160dk_nrf9160ns_DEPRECATED nrf9160dk_nrf9160_ns) -set(circuitdojo_feather_nrf9160ns_DEPRECATED circuitdojo_feather_nrf9160_ns) -set(nrf9160_innblue21ns_DEPRECATED nrf9160_innblue21_ns) -set(nrf9160_innblue22ns_DEPRECATED nrf9160_innblue22_ns) -set(sparkfun_thing_plus_nrf9160ns_DEPRECATED sparkfun_thing_plus_nrf9160_ns) -set(thingy53_nrf5340_cpuappns_DEPRECATED thingy53_nrf5340_cpuapp_ns) set(esp32_DEPRECATED esp32_devkitc_wrover) diff --git a/boards/mips/qemu_malta/qemu_malta.yaml b/boards/mips/qemu_malta/qemu_malta.yaml index 3749da567ea..083fb0e93b1 100644 --- a/boards/mips/qemu_malta/qemu_malta.yaml +++ b/boards/mips/qemu_malta/qemu_malta.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (little endian) type: qemu simulation: qemu arch: mips diff --git a/boards/mips/qemu_malta/qemu_malta_be.yaml b/boards/mips/qemu_malta/qemu_malta_be.yaml index 80eab182050..91a9444d00b 100644 --- a/boards/mips/qemu_malta/qemu_malta_be.yaml +++ b/boards/mips/qemu_malta/qemu_malta_be.yaml @@ -1,5 +1,5 @@ identifier: qemu_malta_be -name: QEMU emulation for MIPS +name: QEMU emulation for MIPS (big endian) type: qemu simulation: qemu arch: mips diff --git a/boards/nios2/altera_max10/doc/index.rst b/boards/nios2/altera_max10/doc/index.rst index c3a91d2ec9c..db4daf5256a 100644 --- a/boards/nios2/altera_max10/doc/index.rst +++ b/boards/nios2/altera_max10/doc/index.rst @@ -233,14 +233,14 @@ You will see output similar to the following: Listening on port 3335 for connection from GDB: accepted isr_tables_syms () at /projects/zephyr/arch/common/isr_tables.c:63 63 GEN_ABSOLUTE_SYM(__ISR_LIST_SIZEOF, sizeof(struct _isr_list)); - (gdb) b _PrepC + (gdb) b z_prep_c Breakpoint 1 at 0xdf0: file /projects/zephyr/arch/nios2/core/prep_c.c, line 36. (gdb) b z_cstart Breakpoint 2 at 0x1254: file /projects/zephyr/kernel/init.c, line 348. (gdb) c Continuing. - Breakpoint 2, _Cstart () at /projects/zephyr/kernel/init.c:348 + Breakpoint 2, z_cstart () at /projects/zephyr/kernel/init.c:348 348 { (gdb) diff --git a/boards/posix/common/extra_args/CMakeLists.txt b/boards/posix/common/extra_args/CMakeLists.txt new file mode 100644 index 00000000000..c3448051452 --- /dev/null +++ b/boards/posix/common/extra_args/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if (CONFIG_NATIVE_EXTRA_CMDLINE_ARGS) + zephyr_library() + zephyr_library_sources(extra_args.c) +endif() diff --git a/boards/posix/common/extra_args/Kconfig b/boards/posix/common/extra_args/Kconfig new file mode 100644 index 00000000000..e1e1f8d725e --- /dev/null +++ b/boards/posix/common/extra_args/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config NATIVE_EXTRA_CMDLINE_ARGS + depends on ARCH_POSIX + string "Extra command line arguments" + help + Extra command line options/arguments which will be handled like if they were passed to the + program from the shell. These will be parsed just before the shell provided ones. diff --git a/boards/posix/common/extra_args/extra_args.c b/boards/posix/common/extra_args/extra_args.c new file mode 100644 index 00000000000..b2e57dc674e --- /dev/null +++ b/boards/posix/common/extra_args/extra_args.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +static void remove_one_char(char *str) +{ + int i; + + for (i = 0; str[i] != 0; i++) { + str[i] = str[i+1]; + } +} + +static void register_kconfig_args(void) +{ + static char kconfig_args[] = CONFIG_NATIVE_EXTRA_CMDLINE_ARGS; + int argc = 0; + char **argv = NULL; +#define REALLOC_INC 100 + int alloced = 0; + bool new_arg = true, literal = false, escape = false; + + if (kconfig_args[0] == 0) { + return; + } + + for (int i = 0; kconfig_args[i] != 0; i++) { + if ((literal == false) && (escape == false) && isspace(kconfig_args[i])) { + new_arg = true; + kconfig_args[i] = 0; + continue; + } + if ((escape == false) && (kconfig_args[i] == '\\')) { + escape = true; + remove_one_char(&kconfig_args[i]); + i--; + continue; + } + if ((escape == false) && (kconfig_args[i] == '"')) { + literal = !literal; + remove_one_char(&kconfig_args[i]); + i--; + continue; + } + escape = false; + + if (new_arg) { + new_arg = false; + if (argc >= alloced) { + alloced += REALLOC_INC; + argv = nsi_host_realloc(argv, alloced*sizeof(char *)); + if (argv == NULL) { + nsi_print_error_and_exit("Out of memory\n"); + } + } + argv[argc++] = &kconfig_args[i]; + } + } + + nsi_register_extra_args(argc, argv); + + nsi_host_free(argv); +} + +NATIVE_TASK(register_kconfig_args, PRE_BOOT_1, 100); diff --git a/boards/posix/common/natsim_config.cmake b/boards/posix/common/natsim_config.cmake index 2ab155af105..54e800cd327 100644 --- a/boards/posix/common/natsim_config.cmake +++ b/boards/posix/common/natsim_config.cmake @@ -20,7 +20,7 @@ set(nsi_config_content "NSI_EXTRA_LIBS:=$,\ >" "NSI_PATH:=${NSI_DIR}/" "NSI_N_CPUS:=${CONFIG_NATIVE_SIMULATOR_NUMBER_MCUS}" - "NSI_LOCALIZE_OPTIONS:=--localize-symbol=CONFIG_*" + "NSI_LOCALIZE_OPTIONS:=--localize-symbol=CONFIG_* $,\ >" ) string(REPLACE ";" "\n" nsi_config_content "${nsi_config_content}") diff --git a/boards/posix/common/sdl/CMakeLists.txt b/boards/posix/common/sdl/CMakeLists.txt index a790845afd8..0e20283324c 100644 --- a/boards/posix/common/sdl/CMakeLists.txt +++ b/boards/posix/common/sdl/CMakeLists.txt @@ -12,8 +12,10 @@ if (CONFIG_NATIVE_APPLICATION) zephyr_include_directories(${SDL2_INCLUDE_DIRS}) zephyr_compile_options(${SDL2_CFLAGS_OTHER}) else() - target_link_options(native_simulator INTERFACE "-l${SDL2_LIBRARIES}") - target_compile_options(native_simulator INTERFACE "-I${SDL2_INCLUDE_DIRS}" ${SDL2_CFLAGS_OTHER}) + list(TRANSFORM SDL2_LIBRARIES PREPEND "-l" OUTPUT_VARIABLE SDL2_LIBRARIES_OPTION) + target_link_options(native_simulator INTERFACE "${SDL2_LIBRARIES_OPTION}") + list(TRANSFORM SDL2_INCLUDE_DIRS PREPEND "-I" OUTPUT_VARIABLE SDL2_INCLUDE_DIRS_OPTION) + target_compile_options(native_simulator INTERFACE "${SDL2_INCLUDE_DIRS_OPTION}" ${SDL2_CFLAGS_OTHER}) endif() zephyr_library_sources(sdl_events.c) diff --git a/boards/posix/doc/arch_soc.rst b/boards/posix/doc/arch_soc.rst index f0e469308ab..fcc6734d2a6 100644 --- a/boards/posix/doc/arch_soc.rst +++ b/boards/posix/doc/arch_soc.rst @@ -169,6 +169,24 @@ In the previous example, modifying the code as follows would work: #endif } +.. _posix_arch_unsupported: + +Significant unsupported features +******************************** + +Currently, these are the most significant features which are not supported in this architecture: + +* :ref:`User mode/userspace `: When building for these targets, + :kconfig:option:`CONFIG_USERSPACE` will always be disabled, + and all calls into the kernel will be done as normal calls. + +* Stack checks: :kconfig:option:`CONFIG_HW_STACK_PROTECTION`, + :kconfig:option:`CONFIG_STACK_CANARIES`, and + :kconfig:option:`CONFIG_THREAD_ANALYZER`. + This is due to how Zephyr allocated threads' stacks are not `actually` being used like they are + in other architectures. Check + :ref:`the architecture section's architecture layer paragraph ` + for more information. .. _posix_arch_rationale: @@ -219,7 +237,7 @@ section. instruction executes is just some of it; Emulating peripherals accurately is another side. -This native port compiles your code directly for the host architectture +This native port compiles your code directly for the host architecture (typically x86), with no instrumentation or monitoring code. Your code executes directly in the host CPU. That is, your code executes just as fast as it possibly can. @@ -294,6 +312,8 @@ Architecture and design Zephyr layering when built against an embedded target (left), and targeting a POSIX arch based board (right) +.. _posix_arch_design_archl: + Arch layer ========== diff --git a/boards/posix/doc/bsim_boards_design.rst b/boards/posix/doc/bsim_boards_design.rst index 9b6bcfc0bca..6165f76a438 100644 --- a/boards/posix/doc/bsim_boards_design.rst +++ b/boards/posix/doc/bsim_boards_design.rst @@ -167,13 +167,16 @@ The basic architecture layering of these boards is as follows: Overall architecture in a Zephyr application in an embedded target vs a bsim target -Important limitations -===================== +Important limitations and unsupported features +============================================== All native and bsim boards share the same set of :ref:`important limitations which` are inherited from the POSIX arch and `inf_clock` design. +Similarly, they inherit the POSIX architecture +:ref:`unsupported features set `. + .. _Threading: Threading and overall scheduling of CPU and HW models diff --git a/boards/posix/native_posix/CMakeLists.txt b/boards/posix/native_posix/CMakeLists.txt index d9b37953e77..20210a46a81 100644 --- a/boards/posix/native_posix/CMakeLists.txt +++ b/boards/posix/native_posix/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_compile_definitions(NO_POSIX_CHEATS) +zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) zephyr_library_sources( hw_models_top.c diff --git a/boards/posix/native_posix/hw_models_top.c b/boards/posix/native_posix/hw_models_top.c index ebd582fb0b9..ba2f7d6584c 100644 --- a/boards/posix/native_posix/hw_models_top.c +++ b/boards/posix/native_posix/hw_models_top.c @@ -71,7 +71,7 @@ void hwm_signal_end_handler(int sig) * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received * the default handler would be called to terminate the program no matter what. * - * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or + * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809L or * _XOPEN_SOURCE>=500 */ void hwm_set_sig_handler(void) diff --git a/boards/posix/native_posix/hw_models_top.h b/boards/posix/native_posix/hw_models_top.h index 47d3333277e..ea50d0f949c 100644 --- a/boards/posix/native_posix/hw_models_top.h +++ b/boards/posix/native_posix/hw_models_top.h @@ -15,6 +15,7 @@ extern "C" { #endif #define NEVER UINT64_MAX +#define NSI_NEVER UINT64_MAX void hwm_one_event(void); void hwm_init(void); diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index 75af8bdb1fd..74a3c30049b 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -1,219 +1,7 @@ /* - * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ -/dts-v1/; -#include -#include -#include -#include - -/ { - model = "Native POSIX Board"; - compatible = "zephyr,posix"; - - chosen { - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,uart-mcumgr = &uart0; - zephyr,flash = &flash0; - zephyr,entropy = &rng; - zephyr,flash-controller = &flashcontroller0; - zephyr,display = &sdl_dc; - zephyr,canbus = &can_loopback0; - }; - - aliases { - eeprom-0 = &eeprom0; - i2c-0 = &i2c0; - spi-0 = &spi0; - led0 = &led0; - rtc = &rtc; - }; - - leds { - compatible = "gpio-leds"; - led0: led_0 { - gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; - label = "Green LED"; - }; - }; - - lvgl_pointer { - compatible = "zephyr,lvgl-pointer-input"; - input = <&input_sdl_touch>; - }; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu0: cpu@0 { - compatible = "zephyr,native-posix-cpu"; - reg = <0>; - }; - }; - - flashcontroller0: flash-controller@0 { - compatible = "zephyr,sim-flash"; - reg = <0x00000000 DT_SIZE_K(2048)>; - - #address-cells = <1>; - #size-cells = <1>; - erase-value = <0xff>; - - flash0: flash@0 { - status = "okay"; - compatible = "soc-nv-flash"; - erase-block-size = <4096>; - write-block-size = <1>; - reg = <0x00000000 DT_SIZE_K(2048)>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - boot_partition: partition@0 { - label = "mcuboot"; - reg = <0x00000000 0x0000C000>; - }; - slot0_partition: partition@c000 { - label = "image-0"; - reg = <0x0000C000 0x00069000>; - }; - slot1_partition: partition@75000 { - label = "image-1"; - reg = <0x00075000 0x00069000>; - }; - scratch_partition: partition@de000 { - label = "image-scratch"; - reg = <0x000de000 0x0001e000>; - }; - storage_partition: partition@fc000 { - label = "storage"; - reg = <0x000fc000 0x00004000>; - }; - }; - }; - }; - - eeprom0: eeprom { - status = "okay"; - compatible = "zephyr,sim-eeprom"; - size = ; - }; - - i2c0: i2c@100 { - status = "okay"; - compatible = "zephyr,i2c-emul-controller"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x100 4>; - }; - - spi0: spi@200 { - status = "okay"; - compatible = "zephyr,spi-emul-controller"; - clock-frequency = <50000000>; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x200 4>; - }; - - espi0: espi@300 { - status = "okay"; - compatible = "zephyr,espi-emul-controller"; - reg = <0x300 4>; - #address-cells = <1>; - #size-cells = <0>; - }; - - uart0: uart { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - uart1: uart_1 { - status = "okay"; - compatible = "zephyr,native-posix-uart"; - /* Dummy current-speed entry to comply with serial - * DTS binding - */ - current-speed = <0>; - }; - - rng: rng { - status = "okay"; - compatible = "zephyr,native-posix-rng"; - }; - - counter0: counter { - status = "okay"; - compatible = "zephyr,native-posix-counter"; - }; - - gpio0: gpio@800 { - status = "okay"; - compatible = "zephyr,gpio-emul"; - reg = <0x800 0x4>; - rising-edge; - falling-edge; - high-level; - low-level; - gpio-controller; - #gpio-cells = <2>; - }; - - zephyr_udc0: udc0 { - compatible = "zephyr,native-posix-udc"; - }; - - sdl_dc: sdl_dc { - compatible = "zephyr,sdl-dc"; - height = <240>; - width = <320>; - }; - - input_sdl_touch: input-sdl-touch { - compatible = "zephyr,input-sdl-touch"; - }; - - can_loopback0: can_loopback0 { - status = "okay"; - compatible = "zephyr,can-loopback"; - sample-point = <875>; - bus-speed = <125000>; - }; - - can0: can { - status = "disabled"; - compatible = "zephyr,native-posix-linux-can"; - /* adjust zcan0 to desired host interface or create an alternative - * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 - */ - host-interface = "zcan0"; - sample-point = <875>; - bus-speed = <125000>; - }; - - rtc: rtc { - status = "okay"; - compatible = "zephyr,rtc-emul"; - alarms-count = <2>; - }; - - adc0: adc { - compatible = "zephyr,adc-emul"; - nchannels = <2>; - #io-channel-cells = <1>; - status = "okay"; - }; -}; +#include "../native_sim/native_sim.dts" diff --git a/boards/posix/native_posix/native_posix.yaml b/boards/posix/native_posix/native_posix.yaml index a1fb897eb75..d3ba08cc9a6 100644 --- a/boards/posix/native_posix/native_posix.yaml +++ b/boards/posix/native_posix/native_posix.yaml @@ -11,6 +11,7 @@ toolchain: supported: - can - counter + - dma - eeprom - netif:eth - usb_device @@ -19,6 +20,4 @@ supported: - spi - gpio - rtc -testing: - default: true vendor: zephyr diff --git a/boards/posix/native_posix/native_posix_64.yaml b/boards/posix/native_posix/native_posix_64.yaml index 56ad340f176..544dac9cc2a 100644 --- a/boards/posix/native_posix/native_posix_64.yaml +++ b/boards/posix/native_posix/native_posix_64.yaml @@ -11,6 +11,7 @@ toolchain: supported: - can - counter + - dma - eeprom - netif:eth - usb_device diff --git a/boards/posix/native_sim/CMakeLists.txt b/boards/posix/native_sim/CMakeLists.txt index 34a538f4c60..5ddf0e5f143 100644 --- a/boards/posix/native_sim/CMakeLists.txt +++ b/boards/posix/native_sim/CMakeLists.txt @@ -27,6 +27,10 @@ if(CONFIG_HAS_SDL) add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/sdl/ ${CMAKE_CURRENT_BINARY_DIR}/sdl) endif() +add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/extra_args/ + ${CMAKE_CURRENT_BINARY_DIR}/extra_args +) + set(nsi_config_content ${nsi_config_content} "NSI_NATIVE=1" diff --git a/boards/posix/native_sim/Kconfig b/boards/posix/native_sim/Kconfig index aabbd4d794f..ddf76a5f157 100644 --- a/boards/posix/native_sim/Kconfig +++ b/boards/posix/native_sim/Kconfig @@ -46,5 +46,6 @@ config NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME to set the correct native_sim option (CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME) source "boards/$(ARCH)/common/sdl/Kconfig" +source "boards/$(ARCH)/common/extra_args/Kconfig" endif # BOARD_NATIVE_SIM diff --git a/boards/posix/native_sim/doc/index.rst b/boards/posix/native_sim/doc/index.rst index 5d4ab7b8b8c..64579fc4631 100644 --- a/boards/posix/native_sim/doc/index.rst +++ b/boards/posix/native_sim/doc/index.rst @@ -38,12 +38,18 @@ Please check the .. _nativesim_important_limitations: -Important limitations -********************* +Important limitations and unsupported features +********************************************** ``native_sim`` is based on the :ref:`POSIX architecture`, and therefore :ref:`its limitations ` and considerations apply to it. +Similarly, it inherits the POSIX architecture +:ref:`unsupported features set `. + +Note that some drivers may have limitations, or may not support their whole driver API optional +functionality. + .. _native_sim_how_to_use: How to use it @@ -345,6 +351,10 @@ The following peripherals are currently provided with this board: execution speed of native_sim and the host load, it may return a value considerably ahead of the simulated time. + Note this device does not yet have an :ref:`RTC API compatible driver `. + +.. _nsim_per_entr: + **Entropy device** An entropy device based on the host :c:func:`random` API. This device will generate the same sequence of random numbers if initialized @@ -353,6 +363,8 @@ The following peripherals are currently provided with this board: :samp:`--seed={}` where the value specified is a 32-bit integer such as 97229 (decimal), 0x17BCD (hex), or 0275715 (octal). +.. _nsim_per_ethe: + **Ethernet driver** A simple TAP based ethernet driver is provided. The driver expects that the **zeth** network interface already exists in the host system. The **zeth** @@ -367,6 +379,7 @@ The following peripherals are currently provided with this board: .. _net-tools: https://github.com/zephyrproject-rtos/net-tools +.. _nsim_bt_host_cont: **Bluetooth controller** It's possible to use the host's Bluetooth adapter as a Bluetooth @@ -387,11 +400,15 @@ The following peripherals are currently provided with this board: a virtual Bluetooth controller that does not depend on the Linux Bluetooth stack and its HCI interface. +.. _nsim_per_usb: + **USB controller** It's possible to use the Virtual USB controller working over USB/IP protocol. More information can be found in :ref:`Testing USB over USP/IP in native_sim `. +.. _nsim_per_disp_sdl: + **Display driver** A display driver is provided that creates a window on the host machine to render display content. @@ -406,16 +423,27 @@ The following peripherals are currently provided with this board: .. code-block:: console + $ sudo dpkg --add-architecture i386 + $ sudo apt update $ sudo apt-get install pkg-config libsdl2-dev:i386 $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig .. _SDL2: https://www.libsdl.org/download-2.0.php -**Flash driver** - A flash driver is provided that accesses all flash data through a binary file - on the host file system. The behavior of the flash device can be configured - through the native_sim board devicetree or Kconfig settings under +.. _nsim_per_flash_simu: + +**EEPROM simulator** + The EEPROM simulator can also be used in the native targets. In these, you have the added feature + of keeping the EEPROM content on a file on the host filesystem. + By default this is kept in the file :file:`eeprom.bin` in the current working directory, but you + can select the location of this file and its name with the command line parameter ``--eeprom``. + Some more information can be found in :ref:`the emulators page `. + +**Flash simulator** + The flash simulator can also be used in the native targets. In this you have the option to keep + the flash content in a binary file on the host file system or in RAM. The behavior of the flash + device can be configured through the native_sim board devicetree or Kconfig settings under :kconfig:option:`CONFIG_FLASH_SIMULATOR`. By default the binary data is located in the file :file:`flash.bin` in the current @@ -425,9 +453,44 @@ The following peripherals are currently provided with this board: configuration. In case the file does not exists the driver will take care of creating the file, else the existing file is used. + Some more information can be found in :ref:`the emulators page `. + The flash content can be accessed from the host system, as explained in the `Host based flash access`_ section. +**Input events** + Two optional native input drivers are available: + + **evdev driver** + A driver is provided to read input events from a Linux evdev input device and + inject them back into the Zephyr input subsystem. + + The driver is automatically enabled when :kconfig:option:`CONFIG_INPUT` is + enabled and the devicetree contains a node such as: + + .. code-block:: dts + + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + + The application then has to be run with a command line option to specify + which evdev device node has to be used, for example + ``zephyr.exe --evdev=/dev/input/event0``. + + **Input SDL touch** + This driver emulates a touch panel input using the SDL library. It can be enabled with + :kconfig:option:`CONFIG_INPUT_SDL_TOUCH` and configured with the device tree binding + :dtcompatible:`zephyr,input-sdl-touch`. + + More information on using SDL and the Display driver can be found in + :ref:`its section `. + +**CAN controller** + It is possible to use a host CAN controller with the native SockerCAN Linux driver. It can be + enabled with :kconfig:option:`CONFIG_CAN_NATIVE_LINUX` and configured with the device tree binding + :dtcompatible:`zephyr,native-linux-can`. + .. _native_ptty_uart: PTTY UART @@ -522,6 +585,8 @@ Apart from its own peripherals, the native_sim board also has some dedicated backends for some of Zephyr's subsystems. These backends are designed to ease development by integrating more seamlessly with the host operating system: +.. _nsim_back_console: + **Console backend**: A console backend which by default is configured to redirect any :c:func:`printk` write to the native host application's @@ -531,6 +596,8 @@ development by integrating more seamlessly with the host operating system: Otherwise :kconfig:option:`CONFIG_UART_CONSOLE` will be set to select the UART as console backend. +.. _nsim_back_logger: + **Logger backend**: A backend which prints all logger output to the process ``stdout``. It supports timestamping, which can be enabled with @@ -547,11 +614,18 @@ development by integrating more seamlessly with the host operating system: In this later case, by default, the logger is set to output to the `PTTY UART`_. +.. _nsim_back_trace: + **Tracing**: A backend/"bottom" for Zephyr's CTF tracing subsystem which writes the tracing data to a file in the host filesystem. More information can be found in :ref:`Common Tracing Format ` +Emulators +********* + +All :ref:`available HW emulators ` can be used with native_sim. + .. _native_fuse_flash: Host based flash access @@ -589,6 +663,8 @@ these commands: .. code-block:: console + $ sudo dpkg --add-architecture i386 + $ sudo apt update $ sudo apt-get install pkg-config libfuse-dev:i386 $ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig @@ -603,25 +679,27 @@ host libC (:kconfig:option:`CONFIG_EXTERNAL_LIBC`): .. csv-table:: Drivers/backends vs libC choice :header: Driver class, driver name, driver kconfig, libC choices - adc, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, all - bluetooth, userchan, :kconfig:option:`CONFIG_BT_USERCHAN`, host libC - can, can native posix, :kconfig:option:`CONFIG_CAN_NATIVE_POSIX_LINUX`, host libC - console backend, POSIX arch console, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, all - display, display SDL, :kconfig:option:`CONFIG_SDL_DISPLAY`, all - entropy, native posix entropy, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, all - eprom, eprom emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, host libC - ethernet, eth native_posix, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, all - flash, flash simulator, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, all - flash, host based flash access, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, host libC - gpio, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, all - gpio, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, all - i2c, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, all - input, input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, all - log backend, native backend, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, all - rtc, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, all - serial, uart native posix/PTTY, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, all - serial, uart native TTY, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, all - spi, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, all - system tick, native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, all - tracing, Posix tracing backend, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, all - usb, USB native posix, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, host libC + ADC, ADC emul, :kconfig:option:`CONFIG_ADC_EMUL`, All + Bluetooth, :ref:`Userchan `, :kconfig:option:`CONFIG_BT_USERCHAN`, Host libC + CAN, CAN native Linux, :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`, All + Console backend, :ref:`POSIX arch console `, :kconfig:option:`CONFIG_POSIX_ARCH_CONSOLE`, All + Display, :ref:`Display SDL `, :kconfig:option:`CONFIG_SDL_DISPLAY`, All + Entropy, :ref:`Native posix entropy `, :kconfig:option:`CONFIG_FAKE_ENTROPY_NATIVE_POSIX`, All + EEPROM, EEPROM simulator, :kconfig:option:`CONFIG_EEPROM_SIMULATOR`, Host libC + EEPROM, EEPROM emulator, :kconfig:option:`CONFIG_EEPROM_EMULATOR`, All + Ethernet, :ref:`Eth native_posix `, :kconfig:option:`CONFIG_ETH_NATIVE_POSIX`, All + Flash, :ref:`Flash simulator `, :kconfig:option:`CONFIG_FLASH_SIMULATOR`, All + Flash, :ref:`Host based flash access `, :kconfig:option:`CONFIG_FUSE_FS_ACCESS`, Host libC + GPIO, GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL`, All + GPIO, SDL GPIO emulator, :kconfig:option:`CONFIG_GPIO_EMUL_SDL`, All + I2C, I2C emulator, :kconfig:option:`CONFIG_I2C_EMUL`, All + Input, Input SDL touch, :kconfig:option:`CONFIG_INPUT_SDL_TOUCH`, All + Input, Linux evdev, :kconfig:option:`CONFIG_NATIVE_LINUX_EVDEV`, All + Logger backend, :ref:`Native backend `, :kconfig:option:`CONFIG_LOG_BACKEND_NATIVE_POSIX`, All + RTC, RTC emul, :kconfig:option:`CONFIG_RTC_EMUL`, All + Serial, :ref:`UART native posix/PTTY `, :kconfig:option:`CONFIG_UART_NATIVE_POSIX`, All + Serial, :ref:`UART native TTY `, :kconfig:option:`CONFIG_UART_NATIVE_TTY`, All + SPI, SPI emul, :kconfig:option:`CONFIG_SPI_EMUL`, All + System tick, Native_posix timer, :kconfig:option:`CONFIG_NATIVE_POSIX_TIMER`, All + Tracing, :ref:`Posix tracing backend `, :kconfig:option:`CONFIG_TRACING_BACKEND_POSIX`, All + USB, :ref:`USB native posix `, :kconfig:option:`CONFIG_USB_NATIVE_POSIX`, Host libC diff --git a/boards/posix/native_sim/irq_handler.c b/boards/posix/native_sim/irq_handler.c index 3ad8058eb5b..38462b4b14a 100644 --- a/boards/posix/native_sim/irq_handler.c +++ b/boards/posix/native_sim/irq_handler.c @@ -77,13 +77,20 @@ void posix_irq_handler(void) return; } + irq_nbr = hw_irq_ctrl_get_highest_prio_irq(); + + if (irq_nbr == -1) { + /* This is a phony interrupt during a busy wait, no need for more */ + return; + } + if (_kernel.cpus[0].nested == 0) { may_swap = 0; } _kernel.cpus[0].nested++; - while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) { + do { int last_current_running_prio = hw_irq_ctrl_get_cur_prio(); int last_running_irq = currently_running_irq; @@ -95,7 +102,7 @@ void posix_irq_handler(void) currently_running_irq = last_running_irq; hw_irq_ctrl_set_cur_prio(last_current_running_prio); - } + } while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1); _kernel.cpus[0].nested--; @@ -229,6 +236,11 @@ int posix_get_current_irq(void) void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), const void *isr_param_p) { + if (irq_p >= N_IRQS) { + posix_print_error_and_exit("Attempted to configure not existent interrupt %u\n", + irq_p); + return; + } irq_vector_table[irq_p].irq = irq_p; irq_vector_table[irq_p].func = isr_p; irq_vector_table[irq_p].param = isr_param_p; diff --git a/boards/posix/native_sim/native_posix_compat.h b/boards/posix/native_sim/native_posix_compat.h index a2b5dc0299b..6c943606f3f 100644 --- a/boards/posix/native_sim/native_posix_compat.h +++ b/boards/posix/native_sim/native_posix_compat.h @@ -33,6 +33,8 @@ static ALWAYS_INLINE uint64_t hwm_get_time(void) return nsi_hws_get_time(); } +#define NEVER NSI_NEVER + #ifdef __cplusplus } #endif diff --git a/boards/posix/native_sim/native_sim.dts b/boards/posix/native_sim/native_sim.dts index b27a9bd540d..682049c63ca 100644 --- a/boards/posix/native_sim/native_sim.dts +++ b/boards/posix/native_sim/native_sim.dts @@ -1,7 +1,225 @@ /* - * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) * * SPDX-License-Identifier: Apache-2.0 */ -#include "../native_posix/native_posix.dts" +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "Native Sim Board"; + compatible = "zephyr,posix"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,flash = &flash0; + zephyr,entropy = &rng; + zephyr,flash-controller = &flashcontroller0; + zephyr,display = &sdl_dc; + zephyr,canbus = &can_loopback0; + }; + + aliases { + eeprom-0 = &eeprom0; + i2c-0 = &i2c0; + spi-0 = &spi0; + led0 = &led0; + rtc = &rtc; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&input_sdl_touch>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "zephyr,native-posix-cpu"; + reg = <0>; + }; + }; + + flashcontroller0: flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x00000000 DT_SIZE_K(2048)>; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + + flash0: flash@0 { + status = "okay"; + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + reg = <0x00000000 DT_SIZE_K(2048)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000C000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x00069000>; + }; + slot1_partition: partition@75000 { + label = "image-1"; + reg = <0x00075000 0x00069000>; + }; + scratch_partition: partition@de000 { + label = "image-scratch"; + reg = <0x000de000 0x0001e000>; + }; + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; + }; + }; + + eeprom0: eeprom { + status = "okay"; + compatible = "zephyr,sim-eeprom"; + size = ; + }; + + i2c0: i2c@100 { + status = "okay"; + compatible = "zephyr,i2c-emul-controller"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100 4>; + }; + + spi0: spi@200 { + status = "okay"; + compatible = "zephyr,spi-emul-controller"; + clock-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x200 4>; + }; + + espi0: espi@300 { + status = "okay"; + compatible = "zephyr,espi-emul-controller"; + reg = <0x300 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + uart1: uart_1 { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + rng: rng { + status = "okay"; + compatible = "zephyr,native-posix-rng"; + }; + + counter0: counter { + status = "okay"; + compatible = "zephyr,native-posix-counter"; + }; + + gpio0: gpio@800 { + status = "okay"; + compatible = "zephyr,gpio-emul"; + reg = <0x800 0x4>; + rising-edge; + falling-edge; + high-level; + low-level; + gpio-controller; + #gpio-cells = <2>; + }; + + zephyr_udc0: udc0 { + compatible = "zephyr,native-posix-udc"; + }; + + sdl_dc: sdl_dc { + compatible = "zephyr,sdl-dc"; + height = <240>; + width = <320>; + }; + + input_sdl_touch: input-sdl-touch { + compatible = "zephyr,input-sdl-touch"; + }; + + can_loopback0: can_loopback0 { + status = "okay"; + compatible = "zephyr,can-loopback"; + sample-point = <875>; + bus-speed = <125000>; + }; + + can0: can { + status = "disabled"; + compatible = "zephyr,native-linux-can"; + /* adjust zcan0 to desired host interface or create an alternative + * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 + */ + host-interface = "zcan0"; + sample-point = <875>; + bus-speed = <125000>; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + alarms-count = <2>; + }; + + adc0: adc { + compatible = "zephyr,adc-emul"; + nchannels = <2>; + #io-channel-cells = <1>; + status = "okay"; + }; + + dma: dma { + compatible = "zephyr,dma-emul"; + #dma-cells = <1>; + stack-size = <4096>; + }; +}; diff --git a/boards/posix/native_sim/native_sim.yaml b/boards/posix/native_sim/native_sim.yaml index e2defe1ce40..999b52aa16b 100644 --- a/boards/posix/native_sim/native_sim.yaml +++ b/boards/posix/native_sim/native_sim.yaml @@ -19,4 +19,6 @@ supported: - spi - gpio - rtc +testing: + default: true vendor: zephyr diff --git a/boards/posix/nrf_bsim/CMakeLists.txt b/boards/posix/nrf_bsim/CMakeLists.txt index dfa6248f7dc..3ff7d632d4f 100644 --- a/boards/posix/nrf_bsim/CMakeLists.txt +++ b/boards/posix/nrf_bsim/CMakeLists.txt @@ -73,4 +73,8 @@ set_property(TARGET native_simulator APPEND PROPERTY RUNNER_LINK_LIBRARIES target_compile_options(native_simulator INTERFACE "-DNSI_PRIMARY_MCU_N=${CONFIG_NATIVE_SIMULATOR_PRIMARY_MCU_INDEX}") +add_subdirectory(${ZEPHYR_BASE}/boards/${ARCH}/common/extra_args/ + ${CMAKE_CURRENT_BINARY_DIR}/extra_args +) + include(../common/natsim_config.cmake) diff --git a/boards/posix/nrf_bsim/Kconfig b/boards/posix/nrf_bsim/Kconfig index 7d67c44d284..b43db7fac4a 100644 --- a/boards/posix/nrf_bsim/Kconfig +++ b/boards/posix/nrf_bsim/Kconfig @@ -6,7 +6,9 @@ if SOC_SERIES_BSIM_NRFXX # used by Nordic SoCs, so to make the symbols defined in this file available for # the simulated nrf5x_bsim boards, which use the POSIX architecture, the file # must be read also from here. -source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "soc/common/nordic_nrf/Kconfig.peripherals" + +source "boards/$(ARCH)/common/extra_args/Kconfig" endif # SOC_SERIES_BSIM_NRFXX @@ -17,19 +19,25 @@ endif # SOC_SERIES_BSIM_NRFXX config SOC_SERIES_BSIM_NRFXX bool - depends on SOC_POSIX + select NATIVE_LIBRARY + select SOC_COMPATIBLE_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select PINCTRL_DYNAMIC if PINCTRL help Any NRF simulated SOC with BabbleSim, based on the POSIX arch config SOC_SERIES_BSIM_NRF52X bool - depends on SOC_SERIES_BSIM_NRFXX + select SOC_SERIES_BSIM_NRFXX + select SOC_COMPATIBLE_NRF52X help Any NRF52 simulated SOC with BabbleSim, based on the POSIX arch config SOC_SERIES_BSIM_NRF53X bool - depends on SOC_SERIES_BSIM_NRFXX + select SOC_SERIES_BSIM_NRFXX + select SOC_COMPATIBLE_NRF53X help Any NRF53 simulated SOC with BabbleSim, based on the POSIX arch diff --git a/boards/posix/nrf_bsim/Kconfig.board b/boards/posix/nrf_bsim/Kconfig.board index 4a701c9acdc..fcfbae4d4e7 100644 --- a/boards/posix/nrf_bsim/Kconfig.board +++ b/boards/posix/nrf_bsim/Kconfig.board @@ -2,48 +2,30 @@ config BOARD_NRF52_BSIM bool "NRF52 simulation model" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF52X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF52X select SOC_COMPATIBLE_NRF52833 select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute config BOARD_NRF5340BSIM_NRF5340_CPUNET bool "Simulated NRF53 Network core" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF53X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF53X select SOC_COMPATIBLE_NRF5340_CPUNET select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute config BOARD_NRF5340BSIM_NRF5340_CPUAPP bool "Simulated NRF53 Application core" - select SOC_SERIES_BSIM_NRFXX select SOC_SERIES_BSIM_NRF53X - select SOC_COMPATIBLE_NRF - select SOC_COMPATIBLE_NRF53X select SOC_COMPATIBLE_NRF5340_CPUAPP select NRF_RTC_TIMER select CLOCK_CONTROL - select HAS_NRFX - select HAS_NORDIC_DRIVERS - select NATIVE_LIBRARY help Will produce a console Linux process which can be executed natively. It needs the BabbleSim simulator both in compile time and to execute diff --git a/boards/posix/nrf_bsim/Kconfig.defconfig b/boards/posix/nrf_bsim/Kconfig.defconfig index 6993048248c..d4e48ada7ad 100644 --- a/boards/posix/nrf_bsim/Kconfig.defconfig +++ b/boards/posix/nrf_bsim/Kconfig.defconfig @@ -44,7 +44,8 @@ config BT_CTLR default y if BOARD_NRF52_BSIM || BOARD_NRF5340BSIM_NRF5340_CPUNET depends on BT -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 4096 if BT_HCI_IPC default 4096 if NRF_802154_SER_HOST && BOARD_NRF5340BSIM_NRF5340_CPUAPP default 4096 if NRF_802154_SER_RADIO && BOARD_NRF5340BSIM_NRF5340_CPUNET @@ -86,10 +87,7 @@ endif # LOG if CONSOLE config POSIX_ARCH_CONSOLE - default y if !SERIAL - -config UART_CONSOLE - default y if SERIAL + default y endif # CONSOLE diff --git a/boards/posix/nrf_bsim/board_soc.h b/boards/posix/nrf_bsim/board_soc.h index 1b7e7a85c0c..d75a187aa61 100644 --- a/boards/posix/nrf_bsim/board_soc.h +++ b/boards/posix/nrf_bsim/board_soc.h @@ -29,6 +29,7 @@ #include #include #include "cmsis.h" +#include "soc_nrf_common.h" #if defined(CONFIG_BOARD_NRF52_BSIM) #define OFFLOAD_SW_IRQ SWI0_EGU0_IRQn diff --git a/boards/posix/nrf_bsim/common/bsim_args_runner.c b/boards/posix/nrf_bsim/common/bsim_args_runner.c index 29e0d15dd2e..2e84ca812fe 100644 --- a/boards/posix/nrf_bsim/common/bsim_args_runner.c +++ b/boards/posix/nrf_bsim/common/bsim_args_runner.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "bs_cmd_line.h" #include "bs_cmd_line_typical.h" #include "bs_dynargs.h" @@ -40,6 +41,10 @@ static struct bsim_global_args_t { static bool nosim; +/* Extra "command line options" provided programmatically: */ +static int extra_argc; +static char **extra_argv; + static void cmd_trace_lvl_found(char *argv, int offset) { bs_trace_set_level(global_args.verb); @@ -159,48 +164,76 @@ static void nsif_cpun_save_test_arg(int n, char *c) fptrs[n](c); } +static void nsi_handle_one_cmdline_argument(char *argv) +{ + static enum {Main = 0, Test = 1} parsing = Main; + static uint test_cpu_n; + + if (bs_is_option(argv, "argstest", 0)) { + parsing = Test; + test_cpu_n = NSI_PRIMARY_MCU_N; + return; + } else if (bs_is_multi_opt(argv, "argstest", &test_cpu_n, 0)) { + parsing = Test; + return; + } else if (bs_is_option(argv, "argsmain", 0)) { + parsing = Main; + return; + } + + if (parsing == Main) { + if (!bs_args_parse_one_arg(argv, args_struct)) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("Incorrect option %s\n", + argv); + } + } else if (parsing == Test) { + nsif_cpun_save_test_arg(test_cpu_n, argv); + } else { + bs_trace_error_line("Bad error\n"); + } +} + /** * Check the arguments provided in the command line: set args based on it or * defaults, and check they are correct */ void nsi_handle_cmd_line(int argc, char *argv[]) { - const char *bogus_sim_id = "bogus"; - bs_args_set_defaults(args_struct); global_args.verb = 2; bs_trace_set_level(global_args.verb); - static const char default_phy[] = "2G4"; - - enum {Main = 0, Test = 1} parsing = Main; - uint test_cpu_n; - + for (int i = 0; i < extra_argc; i++) { + nsi_handle_one_cmdline_argument(extra_argv[i]); + } for (int i = 1; i < argc; i++) { - if (bs_is_option(argv[i], "argstest", 0)) { - parsing = Test; - test_cpu_n = NSI_PRIMARY_MCU_N; - continue; - } else if (bs_is_multi_opt(argv[i], "argstest", &test_cpu_n, 0)) { - parsing = Test; - continue; - } else if (bs_is_option(argv[i], "argsmain", 0)) { - parsing = Main; - continue; - } + nsi_handle_one_cmdline_argument(argv[i]); + } +} - if (parsing == Main) { - if (!bs_args_parse_one_arg(argv[i], args_struct)) { - bs_args_print_switches_help(args_struct); - bs_trace_error_line("Incorrect option %s\n", - argv[i]); - } - } else if (parsing == Test) { - nsif_cpun_save_test_arg(test_cpu_n, argv[i]); - } else { - bs_trace_error_line("Bad error\n"); - } +void nsi_register_extra_args(int argc, char *argv[]) +{ + int new_size = extra_argc + argc; + + extra_argv = realloc(extra_argv, new_size*sizeof(char *)); + for (int i = 0; i < argc; i++) { + memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); } + extra_argc += argc; +} + +static void clear_extra_args(void) +{ + free(extra_argv); +} + +NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); + +static void postcheck_cmd_line(void) +{ + static const char *bogus_sim_id = "bogus"; + static const char default_phy[] = "2G4"; /** * If the user did not set the simulation id or device number @@ -246,6 +279,8 @@ void nsi_handle_cmd_line(int argc, char *argv[]) bs_random_init(global_args.rseed); } +NSI_TASK(postcheck_cmd_line, PRE_BOOT_2, 0); + /* * Get the simulation id */ diff --git a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst index da1212e3367..78c8e5c3279 100644 --- a/boards/posix/nrf_bsim/doc/nrf52_bsim.rst +++ b/boards/posix/nrf_bsim/doc/nrf52_bsim.rst @@ -36,6 +36,7 @@ This board includes models of some of the nRF52 SOC peripherals: * RNG (Random Number Generator) * RTC (Real Time Counter) * TEMP (Temperature sensor) +* UART & UARTE (UART with Easy DMA) * UICR (User Information Configuration Registers) and will use the same drivers as the nrf52 dk targets for these. diff --git a/boards/posix/nrf_bsim/irq_handler.c b/boards/posix/nrf_bsim/irq_handler.c index 24c00a4f79c..2d6ad4f66b7 100644 --- a/boards/posix/nrf_bsim/irq_handler.c +++ b/boards/posix/nrf_bsim/irq_handler.c @@ -95,13 +95,20 @@ void posix_irq_handler(void) return; } + irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n); + + if (irq_nbr == -1) { + /* This is a phony interrupt during a busy wait, no need for more */ + return; + } + if (_kernel.cpus[0].nested == 0) { may_swap = 0; } _kernel.cpus[0].nested++; - while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n)) != -1) { + do { int last_current_running_prio = hw_irq_ctrl_get_cur_prio(cpu_n); int last_running_irq = currently_running_irq; @@ -115,7 +122,7 @@ void posix_irq_handler(void) hw_irq_ctrl_reeval_level_irq(cpu_n, irq_nbr); hw_irq_ctrl_set_cur_prio(cpu_n, last_current_running_prio); - } + } while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq(cpu_n)) != -1); _kernel.cpus[0].nested--; @@ -251,6 +258,11 @@ int posix_get_current_irq(void) void posix_isr_declare(unsigned int irq_p, int flags, void isr_p(const void *), const void *isr_param_p) { + if (irq_p >= NHW_INTCTRL_MAX_INTLINES) { + bs_trace_error_time_line("Attempted to configure not existent interrupt %u\n", + irq_p); + return; + } irq_vector_table[irq_p].irq = irq_p; irq_vector_table[irq_p].func = isr_p; irq_vector_table[irq_p].param = isr_param_p; diff --git a/boards/posix/nrf_bsim/nrf52_bsim.dts b/boards/posix/nrf_bsim/nrf52_bsim.dts index a408ceb0eee..8410c80fb74 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.dts +++ b/boards/posix/nrf_bsim/nrf52_bsim.dts @@ -9,6 +9,8 @@ #include #include +/* We resuse the pinctrl definitions directly from the real board : */ +#include <../boards/arm/nrf52833dk_nrf52833/nrf52833dk_nrf52833-pinctrl.dtsi> / { model = "nrf52 bsim"; @@ -22,8 +24,6 @@ /delete-property/ spi-1; /delete-property/ spi-2; /delete-property/ spi-3; - /delete-property/ uart-0; - /delete-property/ uart-1; /delete-property/ adc-0; /delete-property/ wdt-0; /delete-property/ pwm-0; @@ -36,13 +36,15 @@ chosen { zephyr,ieee802154 = &ieee802154; zephyr,flash = &flash0; + /* UART used by the BT controller UART HCI driver by default: */ + zephyr,bt-c2h-uart = &uart1; + /* UART used by the BT host UART HCI driver by default: */ + zephyr,bt-uart = &uart1; }; soc { /delete-node/ memory@20000000; /delete-node/ adc@40007000; - /delete-node/ uart@40002000; - /delete-node/ uart@40028000; /delete-node/ i2c@40003000; /delete-node/ i2c@40004000; /delete-node/ pwm@4001c000; @@ -98,3 +100,22 @@ }; }; }; + +&uart0 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart1 { + compatible = "nordic,nrf-uarte"; + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-1 = <&uart1_sleep>; + pinctrl-names = "default", "sleep"; + hw-flow-control; +}; diff --git a/boards/posix/nrf_bsim/nrf52_bsim.yaml b/boards/posix/nrf_bsim/nrf52_bsim.yaml index 5b29b974009..17aba03864e 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim.yaml +++ b/boards/posix/nrf_bsim/nrf52_bsim.yaml @@ -10,6 +10,6 @@ toolchain: testing: ignore_tags: - modem - - uart + - bsim_skip_CI supported: - gpio diff --git a/boards/posix/nrf_bsim/nrf52_bsim_defconfig b/boards/posix/nrf_bsim/nrf52_bsim_defconfig index 42231465cea..953e8c1aa93 100644 --- a/boards/posix/nrf_bsim/nrf52_bsim_defconfig +++ b/boards/posix/nrf_bsim/nrf52_bsim_defconfig @@ -4,3 +4,4 @@ CONFIG_SOC_POSIX=y CONFIG_BOARD_NRF52_BSIM=y CONFIG_CONSOLE=y CONFIG_NO_OPTIMIZATIONS=y +CONFIG_LOG_BACKEND_UART=n diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts index c5ec3c95af5..72194f3b0e1 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.dts @@ -18,17 +18,13 @@ /delete-property/ sram-0; /delete-property/ i2c-0; /delete-property/ spi-0; - /delete-property/ uart-0; /delete-property/ i2c-1; /delete-property/ spi-1; - /delete-property/ uart-1; /delete-property/ spi-4; /delete-property/ i2c-2; /delete-property/ spi-2; - /delete-property/ uart-2; /delete-property/ i2c-3; /delete-property/ spi-3; - /delete-property/ uart-3; /delete-property/ wdt-0; /delete-property/ wdt-1; /delete-property/ pwm-0; @@ -61,17 +57,13 @@ /delete-node/ ctrlap@6000; /delete-node/ i2c@8000; /delete-node/ spi@8000; - /delete-node/ uart@8000; /delete-node/ i2c@9000; /delete-node/ spi@9000; - /delete-node/ uart@9000; /delete-node/ spi@a000; /delete-node/ i2c@b000; /delete-node/ spi@b000; - /delete-node/ uart@b000; /delete-node/ i2c@c000; /delete-node/ spi@c000; - /delete-node/ uart@c000; /delete-node/ adc@e000; /delete-node/ watchdog@18000; /delete-node/ watchdog@19000; diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml index 822368df0d3..448d4f330c3 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpuapp.yaml @@ -12,3 +12,4 @@ testing: - gpio - modem - uart + - bsim_skip_CI diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts index d9d7b02fc67..93e3ee27163 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.dts @@ -21,7 +21,6 @@ /delete-property/ wdt-0; /delete-property/ i2c-0; /delete-property/ spi-0; - /delete-property/ uart-0; /delete-property/ gpio-0; /delete-property/ gpio-1; }; @@ -41,7 +40,6 @@ /delete-node/ watchdog@4100b000; /delete-node/ i2c@41013000; /delete-node/ spi@41013000; - /delete-node/ uart@41013000; /delete-node/ acl@41080000; /delete-node/ vmc@41081000; /delete-node/ gpio@418c0500; diff --git a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml index 4e305c095d3..4cd71ff3566 100644 --- a/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml +++ b/boards/posix/nrf_bsim/nrf5340bsim_nrf5340_cpunet.yaml @@ -12,3 +12,4 @@ testing: - gpio - modem - uart + - bsim_skip_CI diff --git a/boards/posix/nrf_bsim/soc/pinctrl_soc.h b/boards/posix/nrf_bsim/soc/pinctrl_soc.h new file mode 100644 index 00000000000..f0be0443d5b --- /dev/null +++ b/boards/posix/nrf_bsim/soc/pinctrl_soc.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H +#define BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H + +/* We reuse the real SOC's header: */ +#include "../soc/common/nordic_nrf/pinctrl_soc.h" + +#endif /* BOARDS_POSIX_NRF_BSIM_SOC_PINCTRL_SOC_H */ diff --git a/boards/posix/nrf_bsim/soc/soc_nrf_common.h b/boards/posix/nrf_bsim/soc/soc_nrf_common.h new file mode 100644 index 00000000000..a77778de653 --- /dev/null +++ b/boards/posix/nrf_bsim/soc/soc_nrf_common.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H +#define BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H + +/* We reuse the real SOC's header: */ +#include "../soc/arm/nordic_nrf/common/soc_nrf_common.h" + +#endif /* BOARDS_POSIX_NRF_BSIM_SOC_SOC_NRF_COMMON_H */ diff --git a/boards/riscv/adp_xc7k_ae350/Kconfig.board b/boards/riscv/adp_xc7k_ae350/Kconfig.board index 085eb9696a8..5b58e01fbfd 100644 --- a/boards/riscv/adp_xc7k_ae350/Kconfig.board +++ b/boards/riscv/adp_xc7k_ae350/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_ADP_XC7K_AE350 bool "Andes ADP-XC7K AE350 Platform" - depends on SOC_RISCV_ANDES_AE350 + depends on SOC_ANDES_AE350 diff --git a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig index 3f7f1f727c6..edbe7118c64 100644 --- a/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig +++ b/boards/riscv/adp_xc7k_ae350/adp_xc7k_ae350_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_ANDES_V5=y -CONFIG_SOC_RISCV_ANDES_AE350=y +CONFIG_SOC_SERIES_ANDES_AE350=y +CONFIG_SOC_ANDES_AE350=y CONFIG_BOARD_ADP_XC7K_AE350=y CONFIG_XIP=n CONFIG_CONSOLE=y diff --git a/boards/riscv/beaglev_fire/Kconfig.board b/boards/riscv/beaglev_fire/Kconfig.board new file mode 100644 index 00000000000..55b59d4ac92 --- /dev/null +++ b/boards/riscv/beaglev_fire/Kconfig.board @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_BEAGLEV_FIRE + bool "Beagleboard BeagleV-Fire" + depends on SOC_POLARFIRE + select 64BIT + select SCHED_IPI_SUPPORTED + select CPU_HAS_FPU_DOUBLE_PRECISION diff --git a/boards/riscv/beaglev_fire/Kconfig.defconfig b/boards/riscv/beaglev_fire/Kconfig.defconfig new file mode 100644 index 00000000000..df89660bcb6 --- /dev/null +++ b/boards/riscv/beaglev_fire/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "beaglev_fire" + depends on BOARD_BEAGLEV_FIRE diff --git a/boards/riscv/beaglev_fire/beaglev_fire.dts b/boards/riscv/beaglev_fire/beaglev_fire.dts new file mode 100644 index 00000000000..df956f5c8f2 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire.dts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Microchip Technology Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include + +/ { + model = "BeagleV-Fire"; + compatible = "beagle,beaglev-fire", "microchip,mpfs"; + aliases { + }; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,sram = &sram1; + }; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + clock-frequency = <150000000>; +}; + +&gpio2 { + status = "okay"; +}; diff --git a/boards/riscv/beaglev_fire/beaglev_fire.yaml b/boards/riscv/beaglev_fire/beaglev_fire.yaml new file mode 100644 index 00000000000..64d34b454f8 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire.yaml @@ -0,0 +1,12 @@ +identifier: beaglev_fire +name: Beagleboard BeagleV-Fire +type: mcu +arch: riscv64 +toolchain: + - zephyr +ram: 3840 +testing: + ignore_tags: + - net + - bluetooth +vendor: beagle diff --git a/boards/riscv/beaglev_fire/beaglev_fire_defconfig b/boards/riscv/beaglev_fire/beaglev_fire_defconfig new file mode 100644 index 00000000000..eaf7d9c6f15 --- /dev/null +++ b/boards/riscv/beaglev_fire/beaglev_fire_defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_POLARFIRE=y +CONFIG_SOC_POLARFIRE=y +CONFIG_MPFS_HAL=n +CONFIG_BASE64=y +CONFIG_INCLUDE_RESET_VECTOR=y +CONFIG_BOARD_BEAGLEV_FIRE=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_XIP=n +CONFIG_INIT_STACKS=y +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 +CONFIG_FPU=n diff --git a/boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp b/boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp new file mode 100644 index 00000000000..a4ba6b0d98e Binary files /dev/null and b/boards/riscv/beaglev_fire/doc/img/BeagleV-Fire-Front-Annotated-768x432.webp differ diff --git a/boards/riscv/beaglev_fire/doc/img/board-booting.png b/boards/riscv/beaglev_fire/doc/img/board-booting.png new file mode 100644 index 00000000000..5be27ddfbb1 Binary files /dev/null and b/boards/riscv/beaglev_fire/doc/img/board-booting.png differ diff --git a/boards/riscv/beaglev_fire/doc/index.rst b/boards/riscv/beaglev_fire/doc/index.rst new file mode 100644 index 00000000000..88808145c9b --- /dev/null +++ b/boards/riscv/beaglev_fire/doc/index.rst @@ -0,0 +1,85 @@ +.. _beaglev_fire: + +BeagleV®-Fire +############# + +Overview +******** + +BeagleV®-Fire is a revolutionary single-board computer (SBC) powered by the Microchip’s +PolarFire® MPFS025T 5x core RISC-V System on Chip (SoC) with FPGA fabric. BeagleV®-Fire opens up new +horizons for developers, tinkerers, and the open-source community to explore the vast potential of +RISC-V architecture and FPGA technology. It has the same P8 & P9 cape header pins as BeagleBone +Black allowing you to stack your favorite BeagleBone cape on top to expand it’s capability. +Built around the powerful and energy-efficient RISC-V instruction set architecture (ISA) along with +its versatile FPGA fabric, BeagleV®-Fire SBC offers unparalleled opportunities for developers, +hobbyists, and researchers to explore and experiment with RISC-V technology. + +.. image:: img/BeagleV-Fire-Front-Annotated-768x432.webp + :align: center + :alt: beaglev_fire + +Building +======== + +Applications for the ``beaglev_fire`` board configuration can be built as usual: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: beaglev_fire + :goals: build + +Debugging +========= + +In order to upload the application to the device, you'll need OpenOCD and GDB +with RISC-V support. +You can get them as a part of SoftConsole SDK. +Download and installation instructions can be found on +`Microchip's SoftConsole website +`_. + +You will also require a Debugger such as Microchip's FlashPro5/6. + +Connect to BeagleV-Fire UART debug port using a 3.3v USB to UART bridge. +Now you can run ``tio `` in a terminal window to access the UART debug port connection. Once you +are connected properly you can press the Reset button which will show you a progress bar like: + +.. image:: img/board-booting.png + :align: center + :alt: beaglev_fire + +Once you see that progress bar on your screen you can start pressing any button (0-9/a-z) which +will interrupt the Hart Software Services from booting its payload. + +With the necessary tools installed, you can connect to the board using OpenOCD. +from a different terminal, run: + +.. code-block:: bash + + /openocd/bin/openocd --file \ + /openocd/share/openocd/scripts/board/microsemi-riscv.cfg + + +Leave it running, and in a different terminal, use GDB to upload the binary to +the board. You can use the RISC-V GDB from the Zephyr SDK. +launch GDB: + +.. code-block:: bash + + /riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gdb + + + +Here is the GDB terminal command to connect to the device +and load the binary: + +.. code-block:: bash + + set arch riscv:rv64 + set mem inaccessible-by-default off + file + target extended-remote localhost:3333 + load + break main + continue diff --git a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig index 3686c1e8ad3..922368f923b 100644 --- a/boards/riscv/esp32c3_devkitm/Kconfig.defconfig +++ b/boards/riscv/esp32c3_devkitm/Kconfig.defconfig @@ -7,8 +7,10 @@ config BOARD default "esp32c3_devkitm" depends on BOARD_ESP32C3_DEVKITM -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts index 60cfdea523a..6c390956e48 100644 --- a/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts +++ b/boards/riscv/esp32c3_devkitm/esp32c3_devkitm.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig index 1a1ee456a3d..82e3a5a0c94 100644 --- a/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig +++ b/boards/riscv/esp32c3_luatos_core/Kconfig.defconfig @@ -7,8 +7,10 @@ config BOARD default "esp32c3_luatos_core" depends on BOARD_ESP32C3_LUATOS_CORE || BOARD_ESP32C3_LUATOS_CORE_USB -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts index 5a74be9984e..00a69833557 100644 --- a/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts +++ b/boards/riscv/esp32c3_luatos_core/esp32c3_luatos_core.dts @@ -14,5 +14,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts b/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts index 160d6b14d4d..8939bb4cddb 100644 --- a/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts +++ b/boards/riscv/gd32vf103c_starter/gd32vf103c_starter.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32vf103c_starter-pinctrl.dtsi" #include diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts index 3cb3b024cea..cea9c00b7e9 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.dts @@ -5,7 +5,7 @@ /dts-v1/; -#include +#include #include "gd32vf103v_eval-pinctrl.dtsi" #include diff --git a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml index 306d3e11498..857fe8adf6d 100644 --- a/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml +++ b/boards/riscv/gd32vf103v_eval/gd32vf103v_eval.yaml @@ -10,10 +10,11 @@ flash: 128 toolchain: - zephyr supported: - - uart + - dma + - flash - gpio - pwm - - watchdog - - dma - spi + - uart + - watchdog vendor: gd diff --git a/boards/riscv/hifive1/Kconfig.board b/boards/riscv/hifive1/Kconfig.board index b5b32649441..d2f40472f24 100644 --- a/boards/riscv/hifive1/Kconfig.board +++ b/boards/riscv/hifive1/Kconfig.board @@ -2,4 +2,4 @@ config BOARD_HIFIVE1 bool "HiFive1 target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/hifive1/hifive1_defconfig b/boards/riscv/hifive1/hifive1_defconfig index d37ded2bb25..8e4e8e21c1a 100644 --- a/boards/riscv/hifive1/hifive1_defconfig +++ b/boards/riscv/hifive1/hifive1_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_HIFIVE1=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/hifive1_revb/Kconfig.board b/boards/riscv/hifive1_revb/Kconfig.board index d4c5b99ce72..b0bf1edd156 100644 --- a/boards/riscv/hifive1_revb/Kconfig.board +++ b/boards/riscv/hifive1_revb/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE1_REVB bool "HiFive1 Rev B target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/hifive1_revb/hifive1_revb_defconfig b/boards/riscv/hifive1_revb/hifive1_revb_defconfig index 4f691bd9435..b2119eecae9 100644 --- a/boards/riscv/hifive1_revb/hifive1_revb_defconfig +++ b/boards/riscv/hifive1_revb/hifive1_revb_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_HIFIVE1_REVB=y CONFIG_GPIO=y CONFIG_PINCTRL=y diff --git a/boards/riscv/hifive_unleashed/Kconfig.board b/boards/riscv/hifive_unleashed/Kconfig.board index 4766e0ea792..f6c623e9928 100644 --- a/boards/riscv/hifive_unleashed/Kconfig.board +++ b/boards/riscv/hifive_unleashed/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE_UNLEASHED bool "HiFive Unleashed target" - depends on SOC_RISCV_SIFIVE_FU540 + depends on SOC_SIFIVE_FREEDOM_U540 diff --git a/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig b/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig index 15c9e60d552..51d324d457d 100644 --- a/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig +++ b/boards/riscv/hifive_unleashed/hifive_unleashed_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FU540=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_U500=y +CONFIG_SOC_SIFIVE_FREEDOM_U540=y CONFIG_BOARD_HIFIVE_UNLEASHED=y CONFIG_CONSOLE=y CONFIG_GPIO=y diff --git a/boards/riscv/hifive_unmatched/Kconfig.board b/boards/riscv/hifive_unmatched/Kconfig.board index cf6ac1c8392..bb303cc3aac 100644 --- a/boards/riscv/hifive_unmatched/Kconfig.board +++ b/boards/riscv/hifive_unmatched/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_HIFIVE_UNMATCHED bool "HiFive Unmatched target" - depends on SOC_RISCV_SIFIVE_FU740 + depends on SOC_SIFIVE_FREEDOM_U740 diff --git a/boards/riscv/hifive_unmatched/board.cmake b/boards/riscv/hifive_unmatched/board.cmake index c985f2d7bca..56fe497dd2a 100644 --- a/boards/riscv/hifive_unmatched/board.cmake +++ b/boards/riscv/hifive_unmatched/board.cmake @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +set(SUPPORTED_EMU_PLATFORMS renode) +set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/hifive_unmatched.resc) +set(RENODE_UART sysbus.uart0) + set(OPENOCD_USE_LOAD_IMAGE NO) board_runner_args(openocd "--config=${BOARD_DIR}/support/openocd_hifive_unmatched.cfg") diff --git a/boards/riscv/hifive_unmatched/hifive_unmatched.yaml b/boards/riscv/hifive_unmatched/hifive_unmatched.yaml index 8b62698b61b..39450132d44 100644 --- a/boards/riscv/hifive_unmatched/hifive_unmatched.yaml +++ b/boards/riscv/hifive_unmatched/hifive_unmatched.yaml @@ -5,6 +5,8 @@ arch: riscv64 toolchain: - zephyr ram: 3840 +simulation: renode +simulation_exec: renode testing: ignore_tags: - net diff --git a/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig b/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig index 654fdc1bf2a..be13ed10358 100644 --- a/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig +++ b/boards/riscv/hifive_unmatched/hifive_unmatched_defconfig @@ -1,5 +1,5 @@ -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FU740=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_U700=y +CONFIG_SOC_SIFIVE_FREEDOM_U740=y CONFIG_BOARD_HIFIVE_UNMATCHED=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc new file mode 100644 index 00000000000..535bb06c69c --- /dev/null +++ b/boards/riscv/hifive_unmatched/support/hifive_unmatched.resc @@ -0,0 +1,25 @@ +:description: This script is prepared to run Zephyr on SiFive-FU740 board. +:name: SiFive-FU740 + +$name?="SiFive-FU740" + +using sysbus +mach create $name + +set platform +""" +using "platforms/cpus/sifive-fu740.repl" + +clint: + frequency: 10000000 +""" + +machine LoadPlatformDescriptionFromString $platform +machine PyDevFromFile @scripts/pydev/flipflop.py 0x10000000 0x100 True +showAnalyzer uart0 + +macro reset +""" + sysbus LoadELF $bin +""" +runMacro $reset diff --git a/boards/riscv/icev_wireless/Kconfig.defconfig b/boards/riscv/icev_wireless/Kconfig.defconfig index 84ce9486559..44157fd5b6a 100644 --- a/boards/riscv/icev_wireless/Kconfig.defconfig +++ b/boards/riscv/icev_wireless/Kconfig.defconfig @@ -5,8 +5,10 @@ config BOARD default "icev_wireless" depends on BOARD_ICEV_WIRELESS -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/icev_wireless/icev_wireless.dts b/boards/riscv/icev_wireless/icev_wireless.dts index 998ce4c0bc3..1e5719fe2aa 100644 --- a/boards/riscv/icev_wireless/icev_wireless.dts +++ b/boards/riscv/icev_wireless/icev_wireless.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig b/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig index f082e4a7bad..6866e3f633b 100644 --- a/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig +++ b/boards/riscv/it82xx2_evb/it82xx2_evb_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2023 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_IT8XXX2=y +CONFIG_SOC_SERIES_ITE_IT8XXX2=y CONFIG_SOC_IT8XXX2=y CONFIG_SOC_IT82202_AX=y CONFIG_BOARD_IT82XX2_EVB=y diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml b/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml index 3374ea96c32..308e2c73c14 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb.yaml @@ -1,5 +1,5 @@ identifier: it8xxx2_evb -name: it8xxx2_evb +name: ITE IT8XXX2 EVB type: mcu arch: riscv32 toolchain: diff --git a/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig b/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig index 21967527f8e..38a44d6f8f3 100644 --- a/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig +++ b/boards/riscv/it8xxx2_evb/it8xxx2_evb_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2020 ITE Corporation. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_IT8XXX2=y +CONFIG_SOC_SERIES_ITE_IT8XXX2=y CONFIG_SOC_IT8XXX2=y CONFIG_BOARD_IT8XXX2_EVB=y CONFIG_BOOT_DELAY=1 diff --git a/boards/riscv/longan_nano/longan_nano.dts b/boards/riscv/longan_nano/longan_nano.dts index e86c1992be1..dd59e6cfe5f 100644 --- a/boards/riscv/longan_nano/longan_nano.dts +++ b/boards/riscv/longan_nano/longan_nano.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "longan_nano-pinctrl.dtsi" #include "longan_nano-common.dtsi" diff --git a/boards/riscv/longan_nano/longan_nano_lite.dts b/boards/riscv/longan_nano/longan_nano_lite.dts index 976992c3173..a36827b1bcd 100644 --- a/boards/riscv/longan_nano/longan_nano_lite.dts +++ b/boards/riscv/longan_nano/longan_nano_lite.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include "longan_nano-pinctrl.dtsi" #include "longan_nano-common.dtsi" diff --git a/boards/riscv/m2gl025_miv/Kconfig.board b/boards/riscv/m2gl025_miv/Kconfig.board index 51c2f9d8de3..9f81fad406f 100644 --- a/boards/riscv/m2gl025_miv/Kconfig.board +++ b/boards/riscv/m2gl025_miv/Kconfig.board @@ -2,4 +2,4 @@ config BOARD_M2GL025_MIV bool "Microchip M2GL025 IGLOO2 dev board with Mi-V CPU" - depends on SOC_RISCV32_MIV + depends on SOC_MIV diff --git a/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig b/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig index 8c944a10a74..e33765680d5 100644 --- a/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig +++ b/boards/riscv/m2gl025_miv/m2gl025_miv_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV32_MIV=y -CONFIG_SOC_RISCV32_MIV=y +CONFIG_SOC_SERIES_MIV=y +CONFIG_SOC_MIV=y CONFIG_BOARD_M2GL025_MIV=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/mpfs_icicle/CMakeLists.txt b/boards/riscv/mpfs_icicle/CMakeLists.txt deleted file mode 100644 index ef5e0226694..00000000000 --- a/boards/riscv/mpfs_icicle/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/boards/riscv/mpfs_icicle/Kconfig.board b/boards/riscv/mpfs_icicle/Kconfig.board index 297f4ce4bc7..e772b82d7f5 100644 --- a/boards/riscv/mpfs_icicle/Kconfig.board +++ b/boards/riscv/mpfs_icicle/Kconfig.board @@ -3,7 +3,7 @@ config BOARD_MPFS_ICICLE bool "Microchip PolarFire SoC ICICLE kit" - depends on SOC_MPFS + depends on SOC_POLARFIRE select 64BIT select SCHED_IPI_SUPPORTED select CPU_HAS_FPU_DOUBLE_PRECISION diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle.dts b/boards/riscv/mpfs_icicle/mpfs_icicle.dts index 774a5533233..902180c0a14 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle.dts +++ b/boards/riscv/mpfs_icicle/mpfs_icicle.dts @@ -5,7 +5,7 @@ */ /dts-v1/; -#include +#include #include #include @@ -61,6 +61,19 @@ }; }; +&spi1 { + status = "okay"; +}; + +&syscontroller_qspi { + status = "okay"; + sys_ctrl_flash: spi-nor-flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <5000000>; + }; +}; + &gpio2 { status = "okay"; }; diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay b/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay deleted file mode 100644 index 15c38d914c7..00000000000 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_ddr.overlay +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2020-2021 Microchip Technology Inc - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/ { - chosen { - zephyr,sram = &sram1; - }; -}; diff --git a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig index 5c41649cb3e..60df70677e1 100644 --- a/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig +++ b/boards/riscv/mpfs_icicle/mpfs_icicle_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2020-2021 Microchip Technology Inc # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV64_MIV=y -CONFIG_SOC_MPFS=y +CONFIG_SOC_SERIES_POLARFIRE=y +CONFIG_SOC_POLARFIRE=y CONFIG_MPFS_HAL=n CONFIG_BASE64=y CONFIG_INCLUDE_RESET_VECTOR=y @@ -10,8 +10,6 @@ CONFIG_BOARD_MPFS_ICICLE=y CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y -CONFIG_RISCV_SOC_INTERRUPT_INIT=y -CONFIG_RISCV_HAS_PLIC=y CONFIG_XIP=n CONFIG_INIT_STACKS=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/boards/riscv/neorv32/Kconfig.board b/boards/riscv/neorv32/Kconfig.board index eee37f4a8c3..6d85ebb2e40 100644 --- a/boards/riscv/neorv32/Kconfig.board +++ b/boards/riscv/neorv32/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_NEORV32 bool "NEORV32 Processor (SoC)" - depends on SOC_SERIES_NEORV32 + depends on SOC_NEORV32 diff --git a/boards/riscv/neorv32/neorv32_defconfig b/boards/riscv/neorv32/neorv32_defconfig index 17e9b8038ce..7dc8a74ffff 100644 --- a/boards/riscv/neorv32/neorv32_defconfig +++ b/boards/riscv/neorv32/neorv32_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2021 Henrik Brix Andersen # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_NEORV32=y +CONFIG_SOC_NEORV32=y CONFIG_SOC_NEORV32_ISA_C=y CONFIG_BOARD_NEORV32=y CONFIG_SERIAL=y diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board new file mode 100644 index 00000000000..9bbbba60dd4 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NRF54H20PDK_NRF54H20_CPUPPR + bool "nRF54H20 PDK nRF54H20 PPR MCU" + depends on SOC_NRF54H20_ENGA_CPUPPR diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig new file mode 100644 index 00000000000..256976d6519 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "nrf54h20pdk_nrf54h20_cpuppr" + depends on BOARD_NRF54H20PDK_NRF54H20_CPUPPR diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake b/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake new file mode 100644 index 00000000000..4c63f1dd05e --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/board.cmake @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts new file mode 100644 index 00000000000..83aface6f5c --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.dts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include "nrf54h20pdk_nrf54h20-memory_map.dtsi" +#include "nrf54h20pdk_nrf54h20-pinctrl.dtsi" + +/ { + compatible = "nordic,nrf54h20pdk_nrf54h20-cpuppr"; + model = "Nordic nRF54H20 PDK nRF54H20 Peripheral Processor MCU"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + zephyr,console = &uart135; + zephyr,code-partition = &cpuppr_code_partition; + zephyr,flash = &mram1x; + zephyr,sram = &cpuppr_ram3x_region; + }; +}; + +&grtc { + status = "okay"; + owned-channels = <5>; +}; + +&uart135 { + status = "okay"; + pinctrl-0 = <&uart135_default>; + pinctrl-1 = <&uart135_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart136 { + pinctrl-0 = <&uart136_default>; + pinctrl-1 = <&uart136_sleep>; + pinctrl-names = "default", "sleep"; +}; diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml new file mode 100644 index 00000000000..274be865c36 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +identifier: nrf54h20pdk_nrf54h20_cpuppr +name: nRF54H20-PDK-nRF54H20-PPR +type: mcu +arch: riscv +toolchain: + - zephyr +ram: 28 +flash: 28 +supported: + - gpio diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig new file mode 100644 index 00000000000..fb3dca2266d --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/nrf54h20pdk_nrf54h20_cpuppr_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NRF54HX=y +CONFIG_SOC_NRF54H20=y +CONFIG_SOC_NRF54H20_ENGA_CPUPPR=y +CONFIG_BOARD_NRF54H20PDK_NRF54H20_CPUPPR=y + +CONFIG_XIP=n + +CONFIG_SERIAL=y + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake b/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake new file mode 100644 index 00000000000..5e0fecebdc8 --- /dev/null +++ b/boards/riscv/nrf54h20pdk_nrf54h20/pre_dt_board.cmake @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Allow common DTS files to be included from the other board directory. +# To be removed after HWMv2 (#51831), once both directories can be merged into one. +string(REGEX REPLACE "/riscv/(.*$)" "/arm/\\1" BOARD_DIR_ARM "${BOARD_DIR}") +list(APPEND DTS_EXTRA_CPPFLAGS -isystem "${BOARD_DIR_ARM}") diff --git a/boards/riscv/opentitan_earlgrey/Kconfig.board b/boards/riscv/opentitan_earlgrey/Kconfig.board index ec7f735b442..544c02b1b2a 100644 --- a/boards/riscv/opentitan_earlgrey/Kconfig.board +++ b/boards/riscv/opentitan_earlgrey/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_OPENTITAN_EARLGREY bool "OpenTitan Earl Grey Target" - depends on SOC_RISCV_OPENTITAN + depends on SOC_OPENTITAN diff --git a/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig b/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig index 79299c3892f..886e439b88a 100644 --- a/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig +++ b/boards/riscv/opentitan_earlgrey/opentitan_earlgrey_defconfig @@ -1,8 +1,7 @@ # Copyright (c) 2023 by Rivos Inc. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_OPENTITAN=y -CONFIG_SOC_RISCV_OPENTITAN=y +CONFIG_SOC_OPENTITAN=y CONFIG_BOARD_OPENTITAN_EARLGREY=y CONFIG_XIP=y CONFIG_SERIAL=y diff --git a/boards/riscv/qemu_riscv32/Kconfig.board b/boards/riscv/qemu_riscv32/Kconfig.board index 989fa13b453..7c94b59455c 100644 --- a/boards/riscv/qemu_riscv32/Kconfig.board +++ b/boards/riscv/qemu_riscv32/Kconfig.board @@ -22,7 +22,7 @@ config BOARD_QEMU_RISCV32_SMP config BOARD_QEMU_RISCV32_XIP bool "QEMU RISCV32 XIP target" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 select QEMU_TARGET select HAS_COVERAGE_SUPPORT select CPU_HAS_FPU diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig index f50d82dcb76..946e679a6e8 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig index eef7d03e356..90f87ef6b98 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_smp_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32_SMP=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig b/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig index 2cd0b2cbecb..948fa909a08 100644 --- a/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig +++ b/boards/riscv/qemu_riscv32/qemu_riscv32_xip_defconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_QEMU_RISCV32_XIP=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig b/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig index ef4d6273cfb..1f1c46acb10 100644 --- a/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig +++ b/boards/riscv/qemu_riscv32e/qemu_riscv32e_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV32E=y CONFIG_CONSOLE=y diff --git a/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig b/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig index 6f51da3c592..6bfc46ac907 100644 --- a/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig +++ b/boards/riscv/qemu_riscv64/qemu_riscv64_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV64=y CONFIG_PRIVILEGED_STACK_SIZE=2048 diff --git a/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig b/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig index 78b5b74de9a..265d84a1ded 100644 --- a/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig +++ b/boards/riscv/qemu_riscv64/qemu_riscv64_smp_defconfig @@ -1,6 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_VIRT=y CONFIG_SOC_RISCV_VIRT=y CONFIG_BOARD_QEMU_RISCV64_SMP=y CONFIG_PRIVILEGED_STACK_SIZE=2048 diff --git a/boards/riscv/riscv32_virtual/Kconfig.board b/boards/riscv/riscv32_virtual/Kconfig.board new file mode 100644 index 00000000000..c8722acb384 --- /dev/null +++ b/boards/riscv/riscv32_virtual/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_RISCV32_VIRTUAL + bool "riscv32_virtual" + depends on SOC_RISCV32_VIRTUAL_RENODE diff --git a/boards/riscv/riscv32_virtual/Kconfig.defconfig b/boards/riscv/riscv32_virtual/Kconfig.defconfig new file mode 100644 index 00000000000..840b10fd594 --- /dev/null +++ b/boards/riscv/riscv32_virtual/Kconfig.defconfig @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "riscv32_virtual" + depends on BOARD_RISCV32_VIRTUAL diff --git a/boards/riscv/riscv32_virtual/board.cmake b/boards/riscv/riscv32_virtual/board.cmake new file mode 100644 index 00000000000..cc177a69ce9 --- /dev/null +++ b/boards/riscv/riscv32_virtual/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +set(SUPPORTED_EMU_PLATFORMS renode) +set(RENODE_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/support/riscv32_virtual.resc) +set(RENODE_UART sysbus.uart0) diff --git a/boards/riscv/riscv32_virtual/doc/index.rst b/boards/riscv/riscv32_virtual/doc/index.rst new file mode 100644 index 00000000000..a53384f5331 --- /dev/null +++ b/boards/riscv/riscv32_virtual/doc/index.rst @@ -0,0 +1,56 @@ +.. _riscv32-virtual: + +RISCV32 Virtual +############### + +Overview +******** + +The RISCV32 Virtual board is a virtual platform made with Renode as an alternative to QEMU. +Contrary to QEMU, the peripherals of this platform can be easily configured by editing the +``riscv32_virtual.repl`` script and the devicetree files accordingly, this allows certain hardware +configurations that only exist in proprietary boards/SoCs to be tested in upstream CI. + +Programming and debugging +************************* + +Building +======== + +Applications for the ``riscv32_virtual`` board configuration can be built as usual +(see :ref:`build_an_application`): + +.. zephyr-app-commands:: + :board: riscv32_virtual + :goals: build + +Flashing +======== + +While this board is emulated and you can't "flash" it, you can use this +configuration to run basic Zephyr applications and kernel tests in the Renode +emulated environment. For example, with the :zephyr:code-sample:`synchronization` sample: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: riscv32_virtual + :goals: run + +This will build an image with the synchronization sample app, boot it using +Renode, and display the following console output: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-1511-g56f73bde0fb0 *** + thread_a: Hello World from cpu 0 on riscv32_virtual! + thread_b: Hello World from cpu 0 on riscv32_virtual! + thread_a: Hello World from cpu 0 on riscv32_virtual! + thread_b: Hello World from cpu 0 on riscv32_virtual! + +Exit Renode by pressing :kbd:`CTRL+C`. + +Debugging +========= + +Refer to the detailed overview about :ref:`application_debugging`. diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual.dts b/boards/riscv/riscv32_virtual/riscv32_virtual.dts new file mode 100644 index 00000000000..326b9757518 --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "Renode RISCV32 Virtual target"; + compatible = "renode,riscv32-virtual"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,sram = &sram0; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual.yaml b/boards/riscv/riscv32_virtual/riscv32_virtual.yaml new file mode 100644 index 00000000000..11cefb035df --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual.yaml @@ -0,0 +1,16 @@ +identifier: riscv32_virtual +name: Renode RISC-V 32-bit Virtual Board +type: mcu +arch: riscv32 +toolchain: + - zephyr +ram: 4096 +flash: 4096 +simulation: renode +simulation_exec: renode +testing: + ignore_tags: + - net + - bluetooth +supported: + - uart diff --git a/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig new file mode 100644 index 00000000000..4dcad0a7ea1 --- /dev/null +++ b/boards/riscv/riscv32_virtual/riscv32_virtual_defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_RISCV32_VIRTUAL_RENODE=y +CONFIG_BOARD_RISCV32_VIRTUAL=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=n +CONFIG_XIP=y + +# Workaround for incorrect SYS_CLOCK_HW_CYCLES_PER_SEC +CONFIG_SYS_CLOCK_TICKS_PER_SEC=100 diff --git a/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl b/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl new file mode 100644 index 00000000000..e0df808631b --- /dev/null +++ b/boards/riscv/riscv32_virtual/support/riscv32_virtual.repl @@ -0,0 +1,33 @@ +// Copyright (c) 2023 Meta +// SPDX-License-Identifier: Apache-2.0 + +flash: Memory.MappedMemory @ sysbus 0x80000000 + size: 0x400000 + +ddr: Memory.MappedMemory @ sysbus 0x80400000 + size: 0x400000 + +uart0: UART.NS16550 @ sysbus 0x10000000 + IRQ -> plic0@10 + +uart1: UART.NS16550 @ sysbus 0x10000100 + IRQ -> plic1@10 + +cpu: CPU.RiscV32 @ sysbus + cpuType: "rv32imac_zicsr_zifencei" + privilegeArchitecture: PrivilegeArchitecture.Priv1_10 + timeProvider: clint + +plic0: IRQControllers.PlatformLevelInterruptController @ sysbus 0x0C000000 + 0 -> cpu@11 + numberOfSources: 1023 + numberOfContexts: 1 + +plic1: IRQControllers.PlatformLevelInterruptController @ sysbus 0x08000000 + 0 -> cpu@4 + numberOfSources: 1023 + numberOfContexts: 1 + +clint: IRQControllers.CoreLevelInterruptor @ sysbus 0x02000000 + [0,1] -> cpu@[3,7] + frequency: 4000000 diff --git a/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc b/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc new file mode 100644 index 00000000000..87e327287b6 --- /dev/null +++ b/boards/riscv/riscv32_virtual/support/riscv32_virtual.resc @@ -0,0 +1,17 @@ +:name: RISCV32-Virtual +:description: This script is prepared to run Zephyr on a Renode RISCV32 board. + +$name?="RISCV32-Virtual" + +using sysbus +mach create $name +machine LoadPlatformDescription $ORIGIN/riscv32_virtual.repl + +showAnalyzer uart0 +cpu PerformanceInMips 4 + +macro reset +""" + sysbus LoadELF $bin +""" +runMacro $reset diff --git a/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board b/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board index 34f852dc0ec..cc9e7b4f935 100644 --- a/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board +++ b/boards/riscv/sparkfun_red_v_things_plus/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_SPARKFUN_RED_V_THINGS_PLUS bool "SparkFun RED-V Things Plus board" - depends on SOC_RISCV_SIFIVE_FREEDOM + depends on SOC_SIFIVE_FREEDOM_E340 diff --git a/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig b/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig index de3d18bcfde..8cf24ffbe09 100644 --- a/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig +++ b/boards/riscv/sparkfun_red_v_things_plus/sparkfun_red_v_things_plus_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2022 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_SIFIVE_FREEDOM=y -CONFIG_SOC_RISCV_SIFIVE_FREEDOM=y +CONFIG_SOC_SERIES_SIFIVE_FREEDOM_E300=y +CONFIG_SOC_SIFIVE_FREEDOM_E340=y CONFIG_BOARD_SPARKFUN_RED_V_THINGS_PLUS=y CONFIG_GPIO=y CONFIG_PINCTRL=y diff --git a/boards/riscv/stamp_c3/Kconfig.defconfig b/boards/riscv/stamp_c3/Kconfig.defconfig index cbd96af9cd0..911a8845d70 100644 --- a/boards/riscv/stamp_c3/Kconfig.defconfig +++ b/boards/riscv/stamp_c3/Kconfig.defconfig @@ -7,8 +7,10 @@ config BOARD default "stamp_c3" depends on BOARD_STAMP_C3 -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/stamp_c3/stamp_c3.dts b/boards/riscv/stamp_c3/stamp_c3.dts index 029ae49b198..56353da3d81 100644 --- a/boards/riscv/stamp_c3/stamp_c3.dts +++ b/boards/riscv/stamp_c3/stamp_c3.dts @@ -19,6 +19,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/riscv/stamp_c3/stamp_c3_defconfig b/boards/riscv/stamp_c3/stamp_c3_defconfig index 3b5efc64fa1..021a4e84162 100644 --- a/boards/riscv/stamp_c3/stamp_c3_defconfig +++ b/boards/riscv/stamp_c3/stamp_c3_defconfig @@ -5,8 +5,6 @@ CONFIG_SOC_SERIES_ESP32C3=y CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 - CONFIG_CONSOLE=y CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y diff --git a/boards/riscv/titanium_ti60_f225/Kconfig.board b/boards/riscv/titanium_ti60_f225/Kconfig.board index d6ed41ffc79..bac70816b20 100644 --- a/boards/riscv/titanium_ti60_f225/Kconfig.board +++ b/boards/riscv/titanium_ti60_f225/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_TITANIUM_TI60_F225 bool "Board with Efinix Sapphire riscv SoC" - depends on SOC_SERIES_EFINIX_SAPPHIRE + depends on SOC_EFINIX_SAPPHIRE diff --git a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig index 096980b864e..0608a8e8953 100644 --- a/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig +++ b/boards/riscv/titanium_ti60_f225/titanium_ti60_f225_defconfig @@ -1,7 +1,7 @@ # Copyright (c) 2023 Efinix Inc. # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_EFINIX_SAPPHIRE=y +CONFIG_SOC_EFINIX_SAPPHIRE=y CONFIG_BOARD_TITANIUM_TI60_F225=y CONFIG_CONSOLE=y CONFIG_SERIAL=y diff --git a/boards/riscv/tlsr9518adk80d/Kconfig.board b/boards/riscv/tlsr9518adk80d/Kconfig.board index bd36cb0e481..971b34dc13b 100644 --- a/boards/riscv/tlsr9518adk80d/Kconfig.board +++ b/boards/riscv/tlsr9518adk80d/Kconfig.board @@ -3,4 +3,4 @@ config BOARD_TLSR9518ADK80D bool "Telink B91 Platform" - depends on SOC_RISCV_TELINK_B91 + depends on SOC_TELINK_TLSR9518 diff --git a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig index fe5cfbe8c2e..c4cfdfea718 100644 --- a/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig +++ b/boards/riscv/tlsr9518adk80d/tlsr9518adk80d_defconfig @@ -1,8 +1,8 @@ # Copyright (c) 2021 Telink Semiconductor # SPDX-License-Identifier: Apache-2.0 -CONFIG_SOC_SERIES_RISCV_TELINK_B91=y -CONFIG_SOC_RISCV_TELINK_B91=y +CONFIG_SOC_SERIES_TELINK_TLSR951X=y +CONFIG_SOC_TELINK_TLSR9518=y CONFIG_BOARD_TLSR9518ADK80D=y CONFIG_GPIO=y CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 diff --git a/boards/riscv/xiao_esp32c3/Kconfig.defconfig b/boards/riscv/xiao_esp32c3/Kconfig.defconfig index e67ddbcc42e..2852d11301d 100644 --- a/boards/riscv/xiao_esp32c3/Kconfig.defconfig +++ b/boards/riscv/xiao_esp32c3/Kconfig.defconfig @@ -5,8 +5,10 @@ config BOARD default "xiao_esp32c3" depends on BOARD_XIAO_ESP32C3 -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts index 45823b069c8..5cea1004af6 100644 --- a/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts +++ b/boards/riscv/xiao_esp32c3/xiao_esp32c3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,canbus = &twai; }; diff --git a/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi b/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi index 543d0b86df1..9413a7834d9 100644 --- a/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi +++ b/boards/shields/adafruit_2_8_tft_touch_v2/dts/adafruit_2_8_tft_touch_v2.dtsi @@ -8,7 +8,7 @@ / { chosen { - zephyr,display = &ili9340; + zephyr,display = &adafruit_2_8_tft_touch_v2_ili9340; }; lvgl_pointer { @@ -18,6 +18,31 @@ invert-x; invert-y; }; + + adafruit_2_8_tft_touch_v2_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + spi-dev = <&arduino_spi>; + dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */ + write-only; + #address-cells = <1>; + #size-cells = <0>; + + adafruit_2_8_tft_touch_v2_ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + mipi-max-frequency = <15151515>; + reg = <0>; + width = <320>; + height = <240>; + pixel-format = ; + rotation = <90>; + frmctr1 = [00 18]; + pwctrl1 = [23 00]; + vmctrl1 = [3e 28]; + vmctrl2 = [86]; + pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; + ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; + }; + }; }; &arduino_spi { @@ -25,24 +50,6 @@ cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>, /* D10 */ <&arduino_header 10 GPIO_ACTIVE_LOW>; /* D04 */ - - ili9340: ili9340@0 { - compatible = "ilitek,ili9340"; - spi-max-frequency = <15151515>; - reg = <0>; - cmd-data-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - width = <320>; - height = <240>; - pixel-format = ; - rotation = <90>; - frmctr1 = [00 18]; - pwctrl1 = [23 00]; - vmctrl1 = [3e 28]; - vmctrl2 = [86]; - pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; - ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; - }; - adafruit_2_8_tft_touch_v2_sdhc: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay b/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay index 3cc257e9366..162b1450111 100644 --- a/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay +++ b/boards/shields/buydisplay_2_8_tft_touch_arduino/buydisplay_2_8_tft_touch_arduino.overlay @@ -18,29 +18,37 @@ invert-x; invert-y; }; + + buydisplay_2_8_tft_touch_arduino_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */ + reset-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>; /* D10 */ + spi-dev = <&arduino_spi>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9340_buydisplay_2_8_tft_touch_arduino: ili9340@0 { + compatible = "ilitek,ili9340"; + mipi-max-frequency = <25000000>; + reg = <0>; + width = <240>; + height = <320>; + pixel-format = ; + rotation = <0>; + frmctr1 = [00 18]; + pwctrl1 = [23 00]; + vmctrl1 = [3e 28]; + vmctrl2 = [86]; + pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; + ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; + }; + }; }; &arduino_spi { status = "okay"; cs-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - - ili9340_buydisplay_2_8_tft_touch_arduino: ili9340@0 { - compatible = "ilitek,ili9340"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - reset-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - width = <240>; - height = <320>; - pixel-format = ; - rotation = <0>; - frmctr1 = [00 18]; - pwctrl1 = [23 00]; - vmctrl1 = [3e 28]; - vmctrl2 = [86]; - pgamctrl = [0f 31 2b 0c 0e 08 4e f1 37 07 10 03 0e 09 00]; - ngamctrl = [00 0e 14 03 11 07 31 c1 48 08 0f 0c 31 36 0f]; - }; }; &arduino_i2c { diff --git a/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay b/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay index 5764c415460..0ba02cb5648 100644 --- a/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay +++ b/boards/shields/buydisplay_3_5_tft_touch_arduino/buydisplay_3_5_tft_touch_arduino.overlay @@ -18,28 +18,36 @@ invert-x; invert-y; }; + + buydisplay_3_5_tft_touch_arduino_mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */ + reset-gpios = <&arduino_header 16 GPIO_ACTIVE_HIGH>; /* D10 */ + spi-dev = <&arduino_spi>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9488_buydisplay_3_5_tft_touch_arduino: ili9488@0 { + compatible = "ilitek,ili9488"; + mipi-max-frequency = <25000000>; + reg = <0>; + pixel-format = ; + width = <320>; + height = <480>; + rotation = <0>; + frmctr1 = [a0 11]; + pwctrl1 = [17 15]; + pwctrl2 = [41]; + pgamctrl = [00 03 09 08 16 0a 3f 78 4c 09 0a 08 16 1a 0f]; + ngamctrl = [00 16 19 03 0f 05 32 45 46 04 0e 0d 35 37 0f]; + }; + }; }; &arduino_spi { status = "okay"; cs-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */ - - ili9488_buydisplay_3_5_tft_touch_arduino: ili9488@0 { - compatible = "ilitek,ili9488"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ - reset-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */ - pixel-format = ; - width = <320>; - height = <480>; - rotation = <0>; - frmctr1 = [a0 11]; - pwctrl1 = [17 15]; - pwctrl2 = [41]; - pgamctrl = [00 03 09 08 16 0a 3f 78 4c 09 0a 08 16 1a 0f]; - ngamctrl = [00 16 19 03 0f 05 32 45 46 04 0e 0d 35 37 0f]; - }; }; &arduino_i2c { diff --git a/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay b/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay new file mode 100644 index 00000000000..f28bf527c9a --- /dev/null +++ b/boards/shields/esp_8266/boards/numaker_pfm_m467.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + uart2_esp8266: uart2_esp8266 { + group0 { + pinmux = , + , + , + ; + }; + }; +}; + +&uart2 { + status = "okay"; + current-speed = <115200>; + hw-flow-control; + + pinctrl-0 = <&uart2_esp8266>; + pinctrl-names = "default"; + + esp8266: esp8266 { + compatible = "espressif,esp-at"; + reset-gpios = <&gpioc 4 GPIO_ACTIVE_LOW>; + status = "okay"; + }; +}; + +&gpioc { + status = "okay"; +}; diff --git a/boards/shields/lmp90100_evb/lmp90100_evb.overlay b/boards/shields/lmp90100_evb/lmp90100_evb.overlay index 600eefdb127..7271c9c7c3d 100644 --- a/boards/shields/lmp90100_evb/lmp90100_evb.overlay +++ b/boards/shields/lmp90100_evb/lmp90100_evb.overlay @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + &arduino_spi { status = "okay"; @@ -13,7 +16,7 @@ spi-max-frequency = <1000000>; /* Uncomment to use IRQ instead of polling: */ /* drdyb-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; */ - #io-channel-cells = <2>; + #io-channel-cells = <1>; lmp90100_gpio: gpio { compatible = "ti,lmp90xxx-gpio"; diff --git a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay index 7238a5cfb8e..62f633b1a33 100644 --- a/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay +++ b/boards/shields/mikroe_adc_click/boards/lpcxpresso55s16.overlay @@ -4,7 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -/delete-node/ &mcp3204; +#include + +/delete-node/ &mcp3204_mikroe_adc_click; &mikrobus_spi { status = "okay"; diff --git a/boards/shields/mikroe_adc_click/doc/index.rst b/boards/shields/mikroe_adc_click/doc/index.rst index 41656ab2e36..8157863d7d4 100644 --- a/boards/shields/mikroe_adc_click/doc/index.rst +++ b/boards/shields/mikroe_adc_click/doc/index.rst @@ -35,8 +35,8 @@ Set ``-DSHIELD=mikro_adc_click`` when you invoke ``west build``. For example: .. zephyr-app-commands:: - :zephyr-app: test/boards/board_shell - :board: frdm_k64f + :zephyr-app: + :board: lpcxpresso55s16 :shield: mikroe_adc_click :goals: build diff --git a/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay b/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay index e5604daee7e..6686e9e7812 100644 --- a/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay +++ b/boards/shields/mikroe_adc_click/mikroe_adc_click.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &mikrobus_spi { status = "okay"; diff --git a/boards/shields/npm1300_ek/npm1300_ek.overlay b/boards/shields/npm1300_ek/npm1300_ek.overlay index c5991f78598..592aa55f124 100644 --- a/boards/shields/npm1300_ek/npm1300_ek.overlay +++ b/boards/shields/npm1300_ek/npm1300_ek.overlay @@ -23,32 +23,23 @@ /* limits are set to min/max allowed values */ npm1300_ek_buck1: BUCK1 { - regulator-min-microvolt = <1800000>; + regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; }; npm1300_ek_buck2: BUCK2 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-init-microvolt = <3300000>; - retention-microvolt = <2500000>; - enable-gpios = <&npm1300_ek_gpio 1 GPIO_ACTIVE_LOW>; - retention-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_HIGH>; - pwm-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; npm1300_ek_ldo1: LDO1 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-initial-mode = ; - enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; npm1300_ek_ldo2: LDO2 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3300000>; - regulator-initial-mode = ; - enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; }; }; diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig b/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig new file mode 100644 index 00000000000..b192ce223f0 --- /dev/null +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/Kconfig.defconfig @@ -0,0 +1,42 @@ +# Copyright (c) 2023 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_ST_B_LCD40_DSI1_MB1166 + +# Double frame buffer maintained by lvgl. +if LVGL + +config STM32_LTDC_FB_NUM + default 0 + +config INPUT + default y + +config LV_Z_VDB_SIZE + default 100 + +config LV_Z_DOUBLE_VDB + default y + +config LV_Z_VBD_CUSTOM_SECTION + default y + +config LV_Z_FULL_REFRESH + default y + +config LV_Z_BITS_PER_PIXEL + default 32 + +config LV_DPI_DEF + default 128 + +config LV_Z_FLUSH_THREAD + default y + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_32 +endchoice + +endif # LVGL + +endif # SHIELD_ST_B_LCD40_DSI1_MB1166 diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay index a50b0ef6c53..bbaba0718b9 100644 --- a/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/boards/stm32h747i_disco_m7.overlay @@ -7,11 +7,22 @@ #include / { + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&ft5336>; + invert-y; + }; + chosen { zephyr,display = <dc; }; }; +&sdram2 { + /* Frame buffer memory cache will cause screen flickering. */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + <dc { status = "okay"; ext-sdram = <&sdram2>; @@ -72,3 +83,15 @@ pixel-format = ; rotation = <90>; }; + +&i2c4 { + pinctrl-0 = <&i2c4_scl_pd12 &i2c4_sda_pd13>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; + + ft5336: ft5336@38 { + compatible = "focaltech,ft5336"; + reg = <0x38>; + }; +}; diff --git a/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst b/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst index 407f8c6efda..815b65f5750 100644 --- a/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst +++ b/boards/shields/st_b_lcd40_dsi1_mb1166/doc/index.rst @@ -9,6 +9,9 @@ Overview The B-LCD40-DSI1 shield provides a 4-inch WVGA TFT LCD with MIPI DSI interface and capacitive touch screen. +.. note:: + Currently only the older version MB1166-A03 is supported by Zephyr. + The newer version MB1166-A09 does not get initialized correctly (see :github:`60888`). .. figure:: image.jpg :alt: B-LCD40-DSI1 MB1166 Image diff --git a/boards/shields/waveshare_ups/Kconfig.shield b/boards/shields/waveshare_ups/Kconfig.shield new file mode 100644 index 00000000000..38da89750c4 --- /dev/null +++ b/boards/shields/waveshare_ups/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Joseph Yates +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_WAVESHARE_PICO_UPS_B + def_bool $(shields_list_contains,waveshare_pico_ups_b) diff --git a/boards/shields/waveshare_ups/boards/rpi_pico.overlay b/boards/shields/waveshare_ups/boards/rpi_pico.overlay new file mode 100644 index 00000000000..e8fe6525af1 --- /dev/null +++ b/boards/shields/waveshare_ups/boards/rpi_pico.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +&pinctrl { + i2c1_default: i2c1_default { + group1 { + bias-pull-up; + }; + }; +}; + +&pico_i2c1 { + status = "okay"; +}; diff --git a/boards/shields/waveshare_ups/doc/index.rst b/boards/shields/waveshare_ups/doc/index.rst new file mode 100644 index 00000000000..4fc35403b46 --- /dev/null +++ b/boards/shields/waveshare_ups/doc/index.rst @@ -0,0 +1,141 @@ +.. _waveshare_pico_ups_b_shield: + +Waveshare Pico UPS-B shield +########################### + +Overview +******** + +The Waveshare Pico UPS-B shield is an uninterruptible Power supply (UPS) +module designed for the Raspberry Pi Pico which uses the Texas Instruments' INA219 +current/power Monitor. It communicates with the Raspberry Pi Pico over I2C + +.. figure:: waveshare_pico_ups_b.jpg + :align: center + :alt: Waveshare Pico UPS-B shield + + Waveshare Pico UPS-B shield + +Hardware +-------- + +- INA219 + + - Senses bus voltages from 0 to 26 V + - Reports current, voltage and power + - 16 Programmable Addresses + - SOT23-8 and SOIC-8 packages + - Calibration registers + +- ETA6003 + + - Switching charger with power path management + - Up to 95% DC-DC efficiency + - 0mΩ power path MOSFET + - Up to 2.5A max charging current + +- Connectivity + + - Raspberry Pi Pico compatible (I2C) + - 2 pin jst header for Li-po battery + +-------+-----------------------+---------------------------+ +| Name | Function | Usage | ++=======+=======================+===========================+ +| GP0 | None | | ++-------+-----------------------+---------------------------+ +| GP1 | None | | ++-------+-----------------------+---------------------------+ +| GP2 | None | | ++-------+-----------------------+---------------------------+ +| GP3 | None | | ++-------+-----------------------+---------------------------+ +| GP4 | None | | ++-------+-----------------------+---------------------------+ +| GP5 | None | | ++-------+-----------------------+---------------------------+ +| GP6 | I2C1_SDA ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP7 | I2C1_SCL ACTIVE_LOW | INA219 | ++-------+-----------------------+---------------------------+ +| GP8 | None | | ++-------+-----------------------+---------------------------+ +| GP9 | None | | ++-------+-----------------------+---------------------------+ +| GP10 | None | | ++-------+-----------------------+---------------------------+ +| GP11 | None | | ++-------+-----------------------+---------------------------+ +| GP12 | None | | ++-------+-----------------------+---------------------------+ +| GP13 | None | | ++-------+-----------------------+---------------------------+ +| GP14 | None | | ++-------+-----------------------+---------------------------+ +| GP15 | None | | ++-------+-----------------------+---------------------------+ +| GP16 | None | | ++-------+-----------------------+---------------------------+ +| GP17 | None | | ++-------+-----------------------+---------------------------+ +| GP18 | None | | ++-------+-----------------------+---------------------------+ +| GP19 | None | | ++-------+-----------------------+---------------------------+ +| GP20 | None | | ++-------+-----------------------+---------------------------+ +| GP21 | None | | ++-------+-----------------------+---------------------------+ +| GP22 | None | | ++-------+-----------------------+---------------------------+ +| GP23 | None | | ++-------+-----------------------+---------------------------+ +| GP24 | None | | ++-------+-----------------------+---------------------------+ +| GP25 | None | | ++-------+-----------------------+---------------------------+ +| GP26 | None | | ++-------+-----------------------+---------------------------+ +| GP27 | None | | ++-------+-----------------------+---------------------------+ +| GP28 | None | | ++-------+-----------------------+---------------------------+ + + +- Power Supply + + - 3.3V ~ 5V + +- Components + + - Power switch + - Power LED + - Charging LED + +For more information about the Waveshare Pico UPS-B: + +- `Waveshare Pico UPS website`_ +- `INA219 data sheet`_ +- `ETA6003 data sheet`_ + +Programming +*********** + +Set ``-DSHIELD=waveshare_pico_ups_b`` when you invoke ``west build`` or ``cmake`` in your Zephyr application. For +example: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/ina219 + :tool: all + :board: rpi_pico + :shield: waveshare_pico_ups_b + :goals: build flash + +.. _Waveshare Pico UPS website: + https://www.waveshare.com/wiki/Pico-UPS-B + +.. _INA219 data sheet: + https://www.ti.com/lit/ds/symlink/ina219.pdf + +.. _ETA6003 data sheet: + https://www.waveshare.com/w/upload/3/3f/ETA6003.pdf diff --git a/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg b/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg new file mode 100644 index 00000000000..53f1191db5a Binary files /dev/null and b/boards/shields/waveshare_ups/doc/waveshare_pico_ups_b.jpg differ diff --git a/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay new file mode 100644 index 00000000000..381bce67c74 --- /dev/null +++ b/boards/shields/waveshare_ups/waveshare_pico_ups_b.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Joseph Yates + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pico_i2c1 { + waveshare_pico_ups: ina219@43 { + status = "okay"; + compatible = "ti,ina219"; + reg = <0x43>; + brng = <1>; + pg = <3>; + sadc = <12>; + badc = <12>; + shunt-milliohm = <100>; + lsb-microamp = <20>; + }; +}; diff --git a/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig b/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig new file mode 100644 index 00000000000..88f16f95dc5 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/Kconfig.defconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_X_NUCLEO_BNRG2A1 + +if BT + +config SPI + default y + +choice BT_HCI_BUS_TYPE + default BT_SPI +endchoice + +config BT_BLUENRG_ACI + default y + +# Disable Flow control +config BT_HCI_ACL_FLOW_CONTROL + default n + +endif # BT + +endif # SHIELD_X_NUCLEO_BNRG2A1 diff --git a/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield b/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield new file mode 100644 index 00000000000..67efc1dffa5 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_X_NUCLEO_BNRG2A1 + def_bool $(shields_list_contains,x_nucleo_bnrg2a1) diff --git a/boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp b/boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp new file mode 100644 index 00000000000..82304ace345 Binary files /dev/null and b/boards/shields/x_nucleo_bnrg2a1/doc/img/x-nucleo-bnrg2a1.webp differ diff --git a/boards/shields/x_nucleo_bnrg2a1/doc/index.rst b/boards/shields/x_nucleo_bnrg2a1/doc/index.rst new file mode 100644 index 00000000000..ddc9cf83819 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/doc/index.rst @@ -0,0 +1,91 @@ +.. _x-nucleo-bnrg2a1: + +X-NUCLEO-BNRG2A1: BLE expansion board +##################################### + +Overview +******** +The X-NUCLEO-BNRG2A1 is a Bluetooth Low Energy evaluation board based on the +BlueNRG-M2SP RF module to allow expansion of the STM32 Nucleo boards. +The BlueNRG-M2SP module is FCC (FCC ID: S9NBNRGM2SP) and IC certified +(IC: 8976C-BNRGM2SP). + +The X-NUCLEO-BNRG2A1 is compatible with the ST Morpho and Arduino UNO R3 +connector layout (the user can mount the ST Morpho connectors, if required). The +X-NUCLEO-BNRG2A1 interfaces with the host microcontroller via the SPI pins, and +the user can change the default SPI clock, the SPI chip select and SPI IRQ by +changing either one resistor or jumper on the evaluation board. + +Note : This shield is compatible out of the box with Arduino UNO R3 connectors, +but CS signal is not the standard Arduino SPI_CS signal. +Please refer to "Hardware configuration" section. + +.. image:: img/x-nucleo-bnrg2a1.webp + :align: center + :alt: X-NUCLEO-BNRG2A1 + +More information about the board can be found at the +`X-NUCLEO-BNRG2A1 website`_. + +Hardware configuration +********************** + +Out of the box, X-NUCLEO-BNRG2A1 shield expects SPI CS to be available on +Arduino pin A1 instead of usual Arduino UNO R3 SPI CS D10. +This is not a problem as CS signal is software driven gpio on Arduino A1 +see cs-gpios in x_nucleo_bnrg2a1.overlay + +Shield configuration could be modified by moving resistors or changing jumper as +follows: + + - SPI SCK: to use D3 instead of D13, short J14 pins 2 and 3 + +Additionally, depending on your host board, some modifications of the BLE +expansion board could be made: + + - CS: To use D1 instead of A1, unmount R76 and mount R86 + +nucleo_l476rg does not need hardware modifications. + +Hardware +******** + +X-NUCLEO-BNRG2A1 provides a BlueNRG-M2SP chip with the following key features: + + - Bluetooth v5.2 compliant + - Embedded BALF-NRG-02D3 integrated matched balun with harmonic filter + - BLE data packet length extension + +More information about X-NUCLEO-BNRG2A1 can be found here: + - `X-NUCLEO-BNRG2A1 databrief`_ + +Programming +*********** + +You can use the X-NUCLEO-BNRG2A1 as a Bluetooth Low-Energy controller +shield with an SPI host controller interface (HCI-SPI). Activate the presence +of the shield for the project build by adding the ``-DSHIELD`` arg to the +build command: + + .. zephyr-app-commands:: + :zephyr-app: your_app + :board: your_board_name + :shield: x_nucleo_bnrg2a1 + :goals: build + +Alternatively, set use of this shield in the project's ``CMakeLists.txt`` file: + +.. code-block:: cmake + + set(SHIELD x_nucleo_bnrg2a1) + +References +********** + +.. target-notes:: + +.. _X-NUCLEO-BNRG2A1 website: + https://www.st.com/en/ecosystems/x-nucleo-bnrg2a1.html + +.. _X-NUCLEO-BNRG2A1 databrief: + https://www.st.com/resource/en/data_brief/x-nucleo-bnrg2a1.pdf diff --git a/boards/shields/x_nucleo_bnrg2a1/x_nucleo_bnrg2a1.overlay b/boards/shields/x_nucleo_bnrg2a1/x_nucleo_bnrg2a1.overlay new file mode 100644 index 00000000000..177ac9eb948 --- /dev/null +++ b/boards/shields/x_nucleo_bnrg2a1/x_nucleo_bnrg2a1.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&arduino_spi { + cs-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; /* A1 */ + + bluenrg-2@0 { + compatible = "st,hci-spi-v2"; + reg = <0>; + reset-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ + irq-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* A0 */ + spi-cpha; /* CPHA=1 */ + spi-hold-cs; + spi-max-frequency = ; + reset-assert-duration-ms = <6>; + }; +}; diff --git a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig index eb2ec1c1372..430b8a860f7 100644 --- a/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig +++ b/boards/shields/x_nucleo_idb05a1/Kconfig.defconfig @@ -12,9 +12,6 @@ choice BT_HCI_BUS_TYPE default BT_SPI endchoice -config BT_SPI_BLUENRG - default y - config BT_BLUENRG_ACI default y # Disable Flow control diff --git a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay index 8ccf3d7dbf0..e6dff3c9c9f 100644 --- a/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay +++ b/boards/shields/x_nucleo_idb05a1/x_nucleo_idb05a1.overlay @@ -5,15 +5,14 @@ */ &arduino_spi { - cs-gpios = <&arduino_header 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* A1 */ + cs-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>; /* A1 */ spbtle_rf_x_nucleo_idb05a1: spbtle-rf@0 { - compatible = "zephyr,bt-hci-spi"; + compatible = "st,hci-spi-v1"; reg = <0>; - reset-gpios = <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* D7 */ + reset-gpios = <&arduino_header 13 GPIO_ACTIVE_LOW>; /* D7 */ irq-gpios = <&arduino_header 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>; /* A0 */ - spi-max-frequency = <2000000>; - controller-data-delay-us = <0>; /* No need for extra delay for BlueNRG-MS */ + spi-max-frequency = ; spi-hold-cs; }; }; diff --git a/boards/shields/x_nucleo_iks4a1/Kconfig.shield b/boards/shields/x_nucleo_iks4a1/Kconfig.shield new file mode 100644 index 00000000000..a7532594de0 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_X_NUCLEO_IKS01A4 + def_bool $(shields_list_contains,x_nucleo_iks4a1) diff --git a/boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg b/boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg new file mode 100644 index 00000000000..2b631c634c4 Binary files /dev/null and b/boards/shields/x_nucleo_iks4a1/doc/img/x-nucleo-iks4a1.jpg differ diff --git a/boards/shields/x_nucleo_iks4a1/doc/index.rst b/boards/shields/x_nucleo_iks4a1/doc/index.rst new file mode 100644 index 00000000000..a43492bf948 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/doc/index.rst @@ -0,0 +1,172 @@ +.. _x-nucleo-iks4a1: + +X-NUCLEO-IKS4A1: MEMS Inertial and Environmental Multi sensor shield +#################################################################### + +Overview +******** +The X-NUCLEO-IKS4A1 is a motion MEMS and environmental sensor expansion board +for the STM32 Nucleo. It is equipped with Arduino UNO R3 connector layout, and +allows application development with features like sensor HUB (LSM6DSO16IS and +LSM6DSV16X), camera module integration and Qvar touch/swipe gestures (thanks to +the equipped electrode). + +.. image:: img/x-nucleo-iks4a1.jpg + :align: center + :alt: X-NUCLEO-IKS4A1 + +More general information about the board can be found at the +`X-NUCLEO-IKS4A1 website`_. + +Hardware Description +******************** + +X-NUCLEO-IKS4A1 provides the following key features: + + - LSM6DSO16IS: MEMS 3D accelerometer (±2/±4/±8/±16 g) + 3D gyroscope + (±125/±250/±500/±1000/±2000 dps) with ISPU (Intelligent Processing Unit) + - LIS2MDL: MEMS 3D magnetometer (±50 gauss) + - LIS2DUXS12: Ultra low-power MEMS 3D accelerometer (±2/±4/±8/±16 g) with + Qvar, AI, & anti-aliasing + - LPS22DF: Low-power and high-precision MEMS pressure sensor, 260-1260 hPa + absolute digital output barometer + - SHT40AD1B: High-accuracy, ultra-low-power relative humidity and temperature + sensor (by Sensirion) + - STTS22H: Low-voltage, ultralow-power, 0.5 °C accuracy temperature sensor + (–40 °C to +125 °C) + - LSM6DSV16X: MEMS 3D accelerometer (±2/±4/±8/±16 g) + 3D gyroscope + (±125/±250/±500/±1000/±2000/±4000 dps) with embedded sensor fusion, AI, Qvar + - DIL 24-pin socket available for additional MEMS adapters and other sensors + - Free comprehensive development firmware library and example for all sensors + compatible with STM32Cube firmware + - Equipped with Qvar touch/swipe electrode + - I²C sensor hub features on LSM6DSO and LSM6DSV16X available + - MIPI I3C® compatibility for communication with LIS2DUXS12, LSM6DSV16X and + LPS22DF + - Compatible with STM32 Nucleo boards + - Equipped with Arduino UNO R3 connector + - Equipped with industrial connector for IR sensor (STHS34PF80) application + development. It can be connected at the same time of external MEMS through + DIL24 adapter + - Available interface for external camera module applications coupled with + LSM6DSV16X through aux SPI (3/4 w) + - RoHS compliant + - WEEE compliant + - UKCA compliant + +Hardware Configuration +********************** + +X-NUCLEO-IKS4A1 board can be configured in five different modes, which can be +selected through J4 and J5 jumpers. Additional information about X-NUCLEO-IKS4A1 +configuration modes and how sensors are connected together can be found in the +`X-NUCLEO-IKS4A1 user manual`_ + +.. _x-nucleo-iks4a1-mode-1: + +Mode 1: Standard Mode +===================== + +In standard I2C mode, all devices are connected to an external main board via the +same I2C bus. + +The board configuration is: + + - J4: 1-2, 11-12 (STM_SDA = SENS_SDA, HUB_SDx = GND) + - J5: 1-2, 11-12 (STM_SCL = SENS_SCL, HUB_SCx = GND) + +.. _x-nucleo-iks4a1-mode-2: + +Mode 2: LSM6DSO16IS SensorHub Mode (SHUB2) +========================================== + +In this sensor hub I2C mode, it is possible to power-up the 6-axes IMU +(Inertial Measurement Unit) functionalities by collecting external data +through a direct control of the on-board environmental sensors (temperature, +pressure and magnetometer) and external sensor (DIL24) through the auxiliary +I2Cz bus "SENS_I2C". LSM6DSV16X, LIS2DUXS12 and SHT40AD1B remains connected +to the main bus "uC_I2C" coming from the external board. + +The board configuration is: + + - J4: 7-8 (HUB2_SDx = SENS_SDA) + - J5: 7-8 (HUB2_SCx = SENS_SCL) + +.. _x-nucleo-iks4a1-mode-3: + +Mode 3: LSM6DSV16X SensorHub Mode (SHUB1) +========================================= + +In this sensor hub, it is possible to power-up the 6-axes IMU (Inertial +Measurement Unit) functionalities by collecting external data through +a direct control of the on-board environmental sensors (temperature, +pressure and magnetometer) and external sensor (DIL24) through the auxiliary +I2C bus "SENS_I2C". LSM6DSO16IS, LIS2DUXS12 and SHT40AD1B remains connected +to the main bus "uC_I2C" coming from the external board. + +The board configuration is: + + - J4: 5-6 (HUB1_SDx = SENS_SDA) + - J5: 5-6 (HUB1_SDx = SENS_SDA) + +Mode 4: DIL24 SensorHub Mode +============================ + +In case a sensor with sensor hub embedded functionality is mounted to the +board through DIL24 adapter, it is possible to exploit this functionality +as for LSM6DSO16IS and the LSM6DSV16X. In this configuration, may be necessary +to connect the DIL24 to the external board through SPI lines in order to +avoid an address conflict on I2C bus with the LSM6DSO16IS and the LSM6DSV16X. +This is done by changing the SBx configuration. + +The board configuration is: + + - J4: 9-10 (DIL_SDx = SENS_SDA) + - J5: 9-10 (DIL_SDx = SENS_SDA) + +Mode 5: LSM6DSO16IS as Qvar controller +====================================== + +In this configuration, it is possible to use the equipped Qvar swipe electrode +(by plugging it on JP6 and JP7 connectors) through the LSM6DSO16IS. + +The board configuration is: + + - J4: 3-4 (HUB1_SDx = QVAR1) + - J5: 3-4 (HUB1_Scx = QVAR2) + +Devicetree Overlays +******************* + +There are three predefined DT overlays in the board: + +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in Standard Mode (:ref:`x-nucleo-iks4a1-mode-1`) +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in SHUB1 Mode (:ref:`x-nucleo-iks4a1-mode-3`) +- :zephyr_file:`boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay` + This overlay describes sensor connections (and matching h/w configuration to be done) + as explained in SHUB2 Mode (:ref:`x-nucleo-iks4a1-mode-2`) + +Examples +******** + +Three samples are provided as examples for ``x-nucleo-iks4a1`` shield, each one associated +with one of the overlays described above: + +- :ref:`x-nucleo-iks4a1-std-sample` application, to be used when the shield is configured + in Standard Mode (Mode 1) +- :ref:`x-nucleo-iks4a1-shub1-sample` application, to be used when the shield is configured + in SHUB1 Mode (Mode 3) +- :ref:`x-nucleo-iks4a1-shub2-sample` application, to be used when the shield is configured + in SHUB2 Mode (Mode 2) + +See also :ref:`shields` for more details. + +.. _X-NUCLEO-IKS4A1 website: + http://www.st.com/en/ecosystems/x-nucleo-iks4a1.html + +.. _X-NUCLEO-IKS4A1 user manual: + https://www.st.com/resource/en/user_manual/um3239-getting-started-with-the-xnucleoiks4a1-motion-mems-and-environmental-sensor-expansion-board-for-stm32-nucleo-stmicroelectronics.pdf diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay new file mode 100644 index 00000000000..3cda8324777 --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1.overlay @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + magn0 = &lis2mdl_1e_x_nucleo_iks4a1; + accel0 = &lsm6dso16is_6a_x_nucleo_iks4a1; + accel1 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + press0 = &lps22df_5d_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dso16is_6a_x_nucleo_iks4a1: lsm6dso16is@6a { + compatible = "st,lsm6dso16is"; + reg = <0x6a>; + accel-odr = <0x1b>; + gyro-odr = <0x11>; + irq-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 (PC0) */ + drdy-pin = <1>; + }; + + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = <0x02>; + gyro-odr = <0x02>; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; + + lis2mdl_1e_x_nucleo_iks4a1: lis2mdl@1e { + compatible = "st,lis2mdl"; + reg = <0x1e>; + irq-gpios = <&arduino_header 2 GPIO_ACTIVE_HIGH>; /* A2 (PA4) */ + }; + + lps22df_5d_x_nucleo_iks4a1: lps22df@5d { + compatible = "st,lps22df"; + reg = <0x5d>; + drdy-pulsed; + drdy-gpios = <&arduino_header 12 GPIO_ACTIVE_HIGH>; /* D6 (PB10) */ + }; +}; diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay new file mode 100644 index 00000000000..6560816c25c --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub1.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = <0x02>; + gyro-odr = <0x02>; + int1-gpios = <&arduino_header 11 GPIO_ACTIVE_HIGH>; /* D5 */ + drdy-pin = <1>; + }; +}; diff --git a/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay new file mode 100644 index 00000000000..6c259fb221b --- /dev/null +++ b/boards/shields/x_nucleo_iks4a1/x_nucleo_iks4a1_shub2.overlay @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + accel0 = &lsm6dso16is_6a_x_nucleo_iks4a1_shub; + }; +}; + +&arduino_i2c { + lsm6dso16is_6a_x_nucleo_iks4a1_shub: lsm6dso16is@6a { + compatible = "st,lsm6dso16is"; + reg = <0x6a>; + irq-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 */ + drdy-pin = <1>; + }; +}; diff --git a/boards/sparc/gr716a_mini/gr716a_mini.dts b/boards/sparc/gr716a_mini/gr716a_mini.dts index 551caba6b8a..745caa64f67 100644 --- a/boards/sparc/gr716a_mini/gr716a_mini.dts +++ b/boards/sparc/gr716a_mini/gr716a_mini.dts @@ -6,11 +6,15 @@ /dts-v1/; +#include #include / { model = "GR716-MINI Development Board"; compatible = "gaisler,gr716a-mini"; + aliases { + spi-flash0 = &flash0; + }; chosen { zephyr,console = &uart0; zephyr,shell-uart = &uart0; @@ -21,3 +25,15 @@ &uart0 { status = "okay"; }; + +&spim0 { + status = "okay"; + /* 256 Mbit SPI flash MX25L25635FZ2I-10G in 8 pin WSON package */ + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + size = ; + jedec-id = [c2 20 19]; + }; +}; diff --git a/boards/sparc/gr716a_mini/gr716a_mini.yaml b/boards/sparc/gr716a_mini/gr716a_mini.yaml index 4107097aab5..8b673cebfa6 100644 --- a/boards/sparc/gr716a_mini/gr716a_mini.yaml +++ b/boards/sparc/gr716a_mini/gr716a_mini.yaml @@ -9,6 +9,7 @@ toolchain: - xtools supported: - netif + - spi testing: ignore_tags: - net diff --git a/boards/x86/acrn/Kconfig.defconfig b/boards/x86/acrn/Kconfig.defconfig index 0216875583c..a1a8936e38b 100644 --- a/boards/x86/acrn/Kconfig.defconfig +++ b/boards/x86/acrn/Kconfig.defconfig @@ -10,8 +10,8 @@ config BOARD config MP_MAX_NUM_CPUS default 2 -config HEAP_MEM_POOL_SIZE - default 32768 if ACPI - depends on KERNEL_MEM_POOL +config HEAP_MEM_POOL_ADD_SIZE_ACPI + default 32768 + depends on ACPI endif diff --git a/boards/x86/intel_adl/Kconfig.defconfig b/boards/x86/intel_adl/Kconfig.defconfig index cc9e3882ec4..5a61d2f552e 100644 --- a/boards/x86/intel_adl/Kconfig.defconfig +++ b/boards/x86/intel_adl/Kconfig.defconfig @@ -33,12 +33,10 @@ config ACPI default y if ACPI -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 -config ACPI_PRT_BUS_NAME - default "_SB.PC00" if SHELL config SHELL_STACK_SIZE @@ -46,4 +44,16 @@ config SHELL_STACK_SIZE endif # SHELL endif # ACPI +if DMA +config DMA_64BIT + default y +config DMA_DW_HW_LLI + default n +config DMA_DW_CHANNEL_COUNT + default 2 +endif + +config UART_NS16550_INTEL_LPSS_DMA + default y + endif # BOARD_INTEL_ADL_CRB || BOARD_INTEL_ADL_RVP || BOARD_UP_SQUARED_PRO_7000 diff --git a/boards/x86/intel_adl/intel_adl_crb.dts b/boards/x86/intel_adl/intel_adl_crb.dts index 7a5f8b9d6e0..e78b92aff4d 100644 --- a/boards/x86/intel_adl/intel_adl_crb.dts +++ b/boards/x86/intel_adl/intel_adl_crb.dts @@ -23,7 +23,3 @@ &uart0 { status = "okay"; }; - -&uart1 { - status = "okay"; -}; diff --git a/boards/x86/intel_adl/intel_adl_crb_defconfig b/boards/x86/intel_adl/intel_adl_crb_defconfig index c2c1a37850d..5287bfcacc0 100644 --- a/boards/x86/intel_adl/intel_adl_crb_defconfig +++ b/boards/x86/intel_adl/intel_adl_crb_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/intel_adl_rvp_defconfig b/boards/x86/intel_adl/intel_adl_rvp_defconfig index 41260a3b233..0f6ed718268 100644 --- a/boards/x86/intel_adl/intel_adl_rvp_defconfig +++ b/boards/x86/intel_adl/intel_adl_rvp_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_adl/up_squared_pro_7000_defconfig b/boards/x86/intel_adl/up_squared_pro_7000_defconfig index 211ce9f24e1..4c228677a70 100644 --- a/boards/x86/intel_adl/up_squared_pro_7000_defconfig +++ b/boards/x86/intel_adl/up_squared_pro_7000_defconfig @@ -12,4 +12,3 @@ CONFIG_X2APIC=y CONFIG_SMP=y CONFIG_BUILD_OUTPUT_EFI=y CONFIG_BUILD_NO_GAP_FILL=y -CONFIG_UART_NS16550_PARENT_INIT_LEVEL=y diff --git a/boards/x86/intel_ehl/Kconfig.defconfig b/boards/x86/intel_ehl/Kconfig.defconfig index 7d6667a6cec..ae8270faa64 100644 --- a/boards/x86/intel_ehl/Kconfig.defconfig +++ b/boards/x86/intel_ehl/Kconfig.defconfig @@ -19,13 +19,9 @@ config SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN default n endif -config ACPI_PRT_BUS_NAME +config HEAP_MEM_POOL_ADD_SIZE_ACPI + default 2097152 depends on ACPI - default "_SB.PC00" - -config HEAP_MEM_POOL_SIZE - default 2097152 if ACPI - depends on KERNEL_MEM_POOL # TSC on this board is 1.9 GHz, HPET and APIC are 19.2 MHz config SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/boards/x86/intel_rpl/Kconfig.board b/boards/x86/intel_rpl/Kconfig.board index f806be34a88..0424004d10b 100644 --- a/boards/x86/intel_rpl/Kconfig.board +++ b/boards/x86/intel_rpl/Kconfig.board @@ -1,4 +1,4 @@ -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 config BOARD_INTEL_RPL_S_CRB @@ -6,3 +6,9 @@ config BOARD_INTEL_RPL_S_CRB depends on SOC_RAPTOR_LAKE select X86_64 select HAS_COVERAGE_SUPPORT + +config BOARD_INTEL_RPL_P_CRB + bool "Raptor Lake P CRB" + depends on SOC_RAPTOR_LAKE + select X86_64 + select HAS_COVERAGE_SUPPORT diff --git a/boards/x86/intel_rpl/Kconfig.defconfig b/boards/x86/intel_rpl/Kconfig.defconfig index 78c10d200a3..0458aef89be 100644 --- a/boards/x86/intel_rpl/Kconfig.defconfig +++ b/boards/x86/intel_rpl/Kconfig.defconfig @@ -1,10 +1,11 @@ -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 -if BOARD_INTEL_RPL_S_CRB +if BOARD_INTEL_RPL_S_CRB || BOARD_INTEL_RPL_P_CRB config BOARD - default "intel_rpl_s_crb" + default "intel_rpl_p_crb" if BOARD_INTEL_RPL_P_CRB + default "intel_rpl_s_crb" if BOARD_INTEL_RPL_S_CRB config BUILD_OUTPUT_STRIPPED default y @@ -31,12 +32,10 @@ config ACPI default y if ACPI -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_ACPI default 64000000 config MAIN_STACK_SIZE default 320000 -config ACPI_PRT_BUS_NAME - default "_SB.PC00" if SHELL config SHELL_STACK_SIZE @@ -53,4 +52,12 @@ config DMA_DW_CHANNEL_COUNT default 2 endif -endif # BOARD_INTEL_RPL_S_CRB +config UART_NS16550_INTEL_LPSS_DMA + default y if BOARD_INTEL_RPL_S_CRB + +if SHELL +config SHELL_STACK_SIZE + default 320000 +endif + +endif # BOARD_INTEL_RPL_S_CRB || BOARD_INTEL_RPL_P_CRB diff --git a/boards/x86/intel_rpl/doc/index.rst b/boards/x86/intel_rpl/doc/index.rst index b9c64ded19e..7c3d7758484 100644 --- a/boards/x86/intel_rpl/doc/index.rst +++ b/boards/x86/intel_rpl/doc/index.rst @@ -1,23 +1,37 @@ -.. _intel_rpl_s_crb: +.. _intel_rpl_crb: -Raptor Lake S CRB -################# +Raptor Lake CRB +############### Overview ******** -Raptor Lake Reference Board (RPL CRB) is an example implementation of a -compact single board computer with high performance for IoT edge devices. +Raptor Lake processor is a 13th generation 64-bit multi-core processor built +on a 10-nanometer technology process. Raptor Lake is based on a Hybrid +architecture, utilizing P-cores for performance and E-Cores for efficiency. -This board configuration enables kernel support for the `RPL`_ board. +Raptor Lake S and Raptor Lake P processor lines are supported. -.. note:: - This board configuration works on the variant of `RPL`_ - boards containing Intel |reg| Core |trade| SoC. +The S-Processor line is a 2-Chip Platform that includes the Processor Die and +Platform Controller Hub (PCH-S) Die in the Package. + +The P-Processor line is a 2-Die Multi Chip Package (MCP) that includes the +Processor Die and Platform Controller Hub (PCH-P) Die on the same package as +the Processor Die. + +For more information about Raptor Lake Processor lines, P-cores, and E-cores +please refer to `RPL`_. + +Raptor Lake Customer Reference Board (RPL CRB) is an example implementation of a +compact single board computer with high performance for IoT edge devices. The +supported boards are `intel_rpl_s_crb` and `intel_rpl_p_crb`. + +These board configurations enable kernel support for the supported Raptor Lake +boards. Hardware ******** -General information about the board can be found at the `RPL`_ website. +General information about the board can be found at the `RPL`_. .. include:: ../../../../soc/x86/raptor_lake/doc/supported_features.txt @@ -25,11 +39,11 @@ General information about the board can be found at the `RPL`_ website. Connections and IOs =================== -Refer to the `RPL`_ website for more information. +Refer to the `RPL`_ for more information. Programming and Debugging ************************* -Use the following procedures for booting an image on a RPL CRB board. +Use the following procedures for booting an image on an RPL CRB board. .. contents:: :depth: 1 @@ -58,4 +72,4 @@ Booting the Raptor Lake S CRB Board using UEFI .. include:: ../../common/efi_boot.rst :start-after: start_include_here -.. _RPL: https://www.intel.com/content/www/us/en/newsroom/resources/13th-gen-core.html#gs.glf2fn +.. _RPL: https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/ diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb.dts b/boards/x86/intel_rpl/intel_rpl_p_crb.dts new file mode 100644 index 00000000000..ea07719a9b5 --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +#define DT_DRAM_SIZE DT_SIZE_M(2048) + +#include + +/ { + model = "intel_rpl_p_crb"; + compatible = "intel,raptor-lake-crb"; + + chosen { + zephyr,sram = &dram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + watchdog0 = &tco_wdt; + rtc = &rtc; + }; +}; diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb.yaml b/boards/x86/intel_rpl/intel_rpl_p_crb.yaml new file mode 100644 index 00000000000..2e6504dd32f --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb.yaml @@ -0,0 +1,22 @@ +identifier: intel_rpl_p_crb +name: Raptor Lake P CRB +type: mcu +arch: x86 +toolchain: + - zephyr +ram: 2048 +supported: + - acpi + - smp + - smbus + - watchdog + - rtc + - pwm + - gpio + - spi + - i2c +testing: + ignore_tags: + - net + - bluetooth +vendor: intel diff --git a/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig b/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig new file mode 100644 index 00000000000..09fd65cf261 --- /dev/null +++ b/boards/x86/intel_rpl/intel_rpl_p_crb_defconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_RAPTOR_LAKE=y +CONFIG_BOARD_INTEL_RPL_P_CRB=y +CONFIG_PIC_DISABLE=y +CONFIG_LOAPIC=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_NS16550=y +CONFIG_UART_NS16550_VARIANT_NS16750=y +CONFIG_UART_CONSOLE=y +CONFIG_X2APIC=y +CONFIG_SMP=y +CONFIG_BUILD_OUTPUT_EFI=y +CONFIG_BUILD_NO_GAP_FILL=y diff --git a/boards/x86/intel_rpl/intel_rpl_s_crb.dts b/boards/x86/intel_rpl/intel_rpl_s_crb.dts index 5301b373022..9a18aa57266 100644 --- a/boards/x86/intel_rpl/intel_rpl_s_crb.dts +++ b/boards/x86/intel_rpl/intel_rpl_s_crb.dts @@ -9,7 +9,7 @@ #define DT_DRAM_SIZE DT_SIZE_M(2048) -#include +#include / { model = "intel_rpl_s_crb"; diff --git a/boards/x86/qemu_x86/Kconfig.defconfig b/boards/x86/qemu_x86/Kconfig.defconfig index 84f66e32004..1e2b7af0a4d 100644 --- a/boards/x86/qemu_x86/Kconfig.defconfig +++ b/boards/x86/qemu_x86/Kconfig.defconfig @@ -24,10 +24,6 @@ config FLASH_SIMULATOR config KERNEL_VM_SIZE default 0x10000000 if ACPI -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - config MULTIBOOT default y @@ -53,10 +49,6 @@ config BOARD config KERNEL_VM_SIZE default 0x10000000 if ACPI -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - endif # BOARD_QEMU_X86_64 if BOARD_QEMU_X86_LAKEMONT diff --git a/boards/x86/qemu_x86/board.cmake b/boards/x86/qemu_x86/board.cmake index 934b078154e..97a56a92770 100644 --- a/boards/x86/qemu_x86/board.cmake +++ b/boards/x86/qemu_x86/board.cmake @@ -56,6 +56,9 @@ endif() if(CONFIG_X86_SSE4A) string(JOIN "," QEMU_CPU_FLAGS "${QEMU_CPU_FLAGS}" "sse4a") endif() +if(NOT CONFIG_X86_64 AND CONFIG_CACHE_MANAGEMENT) + string(JOIN "," QEMU_CPU_FLAGS "${QEMU_CPU_FLAGS}" "clflush") +endif() set(QEMU_FLAGS_${ARCH} -m ${QEMU_MEMORY_SIZE_MB} diff --git a/boards/x86/qemu_x86/qemu_x86.dts b/boards/x86/qemu_x86/qemu_x86.dts index 62dfaf57b05..6117d7927ab 100644 --- a/boards/x86/qemu_x86/qemu_x86.dts +++ b/boards/x86/qemu_x86/qemu_x86.dts @@ -49,7 +49,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; can0: can0 { diff --git a/boards/x86/qemu_x86/qemu_x86_64.dts b/boards/x86/qemu_x86/qemu_x86_64.dts index 83bf2c7fd0f..fc252104773 100644 --- a/boards/x86/qemu_x86/qemu_x86_64.dts +++ b/boards/x86/qemu_x86/qemu_x86_64.dts @@ -5,6 +5,17 @@ #include "qemu_x86.dts" +/ { + cpus { + cpu@1 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <1>; + }; + }; +}; + &pcie0 { smbus0: smbus0 { compatible = "intel,pch-smbus"; diff --git a/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts b/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts index 92522ab8a4e..8a5f2d51154 100644 --- a/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts +++ b/boards/x86/qemu_x86/qemu_x86_64_nokpti.dts @@ -4,3 +4,14 @@ */ #include "qemu_x86.dts" + +/ { + cpus { + cpu@1 { + device_type = "cpu"; + compatible = "intel,x86"; + d-cache-line-size = <64>; + reg = <1>; + }; + }; +}; diff --git a/boards/x86/qemu_x86/qemu_x86_tiny_768.conf b/boards/x86/qemu_x86/qemu_x86_tiny_768.conf index 4601be10f38..583d6a85451 100644 --- a/boards/x86/qemu_x86/qemu_x86_tiny_768.conf +++ b/boards/x86/qemu_x86/qemu_x86_tiny_768.conf @@ -3,3 +3,7 @@ # Enable coverage regardless since this config for coverage only. CONFIG_COVERAGE=y + +# Need more stack space due to coverage being enabled. +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_IDLE_STACK_SIZE=1024 diff --git a/boards/x86/up_squared/Kconfig.defconfig b/boards/x86/up_squared/Kconfig.defconfig index 33cf546edfc..e8eecbcc508 100644 --- a/boards/x86/up_squared/Kconfig.defconfig +++ b/boards/x86/up_squared/Kconfig.defconfig @@ -8,10 +8,6 @@ config BOARD config MP_MAX_NUM_CPUS default 2 if BOARD_UP_SQUARED -config HEAP_MEM_POOL_SIZE - default 1048576 if ACPI - depends on KERNEL_MEM_POOL - config BUILD_OUTPUT_STRIPPED default y diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board index 5c3fa887b57..a295f3bfc50 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.board @@ -5,6 +5,10 @@ config BOARD_ESP32_DEVKITC_WROOM bool "ESP32-DEVKITC-WROOM Development Board" depends on SOC_SERIES_ESP32 +config BOARD_ESP32_DEVKITC_WROOM_APPCPU + bool "ESP32 Board configuration for APPCPU (core 1)." + depends on SOC_SERIES_ESP32 && SOC_ESP32_APPCPU + choice SOC_PART_NUMBER default SOC_ESP32_WROOM_32UE_N4 endchoice diff --git a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig index cf2cb4403a1..aadb2d833f8 100644 --- a/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wroom/Kconfig.defconfig @@ -3,18 +3,36 @@ # Copyright (c) 2017 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +if BOARD_ESP32_DEVKITC_WROOM + config BOARD default "esp32_devkitc_wroom" - depends on BOARD_ESP32_DEVKITC_WROOM - -config ENTROPY_GENERATOR - default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice + +endif # BOARD_ESP32_DEVKITC_WROOM + +if BOARD_ESP32_DEVKITC_WROOM_APPCPU + +config BOARD + default "esp32_devkitc_wroom_appcpu" + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + default 4096 + +config KERNEL_BIN_NAME + default "esp32_appcpu_firmware" + +endif # BOARD_ESP32_DEVKITC_WROOM_APPCPU + +config ENTROPY_GENERATOR + default y diff --git a/boards/xtensa/esp32_devkitc_wroom/doc/index.rst b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst index b8856c7b3cb..ceeb7d38ba9 100644 --- a/boards/xtensa/esp32_devkitc_wroom/doc/index.rst +++ b/boards/xtensa/esp32_devkitc_wroom/doc/index.rst @@ -47,6 +47,12 @@ The features include the following: ESP32-DevKitC-WROOM-32D DK +Asymmetric Multiprocessing (AMP) +******************************** + +ESP32-DEVKITC-WROOM allows 2 different applications to be executed in ESP32 SoC. Due to its dual-core architecture, each core can be enabled to execute customized tasks in stand-alone mode +and/or exchanging data over OpenAMP framework. See :ref:`ipc_samples` folder as code reference. + Supported Features ================== diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts index 6fa0bf47f61..a33384c2a5c 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.dts @@ -8,6 +8,7 @@ #include #include "esp32_devkitc_wroom-pinctrl.dtsi" #include +#include / { model = "Espressif ESP32-DEVKITC-WROOM-32D"; @@ -34,6 +35,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; @@ -73,6 +75,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { status = "okay"; clock-frequency = ; diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml index 0481a96df00..19155f8a0d1 100644 --- a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom.yaml @@ -17,6 +17,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts new file mode 100644 index 00000000000..c58f39cd444 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include + +/ { + model = "esp32_wroom_appcpu"; + compatible = "espressif,esp32_appcpu"; + + chosen { + zephyr,sram = &sram0; + zephyr,ipc_shm = &shm0; + zephyr,ipc = &ipm0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&trng0 { + status = "okay"; +}; diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml new file mode 100644 index 00000000000..02f9916ef90 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32_devkitc_wroom_appcpu +name: ESP32 DEVKITC WROOM APPCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - uart +testing: + ignore_tags: + - net + - bluetooth + - flash + - cpp + - posix + - watchdog + - logging + - kernel + - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp +vendor: espressif diff --git a/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig new file mode 100644 index 00000000000..81406ae4c49 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wroom/esp32_devkitc_wroom_appcpu_defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_ESP32=y +CONFIG_SOC_ESP32_APPCPU=y +CONFIG_BOARD_ESP32_DEVKITC_WROOM_APPCPU=y + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y +CONFIG_MINIMAL_LIBC=y diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board index b345a9dff44..20e59ac10fe 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.board +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.board @@ -5,6 +5,10 @@ config BOARD_ESP32_DEVKITC_WROVER bool "ESP32-DEVKITC-WROVER-E Development board" depends on SOC_SERIES_ESP32 +config BOARD_ESP32_DEVKITC_WROVER_APPCPU + bool "ESP32 Board configuration for APPCPU (core 1)." + depends on SOC_SERIES_ESP32 && SOC_ESP32_APPCPU + choice SOC_PART_NUMBER default SOC_ESP32_WROVER_E_N4R8 endchoice diff --git a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig index 8b977af6943..84b365c2b77 100644 --- a/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig +++ b/boards/xtensa/esp32_devkitc_wrover/Kconfig.defconfig @@ -1,18 +1,35 @@ # Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. # SPDX-License-Identifier: Apache-2.0 +if BOARD_ESP32_DEVKITC_WROVER + config BOARD default "esp32_devkitc_wrover" - depends on BOARD_ESP32_DEVKITC_WROVER - -config ENTROPY_GENERATOR - default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 choice BT_HCI_BUS_TYPE default BT_ESP32 if BT endchoice + +endif # BOARD_ESP32_DEVKITC_WROVER + +if BOARD_ESP32_DEVKITC_WROVER_APPCPU + +config BOARD + default "esp32_devkitc_wrover_appcpu" + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + default 4096 + +config KERNEL_BIN_NAME + default "esp32_appcpu_firmware" +endif + +config ENTROPY_GENERATOR + default y diff --git a/boards/xtensa/esp32_devkitc_wrover/doc/index.rst b/boards/xtensa/esp32_devkitc_wrover/doc/index.rst index e7615f13335..ec59ab5c640 100644 --- a/boards/xtensa/esp32_devkitc_wrover/doc/index.rst +++ b/boards/xtensa/esp32_devkitc_wrover/doc/index.rst @@ -47,6 +47,12 @@ The features include the following: ESP32-DevKitC-WROVER-IE +Asymmetric Multiprocessing (AMP) +******************************** + +ESP32-DEVKITC-WROVER allows 2 different applications to be executed in ESP32 SoC. Due to its dual-core architecture, each core can be enabled to execute customized tasks in stand-alone mode +and/or exchanging data over OpenAMP framework. See :ref:`ipc_samples` folder as code reference. + Supported Features ================== diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts index 43218f3e81f..d62fe5ccfb8 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.dts @@ -8,6 +8,7 @@ #include #include "esp32_devkitc_wrover-pinctrl.dtsi" #include +#include / { model = "Espressif ESP32-DEVKITC-WROVER-E"; @@ -34,6 +35,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; @@ -72,6 +74,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { status = "okay"; clock-frequency = ; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml index 7ae68f8e9de..df56a1dbc55 100644 --- a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover.yaml @@ -17,6 +17,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts new file mode 100644 index 00000000000..2b6f0626356 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include + +/ { + model = "esp32_wrover_appcpu"; + compatible = "espressif,esp32_appcpu"; + + chosen { + zephyr,sram = &sram0; + zephyr,ipc_shm = &shm0; + zephyr,ipc = &ipm0; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&trng0 { + status = "okay"; +}; diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml new file mode 100644 index 00000000000..03fe6a111a6 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu.yaml @@ -0,0 +1,27 @@ +identifier: esp32_devkitc_wrover_appcpu +name: ESP32 DEVKITC WROVER APPCPU +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - uart +testing: + ignore_tags: + - net + - bluetooth + - flash + - cpp + - posix + - watchdog + - logging + - kernel + - pm + - gpio + - crypto + - eeprom + - heap + - cmsis_rtos + - jwt + - zdsp +vendor: espressif diff --git a/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig new file mode 100644 index 00000000000..5363f493882 --- /dev/null +++ b/boards/xtensa/esp32_devkitc_wrover/esp32_devkitc_wrover_appcpu_defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_ESP32=y +CONFIG_SOC_ESP32_APPCPU=y +CONFIG_BOARD_ESP32_DEVKITC_WROVER_APPCPU=y + +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_CLOCK_CONTROL=y +CONFIG_MINIMAL_LIBC=y diff --git a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig index aed4adc50a8..8797780b74e 100644 --- a/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig +++ b/boards/xtensa/esp32_ethernet_kit/Kconfig.defconfig @@ -17,8 +17,10 @@ endchoice config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts index 3139e8beaa3..50b01b88b2f 100644 --- a/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts +++ b/boards/xtensa/esp32_ethernet_kit/esp32_ethernet_kit.dts @@ -22,6 +22,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp32_net/Kconfig.board b/boards/xtensa/esp32_net/Kconfig.board deleted file mode 100644 index 946a59dce7f..00000000000 --- a/boards/xtensa/esp32_net/Kconfig.board +++ /dev/null @@ -1,12 +0,0 @@ -# ESP32 board configuration - -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD_ESP32_NET - bool "ESP32 Board configuration for APP_CPU" - depends on SOC_SERIES_ESP32_NET - -choice SOC_PART_NUMBER - default SOC_ESP32_NET -endchoice diff --git a/boards/xtensa/esp32_net/Kconfig.defconfig b/boards/xtensa/esp32_net/Kconfig.defconfig deleted file mode 100644 index 928a4c06de9..00000000000 --- a/boards/xtensa/esp32_net/Kconfig.defconfig +++ /dev/null @@ -1,20 +0,0 @@ -# ESP32_NET board configuration - -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config BOARD - default "esp32_net" - depends on BOARD_ESP32_NET - -config ENTROPY_GENERATOR - default y - -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI - default 40960 if BT - default 4096 - -choice BT_HCI_BUS_TYPE - default BT_ESP32 if BT -endchoice diff --git a/boards/xtensa/esp32_net/doc/index.rst b/boards/xtensa/esp32_net/doc/index.rst deleted file mode 100644 index 5321727aa7d..00000000000 --- a/boards/xtensa/esp32_net/doc/index.rst +++ /dev/null @@ -1,169 +0,0 @@ -.. _esp32_net: - -ESP32-NET -######### - -Overview -******** - -ESP32_NET is a board configuration to allow zephyr application building -targeted to ESP32 APP_CPU only, please refer ESP32 board to a more complete -list of features. - -System requirements -******************* - -Prerequisites -------------- - -Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command -below to retrieve those files. - -.. code-block:: console - - west blobs fetch hal_espressif - -.. note:: - - It is recommended running the command above after :file:`west update`. - -Building & Flashing -------------------- - -Build and flash applications as usual (see :ref:`build_an_application` and -:ref:`application_run` for more details). - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: build - -The usual ``flash`` target will work with the ``esp32_devkitc_wroom`` board -configuration. Here is an example for the :ref:`hello_world` -application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: flash - -Open the serial monitor using the following command: - -.. code-block:: shell - - west espressif monitor - -After the board has automatically reset and booted, you should see the following -message in the monitor: - -.. code-block:: console - - ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** - Hello World! esp32_devkitc_wroom - -Debugging ---------- - -As with much custom hardware, the ESP32 modules require patches to -OpenOCD that are not upstreamed yet. Espressif maintains their own fork of -the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_ - -The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the -``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` -parameter when building. - -Here is an example for building the :ref:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: build flash - :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= - -You can debug an application in the usual way. Here is an example for the :ref:`hello_world` application. - -.. zephyr-app-commands:: - :zephyr-app: samples/hello_world - :board: esp32_devkitc_wroom - :goals: debug - -Using JTAG -====================== - -On the ESP-WROVER-KIT board, the JTAG pins are connected internally to -a USB serial port on the same device as the console. These boards -require no external hardware and are debuggable as-is. The JTAG -signals, however, must be jumpered closed to connect the internal -controller (the default is to leave them disconnected). The jumper -headers are on the right side of the board as viewed from the power -switch, next to similar headers for SPI and UART. See -`ESP-WROVER-32 V3 Getting Started Guide`_ for details. - -On the ESP-WROOM-32 DevKitC board, the JTAG pins are not run to a -standard connector (e.g. ARM 20-pin) and need to be manually connected -to the external programmer (e.g. a Flyswatter2): - -+------------+-----------+ -| ESP32 pin | JTAG pin | -+============+===========+ -| 3V3 | VTRef | -+------------+-----------+ -| EN | nTRST | -+------------+-----------+ -| IO14 | TMS | -+------------+-----------+ -| IO12 | TDI | -+------------+-----------+ -| GND | GND | -+------------+-----------+ -| IO13 | TCK | -+------------+-----------+ -| IO15 | TDO | -+------------+-----------+ - -Once the device is connected, you should be able to connect with (for -a DevKitC board, replace with esp32-wrover.cfg for WROVER): - -.. code-block:: console - - cd ~/esp/openocd-esp32 - src/openocd -f interface/ftdi/flyswatter2.cfg -c 'set ESP32_ONLYCPU 1' -c 'set ESP32_RTOS none' -f board/esp-wroom-32.cfg -s tcl - -The ESP32_ONLYCPU setting is critical: without it OpenOCD will present -only the "APP_CPU" via the gdbserver, and not the "PRO_CPU" on which -Zephyr is running. It's currently unexplored as to whether the CPU -can be switched at runtime or if breakpoints can be set for -either/both. - -Now you can connect to openocd with gdb and point it to the OpenOCD -gdbserver running (by default) on localhost port 3333. Note that you -must use the gdb distributed with the ESP-32 SDK. Builds off of the -FSF mainline get inexplicable protocol errors when connecting. - -.. code-block:: console - - ~/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-gdb outdir/esp32/zephyr.elf - (gdb) target remote localhost:3333 - -Further documentation can be obtained from the SoC vendor in `JTAG debugging -for ESP32`_. - -Note on Debugging with GDB Stub -=============================== - -GDB stub is enabled on ESP32. - -* When adding breakpoints, please use hardware breakpoints with command - ``hbreak``. Command ``break`` uses software breakpoints which requires - modifying memory content to insert break/trap instructions. - This does not work as the code is on flash which cannot be randomly - accessed for modification. - -References -********** - -.. _`ESP32 Technical Reference Manual`: https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf -.. _`JTAG debugging for ESP32`: http://esp-idf.readthedocs.io/en/latest/api-guides/jtag-debugging/index.html -.. _`Hardware Reference`: https://esp-idf.readthedocs.io/en/latest/hw-reference/index.html -.. _`ESP-WROVER-32 V3 Getting Started Guide`: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-wrover-kit.html -.. _`OpenOCD ESP32`: https://github.com/espressif/openocd-esp32/releases diff --git a/boards/xtensa/esp32_net/esp32_net.dts b/boards/xtensa/esp32_net/esp32_net.dts deleted file mode 100644 index 7479d342fb6..00000000000 --- a/boards/xtensa/esp32_net/esp32_net.dts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ -/dts-v1/; - -#include - -/ { - model = "esp32_net"; - compatible = "espressif,esp32_net"; - - chosen { - zephyr,sram = &sram0; - }; -}; - -&cpu0 { - clock-frequency = ; -}; - -&cpu1 { - clock-frequency = ; -}; - -&trng0 { - status = "okay"; -}; diff --git a/boards/xtensa/esp32_net/esp32_net.yaml b/boards/xtensa/esp32_net/esp32_net.yaml deleted file mode 100644 index 14739928f62..00000000000 --- a/boards/xtensa/esp32_net/esp32_net.yaml +++ /dev/null @@ -1,22 +0,0 @@ -identifier: esp32_net -name: ESP32_NET -type: mcu -arch: xtensa -toolchain: - - zephyr -supported: - - gpio - - i2c - - uart -testing: - ignore_tags: - - net - - bluetooth - - flash - - cpp - - posix - - watchdog - - logging - - kernel - - pm -vendor: espressif diff --git a/boards/xtensa/esp32_net/esp32_net_defconfig b/boards/xtensa/esp32_net/esp32_net_defconfig deleted file mode 100644 index 94fed73bc45..00000000000 --- a/boards/xtensa/esp32_net/esp32_net_defconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_BOARD_ESP32_NET=y -CONFIG_SOC_SERIES_ESP32_NET=y - -CONFIG_MAIN_STACK_SIZE=2048 - -CONFIG_CONSOLE=n -CONFIG_SERIAL=n -CONFIG_UART_CONSOLE=n - -CONFIG_GPIO=n -CONFIG_GPIO_ESP32=n - -CONFIG_I2C=n diff --git a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig index 94937f824dc..2319c0061e4 100644 --- a/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_franzininho/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts index 66c85606097..2ce35ee5534 100644 --- a/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts +++ b/boards/xtensa/esp32s2_franzininho/esp32s2_franzininho.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig index 7724f8c90a1..709b0d5b53b 100644 --- a/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_lolin_mini/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts index 9f90447560b..3ce00f8bdb8 100644 --- a/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts +++ b/boards/xtensa/esp32s2_lolin_mini/esp32s2_lolin_mini.dts @@ -25,6 +25,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/esp32s2_saola/Kconfig.defconfig b/boards/xtensa/esp32s2_saola/Kconfig.defconfig index 077b2bde4ac..8b160c02935 100644 --- a/boards/xtensa/esp32s2_saola/Kconfig.defconfig +++ b/boards/xtensa/esp32s2_saola/Kconfig.defconfig @@ -10,6 +10,7 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int default 32768 if WIFI default 4096 diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts index 7a5c4fb087a..781f4b758d6 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.dts +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.dts @@ -9,6 +9,7 @@ #include #include "esp32s2_saola-pinctrl.dtsi" #include +#include / { model = "esp32s2_saola"; @@ -25,6 +26,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; gpio_keys { @@ -56,6 +58,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &timer0 { status = "disabled"; }; diff --git a/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml b/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml index 261d7d0eb8f..1e1e391bb0e 100644 --- a/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml +++ b/boards/xtensa/esp32s2_saola/esp32s2_saola.yaml @@ -16,6 +16,7 @@ supported: - spi - counter - entropy + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig index cb102b4ee64..54a01595721 100644 --- a/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_devkitm/Kconfig.defconfig @@ -8,8 +8,10 @@ if BOARD_ESP32S3_DEVKITM config BOARD default "esp32s3_devkitm" -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 @@ -24,11 +26,11 @@ if BOARD_ESP32S3_DEVKITM_APPCPU config BOARD default "esp32s3_devkitm_appcpu" -config HEAP_MEM_POOL_SIZE - default 4096 +config HEAP_MEM_POOL_ADD_SIZE_BOARD + def_int 4096 config KERNEL_BIN_NAME - default "esp32_net_firmware" + default "esp32_appcpu_firmware" endif config ENTROPY_GENERATOR diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts index f7c75b12017..640304ee00f 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.dts @@ -8,6 +8,7 @@ #include #include "esp32s3_devkitm-pinctrl.dtsi" #include +#include / { model = "esp32s3_devkitm"; @@ -23,6 +24,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { @@ -67,6 +69,18 @@ status = "okay"; }; +&touch { + debounce-interval-ms = <30>; + href-microvolt = <2700000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; +}; + &i2c0 { clock-frequency = ; pinctrl-0 = <&i2c0_default>; diff --git a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml index 160e01f4d6e..cce4cb8b82e 100644 --- a/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml +++ b/boards/xtensa/esp32s3_devkitm/esp32s3_devkitm.yaml @@ -15,6 +15,7 @@ supported: - entropy - pwm - dma + - input testing: ignore_tags: - net diff --git a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig index 88744adac06..35d4a9bc3fc 100644 --- a/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig +++ b/boards/xtensa/esp32s3_luatos_core/Kconfig.defconfig @@ -10,8 +10,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts index 89bebe9018c..fea76fca3b7 100644 --- a/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts +++ b/boards/xtensa/esp32s3_luatos_core/esp32s3_luatos_core.dts @@ -25,5 +25,6 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig index 65efe16093d..378b557eb7f 100644 --- a/boards/xtensa/esp_wrover_kit/Kconfig.defconfig +++ b/boards/xtensa/esp_wrover_kit/Kconfig.defconfig @@ -7,8 +7,10 @@ config BOARD default "esp_wrover_kit" depends on BOARD_ESP_WROVER_KIT -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts index 54ded2ac1b3..f7385037609 100644 --- a/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts +++ b/boards/xtensa/esp_wrover_kit/esp_wrover_kit.dts @@ -32,6 +32,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; @@ -69,6 +70,26 @@ pwms = <&ledc0 2 PWM_HZ(100) PWM_POLARITY_NORMAL>; }; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + reg = <0>; + pixel-format = <0>; + rotation = <0>; + width = <240>; + height = <320>; + }; + }; }; &cpu0 { @@ -124,18 +145,6 @@ status = "okay"; pinctrl-0 = <&spim3_default>; pinctrl-names = "default"; - - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - pixel-format = <0>; - rotation = <0>; - width = <240>; - height = <320>; - }; }; &ledc0 { diff --git a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig index d8e0ba31dba..eaf538cd281 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig +++ b/boards/xtensa/heltec_wifi_lora32_v2/Kconfig.defconfig @@ -10,8 +10,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts index 5fd323082a3..636f1afd354 100644 --- a/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts +++ b/boards/xtensa/heltec_wifi_lora32_v2/heltec_wifi_lora32_v2.dts @@ -54,6 +54,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt new file mode 100644 index 00000000000..11856690835 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(CONFIG_GPIO_ESP32) + zephyr_library() + zephyr_library_sources(board_init.c) +endif() diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board new file mode 100644 index 00000000000..a590916109d --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.board @@ -0,0 +1,13 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_HELTEC_WIRELESS_STICK_LITE + bool "Heltec Wireless Stick Lite (V3) Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig new file mode 100644 index 00000000000..ea79f62e2fa --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Heltec Wireless Stick Lite (V3) board configuration + +# Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) +# Copyright (c) 2023 The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "heltec_wireless_stick_lite_v3" + depends on BOARD_HELTEC_WIRELESS_STICK_LITE + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI + default 40960 if BT + default 4096 + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild new file mode 100644 index 00000000000..3a2d17ac5cf --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/esp32_net/board.cmake b/boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake similarity index 100% rename from boards/xtensa/esp32_net/board.cmake rename to boards/xtensa/heltec_wireless_stick_lite_v3/board.cmake diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c new file mode 100644 index 00000000000..f36032fcfa4 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/board_init.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define VEXT_PIN DT_GPIO_PIN(DT_NODELABEL(vext), gpios) + +static int board_heltec_wireless_stick_lite_v3_init(void) +{ + const struct device *gpio; + + gpio = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + if (!device_is_ready(gpio)) { + return -ENODEV; + } + + /* turns external VCC on */ + gpio_pin_configure(gpio, VEXT_PIN, GPIO_OUTPUT); + gpio_pin_set_raw(gpio, VEXT_PIN, 0); + + return 0; +} + +SYS_INIT(board_heltec_wireless_stick_lite_v3_init, PRE_KERNEL_2, CONFIG_GPIO_INIT_PRIORITY); diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp new file mode 100644 index 00000000000..4cdb9bfdded Binary files /dev/null and b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3.webp differ diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3_pinout.webp b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3_pinout.webp new file mode 100644 index 00000000000..b24d2de9911 Binary files /dev/null and b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/heltec_wireless_stick_lite_v3_pinout.webp differ diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/doc/index.rst b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/index.rst new file mode 100644 index 00000000000..24170d4cb1b --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/doc/index.rst @@ -0,0 +1,306 @@ +.. heltec_wireless_stick_lite_v3: + +HelTec Wireless Stick Lite (V3) +############################### + +Overview +******** + +HelTec Wireless Stick Lite (V3) is a development board with Wi-Fi, Bluetooth and LoRa support. It is designed and produced by HelTec Automation(TM). [1]_ + +.. figure:: heltec_wireless_stick_lite_v3.webp + :width: 400px + :align: center + :alt: HelTec Wireless Stick Lite (V3) + + HelTec Wireless Stick Lite (V3) (Credit: Chengdu HelTec Automation Technology Co., Ltd.) + +Hardware +******** + +The main hardware features are: + +- ESP32-S3FN8 low-power MCU-based SoC (dual-core Xtensa® 32-bit LX7 microprocessor, five stage pipeline rack Structure, main frequency up to 240 MHz). +- Semtech SX1262 LoRa node chip +- Type-C USB interface with a complete voltage regulator, ESD protection, short circuit protection, RF shielding, and other protection measures (note: you need an USB-A to USB-C cable if you want to power-up the board from USB). +- Onboard SH1.25-2 battery interface, integrated lithium battery management system (charge and discharge management, overcharge protection, battery power detection, USB / battery power automatic switching). +- Integrated WiFi and Bluetooth interfaces with 2.4GHz metal spring antenna and reserved IPEX (U.FL) interface for LoRa use. +- Integrated CP2102 USB to serial port chip, convenient for program downloading, debugging information printing. +- Good RF circuit design and low-power design. + +Supported Features +================== +- LoRa via SPI +- UART0 (USB Serial via CP2102) +- UART1 +- I2C +- CAN (optional, need to enable) +- PWM LED +- User Switch / Button + +Connections and IOs +=================== + +.. figure:: heltec_wireless_stick_lite_v3_pinout.webp + :width: 600px + :align: center + :alt: HelTec Wireless Stick Lite (V3) Pinout + + Pinout (Credit: Chengdu HelTec Automation Technology Co., Ltd.) + +.. table:: HelTec Wireless Stick Lite (V3) Pinout + :widths: auto + + +--------+---------+-----------------------------+ + | Header | Function| Description | + +========+=========+=============================+ + | J2.1 | Ve | | + +--------+---------+-----------------------------+ + | J2.2 | GND | | + +--------+---------+-----------------------------+ + | J2.3 | | | + +--------+---------+-----------------------------+ + | J2.4 | U0RXD | Zephyr Console+Shell | + +--------+---------+-----------------------------+ + | J2.5 | U0TXD | Zephyr Console+Shell | + +--------+---------+-----------------------------+ + | J2.6 | | | + +--------+---------+-----------------------------+ + | J2.7 | | | + +--------+---------+-----------------------------+ + | J2.8 | GPIO35 | PWM LED Control | + +--------+---------+-----------------------------+ + | J2.9 | GPIO36 | Vext Control | + +--------+---------+-----------------------------+ + | J2.10 | GPIO37 | ADC Control | + +--------+---------+-----------------------------+ + | J2.11 | | | + +--------+---------+-----------------------------+ + | J2.12 | GPIO39 | | + +--------+---------+-----------------------------+ + | J2.13 | GPIO40 | | + +--------+---------+-----------------------------+ + | J2.14 | GPIO41 | | + +--------+---------+-----------------------------+ + | J2.15 | GPIO42 | | + +--------+---------+-----------------------------+ + | J2.16 | GPIO45 | | + +--------+---------+-----------------------------+ + | J2.17 | GPIO46 | | + +--------+---------+-----------------------------+ + | J2.18 | ADC1_CH0| Battery Voltage Measurement | + +--------+---------+-----------------------------+ + | J2.19 | | | + +--------+---------+-----------------------------+ + | J2.20 | | | + +--------+---------+-----------------------------+ + | J3.1 | 5V | | + +--------+---------+-----------------------------+ + | J3.2 | 3V3 | | + +--------+---------+-----------------------------+ + | J3.3 | GND | | + +--------+---------+-----------------------------+ + | J3.4 | GPIO47 | | + +--------+---------+-----------------------------+ + | J3.5 | GPIO48 | | + +--------+---------+-----------------------------+ + | J3.6 | GPIO0 | User Switch | + +--------+---------+-----------------------------+ + | J3.7 | | | + +--------+---------+-----------------------------+ + | J3.8 | | | + +--------+---------+-----------------------------+ + | J3.9 | U1RXD | UART 1 | + +--------+---------+-----------------------------+ + | J3.10 | GPIO21 | | + +--------+---------+-----------------------------+ + | J3.11 | | | + +--------+---------+-----------------------------+ + | J3.12 | U1TXD | UART 1 | + +--------+---------+-----------------------------+ + | J3.13 | | | + +--------+---------+-----------------------------+ + | J3.14 | NC | Reset Switch | + +--------+---------+-----------------------------+ + | J3.15 | | | + +--------+---------+-----------------------------+ + | J3.16 | | | + +--------+---------+-----------------------------+ + | J3.17 | | | + +--------+---------+-----------------------------+ + | J3.18 | | | + +--------+---------+-----------------------------+ + | J3.19 | TWAI_TX | CAN (optional) | + +--------+---------+-----------------------------+ + | J3.20 | TWAI_RX | CAN (optional) | + +--------+---------+-----------------------------+ + + +System requirements +******************* + +Prerequisites +============= + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Programming and Debugging +************************* + +ESP-IDF bootloader +================== + +The board is using the ESP-IDF bootloader as the default 2nd stage bootloader. +It is build as a subproject at each application build. No further attention +is expected from the user. + +MCUboot bootloader +================== + +User may choose to use MCUboot bootloader instead. In that case the bootloader +must be build (and flash) at least once. + +There are two options to be used when building an application: + +1. Sysbuild +2. Manual build + +.. note:: + + User can select the MCUboot bootloader by adding the following line + to the board default configuration file. + ``` + CONFIG_BOOTLOADER_MCUBOOT=y + ``` + +Sysbuild +======== + +The sysbuild makes possible to build and flash all necessary images needed to +bootstrap the board with the EPS32-S3 SoC. + +To build the sample application using sysbuild use the command: + +.. zephyr-app-commands:: + :tool: west + :app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: build + :west-args: --sysbuild + :compact: + +By default, the ESP32S3 sysbuild creates bootloader (MCUboot) and application +images. But it can be configured to create other kind of images. + +Build directory structure created by sysbuild is different from traditional +Zephyr build. Output is structured by the domain subdirectories: + +.. code-block:: + + build/ + ├── hello_world + │   └── zephyr + │   ├── zephyr.elf + │   └── zephyr.bin + ├── mcuboot + │ └── zephyr + │ ├── zephyr.elf + │ └── zephyr.bin + └── domains.yaml + +.. note:: + + With ``--sysbuild`` option the bootloader will be re-build and re-flash + every time the pristine build is used. + +For more information about the system build please read the :ref:`sysbuild` documentation. + +Manual build +============ + +During the development cycle, it is intended to build & flash as quickly possible. +For that reason, images can be build one at a time using traditional build. + +The instructions following are relevant for both manual build and sysbuild. +The only difference is the structure of the build directory. + +.. note:: + + Remember that bootloader (MCUboot) needs to be flash at least once. + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: build + +The usual ``flash`` target will work with the ``heltec_wireless_stick_lite_v3`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: flash + +Open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! heltec_wireless_stick_lite_v3 + +Debugging +========= + +As with much custom hardware, the ESP32S3 modules require patches to +OpenOCD that are not upstreamed yet. Espressif maintains their own fork of +the project. The custom OpenOCD can be obtained at `OpenOCD ESP32`_ + +The Zephyr SDK uses a bundled version of OpenOCD by default. You can overwrite that behavior by adding the +``-DOPENOCD= -DOPENOCD_DEFAULT_PATH=`` +parameter when building. + +Here is an example for building the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: build flash + :gen-args: -DOPENOCD= -DOPENOCD_DEFAULT_PATH= + +You can debug an application in the usual way. Here is an example for the :ref:`hello_world` application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: heltec_wireless_stick_lite_v3 + :goals: debug + +References +********** + +- `Heltec Wireless Stick Lite (v3) Pinout Diagram `_ +- `Heltec Wireless Stick Lite (v3) Schematic Diagrams `_ +- `ESP-IDF Programming Guide `_ +- `esptool documentation `_ +- `OpenOCD ESP32 `_ + +.. [1] https://heltec.org/project/wireless-stick-lite-v2/ diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi new file mode 100644 index 00000000000..6afc36ddec6 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3-pinctrl.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + uart1_default: uart1_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + , + ; + }; + group2 { + pinmux = ; + output-low; + }; + }; + + twai_default: twai_default { + group1 { + pinmux = , + ; + }; + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = ; + output-enable; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts new file mode 100644 index 00000000000..9a23a008c2f --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.dts @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * Copyright (c) 2023 The Zephyr Project Contributors + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "heltec_wireless_stick_lite_v3-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "heltec_wireless_stick_lite_v3"; + compatible = "espressif,esp32s3"; + + aliases { + pwm-0 = &ledc0; + pwm-led0 = &pwm_led_white; + uart-0 = &uart0; + uart-1 = &uart1; + i2c-0 = &i2c0; + lora0 = &lora0; + sw0 = &button0; + watchdog0 = &wdt0; + }; + + leds { + compatible = "gpio-leds"; + + vext: vext { + gpios = <&gpio0 36 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "Vext Control"; + }; + + adc: adc { + gpios = <&gpio0 37 GPIO_ACTIVE_LOW>; + label = "ADC Control"; + }; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led_white: pwm_led_gpio0_35 { + label = "White PWM LED"; + pwms = <&ledc0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>; + }; + }; + + buttons { + compatible = "gpio-keys"; + button0: button_0 { + gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + label = "USER SW"; + zephyr,code = ; + }; + }; + + vbatt { + compatible = "voltage-divider"; + io-channels = <&adc1 0>; + output-ohms = <100000>; + full-ohms = <(100000 + 390000)>; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&adc1 { + status ="okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; +}; + +&i2c0 { + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; + lora0: lora@0 { + compatible = "semtech,sx1262"; + reg = <0>; + reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; + busy-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; + dio1-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + dio2-tx-enable; + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + spi-max-frequency = <16000000>; + }; +}; + +&twai { + pinctrl-0 = <&twai_default>; + pinctrl-names = "default"; + bus-speed = <125000>; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 64kB for the bootloader */ + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml new file mode 100644 index 00000000000..05c89b6d984 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3.yaml @@ -0,0 +1,22 @@ +identifier: heltec_wireless_stick_lite_v3 +name: Heltec Wireless Stick Lite (V3) +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - can + - counter + - watchdog + - entropy + - pwm + - dma + - lora +testing: + ignore_tags: + - net + - bluetooth diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig new file mode 100644 index 00000000000..a32ddde0422 --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/heltec_wireless_stick_lite_v3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_HELTEC_WIRELESS_STICK_LITE=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CLOCK_CONTROL=y +CONFIG_CONSOLE=y +CONFIG_GPIO=y +CONFIG_PWM=y +CONFIG_SERIAL=y +CONFIG_SPI=y +CONFIG_UART_CONSOLE=y diff --git a/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg new file mode 100644 index 00000000000..2f740b4a36a --- /dev/null +++ b/boards/xtensa/heltec_wireless_stick_lite_v3/support/openocd.cfg @@ -0,0 +1,7 @@ +set ESP_RTOS none +set ESP32_ONLYCPU 1 + +# Source the JTAG interface configuration file +source [find interface/esp_usb_jtag.cfg] +# Source the ESP32-S3 configuration file +source [find target/esp32s3.cfg] diff --git a/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake b/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake index 63777239a1d..e9778da4d84 100644 --- a/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake +++ b/boards/xtensa/intel_adsp_ace15_mtpm/board.cmake @@ -6,4 +6,4 @@ board_set_rimage_target(mtl) set(RIMAGE_SIGN_KEY "otc_private_key_3k.pem" CACHE STRING "default in ace15_mtpm/board.cmake") -include(${ZEPHYR_BASE}/boards/common/intel_adsp.board.cmake) +board_finalize_runner_args(intel_adsp) diff --git a/boards/xtensa/intel_adsp_cavs25/board.cmake b/boards/xtensa/intel_adsp_cavs25/board.cmake index 8d7f36e07bd..1bdb2698c12 100644 --- a/boards/xtensa/intel_adsp_cavs25/board.cmake +++ b/boards/xtensa/intel_adsp_cavs25/board.cmake @@ -17,4 +17,4 @@ if(CONFIG_BOARD_INTEL_ADSP_CAVS25_TGPH) board_set_rimage_target(tgl-h) endif() -include(${ZEPHYR_BASE}/boards/common/intel_adsp.board.cmake) +board_finalize_runner_args(intel_adsp) diff --git a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst index 737cdbee05b..6b0a4526fe4 100644 --- a/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst +++ b/boards/xtensa/intel_adsp_cavs25/doc/intel_adsp_generic.rst @@ -64,9 +64,10 @@ you will also need to set up the SOF rimage signing tool and key. .. code-block:: shell - cd zephyrproject/modules/audio/sof/ - git clone https://github.com/thesofproject/rimage --recurse-submodules - cd rimage + cd zephyrproject + west config manifest.project-filter -- +sof + west update + cd modules/audio/sof/tools/rimage Follow the instructions in the rimage :file:`README.md` to build the tool on your system. You can either copy the executable to a directory in your PATH or @@ -74,21 +75,9 @@ use ``west config rimage.path /path/to/rimage-build/rimage``; see more details in the output of ``west sign -h``. Running directly from the build directory makes you less likely to use an obsolete rimage version by mistake. -Until https://github.com/zephyrproject-rtos/zephyr/issues/58212 gets -implemented, you must manually and regularly update and rebuild rimage. - -The SOF project does not require this manual step because its west manifest -automatically downloads and builds a specific rimage version validated with -matching SOF sources. An indirect Zephyr -> SOF -> rimage dependency chain is -unfortunately not appropriate because unlike rimage, SOF is *not* required to -run Zephyr on cAVS/ACE hardware. - -Until https://github.com/thesofproject/sof/issues/7270 is implemented, -platform-specific configuration files are also located in the rimage -repository, more specifically in the ``rimage/config/`` subdirectory; this is -another reason to update rimage regularly. If you cloned rimage in a location -different from above (not recommended) then you must also run ``west config -build.cmake-args -- -DRIMAGE_CONFIG_PATH=/path/to/source/rimage/config``. +Platform-specific configuration files are located in the ``rimage/config/`` +subdirectory. For a different configuration directory you can use: +``west config build.cmake-args -- -DRIMAGE_CONFIG_PATH=/path/to/my/rimage/config``. Xtensa Toolchain (Optional) @@ -154,12 +143,10 @@ undocumented rimage precedence rules it's best to use only one way at a time. ``boards/my/board/board.cmake``, see example in ``soc/xtensa/intel_adsp/common/CMakeLists.txt`` -For backwards compatibility reasons, you can also pass rimage parameters like -the path to the tool binary as arguments to -``west flash`` if the flash target exists for your board. To see a list -of all arguments to the Intel ADSP runner, run the following after you have -built the binary. There are multiple arguments related to signing, including a -key argument. +Starting with Zephyr 3.6.0, ``west flash`` does not invoke ``west sign`` +anymore and you cannot pass rimage parameters to ``west flash`` anymore. To +see an up-to-date list of all arguments to the Intel ADSP runner, run the +following after you have built the binary: .. code-block:: console diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.board b/boards/xtensa/kincony_kc868_a32/Kconfig.board new file mode 100644 index 00000000000..098f377092b --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_KINCONY_KC868_A32 + bool "KINCONY KC868-A32 Board" + depends on SOC_SERIES_ESP32 + +choice SOC_PART_NUMBER + default SOC_ESP32_WROOM_32UE_N4 +endchoice diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig new file mode 100644 index 00000000000..85e02264b5a --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "kincony_kc868_a32" + depends on BOARD_KINCONY_KC868_A32 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_SIZE + default 65535 if WIFI && BT + default 51200 if WIFI + default 40960 if BT + default 4096 diff --git a/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild b/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild new file mode 100644 index 00000000000..bcf253836da --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/kincony_kc868_a32/board.cmake b/boards/xtensa/kincony_kc868_a32/board.cmake new file mode 100644 index 00000000000..bf24ed17150 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/board.cmake @@ -0,0 +1,11 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() + +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg b/boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg new file mode 100644 index 00000000000..9fa5685bb4d Binary files /dev/null and b/boards/xtensa/kincony_kc868_a32/doc/img/kincony_kc868_a32.jpg differ diff --git a/boards/xtensa/kincony_kc868_a32/doc/index.rst b/boards/xtensa/kincony_kc868_a32/doc/index.rst new file mode 100644 index 00000000000..dfd4797701b --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/doc/index.rst @@ -0,0 +1,97 @@ +.. _kincony_kc868_a32: + +KINCONY KC868-A32 +################# + +Overview +******** + +Kincony KC868-A32 is a home automation relay module based on the +Espressif ESP-WROOM-32 module with all its inherent capabilities +(Wi-Fi, Bluetooth, etc.) + +The features include the following: + +- 32 digital optoisolated inputs “dry contact” +- 4 analog inputs 0-5 V +- 32 relays 220 V, 10 A (COM, NO, NC) +- RS485 interface +- I2C connector +- Connector GSM/HMI +- Ethernet LAN8270A +- USB Type-B connector for programming and filling firmware +- RESET and DOWNLOAD buttons +- Powered by 12V DC + +.. figure:: img/kincony_kc868_a32.jpg + :align: center + :alt: KINCONCY-KC868-A32 + + KINCONCY-KC868-A32 + +System requirements +=================== + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +------------------- + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: kincony_kc868_a32 + :goals: build + +The usual ``flash`` target will work with the ``kincony_kc868_a32`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: kincony_kc868_a32 + :goals: flash + +Open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! kincony_kc868_a32 + +Enabling Ethernet +***************** + +Enable Ethernet in KConfig: + +.. code-block:: cfg + + CONFIG_NETWORKING=y + CONFIG_NET_L2_ETHERNET=y + CONFIG_MDIO=y + +References +********** + +.. _KINCONY KC868-A32 User Guide: https://www.kincony.com/arduino-esp32-32-channel-relay-module-kc868-a32.html diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi new file mode 100644 index 00000000000..e1ee7cb2432 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32-pinctrl.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) Bartosz Bilas + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + mdio_default: mdio_default { + group1 { + pinmux = , + ; + }; + }; +}; diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts new file mode 100644 index 00000000000..2690ae75b24 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.dts @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023 Bartosz Bilas + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "kincony_kc868_a32-pinctrl.dtsi" + +/ { + model = "Kincony KC868-A32"; + compatible = "espressif,esp32"; + + aliases { + uart-0 = &uart0; + watchdog0 = &wdt0; + }; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&cpu0 { + clock-frequency = ; + cpu-power-states = <&light_sleep &deep_sleep>; +}; + +&cpu1 { + clock-frequency = ; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 15 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 13 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + + i2c0_pcf8574@21 { + compatible = "nxp,pcf857x"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@22 { + compatible = "nxp,pcf857x"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@24 { + compatible = "nxp,pcf857x"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c0_pcf8574@25 { + compatible = "nxp,pcf857x"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + sda-gpios = <&gpio0 4 GPIO_OPEN_DRAIN>; + scl-gpios = <&gpio0 5 GPIO_OPEN_DRAIN>; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + + i2c1_pcf8574@21 { + compatible = "nxp,pcf857x"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@22 { + compatible = "nxp,pcf857x"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@24 { + compatible = "nxp,pcf857x"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + i2c1_pcf8574@25 { + compatible = "nxp,pcf857x"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; +}; + +&mdio { + pinctrl-0 = <&mdio_default>; + pinctrl-names = "default"; + status = "okay"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + status = "okay"; + reg = <0>; + }; +}; + +ð { + status = "okay"; + phy-handle = <&phy>; + ref-clk-output-gpios = <&gpio0 17 0>; +}; + +&psram0 { + status = "disabled"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&trng0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserve 60kB for the bootloader */ + boot_partition: partition@1000 { + label = "mcuboot"; + reg = <0x00001000 0x0000F000>; + read-only; + }; + + /* Reserve 1024kB for the application in slot 0 */ + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + /* Reserve 1024kB for the application in slot 1 */ + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + /* Reserve 256kB for the scratch partition */ + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml new file mode 100644 index 00000000000..72577b2572a --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32.yaml @@ -0,0 +1,19 @@ +identifier: kincony_kc868_a32 +name: KINCONY-KC868-A32 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - watchdog + - uart + - nvs + - counter + - entropy +testing: + ignore_tags: + - net + - bluetooth +vendor: kincony diff --git a/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig new file mode 100644 index 00000000000..7bb4a23e794 --- /dev/null +++ b/boards/xtensa/kincony_kc868_a32/kincony_kc868_a32_defconfig @@ -0,0 +1,14 @@ +# Copyright (c) Bartosz Bilas +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_KINCONY_KC868_A32=y +CONFIG_SOC_SERIES_ESP32=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y + +CONFIG_GPIO=y +CONFIG_I2C=y diff --git a/boards/xtensa/esp32_net/support/openocd.cfg b/boards/xtensa/kincony_kc868_a32/support/openocd.cfg similarity index 100% rename from boards/xtensa/esp32_net/support/openocd.cfg rename to boards/xtensa/kincony_kc868_a32/support/openocd.cfg diff --git a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig index b9bd2641458..94f209758eb 100644 --- a/boards/xtensa/m5stack_atoms3/Kconfig.defconfig +++ b/boards/xtensa/m5stack_atoms3/Kconfig.defconfig @@ -11,8 +11,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 65536 if BT default 4096 diff --git a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts index abbff8bbbfd..72ebd81b42f 100644 --- a/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts +++ b/boards/xtensa/m5stack_atoms3/m5stack_atoms3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &st7789v; }; diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.board b/boards/xtensa/m5stack_atoms3_lite/Kconfig.board new file mode 100644 index 00000000000..2c77718895e --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack AtomS3 Lite board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +# M5Stack AtomS3 Lite +config BOARD_M5STACK_ATOMS3_LITE + bool "M5Stack AtomS3 Lite Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig b/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig new file mode 100644 index 00000000000..8f982cec80b --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.defconfig @@ -0,0 +1,26 @@ +# M5Stack AtomS3 Lite board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_ATOMS3_LITE + +config BOARD + default "m5stack_atoms3_lite" + depends on BOARD_M5STACK_ATOMS3_LITE + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 98304 if WIFI + default 65536 if BT + default 4096 + +config KERNEL_MEM_POOL + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice +endif # BOARD_M5STACK_ATOMS3_LITE diff --git a/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild b/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild new file mode 100644 index 00000000000..3a2d17ac5cf --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT +endchoice + +choice BOOT_SIGNATURE_TYPE + default BOOT_SIGNATURE_TYPE_NONE +endchoice diff --git a/boards/xtensa/m5stack_atoms3_lite/board.cmake b/boards/xtensa/m5stack_atoms3_lite/board.cmake new file mode 100644 index 00000000000..2f04d1fe886 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp b/boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp new file mode 100644 index 00000000000..c538a14dc0e Binary files /dev/null and b/boards/xtensa/m5stack_atoms3_lite/doc/img/m5stack_atoms3_lite.webp differ diff --git a/boards/xtensa/m5stack_atoms3_lite/doc/index.rst b/boards/xtensa/m5stack_atoms3_lite/doc/index.rst new file mode 100644 index 00000000000..c51f580aa62 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/doc/index.rst @@ -0,0 +1,134 @@ +.. _m5stack_atoms3_lite: + +M5Stack AtomS3 Lite +################### + +Overview +******** + +M5Stack AtomS3 Lite is an ESP32-based development board from M5Stack. + +It features the following integrated components: + +- ESP32-S3FN8 chip (240MHz dual core, Wi-Fi/BLE 5.0) +- 512KB of SRAM +- 384KB of ROM +- 8MB of Flash +- RGB Status-LED + + +.. figure:: img/m5stack_atoms3_lite.webp + :align: center + :alt: M5Stack AtomS3 Lite + + M5Stack AtomS3 Lite + + +Supported Features +================== + +The Zephyr m5stack_atoms3_lite board configuration supports the following hardware features: + ++-----------+------------+-------------------------------------+ +| Interface | Controller | Driver/Component | ++===========+============+=====================================+ +| NVIC | on-chip | nested vector interrupt controller | ++-----------+------------+-------------------------------------+ +| UART | on-chip | serial port-polling; | +| | | serial port-interrupt | ++-----------+------------+-------------------------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+-------------------------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+-------------------------------------+ +| I2C | on-chip | i2c | ++-----------+------------+-------------------------------------+ +| SPI | on-chip | spi | ++-----------+------------+-------------------------------------+ +| CLOCK | on-chip | reset and clock control | ++-----------+------------+-------------------------------------+ +| COUNTER | on-chip | rtc | ++-----------+------------+-------------------------------------+ +| WATCHDOG | on-chip | independent watchdog | ++-----------+------------+-------------------------------------+ +| PWM | on-chip | pwm | ++-----------+------------+-------------------------------------+ +| ADC | on-chip | adc | ++-----------+------------+-------------------------------------+ +| DAC | on-chip | dac | ++-----------+------------+-------------------------------------+ +| die-temp | on-chip | die temperature sensor | ++-----------+------------+-------------------------------------+ + + +Start Application Development +***************************** + +Before powering up your M5Stack AtomS3 Lite, please make sure that the board is in good +condition with no obvious signs of damage. + +System requirements +=================== + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: shell + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +------------------- + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_atoms3_lite + :goals: build + +The usual ``flash`` target will work with the ``m5stack_atoms3_lite`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_atoms3_lite + :goals: flash + +The baud rate of 921600bps is set by default. If experiencing issues when flashing, +try using different values by using ``--esp-baud-rate `` option during +``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). + +You can also open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! m5stack_atoms3_lite + +Debugging +--------- + +M5Stack AtomS3 Lite debugging is not supported due to pinout limitations. + +Related Documents +***************** + +- `M5Stack AtomS3 Lite schematic `_ +- `ESP32S3 Datasheet `_ diff --git a/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi b/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi new file mode 100644 index 00000000000..db98d8885dd --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/grove_connectors.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + grove_header: grove_header { + compatible = "grove-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = <0 0 &gpio0 1 0>, + <1 0 &gpio0 2 0>; + }; +}; + +grove_i2c1: &i2c1 {}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi new file mode 100644 index 00000000000..051456e687c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite-pinctrl.dtsi @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim3_ws2812_led: spim3_ws2812_led { + group1 { + pinmux = ; + output-low; + }; + }; +}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts new file mode 100644 index 00000000000..51b65cfba0c --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.dts @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2023 Benjamin Cabé + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_atoms3_lite-pinctrl.dtsi" +#include +#include +#include + +/ { + model = "M5Stack AtomS3 Lite"; + compatible = "m5stack,atoms3_lite"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + i2c-0 = &i2c0; + led-strip = &status_rgb_led; + }; + + buttons { + compatible = "gpio-keys"; + debounce-interval-ms = <100>; + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "okay"; +}; +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + line-idle-low; + pinctrl-0 = <&spim3_ws2812_led>; + pinctrl-names = "default"; + + status_rgb_led: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + reg = <0>; + spi-max-frequency = ; + + chain-length = <1>; + color-mapping = , + , + ; + spi-one-frame = ; + spi-zero-frame = ; + }; +}; +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000F000>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml new file mode 100644 index 00000000000..82426e35fe6 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite.yaml @@ -0,0 +1,23 @@ +identifier: m5stack_atoms3_lite +name: M5Stack AtomS3-Lite +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - uart + - i2c + - spi + - counter + - watchdog + - entropy + - pwm + - pinmux + - nvs + - dma +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig new file mode 100644 index 00000000000..18468290e06 --- /dev/null +++ b/boards/xtensa/m5stack_atoms3_lite/m5stack_atoms3_lite_defconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_ATOMS3_LITE=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_GPIO=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/m5stack_core2/Kconfig.defconfig b/boards/xtensa/m5stack_core2/Kconfig.defconfig index 08fc712b0d3..15dfc61483a 100644 --- a/boards/xtensa/m5stack_core2/Kconfig.defconfig +++ b/boards/xtensa/m5stack_core2/Kconfig.defconfig @@ -12,8 +12,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 65536 if BT default 4096 @@ -39,4 +41,13 @@ config INPUT config LV_COLOR_16_SWAP default y if LVGL +# Increase initialization priority of MIPI DBI device, so that it initializes +# after the GPIO controller +if MIPI_DBI + +config MIPI_DBI_INIT_PRIORITY + default 82 + +endif # MIPI_DBI + endif # BOARD_M5STACK_CORE2 diff --git a/boards/xtensa/m5stack_core2/doc/index.rst b/boards/xtensa/m5stack_core2/doc/index.rst index 4ca27c546f5..11fd9b9826e 100644 --- a/boards/xtensa/m5stack_core2/doc/index.rst +++ b/boards/xtensa/m5stack_core2/doc/index.rst @@ -50,37 +50,39 @@ of the M5Stack Core2 board. .. _PMU-AXP192: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/AXP192_datasheet_en.pdf .. _VIB-1072_RFN01: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/1027RFN01-33d.pdf -+------------------+--------------------------------------------------------------------------+ -| Key Component | Description | -+==================+==========================================================================+ -|| ESP32-D0WDQ6-V2 || This `MPU-ESP32`_ module provides complete Wi-Fi and Bluetooth | -|| module || functionalities and integrates a 16-MB SPI flash. | -+------------------+--------------------------------------------------------------------------+ -|| 32.768 kHz RTC || External precision 32.768 kHz crystal oscillator serves as a clock with | -|| || low-power consumption while the chip is in Deep-sleep mode. | -+------------------+--------------------------------------------------------------------------+ -| Status LED | One user LED connected to the GPIO pin. | -+------------------+--------------------------------------------------------------------------+ -|| USB Port || USB interface. Power supply for the board as well as the | -|| || communication interface between a computer and the board. | -|| || Contains: TypeC x 1, GROVE(I2C+I/O+UART) x 1 | -+------------------+--------------------------------------------------------------------------+ -| Reset button | Reset button | -+------------------+--------------------------------------------------------------------------+ -| Power Switch | Power on/off button. | -+------------------+--------------------------------------------------------------------------+ -|| LCD screen || Built-in LCD TFT display \(`LCD-ILI9342C`_, 2", 320x240 px\) | -|| || controlled via SPI interface | -+------------------+--------------------------------------------------------------------------+ -|| 6-axis IMU || The `MPU-6886`_ is a 6-axis motion tracker (6DOF IMU) device that | -|| MPU6886 || combines a 3-axis gyroscope and a 3-axis accelerometer. | -|| || For details please refer to :ref:`m5stack_core2_ext` | -+------------------+--------------------------------------------------------------------------+ -|| Built-in || The `SPM-1423`_ I2S driven microphone. | -|| microphone || | -+------------------+--------------------------------------------------------------------------+ -| Built-in speaker | 1W speaker for audio output via I2S interface. | -+------------------+--------------------------------------------------------------------------+ ++------------------+--------------------------------------------------------------------------+------------+ +| Key Component | Description | Status | ++==================+==========================================================================+============+ +|| ESP32-D0WDQ6-V2 || This `MPU-ESP32`_ module provides complete Wi-Fi and Bluetooth || supported | +|| module || functionalities and integrates a 16-MB SPI flash. || | ++------------------+--------------------------------------------------------------------------+------------+ +|| 32.768 kHz RTC || External precision 32.768 kHz crystal oscillator serves as a clock with || supported | +|| || low-power consumption while the chip is in Deep-sleep mode. || | ++------------------+--------------------------------------------------------------------------+------------+ +| Status LED | One user LED connected to the GPIO pin. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| USB Port || USB interface. Power supply for the board as well as the || supported | +|| || communication interface between a computer and the board. || | +|| || Contains: TypeC x 1, GROVE(I2C+I/O+UART) x 1 || | ++------------------+--------------------------------------------------------------------------+------------+ +| Reset button | Reset button | supported | ++------------------+--------------------------------------------------------------------------+------------+ +| Power Switch | Power on/off button. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| LCD screen || Built-in LCD TFT display \(`LCD-ILI9342C`_, 2", 320x240 px\) || supported | +|| || controlled via SPI interface || | ++------------------+--------------------------------------------------------------------------+------------+ +| SD-Card slot | SD-Card connection via SPI-mode. | supported | ++------------------+--------------------------------------------------------------------------+------------+ +|| 6-axis IMU || The `MPU-6886`_ is a 6-axis motion tracker (6DOF IMU) device that || todo | +|| MPU6886 || combines a 3-axis gyroscope and a 3-axis accelerometer. || | +|| || For details please refer to :ref:`m5stack_core2_ext` || | ++------------------+--------------------------------------------------------------------------+------------+ +|| Built-in || The `SPM-1423`_ I2S driven microphone. || todo | +|| microphone || || | ++------------------+--------------------------------------------------------------------------+------------+ +| Built-in speaker | 1W speaker for audio output via I2S interface. | todo | ++------------------+--------------------------------------------------------------------------+------------+ Supported Features ================== diff --git a/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi b/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi index ac0908ac62a..05db025471f 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi +++ b/boards/xtensa/m5stack_core2/m5stack_core2-pinctrl.dtsi @@ -39,8 +39,7 @@ spim3_default: spim3_default { group1 { pinmux = , - , - ; + ; }; group2 { pinmux = ; @@ -48,18 +47,6 @@ }; }; - spim2_default: spim2_default { - group1 { - pinmux = , - , - ; - }; - group2 { - pinmux = ; - output-low; - }; - }; - i2c0_default: i2c0_default { group1 { pinmux = , diff --git a/boards/xtensa/m5stack_core2/m5stack_core2.dts b/boards/xtensa/m5stack_core2/m5stack_core2.dts index 41ccb5be074..c8c56b75ff9 100644 --- a/boards/xtensa/m5stack_core2/m5stack_core2.dts +++ b/boards/xtensa/m5stack_core2/m5stack_core2.dts @@ -46,6 +46,29 @@ lvgl_pointer { compatible = "zephyr,lvgl-pointer-input"; input = <&ft5336_touch>; + swap-xy; + }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_HIGH)>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9342c: ili9342c@0 { + compatible = "ilitek,ili9342c"; + mipi-max-frequency = <30000000>; + reg = <0>; + vin-supply = <&lcd_bg>; + pixel-format = ; + display-inversion; + width = <320>; + height = <240>; + rotation = <0>; + }; }; }; @@ -182,20 +205,19 @@ pinctrl-names = "default"; dma-enabled; clock-frequency = <20000000>; - cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; - - ili9342c: ili9342c@0 { - compatible = "ilitek,ili9342c"; - spi-max-frequency = <30000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 15 GPIO_ACTIVE_LOW>; - vin-supply = <&lcd_bg>; - reset-gpios = <&axp192_gpio 4 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; - pixel-format = ; - display-inversion; - width = <320>; - height = <240>; - rotation = <0>; + cs-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>; + + sdhc0: sdhc@1 { + compatible = "zephyr,sdhc-spi-slot"; + reg = <1>; + status = "okay"; + spi-max-frequency = <20000000>; + mmc { + compatible = "zephyr,sdmmc-disk"; + status = "okay"; + }; + }; }; diff --git a/boards/xtensa/m5stack_stamps3/Kconfig.board b/boards/xtensa/m5stack_stamps3/Kconfig.board new file mode 100644 index 00000000000..1f22500830e --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/Kconfig.board @@ -0,0 +1,12 @@ +# M5Stack StampS3 board configuration + +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_M5STACK_STAMPS3 + bool "M5Stack StampS3 Development Board" + depends on SOC_SERIES_ESP32S3 + +choice SOC_PART_NUMBER + default SOC_ESP32S3_FN8 +endchoice diff --git a/boards/xtensa/m5stack_stamps3/Kconfig.defconfig b/boards/xtensa/m5stack_stamps3/Kconfig.defconfig new file mode 100644 index 00000000000..f451db3e231 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/Kconfig.defconfig @@ -0,0 +1,27 @@ +# M5Stack StampS3 board configuration +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_M5STACK_STAMPS3 + +config BOARD + default "m5stack_stamps3" + depends on BOARD_M5STACK_STAMPS3 + +config ENTROPY_GENERATOR + default y + +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 98304 if WIFI + default 65536 if BT + default 4096 + +config KERNEL_MEM_POOL + default y + +choice BT_HCI_BUS_TYPE + default BT_ESP32 if BT +endchoice + +endif # BOARD_M5STACK_STAMPS3 diff --git a/boards/xtensa/m5stack_stamps3/board.cmake b/boards/xtensa/m5stack_stamps3/board.cmake new file mode 100644 index 00000000000..2f04d1fe886 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/board.cmake @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*") + set(OPENOCD OPENOCD-NOTFOUND) +endif() +find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH) + +include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake) +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) diff --git a/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp b/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp new file mode 100644 index 00000000000..3d24c0322e3 Binary files /dev/null and b/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3.webp differ diff --git a/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3_header.webp b/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3_header.webp new file mode 100644 index 00000000000..ae0d629f738 Binary files /dev/null and b/boards/xtensa/m5stack_stamps3/doc/img/m5stack_stamps3_header.webp differ diff --git a/boards/xtensa/m5stack_stamps3/doc/index.rst b/boards/xtensa/m5stack_stamps3/doc/index.rst new file mode 100644 index 00000000000..75c660de803 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/doc/index.rst @@ -0,0 +1,199 @@ +.. _m5stack_stamps3: + +M5Stack StampS3 +############### + +Overview +******** + +M5Stack StampS3 is an ESP32-based development board from M5Stack. +It features the following integrated components: + +- ESP32-S3FN8 chip (240MHz dual core) +- 512KB SRAM +- 384KB ROM +- 8MB Flash +- Wi-Fi +- Bluetooth +- User-Button + +.. figure:: img/m5stack_stamps3.webp + :align: center + :alt: M5Stack StampS3 + :width: 400 px + + M5Stack StampS3 module + +Functional Description +********************** + +The following table below describes the key components, interfaces, and controls +of the M5Stack StampS3 module. + ++---------------+-----------------------------------------------------------------+-----------+ +| Key Component | Description | Status | ++===============+=================================================================+===========+ +| ESP32-S3FN8 | This MPU-ESP32S3 module provides complete Wi-Fi and Bluetooth | supported | +| module | functionalities and integrates a 8MB flash. | | ++---------------+-----------------------------------------------------------------+-----------+ +| Status LED | One user LED connected via :dtcompatible:`worldsemi,ws2812-spi` | supported | +| | interface (``led-strip``). | | ++---------------+-----------------------------------------------------------------+-----------+ +| USB Port | USB interface. Power supply for the board as well as the | supported | +| | communication interface between a computer and the board. | | ++---------------+-----------------------------------------------------------------+-----------+ +| User button | User button (``sw0``) | supported | ++---------------+-----------------------------------------------------------------+-----------+ + +Main connector header +===================== + +The Zephyr m5stack_stamps3 board can be used on various applications. It +therefore publishes a header definition to be used in different shields: +:dtcompatible:`m5stack,stamps3-header`. + +.. figure:: img/m5stack_stamps3_header.webp + :align: center + :alt: M5Stack StampS3 Header + :width: 400 px + + M5Stack StampS3 connector header + +Following interfaces are being exported for this header: + +- ``m5stack_stamps3_clkout0``: PWM output with 2 channels (0 and 2). +- ``m5stack_stamps3_spilcd``: SPI interface for interfacing LCDs. Consists of a + CLK, MOSI and CS signal. +- ``m5stack_stamps3_i2c0`` and ``m5stack_stamps3_i2c1``: I2C interfaces (SDA, SCL). +- ``m5stack_stamps3_uart0``: UART interface (RXD, TXD). +- ``m5stack_stamps3_header``: All GPIOs are of course accessible via main header + definition. + ++-----+-----------------------------------------+-----+---------------------------------+ +| Pin | Functions | Pin | Functions | ++=====+=========================================+=====+=================================+ +| 1 | | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 2 | | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 3 | ``m5stack_stamps3_clkout0`` - Channel 0 | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 4 | | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 5 | ``m5stack_stamps3_spilcd`` - MOSI | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 6 | ``m5stack_stamps3_spilcd`` - CLK | | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 7 | ``m5stack_stamps3_spilcd`` - CS | 28 | **3V3** | ++-----+-----------------------------------------+-----+---------------------------------+ +| 8 | | 27 | ``m5stack_stamps3_uart0`` - TXD | ++-----+-----------------------------------------+-----+---------------------------------+ +| 9 | ``m5stack_stamps3_clkout0`` - Channel 2 | 26 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 10 | | 25 | ``m5stack_stamps3_uart0`` - RXD | ++-----+-----------------------------------------+-----+---------------------------------+ +| 11 | **GND** | 24 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 12 | ``m5stack_stamps3_i2c1`` - SDA | 23 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 13 | **5V** | 22 | **EN** | ++-----+-----------------------------------------+-----+---------------------------------+ +| 14 | ``m5stack_stamps3_i2c1`` - SCL | 21 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 15 | ``m5stack_stamps3_i2c0`` - SDA | 20 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 16 | | 19 | | ++-----+-----------------------------------------+-----+---------------------------------+ +| 17 | ``m5stack_stamps3_i2c0`` - SCL | 18 | **GND** | ++-----+-----------------------------------------+-----+---------------------------------+ + +Power supply +============ + +M5Stack StampS3 requires a single 5V input power supply. The module internally +features a DCDC (MUN3CAD01-SC) to generate the 3.3V needed for the MCU. + +The **EN** signal (Pin 22) is an active low signal to enable the **3V3** power +supply. If this pin is pulled low this main 3.3V power supply for the MCU will be +deactivated. It is internally equipped with a pull-up and can hence be left open +if unused. + +Start Application Development +***************************** + +Before powering up your M5Stack StampS3, please make sure that the board is in good +condition with no obvious signs of damage. + +System requirements +=================== + +Prerequisites +------------- + +Espressif HAL requires WiFi and Bluetooth binary blobs in order work. Run the command +below to retrieve those files. + +.. code-block:: console + + west blobs fetch hal_espressif + +.. note:: + + It is recommended running the command above after :file:`west update`. + +Building & Flashing +------------------- + +Build and flash applications as usual (see :ref:`build_an_application` and +:ref:`application_run` for more details). + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_stamps3 + :goals: build + +The usual ``flash`` target will work with the ``m5stack_stamps3`` board +configuration. Here is an example for the :ref:`hello_world` +application. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: m5stack_stamps3 + :goals: flash + +The baud rate of 921600bps is set by default. If experiencing issues when flashing, +try using different values by using ``--esp-baud-rate `` option during +``west flash`` (e.g. ``west flash --esp-baud-rate 115200``). + +You can also open the serial monitor using the following command: + +.. code-block:: shell + + west espressif monitor + +After the board has automatically reset and booted, you should see the following +message in the monitor: + +.. code-block:: console + + ***** Booting Zephyr OS vx.x.x-xxx-gxxxxxxxxxxxx ***** + Hello World! m5stack_stamps3 + +Debugging +--------- + +M5Stack StampS3 exports a JTAG-interface via Pins 19 (MTCK), 21 (MTDO), 23 +(MTDI), 25 (MTMS). + +.. note:: + + Please note that additional JTAG equipment is needed to utilize JTAG. Refer to + the ESP32S3 datasheet and the M5Stack StampS3 documentation for details. + +Related Documents +***************** + +- `M5Stack StampS3 schematic `_ +- `M5Stack StampS3 `_ +- `ESP32 Datasheet `_ (PDF) +- `ESP32 Hardware Reference `_ diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi b/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi new file mode 100644 index 00000000000..c10190db129 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3-pinctrl.dtsi @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + #include + #include + +&pinctrl { + uart0_default: uart0_default { + group1 { + pinmux = ; + output-high; + }; + group2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c0_default: i2c0_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + i2c1_default: i2c1_default { + group1 { + pinmux = , + ; + bias-pull-up; + drive-open-drain; + output-high; + }; + }; + + spim2_default: spim2_default { + group1 { + pinmux = , + ; + }; + group2 { + pinmux = ; + output-low; + }; + + }; + + spim3_default: spim3_default { + group1 { + pinmux = ; + output-low; + }; + + }; + + ledc0_default: ledc0_default { + group1 { + pinmux = ; /* lcd backlight */ + output-enable; + }; + group2 { + pinmux = ; /* beeper */ + output-enable; + }; + }; + + mcpwm0_default: mcpwm0_default { + group1 { + pinmux = ; /* lcd backlight */ + output-enable; + }; + group2 { + pinmux = ; + output-enable; + }; + }; +}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts new file mode 100644 index 00000000000..b4087e31bd9 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.dts @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +/dts-v1/; + +#include +#include "m5stack_stamps3-pinctrl.dtsi" +#include "m5stack_stamps3_connectors.dtsi" +#include +#include +#include +#include + +/ { + model = "M5Stack StampS3"; + compatible = "m5stack,stamps3"; + + chosen { + zephyr,sram = &sram0; + zephyr,console = &usb_serial; + zephyr,shell-uart = &usb_serial; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + sw0 = &user_button_0; + watchdog0 = &wdt0; + //pwm-0 = &ledc0; + i2c-0 = &i2c0; + led-strip = &status_rgb_led; + }; + + gpio_keys { + compatible = "gpio-keys"; + + /* This is the button that's underneath the LCD display */ + user_button_0: button_0 { + label = "User button 0"; + gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + zephyr,code = ; + }; + }; +}; + +&cpu0 { + clock-frequency = ; +}; + +&cpu1 { + clock-frequency = ; +}; + +&usb_serial { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; +}; + +&i2c1 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; +}; + +&trng0 { + status = "okay"; +}; + +&mcpwm0 { + status = "okay"; + pinctrl-0 = <&mcpwm0_default>; + pinctrl-names = "default"; + prescale = <255>; + prescale-timer0 = <100>; + prescale-timer1 = <100>; +}; + +&ledc0 { + pinctrl-0 = <&ledc0_default>; + pinctrl-names = "default"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + channel0@0 { + reg = <0x0>; + timer = <0>; + }; + channel0@1 { + reg = <0x1>; + timer = <0>; + }; +}; + + +&spi2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pinctrl-0 = <&spim2_default>; + pinctrl-names = "default"; +}; + +&spi3 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + line-idle-low; + pinctrl-0 = <&spim3_default>; + pinctrl-names = "default"; + + status_rgb_led: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + reg = <0x0>; + spi-max-frequency = ; + + chain-length = <1>; + color-mapping = , + , + ; + spi-one-frame = ; + spi-zero-frame = ; + reset-delay = <250>; + }; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&flash0 { + status = "okay"; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000F000>; + read-only; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00100000>; + }; + + slot1_partition: partition@110000 { + label = "image-1"; + reg = <0x00110000 0x00100000>; + }; + + scratch_partition: partition@210000 { + label = "image-scratch"; + reg = <0x00210000 0x00040000>; + }; + + storage_partition: partition@250000 { + label = "storage"; + reg = <0x00250000 0x00006000>; + }; + }; +}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml new file mode 100644 index 00000000000..f5275cabe05 --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3.yaml @@ -0,0 +1,20 @@ +identifier: m5stack_stamps3 +name: M5Stack StampS3 +type: mcu +arch: xtensa +toolchain: + - zephyr +supported: + - gpio + - i2c + - spi + - watchdog + - uart + - pwm + - pinmux + - nvs +testing: + ignore_tags: + - net + - bluetooth +vendor: m5stack diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi new file mode 100644 index 00000000000..393b741440a --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_connectors.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + m5stack_stamps3_header: m5stack_stamps3_header { + compatible = "m5stack,stamps3-header"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map = + <0 0 &gpio0 1 0>, /* GPIO/AIN */ + <1 0 &gpio0 2 0>, /* GPIO/AIN */ + <2 0 &gpio0 3 0>, /* GPIO/AIN/CLKOUT1-3 */ + <3 0 &gpio0 4 0>, /* GPIO/AIN */ + <4 0 &gpio0 5 0>, /* GPIO/AIN/SPI2-MOSI */ + <5 0 &gpio0 6 0>, /* GPIO/AIN/SPI2-CLK */ + <6 0 &gpio0 7 0>, /* GPIO/AIN/SPI2-CS */ + <7 0 &gpio0 8 0>, /* GPIO/AIN */ + <8 0 &gpio0 9 0>, /* GPIO/AIN/CLKOUT1-4 */ + <9 0 &gpio0 10 0>, /* GPIO/AIN */ + /* 10 GND */ + <11 0 &gpio0 11 0>, /* GPIO/AIN/SDA1 */ + /* 11 5V */ + <12 0 &gpio0 12 0>, /* GPIO/AIN/SCL1 */ + <14 0 &gpio0 13 0>, /* GPIO/AIN/SDA0 */ + <15 0 &gpio0 14 0>, /* GPIO/AIN */ + <16 0 &gpio0 15 0>, /* GPIO/AIN/SCL0 */ + /* 17 GND */ + <18 0 &gpio1 7 0>, /* GPIO/CLKOUT0-0 */ + <19 0 &gpio0 0 0>, /* GPIO */ + <20 0 &gpio1 8 0>, /* GPIO/CLKOUT0-1 */ + /* 21 EN */ + <22 0 &gpio1 9 0>, /* GPIO/CLKOUT1-0 */ + <23 0 &gpio1 12 0>, /* GPIO/CLKOUT1-1/RXD0 */ + <24 0 &gpio1 10 0>, /* GPIO */ + <25 0 &gpio1 11 0>, /* GPIO/CLKOUT1.2/TXD0 */ + <26 0 &gpio1 14 0>; /* GPIO */ + /* 27 3V3 */ + }; +}; + +m5stack_stamps3_uart0: &uart0 {}; +m5stack_stamps3_i2c0: &i2c0 {}; +m5stack_stamps3_i2c1: &i2c1 {}; +m5stack_stamps3_clkout0: &mcpwm0 {}; +m5stack_stamps3_spilcd: &spi2 {}; diff --git a/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig new file mode 100644 index 00000000000..34f489623bc --- /dev/null +++ b/boards/xtensa/m5stack_stamps3/m5stack_stamps3_defconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_M5STACK_STAMPS3=y +CONFIG_SOC_SERIES_ESP32S3=y + +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_GPIO=y + +CONFIG_CONSOLE=y +CONFIG_PWM=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_CLOCK_CONTROL=y diff --git a/boards/xtensa/m5stickc_plus/Kconfig.defconfig b/boards/xtensa/m5stickc_plus/Kconfig.defconfig index 2fdc31f4008..a9e73202781 100644 --- a/boards/xtensa/m5stickc_plus/Kconfig.defconfig +++ b/boards/xtensa/m5stickc_plus/Kconfig.defconfig @@ -10,8 +10,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts index 8cdd4170ba5..6737973adae 100644 --- a/boards/xtensa/m5stickc_plus/m5stickc_plus.dts +++ b/boards/xtensa/m5stickc_plus/m5stickc_plus.dts @@ -27,6 +27,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; leds { diff --git a/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board new file mode 100644 index 00000000000..d9a1ff65953 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.board @@ -0,0 +1,7 @@ +# Xtensa board configuration + +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_NXP_ADSP_IMX8ULP + bool "NXP ADSP i.MX8ULP" diff --git a/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig new file mode 100644 index 00000000000..431515d5961 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NXP_ADSP_IMX8ULP + +config BOARD + default "nxp_adsp_imx8ulp" + +endif # BOARD_NXP_ADSP_IMX8ULP diff --git a/boards/xtensa/nxp_adsp_imx8ulp/board.cmake b/boards/xtensa/nxp_adsp_imx8ulp/board.cmake new file mode 100644 index 00000000000..e05fbc891e5 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +board_set_flasher_ifnset(misc-flasher) +board_finalize_runner_args(misc-flasher) + +board_set_rimage_target(imx8ulp) diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts new file mode 100644 index 00000000000..d584097cb03 --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.dts @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "nxp_adsp_imx8ulp"; + compatible = "nxp"; + + chosen { + zephyr,sram = &sram0; + }; +}; diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml new file mode 100644 index 00000000000..e71105631da --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp.yaml @@ -0,0 +1,10 @@ +identifier: nxp_adsp_imx8ulp +name: i.MX8ULP DSP +type: mcu +arch: xtensa +toolchain: + - zephyr +testing: + only_tags: + - kernel + - sof diff --git a/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig new file mode 100644 index 00000000000..cc1911c615c --- /dev/null +++ b/boards/xtensa/nxp_adsp_imx8ulp/nxp_adsp_imx8ulp_defconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SOC_SERIES_NXP_IMX8ULP=y +CONFIG_SOC_NXP_IMX8ULP=y +CONFIG_BOARD_NXP_ADSP_IMX8ULP=y + +CONFIG_BUILD_OUTPUT_BIN=n + +CONFIG_DYNAMIC_INTERRUPTS=y + +CONFIG_LOG=y diff --git a/boards/xtensa/odroid_go/Kconfig.defconfig b/boards/xtensa/odroid_go/Kconfig.defconfig index 7193624673e..1827d83a041 100644 --- a/boards/xtensa/odroid_go/Kconfig.defconfig +++ b/boards/xtensa/odroid_go/Kconfig.defconfig @@ -16,8 +16,10 @@ config SPI config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/odroid_go/odroid_go.dts b/boards/xtensa/odroid_go/odroid_go.dts index 0a868adc2a3..31ceee79d3c 100644 --- a/boards/xtensa/odroid_go/odroid_go.dts +++ b/boards/xtensa/odroid_go/odroid_go.dts @@ -18,6 +18,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; zephyr,display = &ili9341; }; @@ -76,6 +77,25 @@ sw0 = &menu_button; watchdog0 = &wdt0; }; + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + dc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + spi-dev = <&spi3>; + write-only; + #address-cells = <1>; + #size-cells = <0>; + + ili9341: ili9341@0 { + compatible = "ilitek,ili9341"; + mipi-max-frequency = <25000000>; + pixel-format = <0>; + reg = <0>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; }; &cpu0 { @@ -123,17 +143,6 @@ pinctrl-0 = <&spim3_default>; pinctrl-names = "default"; - ili9341: ili9341@0 { - compatible = "ilitek,ili9341"; - spi-max-frequency = <25000000>; - reg = <0>; - cmd-data-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; - pixel-format = <0>; - rotation = <270>; - width = <320>; - height = <240>; - }; - sdhc0: sdhc@1 { compatible = "zephyr,sdhc-spi-slot"; reg = <1>; diff --git a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig index 8e788f6a393..6aca00ecad5 100644 --- a/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig +++ b/boards/xtensa/olimex_esp32_evb/Kconfig.defconfig @@ -11,8 +11,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts index 0abf7d7128e..11747f1a7b6 100644 --- a/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts +++ b/boards/xtensa/olimex_esp32_evb/olimex_esp32_evb.dts @@ -19,6 +19,7 @@ zephyr,shell-uart = &uart0; zephyr,sram = &sram0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig index 4a1b168cf54..3bc3e999189 100644 --- a/boards/xtensa/xiao_esp32s3/Kconfig.defconfig +++ b/boards/xtensa/xiao_esp32s3/Kconfig.defconfig @@ -8,8 +8,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts index ecd7814bb6b..a4592b26bce 100644 --- a/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts +++ b/boards/xtensa/xiao_esp32s3/xiao_esp32s3.dts @@ -19,6 +19,7 @@ zephyr,console = &usb_serial; zephyr,shell-uart = &usb_serial; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; aliases { diff --git a/boards/xtensa/xt-sim/xt-sim_defconfig b/boards/xtensa/xt-sim/xt-sim_defconfig index ae3d7a6cd91..73700f07275 100644 --- a/boards/xtensa/xt-sim/xt-sim_defconfig +++ b/boards/xtensa/xt-sim/xt-sim_defconfig @@ -8,3 +8,5 @@ CONFIG_CONSOLE=y CONFIG_GEN_ISR_TABLES=y CONFIG_GEN_IRQ_VECTOR_TABLE=n CONFIG_SIMULATOR_XTENSA=y + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=2000000 diff --git a/boards/xtensa/yd_esp32/Kconfig.defconfig b/boards/xtensa/yd_esp32/Kconfig.defconfig index ebb60766eb9..4807671ca79 100644 --- a/boards/xtensa/yd_esp32/Kconfig.defconfig +++ b/boards/xtensa/yd_esp32/Kconfig.defconfig @@ -10,8 +10,10 @@ config BOARD config ENTROPY_GENERATOR default y -config HEAP_MEM_POOL_SIZE - default 98304 if WIFI +config HEAP_MEM_POOL_ADD_SIZE_BOARD + int + default 65535 if WIFI && BT + default 51200 if WIFI default 40960 if BT default 4096 diff --git a/boards/xtensa/yd_esp32/yd_esp32.dts b/boards/xtensa/yd_esp32/yd_esp32.dts index 3995788beb2..9442e5009e4 100644 --- a/boards/xtensa/yd_esp32/yd_esp32.dts +++ b/boards/xtensa/yd_esp32/yd_esp32.dts @@ -34,6 +34,7 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; diff --git a/cmake/bintools/gnu/target.cmake b/cmake/bintools/gnu/target.cmake index 86c66b4825c..612f6de79b2 100644 --- a/cmake/bintools/gnu/target.cmake +++ b/cmake/bintools/gnu/target.cmake @@ -5,8 +5,13 @@ find_program(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_OBJDUMP ${CROSS_COMPILE}objdump PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_AS ${CROSS_COMPILE}as PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) -find_program(CMAKE_AR ${CROSS_COMPILE}ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) -find_program(CMAKE_RANLIB ${CROSS_COMPILE}ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +if(CONFIG_LTO) + find_program(CMAKE_AR ${CROSS_COMPILE}gcc-ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + find_program(CMAKE_RANLIB ${CROSS_COMPILE}gcc-ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +else() + find_program(CMAKE_AR ${CROSS_COMPILE}ar PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + find_program(CMAKE_RANLIB ${CROSS_COMPILE}ranlib PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) +endif() find_program(CMAKE_READELF ${CROSS_COMPILE}readelf PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_NM ${CROSS_COMPILE}nm PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) find_program(CMAKE_STRIP ${CROSS_COMPILE}strip PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) diff --git a/cmake/bintools/gnu/target_bintools.cmake b/cmake/bintools/gnu/target_bintools.cmake index e8cb6e181d5..8aac55b0400 100644 --- a/cmake/bintools/gnu/target_bintools.cmake +++ b/cmake/bintools/gnu/target_bintools.cmake @@ -93,6 +93,7 @@ set_property(TARGET bintools PROPERTY strip_flag_final "") set_property(TARGET bintools PROPERTY strip_flag_all --strip-all) set_property(TARGET bintools PROPERTY strip_flag_debug --strip-debug) set_property(TARGET bintools PROPERTY strip_flag_dwo --strip-dwo) +set_property(TARGET bintools PROPERTY strip_flag_remove_section -R ) set_property(TARGET bintools PROPERTY strip_flag_infile "") set_property(TARGET bintools PROPERTY strip_flag_outfile -o ) diff --git a/cmake/bintools/llvm/target.cmake b/cmake/bintools/llvm/target.cmake index 447d2adf555..9489491968f 100644 --- a/cmake/bintools/llvm/target.cmake +++ b/cmake/bintools/llvm/target.cmake @@ -26,7 +26,11 @@ find_program(CMAKE_OBJCOPY NAMES llvm-objcopy-${CLANGVER} objcopy ${find_program_binutils_args}) -find_program(CMAKE_READELF readelf ${find_program_binutils_args}) +find_program(CMAKE_READELF NAMES + llvm-readelf + llvm-readelf-${CLANGVER} + readelf + ${find_program_binutils_args}) # Use the gnu binutil abstraction include(${ZEPHYR_BASE}/cmake/bintools/llvm/target_bintools.cmake) diff --git a/cmake/compiler/arcmwdt/compiler_flags.cmake b/cmake/compiler/arcmwdt/compiler_flags.cmake index 7ab83ba507d..5383016795b 100644 --- a/cmake/compiler/arcmwdt/compiler_flags.cmake +++ b/cmake/compiler/arcmwdt/compiler_flags.cmake @@ -33,6 +33,9 @@ set_compiler_property(PROPERTY warning_base -Wno-typedef-redefinition ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 diff --git a/cmake/compiler/arcmwdt/generic.cmake b/cmake/compiler/arcmwdt/generic.cmake index c7ab586b3f3..d28ad81ea04 100644 --- a/cmake/compiler/arcmwdt/generic.cmake +++ b/cmake/compiler/arcmwdt/generic.cmake @@ -17,12 +17,12 @@ execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret OUTPUT_VARIABLE full_version_output - ERROR_QUIET ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? - '${CMAKE_C_COMPILER} --version'" + '${CMAKE_C_COMPILER} --version' + ${full_version_output}" ) else() set(ARCMWDT_MIN_REQUIRED_VERS "2022.09") diff --git a/cmake/compiler/armclang/generic.cmake b/cmake/compiler/armclang/generic.cmake index 7804cd0e640..0f12abce247 100644 --- a/cmake/compiler/armclang/generic.cmake +++ b/cmake/compiler/armclang/generic.cmake @@ -28,13 +28,13 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. " "Are permissions set correctly? '${CMAKE_C_COMPILER} --version' " + "${stdoutput}" "And is the license setup correctly ?" ) endif() diff --git a/cmake/compiler/clang/compiler_flags.cmake b/cmake/compiler/clang/compiler_flags.cmake index 3658161123b..e0448d0720e 100644 --- a/cmake/compiler/clang/compiler_flags.cmake +++ b/cmake/compiler/clang/compiler_flags.cmake @@ -45,6 +45,9 @@ check_set_compiler_property(PROPERTY warning_base -Wno-deprecated-non-prototype ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index 5b1dbde49c6..5867392c307 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -21,6 +21,9 @@ endif() set_compiler_property(PROPERTY optimization_speed -O2) set_compiler_property(PROPERTY optimization_size -Os) +set_compiler_property(PROPERTY optimization_lto -flto) +set_compiler_property(PROPERTY prohibit_lto -fno-lto) + ####################################################### # This section covers flags related to warning levels # ####################################################### @@ -32,6 +35,9 @@ check_set_compiler_property(PROPERTY warning_base "SHELL:-Wformat -Wno-format-zero-length" ) +# C implicit promotion rules will want to make floats into doubles very easily +check_set_compiler_property(APPEND PROPERTY warning_base -Wdouble-promotion) + check_set_compiler_property(APPEND PROPERTY warning_base -Wno-pointer-sign) # Prohibit void pointer arithmetic. Illegal in C99 @@ -169,9 +175,11 @@ endif() if(NOT CONFIG_NO_OPTIMIZATIONS) # _FORTIFY_SOURCE: Detect common-case buffer overflows for certain functions - # _FORTIFY_SOURCE=1 : Compile-time checks (requires -O1 at least) - # _FORTIFY_SOURCE=2 : Additional lightweight run-time checks - set_compiler_property(PROPERTY security_fortify_compile_time _FORTIFY_SOURCE=1) + # _FORTIFY_SOURCE=1 : Loose checking (use wide bounds checks) + # _FORTIFY_SOURCE=2 : Tight checking (use narrow bounds checks) + # GCC always does compile-time bounds checking for string/mem functions, so + # there's no additional value to set here + set_compiler_property(PROPERTY security_fortify_compile_time) set_compiler_property(PROPERTY security_fortify_run_time _FORTIFY_SOURCE=2) endif() diff --git a/cmake/compiler/gcc/generic.cmake b/cmake/compiler/gcc/generic.cmake index ca96eb93809..c9cc643e3dd 100644 --- a/cmake/compiler/gcc/generic.cmake +++ b/cmake/compiler/gcc/generic.cmake @@ -18,12 +18,12 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? -'${CMAKE_C_COMPILER} --version' + ${CMAKE_C_COMPILER} --version + ${stdoutput} " ) endif() diff --git a/cmake/compiler/gcc/target.cmake b/cmake/compiler/gcc/target.cmake index 86807bd8a4f..5b1e5db1218 100644 --- a/cmake/compiler/gcc/target.cmake +++ b/cmake/compiler/gcc/target.cmake @@ -76,6 +76,8 @@ elseif("${ARCH}" STREQUAL "sparc") include(${CMAKE_CURRENT_LIST_DIR}/target_sparc.cmake) elseif("${ARCH}" STREQUAL "mips") include(${CMAKE_CURRENT_LIST_DIR}/target_mips.cmake) +elseif("${ARCH}" STREQUAL "xtensa") + include(${CMAKE_CURRENT_LIST_DIR}/target_xtensa.cmake) endif() if(SYSROOT_DIR) diff --git a/cmake/compiler/gcc/target_arm.cmake b/cmake/compiler/gcc/target_arm.cmake index a813c2563a3..6659c7bf417 100644 --- a/cmake/compiler/gcc/target_arm.cmake +++ b/cmake/compiler/gcc/target_arm.cmake @@ -41,3 +41,22 @@ endif() list(APPEND TOOLCHAIN_C_FLAGS ${ARM_C_FLAGS}) list(APPEND TOOLCHAIN_LD_FLAGS NO_SPLIT ${ARM_C_FLAGS}) + +# Flags not supported by llext linker +# (regexps are supported and match whole word) +set(LLEXT_REMOVE_FLAGS + -fno-pic + -fno-pie + -ffunction-sections + -fdata-sections + -g.* + -Os + -mcpu=.* +) + +# Flags to be added to llext code compilation +set(LLEXT_APPEND_FLAGS + -mlong-calls + -mthumb + -mcpu=cortex-m33+nodsp +) diff --git a/cmake/compiler/gcc/target_xtensa.cmake b/cmake/compiler/gcc/target_xtensa.cmake new file mode 100644 index 00000000000..177830427db --- /dev/null +++ b/cmake/compiler/gcc/target_xtensa.cmake @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 + +# Flags not supported by llext linker +# (regexps are supported and match whole word) +set(LLEXT_REMOVE_FLAGS + -fno-pic + -fno-pie + -ffunction-sections + -fdata-sections + -g.* + -Os + -mcpu=.* +) + +# Flags to be added to llext code compilation +set(LLEXT_APPEND_FLAGS + -fPIC + -nostdlib + -nodefaultlibs + -shared +) diff --git a/cmake/compiler/xcc/generic.cmake b/cmake/compiler/xcc/generic.cmake index ca96eb93809..c9cc643e3dd 100644 --- a/cmake/compiler/xcc/generic.cmake +++ b/cmake/compiler/xcc/generic.cmake @@ -18,12 +18,12 @@ endif() execute_process( COMMAND ${CMAKE_C_COMPILER} --version RESULT_VARIABLE ret - OUTPUT_QUIET - ERROR_QUIET + OUTPUT_VARIABLE stdoutput ) if(ret) message(FATAL_ERROR "Executing the below command failed. Are permissions set correctly? -'${CMAKE_C_COMPILER} --version' + ${CMAKE_C_COMPILER} --version + ${stdoutput} " ) endif() diff --git a/cmake/hex.cmake b/cmake/hex.cmake index 5823dc9109b..f5eb586f7bd 100644 --- a/cmake/hex.cmake +++ b/cmake/hex.cmake @@ -1,5 +1,9 @@ # SPDX-License-Identifier: Apache-2.0 +# This code was deprecated after Zephyr v3.5.0 +message(DEPRECATION "The to_hex() and from_hex() functions are deprecated. Please " + "use CMake's math(... OUTPUT_FORMAT ) instead.") + # from https://gist.github.com/korzo89/71a6de0f388f7cf8b349101b0134060c function(from_hex HEX DEC) string(SUBSTRING "${HEX}" 2 -1 HEX) @@ -34,6 +38,10 @@ function(from_hex HEX DEC) endfunction() function(to_hex DEC HEX) + if(DEC EQUAL 0) + set(${HEX} "0x0" PARENT_SCOPE) + return() + endif() while(DEC GREATER 0) math(EXPR _val "${DEC} % 16") math(EXPR DEC "${DEC} / 16") diff --git a/cmake/linker/ld/linker_flags.cmake b/cmake/linker/ld/linker_flags.cmake index 8209f4dfbdc..5660b410760 100644 --- a/cmake/linker/ld/linker_flags.cmake +++ b/cmake/linker/ld/linker_flags.cmake @@ -12,6 +12,8 @@ endif() set_property(TARGET linker PROPERTY partial_linking "-r") +set_property(TARGET linker PROPERTY lto_arguments -flto -fno-ipa-sra -ffunction-sections -fdata-sections) + # Some linker flags might not be purely ld specific, but a combination of # linker and compiler, such as: # --coverage for clang diff --git a/cmake/linker/ld/target_relocation.cmake b/cmake/linker/ld/target_relocation.cmake index c290a330484..a90941d04af 100644 --- a/cmake/linker/ld/target_relocation.cmake +++ b/cmake/linker/ld/target_relocation.cmake @@ -32,7 +32,7 @@ macro(toolchain_ld_relocation) -b ${MEM_RELOCATION_SRAM_BSS_LD} -c ${MEM_RELOCATION_CODE} --default_ram_region ${MEM_REGION_DEFAULT_RAM} - DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} + DEPENDS app kernel ${ZEPHYR_LIBS_PROPERTY} ${DICT_FILE} ) add_library(code_relocation_source_lib STATIC ${MEM_RELOCATION_CODE}) diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake index 0c7310ab905..332d44b2435 100644 --- a/cmake/linker_script/arm/linker.cmake +++ b/cmake/linker_script/arm/linker.cmake @@ -16,10 +16,17 @@ math(EXPR FLASH_ADDR OUTPUT_FORMAT HEXADECIMAL ) -math(EXPR FLASH_SIZE - "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0)" - OUTPUT_FORMAT HEXADECIMAL -) +if(CONFIG_FLASH_LOAD_SIZE GREATER 0) + math(EXPR FLASH_SIZE + "(${CONFIG_FLASH_LOAD_SIZE} + 0) - (${CONFIG_ROM_END_OFFSET} + 0)" + OUTPUT_FORMAT HEXADECIMAL + ) +else() + math(EXPR FLASH_SIZE + "(${CONFIG_FLASH_SIZE} + 0) * 1024 - (${CONFIG_FLASH_LOAD_OFFSET} + 0) - (${CONFIG_ROM_END_OFFSET} + 0)" + OUTPUT_FORMAT HEXADECIMAL + ) +endif() set(RAM_ADDR ${CONFIG_SRAM_BASE_ADDRESS}) math(EXPR RAM_SIZE "(${CONFIG_SRAM_SIZE} + 0) * 1024" OUTPUT_FORMAT HEXADECIMAL) diff --git a/cmake/linker_script/common/common-ram.cmake b/cmake/linker_script/common/common-ram.cmake index a116977ce8c..7e639043bce 100644 --- a/cmake/linker_script/common/common-ram.cmake +++ b/cmake/linker_script/common/common-ram.cmake @@ -128,3 +128,7 @@ if(CONFIG_USB_HOST_STACK) zephyr_iterable_section(NAME usbh_contex GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) zephyr_iterable_section(NAME usbh_class_data GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) endif() + +if(CONFIG_DEVICE_MUTABLE) + zephyr_iterable_section(NAME device_mutable GROUP DATA_REGION ${XIP_ALIGN_WITH_INPUT} SUBALIGN 4) +endif() diff --git a/cmake/linker_script/common/common-rom.cmake b/cmake/linker_script/common/common-rom.cmake index d79fa223fc5..d955c8ad0b6 100644 --- a/cmake/linker_script/common/common-rom.cmake +++ b/cmake/linker_script/common/common-rom.cmake @@ -216,6 +216,7 @@ endif() if(CONFIG_ZBUS) zephyr_iterable_section(NAME zbus_channel KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) + zephyr_iterable_section(NAME zbus_observer KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) zephyr_iterable_section(NAME zbus_channel_observation KVMA RAM_REGION GROUP RODATA_REGION SUBALIGN 4) endif() diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 3b29069ca35..6dd0717f515 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -96,6 +96,11 @@ function(zephyr_mcuboot_tasks) set(imgtool_extra --key "${keyfile}" ${imgtool_extra}) endif() + # Use overwrite-only instead of swap upgrades. + if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) + set(imgtool_extra --overwrite-only --align 1 ${imgtool_extra}) + endif() + set(imgtool_args -- ${imgtool_extra}) # Extensionless prefix of any output file. diff --git a/cmake/modules/FindDeprecated.cmake b/cmake/modules/FindDeprecated.cmake index 66cac2a5583..875f243b034 100644 --- a/cmake/modules/FindDeprecated.cmake +++ b/cmake/modules/FindDeprecated.cmake @@ -37,26 +37,6 @@ if("${Deprecated_FIND_COMPONENTS}" STREQUAL "") message(WARNING "find_package(Deprecated) missing required COMPONENTS keyword") endif() -if("XCC_USE_CLANG" IN_LIST Deprecated_FIND_COMPONENTS) - list(REMOVE_ITEM Deprecated_FIND_COMPONENTS XCC_USE_CLANG) - # This code was deprecated after Zephyr v3.0.0 - # Keep XCC_USE_CLANG behaviour for a while. - if(NOT DEFINED ZEPHYR_TOOLCHAIN_VARIANT) - set(ZEPHYR_TOOLCHAIN_VARIANT $ENV{ZEPHYR_TOOLCHAIN_VARIANT}) - endif() - - if ("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc" - AND "$ENV{XCC_USE_CLANG}" STREQUAL "1") - set(ZEPHYR_TOOLCHAIN_VARIANT xt-clang CACHE STRING "Zephyr toolchain variant" FORCE) - message(DEPRECATION "XCC_USE_CLANG is deprecated. Please set ZEPHYR_TOOLCHAIN_VARIANT to 'xt-clang'") - endif() - - if("${ZEPHYR_TOOLCHAIN_VARIANT}" STREQUAL "xcc-clang") - set(ZEPHYR_TOOLCHAIN_VARIANT xt-clang CACHE STRING "Zephyr toolchain variant" FORCE) - message(DEPRECATION "ZEPHYR_TOOLCHAIN_VARIANT 'xcc-clang' is deprecated. Please set ZEPHYR_TOOLCHAIN_VARIANT to 'xt-clang'") - endif() -endif() - if("CROSS_COMPILE" IN_LIST Deprecated_FIND_COMPONENTS) list(REMOVE_ITEM Deprecated_FIND_COMPONENTS CROSS_COMPILE) # This code was deprecated after Zephyr v3.1.0 @@ -107,13 +87,6 @@ if("SOURCES" IN_LIST Deprecated_FIND_COMPONENTS) endif() endif() -if("PRJ_BOARD" IN_LIST Deprecated_FIND_COMPONENTS) - # This code was deprecated after Zephyr v3.3.0 - list(REMOVE_ITEM Deprecated_FIND_COMPONENTS PRJ_BOARD) - message(DEPRECATION "'prj_.conf' files are deprecated and should be " - "replaced with board Kconfig fragments instead.") -endif() - if("PYTHON_PREFER" IN_LIST Deprecated_FIND_COMPONENTS) # This code was deprecated after Zephyr v3.4.0 list(REMOVE_ITEM Deprecated_FIND_COMPONENTS PYTHON_PREFER) diff --git a/cmake/modules/FindHostTools.cmake b/cmake/modules/FindHostTools.cmake index 82225b49e56..b2d5257642d 100644 --- a/cmake/modules/FindHostTools.cmake +++ b/cmake/modules/FindHostTools.cmake @@ -48,7 +48,7 @@ if(HostTools_FOUND) return() endif() -find_package(Deprecated COMPONENTS XCC_USE_CLANG CROSS_COMPILE) +find_package(Deprecated COMPONENTS CROSS_COMPILE) find_package(Zephyr-sdk 0.16) diff --git a/cmake/modules/configuration_files.cmake b/cmake/modules/configuration_files.cmake index 76d19e5ebbb..4f2e469ab79 100644 --- a/cmake/modules/configuration_files.cmake +++ b/cmake/modules/configuration_files.cmake @@ -27,6 +27,9 @@ include_guard(GLOBAL) include(extensions) +# Merge in variables from other sources (e.g. sysbuild) +zephyr_get(FILE_SUFFIX SYSBUILD GLOBAL) + zephyr_get(APPLICATION_CONFIG_DIR) if(DEFINED APPLICATION_CONFIG_DIR) string(CONFIGURE ${APPLICATION_CONFIG_DIR} APPLICATION_CONFIG_DIR) @@ -40,73 +43,42 @@ else() endif() zephyr_get(CONF_FILE SYSBUILD LOCAL) -if(DEFINED CONF_FILE) - # This ensures that CACHE{CONF_FILE} will be set correctly to current scope - # variable CONF_FILE. An already current scope variable will stay the same. - set(CONF_FILE ${CONF_FILE}) - - # CONF_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. This has precedence over the environment - # variable CONF_FILE and the default prj.conf - - # In order to support a `prj_.conf pattern for auto inclusion of board - # overlays, then we must first ensure only a single conf file is provided. +if(NOT DEFINED CONF_FILE) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} KCONF CONF_FILE NAMES "prj.conf" SUFFIX ${FILE_SUFFIX} REQUIRED) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE) +else() string(CONFIGURE "${CONF_FILE}" CONF_FILE_EXPANDED) string(REPLACE " " ";" CONF_FILE_AS_LIST "${CONF_FILE_EXPANDED}") list(LENGTH CONF_FILE_AS_LIST CONF_FILE_LENGTH) if(${CONF_FILE_LENGTH} EQUAL 1) - # Need the file name to look for match. - # Need path in order to check if it is absolute. get_filename_component(CONF_FILE_NAME ${CONF_FILE} NAME) if(${CONF_FILE_NAME} MATCHES "prj_(.*).conf") set(CONF_FILE_BUILD_TYPE ${CMAKE_MATCH_1}) - set(CONF_FILE_INCLUDE_FRAGMENTS true) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE + BUILD ${CONF_FILE_BUILD_TYPE} + ) + set(CONF_FILE_FORCE_CACHE FORCE) endif() endif() -elseif(CACHED_CONF_FILE) - # Cached conf file is present. - # That value has precedence over anything else than a new - # `cmake -DCONF_FILE=` invocation. - set(CONF_FILE ${CACHED_CONF_FILE}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj_${BOARD}.conf) - find_package(Deprecated COMPONENTS PRJ_BOARD) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE ${APPLICATION_CONFIG_DIR}/prj.conf) - set(CONF_FILE_INCLUDE_FRAGMENTS true) -else() - message(FATAL_ERROR "No prj.conf file was found in the ${APPLICATION_CONFIG_DIR} folder, " - "please read the Zephyr documentation on application development.") -endif() - -if(CONF_FILE_INCLUDE_FRAGMENTS) - zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards KCONF CONF_FILE BUILD ${CONF_FILE_BUILD_TYPE}) endif() set(APPLICATION_CONFIG_DIR ${APPLICATION_CONFIG_DIR} CACHE INTERNAL "The application configuration folder" FORCE) -set(CACHED_CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ +set(CONF_FILE ${CONF_FILE} CACHE STRING "If desired, you can build the application using\ the configuration settings specified in an alternate .conf file using this parameter. \ These settings will override the settings in the application’s .config file or its default .conf file.\ Multiple files may be listed, e.g. CONF_FILE=\"prj1.conf;prj2.conf\" \ The CACHED_CONF_FILE is internal Zephyr variable used between CMake runs. \ -To change CONF_FILE, use the CONF_FILE variable.") -unset(CONF_FILE CACHE) - -zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS) +To change CONF_FILE, use the CONF_FILE variable." ${CONF_FILE_FORCE_CACHE}) # The CONF_FILE variable is now set to its final value. zephyr_boilerplate_watch(CONF_FILE) +zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR}/boards DTS APP_BOARD_DTS SUFFIX ${FILE_SUFFIX}) + zephyr_get(DTC_OVERLAY_FILE SYSBUILD LOCAL) -if(DTC_OVERLAY_FILE) - # DTC_OVERLAY_FILE has either been specified on the cmake CLI or is already - # in the CMakeCache.txt. -elseif(APP_BOARD_DTS) - set(DTC_OVERLAY_FILE ${APP_BOARD_DTS}) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/${BOARD}.overlay) -elseif(EXISTS ${APPLICATION_CONFIG_DIR}/app.overlay) - set(DTC_OVERLAY_FILE ${APPLICATION_CONFIG_DIR}/app.overlay) +if(NOT DEFINED DTC_OVERLAY_FILE) + zephyr_file(CONF_FILES ${APPLICATION_CONFIG_DIR} DTS DTC_OVERLAY_FILE + NAMES "${APP_BOARD_DTS};${BOARD}.overlay;app.overlay" SUFFIX ${FILE_SUFFIX}) endif() set(DTC_OVERLAY_FILE ${DTC_OVERLAY_FILE} CACHE STRING "If desired, you can \ diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index c9ac751a1e5..23659c18692 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -125,7 +125,7 @@ set(VENDOR_PREFIXES dts/bindings/vendor-prefixes.txt) set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts) if(EXISTS ${DTS_SOURCE}) # We found a devicetree. Check for a board revision overlay. - if(BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) + if(DEFINED BOARD_REVISION AND EXISTS ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) list(APPEND DTS_SOURCE ${BOARD_DIR}/${BOARD}_${BOARD_REVISION_STRING}.overlay) endif() else() diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake index 6bdd55433eb..e636a2cb473 100644 --- a/cmake/modules/extensions.cmake +++ b/cmake/modules/extensions.cmake @@ -34,6 +34,7 @@ include(CheckCXXCompilerFlag) # 5. Zephyr linker functions # 5.1. zephyr_linker* # 6 Function helper macros +# 7 Linkable loadable extensions (llext) ######################################################## # 1. Zephyr-aware extensions @@ -773,7 +774,7 @@ endmacro() # # Within application CMakeLists.txt files, ensure that all calls to # board_runner_args() are part of a macro named app_set_runner_args(), -# like this, which is defined before including the boilerplate file: +# like this, which is defined before calling 'find_package(Zephyr)': # macro(app_set_runner_args) # board_runner_args(runner "--some-app-setting=value") # endmacro() @@ -1158,6 +1159,8 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # copied/included verbatim into the given in the global linker.ld. # Preprocessor directives work inside . Relative paths are resolved # relative to the calling file, like zephyr_sources(). +# Subsequent calls to zephyr_linker_sources with the same file(s) will remove +# these from the original location. Only the last call is considered. # is one of # NOINIT Inside the noinit output section. # RWDATA Inside the data output section. @@ -1169,6 +1172,8 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized. # RAMFUNC_SECTION Inside the RAMFUNC RAMABLE_REGION GROUP, not initialized. # NOCACHE_SECTION Inside the NOCACHE section +# ITCM_SECTION Inside the itcm section. +# DTCM_SECTION Inside the dtcm data section. # SECTIONS Near the end of the file. Don't use this when linking into # RAMABLE_REGION, use RAM_SECTIONS instead. # PINNED_RODATA Similar to RODATA but pinned in memory. @@ -1183,8 +1188,9 @@ endfunction(zephyr_check_compiler_flag_hardcoded) # Use NOINIT, RWDATA, and RODATA unless they don't work for your use case. # # When placing into NOINIT, RWDATA, RODATA, ROM_START, RAMFUNC_SECTION, -# NOCACHE_SECTION the contents of the files will be placed inside -# an output section, so assume the section definition is already present, e.g.: +# NOCACHE_SECTION, DTCM_SECTION or ITCM_SECTION the contents of the files will +# be placed inside an output section, so assume the section definition is +# already present, e.g.: # _mysection_start = .; # KEEP(*(.mysection)); # _mysection_end = .; @@ -1219,6 +1225,8 @@ function(zephyr_linker_sources location) set(rodata_path "${snippet_base}/snippets-rodata.ld") set(ramfunc_path "${snippet_base}/snippets-ramfunc-section.ld") set(nocache_path "${snippet_base}/snippets-nocache-section.ld") + set(itcm_path "${snippet_base}/snippets-itcm-section.ld") + set(dtcm_path "${snippet_base}/snippets-dtcm-section.ld") set(pinned_ram_sections_path "${snippet_base}/snippets-pinned-ram-sections.ld") set(pinned_data_sections_path "${snippet_base}/snippets-pinned-data-sections.ld") @@ -1236,6 +1244,8 @@ function(zephyr_linker_sources location) file(WRITE ${rodata_path} "") file(WRITE ${ramfunc_path} "") file(WRITE ${nocache_path} "") + file(WRITE ${itcm_path} "") + file(WRITE ${dtcm_path} "") file(WRITE ${pinned_ram_sections_path} "") file(WRITE ${pinned_data_sections_path} "") file(WRITE ${pinned_rodata_path} "") @@ -1261,6 +1271,22 @@ function(zephyr_linker_sources location) set(snippet_path "${ramfunc_path}") elseif("${location}" STREQUAL "NOCACHE_SECTION") set(snippet_path "${nocache_path}") + elseif("${location}" STREQUAL "ITCM_SECTION") + dt_has_chosen(HAS_ITCM PROPERTY "zephyr,itcm") + if(NOT HAS_ITCM) + message(FATAL_ERROR "Trying to link snippet into itcm but no itcm available. " + "Add `zephyr,itcm` to the device tree if supported on your device or choose another " + "location.") + endif() + set(snippet_path "${itcm_path}") + elseif("${location}" STREQUAL "DTCM_SECTION") + dt_has_chosen(HAS_DTCM PROPERTY "zephyr,dtcm") + if(NOT HAS_DTCM) + message(FATAL_ERROR "Trying to link snippet into dtcm but no dtcm available. " + "Add `zephyr,dtcm` to the device tree if supported on your device or choose another " + "location.") + endif() + set(snippet_path "${dtcm_path}") elseif("${location}" STREQUAL "PINNED_RAM_SECTIONS") set(snippet_path "${pinned_ram_sections_path}") elseif("${location}" STREQUAL "PINNED_DATA_SECTIONS") @@ -1295,6 +1321,16 @@ function(zephyr_linker_sources location) # Create strings to be written into the file set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"") + # Remove line from other snippet file, if already used + get_property(old_path GLOBAL PROPERTY "snippet_files_used_${relpath}") + if (DEFINED old_path) + file(STRINGS ${old_path} lines) + list(FILTER lines EXCLUDE REGEX ${relpath}) + string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line. + file(WRITE ${old_path} ${lines} "\n") + endif() + set_property(GLOBAL PROPERTY "snippet_files_used_${relpath}" ${snippet_path}) + # Add new line to existing lines, sort them, and write them back. file(STRINGS ${snippet_path} lines) # Get current lines (without newlines). list(APPEND lines ${include_str}) @@ -1330,9 +1366,11 @@ endmacro() # The following optional arguments are supported: # - NOCOPY: this flag indicates that the file data does not need to be copied # at boot time (For example, for flash XIP). +# - NOKEEP: suppress the generation of KEEP() statements in the linker script, +# to allow any unused code in the given files/library to be discarded. # - PHDR [program_header]: add program header. Used on Xtensa platforms. function(zephyr_code_relocate) - set(options NOCOPY) + set(options NOCOPY NOKEEP) set(single_args LIBRARY LOCATION PHDR) set(multi_args FILES) cmake_parse_arguments(CODE_REL "${options}" "${single_args}" @@ -1392,21 +1430,25 @@ function(zephyr_code_relocate) endif() endif() if(NOT CODE_REL_NOCOPY) - set(copy_flag COPY) + set(flag_list COPY) else() - set(copy_flag NOCOPY) + set(flag_list NOCOPY) + endif() + if(CODE_REL_NOKEEP) + list(APPEND flag_list NOKEEP) endif() if(CODE_REL_PHDR) set(CODE_REL_LOCATION "${CODE_REL_LOCATION}\ :${CODE_REL_PHDR}") endif() - # We use the "|" character to separate code relocation directives instead - # of using CMake lists. This way, the ";" character can be reserved for - # generator expression file lists. + # We use the "|" character to separate code relocation directives, instead of + # using set_property(APPEND) to produce a ";"-separated CMake list. This way, + # each directive can embed multiple CMake lists, representing flags and files, + # the latter of which can come from generator expressions. get_property(code_rel_str TARGET code_data_relocation_target PROPERTY COMPILE_DEFINITIONS) set_property(TARGET code_data_relocation_target PROPERTY COMPILE_DEFINITIONS - "${code_rel_str}|${CODE_REL_LOCATION}:${copy_flag}:${file_list}") + "${code_rel_str}|${CODE_REL_LOCATION}:${flag_list}:${file_list}") endfunction() # Usage: @@ -1559,6 +1601,73 @@ function(zephyr_syscall_header_ifdef feature_toggle) endif() endfunction() +# Verify blobs fetched using west. If the sha256 checksum isn't valid, a warning/ +# fatal error message is printed (depends on REQUIRED flag). +# +# Usage: +# zephyr_blobs_verify( [REQUIRED]) +# +# Example: +# zephyr_blobs_verify(MODULE my_module REQUIRED) # verify all blobs in my_module and fail on error +# zephyr_blobs_verify(FILES img/file.bin) # verify a single file and print on error +function(zephyr_blobs_verify) + cmake_parse_arguments(BLOBS_VERIFY "REQUIRED" "MODULE" "FILES" ${ARGN}) + + if((DEFINED BLOBS_VERIFY_MODULE) EQUAL (DEFINED BLOBS_VERIFY_FILES)) + message(FATAL_ERROR "Either MODULE or FILES required when calling ${CMAKE_CURRENT_FUNCTION}") + endif() + + if(NOT WEST) + return() + endif() + + execute_process( + COMMAND ${WEST} blobs list ${BLOBS_VERIFY_MODULE} --format "{status} {abspath}" + OUTPUT_VARIABLE BLOBS_LIST_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + + if(${BLOBS_VERIFY_REQUIRED}) + set(msg_lvl FATAL_ERROR) + else() + set(msg_lvl WARNING) + endif() + + string(REPLACE "\n" ";" BLOBS_LIST ${BLOBS_LIST_OUTPUT}) + + if(DEFINED BLOBS_VERIFY_FILES) + foreach(file ${BLOBS_VERIFY_FILES}) + # Resolve path. + if(IS_ABSOLUTE ${file}) + file(REAL_PATH "${file}" real_path) + else() + file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${file}" real_path) + endif() + file(TO_NATIVE_PATH ${real_path} path) + + message(VERBOSE "Verifying blob \"${path}\"") + + # Each path that has a correct sha256 is prefixed with an A + if(NOT "A ${path}" IN_LIST BLOBS_LIST) + message(${msg_lvl} "Blob for path \"${path}\" isn't valid.") + endif() + endforeach() + else() + foreach(blob ${BLOBS_LIST}) + separate_arguments(blob) + list(GET blob 0 status) + list(GET blob 1 path) + + message(VERBOSE "Verifying blob \"${path}\"") + + if(NOT "${status}" STREQUAL "A") + message(${msg_lvl} "Blob for path \"${path}\" isn't valid. Update with: west blobs fetch ${BLOBS_VERIFY_MODULE}") + endif() + endforeach() + endif() +endfunction() + ######################################################## # 2. Kconfig-aware extensions ######################################################## @@ -2316,6 +2425,12 @@ endfunction() # # returns an updated list of absolute paths # +# Usage: +# zephyr_file(CONF_FILES [DTS ] [KCONF ] +# [BOARD [BOARD_REVISION ] | NAMES ...] +# [BUILD ] [SUFFIX ] [REQUIRED] +# ) +# # CONF_FILES : Find all configuration files in the list of paths and # return them in a list. If paths is empty then no configuration # files are returned. Configuration files will be: @@ -2329,14 +2444,27 @@ endfunction() # revision. Requires BOARD to be specified. # # If no board is given the current BOARD and -# BOARD_REVISION will be used. -# -# DTS : List to append DTS overlay files in to -# KCONF : List to append Kconfig fragment files in to -# BUILD : Build type to include for search. -# For example: -# BUILD debug, will look for _debug.conf -# and _debug.overlay, instead of .conf +# BOARD_REVISION will be used, unless NAMES are +# specified. +# +# NAMES [name2] ... List of file names to look for and instead of +# creating file names based on board settings. +# Only the first match found in will be +# returned in the +# +# DTS : List to append DTS overlay files in to +# KCONF : List to append Kconfig fragment files in to +# BUILD : Build type to include for search. +# For example: +# BUILD debug, will look for _debug.conf +# and _debug.overlay, instead of .conf +# SUFFIX : Suffix name to check for instead of the default name +# but with a fallback to the default name if not found. +# For example: +# SUFFIX fish, will look for _fish.conf and use +# if found but will use .conf if not found +# REQUIRED: Option to indicate that the specified by DTS or KCONF +# must contain at least one element, else an error will be raised. # function(zephyr_file) set(file_options APPLICATION_ROOT CONF_FILES) @@ -2348,16 +2476,16 @@ Please provide one of following: APPLICATION_ROOT, CONF_FILES") if(${ARGV0} STREQUAL APPLICATION_ROOT) set(single_args APPLICATION_ROOT) elseif(${ARGV0} STREQUAL CONF_FILES) - set(single_args BOARD BOARD_REVISION DTS KCONF BUILD) - set(multi_args CONF_FILES) + set(options REQUIRED) + set(single_args BOARD BOARD_REVISION DTS KCONF BUILD SUFFIX) + set(multi_args CONF_FILES NAMES) endif() - cmake_parse_arguments(FILE "" "${single_args}" "${multi_args}" ${ARGN}) + cmake_parse_arguments(FILE "${options}" "${single_args}" "${multi_args}" ${ARGN}) if(FILE_UNPARSED_ARGUMENTS) message(FATAL_ERROR "zephyr_file(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}") endif() - if(FILE_APPLICATION_ROOT) # Note: user can do: `-D=` and app can at same # time specify `list(APPEND )` @@ -2409,44 +2537,104 @@ Relative paths are only allowed with `-D${ARGV1}=`") endif() endif() - zephyr_build_string(filename - BOARD ${FILE_BOARD} - BUILD ${FILE_BUILD} - ) - set(filename_list ${filename}) + if(FILE_NAMES) + set(dts_filename_list ${FILE_NAMES}) + set(kconf_filename_list ${FILE_NAMES}) + else() + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BUILD ${FILE_BUILD} + ) + set(filename_list ${filename}) - zephyr_build_string(filename - BOARD ${FILE_BOARD} - BOARD_REVISION ${FILE_BOARD_REVISION} - BUILD ${FILE_BUILD} - ) - list(APPEND filename_list ${filename}) - list(REMOVE_DUPLICATES filename_list) + zephyr_build_string(filename + BOARD ${FILE_BOARD} + BOARD_REVISION ${FILE_BOARD_REVISION} + BUILD ${FILE_BUILD} + ) + list(APPEND filename_list ${filename}) + list(REMOVE_DUPLICATES filename_list) + set(dts_filename_list ${filename_list}) + list(TRANSFORM dts_filename_list APPEND ".overlay") + + set(kconf_filename_list ${filename_list}) + list(TRANSFORM kconf_filename_list APPEND ".conf") + endif() if(FILE_DTS) foreach(path ${FILE_CONF_FILES}) - foreach(filename ${filename_list}) - if(EXISTS ${path}/${filename}.overlay) - list(APPEND ${FILE_DTS} ${path}/${filename}.overlay) + foreach(filename ${dts_filename_list}) + if(NOT IS_ABSOLUTE ${filename}) + set(test_file ${path}/${filename}) + else() + set(test_file ${filename}) + endif() + zephyr_file_suffix(test_file SUFFIX ${FILE_SUFFIX}) + + if(EXISTS ${test_file}) + list(APPEND ${FILE_DTS} ${test_file}) + + if(DEFINED FILE_BUILD) + set(deprecated_file_found y) + endif() + + if(FILE_NAMES) + break() + endif() endif() endforeach() endforeach() # This updates the provided list in parent scope (callers scope) set(${FILE_DTS} ${${FILE_DTS}} PARENT_SCOPE) + + if(NOT ${FILE_DTS}) + set(not_found ${dts_filename_list}) + endif() endif() if(FILE_KCONF) foreach(path ${FILE_CONF_FILES}) - foreach(filename ${filename_list}) - if(EXISTS ${path}/${filename}.conf) - list(APPEND ${FILE_KCONF} ${path}/${filename}.conf) + foreach(filename ${kconf_filename_list}) + if(NOT IS_ABSOLUTE ${filename}) + set(test_file ${path}/${filename}) + else() + set(test_file ${filename}) + endif() + zephyr_file_suffix(test_file SUFFIX ${FILE_SUFFIX}) + + if(EXISTS ${test_file}) + list(APPEND ${FILE_KCONF} ${test_file}) + + if(DEFINED FILE_BUILD) + set(deprecated_file_found y) + endif() + + if(FILE_NAMES) + break() + endif() endif() endforeach() endforeach() # This updates the provided list in parent scope (callers scope) set(${FILE_KCONF} ${${FILE_KCONF}} PARENT_SCOPE) + + if(NOT ${FILE_KCONF}) + set(not_found ${kconf_filename_list}) + endif() + endif() + + if(FILE_REQUIRED AND DEFINED not_found) + message(FATAL_ERROR + "No ${not_found} file(s) was found in the ${FILE_CONF_FILES} folder(s), " + "please read the Zephyr documentation on application development." + ) + endif() + + if(deprecated_file_found) + message(DEPRECATION "prj_.conf was deprecated after Zephyr 3.5," + " you should switch to using -DFILE_SUFFIX instead") endif() endif() endfunction() @@ -2487,6 +2675,56 @@ function(zephyr_file_copy oldname newname) endif() endfunction() +# Usage: +# zephyr_file_suffix( SUFFIX ) +# +# Zephyr file add suffix extension. +# This function will check the provied filename or list of filenames to see if they have a +# `_` extension to them and if so, updates the supplied variable/list with the new +# path/paths. +# +# : Variable (singlular or list) of absolute path filename(s) which should be checked +# and updated if there is a filename which has the present. +# : The suffix to test for and append to the end of the provided filename. +# +# Returns an updated variable of absolute path(s) +# +function(zephyr_file_suffix filename) + set(single_args SUFFIX) + cmake_parse_arguments(FILE "" "${single_args}" "" ${ARGN}) + + if(NOT DEFINED FILE_SUFFIX OR NOT DEFINED ${filename}) + # If the file suffix variable is not known then there is nothing to do, return early + return() + endif() + + set(tmp_new_list) + + foreach(file ${${filename}}) + if("${file}" STREQUAL "") + # Skip checking empty variables + continue() + endif() + + # Search for the full stop so we know where to add the file suffix before the file extension + cmake_path(GET file EXTENSION file_ext) + cmake_path(REMOVE_EXTENSION file OUTPUT_VARIABLE new_filename) + cmake_path(APPEND_STRING new_filename "_${FILE_SUFFIX}${file_ext}") + + # Use the filename with the suffix if it exists, if not then fall back to the default + if(EXISTS "${new_filename}") + list(APPEND tmp_new_list ${new_filename}) + else() + list(APPEND tmp_new_list ${file}) + endif() + endforeach() + + # Update supplied variable if it differs + if(NOT "${${filename}}" STREQUAL "${tmp_new_list}") + set(${filename} "${tmp_new_list}" PARENT_SCOPE) + endif() +endfunction() + # Usage: # zephyr_string( ...) # @@ -4786,3 +5024,138 @@ macro(zephyr_check_flags_exclusive function prefix) ) endif() endmacro() + +######################################################## +# 7. Linkable loadable extensions (llext) +######################################################## +# +# These functions simplify the creation and management of linkable +# loadable extensions (llexts). +# + +# Add a custom target that compiles a single source file to a .llext file. +# +# Output and source files must be specified using the OUTPUT and SOURCES +# arguments. Only one source file is currently supported. +# +# The llext code will be compiled with mostly the same C compiler flags used +# in the Zephyr build, but with some important modifications. The list of +# flags to remove and flags to append is controlled respectively by the +# LLEXT_REMOVE_FLAGS and LLEXT_APPEND_FLAGS global variables. + +# The C_FLAGS argument can be used to pass additional compiler flags to the +# compilation of this particular llext. +# +# Example usage: +# add_llext_target(hello_world +# OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext +# SOURCES ${PROJECT_SOURCE_DIR}/src/llext/hello_world.c +# C_FLAGS -Werror +# ) +# will compile the source file src/llext/hello_world.c to a file +# ${PROJECT_BINARY_DIR}/hello_world.llext, adding -Werror to the compilation. +# +function(add_llext_target target_name) + set(single_args OUTPUT) + set(multi_args SOURCES;C_FLAGS) + cmake_parse_arguments(PARSE_ARGV 1 LLEXT "${options}" "${single_args}" "${multi_args}") + + # Check that the llext subsystem is enabled for this build + if (NOT CONFIG_LLEXT) + message(FATAL_ERROR "add_llext_target: CONFIG_LLEXT must be enabled") + endif() + + # Output file must be provided + if(NOT LLEXT_OUTPUT) + message(FATAL_ERROR "add_llext_target: OUTPUT argument must be provided") + endif() + + # Source list length must currently be 1 + list(LENGTH LLEXT_SOURCES source_count) + if(NOT source_count EQUAL 1) + message(FATAL_ERROR "add_llext_target: only one source file is supported") + endif() + + set(output_file ${LLEXT_OUTPUT}) + set(source_file ${LLEXT_SOURCES}) + get_filename_component(output_name ${output_file} NAME) + + # Add user-visible target and dependency + add_custom_target(${target_name} + COMMENT "Compiling ${output_name}" + DEPENDS ${output_file} + ) + + # Convert the LLEXT_REMOVE_FLAGS list to a regular expression, and use it to + # filter out these flags from the Zephyr target settings + list(TRANSFORM LLEXT_REMOVE_FLAGS + REPLACE "(.+)" "^\\1$" + OUTPUT_VARIABLE llext_remove_flags_regexp + ) + string(REPLACE ";" "|" llext_remove_flags_regexp "${llext_remove_flags_regexp}") + set(zephyr_flags + "$" + ) + set(zephyr_filtered_flags + "$" + ) + + # Compile the source file to an object file using current Zephyr settings + # but a different set of flags + add_library(${target_name}_lib OBJECT ${source_file}) + target_compile_definitions(${target_name}_lib PRIVATE + $ + ) + target_compile_options(${target_name}_lib PRIVATE + ${zephyr_filtered_flags} + ${LLEXT_APPEND_FLAGS} + ${LLEXT_C_FLAGS} + ) + target_include_directories(${target_name}_lib PRIVATE + $ + ) + target_include_directories(${target_name}_lib SYSTEM PUBLIC + $ + ) + add_dependencies(${target_name}_lib + zephyr_interface + zephyr_generated_headers + ) + + # Arch-specific conversion of the object file to an llext + if(CONFIG_ARM) + + # No conversion required, simply copy the object file + add_custom_command( + OUTPUT ${output_file} + COMMAND ${CMAKE_COMMAND} -E copy $ ${output_file} + DEPENDS ${target_name}_lib $ + ) + + elseif(CONFIG_XTENSA) + + # Generate an intermediate file name + get_filename_component(output_dir ${output_file} DIRECTORY) + get_filename_component(output_name_we ${output_file} NAME_WE) + set(pre_output_file ${output_dir}/${output_name_we}.pre.llext) + + # Need to convert the object file to a shared library, then strip some sections + add_custom_command( + OUTPUT ${output_file} + BYPRODUCTS ${pre_output_file} + COMMAND ${CMAKE_C_COMPILER} ${LLEXT_APPEND_FLAGS} + -o ${pre_output_file} + $ + COMMAND $ + $ + $.xt.* + $${pre_output_file} + $${output_file} + $ + DEPENDS ${target_name}_lib $ + ) + + else() + message(FATAL_ERROR "add_llext_target: unsupported architecture") + endif() +endfunction() diff --git a/cmake/modules/generated_file_directories.cmake b/cmake/modules/generated_file_directories.cmake index aac3b39a6f9..9b18e1794de 100644 --- a/cmake/modules/generated_file_directories.cmake +++ b/cmake/modules/generated_file_directories.cmake @@ -19,6 +19,6 @@ include_guard(GLOBAL) # Optional environment variables: # None -set(BINARY_DIR_INCLUDE ${PROJECT_BINARY_DIR}/include/generated) -set(BINARY_DIR_INCLUDE_GENERATED ${PROJECT_BINARY_DIR}/include/generated) +set(BINARY_DIR_INCLUDE ${PROJECT_BINARY_DIR}/include) +set(BINARY_DIR_INCLUDE_GENERATED ${BINARY_DIR_INCLUDE}/generated) file(MAKE_DIRECTORY ${BINARY_DIR_INCLUDE_GENERATED}) diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 1a78b3ebd02..2fe8533bfb8 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -84,7 +84,7 @@ if(EXTRA_CONF_FILE) string(REPLACE " " ";" EXTRA_CONF_FILE_AS_LIST "${EXTRA_CONF_FILE_EXPANDED}") endif() -zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} KCONF board_extension_conf_files) +zephyr_file(CONF_FILES ${BOARD_EXTENSION_DIRS} KCONF board_extension_conf_files SUFFIX ${FILE_SUFFIX}) # DTS_ROOT_BINDINGS is a semicolon separated list, this causes # problems when invoking kconfig_target since semicolon is a special @@ -133,6 +133,8 @@ set(COMMON_KCONFIG_ENV_SETTINGS srctree=${ZEPHYR_BASE} KERNELVERSION=${KERNELVERSION} APPVERSION=${APP_VERSION_STRING} + APP_VERSION_EXTENDED_STRING=${APP_VERSION_EXTENDED_STRING} + APP_VERSION_TWEAK_STRING=${APP_VERSION_TWEAK_STRING} CONFIG_=${KCONFIG_NAMESPACE}_ KCONFIG_CONFIG=${DOTCONFIG} # Set environment variables so that Kconfig can prune Kconfig source diff --git a/cmake/modules/python.cmake b/cmake/modules/python.cmake index 78a29959b8b..6fc765f8f58 100644 --- a/cmake/modules/python.cmake +++ b/cmake/modules/python.cmake @@ -31,7 +31,6 @@ if(NOT Python3_EXECUTABLE) "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))" RESULT_VARIABLE result OUTPUT_VARIABLE version - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if(version VERSION_LESS PYTHON_MINIMUM_REQUIRED) diff --git a/cmake/modules/shields.cmake b/cmake/modules/shields.cmake index 77abc4d603b..ec172512b68 100644 --- a/cmake/modules/shields.cmake +++ b/cmake/modules/shields.cmake @@ -79,41 +79,53 @@ foreach(root ${BOARD_ROOT}) list(REMOVE_ITEM SHIELD-NOTFOUND ${s}) - # Add .overlay to the shield_dts_files output variable. - list(APPEND - shield_dts_files - ${SHIELD_DIR_${s}}/${s}.overlay - ) - - # Add the shield's directory to the SHIELD_DIRS output variable. - list(APPEND - SHIELD_DIRS - ${SHIELD_DIR_${s}} - ) + # Add .overlay to a temporary variable + set(shield_${s}_dts_file ${SHIELD_DIR_${s}}/${s}.overlay) # Search for shield/shield.conf file if(EXISTS ${SHIELD_DIR_${s}}/${s}.conf) - # Add .conf to the shield_conf_files output variable. - list(APPEND - shield_conf_files - ${SHIELD_DIR_${s}}/${s}.conf - ) + # Add .conf to a temporary variable + set(shield_${s}_conf_file ${SHIELD_DIR_${s}}/${s}.conf) endif() - - # Add board-specific .conf and .overlay files to their - # respective output variables. - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards - DTS shield_dts_files - KCONF shield_conf_files - ) - zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} - DTS shield_dts_files - KCONF shield_conf_files - ) endforeach() endif() endforeach() +# Process shields in-order +if(DEFINED SHIELD) + foreach(s ${SHIELD_AS_LIST}) + # Add .overlay to the shield_dts_files output variable. + list(APPEND + shield_dts_files + ${shield_${s}_dts_file} + ) + + # Add the shield's directory to the SHIELD_DIRS output variable. + list(APPEND + SHIELD_DIRS + ${SHIELD_DIR_${s}} + ) + + if(DEFINED shield_${s}_conf_file) + list(APPEND + shield_conf_files + ${shield_${s}_conf_file} + ) + endif() + + # Add board-specific .conf and .overlay files to their + # respective output variables. + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards + DTS shield_dts_files + KCONF shield_conf_files + ) + zephyr_file(CONF_FILES ${SHIELD_DIR_${s}}/boards/${s} + DTS shield_dts_files + KCONF shield_conf_files + ) + endforeach() +endif() + # Prepare shield usage command printing. # This command prints all shields in the system in the following cases: # - User specifies an invalid SHIELD diff --git a/cmake/modules/version.cmake b/cmake/modules/version.cmake index 49d172871e7..72c0424031a 100644 --- a/cmake/modules/version.cmake +++ b/cmake/modules/version.cmake @@ -11,8 +11,10 @@ # # Outputs with examples:: # -# PROJECT_VERSION 1.14.99.07 -# KERNEL_VERSION_STRING "1.14.99-extraver" +# PROJECT_VERSION 1.14.99.07 +# KERNEL_VERSION_STRING "1.14.99-extraver" +# KERNEL_VERSION_EXTENDED_STRING "1.14.99-extraver+7" +# KERNEL_VERSION_TWEAK_STRING "1.14.99+7" # # KERNEL_VERSION_MAJOR 1 # KERNEL_VERSION_MINOR 14 @@ -33,8 +35,6 @@ # Therefore `version.cmake` should not use include_guard(GLOBAL). # The final load of `version.cmake` will setup correct build version values. -include(${ZEPHYR_BASE}/cmake/hex.cmake) - if(NOT DEFINED VERSION_FILE AND NOT DEFINED VERSION_TYPE) set(VERSION_FILE ${ZEPHYR_BASE}/VERSION ${APPLICATION_SOURCE_DIR}/VERSION) set(VERSION_TYPE KERNEL APP) @@ -62,9 +62,9 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) string(REGEX MATCH "EXTRAVERSION = ([a-z0-9]*)" _ ${ver}) set(${type}_VERSION_EXTRA ${CMAKE_MATCH_1}) - # Temporary convenience variable + # Temporary convenience variables set(${type}_VERSION_WITHOUT_TWEAK ${${type}_VERSION_MAJOR}.${${type}_VERSION_MINOR}.${${type}_PATCHLEVEL}) - + set(${type}_VERSION_WITH_TWEAK ${${type}_VERSION_MAJOR}.${${type}_VERSION_MINOR}.${${type}_PATCHLEVEL}+${${type}_VERSION_TWEAK}) set(MAJOR ${${type}_VERSION_MAJOR}) # Temporary convenience variable set(MINOR ${${type}_VERSION_MINOR}) # Temporary convenience variable @@ -74,14 +74,16 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) math(EXPR ${type}_VERSION_NUMBER_INT "(${MAJOR} << 16) + (${MINOR} << 8) + (${PATCH})") math(EXPR ${type}VERSION_INT "(${MAJOR} << 24) + (${MINOR} << 16) + (${PATCH} << 8) + (${TWEAK})") - to_hex(${${type}_VERSION_NUMBER_INT} ${type}_VERSION_NUMBER) - to_hex(${${type}VERSION_INT} ${type}VERSION) + math(EXPR ${type}_VERSION_NUMBER "${${type}_VERSION_NUMBER_INT}" OUTPUT_FORMAT HEXADECIMAL) + math(EXPR ${type}VERSION "${${type}VERSION_INT}" OUTPUT_FORMAT HEXADECIMAL) if(${type}_VERSION_EXTRA) set(${type}_VERSION_STRING "${${type}_VERSION_WITHOUT_TWEAK}-${${type}_VERSION_EXTRA}") else() set(${type}_VERSION_STRING "${${type}_VERSION_WITHOUT_TWEAK}") endif() + set(${type}_VERSION_TWEAK_STRING "${${type}_VERSION_WITH_TWEAK}") + set(${type}_VERSION_EXTENDED_STRING "${${type}_VERSION_STRING}+${${type}_VERSION_TWEAK}") if(type STREQUAL KERNEL) set(PROJECT_VERSION_MAJOR ${${type}_VERSION_MAJOR}) @@ -118,5 +120,7 @@ foreach(type file IN ZIP_LISTS VERSION_TYPE VERSION_FILE) unset(MAJOR) unset(MINOR) unset(PATCH) + unset(TWEAK) unset(${type}_VERSION_WITHOUT_TWEAK) + unset(${type}_VERSION_WITH_TWEAK) endforeach() diff --git a/cmake/modules/zephyr_module.cmake b/cmake/modules/zephyr_module.cmake index 90afc1f02e5..191c71c193b 100644 --- a/cmake/modules/zephyr_module.cmake +++ b/cmake/modules/zephyr_module.cmake @@ -48,17 +48,13 @@ set(cmake_modules_file ${CMAKE_BINARY_DIR}/zephyr_modules.txt) set(cmake_sysbuild_file ${CMAKE_BINARY_DIR}/sysbuild_modules.txt) set(zephyr_settings_file ${CMAKE_BINARY_DIR}/zephyr_settings.txt) -if(WEST) - set(west_arg "--zephyr-base" ${ZEPHYR_BASE}) -endif() - if(WEST OR ZEPHYR_MODULES) # Zephyr module uses west, so only call it if west is installed or # ZEPHYR_MODULES was provided as argument to CMake. execute_process( COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/zephyr_module.py - ${west_arg} + --zephyr-base=${ZEPHYR_BASE} ${ZEPHYR_MODULES_ARG} ${EXTRA_ZEPHYR_MODULES_ARG} --kconfig-out ${kconfig_modules_file} @@ -141,6 +137,7 @@ if(WEST OR ZEPHYR_MODULES) zephyr_string(SANITIZE TOUPPER MODULE_NAME_UPPER ${module_name}) if(NOT ${MODULE_NAME_UPPER} STREQUAL CURRENT) + set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_NAME ${module_name}) set(ZEPHYR_${MODULE_NAME_UPPER}_MODULE_DIR ${module_path}) set(ZEPHYR_${MODULE_NAME_UPPER}_CMAKE_DIR ${cmake_path}) else() diff --git a/cmake/sca/codechecker/sca.cmake b/cmake/sca/codechecker/sca.cmake index c7cf6325c40..87b6015ae84 100644 --- a/cmake/sca/codechecker/sca.cmake +++ b/cmake/sca/codechecker/sca.cmake @@ -3,7 +3,7 @@ # Copyright (c) 2023, Basalte bv find_program(CODECHECKER_EXE CodeChecker REQUIRED) -message(STATUS "Found CodeChecker: ${CODECHECKER_EXE}") +message(STATUS "Found SCA: CodeChecker (${CODECHECKER_EXE})") # CodeChecker uses the compile_commands.json as input set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/cmake/sca/cpptest/sca.cmake b/cmake/sca/cpptest/sca.cmake new file mode 100644 index 00000000000..cc226345d1c --- /dev/null +++ b/cmake/sca/cpptest/sca.cmake @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024, Space Cubics, LLC. + +find_program(CPPTESTSCAN cpptestscan REQUIRED) +message(STATUS "Found SCA: Parasoft C/C++test (${CPPTESTSCAN})") + +set(output_dir ${CMAKE_BINARY_DIR}/sca/cpptest) +file(MAKE_DIRECTORY ${output_dir}) + +set(output_file ${output_dir}/cpptestscan.bdf) +set(output_arg --cpptestscanOutputFile=${output_file}) + +set(CMAKE_C_COMPILER_LAUNCHER ${CPPTESTSCAN} ${output_arg} CACHE INTERNAL "") +set(CMAKE_CXX_COMPILER_LAUNCHER ${CPPTESTSCAN} ${output_arg} CACHE INTERNAL "") diff --git a/cmake/sca/gcc/sca.cmake b/cmake/sca/gcc/sca.cmake new file mode 100644 index 00000000000..c106933c101 --- /dev/null +++ b/cmake/sca/gcc/sca.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024 Intel Corporation + +list(APPEND TOOLCHAIN_C_FLAGS -fanalyzer) diff --git a/cmake/sca/sparse/sca.cmake b/cmake/sca/sparse/sca.cmake index 21511b07baa..356364997e6 100644 --- a/cmake/sca/sparse/sca.cmake +++ b/cmake/sca/sparse/sca.cmake @@ -3,7 +3,7 @@ # Copyright (c) 2022, Nordic Semiconductor ASA find_program(SPARSE_COMPILER cgcc REQUIRED) -message(STATUS "Found sparse: ${SPARSE_COMPILER}") +message(STATUS "Found SCA: sparse (${SPARSE_COMPILER})") # Create sparse.cmake which will be called as compiler launcher. # sparse.cmake will ensure that REAL_CC is set correctly in environment before diff --git a/cmake/sca/sparse/sparse.template b/cmake/sca/sparse/sparse.template index 8fde837aa26..b54d3e9ed14 100644 --- a/cmake/sca/sparse/sparse.template +++ b/cmake/sca/sparse/sparse.template @@ -16,4 +16,6 @@ endforeach() foreach(i RANGE ${end_of_options} ${CMAKE_ARGC}) list(APPEND ARGS ${CMAKE_ARGV${i}}) endforeach() -execute_process(COMMAND @CMAKE_COMMAND@ -E env REAL_CC=@CMAKE_C_COMPILER@ @SPARSE_COMPILER@ ${ARGS}) +execute_process(COMMAND @CMAKE_COMMAND@ -E env REAL_CC=@CMAKE_C_COMPILER@ @SPARSE_COMPILER@ ${ARGS} + COMMAND_ERROR_IS_FATAL ANY +) diff --git a/cmake/toolchain/espressif/target.cmake b/cmake/toolchain/espressif/target.cmake index 35d2a01555a..7d6f7eddf16 100644 --- a/cmake/toolchain/espressif/target.cmake +++ b/cmake/toolchain/espressif/target.cmake @@ -12,7 +12,7 @@ set(CROSS_COMPILE_TARGET_xtensa_esp32s2 xtensa-esp32s2-elf) set(CROSS_COMPILE_TARGET_xtensa_esp32s3 xtensa-esp32s3-elf) set(CROSS_COMPILE_TARGET_riscv_esp32c3 riscv32-esp-elf) -set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC}}) +set(CROSS_COMPILE_TARGET ${CROSS_COMPILE_TARGET_${ARCH}_${CONFIG_SOC_SERIES}}) set(SYSROOT_TARGET ${CROSS_COMPILE_TARGET}) if(ESPRESSIF_DEPRECATED_PATH) diff --git a/cmake/usage/usage.cmake b/cmake/usage/usage.cmake index 9472f2fa9bb..2f4b0b76ddd 100644 --- a/cmake/usage/usage.cmake +++ b/cmake/usage/usage.cmake @@ -27,6 +27,7 @@ message(" debugserver - Run \"west debugserver\" (or start GDB server on port message(" attach - Run \"west attach\"") message(" ram_report - Build and create RAM usage report") message(" rom_report - Build and create ROM usage report") +message(" initlevels - Display the initialization sequence") message(" boards - Display supported boards") message(" shields - Display supported shields") message(" usage - Display this text") diff --git a/doc/_doxygen/doxygen-awesome-darkmode-toggle.js b/doc/_doxygen/doxygen-awesome-darkmode-toggle.js index ae72bf7ec6e..4b4d92d4923 100644 --- a/doc/_doxygen/doxygen-awesome-darkmode-toggle.js +++ b/doc/_doxygen/doxygen-awesome-darkmode-toggle.js @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,19 +28,25 @@ SOFTWARE. */ class DoxygenAwesomeDarkModeToggle extends HTMLElement { + // SVG icons from https://fonts.google.com/icons + // Licensed under the Apache 2.0 license: + // https://www.apache.org/licenses/LICENSE-2.0.html + static lightModeIcon = `` + static darkModeIcon = `` + static title = "Toggle Light/Dark Mode" + static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" static _staticConstructor = function() { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) + DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference) // Update the color scheme when the browsers preference changes // without user interaction on the website. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() }) // Update the color scheme when the tab is made visible again. - // It is possible that the appearance was changed in another tab + // It is possible that the appearance was changed in another tab // while this tab was in the background. document.addEventListener("visibilitychange", visibilityState => { if (document.visibilityState === 'visible') { @@ -49,6 +55,32 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { }); }() + static init() { + $(function() { + $(document).ready(function() { + const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle') + toggleButton.title = DoxygenAwesomeDarkModeToggle.title + toggleButton.updateIcon() + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { + toggleButton.updateIcon() + }) + document.addEventListener("visibilitychange", visibilityState => { + if (document.visibilityState === 'visible') { + toggleButton.updateIcon() + } + }); + + $(document).ready(function(){ + document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) + }) + $(window).resize(function(){ + document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) + }) + }) + }) + } + constructor() { super(); this.onclick=this.toggleDarkMode @@ -65,7 +97,7 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { * @returns `true` for dark-mode, `false` for light-mode user preference */ static get userPreference() { - return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || + return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) } @@ -88,11 +120,12 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { } static enableDarkMode(enable) { - let head = document.getElementsByTagName('head')[0] if(enable) { + DoxygenAwesomeDarkModeToggle.darkModeEnabled = true document.documentElement.classList.add("dark-mode") document.documentElement.classList.remove("light-mode") } else { + DoxygenAwesomeDarkModeToggle.darkModeEnabled = false document.documentElement.classList.remove("dark-mode") document.documentElement.classList.add("light-mode") } @@ -109,6 +142,15 @@ class DoxygenAwesomeDarkModeToggle extends HTMLElement { toggleDarkMode() { DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference + this.updateIcon() + } + + updateIcon() { + if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) { + this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon + } else { + this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon + } } } diff --git a/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css b/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css index b988b6f05ed..7114a030435 100644 --- a/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css +++ b/doc/_doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css @@ -1,4 +1,3 @@ - /** Doxygen Awesome @@ -6,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doc/_doxygen/doxygen-awesome-sidebar-only.css b/doc/_doxygen/doxygen-awesome-sidebar-only.css index 526761db69a..853f6d6926e 100644 --- a/doc/_doxygen/doxygen-awesome-sidebar-only.css +++ b/doc/_doxygen/doxygen-awesome-sidebar-only.css @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -31,10 +31,16 @@ html { /* side nav width. MUST be = `TREEVIEW_WIDTH`. * Make sure it is wide enough to contain the page title (logo + title + version) */ - --side-nav-fixed-width: 340px; + --side-nav-fixed-width: 335px; --menu-display: none; --top-height: 120px; + --toc-sticky-top: -25px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px); +} + +#projectname { + white-space: nowrap; } @@ -64,6 +70,7 @@ html { height: var(--top-height); margin-bottom: calc(0px - var(--top-height)); max-width: var(--side-nav-fixed-width); + overflow: hidden; background: var(--side-nav-background); } #main-nav { @@ -74,6 +81,7 @@ html { .ui-resizable-handle { cursor: default; width: 1px !important; + background: var(--separator-color); box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color); } diff --git a/doc/_doxygen/doxygen-awesome.css b/doc/_doxygen/doxygen-awesome.css index 8414dcbf651..05ecbfe94c1 100644 --- a/doc/_doxygen/doxygen-awesome.css +++ b/doc/_doxygen/doxygen-awesome.css @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,15 +30,13 @@ SOFTWARE. html { /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ --primary-color: #1779c4; - --primary-dark-color: #00559f; - --primary-light-color: #7aabd6; - --primary-lighter-color: #cae1f1; - --primary-lightest-color: #e9f1f8; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; /* page base colors */ - --page-background-color: white; - --page-foreground-color: #2c3e50; - --page-secondary-foreground-color: #67727e; + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; /* color for all separators on the website: hr, borders, ... */ --separator-color: #dedede; @@ -53,49 +51,57 @@ html { --spacing-medium: 10px; --spacing-large: 16px; - /* default box shadow used for raising an element above the normal content. Used in dropdowns, Searchresult, ... */ - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.1); + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); - --odd-color: rgba(0,0,0,.03); + --odd-color: rgba(0,0,0,.028); /* font-families. will affect all text on the website * font-family: the normal font for text, headlines, menus * font-family-monospace: used for preformatted text in memtitle, code, fragments */ --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; - --font-family-monospace: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; /* font sizes */ --page-font-size: 15.6px; --navigation-font-size: 14.4px; - --code-font-size: 14.4px; /* affects code, fragment */ + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ --title-font-size: 22px; /* content text properties. These only affect the page content, not the navigation or any other ui elements */ --content-line-height: 27px; /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ - --content-maxwidth: 1000px; + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); /* colors for various content boxes: @warning, @note, @deprecated @bug */ - --warning-color: #fca49b; - --warning-color-dark: #b61825; - --warning-color-darker: #75070f; - --note-color: rgba(255,229,100,.3); - --note-color-dark: #c39900; - --note-color-darker: #8d7400; - --deprecated-color: rgb(214, 216, 224); + --warning-color: #faf3d8; + --warning-color-dark: #f3a600; + --warning-color-darker: #5f4204; + --note-color: #e4f3ff; + --note-color-dark: #1879C4; + --note-color-darker: #274a5c; + --todo-color: #e4dafd; + --todo-color-dark: #5b2bdd; + --todo-color-darker: #2a0d72; + --deprecated-color: #ecf0f3; --deprecated-color-dark: #5b6269; --deprecated-color-darker: #43454a; - --bug-color: rgb(246, 208, 178); - --bug-color-dark: #a53a00; - --bug-color-darker: #5b1d00; - --invariant-color: #b7f8d0; - --invariant-color-dark: #00ba44; - --invariant-color-darker: #008622; + --bug-color: #f8d1cc; + --bug-color-dark: #b61825; + --bug-color-darker: #75070f; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; /* blockquote colors */ - --blockquote-background: #f5f5f5; - --blockquote-foreground: #727272; + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; /* table colors */ --tablehead-background: #f1f1f1; @@ -124,24 +130,25 @@ html { * on smaller screens the searchbar will always fill the entire screen width) */ --searchbar-height: 33px; --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); /* code block colors */ --code-background: #f5f5f5; --code-foreground: var(--page-foreground-color); /* fragment colors */ - --fragment-background: #282c34; - --fragment-foreground: #ffffff; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; --fragment-lineheight: 20px; /* sidebar navigation (treeview) colors */ @@ -150,16 +157,27 @@ html { --side-nav-arrow-opacity: 0; --side-nav-arrow-hover-opacity: 0.9; - /* height of an item in any tree / collapsable table */ + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsible table */ --tree-item-height: 30px; - --darkmode-toggle-button-icon: '☀️' + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); + + --animation-duration: .12s } @media screen and (max-width: 767px) { html { --page-font-size: 16px; --navigation-font-size: 16px; + --toc-font-size: 15px; --code-font-size: 15px; /* affects code, fragment */ --title-font-size: 22px; } @@ -170,44 +188,59 @@ html { color-scheme: dark; --primary-color: #1982d2; - --primary-dark-color: #5ca8e2; + --primary-dark-color: #86a9c4; --primary-light-color: #4779ac; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35); + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); - --odd-color: rgba(0,0,0,.1); + --odd-color: rgba(100,100,100,.06); --menu-selected-background: rgba(0,0,0,.4); --page-background-color: #1C1D1F; --page-foreground-color: #d2dbde; --page-secondary-foreground-color: #859399; - --separator-color: #000000; + --separator-color: #38393b; --side-nav-background: #252628; --code-background: #2a2c2f; --tablehead-background: #2a2c2f; - --blockquote-background: #1f2022; - --blockquote-foreground: #77848a; - - --warning-color: #b61825; - --warning-color-dark: #510a02; - --warning-color-darker: #f5b1aa; - --note-color: rgb(255, 183, 0); - --note-color-dark: #9f7300; - --note-color-darker: #645b39; - --deprecated-color: rgb(88, 90, 96); - --deprecated-color-dark: #262e37; - --deprecated-color-darker: #a0a5b0; - --bug-color: rgb(248, 113, 0); - --bug-color-dark: #812a00; - --bug-color-darker: #ffd3be; - - --darkmode-toggle-button-icon: '🌛'; + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; } } @@ -216,44 +249,59 @@ html.dark-mode { color-scheme: dark; --primary-color: #1982d2; - --primary-dark-color: #5ca8e2; + --primary-dark-color: #86a9c4; --primary-light-color: #4779ac; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - --box-shadow: 0 2px 10px 0 rgba(0,0,0,.35); + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); - --odd-color: rgba(0,0,0,.1); + --odd-color: rgba(100,100,100,.06); --menu-selected-background: rgba(0,0,0,.4); --page-background-color: #1C1D1F; --page-foreground-color: #d2dbde; --page-secondary-foreground-color: #859399; - --separator-color: #000000; + --separator-color: #38393b; --side-nav-background: #252628; --code-background: #2a2c2f; --tablehead-background: #2a2c2f; - --blockquote-background: #1f2022; - --blockquote-foreground: #77848a; + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #3b2e04; + --warning-color-dark: #f1b602; + --warning-color-darker: #ceb670; + --note-color: #163750; + --note-color-dark: #1982D2; + --note-color-darker: #dcf0fa; + --todo-color: #2a2536; + --todo-color-dark: #7661b3; + --todo-color-darker: #ae9ed6; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2e1917; + --bug-color-dark: #ad2617; + --bug-color-darker: #f5b1aa; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; - --warning-color: #b61825; - --warning-color-dark: #510a02; - --warning-color-darker: #f5b1aa; - --note-color: rgb(255, 183, 0); - --note-color-dark: #9f7300; - --note-color-darker: #645b39; - --deprecated-color: rgb(88, 90, 96); - --deprecated-color-dark: #262e37; - --deprecated-color-darker: #a0a5b0; - --bug-color: rgb(248, 113, 0); - --bug-color-dark: #812a00; - --bug-color-darker: #ffd3be; - - --darkmode-toggle-button-icon: '🌛'; + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; } body { @@ -262,25 +310,37 @@ body { font-size: var(--page-font-size); } -body, table, div, p, dl, #nav-tree .label, .title, .sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, .SelectItem, #MSearchField, .navpath li.navelem a, .navpath li.navelem a:hover { +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition { font-family: var(--font-family); } h1, h2, h3, h4, h5 { - margin-top: .9em; + margin-top: 1em; font-weight: 600; line-height: initial; } -p, div, table, dl { +p, div, table, dl, p.reference, p.definition { font-size: var(--page-font-size); } +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + a:link, a:visited, a:hover, a:focus, a:active { color: var(--primary-color) !important; font-weight: 500; } +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + /* Title and top navigation */ @@ -356,10 +416,23 @@ a:link, a:visited, a:hover, a:focus, a:active { margin-bottom: -1px; } +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + @media screen and (max-width: 767px) { .sm-dox a span.sub-arrow { background: var(--code-background); } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } } @media screen and (min-width: 768px) { @@ -434,6 +507,7 @@ a:link, a:visited, a:hover, a:focus, a:active { color: var(--header-foreground) !important; font-weight: normal; font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; } .sm-dox a:focus { @@ -470,7 +544,7 @@ a:link, a:visited, a:hover, a:focus, a:active { #MSearchBox { height: var(--searchbar-height); background: var(--searchbar-background); - border-radius: var(--searchbar-height); + border-radius: var(--searchbar-border-radius); border: 1px solid var(--separator-color); overflow: hidden; width: var(--searchbar-width); @@ -480,8 +554,27 @@ a:link, a:visited, a:hover, a:focus, a:active { margin-top: 0; } -.left #MSearchSelect { +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; } .tabs .left #MSearchSelect { @@ -536,12 +629,9 @@ a:link, a:visited, a:hover, a:focus, a:active { top: calc(calc(var(--searchbar-height) / 2) - 11px); } -.left #MSearchSelect { - padding-left: 8px; -} - #MSearchBox span.left, #MSearchBox span.right { background: none; + background-image: none; } #MSearchBox span.right { @@ -595,11 +685,22 @@ html.dark-mode iframe#MSearchResults { filter: invert() hue-rotate(180deg); } +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + #MSearchSelectWindow { border: 1px solid var(--separator-color); border-radius: var(--border-radius-medium); box-shadow: var(--box-shadow); background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); } #MSearchSelectWindow a.SelectItem { @@ -649,6 +750,7 @@ html.dark-mode iframe#MSearchResults { overflow: auto; transform: translate(0, 20px); animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; } /* @@ -676,6 +778,8 @@ html.dark-mode iframe#MSearchResults { #side-nav { padding: 0 !important; background: var(--side-nav-background); + min-width: 8px; + max-width: 50vw; } @media screen and (max-width: 767px) { @@ -685,13 +789,12 @@ html.dark-mode iframe#MSearchResults { #doc-content { margin-left: 0 !important; - height: auto !important; - padding-bottom: calc(2 * var(--spacing-large)); } } #nav-tree { background: transparent; + margin-right: 1px; } #nav-tree .label { @@ -704,17 +807,31 @@ html.dark-mode iframe#MSearchResults { } #nav-sync { - top: 12px !important; + bottom: 12px; right: 12px; + top: auto !important; + user-select: none; } #nav-tree .selected { text-shadow: none; background-image: none; background-color: transparent; - box-shadow: inset 4px 0 0 0 var(--primary-color); + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); } + #nav-tree a { color: var(--side-nav-foreground) !important; font-weight: normal; @@ -750,8 +867,9 @@ html.dark-mode iframe#MSearchResults { } .ui-resizable-e { - background: var(--separator-color); - width: 1px; + width: 4px; + background: transparent; + box-shadow: inset -1px 0 0 0 var(--separator-color); } /* @@ -764,6 +882,21 @@ div.header { background-image: none; } +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + div.contents, div.header .title, div.header .summary { max-width: var(--content-maxwidth); } @@ -783,7 +916,7 @@ div.headertitle { div.header .title { font-weight: 600; - font-size: 210%; + font-size: 225%; padding: var(--spacing-medium) var(--spacing-large); word-break: break-word; } @@ -799,14 +932,6 @@ td.memSeparator { border-color: var(--separator-color); } -.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { - background: var(--code-background); -} - -.mdescRight { - color: var(--page-secondary-foreground-color); -} - span.mlabel { background: var(--primary-color); border: none; @@ -834,34 +959,82 @@ div.contents div.dyncontent { @media (prefers-color-scheme: dark) { html:not(.light-mode) div.contents div.dyncontent img, html:not(.light-mode) div.contents center img, - html:not(.light-mode) div.contents table img, + html:not(.light-mode) div.contents > table img, html:not(.light-mode) div.contents div.dyncontent iframe, html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); + html:not(.light-mode) div.contents table iframe, + html:not(.light-mode) div.contents .dotgraph iframe { + filter: brightness(89%) hue-rotate(180deg) invert(); } } html.dark-mode div.contents div.dyncontent img, html.dark-mode div.contents center img, -html.dark-mode div.contents table img, +html.dark-mode div.contents > table img, html.dark-mode div.contents div.dyncontent iframe, html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); +html.dark-mode div.contents table iframe, +html.dark-mode div.contents .dotgraph iframe + { + filter: brightness(89%) hue-rotate(180deg) invert(); } h2.groupheader { - border-bottom: 1px solid var(--separator-color); + border-bottom: 0px; color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); } blockquote { - padding: var(--spacing-small) var(--spacing-medium); + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); background: var(--blockquote-background); color: var(--blockquote-foreground); - border-left: 2px solid var(--blockquote-foreground); - margin: 0; + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; } blockquote p { @@ -872,62 +1045,156 @@ blockquote p { color: var(--primary-dark-color); } -.glow { - text-shadow: 0 0 15px var(--primary-light-color) !important; +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); } .alphachar a { color: var(--page-foreground-color); } +.dotgraph { + max-width: 100%; + overflow-x: scroll; +} + +.dotgraph .caption { + position: sticky; + left: 0; +} + +/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */ +.interactive_dotgraph .dotgraph iframe { + max-width: 100%; +} + /* Table of Contents */ -div.toc { - background-color: var(--side-nav-background); - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - box-shadow: var(--box-shadow); +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); padding: 0 var(--spacing-large); - margin: 0 0 var(--spacing-medium) var(--spacing-medium); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); } div.toc h3 { - color: var(--side-nav-foreground); + color: var(--toc-foreground); font-size: var(--navigation-font-size); - margin: var(--spacing-large) 0; + margin: var(--spacing-large) 0 var(--spacing-medium) 0; } div.toc li { - font-size: var(--navigation-font-size); padding: 0; background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; } -div.toc li:before { - content: '↓'; - font-weight: 800; - font-family: var(--font-family); - margin-right: var(--spacing-small); - color: var(--side-nav-foreground); - opacity: .4; +div.toc li::before { + display: none; } -div.toc ul li.level1 { - margin: 0; +div.toc ul { + margin-top: 0 } -div.toc ul li.level2, div.toc ul li.level3 { - margin-top: 0; +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; } -@media screen and (max-width: 767px) { - div.toc { +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; float: none; width: auto; margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform var(--animation-duration) ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; } } @@ -937,7 +1204,7 @@ div.toc ul li.level2, div.toc ul li.level3 { code, div.fragment, pre.fragment { border-radius: var(--border-radius-small); - border: none; + border: 1px solid var(--separator-color); overflow: hidden; } @@ -946,12 +1213,11 @@ code { background: var(--code-background); color: var(--code-foreground); padding: 2px 6px; - word-break: break-word; } div.fragment, pre.fragment { margin: var(--spacing-medium) 0; - padding: 14px 16px; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); background: var(--fragment-background); color: var(--fragment-foreground); overflow-x: auto; @@ -961,24 +1227,49 @@ div.fragment, pre.fragment { div.fragment, pre.fragment { border-top-right-radius: 0; border-bottom-right-radius: 0; + border-right: 0; } - .contents > div.fragment, .textblock > div.fragment, .textblock > pre.fragment { + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .textblock > .tabbed > ul > li > div.fragment, + .textblock > .tabbed > ul > li > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .tabbed > ul > li > .doxygen-awesome-fragment-wrapper > pre.fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-large)); border-radius: 0; + border-left: 0; } - .textblock li > .fragment { + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-large)); } - .memdoc li > .fragment { + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); } - .memdoc > div.fragment, .memdoc > pre.fragment, dl dd > div.fragment, dl dd pre.fragment { + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); border-radius: 0; + border-left: 0; } } @@ -1038,15 +1329,29 @@ div.fragment span.lineno a { color: var(--fragment-link) !important; } -div.fragment .line:first-child .lineno { +div.fragment > .line:first-child .lineno { box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); + background-color: var(--fragment-linenumber-background) !important; +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; } /* dl warning, attention, note, deprecated, bug, ... */ -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre { +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { padding: var(--spacing-medium); margin: var(--spacing-medium) 0; color: var(--page-background-color); @@ -1069,16 +1374,30 @@ dl.warning dt, dl.attention dt { color: var(--warning-color-dark); } -dl.note { +dl.note, dl.remark { background: var(--note-color); border-left: 8px solid var(--note-color-dark); color: var(--note-color-darker); } -dl.note dt { +dl.note dt, dl.remark dt { color: var(--note-color-dark); } +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + dl.bug { background: var(--bug-color); border-left: 8px solid var(--bug-color-dark); @@ -1099,16 +1418,20 @@ dl.deprecated dt a { color: var(--deprecated-color-dark) !important; } -dl.section dd, dl.bug dd, dl.deprecated dd { +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { margin-inline-start: 0px; } -dl.invariant, dl.pre { +dl.invariant, dl.pre, dl.post { background: var(--invariant-color); border-left: 8px solid var(--invariant-color-dark); color: var(--invariant-color-darker); } +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + /* memitem */ @@ -1126,32 +1449,63 @@ div.memdoc { h2.memtitle, div.memitem { border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; } div.memproto, h2.memtitle { - background: var(--code-background); - text-shadow: none; + background: var(--fragment-background); } h2.memtitle { font-weight: 500; - font-family: monospace, fixed; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); border-bottom: none; border-top-left-radius: var(--border-radius-medium); border-top-right-radius: var(--border-radius-medium); word-break: break-all; + position: relative; } -a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { - border-color: var(--primary-light-color); +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; } -a:target + h2.memtitle { - box-shadow: -3px -3px 3px 0 var(--primary-lightest-color), 3px -3px 3px 0 var(--primary-lightest-color); +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; } -a:target + h2.memtitle + div.memitem { - box-shadow: 0 0 10px 0 var(--primary-lighter-color); +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); } div.memitem { @@ -1180,8 +1534,18 @@ div.memtitle { } div.memproto table.memname { - font-family: monospace, fixed; + font-family: var(--font-family-monospace); color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; } table.mlabels, table.mlabels > tbody { @@ -1192,6 +1556,12 @@ td.mlabels-left { width: auto; } +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + table.mlabels > tbody > tr:first-child { display: flex; justify-content: space-between; @@ -1241,56 +1611,361 @@ dl.reflist dd { Table */ -table.markdownTable, table.fieldtable { - width: 100%; - border: 1px solid var(--separator-color); +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.markdownTable, table.doxtable, table.fieldtable { + padding: 1px; +} + +table.doxtable caption { + display: block; } table.fieldtable { - box-shadow: none; - border-radius: var(--border-radius-small); + border-collapse: collapse; + width: 100%; } -th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { background: var(--tablehead-background); color: var(--tablehead-foreground); font-weight: 600; font-size: var(--page-font-size); } -table.markdownTable td, table.markdownTable th, table.fieldtable dt { +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { border: 1px solid var(--separator-color); padding: var(--spacing-small) var(--spacing-medium); } +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: block; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: table; + width: 100%; +} + table.fieldtable th { font-size: var(--page-font-size); font-weight: 600; background-image: none; background-color: var(--tablehead-background); color: var(--tablehead-foreground); - border-bottom: 1px solid var(--separator-color); } -.fieldtable td.fieldtype, .fieldtable td.fieldname { +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { border-bottom: 1px solid var(--separator-color); border-right: 1px solid var(--separator-color); } -.fieldtable td.fielddoc { - border-bottom: 1px solid var(--separator-color); +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); } -.memberdecls td.glow, .fieldtable tr.glow { - background-color: var(--primary-light-color); - box-shadow: 0 0 15px var(--primary-lighter-color); +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; } table.memberdecls { display: block; - overflow-x: auto; - overflow-y: hidden; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform var(--animation-duration) ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } } @@ -1301,15 +1976,33 @@ table.memberdecls { hr { margin-top: var(--spacing-large); margin-bottom: var(--spacing-large); - border-top:1px solid var(--separator-color); + height: 1px; + background-color: var(--separator-color); + border: 0; } .contents hr { - box-shadow: var(--content-maxwidth) 0 0 0 var(--separator-color), calc(0px - var(--content-maxwidth)) 0 0 0 var(--separator-color); + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); } -.contents img { +.contents img, .contents .center, .contents center, .contents div.image object { max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } } /* @@ -1325,18 +2018,42 @@ table.directory { font-family: var(--font-family); font-size: var(--page-font-size); font-weight: normal; + width: 100%; } -.directory td.entry { - padding: var(--spacing-small); - display: flex; - align-items: center; +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; } -.directory tr.even { +table.directory tr.even { background-color: var(--odd-color); } +table.directory tr.odd { + background-color: transparent; +} + .icona { width: auto; height: auto; @@ -1345,14 +2062,20 @@ table.directory { .icon { background: var(--primary-color); - width: 18px; - height: 18px; - line-height: 18px; + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; } .iconfopen, .icondoc, .iconfclosed { background-position: center; margin-bottom: 0; + height: var(--table-line-height); } .icondoc { @@ -1361,8 +2084,8 @@ table.directory { @media screen and (max-width: 767px) { div.directory { - margin-left: calc(0px - var(--spacing-medium)); - margin-right: calc(0px - var(--spacing-medium)); + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); } } @@ -1385,10 +2108,35 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { border-radius: var(--border-radius-small); } -@media screen and (max-width: 767px) { - .classindex { - margin: 0 calc(0px - var(--spacing-small)); - } +.classindex dl.even { + background-color: transparent; +} + +/* + Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; } /* @@ -1396,7 +2144,6 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { */ #nav-path { - margin-bottom: -1px; width: 100%; } @@ -1406,6 +2153,8 @@ html.dark-mode .iconfopen, html.dark-mode .iconfclosed { border: none; border-top: 1px solid var(--separator-color); border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); font-size: var(--navigation-font-size); } @@ -1418,6 +2167,7 @@ img.footer { } address.footer { + color: var(--page-secondary-foreground-color); margin-bottom: var(--spacing-large); } @@ -1457,7 +2207,7 @@ li.navelem:first-child:before { border-bottom-color: transparent; border-right-color: transparent; border-top-color: transparent; - transform: scaleY(4.2); + transform: translateY(-1px) scaleY(4.2); z-index: 10; margin-left: 6px; } @@ -1468,7 +2218,7 @@ li.navelem:first-child:before { border-bottom-color: transparent; border-right-color: transparent; border-top-color: transparent; - transform: scaleY(3.2); + transform: translateY(-1px) scaleY(3.2); margin-right: var(--spacing-small); } @@ -1476,6 +2226,106 @@ li.navelem:first-child:before { color: var(--primary-color); } +/* + Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar, +.contents .dotgraph::-webkit-scrollbar, +.contents .tabs-overview-container::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb, +.contents .dotgraph::-webkit-scrollbar-thumb, +.contents .tabs-overview-container::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb, +.contents .dotgraph:hover::-webkit-scrollbar-thumb, +.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track, +.contents .dotgraph::-webkit-scrollbar-track, +.contents .tabs-overview-container::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* + Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc, +.contents .dotgraph, +.contents .tabs-overview-container { + scrollbar-width: thin; +} + /* Optional Dark mode toggle button */ @@ -1488,17 +2338,332 @@ doxygen-awesome-dark-mode-toggle { height: var(--searchbar-height); background: none; border: none; - font-size: 23px; - border-radius: var(--border-radius-medium); + border-radius: var(--searchbar-height); vertical-align: middle; text-align: center; line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform var(--animation-duration) ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); } doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* + Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* + Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity var(--animation-duration) ease-in-out, color var(--animation-duration) ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} + +/* + Optional tab feature +*/ + +.tabbed ul { + padding-inline-start: 0px; + margin: 0; + padding: var(--spacing-small) 0; +} + +.tabbed li { + display: none; +} + +.tabbed li.selected { + display: block; +} + +.tabs-overview-container { + overflow-x: auto; + display: block; + overflow-y: visible; +} + +.tabs-overview { + border-bottom: 1px solid var(--separator-color); + display: flex; + flex-direction: row; +} + +@media screen and (max-width: 767px) { + .tabs-overview-container { + margin: 0 calc(0px - var(--spacing-large)); + } + .tabs-overview { + padding: 0 var(--spacing-large) + } +} + +.tabs-overview button.tab-button { + color: var(--page-foreground-color); + margin: 0; + border: none; + background: transparent; + padding: calc(var(--spacing-large) / 2) 0; + display: inline-block; + font-size: var(--page-font-size); + cursor: pointer; + box-shadow: 0 1px 0 0 var(--separator-color); + position: relative; + + -webkit-tap-highlight-color: transparent; +} + +.tabs-overview button.tab-button .tab-title::before { + display: block; + content: attr(title); + font-weight: 600; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.tabs-overview button.tab-button .tab-title { + float: left; + white-space: nowrap; + font-weight: normal; + padding: calc(var(--spacing-large) / 2) var(--spacing-large); + border-radius: var(--border-radius-medium); + transition: background-color var(--animation-duration) ease-in-out, font-weight var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button:not(:last-child) .tab-title { + box-shadow: 8px 0 0 -7px var(--separator-color); +} + +.tabs-overview button.tab-button:hover .tab-title { background: var(--separator-color); + box-shadow: none; +} + +.tabs-overview button.tab-button.active .tab-title { + font-weight: 600; +} + +.tabs-overview button.tab-button::after { + content: ''; + display: block; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 0; + width: 0%; + margin: 0 auto; + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + background-color: var(--primary-color); + transition: width var(--animation-duration) ease-in-out, height var(--animation-duration) ease-in-out; +} + +.tabs-overview button.tab-button.active::after { + width: 100%; + box-sizing: border-box; + height: 3px; +} + + +/* + Navigation Buttons +*/ + +.section_buttons:not(:empty) { + margin-top: calc(var(--spacing-large) * 3); +} + +.section_buttons table.markdownTable { + display: block; + width: 100%; +} + +.section_buttons table.markdownTable tbody { + display: table !important; + width: 100%; + box-shadow: none; + border-spacing: 10px; +} + +.section_buttons table.markdownTable td { + padding: 0; } -doxygen-awesome-dark-mode-toggle:after { - content: var(--darkmode-toggle-button-icon) +.section_buttons table.markdownTable th { + display: none; +} + +.section_buttons table.markdownTable tr.markdownTableHead { + border: none; +} + +.section_buttons tr th, .section_buttons tr td { + background: none; + border: none; + padding: var(--spacing-large) 0 var(--spacing-small); +} + +.section_buttons a { + display: inline-block; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + color: var(--page-secondary-foreground-color) !important; + text-decoration: none; + transition: color var(--animation-duration) ease-in-out, background-color var(--animation-duration) ease-in-out; +} + +.section_buttons a:hover { + color: var(--page-foreground-color) !important; + background-color: var(--odd-color); +} + +.section_buttons tr td.markdownTableBodyLeft a { + padding: var(--spacing-medium) var(--spacing-large) var(--spacing-medium) calc(var(--spacing-large) / 2); +} + +.section_buttons tr td.markdownTableBodyRight a { + padding: var(--spacing-medium) calc(var(--spacing-large) / 2) var(--spacing-medium) var(--spacing-large); +} + +.section_buttons tr td.markdownTableBodyLeft a::before, +.section_buttons tr td.markdownTableBodyRight a::after { + color: var(--page-secondary-foreground-color) !important; + display: inline-block; + transition: color .08s ease-in-out, transform .09s ease-in-out; +} + +.section_buttons tr td.markdownTableBodyLeft a::before { + content: '〈'; + padding-right: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyRight a::after { + content: '〉'; + padding-left: var(--spacing-large); +} + + +.section_buttons tr td.markdownTableBodyLeft a:hover::before { + color: var(--page-foreground-color) !important; + transform: translateX(-3px); +} + +.section_buttons tr td.markdownTableBodyRight a:hover::after { + color: var(--page-foreground-color) !important; + transform: translateX(3px); +} + +@media screen and (max-width: 450px) { + .section_buttons a { + width: 100%; + box-sizing: border-box; + } + + .section_buttons tr td:nth-of-type(1).markdownTableBodyLeft a { + border-radius: var(--border-radius-medium) 0 0 var(--border-radius-medium); + border-right: none; + } + + .section_buttons tr td:nth-of-type(2).markdownTableBodyRight a { + border-radius: 0 var(--border-radius-medium) var(--border-radius-medium) 0; + } } diff --git a/doc/_doxygen/footer.html b/doc/_doxygen/footer.html index 9d24d69b7be..efa3357e594 100644 --- a/doc/_doxygen/footer.html +++ b/doc/_doxygen/footer.html @@ -13,19 +13,5 @@ $generatedby doxygen $doxygenversion - diff --git a/doc/_doxygen/header.html b/doc/_doxygen/header.html index 4422349d766..06be6c6529d 100644 --- a/doc/_doxygen/header.html +++ b/doc/_doxygen/header.html @@ -13,6 +13,9 @@ + $treeview $search $mathjax diff --git a/doc/_extensions/zephyr/application.py b/doc/_extensions/zephyr/application.py index 969e3290a59..5e012b43aa2 100644 --- a/doc/_extensions/zephyr/application.py +++ b/doc/_extensions/zephyr/application.py @@ -75,6 +75,10 @@ class ZephyrAppCommandsDirective(Directive): mostly useful for distinguishing builds for one application within a single page. + \:build-dir-fmt: + if set, assume that "west config build.dir-fmt" has been set to this + path. Exclusive with 'build-dir' and depends on 'tool=west'. + \:goals: a whitespace-separated list of what to do with the app (in 'build', 'flash', 'debug', 'debugserver', 'run'). Commands to accomplish @@ -113,6 +117,7 @@ class ZephyrAppCommandsDirective(Directive): 'gen-args': directives.unchanged, 'build-args': directives.unchanged, 'build-dir': directives.unchanged, + 'build-dir-fmt': directives.unchanged, 'goals': directives.unchanged_required, 'maybe-skip-config': directives.flag, 'compact': directives.flag, @@ -143,6 +148,7 @@ def run(self): gen_args = self.options.get('gen-args', None) build_args = self.options.get('build-args', None) build_dir_append = self.options.get('build-dir', '').strip('/') + build_dir_fmt = self.options.get('build-dir-fmt', None) goals = self.options.get('goals').split() skip_config = 'maybe-skip-config' in self.options compact = 'compact' in self.options @@ -156,6 +162,12 @@ def run(self): if app and zephyr_app: raise self.error('Both app and zephyr-app options were given.') + if build_dir_append != '' and build_dir_fmt: + raise self.error('Both build-dir and build-dir-fmt options were given.') + + if build_dir_fmt and tool != 'west': + raise self.error('build-dir-fmt is only supported for the west build tool.') + if generator not in self.GENERATORS: raise self.error('Unknown generator {}; choose from: {}'.format( generator, self.GENERATORS)) @@ -195,6 +207,7 @@ def run(self): 'gen_args': gen_args, 'build_args': build_args, 'build_dir': build_dir, + 'build_dir_fmt': build_dir_fmt, 'goals': goals, 'compact': compact, 'skip_config': skip_config, @@ -248,6 +261,7 @@ def _generate_west(self, **kwargs): goals = kwargs['goals'] cd_into = kwargs['cd_into'] build_dir = kwargs['build_dir'] + build_dir_fmt = kwargs['build_dir_fmt'] compact = kwargs['compact'] west_args = kwargs['west_args'] flash_args = kwargs['flash_args'] @@ -261,7 +275,15 @@ def _generate_west(self, **kwargs): # ignore zephyr_app since west needs to run within # the installation. Instead rely on relative path. src = ' {}'.format(app) if app and not cd_into else '' - dst = ' -d {}'.format(build_dir) if build_dir != 'build' else '' + + if build_dir_fmt is None: + dst = ' -d {}'.format(build_dir) if build_dir != 'build' else '' + build_dst = dst + else: + app_name = app.split('/')[-1] + build_dir_formatted = build_dir_fmt.format(app=app_name, board=board, source_dir=app) + dst = ' -d {}'.format(build_dir_formatted) + build_dst = '' if in_tree and not compact: content.append(in_tree) @@ -280,7 +302,7 @@ def _generate_west(self, **kwargs): # # For now, this keeps the resulting commands working. content.append('west build -b {}{}{}{}{}'. - format(board, west_args, dst, src, cmake_args)) + format(board, west_args, build_dst, src, cmake_args)) # If we're signing, we want to do that next, so that flashing # etc. commands can use the signed file which must be created diff --git a/doc/_extensions/zephyr/domain.py b/doc/_extensions/zephyr/domain.py index 053965e26e3..66327f9c7ad 100644 --- a/doc/_extensions/zephyr/domain.py +++ b/doc/_extensions/zephyr/domain.py @@ -80,9 +80,6 @@ class ConvertCodeSampleNode(SphinxTransform): default_priority = 100 def apply(self): - if not self.config.zephyr_domain_apply_transforms: - return - matcher = NodeMatcher(CodeSampleNode) for node in self.document.traverse(matcher): self.convert_node(node) @@ -143,9 +140,6 @@ class ProcessRelatedCodeSamplesNode(SphinxPostTransform): default_priority = 5 # before ReferencesResolver def run(self, **kwargs: Any) -> None: - if not self.config.zephyr_domain_apply_transforms: - return - matcher = NodeMatcher(RelatedCodeSamplesNode) for node in self.document.traverse(matcher): id = node["id"] # the ID of the node is the name of the doxygen group for which we @@ -315,14 +309,14 @@ class CustomDoxygenGroupDirective(DoxygenGroupDirective): def run(self) -> List[Node]: nodes = super().run() - if self.config.zephyr_domain_apply_transforms: + if self.config.zephyr_breathe_insert_related_samples: return [RelatedCodeSamplesNode(id=self.arguments[0]), *nodes] else: return nodes def setup(app): - app.add_config_value("zephyr_domain_apply_transforms", False, "env") + app.add_config_value("zephyr_breathe_insert_related_samples", False, "env") app.add_domain(ZephyrDomain) diff --git a/doc/_extensions/zephyr/gh_utils.py b/doc/_extensions/zephyr/gh_utils.py index 2c992436c87..f2795e88496 100644 --- a/doc/_extensions/zephyr/gh_utils.py +++ b/doc/_extensions/zephyr/gh_utils.py @@ -173,7 +173,8 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: Returns: Optional[Tuple[str, str]] -- Tuple with the date and SHA1 of the last commit made to the - page, or None if the page is not in the repo. + page, or None if the page is not in the repo (generated file, or manually authored file not + yet tracked by git). """ page_prefix = get_page_prefix(app, pagename) @@ -186,6 +187,15 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: app.env.doc2path(pagename, False), ) + # Check if the file is tracked by git + try: + subprocess.check_output( + ["git", "ls-files", "--error-unmatch", orig_path], + stderr=subprocess.STDOUT, + ) + except subprocess.CalledProcessError: + return None + try: date_and_sha1 = ( subprocess.check_output( @@ -212,7 +222,6 @@ def git_info_filter(app: Sphinx, pagename) -> Optional[Tuple[str, str]]: except subprocess.CalledProcessError: return None - def add_jinja_filter(app: Sphinx): if app.builder.format != "html": return diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index 0180d1f5373..b1d199a0d2f 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -13,9 +13,11 @@ """ REDIRECTS = [ + # zephyr-keep-sorted-start ('application/index', 'develop/application/index'), ('boards/x86/ehl_crb/doc/index', 'boards/x86/intel_ehl/doc/index'), ('boards/x86/rpl_crb/doc/index', 'boards/x86/intel_rpl/doc/index'), + ('connectivity/networking/networking-api-usage', 'connectivity/networking/api/index'), ('development_process/code_flow', 'project/code_flow'), ('development_process/index', 'project/index'), ('development_process/issues', 'project/issues'), @@ -31,10 +33,11 @@ ('guides/bluetooth/index', 'connectivity/bluetooth/index'), ('guides/bluetooth/sm-pics', 'connectivity/bluetooth/sm-pics'), ('guides/build/index', 'build/cmake/index'), - ('guides/build/kconfig/extensions', '/build/kconfig/extensions'), - ('guides/build/kconfig/menuconfig', '/build/kconfig/menuconfig'), - ('guides/build/kconfig/setting', '/build/kconfig/setting'), - ('guides/build/kconfig/tips', '/build/kconfig/tips'), + ('guides/build/kconfig/extensions', 'build/kconfig/extensions'), + ('guides/build/kconfig/menuconfig', 'build/kconfig/menuconfig'), + ('guides/build/kconfig/preprocessor-functions', 'build/kconfig/preprocessor-functions'), + ('guides/build/kconfig/setting', 'build/kconfig/setting'), + ('guides/build/kconfig/tips', 'build/kconfig/tips'), ('guides/coccinelle', 'develop/tools/coccinelle'), ('guides/code-relocation', 'kernel/code-relocation'), ('guides/crypto/index', 'services/crypto/index'), @@ -58,6 +61,12 @@ ('guides/flash_debug/host-tools', 'develop/flash_debug/host-tools'), ('guides/flash_debug/index', 'develop/flash_debug/index'), ('guides/flash_debug/probes', 'develop/flash_debug/probes'), + ('guides/kconfig/extensions', 'build/kconfig/extensions'), + ('guides/kconfig/index', 'build/kconfig/index'), + ('guides/kconfig/menuconfig', 'build/kconfig/menuconfig'), + ('guides/kconfig/preprocessor-functions', 'build/kconfig/preprocessor-functions'), + ('guides/kconfig/setting', 'build/kconfig/setting'), + ('guides/kconfig/tips', 'build/kconfig/tips'), ('guides/modules', 'develop/modules'), ('guides/networking/index', 'connectivity/networking/index'), ('guides/optimizations/index', 'develop/optimizations/index'), @@ -71,7 +80,6 @@ ('guides/pm/power_domain', 'services/pm/power_domain'), ('guides/pm/system', 'services/pm/system'), ('guides/portability/index', 'services/portability/index'), - ('guides/portability/posix', 'services/portability/posix'), ('guides/porting/arch', 'hardware/porting/arch'), ('guides/porting/board_porting', 'hardware/porting/board_porting'), ('guides/porting/index', 'hardware/porting/index'), @@ -165,4 +173,6 @@ ('reference/util/index', 'kernel/util/index'), ('samples/drivers/kscan_touch', 'samples/subsys/input/input'), ('samples/net/cloud/google_iot_mqtt', 'samples/net/cloud'), + ('services/portability/posix', 'services/portability/posix/index'), + # zephyr-keep-sorted-stop ] diff --git a/doc/_static/css/custom.css b/doc/_static/css/custom.css index 72756780b8e..a374fda4d37 100644 --- a/doc/_static/css/custom.css +++ b/doc/_static/css/custom.css @@ -163,105 +163,6 @@ a.icon-home:visited { color: var(--navbar-level-1-color); } -/* Sphinx Search extension */ -/* .wy-body-for-nav is used for higher rule specificity */ - -/* Search popup body */ -.wy-body-for-nav .search__outer { - background-color: var(--content-background-color); - border: 2px solid var(--content-background-color); -} -.wy-body-for-nav .search__cross svg { - fill: var(--body-color); -} - -.wy-body-for-nav .search__outer::-webkit-scrollbar-track { - border-radius: 10px; - background-color: var(--content-background-color); -} -.wy-body-for-nav .search__outer::-webkit-scrollbar { - width: 7px; - height: 7px; - background-color: var(--content-background-color); -} -.wy-body-for-nav .search__outer::-webkit-scrollbar-thumb { - border-radius: 10px; - background-color: var(--hr-color); -} - -/* Search input */ -.wy-body-for-nav .search__outer__input { - background-color: var(--search-input-background-color); - background-image: none; - border-radius: 50px; - border: 2px solid transparent; - color: var(--body-color); - height: 36px; - padding: 6px 12px; -} -.wy-body-for-nav .search__outer__input:focus { - border-color: var(--input-focus-border-color); -} -.wy-body-for-nav .search__outer .bar:after, -.wy-body-for-nav .search__outer .bar:before { - display: none; -} - -/* Search results item */ -.wy-body-for-nav .search__result__single { - border-bottom-color: var(--hr-color); -} -/* Search item title */ -.wy-body-for-nav .search__result__title { - color: var(--link-color); - border-bottom: none; - font-size: 120%; - font-weight: 400; -} - -/* Search item section */ -.wy-body-for-nav .outer_div_page_results:hover, -.wy-body-for-nav .search__result__box .active { - background-color: var(--search-active-color); -} -.wy-body-for-nav .search__result__subheading{ - color: var(--body-color); - font-size: 100%; - font-weight: 400; -} -.wy-body-for-nav .search__result__content { - color: var(--footer-color); -} - -/* Search item matching substring */ -.wy-body-for-nav .search__outer .search__result__title span, -.wy-body-for-nav .search__outer .search__result__content span { - color: var(--search-match-color); - border-bottom: 1px solid var(--search-match-color); - background-color: var(--search-match-background-color); - padding: 0 2px; -} -.wy-body-for-nav .search__result__subheading span { - border-bottom-color: var(--body-color); -} - -/* Search empty results */ -/* The original styles are inlined, see https://github.com/readthedocs/readthedocs-sphinx-search/issues/48 */ -.wy-body-for-nav .search__result__box { - color: var(--body-color) !important; -} - -/* Search footer & credits */ -.wy-body-for-nav .rtd__search__credits { - background-color: var(--search-credits-background-color); - border-color: var(--search-credits-background-color); - color: var(--search-credits-color); - padding: 4px 8px; -} -.wy-body-for-nav .rtd__search__credits a { - color: var(--search-credits-link-color); -} - /* Main sections */ .wy-nav-content-wrap { @@ -651,7 +552,10 @@ kbd, .kbd, background-color: var(--navbar-background-color-active); } -.wy-side-nav-search input[type="text"] { +.wy-side-nav-search input[type=search] { + width: 100%; + border-radius: 50px; + padding: 6px 12px; background-color: var(--input-background-color); color: var(--body-color); /* Avoid reflowing when toggling the focus state */ @@ -662,11 +566,11 @@ kbd, .kbd, font-size: 14px; } -.wy-side-nav-search input[type="text"]:focus { +.wy-side-nav-search input[type="search"]:focus { border: 2px solid var(--input-focus-border-color); } -.wy-side-nav-search input[type="text"]::placeholder { +.wy-side-nav-search input[type="search"]::placeholder { color: var(--body-color); opacity: 0.55; } @@ -988,3 +892,61 @@ dark-mode-toggle::part(toggleLabel){ font-size: 3rem; color: white; } + +/* Custom search box, including search engine selection */ + +.search-container { + position: relative; +} + +#search-se-settings-icon { + position: absolute; + color: var(--body-color); + right: 10px; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + opacity: 0.8; +} + +#search-se-menu { + display: none; + position: absolute; + font-size: 11px; + background-color: var(--input-background-color); + color: var(--body-color); + right: 0px; + top: 36px; + border: solid 1px var(--body-color); + border-radius: 10px; + z-index: 1000; +} + +#search-se-menu ul { + list-style: none; + margin: 0; + padding: 2px; +} + +#search-se-menu ul li { + padding: 8px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1em; +} + +#search-se-menu [role="menuitemradio"]:focus { + background-color: var(--navbar-current-background-color-hover); + color: var(--navbar-level-1-color); + border-radius: 10px; +} + +#search-se-menu ul li .fa-check { + display: none; + } + + #search-se-menu ul li.selected .fa-check { + display: inline; + } diff --git a/doc/_static/css/gcs.css b/doc/_static/css/gcs.css new file mode 100644 index 00000000000..16501108852 --- /dev/null +++ b/doc/_static/css/gcs.css @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023, Benjamin Cabé . + * SPDX-License-Identifier: Apache-2.0 + * + * Custom stylesheet for Google Programmable Search Engine results. + */ + +.gs-webResult .gs-snippet, +.gs-fileFormatType, +.gs-spelling, +.gsc-refinementHeader, +.gsc-result-info, +.gsc-orderby-label { + color: var(--body-color) !important; +} + +.gsc-control-cse { + width: 100%; + padding: 0 !important; + font-family: inherit !important; + font-size: inherit !important; + background-color: inherit !important; + border: none !important; + font-size: inherit !important; +} + +.gsc-completion-container { + font-family: inherit !important; +} + +.gs-result .gs-title, .gs-result .gs-title * { + color: var(--link-color) !important; + background-color: var(--content-background-color) !important; +} + +.gs-result .gs-title:visited, .gs-result .gs-title:visited * { + color: var(--link-color-visited) !important; +} + +.gsc-results .gsc-cursor-box .gsc-cursor-page, +.gsc-results .gsc-cursor-box .gsc-cursor-current-page { + background-color: var(--content-background-color) !important; + color: var(--link-color) !important; +} + +.gs-result .gs-image, .gs-result .gs-promotion-image { + border: none !important; + padding-right: .5em; +} + +.gsc-table-result { + font-family: inherit !important; + padding-top: .5em !important; + font-size: inherit !important; +} + +.gsc-tabHeader.gsc-tabhActive, .gsc-refinementHeader.gsc-refinementhActive, +.gsc-tabHeader.gsc-tabhInactive, .gsc-refinementHeader.gsc-refinementhInactive { + background-color: inherit !important; +} + +.gs-no-results-result .gs-snippet, .gs-error-result .gs-snippet { + color: var(--admonition-attention-title-color) !important; + background-color: var(--admonition-attention-title-background-color) !important; +} + +.gsc-webResult .gsc-result { + background-color: inherit !important; + margin: 0; + padding: .5em 0; + border: none !important; + border-bottom: 1px solid var(--hr-color) !important; +} + +.gs-webResult div.gs-per-result-labels { + margin-top: 1.3em; + margin-bottom: 0.3em; + font-size:0.8em; +} + +.gs-webResult div.gs-per-result-labels span { + display: none; +} + +.gs-webResult div.gs-per-result-labels a.gs-label { + text-decoration: none !important; + cursor: pointer; + padding: 0.4em 0.6em; + margin-left: .5em; + color: var(--admonition-tip-title-color) !important; + background-color: var(--admonition-tip-title-background-color) !important; + border-radius: 50px; +} + +.gcsc-find-more-on-google { + color: var(--link-color) !important; +} + +.gcsc-find-more-on-google-magnifier { + fill: var(--link-color) !important; +} diff --git a/doc/_static/js/custom.js b/doc/_static/js/custom.js new file mode 100644 index 00000000000..52f254b38c7 --- /dev/null +++ b/doc/_static/js/custom.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2020-2023, The Godot community + * Copyright (c) 2023, Benjamin Cabé + * SPDX-License-Identifier: CC-BY-3.0 + */ + + +// Handle page scroll and adjust sidebar accordingly. + +// Each page has two scrolls: the main scroll, which is moving the content of the page; +// and the sidebar scroll, which is moving the navigation in the sidebar. +// We want the logo to gradually disappear as the main content is scrolled, giving +// more room to the navigation on the left. This means adjusting the height +// available to the navigation on the fly. +const registerOnScrollEvent = (function(){ + // Configuration. + + // The number of pixels the user must scroll by before the logo is completely hidden. + const scrollTopPixels = 156; + // The target margin to be applied to the navigation bar when the logo is hidden. + const menuTopMargin = 54; + // The max-height offset when the logo is completely visible. + const menuHeightOffset_default = 210; + // The max-height offset when the logo is completely hidden. + const menuHeightOffset_fixed = 63; + // The distance between the two max-height offset values above; used for intermediate values. + const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); + + // Media query handler. + return function(mediaQuery) { + // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). + // This handler is executed when the result of the query evaluation changes, which means that + // the page has moved between "desktop" and "mobile" states. + + // When entering the "desktop" state, we register scroll events and adjust elements on the page. + // When entering the "mobile" state, we clean up any registered events and restore elements on the page + // to their initial state. + + const $window = $(window); + const $sidebar = $('.wy-side-scroll'); + const $search = $sidebar.children('.wy-side-nav-search'); + const $menu = $sidebar.children('.wy-menu-vertical'); + + if (mediaQuery.matches) { + // Entering the "desktop" state. + + // The main scroll event handler. + // Executed as the page is scrolled and once immediately as the page enters this state. + const handleMainScroll = (currentScroll) => { + if (currentScroll >= scrollTopPixels) { + // After the page is scrolled below the threshold, we fix everything in place. + $search.css('margin-top', `-${scrollTopPixels}px`); + $menu.css('margin-top', `${menuTopMargin}px`); + $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); + } + else { + // Between the top of the page and the threshold we calculate intermediate values + // to guarantee a smooth transition. + $search.css('margin-top', `-${currentScroll}px`); + $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); + + if (currentScroll > 0) { + const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; + const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; + $menu.css('max-height', `calc(100% - ${offsetValue}px)`); + } else { + $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); + } + } + }; + + // The sidebar scroll event handler. + // Executed as the sidebar is scrolled as well as after the main scroll. This is needed + // because the main scroll can affect the scrollable area of the sidebar. + const handleSidebarScroll = () => { + const menuElement = $menu.get(0); + const menuScrollTop = $menu.scrollTop(); + const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); + + // As the navigation is scrolled we add a shadow to the top bar hanging over it. + if (menuScrollTop > 0) { + $search.addClass('fixed-and-scrolled'); + } else { + $search.removeClass('fixed-and-scrolled'); + } + }; + + $search.addClass('fixed'); + + $window.scroll(function() { + handleMainScroll(window.scrollY); + handleSidebarScroll(); + }); + + $menu.scroll(function() { + handleSidebarScroll(); + }); + + handleMainScroll(window.scrollY); + handleSidebarScroll(); + } else { + // Entering the "mobile" state. + + $window.unbind('scroll'); + $menu.unbind('scroll'); + + $search.removeClass('fixed'); + + $search.css('margin-top', `0px`); + $menu.css('margin-top', `0px`); + $menu.css('max-height', 'initial'); + } + }; + })(); + + $(document).ready(() => { + // Initialize handlers for page scrolling and our custom sidebar. + const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); + + registerOnScrollEvent(mediaQuery); + mediaQuery.addListener(registerOnScrollEvent); + }); diff --git a/doc/_static/latex/preamble.tex b/doc/_static/latex/preamble.tex index 3213c955bdb..50ef29d4d2b 100644 --- a/doc/_static/latex/preamble.tex +++ b/doc/_static/latex/preamble.tex @@ -5,6 +5,7 @@ \usepackage[some]{background} \usepackage{sectsty} +\usepackage{pdflscape} \definecolor{bg-color}{HTML}{333f67} diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html index 54ba724acb3..757bb27529d 100644 --- a/doc/_templates/footer.html +++ b/doc/_templates/footer.html @@ -13,7 +13,7 @@

{%- set git_last_updated, sha1 = pagename | git_info | default((None, None), true) %} {%- if git_last_updated %} -
+

Help us keep our technical documentation accurate and up-to-date!

diff --git a/doc/_templates/gsearch.html b/doc/_templates/gsearch.html new file mode 100644 index 00000000000..1953466355b --- /dev/null +++ b/doc/_templates/gsearch.html @@ -0,0 +1,17 @@ +{%- extends "!search.html" %} + +{%- block scripts %} + {{ super.super() }} + +{%- endblock %} + +{% block footer %} + {{ super.super() }} +{% endblock %} + +{% block body %} +

{{ _('Search Results') }}

+ +
+{% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index 205b2488555..6d58c015548 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -1,12 +1,12 @@ {% extends "!layout.html" %} {% block document %} {% if is_release %} -
+
The latest development version of this page may be more current than this released {{ version }} version.
{% else %} -
+
This is the documentation for the latest (main) development branch of Zephyr. If you are looking for the documentation of previous releases, use the drop-down menu on the left and select the desired version. @@ -15,20 +15,22 @@ {{ super() }} {% endblock %} {% block menu %} - {% include "zversions.html" %} - {{ super() }} - {% if reference_links %} -
-

Reference

-
    - {% for title, url in reference_links.items() %} -
  • - {{ title }} -
  • - {% endfor %} -
+
+ {% include "zversions.html" %} + {{ super() }} + {% if reference_links %} +
+

Reference

+
    + {% for title, url in reference_links.items() %} +
  • + {{ title }} +
  • + {% endfor %} +
+
+ {% endif %}
- {% endif %} {% endblock %} {% block extrahead %} diff --git a/doc/_templates/searchbox.html b/doc/_templates/searchbox.html new file mode 100644 index 00000000000..4779a49c03b --- /dev/null +++ b/doc/_templates/searchbox.html @@ -0,0 +1,130 @@ +{# + Override the default searchbox from RTD theme to provide the ability to select a search method + (ex. built-in search, Google Custom Search, ...) +#} +{%- if ('singlehtml' not in builder) %} + +{%- if google_searchengine_id is defined %} + +{%- endif %} +{%- endif %} \ No newline at end of file diff --git a/doc/build/dts/bindings-syntax.rst b/doc/build/dts/bindings-syntax.rst index aff8bb64105..4cdadf62631 100644 --- a/doc/build/dts/bindings-syntax.rst +++ b/doc/build/dts/bindings-syntax.rst @@ -632,7 +632,7 @@ property, like the PWM controllers ``pwm1`` and ``pwm2`` in this example: }; pwm2: pwm@deadbeef { - compatible = "foo,pwm"; + compatible = "bar,pwm"; #pwm-cells = <1>; }; diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index 66e74bfbf55..f42f4838877 100644 --- a/doc/build/dts/macros.bnf +++ b/doc/build/dts/macros.bnf @@ -37,11 +37,14 @@ node-macro =/ %s"DT_N" path-id %s"_REG_NAME_" dt-name %s"_VAL_" ( %s"ADDRESS" / %s"SIZE") ; The interrupts property is also special. node-macro =/ %s"DT_N" path-id %s"_IRQ_NUM" +node-macro =/ %s"DT_N" path-id %s"_IRQ_LEVEL" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT "_EXISTS" node-macro =/ %s"DT_N" path-id %s"_IRQ_IDX_" DIGIT %s"_VAL_" dt-name [ %s"_EXISTS" ] +node-macro =/ %s"DT_N" path-id %s"_CONTROLLER" node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name %s"_VAL_" dt-name [ %s"_EXISTS" ] +node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name "_CONTROLLER" ; The ranges property is also special. node-macro =/ %s"DT_N" path-id %s"_RANGES_NUM" node-macro =/ %s"DT_N" path-id %s"_RANGES_IDX_" DIGIT "_EXISTS" diff --git a/doc/build/sysbuild/index.rst b/doc/build/sysbuild/index.rst index b66ec8938c7..5827f135865 100644 --- a/doc/build/sysbuild/index.rst +++ b/doc/build/sysbuild/index.rst @@ -651,6 +651,74 @@ configuration files for ``my_sample`` will be ignored. This give you full control on how images are configured when integrating those with ``application``. +.. _sysbuild_file_suffixes: + +Sysbuild file suffix support +---------------------------- + +File suffix support through the makevar:`FILE_SUFFIX` is supported in sysbuild +(see :ref:`application-file-suffixes` for details on this feature in applications). For sysbuild, +a globally provided option will be passed down to all images. In addition, the image configuration +file will have this value applied and used (instead of the build type) if the file exists. + +Given the example project: + +.. code-block:: none + + /application + ├── CMakeLists.txt + ├── prj.conf + ├── sysbuild.conf + ├── sysbuild_test_key.conf + └── sysbuild + ├── mcuboot.conf + ├── mcuboot_max_log.conf + └── my_sample.conf + +* If ``FILE_SUFFIX`` is not defined and both ``mcuboot`` and ``my_sample`` images are included, + ``mcuboot`` will use the ``mcuboot.conf`` Kconfig fragment file and ``my_sample`` will use the + ``my_sample.conf`` Kconfig fragment file. Sysbuild itself will use the ``sysbuild.conf`` + Kconfig fragment file. + +* If ``FILE_SUFFIX`` is set to ``max_log`` and both ``mcuboot`` and ``my_sample`` images are + included, ``mcuboot`` will use the ``mcuboot_max_log.conf`` Kconfig fragment file and + ``my_sample`` will use the ``my_sample.conf`` Kconfig fragment file (as it will fallback to the + file without the suffix). Sysbuild itself will use the ``sysbuild.conf`` Kconfig fragment file + (as it will fallback to the file without the suffix). + +* If ``FILE_SUFFIX`` is set to ``test_key`` and both ``mcuboot`` and ``my_sample`` images are + included, ``mcuboot`` will use the ``mcuboot.conf`` Kconfig fragment file and + ``my_sample`` will use the ``my_sample.conf`` Kconfig fragment file (as it will fallback to the + files without the suffix). Sysbuild itself will use the ``sysbuild_test_key.conf`` Kconfig + fragment file. This can be used to apply a different sysbuild configuration, for example to use + a different signing key in MCUboot and when signing the main application. + +The ``FILE_SUFFIX`` can also be applied only to single images by prefixing the variable with the +image name: + +.. tabs:: + + .. group-tab:: ``west build`` + + .. zephyr-app-commands:: + :tool: west + :app: file_suffix_example + :board: reel_board + :goals: build + :west-args: --sysbuild + :gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -Dmcuboot_FILE_SUFFIX="max_log" + :compact: + + .. group-tab:: ``cmake`` + + .. zephyr-app-commands:: + :tool: cmake + :app: share/sysbuild + :board: reel_board + :goals: build + :gen-args: -DAPP_DIR= -DSB_CONFIG_BOOTLOADER_MCUBOOT=y -Dmcuboot_FILE_SUFFIX="max_log" + :compact: + .. _sysbuild_zephyr_application_dependencies: Adding dependencies among Zephyr applications diff --git a/doc/build/version/index.rst b/doc/build/version/index.rst index 8d169a85bf5..2106a65e169 100644 --- a/doc/build/version/index.rst +++ b/doc/build/version/index.rst @@ -73,85 +73,120 @@ To use the version information in application code, the version file must be inc fields can be freely used. The include file name is :file:`app_version.h` (no path is needed), the following defines are available: -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| Define | Type | Field(s) | Example | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APPVERSION | Numerical | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | -| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | -| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | -| | | ``VERSION_TWEAK`` | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_NUMBER | Numerical | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | -| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | -| | | ``PATCHLEVEL`` | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` |br| | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ -| APP_BUILD_VERSION | String (unquoted) | None (value of ``git describe --abbrev=12 --always`` | v3.3.0-18-g2c85d9224fca | -| | | from application repository) | | -+--------------------+-------------------+------------------------------------------------------+-------------------------+ ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| Define | Type | Field(s) | Example | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APPVERSION | Numerical | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_NUMBER | Numerical | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_EXTENDED_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3-unstable+4" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` |br| | | +| | | ``VERSION_TWEAK`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_VERSION_TWEAK_STRING | String (quoted) | ``VERSION_MAJOR``, |br| | "1.2.3+4" | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` |br| | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ +| APP_BUILD_VERSION | String (unquoted) | None (value of ``git describe --abbrev=12 --always`` | v3.3.0-18-g2c85d9224fca | +| | | from application repository) | | ++-----------------------------+-------------------+------------------------------------------------------+-------------------------+ Use in Kconfig ============== The following variables are available for usage in Kconfig files: -+------------------+-----------+-------------------------+----------------+ -| Variable | Type | Field(s) | Example | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_MAJOR) | Numerical | ``VERSION_MAJOR`` | 1 | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_MINOR) | Numerical | ``VERSION_MINOR`` | 2 | -+------------------+-----------+-------------------------+----------------+ -| $(PATCHLEVEL) | Numerical | ``PATCHLEVEL`` | 3 | -+------------------+-----------+-------------------------+----------------+ -| $(VERSION_TWEAK) | Numerical | ``VERSION_TWEAK`` | 4 | -+------------------+-----------+-------------------------+----------------+ -| $(APPVERSION) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` | | -+------------------+-----------+-------------------------+----------------+ ++--------------------------------+-----------+--------------------------+------------------+ +| Variable | Type | Field(s) | Example | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_MAJOR) | Numerical | ``VERSION_MAJOR`` | 1 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_MINOR) | Numerical | ``VERSION_MINOR`` | 2 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(PATCHLEVEL) | Numerical | ``PATCHLEVEL`` | 3 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(VERSION_TWEAK) | Numerical | ``VERSION_TWEAK`` | 4 | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APPVERSION) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APP_VERSION_EXTENDED_STRING) | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION``, |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------------------+-----------+--------------------------+------------------+ +| $(APP_VERSION_TWEAK_STRING) | String | ``VERSION_MAJOR``, |br| | 1.2.3+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` | | ++--------------------------------+-----------+--------------------------+------------------+ Use in CMake ============ The following variable are available for usage in CMake files: -+--------------------+-----------------+---------------------------------------------------+----------------+ -| Variable | Type | Field(s) | Example | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APPVERSION | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | -| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | -| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | -| | | ``VERSION_TWEAK`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_NUMBER | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | -| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | -| | | ``PATCHLEVEL`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | -+--------------------+-----------------+---------------------------------------------------+----------------+ -| APP_VERSION_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | -| | | ``VERSION_MINOR``, |br| | | -| | | ``PATCHLEVEL``, |br| | | -| | | ``EXTRAVERSION`` | | -+--------------------+-----------------+---------------------------------------------------+----------------+ ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| Variable | Type | Field(s) | Example | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APPVERSION | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 24 bits), |br| | 0x1020304 | +| | | ``VERSION_MINOR`` (left shifted by 16 bits), |br| | | +| | | ``PATCHLEVEL`` (left shifted by 8 bits), |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_NUMBER | Numerical (hex) | ``VERSION_MAJOR`` (left shifted by 16 bits), |br| | 0x10203 | +| | | ``VERSION_MINOR`` (left shifted by 8 bits), |br| | | +| | | ``PATCHLEVEL`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_MAJOR | Numerical | ``VERSION_MAJOR`` | 1 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_MINOR | Numerical | ``VERSION_MINOR`` | 2 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_PATCHLEVEL | Numerical | ``PATCHLEVEL`` | 3 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_TWEAK | Numerical | ``VERSION_TWEAK`` | 4 | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_EXTENDED_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3-unstable+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``EXTRAVERSION``, |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ +| APP_VERSION_TWEAK_STRING | String | ``VERSION_MAJOR``, |br| | 1.2.3+4 | +| | | ``VERSION_MINOR``, |br| | | +| | | ``PATCHLEVEL``, |br| | | +| | | ``VERSION_TWEAK`` | | ++-----------------------------+-----------------+---------------------------------------------------+------------------+ Use in MCUboot-supported applications ===================================== @@ -159,6 +194,3 @@ Use in MCUboot-supported applications No additional configuration needs to be done to the target application so long as it is configured to support MCUboot and a signed image is generated, the version information will be automatically included in the image data. - -The format used for signing is ``VERSION_MAJOR`` . ``VERSION_MINOR`` . ``PATCHLEVEL``, the tweak -version field is not currently used. diff --git a/doc/conf.py b/doc/conf.py index 4bab42dcc90..a570eef7c35 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,8 +8,6 @@ import textwrap from sphinx.cmd.build import get_parser -import sphinx_rtd_theme - args = get_parser().parse_args() ZEPHYR_BASE = Path(__file__).resolve().parents[1] @@ -27,6 +25,9 @@ # for autodoc directives on runners.xyz. sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "west_commands")) +# Add the directory which contains the pytest-twister-pytest +sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "pylib" / "pytest-twister-harness" / "src")) + import redirects try: @@ -37,7 +38,7 @@ # -- Project -------------------------------------------------------------- project = "Zephyr Project" -copyright = "2015-2023 Zephyr Project members and individual contributors" +copyright = "2015-2024 Zephyr Project members and individual contributors" author = "The Zephyr Project Contributors" # parse version from 'VERSION' file @@ -65,10 +66,15 @@ release = version +# parse SDK version from 'SDK_VERSION' file +with open(ZEPHYR_BASE / "SDK_VERSION") as f: + sdk_version = f.read().strip() + # -- General configuration ------------------------------------------------ extensions = [ "breathe", + "sphinx_rtd_theme", "sphinx.ext.todo", "sphinx.ext.extlinks", "sphinx.ext.autodoc", @@ -129,14 +135,27 @@ ("c:identifier", "va_list"), ] -rst_epilog = """ +SDK_URL_BASE="https://github.com/zephyrproject-rtos/sdk-ng/releases/download" + +rst_epilog = f""" .. include:: /substitutions.txt + +.. |sdk-version-literal| replace:: ``{sdk_version}`` +.. |sdk-version-trim| unicode:: {sdk_version} + :trim: +.. |sdk-version-ltrim| unicode:: {sdk_version} + :ltrim: +.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v{sdk_version} +.. |sdk-url-linux| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_linux-x86_64.tar.xz` +.. |sdk-url-linux-sha| replace:: `{SDK_URL_BASE}/v{sdk_version}/sha256.sum` +.. |sdk-url-macos| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_macos-x86_64.tar.xz` +.. |sdk-url-macos-sha| replace:: `{SDK_URL_BASE}/v{sdk_version}/sha256.sum` +.. |sdk-url-windows| replace:: `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_windows-x86_64.7z` """ # -- Options for HTML output ---------------------------------------------- html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_theme_options = { "logo_only": True, "prev_next_buttons_location": None @@ -152,6 +171,9 @@ html_show_sourcelink = False html_show_sphinx = False html_search_scorer = str(ZEPHYR_BASE / "doc" / "_static" / "js" / "scorer.js") +html_additional_pages = { + "gsearch": "gsearch.html" +} is_release = tags.has("release") # pylint: disable=undefined-variable reference_prefix = "" @@ -175,7 +197,11 @@ "Kconfig Options": f"{reference_prefix}/kconfig.html", "Devicetree Bindings": f"{reference_prefix}/build/dts/api/bindings.html", "West Projects": f"{reference_prefix}/develop/manifest/index.html", - } + }, + # Set google_searchengine_id to your Search Engine ID to replace built-in search + # engine with Google's Programmable Search Engine. + # See https://programmablesearchengine.google.com/ for details. + "google_searchengine_id": "746031aa0d56d4912", } # -- Options for LaTeX output --------------------------------------------- @@ -304,7 +330,7 @@ # -- Options for zephyr.domain -------------------------------------------- -zephyr_domain_apply_transforms = True +zephyr_breathe_insert_related_samples = True # -- Options for sphinx.ext.graphviz -------------------------------------- @@ -342,4 +368,5 @@ def setup(app): # theme customizations app.add_css_file("css/custom.css") + app.add_js_file("js/custom.js") app.add_js_file("js/dark-mode-toggle.min.mjs", type="module") diff --git a/doc/connectivity/bluetooth/api/index.rst b/doc/connectivity/bluetooth/api/index.rst index 51c36386114..fa7e357f7d8 100644 --- a/doc/connectivity/bluetooth/api/index.rst +++ b/doc/connectivity/bluetooth/api/index.rst @@ -35,6 +35,8 @@ Bluetooth APIs shell/cap.rst shell/ccp.rst shell/csip.rst + shell/gmap.rst shell/iso.rst shell/mcp.rst shell/tmap.rst + shell/pbp.rst diff --git a/doc/connectivity/bluetooth/api/mesh.rst b/doc/connectivity/bluetooth/api/mesh.rst index f234ff7cedc..358ba3dc62e 100644 --- a/doc/connectivity/bluetooth/api/mesh.rst +++ b/doc/connectivity/bluetooth/api/mesh.rst @@ -5,10 +5,7 @@ Bluetooth Mesh Profile The Bluetooth Mesh profile adds secure wireless multi-hop communication for Bluetooth Low Energy. This module implements the -`Bluetooth Mesh Profile Specification v1.0.1 `_. - -Implementation of the `Bluetooth Mesh Protocol Specification v1.1 `_ -is in experimental state. +`Bluetooth Mesh Protocol Specification v1.1 `_. Read more about Bluetooth Mesh on the `Bluetooth SIG Website `_. diff --git a/doc/connectivity/bluetooth/api/mesh/access.rst b/doc/connectivity/bluetooth/api/mesh/access.rst index cb02028b697..aa6082f5df4 100644 --- a/doc/connectivity/bluetooth/api/mesh/access.rst +++ b/doc/connectivity/bluetooth/api/mesh/access.rst @@ -168,15 +168,6 @@ needs to be stored. Composition Data ================ -.. note:: - - The implementation of the Bluetooth Mesh Protocol Specification version 1.1 - is currently in an experimental state. For Bluetooth Mesh Profile Specification - version 1.0.1, only Composition Data Page 0 is supported. Users that are developing - for Bluetooth Mesh Profile Specification version 1.0.1 may therefore disregard all - parts of the following section mentioning the :ref:`bluetooth_mesh_lcd_srv` - model and Composition Data Pages 1, 2, 128, 129 and 130. - The Composition Data provides information about a mesh device. A device's Composition Data holds information about the elements on the device, the models that it supports, and other features. The Composition @@ -188,7 +179,7 @@ the :ref:`bluetooth_mesh_lcd_srv` model. Composition Data Page 0 ----------------------- -Composition Data Page 0 provides the fundemental information about a device, and +Composition Data Page 0 provides the fundamental information about a device, and is mandatory for all mesh devices. It contains the element and model composition, the supported features, and manufacturer information. diff --git a/doc/connectivity/bluetooth/api/mesh/dfu.rst b/doc/connectivity/bluetooth/api/mesh/dfu.rst index 6718b3ea0ce..d2bf4ced2ce 100644 --- a/doc/connectivity/bluetooth/api/mesh/dfu.rst +++ b/doc/connectivity/bluetooth/api/mesh/dfu.rst @@ -164,7 +164,7 @@ Firmware metadata | | | in the New firmware core type field. | +------------------------+--------------+----------------------------------------+ | Application-specific | | Application-specific data to allow | -| data for new firmware | (Optional) | application to execut some | +| data for new firmware | (Optional) | application to execute some | | | | vendor-specific behaviors using | | | | this data before it can respond | | | | with a status message. | diff --git a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst index 4f3354945c9..76bd0330a98 100644 --- a/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst +++ b/doc/connectivity/bluetooth/api/mesh/sar_cfg.rst @@ -43,36 +43,8 @@ Keep this in mind when defining the size of the buffers. SAR does not impose extra overhead on the access layer payload per segment. -Intervals, timers and retransmission counters -********************************************* - -The current stable stack implementation allows you to configure the following SAR behavior. - -When sending a segmented message to a unicast address, the unacknowledged segments are repeated -the :kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT` number of times before the transmission -is considered as failed. The same option configures a number of retransmissions to a group or -virtual address, but the transmission always succeedes after retransmitting all segments the -configured number of times. - -The timeout between each retransmission to a unicast address is configured by the Kconfig option -:kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST`. The timeout between each -retransmission to a group or a virtual address is configured by the Kconfig option -:kconfig:option:`CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP`. - -The time before sending a Segment Acknowledgment message is controlled by the Kconfig options -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT`, -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_PER_HOP_TIMEOUT` and -:kconfig:option:`CONFIG_BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT`, and is defined as: - -.. math:: - \begin{aligned} - \max(&\mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_BASE\_TIMEOUT} \\ - &+ \text{TTL} \times \mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_PER\_HOP\_TIMEOUT} \\ - &+ \text{number of un-acked segments} \times \mathtt{CONFIG\_BT\_MESH\_SEG\_ACK\_PER\_SEGMENT\_TIMEOUT} , 400) - \end{aligned} - Segmentation and reassembly (SAR) Configuration models -====================================================== +****************************************************** With Bluetooth Mesh Protocol Specification version 1.1, it became possible to configure SAR behavior, such as intervals, timers and retransmission counters, over a mesh network using SAR @@ -139,7 +111,7 @@ of the `SAR Acknowledgment Retransmissions Count`_ state. .. _bt_mesh_sar_cfg_states: SAR states -========== +********** There are two states defined related to segmentation and reassembly: @@ -168,7 +140,7 @@ the following states: * SAR Receiver Segment Interval Step SAR Segment Interval Step -------------------------- +========================= SAR Segment Interval Step state holds a value that controls the interval between transmissions of segments of a segmented message. The interval is measured in milliseconds. @@ -182,7 +154,7 @@ value. Segment transmission interval is then calculated using the following form SAR Unicast Retransmissions Count ---------------------------------- +================================= SAR Unicast Retransmissions Count holds a value that defines the maximum number of retransmissions of a segmented message to a unicast destination. Use the @@ -190,7 +162,7 @@ of a segmented message to a unicast destination. Use the value for this state. SAR Unicast Retransmissions Without Progress Count --------------------------------------------------- +================================================== This state holds a value that defines the maximum number of retransmissions of a segmented message to a unicast address that will be sent if no acknowledgment was received during the timeout, or if @@ -199,7 +171,7 @@ an acknowledgment with already confirmed segments was received. Use the Kconfig of retransmissions. SAR Unicast Retransmissions Interval Step ------------------------------------------ +========================================= The value of this state controls the interval step used for delaying the retransmissions of unacknowledged segments of a segmented message to a unicast address. The interval step is measured @@ -214,7 +186,7 @@ default value. This value is then used to calculate the interval step using the SAR Unicast Retransmissions Interval Increment ----------------------------------------------- +============================================== SAR Unicast Retransmissions Interval Increment holds a value that controls the interval increment used for delaying the retransmissions of unacknowledged segments of a segmented message to a unicast @@ -230,7 +202,7 @@ formula: SAR Multicast Retransmissions Count ------------------------------------ +=================================== The state holds a value that controls the total number of retransmissions of a segmented message to a multicast address. Use the Kconfig option @@ -238,7 +210,7 @@ a multicast address. Use the Kconfig option retransmissions. SAR Multicast Retransmissions Interval Step -------------------------------------------- +=========================================== This state holds a value that controls the interval between retransmissions of all segments in a segmented message to a multicast address. The interval is measured in milliseconds. @@ -252,7 +224,7 @@ default value that is used to calculate the interval using the following formula SAR Discard Timeout -------------------- +=================== The value of this state defines the time in seconds that the lower transport layer waits after receiving segments of a segmented message before discarding that segmented message. Use the Kconfig @@ -265,7 +237,7 @@ timeout will be calculated using the following formula: SAR Acknowledgment Delay Increment ----------------------------------- +================================== This state holds a value that controls the delay increment of an interval used for delaying the transmission of an acknowledgment message after receiving a new segment. The increment is measured @@ -276,7 +248,7 @@ value. The increment value is calculated to be :math:`\verb|CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC| + 1.5`. SAR Segments Threshold ----------------------- +====================== SAR Segments Threshold state holds a value that defines a threshold in number of segments of a segmented message for acknowledgment retransmissions. Use the Kconfig option @@ -287,7 +259,7 @@ additionally retransmit every acknowledgment message the number of times given b :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT`. SAR Acknowledgment Retransmissions Count ----------------------------------------- +======================================== The SAR Acknowledgment Retransmissions Count state controls the number of retransmissions of Segment Acknowledgment messages sent by the lower transport layer. It gives the total number of @@ -300,7 +272,7 @@ value for this state. The maximum number of transmissions of a Segment Acknowle :math:`\verb|CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT| + 1`. SAR Receiver Segment Interval Step ----------------------------------- +================================== The SAR Receiver Segment Interval Step defines the segments reception interval step used for delaying the transmission of an acknowledgment message after receiving a new segment. The interval diff --git a/doc/connectivity/bluetooth/api/mesh/shell.rst b/doc/connectivity/bluetooth/api/mesh/shell.rst index 3d925f29a3e..366e5d9ebad 100644 --- a/doc/connectivity/bluetooth/api/mesh/shell.rst +++ b/doc/connectivity/bluetooth/api/mesh/shell.rst @@ -944,7 +944,7 @@ application. This shell module can be used to trigger interaction between Health on devices in a Mesh network. By default, the module will choose the first Health Client instance in the model composition when -using the Health Client commands. To choose a spesific Health Client instance the user can utilize +using the Health Client commands. To choose a specific Health Client instance the user can utilize the commands ``mesh models health instance set`` and ``mesh models health instance get-all``. The Health Client may use the general messages parameters set by ``mesh target dst``, diff --git a/doc/connectivity/bluetooth/api/shell/cap.rst b/doc/connectivity/bluetooth/api/shell/cap.rst index 5ab57a8d320..51a42c90260 100644 --- a/doc/connectivity/bluetooth/api/shell/cap.rst +++ b/doc/connectivity/bluetooth/api/shell/cap.rst @@ -137,3 +137,94 @@ used. uart:~$ cap_initiator unicast-stop Unicast stopped for group 0x81e41c0 completed + +CAP Commander +************* + +The Commander will typically be a either co-located with a CAP Initiator or be on a separate +resource-rich mobile device, such as a phone or smartwatch. The Commander can +discover CAP Acceptors's CAS and optional CSIS services. The CSIS service can be read to provide +information about other CAP Acceptors in the same Coordinated Set. The Commander can provide +information about broadcast sources to CAP Acceptors or coordinate capture and rendering information +such as mute or volume states. + +Using the CAP Commander +======================= + +When the Bluetooth stack has been initialized (:code:`bt init`), the Commander can discover CAS and +the optionally included CSIS instance by calling (:code:`cap_commander discover`). + +.. code-block:: console + + cap_commander --help + cap_commander - Bluetooth CAP commander shell commands + Subcommands: + discover :Discover CAS + change_volume :Change volume on all connections + change_volume_offset :Change volume offset per connection + + +Before being able to perform any stream operation, the device must also perform the +:code:`bap discover` operation to discover the ASEs and PAC records. The :code:`bap init` +command also needs to be called. + +When connected +-------------- + +Discovering CAS and CSIS on a device: + +.. code-block:: console + + uart:~$ cap_commander discover + discovery completed with CSIS + + +Setting the volume on all connected devices: + +.. code-block:: console + + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ cap_commander change_volume 15 + uart:~$ cap_commander change_volume 15 + Setting volume to 15 on 2 connections + VCP volume 15, mute 0 + VCP vol_set done + VCP volume 15, mute 0 + VCP flags 0x01 + VCP vol_set done + Volume change completed + + +Setting the volume offset on one or more connected devices. The offsets are set by connection index, +so connection index 0 gets the first offset, and index 1 gets the second offset, etc.: + +.. code-block:: console + + uart:~$ bt connect + Connected: + uart:~$ cap_commander discover + discovery completed with CSIS + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ + uart:~$ bt connect + Connected: + uart:~$ cap_commander discover + discovery completed with CSIS + uart:~$ vcp_vol_ctlr discover + VCP discover done with 1 VOCS and 1 AICS + uart:~$ + uart:~$ cap_commander change_volume_offset 10 + Setting volume offset on 1 connections + VOCS inst 0x200140a4 offset 10 + Offset set for inst 0x200140a4 + Volume offset change completed + uart:~$ + uart:~$ cap_commander change_volume_offset 10 15 + Setting volume offset on 2 connections + Offset set for inst 0x200140a4 + VOCS inst 0x20014188 offset 15 + Offset set for inst 0x20014188 + Volume offset change completed diff --git a/doc/connectivity/bluetooth/api/shell/gmap.rst b/doc/connectivity/bluetooth/api/shell/gmap.rst new file mode 100644 index 00000000000..11259297a5b --- /dev/null +++ b/doc/connectivity/bluetooth/api/shell/gmap.rst @@ -0,0 +1,82 @@ +Bluetooth: Gaming Audio Profile Shell +##################################### + +This document describes how to run the Gaming Audio Profile shell functionality. +Unlike most other low-layer profiles, GMAP is a profile that exists and has a service (GMAS) on all +devices. Thus both the initiator and acceptor (or central and peripheral) should do a discovery of +the remote device's GMAS to see what GMAP roles and features they support. + +Using the GMAP Shell +******************** + +When the Bluetooth stack has been initialized (:code:`bt init`), the GMAS can be registered by +by calling :code:`gmap init`. It is also strongly suggested to enable BAP via :code:`bap init`. + +.. code-block:: console + + gmap --help + gmap - Bluetooth GMAP shell commands + Subcommands: + init :[none] + set_role :[ugt | ugg | bgr | bgs] + discover :[none] + ac_1 : + ac_2 : + ac_3 : + ac_4 : + ac_5 : + ac_6_i : + ac_6_ii : + ac_7_ii : + ac_8_i : + ac_8_ii : + ac_11_i : + ac_11_ii : + ac_12 : + ac_13 : + ac_14 : + +The :code:`set_role` command can be used to change the role at runtime, assuming that the device +supports the role (the GMAP roles depend on some BAP configurations). + +Example Central with GMAP UGT role +********************************** + +Connect and establish Gaming Audio streams using Audio Configuration (AC) 3 +(some logging has been omitted for clarity): + +.. code-block:: console + + uart:~$ bt init + uart:~$ bap init + uart:~$ gmap init + uart:~$ bt connect
+ uart:~$ gatt exchange-mtu + uart:~$ bap discover + Discover complete: err 0 + uart:~$ cap_initiator discover + discovery completed with CSIS + uart:~$ gmap discover + gmap discovered for conn 0x2001c7d8: + role 0x0f + ugg_feat 0x07 + ugt_feat 0x6f + bgs_feat 0x01 + bgr_feat 0x03 + uart:~$ gmap ac_3 32_2_gr 32_2_gs + Starting 2 streams for AC_3 + stream 0x20020060 config operation rsp_code 0 reason 0 + stream 0x200204d0 config operation rsp_code 0 reason 0 + stream 0x200204d0 qos operation rsp_code 0 reason 0 + stream 0x20020060 qos operation rsp_code 0 reason 0 + Stream 0x20020060 enabled + stream 0x200204d0 enable operation rsp_code 0 reason 0 + Stream 0x200204d0 enabled + stream 0x20020060 enable operation rsp_code 0 reason 0 + Stream 0x20020060 started + stream 0x200204d0 start operation rsp_code 0 reason 0 + Stream 0x200204d0 started + Unicast start completed + uart:~$ bap start_sine + Started transmitting on default_stream 0x20020060 + [0]: stream 0x20020060 : TX LC3: 80 (seq_num 24800) diff --git a/doc/connectivity/bluetooth/api/shell/pbp.rst b/doc/connectivity/bluetooth/api/shell/pbp.rst new file mode 100644 index 00000000000..ba3e0f459fd --- /dev/null +++ b/doc/connectivity/bluetooth/api/shell/pbp.rst @@ -0,0 +1,20 @@ +Bluetooth: Public Broadcast Profile Shell +######################################### + +This document describes how to run the Public Broadcast Profile functionality. +PBP does not have an associated service. Its purpose is to enable a faster, more +efficient discovery of Broadcast Sources that are transmitting audio with commonly used codec configurations. + +Using the PBP Shell +******************* + +When the Bluetooth stack has been initialized (:code:`bt init`), the Public Broadcast Profile is ready to run. +To set the Public Broadcast Announcement features call :code:`pbp set_features`. + +.. code-block:: console + + + pbp --help + pbp - Bluetooth PBP shell commands + Subcommands: + set_features :Set the Public Broadcast Announcement features diff --git a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst index aa62b426160..85388b6dc0f 100644 --- a/doc/connectivity/bluetooth/bluetooth-audio-arch.rst +++ b/doc/connectivity/bluetooth/bluetooth-audio-arch.rst @@ -132,7 +132,10 @@ Bluetooth Audio Stack. | | | | | - Shell Module | | | | | | | - BSIM test | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Commander | | | - Not Started | | + | | Commander | | | - WIP | - Feature complete | + | | | | | | - Shell Module | + | | | | | | - BSIM test | + | | | | | | - Sample Application | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ | HAP | Hearing Aid | 1.0 | 3.1 | - Feature complete | | | | | | | - Shell Module | | @@ -179,40 +182,40 @@ Bluetooth Audio Stack. | | | | | - BSIM test | | | | | | | - Sample Application | | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | PBP | Public Broadcast Source | | | - WIP :github:`60777` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | PBP | Public Broadcast Source | | 3.5 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Public Broadcast Sink | | | - WIP :github:`60777` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Public Broadcast Sink | | 3.5 | - Feature complete | | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | - Sample Application | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ | | Public Broadcast Assistant | | | | - Feature complete | | | | | | | - Shell Module | | | | | | | - BSIM test | | | | | | | - Sample Application | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | GMAP | Unicast Game Gateway | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | GMAP | Unicast Game Gateway | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Unicast Game Terminal | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Unicast Game Terminal | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Broadcast Game Sender | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Broadcast Game Sender | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | | +-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ - | | Broadcast Game Receiver | | | - WIP :github:`57032` | - Feature complete | - | | | | | | - Shell Module | - | | | | | | - BSIM test | - | | | | | | - Sample Application | + | | Broadcast Game Receiver | | 3.5 | - Feature complete | - Sample Application | + | | | | | - Shell Module | | + | | | | | - BSIM test | | + | | | | | | | +--------+-------------------------------+---------+------------------+-----------------------+--------------------------------------------------+ Using the Bluetooth Audio Stack diff --git a/doc/connectivity/bluetooth/img/cap_proc.svg b/doc/connectivity/bluetooth/img/cap_proc.svg index ef476096ad2..70e56eebc25 100644 --- a/doc/connectivity/bluetooth/img/cap_proc.svg +++ b/doc/connectivity/bluetooth/img/cap_proc.svg @@ -1,3 +1,3 @@ -
CSIP
CSIP
BAP
BAP
VCP
VCP
MICP
MICP
CCP
CCP
MCP
MCP
CAP
CAP
Unicast Audio Start
Unicast Audio Start
Unicast Audio Update
Unicast Audio Update
Unicast Audio Stop
Unicast Audio Stop
Broadcast Audio Start
Broadcast Audio Start
Broadcast Audio Update
Broadcast Audio Update
Broadcast Audio Stop
Broadcast Audio Stop
Change Volume
Change Volume
Change Volume Offset
Change Volume Offset
Change Volume Mute
Change Volume Mute
Microphone Mute State
Microphone Mute State
Change Microphone Gain Setting
Change Microphone Gain Setting
Find Content Control Service
Find Content Control Service
Discovery
Discovery
Discovery
Discovery
Coordinated Set Dsicovery
Coordinated Set Dsicovery
Set Members Discovery
Set Members Discovery
Lock Request
Lock Request
Lock Release
Lock Release
For all connected procedures for CSIP sets
F...
Ordered Access
Ordered Access
Audio Role Discovery
Audio Role Discovery
Audio Capability Discovery
Audio Capability Discovery
ASE ID Discovery
ASE ID Discovery
Supported Audio Context Discovery
Supported Audio Context Discovery
Available Audio Context Discovery
Available Audio Context Discovery
Codec Configuration
Codec Configuration
QoS Configuration
QoS Configuration
Enabling ASE
Enabling ASE
Updating unicast metadata
Updating unicast metadata
Disabling ASE
Disabling ASE
Releasing ASE
Releasing ASE
Configure broadcast source
Configure broadcast source
Reconfigure broadcast source
Reconfigure broadcast source
Broadcast audio establishment
Broadcast audio establishment
Broadcast Audio Metadata update
Broadcast Audio Metadata update
Broadcast Audio Disable
Broadcast Audio Disable
Broadcast Audio Release
Broadcast Audio Release
Broadcast Audio Synchronization
Broadcast Audio Synchronization
Configure volume state notifications
Configure volume state notifications
Read Volume State
Read Volume State
Configure Volume flag notifications
Configure Volume flag notifications
Read Volume Flags
Read Volume Flags
Set Initial Volume
Set Initial Volume
Relative Volume Down
Relative Volume Down
Relative Volume Up
Relative Volume Up
Unmute and Relative Volume Down
Unmute and Relative Volume Down
Unmute and Relative volume Up
Unmute and Relative volume Up
Set Absolute Volume
Set Absolute Volume
Unmute
Unmute
Mute
Mute
Configure volume offset state notifications
Configure volume offset state notifications
Read Volume Offset State
Read Volume Offset State
Configure Audio Locaiton notifications
Configure Audio Locaiton notifications
Read Audio Location
Read Audio Location
Set Volume Offset
Set Volume Offset
Configure audio output description notifications
Configure audio output description notifications
Read Audio Output Description
Read Audio Output Description
Set Audio Output Description
Set Audio Output Description
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Configure mute notifications
Configure mute notifications
Read Mute State
Read Mute State
Set Mute State
Set Mute State
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Discovery
Discovery
Read Bearer Provide Name
Read Bearer Provide Name
Read Bearer UCI
Read Bearer UCI
Read Bearer Technology
Read Bearer Technology
Read Bearer URI Schemes Supported List
Read Bearer URI Schemes Supported List
Read Bearer Signal Strength
Read Bearer Signal Strength
Read Bearer Signal Strength Reporting Interval
Read Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Reader List Current Calls
Reader List Current Calls
Read Content Control ID
Read Content Control ID
Read Incoming Clal Target Bearer URI
Read Incoming Clal Target Bearer URI
Read Status Flags
Read Status Flags
Read Call State
Read Call State
Answer Incoming Call
Answer Incoming Call
Terminate Call
Terminate Call
Move Call To Local Hold
Move Call To Local Hold
Move Locally Held Call To Active Call
Move Locally Held Call To Active Call
Move Locally And Remotely Held Call To Remotely Held Call
Move Locally And Remotely Held Call To Remotely Held Ca...
Originate Call
Originate Call
Join Calls
Join Calls
Read Call Control Point Optional Opcodes
Read Call Control Point Optional Opcodes
Read Incoming Call
Read Incoming Call
Read Call Friendly Name
Read Call Friendly Name
Discovery
Discovery
Read Media Information
Read Media Information
Read Media Player Icon Object Information
Read Media Player Icon Object Information
Read Track Title
Read Track Title
Set Absolute Track Position
Set Absolute Track Position
Set Relative Track Position 
Set Relative Track Position 
Read Playback Speed
Read Playback Speed
Read Track Duration
Read Track Duration
Read Track Position
Read Track Position
Set Playback Speed
Set Playback Speed
Read Seeking Speek
Read Seeking Speek
Read Current Track Segments Object Information
Read Current Track Segments Object Information
Read Current Track Object Information
Read Current Track Object Information
Set Current Track Object ID
Set Current Track Object ID
Read Next Track Object Information
Read Next Track Object Information
Set Next Track Object ID
Set Next Track Object ID
Track Discovery – Discover by Current Group Object ID
Track Discovery – Discover by Current Group Object ID
Set Current Group Object ID
Set Current Group Object ID
Read Parent Group Object Information
Read Parent Group Object Information
Read Playing Order
Read Playing Order
Set Playing Order
Set Playing Order
Read Playing Order Supported
Read Playing Order Supported
Read Media State
Read Media State
Play Current Track
Play Current Track
Pause Current Track
Pause Current Track
Fast Forward Fast Rewind
Fast Forward Fast Rewind
Stop Current Track
Stop Current Track
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Next Segment
Move to Next Segment
Move to First Segment
Move to First Segment
Move to Last Segment
Move to Last Segment
Move to Segment Number
Move to Segment Number
Move to Previous Track
Move to Previous Track
Move to Next Track
Move to Next Track
Move to First Track
Move to First Track
Move to Last Track
Move to Last Track
Move to Previous Group
Move to Previous Group
Move to Next Group
Move to Next Group
Move to First Group
Move to First Group
Move to Last Group
Move to Last Group
Move to Group Number
Move to Group Number
Read Media Control Point Opcodes Supported
Read Media Control Point Opcodes Supported
Search
Search
Read Content Control ID
Read Content Control ID
C
C
I
I
I
I
A
A
I
I
A
A
I
I
A
A
I
I
I
I
I
I
C
C
C
C
C
C
C
C
C
C
C
C
Broadcast Audio Reception Start
Broadcast Audio Reception Start
Adding Broadcast Sources
Adding Broadcast Sources
Modifying Broadcast Sources
Modifying Broadcast Sources
SyncInfo Transfer
SyncInfo Transfer
Setting Broadcast Code
Setting Broadcast Code
Removing Broadcast Sources
Removing Broadcast Sources
Broadcast Audio Reception Stop
Broadcast Audio Reception Stop
Broadcast to Unicast Audio Handover
Broadcast to Unicast Audio Handover
Unicast to Broadcast Audio Handover
Unicast to Broadcast Audio Handover
C
C
C
C
I
I
I
I
Distribute Broadcast_Code
Distribute Broadcast_Code
C
C
A
A
A
A
Text is not SVG - cannot display
\ No newline at end of file +
CSIP
CSIP
BAP
BAP
VCP
VCP
MICP
MICP
CCP
CCP
MCP
MCP
CAP
CAP
Unicast Audio Start
Unicast Audio Start
Unicast Audio Update
Unicast Audio Update
Unicast Audio Stop
Unicast Audio Stop
Broadcast Audio Start
Broadcast Audio Start
Broadcast Audio Update
Broadcast Audio Update
Broadcast Audio Stop
Broadcast Audio Stop
Change Volume
Change Volume
Change Volume Offset
Change Volume Offset
Change Volume Mute
Change Volume Mute
Microphone Mute State
Microphone Mute State
Change Microphone Gain Setting
Change Microphone Gain Setting
Find Content Control Service
Find Content Control Service
Discovery
Discovery
Discovery
Discovery
Coordinated Set Dsicovery
Coordinated Set Dsicovery
Set Members Discovery
Set Members Discovery
Lock Request
Lock Request
Lock Release
Lock Release
For all connected procedures for CSIP sets
F...
Ordered Access
Ordered Access
Audio Role Discovery
Audio Role Discovery
Audio Capability Discovery
Audio Capability Discovery
ASE ID Discovery
ASE ID Discovery
Supported Audio Context Discovery
Supported Audio Context Discovery
Available Audio Context Discovery
Available Audio Context Discovery
Codec Configuration
Codec Configuration
QoS Configuration
QoS Configuration
Enabling ASE
Enabling ASE
Updating unicast metadata
Updating unicast metadata
Disabling ASE
Disabling ASE
Releasing ASE
Releasing ASE
Configure broadcast source
Configure broadcast source
Reconfigure broadcast source
Reconfigure broadcast source
Broadcast audio establishment
Broadcast audio establishment
Broadcast Audio Metadata update
Broadcast Audio Metadata update
Broadcast Audio Disable
Broadcast Audio Disable
Broadcast Audio Release
Broadcast Audio Release
Broadcast Audio Synchronization
Broadcast Audio Synchronization
Configure volume state notifications
Configure volume state notifications
Read Volume State
Read Volume State
Configure Volume flag notifications
Configure Volume flag notifications
Read Volume Flags
Read Volume Flags
Set Initial Volume
Set Initial Volume
Relative Volume Down
Relative Volume Down
Relative Volume Up
Relative Volume Up
Unmute and Relative Volume Down
Unmute and Relative Volume Down
Unmute and Relative volume Up
Unmute and Relative volume Up
Set Absolute Volume
Set Absolute Volume
Unmute
Unmute
Mute
Mute
Configure volume offset state notifications
Configure volume offset state notifications
Read Volume Offset State
Read Volume Offset State
Configure Audio Location notifications
Configure Audio Location notifications
Read Audio Location
Read Audio Location
Set Volume Offset
Set Volume Offset
Configure audio output description notifications
Configure audio output description notifications
Read Audio Output Description
Read Audio Output Description
Set Audio Output Description
Set Audio Output Description
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Configure mute notifications
Configure mute notifications
Read Mute State
Read Mute State
Set Mute State
Set Mute State
Configure Audio input state notifications
Configure Audio input state notifications
Read Audio Input State
Read Audio Input State
Read Gain Setting Properties
Read Gain Setting Properties
Read Audio Input Type
Read Audio Input Type
Configure Audio Input Status Notifications
Configure Audio Input Status Notifications
Read Audio Input Status
Read Audio Input Status
Set Gain Setting
Set Gain Setting
Unmute
Unmute
Mute
Mute
Set Manual Gain Mode
Set Manual Gain Mode
Set Automatic Gain Mode
Set Automatic Gain Mode
Configure Audio Input Description
Configure Audio Input Description
Read Audio Input Description
Read Audio Input Description
Set Audio Input Description
Set Audio Input Description
Discovery
Discovery
Discovery
Discovery
Read Bearer Provide Name
Read Bearer Provide Name
Read Bearer UCI
Read Bearer UCI
Read Bearer Technology
Read Bearer Technology
Read Bearer URI Schemes Supported List
Read Bearer URI Schemes Supported List
Read Bearer Signal Strength
Read Bearer Signal Strength
Read Bearer Signal Strength Reporting Interval
Read Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Set Bearer Signal Strength Reporting Interval
Reader List Current Calls
Reader List Current Calls
Read Content Control ID
Read Content Control ID
Read Incoming Clal Target Bearer URI
Read Incoming Clal Target Bearer URI
Read Status Flags
Read Status Flags
Read Call State
Read Call State
Answer Incoming Call
Answer Incoming Call
Terminate Call
Terminate Call
Move Call To Local Hold
Move Call To Local Hold
Move Locally Held Call To Active Call
Move Locally Held Call To Active Call
Move Locally And Remotely Held Call To Remotely Held Call
Move Locally And Remotely Held Call To Remotely Held Ca...
Originate Call
Originate Call
Join Calls
Join Calls
Read Call Control Point Optional Opcodes
Read Call Control Point Optional Opcodes
Read Incoming Call
Read Incoming Call
Read Call Friendly Name
Read Call Friendly Name
Discovery
Discovery
Read Media Information
Read Media Information
Read Media Player Icon Object Information
Read Media Player Icon Object Information
Read Track Title
Read Track Title
Set Absolute Track Position
Set Absolute Track Position
Set Relative Track Position 
Set Relative Track Position 
Read Playback Speed
Read Playback Speed
Read Track Duration
Read Track Duration
Read Track Position
Read Track Position
Set Playback Speed
Set Playback Speed
Read Seeking Speek
Read Seeking Speek
Read Current Track Segments Object Information
Read Current Track Segments Object Information
Read Current Track Object Information
Read Current Track Object Information
Set Current Track Object ID
Set Current Track Object ID
Read Next Track Object Information
Read Next Track Object Information
Set Next Track Object ID
Set Next Track Object ID
Track Discovery – Discover by Current Group Object ID
Track Discovery – Discover by Current Group Object ID
Set Current Group Object ID
Set Current Group Object ID
Read Parent Group Object Information
Read Parent Group Object Information
Read Playing Order
Read Playing Order
Set Playing Order
Set Playing Order
Read Playing Order Supported
Read Playing Order Supported
Read Media State
Read Media State
Play Current Track
Play Current Track
Pause Current Track
Pause Current Track
Fast Forward Fast Rewind
Fast Forward Fast Rewind
Stop Current Track
Stop Current Track
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Previous Segment
Move to Next Segment
Move to Next Segment
Move to First Segment
Move to First Segment
Move to Last Segment
Move to Last Segment
Move to Segment Number
Move to Segment Number
Move to Previous Track
Move to Previous Track
Move to Next Track
Move to Next Track
Move to First Track
Move to First Track
Move to Last Track
Move to Last Track
Move to Previous Group
Move to Previous Group
Move to Next Group
Move to Next Group
Move to First Group
Move to First Group
Move to Last Group
Move to Last Group
Move to Group Number
Move to Group Number
Read Media Control Point Opcodes Supported
Read Media Control Point Opcodes Supported
Search
Search
Read Content Control ID
Read Content Control ID
C
C
I
I
I
I
A
A
I
I
A
A
I
I
A
A
I
I
I
I
I
I
C
C
C
C
C
C
C
C
C
C
C
C
Broadcast Audio Reception Start
Broadcast Audio Reception Start
Adding Broadcast Sources
Adding Broadcast Sources
Modifying Broadcast Sources
Modifying Broadcast Sources
SyncInfo Transfer
SyncInfo Transfer
Setting Broadcast Code
Setting Broadcast Code
Removing Broadcast Sources
Removing Broadcast Sources
Broadcast Audio Reception Stop
Broadcast Audio Reception Stop
Broadcast to Unicast Audio Handover
Broadcast to Unicast Audio Handover
Unicast to Broadcast Audio Handover
Unicast to Broadcast Audio Handover
C
C
C
C
I
I
I
I
Distribute Broadcast_Code
Distribute Broadcast_Code
C
C
A
A
A
A
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/connectivity/networking/api/coap.rst b/doc/connectivity/networking/api/coap.rst index ffb794a0c8a..e3a4d01d594 100644 --- a/doc/connectivity/networking/api/coap.rst +++ b/doc/connectivity/networking/api/coap.rst @@ -17,7 +17,8 @@ that support CoAP's features. For more information about the protocol itself, see `IETF RFC7252 The Constrained Application Protocol `_. Zephyr provides a CoAP library which supports client and server roles. -The library is configurable as per user needs. The Zephyr CoAP library +The library can be enabled with :kconfig:option:`CONFIG_COAP` Kconfig option and +is configurable as per user needs. The Zephyr CoAP library is implemented using plain buffers. Users of the API create sockets for communication and pass the buffer to the library for parsing and other purposes. The library itself doesn't create any sockets for users. diff --git a/doc/connectivity/networking/api/coap_client.rst b/doc/connectivity/networking/api/coap_client.rst index 2251bb3d0da..0d682a04746 100644 --- a/doc/connectivity/networking/api/coap_client.rst +++ b/doc/connectivity/networking/api/coap_client.rst @@ -11,6 +11,7 @@ Overview ******** The CoAP client library allows application to send CoAP requests and parse CoAP responses. +The library can be enabled with :kconfig:option:`CONFIG_COAP_CLIENT` Kconfig option. The application is notified about the response via a callback that is provided to the API in the request. The CoAP client handles the communication over sockets. As the CoAP client doesn't create socket it is using, the application is responsible for creating diff --git a/doc/connectivity/networking/api/coap_server.rst b/doc/connectivity/networking/api/coap_server.rst index bd53630ad6c..1666880f2fc 100644 --- a/doc/connectivity/networking/api/coap_server.rst +++ b/doc/connectivity/networking/api/coap_server.rst @@ -27,7 +27,7 @@ Some configuration is required to make sure services can be started using the Co All services are added to a predefined linker section and all resources for each service also get their respective linker sections. If you would have a service ``my_service`` it has to be -prefixed wth ``coap_resource_`` and added to a linker file: +prefixed with ``coap_resource_`` and added to a linker file: .. code-block:: c :caption: ``sections-ram.ld`` @@ -125,9 +125,7 @@ Observable resources ******************** The CoAP server provides logic for parsing observe requests and stores these using the runtime data -of CoAP services. Together with observer events, enabled with -:kconfig:option:`CONFIG_COAP_OBSERVER_EVENTS`, the application can easily keep track of clients -and send state updates. An example using a temperature sensor can look like: +of CoAP services. An example using a temperature sensor can look like: .. code-block:: c @@ -138,15 +136,6 @@ and send state updates. An example using a temperature sensor can look like: static void notify_observers(struct k_work *work); K_WORK_DELAYABLE_DEFINE(temp_work, notify_observers); - static void temp_observer_event(struct coap_resource *resource, struct coap_observer *observer, - enum coap_observer_event event) - { - /* Only track the sensor temperature if an observer is active */ - if (event == COAP_OBSERVER_ADDED) { - k_work_schedule(&temp_work, K_SECONDS(1)); - } - } - static int send_temperature(struct coap_resource *resource, const struct sockaddr *addr, socklen_t addr_len, uint16_t age, uint16_t id, const uint8_t *token, uint8_t tkl, @@ -221,7 +210,6 @@ and send state updates. An example using a temperature sensor can look like: .path = temp_resource_path, .get = temp_get, .notify = temp_notify, - .observer_event_handler = temp_observer_event, }); static void notify_observers(struct k_work *work) @@ -234,6 +222,54 @@ and send state updates. An example using a temperature sensor can look like: k_work_reschedule(&temp_work, K_SECONDS(1)); } +CoAP Events +*********** + +By enabling :kconfig:option:`CONFIG_NET_MGMT_EVENT` the user can register for CoAP events. The +following example simply prints when an event occurs. + +.. code-block:: c + + #include + #include + #include + + #define COAP_EVENTS_SET (NET_EVENT_COAP_OBSERVER_ADDED | NET_EVENT_COAP_OBSERVER_REMOVED | \ + NET_EVENT_COAP_SERVICE_STARTED | NET_EVENT_COAP_SERVICE_STOPPED) + + void coap_event_handler(uint32_t mgmt_event, struct net_if *iface, + void *info, size_t info_length, void *user_data) + { + switch (mgmt_event) { + case NET_EVENT_COAP_OBSERVER_ADDED: + printk("CoAP observer added"); + break; + case NET_EVENT_COAP_OBSERVER_REMOVED: + printk("CoAP observer removed"); + break; + case NET_EVENT_COAP_SERVICE_STARTED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + printk("CoAP service %s started", net_event->service->name); + } else { + printk("CoAP service started"); + } + break; + case NET_EVENT_COAP_SERVICE_STOPPED: + if (info != NULL && info_length == sizeof(struct net_event_coap_service)) { + struct net_event_coap_service *net_event = info; + + printk("CoAP service %s stopped", net_event->service->name); + } else { + printk("CoAP service stopped"); + } + break; + } + } + + NET_MGMT_REGISTER_EVENT_HANDLER(coap_events, COAP_EVENTS_SET, coap_event_handler, NULL); + CoRE Link Format **************** diff --git a/doc/connectivity/networking/api/http.rst b/doc/connectivity/networking/api/http.rst index 060a41643d9..d32748e77fa 100644 --- a/doc/connectivity/networking/api/http.rst +++ b/doc/connectivity/networking/api/http.rst @@ -13,6 +13,7 @@ Overview The HTTP client library allows you to send HTTP requests and parse HTTP responses. The library communicates over the sockets API but it does not create sockets on its own. +It can be enabled with :kconfig:option:`CONFIG_HTTP_CLIENT` Kconfig option. The application must be responsible for creating a socket and passing it to the library. Therefore, depending on the application's needs, the library can communicate over diff --git a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png deleted file mode 100644 index b367a17dbee..00000000000 Binary files a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.png and /dev/null differ diff --git a/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg new file mode 100644 index 00000000000..c9da075b2a3 --- /dev/null +++ b/doc/connectivity/networking/api/images/lwm2m_engine_state_machine.svg @@ -0,0 +1,4 @@ + + + +
lwm2m_rd_client_start()
lwm2m_rd_client_start()
IDLE
IDLE
INIT
INIT
LwM2M engine state machine
LwM2M engine state machine
DO
REGISTRATION
DO...
if bootstrap needed
if bootstrap needed
Send bootstrap registration message
Send bootstrap registration message
DO
BOOTSTRAP REG
DO...
Send registration message
Send registration message
REGISTRATION
SENT
REGISTRATION...
Successful registration response
Emit event 5
Successful registration response...
REGISTRATION
DONE
REGISTRATION...
Only in queue mode
after idle period.
Emit event 10
Only in queue mode...
RX OFF
IDLE
RX OFF...
UPDATE SENT
UPDATE SENT
Update
Update
Update
Update
Successful update
Emit event 7
Successful update...
Send deregistration message
Send deregistration message
DEREGISTER
DEREGISTER
acknowledged
acknowledged
DEREGISTRATION
SENT
DEREGISTRATION...
stop requested
Emit event 9
stop requested...
Server
is disabled
Server...
DEREGISTERED
DEREGISTERED
lwm2m_rd_client_stop()
lwm2m_rd_...
NETWORK
ERROR
NETWORK...
Message transmisison
failed
Message...
Successful bootstrap registration response
Emit event 2
Successful bootstrap registration response...
BOOTSTRAP REQ SENT
BOOTSTRAP REQ SENT
Bootstrap finish from server
Bootstrap finish from server
BOOTSTRAP REQ DONE
BOOTSTRAP REQ DONE
BOOTSTRAP TRANS DONE
BOOTSTRAP TRANS DONE
Emit event 3
Emit event 3
Emit event 11
Emit event 11
Timeout while sending message
If not bootstrap, emit event 6
Timeout while sending message...
Failure code in response
or timeout
Emit event 6
Failure code in response...
Registration failed,
emit event 4
Registration failed,...
Failure
Event 8
Failure...
UPDATE REGISTRATION
UPDATE REGISTRATION
Send update registration
message 
Send update registration...
Registration lifetime
is not yet expired
Registration lifetime...
fallback
fallback
Suspending
Suspending
lwm2m_engine_pause()
lwm2m_engine_pause()
lwm2m_engine_resume()
lwm2m_engine_resume()
ANY
STATE
ANY...
SUSPENDED
SUSPENDED
DO
REGISTRATION
DO...

state was
UPDATE_SENT?

state was...

Y

Y

N

N
REGISTRATION
DONE
REGISTRATION...

N

N

Y

Y

time for
update?

time for...
Bootstrap failed,
emit event 1
Bootstrap...

SERVER
DISABLED
SERVER...
Server disabled,
emit event 12
Server disabled,...
Cannot recover,
emit event 13
Cannot recover,...
Disable timer
expired
Disable timer...
connecting
connecting
connected
connected
stopped
stopped
Disconnected
for a perdiod
Disconnected...
Disconnecting
or stopping
Disconnecting...
Color coding
Color coding
recovering
recovering
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/connectivity/networking/api/index.rst b/doc/connectivity/networking/api/index.rst index 2386a075460..1264ff2aafb 100644 --- a/doc/connectivity/networking/api/index.rst +++ b/doc/connectivity/networking/api/index.rst @@ -3,6 +3,17 @@ Networking APIs ############### +Zephyr provides support for the standard BSD socket APIs (defined in +:zephyr_file:`include/zephyr/net/socket.h`) for the applications to +use. See :ref:`BSD socket API ` for more details. + +Apart of the standard API, Zephyr provides a set of custom networking APIs and +libraries for the application to use. See the list below for details. + +.. note:: + The legacy connectivity API in :zephyr_file:`include/zephyr/net/net_context.h` + should not be used by applications. + .. toctree:: :maxdepth: 2 diff --git a/doc/connectivity/networking/api/lwm2m.rst b/doc/connectivity/networking/api/lwm2m.rst index 3baa4516c5d..8aab68e54ca 100644 --- a/doc/connectivity/networking/api/lwm2m.rst +++ b/doc/connectivity/networking/api/lwm2m.rst @@ -25,6 +25,8 @@ REST API to manage various interfaces with the client. LwM2M uses a simple resource model with the core set of objects and resources defined in the specification. +The LwM2M library can be enabled with :kconfig:option:`CONFIG_LWM2M` Kconfig option. + Example LwM2M object and resources: Device ****************************************** @@ -326,6 +328,9 @@ events, setup a callback function: LOG_DBG("Deregistration client"); break; + case LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED: + LOG_DBG("LwM2M server disabled"); + break; } } @@ -445,7 +450,7 @@ An example of setting up the security object for X509 certificate mode: lwm2m_set_u8(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 2), LWM2M_SECURITY_CERT); lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 3), certificate); lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), key); - lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 5), root_ca); + lwm2m_set_string(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 4), root_ca); Before calling :c:func:`lwm2m_rd_client_start` assign the tls_tag # where the LwM2M library should store the DTLS information prior to connection (normally a @@ -545,7 +550,7 @@ The engine state machine shows when the events are spawned. Events depicted in the diagram are listed in the table. The events are prefixed with ``LWM2M_RD_CLIENT_EVENT_``. -.. figure:: images/lwm2m_engine_state_machine.png +.. figure:: images/lwm2m_engine_state_machine.svg :alt: LwM2M engine state machine State machine for the LwM2M engine @@ -557,79 +562,116 @@ The events are prefixed with ``LWM2M_RD_CLIENT_EVENT_``. * - Event ID - Event Name - Description - - Actions * - 0 - NONE - No event - - Do nothing * - 1 - BOOTSTRAP_REG_FAILURE - Bootstrap registration failed. Occurs if there is a timeout or failure in bootstrap registration. - - Retry bootstrap * - 2 - BOOTSTRAP_REG_COMPLETE - Bootstrap registration complete. Occurs after successful bootstrap registration. - - No actions needed * - 3 - BOOTSTRAP_TRANSFER_COMPLETE - Bootstrap finish command received from the server. - - No actions needed, client proceeds to registration. * - 4 - REGISTRATION_FAILURE - Registration to LwM2M server failed. Occurs if there is a failure in the registration. - - Retry registration * - 5 - REGISTRATION_COMPLETE - Registration to LwM2M server successful. Occurs after a successful registration reply from the LwM2M server or when session resumption is used. - - No actions needed * - 6 - REG_TIMEOUT - Registration or registration update timeout. - Occurs if there is a timeout during registration. - NOTE: If registration fails without a timeout, - a full registration is triggered automatically and - no registration update failure event is generated. - - No actions needed, client proceeds to re-registration automatically. + Occurs if there is a timeout during registration. Client have lost connection to the server. * - 7 - REG_UPDATE_COMPLETE - Registration update completed. Occurs after successful registration update reply from the LwM2M server. - - No actions needed * - 8 - DEREGISTER_FAILURE - Deregistration to LwM2M server failed. Occurs if there is a timeout or failure in the deregistration. - - No actions needed, client proceeds to idle state automatically. * - 9 - DISCONNECT - - Disconnected from LwM2M server. - Occurs if there is a timeout during communication with server. - Also triggered after deregistration has been done. - - If connection is required, the application should restart the client. + - LwM2M client have de-registered from server and is now stopped. + Triggered only if the application have requested the client to stop. * - 10 - QUEUE_MODE_RX_OFF - Used only in queue mode, not actively listening for incoming packets. In queue mode the client is not required to actively listen for the incoming packets after a configured time period. - - No actions needed * - 11 - ENGINE_SUSPENDED - Indicate that client has now paused as a result of calling :c:func:`lwm2m_engine_pause`. State machine is no longer running and the handler thread is suspended. All timers are stopped so notifications are not triggered. - - Engine can be resumed by calling :c:func:`lwm2m_engine_resume`. * - 12 + - SERVER_DISABLED + - Server have executed the disable command. + Client will deregister and stay idle for the disable period. + * - 13 - NETWORK_ERROR - Sending messages to the network failed too many times. - If sending a message fails, it will be retried. - If the retry counter reaches its limits, this event will be triggered. - - No actions needed, client will do a re-registrate automatically. + Client cannot reach any servers or fallback to bootstrap. + LwM2M engine cannot recover and have stopped. + +The LwM2M client engine handles most of the state transitions automatically. The application +needs to handle only the events that indicate that the client have stopped or is in a state +where it cannot recover. +.. list-table:: How application should react to events + :widths: auto + :header-rows: 1 + + * - Event Name + - How application should react + * - NONE + - Ignore the event. + * - BOOTSTRAP_REG_FAILURE + - Try to recover network connection. Then restart the client by calling :c:func:`lwm2m_rd_client_start`. + This might also indicate configuration issue. + * - BOOTSTRAP_REG_COMPLETE + - No actions needed + * - BOOTSTRAP_TRANSFER_COMPLETE + - No actions needed + * - REGISTRATION_FAILURE + - No actions needed + * - REGISTRATION_COMPLETE + - No actions needed. + Application can send or receive data. + * - REG_TIMEOUT + - No actions needed. + Client proceeds to re-registration automatically. Cannot send or receive data. + * - REG_UPDATE_COMPLETE + - No actions needed + Application can send or receive data. + * - DEREGISTER_FAILURE + - No actions needed, client proceeds to idle state automatically. Cannot send or receive data. + * - DISCONNECT + - Engine have stopped as a result of calling :c:func:`lwm2m_rd_client_stop`. + If connection is required, the application should restart the client by calling :c:func:`lwm2m_rd_client_start`. + * - QUEUE_MODE_RX_OFF + - No actions needed. + Application can send but cannot receive data. + Any data transmission will trigger a registration update. + * - ENGINE_SUSPENDED + - Engine can be resumed by calling :c:func:`lwm2m_engine_resume`. + Cannot send or receive data. + * - SERVER_DISABLED + - No actions needed, client will re-register once the disable period is over. + Cannot send or receive data. + * - NETWORK_ERROR + - Try to recover network connection. Then restart the client by calling :c:func:`lwm2m_rd_client_start`. + This might also indicate configuration issue. + +Sending of data in the table above refers to calling :c:func:`lwm2m_send_cb` or by writing into of of the observed resources where observation would trigger a notify message. +Receiving of data refers to receiving read, write or execute operations from the server. Application can register callbacks for these operations. Configuring lifetime and activity period **************************************** diff --git a/doc/connectivity/networking/api/mqtt.rst b/doc/connectivity/networking/api/mqtt.rst index 16ba69e1288..79da5abe57b 100644 --- a/doc/connectivity/networking/api/mqtt.rst +++ b/doc/connectivity/networking/api/mqtt.rst @@ -16,7 +16,8 @@ publish/subscribe messaging transport for machine-to-machine communication. For more information about the protocol itself, see http://mqtt.org/. Zephyr provides an MQTT client library built on top of BSD sockets API. The -library is configurable at a per-client basis, with support for MQTT versions +library can be enabled with :kconfig:option:`CONFIG_MQTT_LIB` Kconfig option and +is configurable at a per-client basis, with support for MQTT versions 3.1.0 and 3.1.1. The Zephyr MQTT implementation can be used with either plain sockets communicating over TCP, or with secure sockets communicating over TLS. See :ref:`bsd_sockets_interface` for more information about Zephyr sockets. @@ -108,7 +109,7 @@ application through the callback function. fds[0].fd = client_ctx.transport.tcp.sock; fds[0].events = ZSOCK_POLLIN; - poll(fds, 1, K_MSEC(5000)); + poll(fds, 1, 5000); mqtt_input(&client_ctx); diff --git a/doc/connectivity/networking/api/mqtt_sn.rst b/doc/connectivity/networking/api/mqtt_sn.rst index 3da4d903725..3235725f2e3 100644 --- a/doc/connectivity/networking/api/mqtt_sn.rst +++ b/doc/connectivity/networking/api/mqtt_sn.rst @@ -17,7 +17,8 @@ over any message-based transport. Originally, it was mainly created with ZigBee but others like Bluetooth, UDP or even a UART can be used just as well. Zephyr provides an MQTT-SN client library built on top of BSD sockets API. The -library is configurable at a per-client basis, with support for MQTT-SN version +library can be enabled with :kconfig:option:`CONFIG_MQTT_SN_LIB` Kconfig option +and is configurable at a per-client basis, with support for MQTT-SN version 1.2. The Zephyr MQTT-SN implementation can be used with any message-based transport, but support for UDP is already built-in. @@ -89,7 +90,7 @@ advertisement mechanism, this is not implemented yet in the library. Call the ``mqtt_sn_connect`` function, which will send a ``CONNECT`` message. The application should periodically call the ``mqtt_sn_input`` function to process -the response received. The appliation does not have to call ``mqtt_sn_input`` if it +the response received. The application does not have to call ``mqtt_sn_input`` if it knows that no data has been received (e.g. when using Bluetooth). Note that ``mqtt_sn_input`` is a non-blocking function, if the transport struct contains a ``poll`` compatible function pointer. diff --git a/doc/connectivity/networking/api/net_mgmt.rst b/doc/connectivity/networking/api/net_mgmt.rst index ed6c512a742..2973ee82b04 100644 --- a/doc/connectivity/networking/api/net_mgmt.rst +++ b/doc/connectivity/networking/api/net_mgmt.rst @@ -49,17 +49,19 @@ Listening to network events You can receive notifications on network events by registering a callback function and specifying a set of events used to filter when -your callback is invoked. The callback will have to be unique for a +your callback is invoked. The callback will have to be unique for a pair of layer and code, whereas on the command part it will be a mask of events. -Two functions are available, :c:func:`net_mgmt_add_event_callback` for -registering the callback function, and -:c:func:`net_mgmt_del_event_callback` +At runtime two functions are available, :c:func:`net_mgmt_add_event_callback` +for registering the callback function, and :c:func:`net_mgmt_del_event_callback` for unregistering a callback. A helper function, :c:func:`net_mgmt_init_event_callback`, can be used to ease the initialization of the callback structure. +Additionally :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER` can be used to +register a callback handler at compile time. + When an event occurs that matches a callback's event set, the associated callback function is invoked with the actual event code. This makes it possible for different events to be handled by the @@ -121,6 +123,44 @@ An example follows. net_mgmt_add_event_callback(&ipv4_callback); } +Or similarly using :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER`. + +.. note:: + + The ``info`` and ``info_length`` arguments are only usable if + :kconfig:option:`CONFIG_NET_MGMT_EVENT_INFO` is enabled. Otherwise these are + ``NULL`` and zero. + +.. code-block:: c + + /* + * Set of events to handle. + */ + #define EVENT_IFACE_SET (NET_EVENT_IF_xxx | NET_EVENT_IF_yyy) + #define EVENT_IPV4_SET (NET_EVENT_IPV4_xxx | NET_EVENT_IPV4_yyy) + + static void event_handler(uint32_t mgmt_event, struct net_if *iface, + void *info, size_t info_length, + void *user_data) + { + if (mgmt_event == NET_EVENT_IF_xxx) { + /* Handle NET_EVENT_IF_xxx */ + } else if (mgmt_event == NET_EVENT_IF_yyy) { + /* Handle NET_EVENT_IF_yyy */ + } else if (mgmt_event == NET_EVENT_IPV4_xxx) { + /* Handle NET_EVENT_IPV4_xxx */ + } else if (mgmt_event == NET_EVENT_IPV4_yyy) { + /* Handle NET_EVENT_IPV4_yyy */ + } else { + /* Spurious (false positive) invocation. */ + } + } + + NET_MGMT_REGISTER_EVENT_HANDLER(iface_event_handler, EVENT_IFACE_SET, + event_handler, NULL); + NET_MGMT_REGISTER_EVENT_HANDLER(ipv4_event_handler, EVENT_IPV4_SET, + event_handler, NULL); + See :zephyr_file:`include/zephyr/net/net_event.h` for available generic core events that can be listened to. diff --git a/doc/connectivity/networking/api/ppp.rst b/doc/connectivity/networking/api/ppp.rst index d0028a075aa..74e2da248f7 100644 --- a/doc/connectivity/networking/api/ppp.rst +++ b/doc/connectivity/networking/api/ppp.rst @@ -21,9 +21,8 @@ In Zephyr, each individual PPP link is modelled as a network interface. This is similar to how Linux implements PPP. PPP support must be enabled at compile time by setting option -:kconfig:option:`CONFIG_NET_PPP` and :kconfig:option:`CONFIG_NET_L2_PPP`. -The PPP support in Zephyr 2.0 is still experimental and the implementation -supports only these protocols: +:kconfig:option:`CONFIG_NET_L2_PPP`. +The PPP implementation supports only these protocols: * LCP (Link Control Protocol, `RFC1661 `__) @@ -34,9 +33,8 @@ supports only these protocols: * IPV6CP (IPv6 Control Protocol, `RFC5072 `__) -See also the :zephyr_file:`samples/net/sockets/echo_server/overlay-ppp.conf` -file for configuration option examples. -For using PPP with GSM modem, see :ref:`gsm_modem` for additional information. +For using PPP with a cellular modem, see :zephyr:code-sample:`cellular-modem` sample +for additional information. Testing ******* diff --git a/doc/connectivity/networking/api/sockets.rst b/doc/connectivity/networking/api/sockets.rst index 720bebeb820..5ea4429cf13 100644 --- a/doc/connectivity/networking/api/sockets.rst +++ b/doc/connectivity/networking/api/sockets.rst @@ -57,6 +57,10 @@ there is a table mapping file descriptors to internal object pointers. The file descriptor table is used by the BSD Sockets API even if the rest of the POSIX subsystem (filesystem, stdin/stdout) is not enabled. +See :zephyr:code-sample:`sockets-echo-server` and :zephyr:code-sample:`sockets-echo-client` +sample applications to learn how to create a simple server or client BSD socket based +application. + .. _secure_sockets_interface: Secure Sockets @@ -157,17 +161,25 @@ option. A network driver that wants to register a new socket implementation should use :c:macro:`NET_SOCKET_OFFLOAD_REGISTER` macro. The macro accepts the following parameters: - * socket_name - an arbitrary name for the socket implementation. - * prio - socket implementation priority, the higher priority is, the earlier - particular implementation is processed when creating a new socket. - Lower numeric value indicate higher priority. - * _family - socket family implemented by the offloaded socket. ``AF_UNSPEC`` - indicate any family. - * _is_supported - a filtering function, used to verify whether particular - socket family, type and protocol are supported by the - offloaded socket implementation. - * _handler - a function compatible with :c:func:`socket` API, used to create - an offloaded socket. + * ``socket_name`` + An arbitrary name for the socket implementation. + + * ``prio`` + Socket implementation's priority. The higher the priority, the earlier this + particular implementation will be processed when creating a new socket. + Lower numeric value indicates higher priority. + + * ``_family`` + Socket family implemented by the offloaded socket. ``AF_UNSPEC`` indicates + any family. + + * ``_is_supported`` + A filtering function, used to verify whether a particular socket family, + type and protocol are supported by the offloaded socket implementation. + + * ``_handler`` + A function compatible with :c:func:`socket` API, used to create an + offloaded socket. Every offloaded socket implementation should also implement a set of socket APIs, specified in :c:struct:`socket_op_vtable` struct. diff --git a/doc/connectivity/networking/api/tftp.rst b/doc/connectivity/networking/api/tftp.rst index 36d9d2cf0bb..6bb309e0791 100644 --- a/doc/connectivity/networking/api/tftp.rst +++ b/doc/connectivity/networking/api/tftp.rst @@ -3,6 +3,12 @@ TFTP #### +Zephyr provides a simple TFTP client library that can enabled with +:kconfig:option:`CONFIG_MQTT_SN_LIB` Kconfig option. + +See :zephyr:code-sample:`TFTP client sample application ` for +more information about the library usage. + API Reference ************* diff --git a/doc/connectivity/networking/api/tls_credentials_shell.rst b/doc/connectivity/networking/api/tls_credentials_shell.rst index 69749a8f972..76c074ae67d 100644 --- a/doc/connectivity/networking/api/tls_credentials_shell.rst +++ b/doc/connectivity/networking/api/tls_credentials_shell.rst @@ -13,7 +13,7 @@ Commands Buffer Credential (``buf``) =========================== -Buffer data incrementaly into the credential buffer so that it can be added using the :ref:`tls_credentials_shell_add_cred` command. +Buffer data incrementally into the credential buffer so that it can be added using the :ref:`tls_credentials_shell_add_cred` command. Alternatively, clear the credential buffer. diff --git a/doc/connectivity/networking/api/websocket.rst b/doc/connectivity/networking/api/websocket.rst index f803e7b2ef8..b1450ae8f90 100644 --- a/doc/connectivity/networking/api/websocket.rst +++ b/doc/connectivity/networking/api/websocket.rst @@ -63,7 +63,7 @@ is supported. In order to send BINARY data, the :c:func:`websocket_send_msg()` must be used. When done, the Websocket transport socket must be closed. User should handle -the lifecycle(close/re-use) of tcp socket after websocket_disconnect. +the lifecycle(close/reuse) of tcp socket after websocket_disconnect. .. code-block:: c diff --git a/doc/connectivity/networking/conn_mgr/implementation.rst b/doc/connectivity/networking/conn_mgr/implementation.rst index 932ec7668d2..f598d571d5e 100644 --- a/doc/connectivity/networking/conn_mgr/implementation.rst +++ b/doc/connectivity/networking/conn_mgr/implementation.rst @@ -281,7 +281,7 @@ If exceptions to this are absolutely necessary, they should be constrained to sp While connectivity implementations must not break, it is acceptable for implementations to have potentially unexpected behavior if applications attempt to directly control the association state. - For instance, if an application directly instructs an underlying technology to dissassociate, it would be acceptable for the connectivity implementation to interpret this as an unexpected connection loss and immediately attempt to re-associate. + For instance, if an application directly instructs an underlying technology to disassociate, it would be acceptable for the connectivity implementation to interpret this as an unexpected connection loss and immediately attempt to re-associate. .. _conn_mgr_impl_guidelines_non_blocking: diff --git a/doc/connectivity/networking/conn_mgr/main.rst b/doc/connectivity/networking/conn_mgr/main.rst index 675be831418..fd7a8bf87ee 100644 --- a/doc/connectivity/networking/conn_mgr/main.rst +++ b/doc/connectivity/networking/conn_mgr/main.rst @@ -197,7 +197,7 @@ Connectivity control Many network interfaces require a network association procedure to be completed before being usable. -For such ifaces, connectivity control can provide a generic API to request network association (:c:func:`conn_mgr_if_connect`) and dissasociation (:c:func:`conn_mgr_if_disconnect`). +For such ifaces, connectivity control can provide a generic API to request network association (:c:func:`conn_mgr_if_connect`) and disassociation (:c:func:`conn_mgr_if_disconnect`). Network interfaces implement support for this API by :ref:`binding themselves to a connectivity implementation `. Using this API, applications can associate with networks with minimal technology-specific boilerplate. @@ -220,7 +220,7 @@ The following sections outline the basic operation of Connection Manager's conne Binding ------- -Before an iface can be commanded to associate or dissasociate using Connection Manager, it must first be bound to a :ref:`connectivity implementation `. +Before an iface can be commanded to associate or disassociate using Connection Manager, it must first be bound to a :ref:`connectivity implementation `. Binding is performed by the provider of the iface, not by the application (see :ref:`conn_mgr_impl_binding`), and can be thought of as an extension of the iface declaration. Once an iface is bound, all connectivity commands passed to it (such as :c:func:`conn_mgr_if_connect` or :c:func:`conn_mgr_if_disconnect`) will be routed to the corresponding implementation function in the connectivity implementation. diff --git a/doc/connectivity/networking/index.rst b/doc/connectivity/networking/index.rst index f900bb56330..26dfbb14147 100644 --- a/doc/connectivity/networking/index.rst +++ b/doc/connectivity/networking/index.rst @@ -12,7 +12,7 @@ operation of the stacks and how they were implemented. overview.rst net-stack-architecture.rst - networking-api-usage.rst + net_config_guide.rst networking_with_host.rst network_monitoring.rst api/index.rst diff --git a/doc/connectivity/networking/net_config_guide.rst b/doc/connectivity/networking/net_config_guide.rst new file mode 100644 index 00000000000..b8341744979 --- /dev/null +++ b/doc/connectivity/networking/net_config_guide.rst @@ -0,0 +1,273 @@ +.. _network_configuration_guide: + +Network Configuration Guide +########################### + +.. contents:: + :local: + :depth: 2 + +This document describes how various network configuration options can be +set according to available resources in the system. + +Network Buffer Configuration Options +************************************ + +The network buffer configuration options control how much data we +are able to either send or receive at the same time. + +:kconfig:option:`CONFIG_NET_PKT_RX_COUNT` + Maximum amount of network packets we can receive at the same time. + +:kconfig:option:`CONFIG_NET_PKT_TX_COUNT` + Maximum amount of network packet sends pending at the same time. + +:kconfig:option:`CONFIG_NET_BUF_RX_COUNT` + How many network buffers are allocated for receiving data. + Each net_buf contains a small header and either a fixed or variable + length data buffer. The :kconfig:option:`CONFIG_NET_BUF_DATA_SIZE` + is used when :kconfig:option:`CONFIG_NET_BUF_FIXED_DATA_SIZE` is set. + This is the default setting. The default size of the buffer is 128 bytes. + + The :kconfig:option:`CONFIG_NET_BUF_VARIABLE_DATA_SIZE` is an experimental + setting. There each net_buf data portion is allocated from a memory pool and + can be the amount of data we have received from the network. + When data is received from the network, it is placed into net_buf data portion. + Depending on device resources and desired network usage, user can tweak + the size of the fixed buffer by setting :kconfig:option:`CONFIG_NET_BUF_DATA_SIZE`, and + the size of the data pool size by setting :kconfig:option:`CONFIG_NET_BUF_DATA_POOL_SIZE` + if variable size buffers are used. + + When using the fixed size data buffers, the memory consumption of network buffers + can be tweaked by selecting the size of the data part according to what kind of network + data we are receiving. If one sets the data size to 256, but only receives packets + that are 32 bytes long, then we are "wasting" 224 bytes for each packet because we + cannot utilize the remaining data. One should not set the data size too low because + there is some overhead involved for each net_buf. For these reasons the default + network buffer size is set to 128 bytes. + + The variable size data buffer feature is marked as experimental as it has not + received as much testing as the fixed size buffers. Using variable size data + buffers tries to improve memory utilization by allocating minimum amount of + data we need for the network data. The extra cost here is the amount of time + that is needed when dynamically allocating the buffer from the memory pool. + + For example, in Ethernet the maximum transmission unit (MTU) size is 1500 bytes. + If one wants to receive two full frames, then the net_pkt RX count should be set to 2, + and net_buf RX count to (1500 / 128) * 2 which is 24. + If TCP is being used, then these values need to be higher because we can queue the + packets internally before delivering to the application. + +:kconfig:option:`CONFIG_NET_BUF_TX_COUNT` + How many network buffers are allocated for sending data. This is similar setting + as the receive buffer count but for sending. + + +Connection Options +****************** + +:kconfig:option:`CONFIG_NET_MAX_CONN` + This option tells how many network connection endpoints are supported. + For example each TCP connection requires one connection endpoint. Similarly + each listening UDP connection requires one connection endpoint. + Also various system services like DHCP and DNS need connection endpoints to work. + The network shell command **net conn** can be used at runtime to see the + network connection information. + +:kconfig:option:`CONFIG_NET_MAX_CONTEXTS` + Number of network contexts to allocate. Each network context describes a network + 5-tuple that is used when listening or sending network traffic. Each BSD socket in the + system uses one network context. + + +Socket Options +************** + +:kconfig:option:`CONFIG_NET_SOCKETS_POLL_MAX` + Maximum number of supported poll() entries. One needs to select proper value here depending + on how many BSD sockets are polled in the system. + +:kconfig:option:`CONFIG_POSIX_MAX_FDS` + Maximum number of open file descriptors, this includes files, sockets, special devices, etc. + One needs to select proper value here depending on how many BSD sockets are created in + the system. + +:kconfig:option:`CONFIG_NET_SOCKETPAIR_BUFFER_SIZE` + This option is used by socketpair() function. It sets the size of the + internal intermediate buffer, in bytes. This sets the limit how large + messages can be passed between two socketpair endpoints. + + +TLS Options +*********** + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS` + Maximum number of TLS/DTLS contexts. Each TLS/DTLS connection needs one context. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS` + This variable sets maximum number of TLS/DTLS credentials that can be + used with a specific socket. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CIPHERSUITES` + Maximum number of TLS/DTLS ciphersuites per socket. + This variable sets maximum number of TLS/DTLS ciphersuites that can + be used with specific socket, if set explicitly by socket option. + By default, all ciphersuites that are available in the system are + available to the socket. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_APP_PROTOCOLS` + Maximum number of supported application layer protocols. + This variable sets maximum number of supported application layer + protocols over TLS/DTLS that can be set explicitly by a socket option. + By default, no supported application layer protocol is set. + +:kconfig:option:`CONFIG_NET_SOCKETS_TLS_MAX_CLIENT_SESSION_COUNT` + This variable specifies maximum number of stored TLS/DTLS sessions, + used for TLS/DTLS session resumption. + +:kconfig:option:`CONFIG_TLS_MAX_CREDENTIALS_NUMBER` + Maximum number of TLS credentials that can be registered. + Make sure that this value is high enough so that all the + certificates can be loaded to the store. + + +IPv4/6 Options +************** + +:kconfig:option:`CONFIG_NET_IF_MAX_IPV4_COUNT` + Maximum number of IPv4 network interfaces in the system. + This tells how many network interfaces there will be in the system + that will have IPv4 enabled. + For example if you have two network interfaces, but only one of them + can use IPv4 addresses, then this value can be set to 1. + If both network interface could use IPv4, then the setting should be + set to 2. + +:kconfig:option:`CONFIG_NET_IF_MAX_IPV6_COUNT` + Maximum number of IPv6 network interfaces in the system. + This is similar setting as the IPv4 count option but for IPv6. + + +TCP Options +*********** + +:kconfig:option:`CONFIG_NET_TCP_TIME_WAIT_DELAY` + How long to wait in TCP *TIME_WAIT* state (in milliseconds). + To avoid a (low-probability) issue when delayed packets from + previous connection get delivered to next connection reusing + the same local/remote ports, + `RFC 793 `_ (TCP) suggests + to keep an old, closed connection in a special *TIME_WAIT* state for + the duration of 2*MSL (Maximum Segment Lifetime). The RFC + suggests to use MSL of 2 minutes, but notes + + *This is an engineering choice, and may be changed if experience indicates + it is desirable to do so.* + + For low-resource systems, having large MSL may lead to quick + resource exhaustion (and related DoS attacks). At the same time, + the issue of packet misdelivery is largely alleviated in the modern + TCP stacks by using random, non-repeating port numbers and initial + sequence numbers. Due to this, Zephyr uses much lower value of 1500ms + by default. Value of 0 disables *TIME_WAIT* state completely. + +:kconfig:option:`CONFIG_NET_TCP_RETRY_COUNT` + Maximum number of TCP segment retransmissions. + The following formula can be used to determine the time (in ms) + that a segment will be be buffered awaiting retransmission: + + .. math:: + + \sum_{n=0}^{\mathtt{NET\_TCP\_RETRY\_COUNT}} \bigg(1 \ll n\bigg)\times + \mathtt{NET\_TCP\_INIT\_RETRANSMISSION\_TIMEOUT} + + With the default value of 9, the IP stack will try to + retransmit for up to 1:42 minutes. This is as close as possible + to the minimum value recommended by + `RFC 1122 `_ (1:40 minutes). + Only 5 bits are dedicated for the retransmission count, so accepted + values are in the 0-31 range. It's highly recommended to not go + below 9, though. + + Should a retransmission timeout occur, the receive callback is + called with :code:`-ETIMEDOUT` error code and the context is dereferenced. + +:kconfig:option:`CONFIG_NET_TCP_MAX_SEND_WINDOW_SIZE` + Maximum sending window size to use. + This value affects how the TCP selects the maximum sending window + size. The default value 0 lets the TCP stack select the value + according to amount of network buffers configured in the system. + Note that if there are multiple active TCP connections in the system, + then this value might require finetuning (lowering), otherwise multiple + TCP connections could easily exhaust net_buf pool for the queued TX data. + +:kconfig:option:`CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE` + Maximum receive window size to use. + This value defines the maximum TCP receive window size. Increasing + this value can improve connection throughput, but requires more + receive buffers available in the system for efficient operation. + The default value 0 lets the TCP stack select the value + according to amount of network buffers configured in the system. + +:kconfig:option:`CONFIG_NET_TCP_RECV_QUEUE_TIMEOUT` + How long to queue received data (in ms). + If we receive out-of-order TCP data, we queue it. This value tells + how long the data is kept before it is discarded if we have not been + able to pass the data to the application. If set to 0, then receive + queueing is not enabled. The value is in milliseconds. + + Note that we only queue data sequentially in current version i.e., + there should be no holes in the queue. For example, if we receive + SEQs 5,4,3,6 and are waiting SEQ 2, the data in segments 3,4,5,6 is + queued (in this order), and then given to application when we receive + SEQ 2. But if we receive SEQs 5,4,3,7 then the SEQ 7 is discarded + because the list would not be sequential as number 6 is be missing. + + +Traffic Class Options +********************* + +It is possible to configure multiple traffic classes (queues) when receiving +or sending network data. Each traffic class queue is implemented as a thread +with different priority. This means that higher priority network packet can +be placed to a higher priority network queue in order to send or receive it +faster or slower. Because of thread scheduling latencies, in practice the +fastest way to send a packet out, is to directly send the packet without +using a dedicated traffic class thread. This is why by default the +:kconfig:option:`CONFIG_NET_TC_TX_COUNT` option is set to 0 if userspace is +not enabled. If userspace is enabled, then the minimum TX traffic class +count is 1. Reason for this is that the userspace application does not +have enough permissions to deliver the message directly. + +In receiving side, it is recommended to have at least one receiving traffic +class queue. Reason is that typically the network device driver is running +in IRQ context when it receives the packet, in which case it should not try +to deliver the network packet directly to the upper layers, but to place +the packet to the traffic class queue. If the network device driver is not +running in IRQ context when it gets the packet, then the RX traffic class +option :kconfig:option:`CONFIG_NET_TC_RX_COUNT` could be set to 0. + + +Stack Size Options +****************** + +There several network specific threads in a network enabled system. +Some of the threads might depend on a configure option which can be +used to enable or disable a feature. Each thread stack size is optimized +to allow normal network operations. + +The network management API is using a dedicated thread by default. The thread +is responsible to deliver network management events to the event listeners that +are setup in the system if the :kconfig:option:`CONFIG_NET_MGMT` and +:kconfig:option:`CONFIG_NET_MGMT_EVENT` options are enabled. +If the options are enabled, the user is able to register a callback function +that the net_mgmt thread is calling for each network management event. +By default the net_mgmt event thread stack size is rather small. +The idea is that the callback function does minimal things so that new +events can be delivered to listeners as fast as possible and they are not lost. +The net_mgmt event thread stack size is controlled by +:kconfig:option:`CONFIG_NET_MGMT_EVENT_QUEUE_SIZE` option. It is recommended +to not do any blocking operations in the callback function. + +The network thread stack utilization can be monitored from kernel shell by +the **kernel threads** command. diff --git a/doc/connectivity/networking/networking-api-usage.rst b/doc/connectivity/networking/networking-api-usage.rst deleted file mode 100644 index 0145482fec9..00000000000 --- a/doc/connectivity/networking/networking-api-usage.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _networking_api_usage: - -Network Connectivity API -######################## - -Applications should use the BSD socket API defined in -:zephyr_file:`include/zephyr/net/socket.h` to create a connection, send or receive data, -and close a connection. The same API can be used when working with UDP or -TCP data. See :ref:`BSD socket API ` for more details. - -See :zephyr:code-sample:`sockets-echo-server` and :zephyr:code-sample:`sockets-echo-client` -sample applications to learn how to create a simple server or client BSD socket based -application. - -The legacy connectivity API in :zephyr_file:`include/zephyr/net/net_context.h` should not be -used by applications. diff --git a/doc/connectivity/usb/device/usb_device.rst b/doc/connectivity/usb/device/usb_device.rst index 134ec5972cd..bf446ae7524 100644 --- a/doc/connectivity/usb/device/usb_device.rst +++ b/doc/connectivity/usb/device/usb_device.rst @@ -537,6 +537,8 @@ The following Product IDs are currently used: +----------------------------------------------------+--------+ | :zephyr:code-sample:`wpan-usb` | 0x000D | +----------------------------------------------------+--------+ +| :zephyr:code-sample:`uac2-explicit-feedback` | 0x000E | ++----------------------------------------------------+--------+ The USB device descriptor field ``bcdDevice`` (Device Release Number) represents the Zephyr kernel major and minor versions as a binary coded decimal value. diff --git a/doc/contribute/bin_blobs.rst b/doc/contribute/bin_blobs.rst index 661007927a0..14c181e4058 100644 --- a/doc/contribute/bin_blobs.rst +++ b/doc/contribute/bin_blobs.rst @@ -1,7 +1,7 @@ .. _bin-blobs: Binary Blobs -************ +############ In the context of an operating system that supports multiple architectures and many different IC families, some functionality may be unavailable without the @@ -22,7 +22,7 @@ therefore free to create Zephyr-based downstream software which uses binary blobs if they cannot meet the requirements described in this page. Software license -================ +**************** Most binary blobs are distributed under proprietary licenses which vary significantly in nature and conditions. It is up to the vendor to specify the @@ -30,7 +30,7 @@ license as part of the blob submission process. Blob vendors may impose a click-through or other EULA-like workflow when users fetch and install blobs. Hosting -======= +******* Blobs must be hosted on the Internet and managed by third-party infrastructure. Two potential examples are Git repositories and web servers managed by @@ -40,10 +40,10 @@ The Zephyr Project does not host binary blobs in its Git repositories or anywhere else. Fetching blobs -============== +************** Blobs are fetched from official third-party sources by the :ref:`west blobs -command ` command. +` command. The blobs themselves must be specified in the :ref:`module.yml ` files included in separate Zephyr :ref:`module repositories @@ -76,7 +76,7 @@ Any accompanying code, including interface header files for the blobs, must be present in the corresponding module repository. Tainting -======== +******** Inclusion of binary blobs will taint the Zephyr build. The definition of tainting originates in the `Linux kernel @@ -96,7 +96,7 @@ Tainting will be communicated to the user in the following manners: .. _bin-blobs-types: Allowed types -============= +************* The following binary blob types are acceptable in Zephyr: @@ -121,7 +121,7 @@ In case of disagreement, the TSC is the arbiter of whether a particular blob fits in one of the above types. Precompiled library-specific requirements -========================================= +***************************************** This section contains additional requirements specific to precompiled library blobs. @@ -132,14 +132,14 @@ distribution if it is discovered that the blob fails to meet these requirements later on. Interface header files ----------------------- +====================== The precompiled library must be accompanied by one or more header files, distributed under a non-copyleft OSI approved license, that define the interface to the library. Allowed dependencies --------------------- +==================== This section defines requirements related to external symbols that a library blob requires the build system to provide. @@ -155,7 +155,7 @@ blob requires the build system to provide. released under an OSI approved license and documented using Doxygen Toolchain requirements ----------------------- +====================== Precompiled library blobs must be in a data format which is compatible with and can be linked by a toolchain supported by the Zephyr Project. This is required @@ -164,7 +164,7 @@ compiler and/or linker flags, however. For example, a porting layer may require special flags, or a static archive may require use of specific linker flags. Limited scope -------------- +============= Allowing arbitrary library blobs carries a risk of degrading the degree to which the upstream Zephyr software distribution is open source. As an extreme @@ -188,7 +188,7 @@ At the discretion of the release team, the project may remove support for a hardware target if it cannot pass this test suite. Support and maintenance -======================= +*********************** The Zephyr Project is not expected to be responsible for the maintenance and support of contributed binary blobs. As a consequence, at the discretion of the @@ -226,7 +226,7 @@ regularly scheduled execution of the CI infrastructure. .. _blobs-process: Submission and review process -============================= +***************************** For references to binary blobs to be included in the project, they must be reviewed and accepted by the Technical Steering Committee (TSC). This process is diff --git a/doc/contribute/coding_guidelines/index.rst b/doc/contribute/coding_guidelines/index.rst index f3bcecddfd9..4677da2e86e 100644 --- a/doc/contribute/coding_guidelines/index.rst +++ b/doc/contribute/coding_guidelines/index.rst @@ -1250,7 +1250,7 @@ Related GitHub Issues and Pull Requests are tagged with the `Inclusive Language .. _Inclusive Language Label: https://github.com/zephyrproject-rtos/zephyr/issues?q=label%3A%22Inclusive+Language%22 .. _I2C Specification: https://www.nxp.com/docs/en/user-guide/UM10204.pdf -.. _Bluetooth Appropriate Language Mapping Tables: https://btprodspecificationrefs.blob.core.windows.net/language-mapping/Appropriate_Language_Mapping_Table.pdf +.. _Bluetooth Appropriate Language Mapping Tables: https://specificationrefs.bluetooth.com/language-mapping/Appropriate_Language_Mapping_Table.pdf .. _OSHWA Resolution to Redefine SPI Signal Names: https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names/ .. _CAN in Automation Inclusive Language news post: https://www.can-cia.org/news/archive/view/?tx_news_pi1%5Bnews%5D=699&tx_news_pi1%5Bday%5D=6&tx_news_pi1%5Bmonth%5D=12&tx_news_pi1%5Byear%5D=2020&cHash=784e79eb438141179386cf7c29ed9438 .. _CAN in Automation Inclusive Language: https://can-newsletter.org/canopen/categories/ @@ -1441,9 +1441,12 @@ shall be limited to the functions, excluding the Annex K "Bounds-checking interfaces", from the ISO/IEC 9899:2011 standard, also known as C11, unless exempted by this rule. -The "Zephyr codebase" in this context refers to all source code files committed +The "Zephyr codebase" in this context refers to all embedded source code files committed to the `main Zephyr repository`_, except the Zephyr kernel as defined by the :ref:`coding_guideline_libc_usage_restrictions_in_zephyr_kernel`. +With embedded source code we refer to code which is meant to be executed in embedded +targets, and therefore excludes host tooling, and code specific for the +:ref:`native ` test targets. The following non-ISO 9899:2011, hereinafter referred to as non-standard, functions and macros are exempt from this rule and allowed to be used in the @@ -1481,102 +1484,3 @@ toolchains that come with their own C standard libraries. .. _main Zephyr repository: https://github.com/zephyrproject-rtos/zephyr .. _strnlen(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html .. _strtok_r(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html - -Parasoft Codescan Tool -********************** - -Parasoft Codescan is an official static code analysis tool used by the Zephyr -project. It is used to automate compliance with a range of coding and security -standards. -The tool is currently set to the MISRA-C:2012 Coding Standard because the Zephyr -:ref:`coding_guidelines` are based on that standard. -It is used together with the Coverity Scan tool to achieve the best code health -and precision in bug findings. - -Violations fixing process -========================= - -Step 1 - Any Zephyr Project member, company or a developer can request access - to the Parasoft reporting centre if they wish to get involved in fixing - violations by submitting issues. - -Step 2 - A developer starts to review violations. - -Step 3 - A developer submits a Github PR with the fix. Commit messages should follow - the same guidelines as other PRs in the Zephyr project. Please add a comment - that your fix was found by a static coding scanning tool. - Developers should follow and refer to the Zephyr :ref:`coding_guidelines` - as basic rules for coding. These rules are based on the MISRA-C standard. - - Below you can find an example of a recommended commit message:: - - lib: os: add braces to 'if' statements - - An 'if' (expression) construct shall be followed by a compound statement. - Add braces to improve readability and maintainability. - - Found as a coding guideline violation (Rule 15.6) by static - coding scanning tool. - - Signed-off-by: Johnny Developer - -Step 4 - If a violation is a false positive, the developer should mark it for the Codescan - tool just like they would do for the Coverity tool. - The developer should also add a comment to the code explaining that - the violation raised by the static code analysis tool should be considered a - false positive. - -Step 5 - If the developer has found a real violation that the community decided to ignore, - the developer must submit a PR with a suppression tag - and a comment explaining why the violation has been deviated. - The template structure of the comment and tag in the code should be:: - - /* Explain why that part of the code doesn't follow the standard, - * explain why it is a deliberate deviation from the standard. - * Don't refer to the Parasoft tool here, just mention that static code - * analysis tool raised a violation in the line below. - */ - code_line_with_a_violation /* parasoft-suppress Rule ID */ - - Below you can find an example of a recommended commit message:: - - testsuite: suppress usage of setjmp in a testcode (rule 21.4) - - According to the Rule 21.4 the standard header file shall not - be used. We will suppress this violation because it is in - test code. Tag suppresses reporting of the violation for the - line where the violation is located. - This is a deliberate deviation. - - Found as a coding guideline violation (Rule 21.4) by static coding - scanning tool. - - Signed-off-by: Johnny Developer - - The example below demonstrates how deviations can be suppressed in the code:: - - /* Static code analysis tool can raise a violation that the standard - * header shall not be used. - * Since this violation is in test code, we will suppress it. - * Deliberate deviation. - */ - #include /* parasoft-suppress MISRAC2012-RULE_21_4-a MISRAC2012-RULE_21_4-b */ - - This variant above suppresses item ``MISRAC2012-RULE_21_4-a`` and ``MISRAC2012-RULE_21_4-b`` - on the line with "setjump" header include. You can add as many rules to suppress you want - - just make sure to keep the Parasoft tag on one line and separate rules with a space. - To read more about suppressing findings in the Parasoft tool, refer to the - official Parasoft `documentation`_ - - .. _documentation: https://docs.parasoft.com/display/CPPTEST1031/Suppressing+Findings - -Step 6 - After a PR is submitted, the developer should add the ``Coding guidelines`` - and ``MISRA-C`` Github labels so their PR can be easily tracked by maintainers. - If you have any concerns about what your PR should look like, you can search - on Github using those tags and refer to similar PRs that have already been merged. diff --git a/doc/contribute/contributor_expectations.rst b/doc/contribute/contributor_expectations.rst index aeb90c33d68..cba1627a1b9 100644 --- a/doc/contribute/contributor_expectations.rst +++ b/doc/contribute/contributor_expectations.rst @@ -3,9 +3,6 @@ Contributor Expectations ######################## -Overview -******** - The Zephyr project encourages :ref:`contributors ` to submit changes as smaller pull requests. Smaller pull requests (PRs) have the following benefits: @@ -30,7 +27,7 @@ benefits: Defining Smaller PRs -==================== +******************** - Smaller PRs should encompass one self-contained logical change. @@ -55,7 +52,7 @@ Defining Smaller PRs Multiple Commits on a Single PR -=============================== +******************************* Contributors are further encouraged to break up PRs into multiple commits. Keep in mind each commit in the PR must still build cleanly and pass all the CI @@ -72,7 +69,7 @@ the PR into multiple commits targeting these specific changes: #. Update the documentation Large Changes -============= +************* Large changes to the Zephyr project must submit an :ref:`RFC proposal ` describing the full scope of change and future work. The RFC proposal provides @@ -265,7 +262,7 @@ the steps below: .. _reviewer-expectations: Reviewer Expectations -##################### +********************* - Be respectful when commenting on PRs. Refer to the Zephyr `Code of Conduct`_ for more details. diff --git a/doc/contribute/external.rst b/doc/contribute/external.rst index e602c94df09..c154bc3a698 100644 --- a/doc/contribute/external.rst +++ b/doc/contribute/external.rst @@ -1,7 +1,7 @@ .. _external-contributions: Contributing External Components -******************************** +################################ In some cases it is desirable to leverage existing, external source code in order to avoid re-implementing basic functionality or features that are readily @@ -21,7 +21,7 @@ code analysis, testing or simulation please refer to the :ref:`external-tooling` section at the end of the page. Software License -================ +**************** .. note:: @@ -49,7 +49,7 @@ for contributed code, we ensure that the Zephyr community can develop products with the Zephyr Project without concerns over patent or copyright issues. Merit -===== +***** Just like with any other regular contribution, one that contains external code needs to be evaluated for merit. However, in the particular case of code that @@ -68,14 +68,14 @@ into the project: Are there other open source project that implement the same functionality? Mode of integration -=================== +******************* There are two ways of integrating external source code into the Zephyr Project, and careful consideration must be taken to choose the appropriate one for each particular case. Integration in the main tree ----------------------------- +============================ The first way to integrate external source code into the project is to simply import the source code files into the main ``zephyr`` repository. This @@ -94,7 +94,7 @@ This mode of integration can be applicable to both small and large external codebases, but it is typically used more commonly with the former. Integration as a module ------------------------ +======================= The second way of integrating external source code into the project is to import the whole or parts of the third-party open source project into a separate @@ -104,7 +104,7 @@ thus it is not automatically subject to the requirements of the previous section. Integration in main manifest file (west.yaml) -+++++++++++++++++++++++++++++++++++++++++++++ +--------------------------------------------- Integrating external code into the main :file:`west.yml` manifest file is limited to code that is used by a Zephyr subsystem (libraries), by a platform, @@ -117,7 +117,7 @@ Integrated modules will not be removed from the tree without a detailed migration plan. Integration as optional modules -+++++++++++++++++++++++++++++++ +------------------------------- Standalone or loose integration of modules/projects without any incoming dependencies shall be made optional and shall be kept standalone. Optional @@ -137,7 +137,7 @@ repository) and all sample or test code shall be maintained as part of the modul over time. Integration as external modules -+++++++++++++++++++++++++++++++ +------------------------------- Similar to optional modules, but added to the Zephyr project as an entry in the documentation using a pre-defined template. This type of modules exists outside the @@ -145,7 +145,7 @@ Zephyr project manifest with documentation instructing users and developers how to integrate the functionality. Ongoing maintenance -=================== +******************* Regardless of the mode of integration, external source code that is integrated in Zephyr requires regular ongoing maintenance. The submitter of the proposal to @@ -157,7 +157,7 @@ process. .. _external-src-process: Submission and review process -============================= +***************************** Before external source code can be included in the project, it must be reviewed and accepted by the Technical Steering Committee (TSC) and, in some cases, by diff --git a/doc/contribute/guidelines.rst b/doc/contribute/guidelines.rst index b3dd735dd42..06a70f0845d 100644 --- a/doc/contribute/guidelines.rst +++ b/doc/contribute/guidelines.rst @@ -532,9 +532,18 @@ results you have to create an account yourself. From the Zephyr project page, you may select "Add me to project" to be added to the project. New members must be approved by an admin. -Coverity scans the Zephyr codebase weekly. GitHub issues are automatically -created for any problems found and assigned to the maintainers of the affected -areas. +Static analysis of the Zephyr codebase is conducted on a bi-weekly basis. GitHub +issues are automatically created for any issues detected by static analysis +tools. These issues will have the same (or equivalent) priority initially +defined by the tool. + +To ensure accountability and efficient issue resolution, they are assigned to +the respective maintainer who is responsible for the affected code. + +A dedicated team comprising members with expertise in static analysis, code +quality, and software security ensures the effectiveness of the static +analysis process and verifies that identified issues are properly +triaged and resolved in a timely manner. Workflow ======== diff --git a/doc/develop/api/api_lifecycle.rst b/doc/develop/api/api_lifecycle.rst index 8f1f689c12c..b34832655c8 100644 --- a/doc/develop/api/api_lifecycle.rst +++ b/doc/develop/api/api_lifecycle.rst @@ -94,23 +94,23 @@ In order to declare an API ``stable``, the following steps need to be followed: `Zephyr Architecture meeting`_ where, barring any objections, the Pull Request will be merged -.. _stable_api_changes: +.. _breaking_api_changes: -Introducing incompatible changes +Introducing breaking API changes ================================ -A stable API, as described above strives to remain backwards-compatible through +A stable API, as described above, strives to remain backwards-compatible through its life-cycle. There are however cases where fulfilling this objective prevents -technical progress or is simply unfeasible without unreasonable burden on the +technical progress, or is simply unfeasible without unreasonable burden on the maintenance of the API and its implementation(s). -An incompatible change is defined as one that forces users to modify their +A breaking API change is defined as one that forces users to modify their existing code in order to maintain the current behavior of their application. The need for recompilation of applications (without changing the application -itself) is not considered an incompatible change. +itself) is not considered a breaking API change. In order to restrict and control the introduction of a change that breaks the -promise of backwards compatibility the following steps must be followed whenever +promise of backwards compatibility, the following steps must be followed whenever such a change is considered necessary in order to accept it in the project: #. An :ref:`RFC issue ` must be opened on GitHub with the following @@ -118,7 +118,7 @@ such a change is considered necessary in order to accept it in the project: .. code-block:: none - Title: RFC: API Change: + Title: RFC: Breaking API Change: Contents: - Problem Description: - Background information on why the change is required - Proposed Change (detailed): @@ -133,7 +133,7 @@ such a change is considered necessary in order to accept it in the project: Instead of a written description of the changes, the RFC issue may link to a Pull Request containing those changes in code form. -#. The RFC issue must be labeled with the GitHub ``Stable API Change`` label +#. The RFC issue must be labeled with the GitHub ``Breaking API Change`` label #. The RFC issue must be submitted for discussion in the next `Zephyr Architecture meeting`_ #. An email must be sent to the ``devel`` mailing list with a subject identical @@ -164,7 +164,7 @@ The Pull Request must include the following: the corresponding maintainers - An entry in the "API Changes" section of the release notes for the next upcoming release -- The labels ``API``, ``Stable API Change`` and ``Release Notes``, as well as +- The labels ``API``, ``Breaking API Change`` and ``Release Notes``, as well as any others that are applicable Once the steps above have been completed, the outcome of the proposal will @@ -177,8 +177,7 @@ If the Pull Request is merged then an email must be sent to the ``devel`` and .. note:: - Incompatible changes will be announced in the "API Changes" section of the - release notes. + Breaking API changes will be listed and described in the migration guide. Deprecated *********** diff --git a/doc/develop/api/overview.rst b/doc/develop/api/overview.rst index 6572ab0f161..20d03836c75 100644 --- a/doc/develop/api/overview.rst +++ b/doc/develop/api/overview.rst @@ -290,7 +290,7 @@ between major releases are available in the :ref:`zephyr_release_notes`. - 3.1 * - :ref:`retained_mem_api` - - Experimental + - Unstable - 3.4 * - :ref:`retention_api` diff --git a/doc/develop/application/index.rst b/doc/develop/application/index.rst index 2cd96b3252b..7604c38d57e 100644 --- a/doc/develop/application/index.rst +++ b/doc/develop/application/index.rst @@ -429,6 +429,11 @@ should know about. See :ref:`set-devicetree-overlays` for examples and :ref:`devicetree-intro` for information about devicetree and Zephyr. +* :makevar:`EXTRA_DTC_OVERLAY_FILE`: Additional devicetree overlay files to use. + Multiple files can be separated with semicolons. This can be useful to leave + :makevar:`DTC_OVERLAY_FILE` at its default value, but "mix in" some additional + overlay files. + * :makevar:`SHIELD`: see :ref:`shields` * :makevar:`ZEPHYR_MODULES`: A `CMake list`_ containing absolute paths of @@ -440,6 +445,10 @@ should know about. * :makevar:`EXTRA_ZEPHYR_MODULES`: Like :makevar:`ZEPHYR_MODULES`, except these will be added to the list of modules found via west, instead of replacing it. +* :makevar:`FILE_SUFFIX`: Optional suffix for filenames that will be added to Kconfig + fragments and devicetree overlays (if these files exists, otherwise will fallback to + the name without the prefix). See :ref:`application-file-suffixes` for details. + .. note:: You can use a :ref:`cmake_build_config_package` to share common settings for @@ -675,6 +684,51 @@ Devicetree Overlays See :ref:`set-devicetree-overlays`. +.. _application-file-suffixes: + +File Suffixes +============= + +Zephyr applications might want to have a single code base with multiple configurations for +different build/product variants which would necessitate different Kconfig options and devicetree +configuration. In order to better configure this, Zephyr provides a :makevar:`FILE_SUFFIX` option +when configuring applications that can be automatically appended to filenames. This is applied to +Kconfig fragments and board overlays but with a fallback so that if such files do not exist, the +files without these suffixes will be used instead. + +Given the following example project layout: + +.. code-block:: none + + + ├── CMakeLists.txt + ├── prj.conf + ├── prj_mouse.conf + ├── boards + │ ├── native_posix.overlay + │ └── qemu_cortex_m3_mouse.overlay + └── src + └── main.c + +* If this is built normally without ``FILE_SUFFIX`` being defined for ``native_posix`` then + ``prj.conf`` and ``boards/native_posix.overlay`` will be used. + +* If this is build normally without ``FILE_SUFFIX`` being defined for ``qemu_cortex_m3`` then + ``prj.conf`` will be used, no application devicetree overlay will be used. + +* If this is built with ``FILE_SUFFIX`` set to ``mouse`` for ``native_posix`` then + ``prj_mouse.conf`` and ``boards/native_posix.overlay`` will be used (there is no + ``native_posix_mouse.overlay`` file so it falls back to ``native_posix.overlay``). + +* If this is build with ``FILE_SUFFIX`` set to ``mouse`` for ``qemu_cortex_m3`` then + ``prj_mouse.conf`` will be used and ``boards/qemu_cortex_m3_mouse.overlay`` will be used. + +.. note:: + + When ``CONF_FILE`` is set in the form of ``prj_X.conf`` then the ``X`` will be used as the + build type. If this is combined with ``FILE_SUFFIX`` then the file suffix option will take + priority over the build type. + Application-Specific Code ************************* diff --git a/doc/develop/beyond-GSG.rst b/doc/develop/beyond-GSG.rst index 1b9aab82644..d9336af5381 100644 --- a/doc/develop/beyond-GSG.rst +++ b/doc/develop/beyond-GSG.rst @@ -215,7 +215,7 @@ depending on your board. The other sample applications in the :zephyr_file:`samples` folder are documented in :ref:`samples-and-demos`. -.. note:: If you want to re-use an +.. note:: If you want to reuse an existing build directory for another board or application, you need to add the parameter ``-p=auto`` to ``west build`` to clean out settings and artifacts from the previous build. @@ -330,7 +330,7 @@ valgrind. .. [#pip] pip is Python's package installer. Its ``install`` command first tries to - re-use packages and package dependencies already installed on your computer. + reuse packages and package dependencies already installed on your computer. If that is not possible, ``pip install`` downloads them from the Python Package Index (PyPI) on the Internet. diff --git a/doc/develop/flash_debug/host-tools.rst b/doc/develop/flash_debug/host-tools.rst index cf349d5d29d..1fcf7fa1d8b 100644 --- a/doc/develop/flash_debug/host-tools.rst +++ b/doc/develop/flash_debug/host-tools.rst @@ -221,6 +221,24 @@ LinkServer is compatible with the following debug probes: - :ref:`mcu-link-cmsis-onboard-debug-probe` - :ref:`opensda-daplink-onboard-debug-probe` +To use LinkServer with West commands, the install folder should be added to the +:envvar:`PATH` :ref:`environment variable `. The default installation +path to add is: + +.. tabs:: + + .. group-tab:: Linux + + .. code-block:: console + + /usr/local/LinkServer + + .. group-tab:: Windows + + .. code-block:: console + + c:\nxp\LinkServer_ + Supported west commands: 1. flash @@ -321,6 +339,8 @@ Started Guide. pyOCD includes support for Zephyr RTOS-awareness. These debug host tools are compatible with the following debug probes: +- :ref:`lpclink2-cmsis-onboard-debug-probe` +- :ref:`mcu-link-cmsis-onboard-debug-probe` - :ref:`opensda-daplink-onboard-debug-probe` - :ref:`stlink-v21-onboard-debug-probe` @@ -477,7 +497,7 @@ afterwards detach the debug session: https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-for-visual-studio-code:MCUXPRESSO-VSC .. _MCUXpresso Installer: - https://www.nxp.com/lgfiles/updates/mcuxpresso/MCUXpressoInstaller.exe + https://github.com/nxp-mcuxpresso/vscode-for-mcux/wiki/Dependency-Installation .. _NXP S32 Design Studio for S32 Platform: https://www.nxp.com/design/software/development-software/s32-design-studio-ide/s32-design-studio-for-s32-platform:S32DS-S32PLATFORM diff --git a/doc/develop/getting_started/installation_linux.rst b/doc/develop/getting_started/installation_linux.rst index f507a8d823c..6ef50b6d45a 100644 --- a/doc/develop/getting_started/installation_linux.rst +++ b/doc/develop/getting_started/installation_linux.rst @@ -78,7 +78,7 @@ need one. sudo apt-get install --no-install-recommends git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ - python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file libpython3.8-dev \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1 .. group-tab:: Fedora @@ -86,9 +86,8 @@ need one. .. code-block:: console sudo dnf group install "Development Tools" "C Development Tools and Libraries" - sudo dnf install git cmake ninja-build gperf ccache dfu-util dtc wget \ - python3-pip python3-tkinter xz file glibc-devel.i686 libstdc++-devel.i686 python38 \ - SDL2-devel + sudo dnf install cmake ninja-build gperf dfu-util dtc wget which \ + python3-pip python3-tkinter xz file python3-devel SDL2-devel .. group-tab:: Clear Linux @@ -227,32 +226,31 @@ The Zephyr SDK supports the following target architectures: Follow these steps to install the Zephyr SDK: -#. Download and verify the `Zephyr SDK bundle - `_: +#. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + wget |sdk-url-linux| + wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing - You can change ``0.16.3`` to another version if needed; the `Zephyr SDK - Releases`_ page contains all available SDK releases. + You can change |sdk-version-literal| to another version if needed; the + `Zephyr SDK Releases`_ page contains all available SDK releases. If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: cd - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.3 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh If this fails, make sure Zephyr's dependencies were installed as described @@ -271,9 +269,9 @@ If you relocate the SDK directory, you need to re-run the setup script. * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting installation + path will be ``$HOME/zephyr-sdk-``. If you install the Zephyr SDK outside any of these locations, you must register the Zephyr SDK in the CMake package registry by running the setup diff --git a/doc/develop/languages/cpp/index.rst b/doc/develop/languages/cpp/index.rst index 5ba5c7d7688..492872d7e9c 100644 --- a/doc/develop/languages/cpp/index.rst +++ b/doc/develop/languages/cpp/index.rst @@ -83,7 +83,7 @@ The scope of the minimal C++ library is strictly limited to providing the basic C++ language support, and it does not implement any `Standard Template Library (STL)`_ classes and functions. For this reason, it is only suitable for use in the applications that implement their own (non-standard) class library and do -rely on the Standard Template Library (STL) components. +not rely on the Standard Template Library (STL) components. Any application that makes use of the Standard Template Library (STL) components, such as ``std::string`` and ``std::vector``, must enable the C++ diff --git a/doc/develop/manifest/external/dummy.rst b/doc/develop/manifest/external/dummy.rst new file mode 100644 index 00000000000..258619d4be6 --- /dev/null +++ b/doc/develop/manifest/external/dummy.rst @@ -0,0 +1,19 @@ +.. _external_module_dummy: + +Add Your External Module Here +############################# + +Introduction +************ + +Short intro into the module and how it relates to Zephyr. + +Usage with Zephyr +***************** + +How to use this module with Zephyr. Provide all the details. + +Reference +********* + +External references and links. diff --git a/doc/develop/manifest/external/external.rst.tmpl b/doc/develop/manifest/external/external.rst.tmpl new file mode 100644 index 00000000000..49e262ab36e --- /dev/null +++ b/doc/develop/manifest/external/external.rst.tmpl @@ -0,0 +1,19 @@ +.. _external_module_: + + +####################### + +Introduction +************ + +Short intro into the module and how it relates to Zephyr. + +Usage with Zephyr +***************** + +How to use this module with Zephyr. Provide all the details. + +Reference +********* + +External references and links. diff --git a/doc/develop/manifest/index.rst b/doc/develop/manifest/index.rst index 4c6d8f99117..a24c32de61c 100644 --- a/doc/develop/manifest/index.rst +++ b/doc/develop/manifest/index.rst @@ -53,6 +53,12 @@ file which includes them. See :ref:`west-manifest-import` for information on recommended ways to do this while still inheriting the mandatory modules from Zephyr's :file:`west.yml`. -.. rst-class:: rst-columns +Use the template :file:`doc/develop/manifest/external/external.rst.tmpl` to add +external modules to the list below: -- TBD +.. toctree:: + :titlesonly: + :maxdepth: 1 + :glob: + + external/* diff --git a/doc/develop/modules.rst b/doc/develop/modules.rst index 42d10c32e98..875f6f62ff1 100644 --- a/doc/develop/modules.rst +++ b/doc/develop/modules.rst @@ -611,9 +611,10 @@ For example, to include the file :file:`some/Kconfig` in module ``foo``: source "$(ZEPHYR_FOO_MODULE_DIR)/some/Kconfig" -During CMake processing of each Zephyr module, the following two variables are +During CMake processing of each Zephyr module, the following variables are also available: +- the current module's name: ``${ZEPHYR_CURRENT_MODULE_NAME}`` - the current module's top level directory: ``${ZEPHYR_CURRENT_MODULE_DIR}`` - the current module's :file:`CMakeLists.txt` directory: ``${ZEPHYR_CURRENT_CMAKE_DIR}`` diff --git a/doc/develop/sca/cpptest.rst b/doc/develop/sca/cpptest.rst new file mode 100644 index 00000000000..a9f02fc09f5 --- /dev/null +++ b/doc/develop/sca/cpptest.rst @@ -0,0 +1,40 @@ +.. _cpptest: + +Parasoft C/C++test support +########################## + +Parasoft `C/C++test `__ is a software testing +and static analysis tool for C and C++. It is a commercial software and you must acquire a +commercial license to use it. + +Documentation of C/C++test can be found at https://docs.parasoft.com/. Please refer to the +documentation for how to use it. + +Generating Build Data Files +*************************** + +To use C/C++test, ``cpptestscan`` must be found in your :envvar:`PATH` environment variable. And +:ref:`west build ` should be called with a ``-DZEPHYR_SCA_VARIANT=cpptest`` +parameter, e.g. + +.. code-block:: shell + + west build -b qemu_cortex_m3 zephyr/samples/hello_world -- -DZEPHYR_SCA_VARIANT=cpptest + + +A ``.bdf`` file will be generated as :file:`build/sca/cpptest/cpptestscan.bdf`. + +Generating a report file +************************ + +Please refer to Parasoft C/C++test documentation for more details. + +To import and generate a report file, something like the following should work. + +.. code-block:: shell + + cpptestcli -data out -localsettings local.conf -bdf build/sca/cpptest/cpptestscan.bdf -config "builtin://Recommended Rules" -report out/report + + +You might need to set ``bdf.import.c.compiler.exec``, ``bdf.import.cpp.compiler.exec``, and +``bdf.import.linker.exec`` to the toolchain :ref:`west build ` used. diff --git a/doc/develop/sca/gcc.rst b/doc/develop/sca/gcc.rst new file mode 100644 index 00000000000..4ae852c81ad --- /dev/null +++ b/doc/develop/sca/gcc.rst @@ -0,0 +1,18 @@ +.. _gcc: + +GCC static analysis support +########################### + +Static analysis was introduced in `GCC `__ 10 and it is enabled +with the option ``-fanalyzer``. This option performs a much more expensive and thorough +analysis of the code than traditional warnings. + +Run GCC static analysis +*********************** + +To run GCC static analysis, :ref:`west build ` should be +called with a ``-DZEPHYR_SCA_VARIANT=gcc`` parameter, e.g. + +.. code-block:: shell + + west build -b qemu_x86 samples/userspace/hello_world_user -- -DZEPHYR_SCA_VARIANT=gcc diff --git a/doc/develop/sca/index.rst b/doc/develop/sca/index.rst index 08b9d96a0cc..0a471439235 100644 --- a/doc/develop/sca/index.rst +++ b/doc/develop/sca/index.rst @@ -31,7 +31,7 @@ structure: └── cmake/ └── sca/ └── / # Name of SCA tool, this is the value given to ZEPHYR_SCA_VARIANT - └── sca.cmake # CMake code that confgures the tool to be used with Zephyr + └── sca.cmake # CMake code that configures the tool to be used with Zephyr To add ``foo`` under ``/path/to/my_tools/cmake/sca`` create the following structure: @@ -63,3 +63,5 @@ The following is a list of SCA tools natively supported by Zephyr build system. codechecker sparse + gcc + cpptest diff --git a/doc/develop/test/coverage.rst b/doc/develop/test/coverage.rst index 84eadad1a21..60faffa1a90 100644 --- a/doc/develop/test/coverage.rst +++ b/doc/develop/test/coverage.rst @@ -142,7 +142,11 @@ or:: $ twister --coverage -p native_sim -T tests/bluetooth -which will produce ``twister-out/coverage/index.html`` with the report. +which will produce ``twister-out/coverage/index.html`` report as well as +the coverage data collected by ``gcovr`` tool in ``twister-out/coverage.json``. + +Other reports might be chosen with ``--coverage-tool`` and ``--coverage-formats`` +command line options. The process differs for unit tests, which are built with the host toolchain and require a different board:: diff --git a/doc/develop/test/pytest.rst b/doc/develop/test/pytest.rst index f6ba54fa52e..ac3980105d9 100644 --- a/doc/develop/test/pytest.rst +++ b/doc/develop/test/pytest.rst @@ -1,4 +1,4 @@ -.. integration-with-pytest: +.. _integration_with_pytest: Integration with pytest test framework ###################################### @@ -46,43 +46,71 @@ sets the test result accordingly. How to create a pytest test *************************** -An example of a pytest test is given at :zephyr_file:`samples/subsys/testsuite/pytest/shell/pytest/test_shell.py`. -Twister calls pytest for each configuration from the .yaml file which uses ``harness: pytest``. -By default, it points to ``pytest`` directory, located next to a directory with binary sources. -A keyword ``pytest_root`` placed under ``harness_config`` section can be used to point to other -files, directories or subtests. +An example folder containing a pytest test, application source code and Twister configuration .yaml +file can look like the following: + +.. code-block:: none + + test_foo/ + ├─── pytest/ + │ └─── test_foo.py + ├─── src/ + │ └─── main.c + ├─── CMakeList.txt + ├─── prj.conf + └─── testcase.yaml + +An example of a pytest test is given at +:zephyr_file:`samples/subsys/testsuite/pytest/shell/pytest/test_shell.py`. Using the configuration +provided in the ``testcase.yaml`` file, Twister builds the application from ``src`` and then, if the +.yaml file contains a ``harness: pytest`` entry, it calls pytest in a separate subprocess. A sample +configuration file may look like this: + +.. code-block:: yaml + + tests: + some.foo.test: + harness: pytest + tags: foo + +By default, pytest tries to look for tests in a ``pytest`` directory located next to a directory +with binary sources. A keyword ``pytest_root`` placed under ``harness_config`` section in .yaml file +can be used to point to other files, directories or subtests (more info :ref:`here `). Pytest scans the given locations looking for tests, following its default -`discovery rules `_ -One can also pass some extra arguments to the pytest from yaml file using ``pytest_args`` keyword -under ``harness_config``, e.g.: ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. -There is also an option to pass ``--pytest-args`` through Twister command line parameters. -This can be particularly useful when one wants to select a specific testcase from a test suite. -For instance, one can use a command: +`discovery rules `_. + +Passing extra arguments +======================= -.. code-block:: console +There are two ways for passing extra arguments to the called pytest subprocess: - $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ - -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ - --pytest-args='-k test_shell_print_version' +#. From .yaml file, using ``pytest_args`` placed under ``harness_config`` section - more info + :ref:`here `. +#. Through Twister command line interface as ``--pytest-args`` argument. This can be particularly + useful when one wants to select a specific testcase from a test suite. For instance, one can use + a command: + .. code-block:: console -Note that ``--pytest-args`` can be passed multiple times to pass several arguments to the pytest. + $ ./scripts/twister --platform native_sim -T samples/subsys/testsuite/pytest/shell \ + -s samples/subsys/testsuite/pytest/shell/sample.pytest.shell \ + --pytest-args='-k test_shell_print_version' -Helpers & fixtures -================== + +Fixtures +******** dut ---- +=== -Give access to a DeviceAdapter type object, that represents Device Under Test. -This fixture is the core of pytest harness plugin. It is required to launch -DUT (initialize logging, flash device, connect serial etc). -This fixture yields a device prepared according to the requested type -(``native``, ``qemu``, ``hardware``, etc.). All types of devices share the same API. -This allows for writing tests which are device-type-agnostic. -Scope of this fixture is determined by the ``pytest_dut_scope`` -keyword placed under ``harness_config`` section. +Give access to a `DeviceAdapter`_ type object, that represents Device Under Test. This fixture is +the core of pytest harness plugin. It is required to launch DUT (initialize logging, flash device, +connect serial etc). This fixture yields a device prepared according to the requested type +(``native``, ``qemu``, ``hardware``, etc.). All types of devices share the same API. This allows for +writing tests which are device-type-agnostic. Scope of this fixture is determined by the +``pytest_dut_scope`` keyword placed under ``harness_config`` section (more info +:ref:`here `). .. code-block:: python @@ -93,13 +121,14 @@ keyword placed under ``harness_config`` section. dut.readlines_until('Hello world') shell ------ +===== -Provide an object with methods used to interact with shell application. -It calls ``wait_for_promt`` method, to not start scenario until DUT is ready. -Note that it uses ``dut`` fixture, so ``dut`` can be skipped when ``shell`` is used. -Scope of this fixture is determined by the ``pytest_dut_scope`` -keyword placed under ``harness_config`` section. +Provide a `Shell `_ class object with methods used to interact with shell application. +It calls ``wait_for_promt`` method, to not start scenario until DUT is ready. The shell fixture +calls ``dut`` fixture, hence has access to all its methods. The ``shell`` fixture adds methods +optimized for interactions with a shell. It can be used instead of ``dut`` for tests. Scope of this +fixture is determined by the ``pytest_dut_scope`` keyword placed under ``harness_config`` section +(more info :ref:`here `). .. code-block:: python @@ -109,16 +138,16 @@ keyword placed under ``harness_config`` section. shell.exec_command('help') mcumgr ------- +====== -Sample fixture to wrap ``mcumgr`` command-line tool used to manage remote devices. -More information about MCUmgr can be found here :ref:`mcu_mgr`. +Sample fixture to wrap ``mcumgr`` command-line tool used to manage remote devices. More information +about MCUmgr can be found here :ref:`mcu_mgr`. .. note:: This fixture requires the ``mcumgr`` available in the system PATH -Only selected functionality of MCUmgr is wrapped by this fixture. -For example, here is a test with a fixture ``mcumgr`` +Only selected functionality of MCUmgr is wrapped by this fixture. For example, here is a test with +a fixture ``mcumgr`` .. code-block:: python @@ -137,6 +166,132 @@ For example, here is a test with a fixture ``mcumgr`` mcumgr.reset_device() # continue test scenario, check version etc. +Classes +******* + +DeviceAdapter +============= + +.. autoclass:: twister_harness.DeviceAdapter + + .. automethod:: launch + + .. automethod:: connect + + .. automethod:: readline + + .. automethod:: readlines + + .. automethod:: readlines_until + + .. automethod:: write + + .. automethod:: disconnect + + .. automethod:: close + +.. _shell_class: + +Shell +===== + +.. autoclass:: twister_harness.Shell + + .. automethod:: exec_command + + .. automethod:: wait_for_prompt + + +Examples of pytest tests in the Zephyr project +********************************************** + +* :zephyr:code-sample:`pytest_shell` +* MCUmgr tests - :zephyr_file:`tests/boot/with_mcumgr` +* LwM2M tests - :zephyr_file:`tests/net/lib/lwm2m/interop` +* GDB stub tests - :zephyr_file:`tests/subsys/debug/gdbstub` + + +FAQ +*** + +How to flash/run application only once per pytest session? +========================================================== + + ``dut`` is a fixture responsible for flashing/running application. By default, its scope is set + as ``function``. This can be changed by adding to .yaml file ``pytest_dut_scope`` keyword placed + under ``harness_config`` section: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_dut_scope: session + + More info can be found :ref:`here `. + +How to run only one particular test from a python file? +======================================================= + + This can be achieved in several ways. In .yaml file it can be added using a ``pytest_root`` entry + placed under ``harness_config`` with list of tests which should be run: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_root: + - "pytest/test_shell.py::test_shell_print_help" + + Particular tests can be also chosen by pytest ``-k`` option (more info about pytest keyword + filter can be found + `here `_ + ). It can be applied by adding ``-k`` filter in ``pytest_args`` in .yaml file: + + .. code-block:: yaml + + harness: pytest + harness_config: + pytest_args: + - "-k test_shell_print_help" + + or by adding it to Twister command overriding parameters from the .yaml file: + + .. code-block:: console + + $ ./scripts/twister ... --pytest-args='-k test_shell_print_help' + +How to get information about used device type in test? +====================================================== + + This can be taken from ``dut`` fixture (which represents `DeviceAdapter`_ object): + + .. code-block:: python + + device_type: str = dut.device_config.type + if device_type == 'hardware': + ... + elif device_type == 'native': + ... + +How to rerun locally pytest tests without rebuilding application by Twister? +============================================================================ + + This can be achieved by running Twister once again with ``--test-only`` argument added to Twister + command. Another way is running Twister with highest verbosity level (``-vv``) and then + copy-pasting from logs command dedicated for spawning pytest (log started by ``Running pytest + command: ...``). + +Is this possible to run pytest tests in parallel? +================================================= + + Basically ``pytest-harness-plugin`` wasn't written with intention of running pytest tests in + parallel. Especially those one dedicated for hardware. There was assumption that parallelization + of tests is made by Twister, and it is responsible for managing available sources (jobs and + hardwares). If anyone is interested in doing this for some reasons (for example via + `pytest-xdist plugin `_) they do so at their own + risk. + + Limitations *********** diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index 122e9c3871b..be24732e1ba 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -347,7 +347,7 @@ build_only: (default False) This option is often used to test drivers and the fact that they are correctly enabled in Zephyr and that the code builds, for example sensor drivers. Such - test shall not be used to verify the functionality of the dritver. + test shall not be used to verify the functionality of the driver. build_on_all: (default False) If true, attempt to build test on all available platforms. This is mostly @@ -419,7 +419,7 @@ harness: Twister to be able to evaluate if a test passes criteria. For example, a keyboard harness is set on tests that require keyboard interaction to reach verdict on whether a test has passed or failed, however, Twister lack this - harness implementation at the momemnt. + harness implementation at the moment. Supported harnesses: @@ -445,6 +445,14 @@ harness: - net - bluetooth + Harness ``bsim`` is implemented in limited way - it helps only to copy the + final executable (``zephyr.exe``) from build directory to BabbleSim's + ``bin`` directory (``${BSIM_OUT_PATH}/bin``). This action is useful to allow + BabbleSim's tests to directly run after. By default, the executable file + name is (with dots and slashes replaced by underscores): + ``bs___``. + This name can be overridden with the ``bsim_exe_name`` option in + ``harness_config`` section. platform_key: Often a test needs to only be built and run once to qualify as passing. @@ -465,7 +473,7 @@ platform_key: Adding platform (board) attributes to include things such as soc name, soc family, and perhaps sets of IP blocks implementing each peripheral interface would enable other interesting uses. For example, this could enable - building and running SPI tests once for eacn unique IP block. + building and running SPI tests once for each unique IP block. harness_config: Extra harness configuration options to be used to select a board and/or @@ -478,15 +486,9 @@ harness_config: type: (required) Depends on the regex string to be matched - - record: - regex: (required) - Any string that the particular test case prints to record test - results. - - regex: (required) - Any string that the particular test case prints to confirm test - runs as expected. + regex: (required) + Strings with regular expressions to match with the test's output + to confirm the test runs as expected. ordered: (default False) Check the regular expression strings in orderly or randomly fashion @@ -494,6 +496,21 @@ harness_config: repeat: Number of times to validate the repeated regex expression + record: (optional) + regex: (required) + The regular expression with named subgroups to match data fields + at the test's output lines where the test provides some custom data + for further analysis. These records will be written into the build + directory 'recording.csv' file as well as 'recording' property + of the test suite object in 'twister.json'. + + For example, to extract three data fields 'metric', 'cycles', 'nanoseconds': + + .. code-block:: yaml + + record: + regex: "(?P.*):(?P.*) cycles, (?P.*) ns" + fixture: Specify a test case dependency on an external device(e.g., sensor), and identify setups that fulfill this dependency. It depends on @@ -505,14 +522,36 @@ harness_config: Only one fixture can be defined per testcase and the fixture name has to be unique across all tests in the test suite. +.. _pytest_root: + pytest_root: (default pytest) - Specify a list of pytest directories, files or subtests that need to be executed - when test case begin to running, default pytest directory is pytest. - After pytest finished, twister will check if this case pass or fail according - to the pytest report. + Specify a list of pytest directories, files or subtests that need to be + executed when a test case begins to run. The default pytest directory is + ``pytest``. After the pytest run is finished, Twister will check if + the test case passed or failed according to the pytest report. + As an example, a list of valid pytest roots is presented below: + + .. code-block:: yaml + + harness_config: + pytest_root: + - "pytest/test_shell_help.py" + - "../shell/pytest/test_shell.py" + - "/tmp/test_shell.py" + - "~/tmp/test_shell.py" + - "$ZEPHYR_BASE/samples/subsys/testsuite/pytest/shell/pytest/test_shell.py" + - "pytest/test_shell_help.py::test_shell2_sample" # select pytest subtest + - "pytest/test_shell_help.py::test_shell2_sample[param_a]" # select pytest parametrized subtest + +.. _pytest_args: pytest_args: (default empty) - Specify a list of additional arguments to pass to ``pytest``. + Specify a list of additional arguments to pass to ``pytest`` e.g.: + ``pytest_args: [‘-k=test_method’, ‘--log-level=DEBUG’]``. Note that + ``--pytest-args`` can be passed multiple times to pass several arguments + to the pytest. + +.. _pytest_dut_scope: pytest_dut_scope: (default function) The scope for which ``dut`` and ``shell`` pytest fixtures are shared. @@ -522,6 +561,11 @@ harness_config: robot_test_path: (default empty) Specify a path to a file containing a Robot Framework test suite to be run. + bsim_exe_name: + If provided, the executable filename when copying to BabbleSim's bin + directory, will be ``bs__`` instead of the + default based on the test path and scenario name. + The following is an example yaml file with a few harness_config options. .. code-block:: yaml @@ -1080,7 +1124,7 @@ using an external J-Link probe. The ``probe_id`` keyword overrides the Quarantine ++++++++++ -Twister allows user to provide onfiguration files defining a list of tests or +Twister allows user to provide configuration files defining a list of tests or platforms to be put under quarantine. Such tests will be skipped and marked accordingly in the output reports. This feature is especially useful when running larger test suits, where a failure of one test can affect the execution @@ -1133,7 +1177,7 @@ Additionally you can quarantine entire architectures or a specific simulator for Test Configuration ****************** -A test configuration can be used to customize various apects of twister +A test configuration can be used to customize various aspects of twister and the default enabled options and features. This allows tweaking the filtering capabilities depending on the environment and makes it possible to adapt and improve coverage when targeting different sets of platforms. @@ -1143,7 +1187,7 @@ assign a specific test to one or more levels. Using command line options of twister it is then possible to select a level and just execute the tests included in this level. -Additionally, the test configuration allows defining level +Additionally, the test configuration allows defining level dependencies and additional inclusion of tests into a specific level if the test itself does not have this information already. @@ -1160,7 +1204,7 @@ locally. As of now, those options are available: CI) - Option to specify your own list of default platforms overriding what upstream defines. -- Ability to override `build_onl_all` options used in some testcases. +- Ability to override `build_on_all` options used in some testcases. This will treat tests or sample as any other just build for default platforms you specify in the configuration file or on the command line. - Ignore some logic in twister to expand platform coverage in cases where @@ -1225,7 +1269,7 @@ Combined configuration To mix the Platform and level configuration, you can take an example as below: -And example platforms plus level configuration: +An example platforms plus level configuration: .. code-block:: yaml @@ -1254,7 +1298,7 @@ And example platforms plus level configuration: A plan to be used verifying regression. -To run with above test_config.yaml file, only default_paltforms with given test level +To run with above test_config.yaml file, only default_platforms with given test level test cases will run. .. tabs:: diff --git a/doc/develop/test/ztest.rst b/doc/develop/test/ztest.rst index f9255ecad2a..124fd415c23 100644 --- a/doc/develop/test/ztest.rst +++ b/doc/develop/test/ztest.rst @@ -197,15 +197,15 @@ function can be written as follows: /* Only suites that use a predicate checking for phase == PWR_PHASE_0 will run. */ state.phase = PWR_PHASE_0; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Only suites that use a predicate checking for phase == PWR_PHASE_1 will run. */ state.phase = PWR_PHASE_1; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Only suites that use a predicate checking for phase == PWR_PHASE_2 will run. */ state.phase = PWR_PHASE_2; - ztest_run_all(&state); + ztest_run_all(&state, false, 1, 1); /* Check that all the suites in this binary ran at least once. */ ztest_verify_all_test_suites_ran(); @@ -553,9 +553,6 @@ See :ref:`FFF Extensions `. Customizing Test Output *********************** -The way output is presented when running tests can be customized. -An example can be found in :zephyr_file:`tests/ztest/custom_output`. - Customization is enabled by setting :kconfig:option:`CONFIG_ZTEST_TC_UTIL_USER_OVERRIDE` to "y" and adding a file :file:`tc_util_user_override.h` with your overrides. diff --git a/doc/develop/toolchains/cadence_xcc.rst b/doc/develop/toolchains/cadence_xcc.rst index 5778c542068..f1de7ed1e53 100644 --- a/doc/develop/toolchains/cadence_xcc.rst +++ b/doc/develop/toolchains/cadence_xcc.rst @@ -68,7 +68,3 @@ Cadence Tensilica Xtensa C/C++ Compiler (XCC) # Linux export XCC_NO_G_FLAG=1 - - * Also note that setting :envvar:`XCC_USE_CLANG` to ``1`` and - :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``xcc`` is deprecated. - Set :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` to ``xt-clang`` instead. diff --git a/doc/develop/toolchains/host.rst b/doc/develop/toolchains/host.rst index adfd41cef9e..900601c97d3 100644 --- a/doc/develop/toolchains/host.rst +++ b/doc/develop/toolchains/host.rst @@ -4,7 +4,7 @@ Host Toolchains ############### In some specific configurations, like when building for non-MCU x86 targets on -a Linux host, you may be able to re-use the native development tools provided +a Linux host, you may be able to reuse the native development tools provided by your operating system. To use your host gcc, set the :envvar:`ZEPHYR_TOOLCHAIN_VARIANT` diff --git a/doc/develop/toolchains/zephyr_sdk.rst b/doc/develop/toolchains/zephyr_sdk.rst index fc6add9d3eb..14cf70f6141 100644 --- a/doc/develop/toolchains/zephyr_sdk.rst +++ b/doc/develop/toolchains/zephyr_sdk.rst @@ -74,7 +74,7 @@ Zephyr SDK installation .. toolchain_zephyr_sdk_install_start -.. note:: You can change ``0.16.3`` to another version in the instructions below +.. note:: You can change |sdk-version-literal| to another version in the instructions below if needed; the `Zephyr SDK Releases`_ page contains all available SDK releases. @@ -87,23 +87,22 @@ Zephyr SDK installation .. _ubuntu_zephyr_sdk: - #. Download and verify the `Zephyr SDK bundle - `_: + #. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: cd ~ - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_linux-x86_64.tar.xz - wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + wget |sdk-url-linux| + wget -O - |sdk-url-linux-sha| | shasum --check --ignore-missing If your host architecture is 64-bit ARM (for example, Raspberry Pi), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM Linux SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: - tar xvf zephyr-sdk-0.16.3_linux-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _linux-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -115,15 +114,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting + installation path will be ``$HOME/zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.3 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh .. note:: @@ -135,32 +134,31 @@ Zephyr SDK installation #. Install `udev `_ rules, which allow you to flash most Zephyr boards as a regular user: - .. code-block:: bash + .. parsed-literal:: - sudo cp ~/zephyr-sdk-0.16.3/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + sudo cp ~/zephyr-sdk- |sdk-version-trim| /sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d sudo udevadm control --reload .. group-tab:: macOS .. _macos_zephyr_sdk: - #. Download and verify the `Zephyr SDK bundle - `_: + #. Download and verify the `Zephyr SDK bundle`_: - .. code-block:: bash + .. parsed-literal:: cd ~ - curl -L -O https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_macos-x86_64.tar.xz - curl -L https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/sha256.sum | shasum --check --ignore-missing + curl -L -O |sdk-url-macos| + curl -L |sdk-url-macos-sha| | shasum --check --ignore-missing If your host architecture is 64-bit ARM (Apple Silicon, also known as M1), replace ``x86_64`` with ``aarch64`` in order to download the 64-bit ARM macOS SDK. #. Extract the Zephyr SDK bundle archive: - .. code-block:: bash + .. parsed-literal:: - tar xvf zephyr-sdk-0.16.3_macos-x86_64.tar.xz + tar xvf zephyr-sdk- |sdk-version-trim| _macos-x86_64.tar.xz .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -172,15 +170,15 @@ Zephyr SDK installation * ``/opt`` * ``/usr/local`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``$HOME``, the resulting installation path will be - ``$HOME/zephyr-sdk-0.16.3``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``$HOME``, the resulting + installation path will be ``$HOME/zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bash + .. parsed-literal:: - cd zephyr-sdk-0.16.3 + cd zephyr-sdk- |sdk-version-ltrim| ./setup.sh .. note:: @@ -195,19 +193,18 @@ Zephyr SDK installation #. Open a ``cmd.exe`` terminal window **as a regular user** - #. Download the `Zephyr SDK bundle - `_: + #. Download the `Zephyr SDK bundle`_: - .. code-block:: bat + .. parsed-literal:: cd %HOMEPATH% - wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.3/zephyr-sdk-0.16.3_windows-x86_64.7z + wget |sdk-url-windows| #. Extract the Zephyr SDK bundle archive: - .. code-block:: bat + .. parsed-literal:: - 7z x zephyr-sdk-0.16.3_windows-x86_64.7z + 7z x zephyr-sdk- |sdk-version-trim| _windows-x86_64.7z .. note:: It is recommended to extract the Zephyr SDK bundle at one of the following locations: @@ -215,15 +212,15 @@ Zephyr SDK installation * ``%HOMEPATH%`` * ``%PROGRAMFILES%`` - The Zephyr SDK bundle archive contains the ``zephyr-sdk-0.16.3`` directory and, when - extracted under ``%HOMEPATH%``, the resulting installation path will be - ``%HOMEPATH%\zephyr-sdk-0.16.3``. + The Zephyr SDK bundle archive contains the ``zephyr-sdk-`` + directory and, when extracted under ``%HOMEPATH%``, the resulting + installation path will be ``%HOMEPATH%\zephyr-sdk-``. #. Run the Zephyr SDK bundle setup script: - .. code-block:: bat + .. parsed-literal:: - cd zephyr-sdk-0.16.3 + cd zephyr-sdk- |sdk-version-ltrim| setup.cmd .. note:: @@ -232,7 +229,6 @@ Zephyr SDK installation You must rerun the setup script if you relocate the Zephyr SDK bundle directory after the initial setup. -.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.16.3 .. _Zephyr SDK Releases: https://github.com/zephyrproject-rtos/sdk-ng/tags .. _Zephyr SDK Version Compatibility Matrix: https://github.com/zephyrproject-rtos/sdk-ng/wiki/Zephyr-SDK-Version-Compatibility-Matrix diff --git a/doc/develop/west/build-flash-debug.rst b/doc/develop/west/build-flash-debug.rst index 0f9f15ef9d7..8356d95cade 100644 --- a/doc/develop/west/build-flash-debug.rst +++ b/doc/develop/west/build-flash-debug.rst @@ -179,7 +179,7 @@ it the value ``always``. For example, these commands are equivalent:: By default, ``west build`` makes no attempt to detect if the build directory needs to be made pristine. This can lead to errors if you do something like -try to re-use a build directory for a different ``--board``. +try to reuse a build directory for a different ``--board``. Using ``--pristine=auto`` makes ``west build`` detect some of these situations and make the build directory pristine before trying the build. diff --git a/doc/develop/west/sign.rst b/doc/develop/west/sign.rst index 8cc55ffeea4..ef98631be1c 100644 --- a/doc/develop/west/sign.rst +++ b/doc/develop/west/sign.rst @@ -100,8 +100,23 @@ The signing script used when running ``west flash`` can be extended or replaced to change features or introduce different signing mechanisms. By default with MCUboot enabled, signing is setup by the :file:`cmake/mcuboot.cmake` file in Zephyr which adds extra post build commands for generating the signed images. -The file used for signing can be replaced by adjusting the ``SIGNING_SCRIPT`` -property on the `zephyr_property_target`, ideally done by a module using: +The file used for signing can be replaced from a sysbuild scope (if being used) +or from a zephyr/zephyr module scope, the priority of which is: + +* Sysbuild +* Zephyr property +* Default MCUboot script (if enabled) + +From sysbuild, ``-D_SIGNING_SCRIPT`` can be used to set a signing script +for a specific image or ``-DSIGNING_SCRIPT`` can be used to set a signing script +for all images, for example: + +.. code-block:: console + + west build -b -DSIGNING_SCRIPT= + +The zephyr property method is achieved by adjusting the ``SIGNING_SCRIPT`` property +on the `zephyr_property_target`, ideally from by a module by using: .. code-block:: cmake diff --git a/doc/develop/west/zephyr-cmds.rst b/doc/develop/west/zephyr-cmds.rst index 056d22e48eb..f6b2322e6a4 100644 --- a/doc/develop/west/zephyr-cmds.rst +++ b/doc/develop/west/zephyr-cmds.rst @@ -89,6 +89,8 @@ To use this command: This step ensures the build directory contains CMake metadata required for SPDX document generation. +#. Enable :file:`CONFIG_BUILD_OUTPUT_META` in your project. + #. Build your application using this pre-created build directory, like so: .. code-block:: bash diff --git a/doc/hardware/arch/arm_cortex_m.rst b/doc/hardware/arch/arm_cortex_m.rst index b037896776f..1c074618567 100644 --- a/doc/hardware/arch/arm_cortex_m.rst +++ b/doc/hardware/arch/arm_cortex_m.rst @@ -262,7 +262,7 @@ interrupt. If the ZLI feature is enabled in Mainline Cortex-M builds (see * Regular HW interrupts are assigned priority levels lower than SVC. The priority level configuration in Cortex-M is implemented in -:file:`include/arch/arm/exc.h`. +:file:`include/arch/arm/exception.h`. Locking and unlocking IRQs -------------------------- diff --git a/doc/hardware/emulator/bus_emulators.rst b/doc/hardware/emulator/bus_emulators.rst new file mode 100644 index 00000000000..3568b0abbdc --- /dev/null +++ b/doc/hardware/emulator/bus_emulators.rst @@ -0,0 +1,168 @@ +.. _bus_emul: + +External Bus and Bus Connected Peripherals Emulators +#################################################### + +Overview +======== + +Zephyr supports a simple emulator framework to support testing of external peripheral drivers +without requiring real hardware. + +Emulators are used to emulate external hardware devices, to support testing of +various subsystems. For example, it is possible to write an emulator +for an I2C compass such that it appears on the I2C bus and can be used +just like a real hardware device. + +Emulators often implement special features for testing. For example a +compass may support returning bogus data if the I2C bus speed is too +high, or may return invalid measurements if calibration has not yet +been completed. This allows for testing that high-level code can +handle these situations correctly. Test coverage can therefore +approach 100% if all failure conditions are emulated. + +Concept +======= + +The diagram below shows application code / high-level tests at the top. +This is the ultimate application we want to run. + +.. figure:: img/arch.svg + :align: center + :alt: Emulator architecture showing tests, emulators and drivers + +Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test +peripheral drivers using an emulation driver connected via a emulated I2C +controller/emulator which passes I2C traffic from the AT24 driver to the AT24 +simulator. + +Separately we can test the STM32 and NXP I2C drivers on real hardware using API +tests. These require some sort of device attached to the bus, but with this, we +can validate much of the driver functionality. + +Putting the two together, we can test the application and peripheral code +entirely on native_sim. Since we know that the I2C driver on the real hardware +works, we should expect the application and peripheral drivers to work on the +real hardware also. + +Using the above framework we can test an entire application (e.g. Embedded +Controller) on native_sim using emulators for all non-chip drivers. + +With this approach we can: + +* Write individual tests for each driver (green), covering all failure modes, + error conditions, etc. + +* Ensure 100% test coverage for drivers (green) + +* Write tests for combinations of drivers, such as GPIOs provided by an I2C GPIO + expander driver talking over an I2C bus, with the GPIOs controlling a charger. + All of this can work in the emulated environment or on real hardware. + +* Write a complex application that ties together all of these pieces and runs on + native_sim. We can develop on a host, use source-level debugging, etc. + +* Transfer the application to any board which provides the required features + (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. + +Creating a Device Driver Emulator +================================= + +The emulator subsystem is modeled on the :ref:`device_model_api`. You create +an emulator instance using one of the :c:func:`EMUL_DT_DEFINE()` or +:c:func:`EMUL_DT_INST_DEFINE()` APIs. + +Emulators for peripheral devices reuse the same devicetree node as the real +device driver. This means that your emulator defines `DT_DRV_COMPAT` using the +same ``compat`` value from the real driver. + +.. code-block:: C + + /* From drivers/sensor/bm160/bm160.c */ + #define DT_DRV_COMPAT bosch_bmi160 + + /* From drivers/sensor/bmi160/emul_bmi160.c */ + #define DT_DRV_COMPAT bosch_bmi160 + +The ``EMUL_DT_DEFINE()`` function accepts two API types: + + #. ``bus_api`` - This points to the API for the upstream bus that the emulator + connects to. The ``bus_api`` parameter is required. The supported + emulated bus types include I2C, SPI, and eSPI. + #. ``_backend_api`` - This points to the device-class specific backend API for + the emulator. The ``_backend_api`` parameter is optional. + +The diagram below demonstrates the logical organization of the ``bus_api`` and +``_backend_api`` using the BC1.2 charging detector driver as the model +device-class. + +.. figure:: img/device_class_emulator.svg + :align: center + :alt: Device class example, demonstrating BC1.2 charging detectors. + +The real code is shown in green, while the emulator code is shown in yellow. + +The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C +controller. The real BC1.2 drivers are unchanged and operate exactly as if there +was a physical I2C controller present in the system. The ``native_sim`` I2C +controller uses the ``bus_api`` to initiate register reads and writes to the +emulator. + +The ``_backend_api`` provides a mechanism for tests to manipulate the emulator +out of band. Each device class defines it's own API functions. The backend API +functions focus on high-level behavior and do not provide hooks for specific +emulators. + +In the case of the BC1.2 charging detector the backend API provides functions +to simulate connecting and disconnecting a charger to the emulated BC1.2 device. +Each emulator is responsible for updating the correct vendor specific registers +and potentially signalling an interrupt. + +Example test flow: + + #. Test registers BC1.2 detection callback using the Zephyr BC1.2 driver API. + #. Test connects a charger using the BC1.2 emulator backend. + #. Test verifies B1.2 detection callback invoked with correct charger type. + #. Test disconnects a charger using the BC1.2 emulator backend. + +With this architecture, the same test can be used will all supported drivers in +the same driver class. + +Available Emulators +=================== + +Zephyr includes the following emulators: + +* I2C emulator driver, allowing drivers to be connected to an emulator so that + tests can be performed without access to the real hardware + +* SPI emulator driver, which does the same for SPI + +* eSPI emulator driver, which does the same for eSPI. The emulator is being + developed to support more functionalities. + +Samples +======= + +Here are some examples present in Zephyr: + +#. Bosch BMI160 sensor driver connected via both I2C and SPI to an emulator: + + .. zephyr-app-commands:: + :app: tests/drivers/sensor/accel/ + :board: native_sim + :goals: build + +#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver + connected via I2C an emulator: + + .. zephyr-app-commands:: + :app: tests/drivers/eeprom/api + :board: native_sim + :goals: build + :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DOVERLAY_CONFIG=at2x_emul.conf + +API Reference +************* + +.. doxygengroup:: io_emulators diff --git a/doc/hardware/emulator/img/app.png b/doc/hardware/emulator/img/app.png deleted file mode 100644 index 25173530ca2..00000000000 Binary files a/doc/hardware/emulator/img/app.png and /dev/null differ diff --git a/doc/hardware/emulator/img/arch.png b/doc/hardware/emulator/img/arch.png deleted file mode 100644 index eac62bf9da6..00000000000 Binary files a/doc/hardware/emulator/img/arch.png and /dev/null differ diff --git a/doc/hardware/emulator/img/arch.svg b/doc/hardware/emulator/img/arch.svg new file mode 100644 index 00000000000..6aa5e703a70 --- /dev/null +++ b/doc/hardware/emulator/img/arch.svg @@ -0,0 +1,4 @@ + + + +
Application
code / tests
Application...
Peripheral drivers
Peripheral drivers
Bus controller emulator
Bus controller em...
Peripheral
emulator
Peripheral...
API tests
API tests
STM32 drivers
STM32 drivers
NXP drivers
NXP drivers
STM32
HW
STM32...
NXP
HW
NXP...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/hardware/emulator/img/device_class_emulator.png b/doc/hardware/emulator/img/device_class_emulator.png deleted file mode 100644 index ad64956fe68..00000000000 Binary files a/doc/hardware/emulator/img/device_class_emulator.png and /dev/null differ diff --git a/doc/hardware/emulator/img/device_class_emulator.svg b/doc/hardware/emulator/img/device_class_emulator.svg new file mode 100644 index 00000000000..a8615ff02a8 --- /dev/null +++ b/doc/hardware/emulator/img/device_class_emulator.svg @@ -0,0 +1,4 @@ + + + +
Tests
Tests
BC1.2 Driver API
BC1.2 Driver API
Diodes
BC1.2 Driver
Diodes...
Mediatek BC1.2 Driver
Mediatek BC1....
I2C controller emulator
I2C controlle...
Diodes BC1.2 Emulator
Diodes BC1.2...
Mediatek BC1.2 Emulator
Mediatek BC1....
bus_api
bus_api
BC1.2 Backend API
BC1.2 Backend API
_backend API
_backend API
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/hardware/emulator/index.rst b/doc/hardware/emulator/index.rst index 4373480a3e0..0369876783a 100644 --- a/doc/hardware/emulator/index.rst +++ b/doc/hardware/emulator/index.rst @@ -1,189 +1,95 @@ .. _emulators: -Peripheral and Hardware Emulators -################################# +Zephyr's device emulators/simulators +#################################### Overview ======== -Zephyr supports a simple emulator framework to support testing of drivers -without requiring real hardware. +Zephyr includes in its codebase a set of device emulators/simulators. +With this we refer to SW components which are built together with the embedded SW +and present themselves as devices of a given class to the rest of the system. -Emulators are used to emulate hardware devices, to support testing of -various subsystems. For example, it is possible to write an emulator -for an I2C compass such that it appears on the I2C bus and can be used -just like a real hardware device. +These device emulators/simulators can be built for any target which has sufficient RAM and flash, +even if some may have extra functionality which is only available in some targets. -Emulators often implement special features for testing. For example a -compass may support returning bogus data if the I2C bus speed is too -high, or may return invalid measurements if calibration has not yet -been completed. This allows for testing that high-level code can -handle these situations correctly. Test coverage can therefore -approach 100% if all failure conditions are emulated. +.. note:: -Concept -======= + | Zephyr also includes and uses many other types of simulators/emulators, including CPU and + platform simulators, radio simulators, and several build targets which allow running the + embedded code in the development host. + | Some of Zephyr communication controllers/drivers include also either loopback modes or loopback + devices. + | This page does not cover any of these. -The diagram below shows application code / high-level tests at the top. -This is the ultimate application we want to run. +.. note:: + Drivers which are specific to some platform, like for example the + :ref:`native_sim specific drivers ` which + emulate a peripheral class by connecting to host APIs are not covered by this page. -.. figure:: img/arch.png - :align: center - :alt: Emulator architecture showing tests, emulators and drivers - -Below that are peripheral drivers, such as the AT24 EEPROM driver. We can test -peripheral drivers using an emulation driver connected via a native_sim I2C -controller/emulator which passes I2C traffic from the AT24 driver to the AT24 -simulator. - -Separately we can test the STM32 and NXP I2C drivers on real hardware using API -tests. These require some sort of device attached to the bus, but with this, we -can validate much of the driver functionality. - -Putting the two together, we can test the application and peripheral code -entirely on native_sim. Since we know that the I2C driver on the real hardware -works, we should expect the application and peripheral drivers to work on the -real hardware also. - -Using the above framework we can test an entire application (e.g. Embedded -Controller) on native_sim using emulators for all non-chip drivers: - -.. figure:: img/app.png - :align: center - :alt: Example system, using emulators to implement a PC EC - -The 'real' code is shown in green. The Zephyr emulation-framework code is shown -in yellow. The blue boxes are the extra code we have to write to emulate the -peripherals. - -With this approach we can: - -* Write individual tests for each driver (green), covering all failure modes, - error conditions, etc. - -* Ensure 100% test coverage for drivers (green) - -* Write tests for combinations of drivers, such as GPIOs provided by an I2C GPIO - expander driver talking over an I2C bus, with the GPIOs controlling a charger. - All of this can work in the emulated environment or on real hardware. - -* Write a complex application that ties together all of these pieces and runs on - native_sim. We can develop on a host, use source-level debugging, etc. - -* Transfer the application to any board which provides the required features - (e.g. I2C, enough GPIOs), by adding Kconfig and devicetree fragments. - -Creating a Device Driver Emulator -================================= - -The emulator subsystem is modeled on the :ref:`device_model_api`. You create -an emulator instance using one of the :c:func:`EMUL_DT_DEFINE()` or -:c:func:`EMUL_DT_INST_DEFINE()` APIs. - -Emulators for peripheral devices reuse the same devicetree node as the real -device driver. This means that your emulator defines `DT_DRV_COMPAT` using the -same ``compat`` value from the real driver. - -.. code-block:: C - - /* From drivers/sensor/bm160/bm160.c */ - #define DT_DRV_COMPAT bosch_bmi160 - - /* From subsys/emul/emul_bmi160.c */ - #define DT_DRV_COMPAT bosch_bmi160 - -The ``EMUL_DT_DEFINE()`` function accepts two API types: - - #. ``bus_api`` - This points to the API for the upstream bus that the emulator - connects to. The ``bus_api`` parameter is required. The supported - emulated bus types include I2C, SPI, and eSPI. - #. ``_backend_api`` - This points to the device-class specific backend API for - the emulator. The ``_backend_api`` parameter is optional. - -The diagram below demonstrates the logical organization of the ``bus_api`` and -``_backend_api`` using the BC1.2 charging detector driver as the model -device-class. - -.. figure:: img/device_class_emulator.png - :align: center - :alt: Device class example, demonstrating BC1.2 charging detectors. - -The real code is shown in green, while the emulator code is shown in yellow. - -The ``bus_api`` connects the BC1.2 emulators to the ``native_sim`` I2C -controller. The real BC1.2 drivers are unchanged and operate exactly as if there -was a physical I2C controller present in the system. The ``native_sim`` I2C -controller uses the ``bus_api`` to initiate register reads and writes to the -emulator. - -The ``_backend_api`` provides a mechanism for tests to manipulate the emulator -out of band. Each device class defines it's own API functions. The backend API -functions focus on high-level behavior and do not provide hooks for specific -emulators. - -In the case of the BC1.2 charging detector the backend API provides functions -to simulate connecting and disconnecting a charger to the emulated BC1.2 device. -Each emulator is responsible for updating the correct vendor specific registers -and potentially signalling an interrupt. - -Example test flow: - - #. Test registers BC1.2 detection callback using the Zephyr BC1.2 driver API. - #. Test connects a charger using the BC1.2 emulator backend. - #. Test verifies B1.2 detection callback invoked with correct charger type. - #. Test disconnects a charger using the BC1.2 emulator backend. - -With this architecture, the same test can be used will all supported drivers in -the same driver class. Available Emulators =================== -Zephyr includes the following emulators: - -* EEPROM, which uses a file as the EEPROM contents - -* I2C emulator driver, allowing drivers to be connected to an emulator so that - tests can be performed without access to the real hardware - -* SPI emulator driver, which does the same for SPI - -* eSPI emulator driver, which does the same for eSPI. The emulator is being - developed to support more functionalities. - -* CAN loopback driver - -A GPIO emulator is planned but is not yet complete. - -Samples -======= - -Here are some examples present in Zephyr: - -#. Bosch BMI160 sensor driver connected via both I2C and SPI to an emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/sensor/accel/ - :board: native_sim - :goals: build - -#. Simple test of the EEPROM emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom/api - :board: native_sim - :goals: build - -#. The same test can be built with a second EEPROM which is an Atmel AT24 EEPROM driver - connected via I2C an emulator: - - .. zephyr-app-commands:: - :app: tests/drivers/eeprom/api - :board: native_sim - :goals: build - :gen-args: -DDTC_OVERLAY_FILE=at2x_emul.overlay -DOVERLAY_CONFIG=at2x_emul.conf - -API Reference -************* - -.. doxygengroup:: io_emulators +**ADC emulator** + * A fake driver which pretends to be actual ADC, and can be used for testing higher-level API + for ADC devices. + * Main Kconfig option: :kconfig:option:`CONFIG_ADC_EMUL` + * DT binding: :dtcompatible:`zephyr,adc-emul` + +**DMA emulator** + * Emulated DMA controller + * Main Kconfig option: :kconfig:option:`CONFIG_DMA_EMUL` + * DT binding: :dtcompatible:`zephyr,dma-emul` + +**EEPROM emulator** + * Emulate an EEPROM on a flash partition + * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_EMULATOR` + * DT binding: :dtcompatible:`zephyr,emu-eeprom` + +.. _emul_eeprom_simu_brief: + +**EEPROM simulator** + * Emulate an EEPROM on RAM + * Main Kconfig option: :kconfig:option:`CONFIG_EEPROM_SIMULATOR` + * DT binding: :dtcompatible:`zephyr,sim-eeprom` + * Note: For :ref:`native targets ` it is also possible to keep the content + as a file on the host filesystem. + +**External bus and bus connected peripheral emulators** + * :ref:`Documentation ` + * Allow emulating external buses like I2C or SPI and peripherals connected to them. + +.. _emul_flash_simu_brief: + +**Flash simulator** + * Emulate a flash on RAM + * Main Kconfig option: :kconfig:option:`CONFIG_FLASH_SIMULATOR` + * DT binding: :dtcompatible:`zephyr,sim-flash` + * Note: For native targets it is also possible to keep the content as a file on the host + filesystem. Check :ref:`the native_sim flash simulator section `. + +**GPIO emulator** + * Emulated GPIO controllers which can be driven from SW + * Main Kconfig option: :kconfig:option:`CONFIG_GPIO_EMUL` + * DT binding: :dtcompatible:`zephyr,gpio-emul` + +**I2C emulator** + * Emulated I2C bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_I2C_EMUL` + * DT binding: :dtcompatible:`zephyr,i2c-emul-controller` + +**RTC emulator** + * Emulated RTC peripheral. See :ref:`RTC emulated device section ` + * Main Kconfig option: :kconfig:option:`CONFIG_RTC_EMUL` + * DT binding: :dtcompatible:`zephyr,rtc-emul` + +**SPI emulator** + * Emulated SPI bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_SPI_EMUL` + * DT binding: :dtcompatible:`zephyr,spi-emul-controller` + +**UART emulator** + * Emulated UART bus. See :ref:`bus emulators `. + * Main Kconfig option: :kconfig:option:`CONFIG_UART_EMUL` + * DT binding: :dtcompatible:`zephyr,uart-emul` diff --git a/doc/hardware/index.rst b/doc/hardware/index.rst index c9ba1c92f8a..72e9cc5fd05 100644 --- a/doc/hardware/index.rst +++ b/doc/hardware/index.rst @@ -10,6 +10,7 @@ Hardware Support barriers/index.rst cache/index.rst emulator/index.rst + emulator/bus_emulators.rst peripherals/index.rst pinctrl/index.rst porting/index diff --git a/doc/hardware/peripherals/can/controller.rst b/doc/hardware/peripherals/can/controller.rst index 6943949d1a4..e8710201349 100644 --- a/doc/hardware/peripherals/can/controller.rst +++ b/doc/hardware/peripherals/can/controller.rst @@ -203,7 +203,7 @@ The filter for this example is configured to match the identifier 0x123 exactly. .. code-block:: C const struct can_filter my_filter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x123, .mask = CAN_STD_ID_MASK }; @@ -226,7 +226,7 @@ The filter for this example is configured to match the extended identifier .. code-block:: C const struct can_filter my_filter = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = 0x1234567, .mask = CAN_EXT_ID_MASK }; diff --git a/doc/hardware/peripherals/can/index.rst b/doc/hardware/peripherals/can/index.rst index 6e96fb15cb2..c605bdd0301 100644 --- a/doc/hardware/peripherals/can/index.rst +++ b/doc/hardware/peripherals/can/index.rst @@ -8,3 +8,4 @@ Controller Area Network (CAN) controller.rst transceiver.rst + shell.rst diff --git a/doc/hardware/peripherals/can/shell.rst b/doc/hardware/peripherals/can/shell.rst new file mode 100644 index 00000000000..5b161fde5d6 --- /dev/null +++ b/doc/hardware/peripherals/can/shell.rst @@ -0,0 +1,269 @@ +.. _can_shell: + +CAN Shell +######### + +.. contents:: + :local: + :depth: 1 + +Overview +******** + +The CAN shell provides a ``can`` command with a set of subcommands for the :ref:`shell ` +module. It allows for testing and exploring the :ref:`can_api` driver API through an interactive +interface without having to write a dedicated application. The CAN shell can also be enabled in +existing applications to aid in interactive debugging of CAN issues. + +The CAN shell provides access to most CAN controller features, including inspection, configuration, +sending and receiving of CAN frames, and bus recovery. + +In order to enable the CAN shell, the following :ref:`Kconfig ` options must be enabled: + +* :kconfig:option:`CONFIG_SHELL` +* :kconfig:option:`CONFIG_CAN` +* :kconfig:option:`CONFIG_CAN_SHELL` + +The following :ref:`Kconfig ` options enable additional subcommands and features of the +``can`` command: + +* :kconfig:option:`CONFIG_CAN_FD_MODE` enables CAN FD specific subcommands (e.g. for setting the + timing for the CAN FD data phase). +* :kconfig:option:`CONFIG_CAN_RX_TIMESTAMP` enables printing of timestamps for received CAN frames. +* :kconfig:option:`CONFIG_CAN_STATS` enables printing of various statistics for the CAN controller + in the ``can show`` subcommand. This depends on :kconfig:option:`CONFIG_STATS` being enabled as + well. +* :kconfig:option:`CONFIG_CAN_AUTO_BUS_OFF_RECOVERY` enables the ``can recover`` subcommand when + disabled. + +For example, building the :ref:`hello_world` sample for the :ref:`frdm_k64f` with the CAN shell and +CAN statistics enabled: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: frdm_k64f + :gen-args: -DCONFIG_SHELL=y -DCONFIG_CAN=y -DCONFIG_CAN_SHELL=y -DCONFIG_STATS=y -DCONFIG_CAN_STATS=y + :goals: build + +See the :ref:`shell ` documentation for general instructions on how to connect and +interact with the shell. The CAN shell comes with built-in help (unless +:kconfig:option:`CONFIG_SHELL_HELP` is disabled). The built-in help messages can be printed by +passing ``-h`` or ``--help`` to the ``can`` command or any of its subcommands. All subcommands also +support tab-completion of their arguments. + +.. tip:: + All of the CAN shell subcommands take the name of a CAN controller as their first argument, which + also supports tab-completion. A list of all devices available can be obtained using the ``device + list`` shell command when :kconfig:option:`CONFIG_DEVICE_SHELL` is enabled. The examples below + all use the device name ``can@0``. + +Inspection +********** + +The properties of a given CAN controller can be inspected using the ``can show`` subcommand as shown +below. The properties include the core CAN clock rate, the maximum supported bitrate, the number of +RX filters supported, capabilities, current mode, current state, error counters, timing limits, and +more: + +.. code-block:: console + + uart:~$ can show can@0 + core clock: 144000000 Hz + max bitrate: 5000000 bps + max std filters: 15 + max ext filters: 15 + capabilities: normal loopback listen-only fd + mode: normal + state: stopped + rx errors: 0 + tx errors: 0 + timing: sjw 1..128, prop_seg 0..0, phase_seg1 2..256, phase_seg2 2..128, prescaler 1..512 + timing data: sjw 1..16, prop_seg 0..0, phase_seg1 1..32, phase_seg2 1..16, prescaler 1..32 + transceiver: passive/none + statistics: + bit errors: 0 + bit0 errors: 0 + bit1 errors: 0 + stuff errors: 0 + crc errors: 0 + form errors: 0 + ack errors: 0 + rx overruns: 0 + +.. note:: + The statistics are only printed if :kconfig:option:`CONFIG_CAN_STATS` is enabled. + +Configuration +************* + +The CAN shell allows for configuring the CAN controller mode and timing, along with starting and +stopping the processing of CAN frames. + +.. note:: + The CAN controller mode and timing can only be changed while the CAN controller is stopped, which + is the initial setting upon boot-up. The initial CAN controller mode is set to ``normal`` and the + initial timing is set according to the ``bus-speed``, ``sample-point``, ``bus-speed-data``, and + ``sample-point-data`` :ref:`devicetree` properties. + +Timing +====== + +The classic CAN bitrate/CAN FD arbitration phase bitrate can be configured using the ``can bitrate`` +subcommand as shown below. The bitrate is specified in bits per second. + +.. code-block:: console + + uart:~$ can bitrate can@0 125000 + setting bitrate to 125000 bps + +If :kconfig:option:`CONFIG_CAN_FD_MODE` is enabled, the data phase bitrate can be configured using +the ``can dbitrate`` subcommand as shown below. The bitrate is specified in bits per second. + +.. code-block:: console + + uart:~$ can dbitrate can@0 1000000 + setting data bitrate to 1000000 bps + +Both of these subcommands allow specifying an optional sample point in per mille and a +(Re)Synchronization Jump Width (SJW) in Time Quanta as positional arguments. Refer to the +interactive help of the subcommands for more details. + +It is also possible to configure the raw bit timing using the ``can timing`` and ``can dtiming`` +subcommands. Refer to the interactive help output for these subcommands for details on the required +arguments. + +Mode +==== + +The CAN shell allows for setting the mode of the CAN controller using the ``can mode`` +subcommand. An example for enabling loopback mode is shown below. + +.. code-block:: console + + uart:~$ can mode can@0 loopback + setting mode 0x00000001 + +The subcommand accepts multiple modes given on the same command line (e.g. ``can mode can@0 fd +loopback`` for setting CAN FD and loopback mode). Vendor-specific modes can be specified in +hexadecimal. + +Starting and Stopping +===================== + +After the timing and mode has been configured as needed, the CAN controller can be started using the +``can start`` subcommand as shown below. This will enable reception and transmission of CAN frames. + +.. code-block:: console + + uart:~$ can start can@0 + starting can@0 + +Prior to reconfiguring the timing or mode, the CAN controller needs to be stopped using the ``can +stop`` subcommand as shown below: + +.. code-block:: console + + uart:~$ can stop can@0 + stopping can@0 + +Receiving +********* + +In order to receive CAN frames, one or more CAN RX filters need to be configured. CAN RX filters are +added using the ``can filter add`` subcommand as shown below. The subcommand accepts a CAN ID in +hexadecimal format along with an optional CAN ID mask, also in hexadecimal format, for setting which +bits in the CAN ID are to be matched. Refer to the interactive help output for this subcommand for +further details on the supported arguments. + +.. code-block:: console + + uart:~$ can filter add can@0 010 + adding filter with standard (11-bit) CAN ID 0x010, CAN ID mask 0x7ff, data frames 1, RTR frames 0, CAN FD frames 0 + filter ID: 0 + +The filter ID (0 in the example above) returned is to be used when removing the CAN RX filter. + +Received CAN frames matching the added filter(s) are printed to the shell. A few examples are shown below: + +.. code-block:: console + + # Flags ID Size Data bytes + -- 010 [8] 01 02 03 04 05 06 07 08 + B- 010 [08] 01 02 03 04 05 06 07 08 + BP 010 [03] 01 aa bb + -- 00000010 [0] + -- 010 [1] 20 + -- 010 [8] remote transmission request + +The columns have the following meaning: + +* Flags + + * ``B``: The frame has the CAN FD Baud Rate Switch (BRS) flag set. + * ``P``: The frame has the CAN FD Error State Indicator (ESI) flag set. The transmitting node is + in error-passive state. + * ``-``: Unset flag. + +* ID + + * ``010``: The standard (11-bit) CAN ID of the frame in hexadecimal format, here 10h. + * ``00000010``: The extended (29-bit) CAN ID of the frame in hexadecimal format, here 10h. + +* Size + + * ``[8]``: The number of frame data bytes in decimal format, here a classic CAN frame with 8 data + bytes. + * ``[08]``: The number of frame data bytes in decimal format, here a CAN FD frame with 8 data + bytes. + +* Data bytes + + * ``01 02 03 04 05 06 07 08``: The frame data bytes in hexadecimal format, here the numbers from 1 + through 8. + * ``remote transmission request``: The frame is a Remote Transmission Request (RTR) frame and thus + carries no data bytes. + +.. tip:: + If :kconfig:option:`CONFIG_CAN_RX_TIMESTAMP` is enabled, each line will be prepended with a + timestamp from the free-running timestamp counter in the CAN controller. + +Configured CAN RX filters can be removed again using the ``can filter remove`` subcommand as shown +below. The filter ID is the ID returned by the ``can filter add`` subcommand (0 in the example +below). + +.. code-block:: console + + uart:~$ can filter remove can@0 0 + removing filter with ID 0 + +Sending +******* + +CAN frames can be queued for transmission using the ``can send`` subcommand as shown below. The +subcommand accepts a CAN ID in hexadecimal format and optionally a number of data bytes, also +specified in hexadecimal. Refer to the interactive help output for this subcommand for further +details on the supported arguments. + +.. code-block:: console + + uart:~$ can send can@0 010 1 2 3 4 5 6 7 8 + enqueuing CAN frame #2 with standard (11-bit) CAN ID 0x010, RTR 0, CAN FD 0, BRS 0, DLC 8 + CAN frame #2 successfully sent + +Bus Recovery +************ + +The ``can recover`` subcommand can be used for initiating recovery from a CAN bus-off event as shown +below: + +.. code-block:: console + + uart:~$ can recover can@0 + recovering, no timeout + +The subcommand accepts an optional bus recovery timeout in milliseconds. If no timeout is specified, +the command will wait indefinitely for the bus recovery to succeed. + +.. note:: + The ``recover`` subcommand is only available if + :kconfig:option:`CONFIG_CAN_AUTO_BUS_OFF_RECOVERY` is disabled. diff --git a/doc/hardware/peripherals/charger.rst b/doc/hardware/peripherals/charger.rst index b88876058b8..0198fe11f65 100644 --- a/doc/hardware/peripherals/charger.rst +++ b/doc/hardware/peripherals/charger.rst @@ -8,6 +8,11 @@ The charger subsystem exposes an API to uniformly access battery charger devices Basic Operation *************** +Initiating a Charge Cycle +========================= + +A charge cycle is initiated or terminated using :c:func:`charger_charge_enable`. + Properties ========== diff --git a/doc/hardware/peripherals/gnss.rst b/doc/hardware/peripherals/gnss.rst index fb750358dc3..bcc40e540ab 100644 --- a/doc/hardware/peripherals/gnss.rst +++ b/doc/hardware/peripherals/gnss.rst @@ -27,7 +27,7 @@ requires little more than implementing power management and configuration for the specific GNSS modem. Adding support for GNSS modems which use other protocols and/or -busses than the usual NMEA0183 over UART is possible, but will +buses than the usual NMEA0183 over UART is possible, but will require a bit more work from the driver developer. Configuration Options diff --git a/doc/hardware/peripherals/i3c.rst b/doc/hardware/peripherals/i3c.rst index 4ffb6dd45e4..347d8944ef1 100644 --- a/doc/hardware/peripherals/i3c.rst +++ b/doc/hardware/peripherals/i3c.rst @@ -303,7 +303,7 @@ the controller. I\ :sup:`2`\ C Devices under I3C Bus ==================================== -Since I3C is backware compatible with I\ :sup:`2`\ C, the I3C controller +Since I3C is backward compatible with I\ :sup:`2`\ C, the I3C controller API can accommodate I2C API calls without modifications if the controller device driver implements the I2C API. This has the advantage of using existing I2C devices without any modifications to their device drivers. diff --git a/doc/hardware/peripherals/index.rst b/doc/hardware/peripherals/index.rst index 19461b6c9f4..cd75fee0371 100644 --- a/doc/hardware/peripherals/index.rst +++ b/doc/hardware/peripherals/index.rst @@ -39,6 +39,7 @@ Peripherals kscan.rst led.rst mdio.rst + mipi_dbi.rst mipi_dsi.rst mbox.rst pcie.rst diff --git a/doc/hardware/peripherals/mipi_dbi.rst b/doc/hardware/peripherals/mipi_dbi.rst new file mode 100644 index 00000000000..640030c3f0b --- /dev/null +++ b/doc/hardware/peripherals/mipi_dbi.rst @@ -0,0 +1,27 @@ +.. _mipi_dbi_api: + +MIPI Display Bus Interface (DBI) +################################### + +The MIPI DBI driver class implements support for MIPI DBI compliant display +controllers. + +MIPI DBI defines 3 interface types: +* Type A: Motorola 6800 parallel bus + +* Type B: Intel 8080 parallel bus + +* Type C: SPI Type serial bit bus with 3 options: + + #. 9 write clocks per byte, final bit is command/data selection bit + + #. Same as above, but 16 write clocks per byte + + #. 8 write clocks per byte. Command/data selected via GPIO pin + +Currently, the API only supports Type C controllers, options 1 and 3. + +API Reference +************* + +.. doxygengroup:: mipi_dbi_interface diff --git a/doc/hardware/peripherals/rtc.rst b/doc/hardware/peripherals/rtc.rst index d2552d078ee..ae69df0b446 100644 --- a/doc/hardware/peripherals/rtc.rst +++ b/doc/hardware/peripherals/rtc.rst @@ -126,3 +126,24 @@ be printed to the console. .. note:: The tests take up to 30 seconds each if they are testing real hardware. + +.. _rtc_api_emul_dev: + +RTC emulated device +******************* + +The emulated RTC device fully implements the RTC API, and will behave like a real +RTC device, with the following limitations: + +* RTC time is not persistent across application initialization. +* RTC alarms are not persistent across application initialization. +* RTC time will drift over time. + +Every time an application is initialized, the RTC's time and alarms are reset. Reading +the time using :c:func:`rtc_get_time` will return ``-ENODATA``, until the time is +set using :c:func:`rtc_set_time`. The RTC will then behave as a real RTC, until the +application is reset. + +The emulated RTC device driver is built for the compatible +:dtcompatible:`zephyr,rtc-emul` and will be included if :kconfig:option:`CONFIG_RTC` +is selected. diff --git a/doc/hardware/peripherals/uart.rst b/doc/hardware/peripherals/uart.rst index 42906bca6fa..177a54dbbfe 100644 --- a/doc/hardware/peripherals/uart.rst +++ b/doc/hardware/peripherals/uart.rst @@ -31,11 +31,11 @@ than the other methods. .. warning:: Interrupt-driven API and the Asynchronous API should NOT be used at - the same time, since both APIs require hardware interrupts to function - properly, using the callbacks for both APIs would result in interference - between each other. :kconfig:option:`CONFIG_UART_EXCLUSIVE_API_CALLBACKS` - is enabled by default so that only the callbacks associated with one API - is active at a time. + the same time for the same hardware peripheral, since both APIs require + hardware interrupts to function properly. Using the callbacks for both + APIs would result in interference between each other. + :kconfig:option:`CONFIG_UART_EXCLUSIVE_API_CALLBACKS` is enabled by default + so that only the callbacks associated with one API is active at a time. Configuration Options diff --git a/doc/hardware/pinctrl/index.rst b/doc/hardware/pinctrl/index.rst index c67f46a0cb1..98edfeacf58 100644 --- a/doc/hardware/pinctrl/index.rst +++ b/doc/hardware/pinctrl/index.rst @@ -145,9 +145,10 @@ In most situations, the states defined in Devicetree will be the ones used in the compiled firmware. However, there are some cases where certain states will be conditionally used depending on a compilation flag. A typical case is the ``sleep`` state. This state is only used in practice if -:kconfig:option:`CONFIG_PM_DEVICE` is enabled. If a firmware variant without device -power management is needed, one should in theory remove the ``sleep`` state from -Devicetree to not waste ROM space storing such unused state. +:kconfig:option:`CONFIG_PM` or :kconfig:option:`CONFIG_PM_DEVICE` is enabled. +If a firmware variant without these power management configurations is needed, +one should in theory remove the ``sleep`` state from Devicetree to not waste ROM +space storing such unused state. States can be skipped by the ``pinctrl`` Devicetree macros if a definition named ``PINCTRL_SKIP_{STATE_NAME}`` expanding to ``1`` is present when pin control @@ -157,8 +158,8 @@ management: .. code-block:: c - #ifndef CONFIG_PM_DEVICE - /** If device power management is not enabled, "sleep" state will be ignored. */ + #if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE) + /** Out of power management configurations, ignore "sleep" state. */ #define PINCTRL_SKIP_SLEEP 1 #endif diff --git a/doc/hardware/porting/arch.rst b/doc/hardware/porting/arch.rst index 0e31a62707b..62b79cdb032 100644 --- a/doc/hardware/porting/arch.rst +++ b/doc/hardware/porting/arch.rst @@ -47,6 +47,16 @@ some are optional: * **Linker scripts and toolchains**: architecture-specific details will most likely be needed in the build system and when linking the image (required). +* **Memory Management and Memory Mapping**: for architecture-specific details + on supporting memory management and memory mapping. + +* **Stack Objects**: for architecture-specific details on memory protection + hardware regarding stack objects. + +* **User Mode Threads**: for supporting threads in user mode. + +* **GDB Stub**: for supporting GDB stub to enable remote debugging. + Early Boot Sequence ******************* @@ -61,9 +71,9 @@ Common steps for all architectures: * If running an :abbr:`XIP (eXecute-In-Place)` kernel, copy initialized data from ROM to RAM. * If not using an ELF loader, zero the BSS section. -* Jump to :code:`_Cstart()`, the early kernel initialization +* Jump to :code:`z_cstart()`, the early kernel initialization - * :code:`_Cstart()` is responsible for context switching out of the fake + * :code:`z_cstart()` is responsible for context switching out of the fake context running at startup into the main thread. Some examples of architecture-specific steps that have to be taken: @@ -467,8 +477,8 @@ be derived from the linker scripts of other architectures. Some sections might be specific to the new architecture, for example the SCB section on ARM and the IDT section on x86. -Memory Management -***************** +Memory Management and Memory Mapping +************************************ If the target platform enables paging and requires drivers to memory-map their I/O regions, :kconfig:option:`CONFIG_MMU` needs to be enabled and the @@ -537,22 +547,21 @@ account storage for TLS and ASLR random offsets. .. code-block:: none - +---------------------+ <- thread.stack_obj - | Reserved Memory | } K_(THREAD|KERNEL)_STACK_RESERVED - +---------------------+ - | Carved-out memory | - |.....................| <- thread.stack_info.start - | Unused stack buffer | - | | - |.....................| <- thread's current stack pointer - | Used stack buffer | - | | - |.....................| <- Initial stack pointer. Computable - | ASLR Random offset | with thread.stack_info.delta - +---------------------| <- thread.userspace_local_data - | Thread-local data | - +---------------------+ <- thread.stack_info.start + - thread.stack_info.size + +---------------------+ <- thread.stack_obj + | Reserved Memory | } K_(THREAD|KERNEL)_STACK_RESERVED + +---------------------+ + | Carved-out memory | + |.....................| <- thread.stack_info.start + | Unused stack buffer | + | | + |.....................| <- thread's current stack pointer + | Used stack buffer | + | | + |.....................| <- Initial stack pointer. Computable + | ASLR Random offset | with thread.stack_info.delta + +---------------------| <- thread.userspace_local_data + | Thread-local data | + +---------------------+ <- thread.stack_info.start + thread.stack_info.size At present, Zephyr does not support stacks that grow upward. diff --git a/doc/introduction/index.rst b/doc/introduction/index.rst index 13204e6bb7d..f8b841ae300 100644 --- a/doc/introduction/index.rst +++ b/doc/introduction/index.rst @@ -80,6 +80,8 @@ Zephyr offers a large and ever growing number of features including: * Red/black tree ready queue * Traditional multi-queue ready queue +.. _zephyr_intro_configurability: + **Highly configurable / Modular for flexibility** Allows an application to incorporate *only* the capabilities it needs as it needs them, and to specify their quantity and size. diff --git a/doc/kernel/code-relocation.rst b/doc/kernel/code-relocation.rst index a9da18e98cd..599cdedccbd 100644 --- a/doc/kernel/code-relocation.rst +++ b/doc/kernel/code-relocation.rst @@ -97,6 +97,22 @@ This section shows additional configuration options that can be set in zephyr_code_relocate(FILES ${sources} LOCATION SRAM) zephyr_code_relocate(FILES $ LOCATION SRAM) +NOKEEP flag +=========== + +By default, all relocated functions and variables will be marked with ``KEEP()`` +when generating ``linker_relocate.ld``. Therefore, if any input file happens to +contain unused symbols, then they will not be discarded by the linker, even when +it is invoked with ``--gc-sections``. If you'd like to override this behavior, +you can pass ``NOKEEP`` to your ``zephyr_code_relocate()`` call. + + .. code-block:: none + + zephyr_code_relocate(FILES src/file1.c LOCATION SRAM2_TEXT NOKEEP) + +The example above will help ensure that any unused code found in the .text +sections of ``file1.c`` will not stick to SRAM2. + NOCOPY flag =========== diff --git a/doc/kernel/drivers/device_driver_model.svg b/doc/kernel/drivers/device_driver_model.svg index 9ace8badffc..fe779232eec 100644 --- a/doc/kernel/drivers/device_driver_model.svg +++ b/doc/kernel/drivers/device_driver_model.svg @@ -1,3 +1,3 @@ -
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 2 of Device Driver 1
Instance 2 of Device Driver 1
Instance 1 of Device Driver 1
Instance 1 of Device Driver 1
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Device Driver 1
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsytem 1
Subsytem 1
Device Driver APIs
Device Driver APIs
Device Driver Instances
Device Driver Instances
Device Driver Implementations
Device Driver Implementations
Device Driver 2
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsytem 2
[Not supported by viewer]
Device Driver 3
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Instance 1 of Device Driver 2
Instance 1 of Device Driver 2
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 1 of Device Driver 3
Instance 1 of Device Driver 3
Application
Application
+
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 2 of Device Driver 1
Instance 2 of Device Driver 1
Instance 1 of Device Driver 1
Instance 1 of Device Driver 1
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Device Driver 1
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsystem 1
Subsystem 1
Device Driver APIs
Device Driver APIs
Device Driver Instances
Device Driver Instances
Device Driver Implementations
Device Driver Implementations
Device Driver 2
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Subsystem 2
[Not supported by viewer]
Device Driver 3
[Not supported by viewer]
API Impl 1
API Impl 1
API Impl 2
API Impl 2
API Impl 3
API Impl 3
Generic
Type API
[Not supported by viewer]
API 1
API 1
API 2
API 2
API 3
API 3
Instance 1 of Device Driver 2
Instance 1 of Device Driver 2
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
struct device {
    const struct config *config;
    const void *api;
    void * const data;
};

struct config {...};
[Not supported by viewer]
Instance 1 of Device Driver 3
Instance 1 of Device Driver 3
Application
Application
diff --git a/doc/kernel/memory_management/heap.rst b/doc/kernel/memory_management/heap.rst index 70d719c7396..a52c5ff77c6 100644 --- a/doc/kernel/memory_management/heap.rst +++ b/doc/kernel/memory_management/heap.rst @@ -165,6 +165,18 @@ the kernel not to define the heap memory pool object. The maximum size is limite by the amount of available memory in the system. The project build will fail in the link stage if the size specified can not be supported. +In addition, each subsystem (board, driver, library, etc) can set a custom +requirement by defining a Kconfig option with the prefix +``HEAP_MEM_POOL_ADD_SIZE_`` (this value is in bytes). If multiple subsystems +specify custom values, the sum of these will be used as the minimum requirement. +If the application tries to set a value that's less than the minimum value, this +will be ignored and the minimum value will be used instead. + +To force a smaller than minimum value to be used, the application may enable the +:kconfig:option:`CONFIG_HEAP_MEM_POOL_IGNORE_MIN` option. This can be useful +when optimizing the heap size and the minimum requirement can be more accurately +determined for a specific application. + Allocating Memory ================= diff --git a/doc/kernel/memory_management/index.rst b/doc/kernel/memory_management/index.rst index 7fbb03f6574..0bbf2f7a428 100644 --- a/doc/kernel/memory_management/index.rst +++ b/doc/kernel/memory_management/index.rst @@ -13,3 +13,4 @@ The following contains various topics regarding memory management. slabs.rst sys_mem_blocks.rst demand_paging.rst + virtual_memory.rst diff --git a/doc/kernel/memory_management/virtual_memory.rst b/doc/kernel/memory_management/virtual_memory.rst new file mode 100644 index 00000000000..dbc95fb7b52 --- /dev/null +++ b/doc/kernel/memory_management/virtual_memory.rst @@ -0,0 +1,197 @@ +.. _memory_management_api_virtual_memory: + +Virtual Memory +############## + +Virtual memory (VM) in Zephyr provides developers with the ability to fine tune +access to memory. To utilize virtual memory, the platform must support +Memory Management Unit (MMU) and it must be enabled in the build. Due to +the target of Zephyr mainly being embedded systems, virtual memory +support in Zephyr differs a bit from that in traditional operating +systems: + +Mapping of Kernel Image + Default is to do 1:1 mapping for the kernel image (including code and data) + between physical and virtual memory address spaces, if demand paging + is not enabled. Deviation from this requires careful manipulation of + linker script. + +Secondary Storage + Basic virtual memory support does not utilize secondary storage to + extend usable memory. The maximum usable memory is the same as + the physical memory. + + * :ref:`memory_management_api_demand_paging` enables utilizing + secondary storage as a backing store for virtual memory, thus + allowing larger usable memory than the available physical memory. + Note that demand paging needs to be explicitly enabled. + + * Although the virtual memory space can be larger than physical + memory space, without enabling demand paging, all virtually + mapped memory must be backed by physical memory. + + +Kconfigs +******** + +Required +======== + +These are the Kconfigs that need to be enabled or defined for kernel to support +virtual memory. + +* :kconfig:option:`CONFIG_MMU`: must be enabled for virtual memory support in + kernel. + +* :kconfig:option:`CONFIG_MMU_PAGE_SIZE`: size of a memory page. Default is 4KB. + +* :kconfig:option:`CONFIG_KERNEL_VM_BASE`: base address of virtual address space. + +* :kconfig:option:`CONFIG_KERNEL_VM_SIZE`: size of virtual address space. + Default is 8MB. + +* :kconfig:option:`CONFIG_KERNEL_VM_OFFSET`: kernel image starts at this offset + from :kconfig:option:`CONFIG_KERNEL_VM_BASE`. + +Optional +======== + +* :kconfig:option:`CONFIG_KERNEL_DIRECT_MAP`: permits 1:1 mappings between + virtual and physical addresses, instead of kernel choosing addresses within + the virtual address space. This is useful for mapping device MMIO regions for + more precise access control. + + +Memory Map Overview +******************* + +This is an overview of the memory map of the virtual memory address space. +Note that the ``Z_*`` macros, which are used in code, may have different +meanings depending on architecture and Kconfigs, which will be explained +below. + +.. code-block:: none + :emphasize-lines: 1, 3, 9, 22, 24 + + +--------------+ <- Z_VIRT_RAM_START + | Undefined VM | <- architecture specific reserved area + +--------------+ <- Z_KERNEL_VIRT_START + | Mapping for | + | main kernel | + | image | + | | + | | + +--------------+ <- Z_FREE_VM_START + | | + | Unused, | + | Available VM | + | | + |..............| <- grows downward as more mappings are made + | Mapping | + +--------------+ + | Mapping | + +--------------+ + | ... | + +--------------+ + | Mapping | + +--------------+ <- memory mappings start here + | Reserved | <- special purpose virtual page(s) of size Z_VM_RESERVED + +--------------+ <- Z_VIRT_RAM_END + +* ``Z_VIRT_RAM_START`` is the beginning of the virtual memory address space. + This needs to be page aligned. Currently, it is the same as + :kconfig:option:`CONFIG_KERNEL_VM_BASE`. + +* ``Z_VIRT_RAM_SIZE`` is the size of the virtual memory address space. + This needs to be page aligned. Currently, it is the same as + :kconfig:option:`CONFIG_KERNEL_VM_SIZE`. + +* ``Z_VIRT_RAM_END`` is simply (``Z_VIRT_RAM_START`` + ``Z_VIRT_RAM_SIZE``). + +* ``Z_KERNEL_VIRT_START`` is the same as ``z_mapped_start`` specified in the linker + script. This is the virtual address of the beginning of the kernel image at + boot time. + +* ``Z_KERNEL_VIRT_END`` is the same as ``z_mapped_end`` specified in the linker + script. This is the virtual address of the end of the kernel image at boot time. + +* ``Z_FREE_VM_START`` is the beginning of the virtual address space where addresses + can be allocated for memory mapping. This depends on whether + :kconfig:option:`CONFIG_ARCH_MAPS_ALL_RAM` is enabled. + + * If it is enabled, which means all physical memory are mapped in virtual + memory address space, and it is the same as + (:kconfig:option:`CONFIG_SRAM_BASE_ADDRESS` + :kconfig:option:`CONFIG_SRAM_SIZE`). + + * If it is disabled, ``Z_FREE_VM_START`` is the same ``Z_KERNEL_VIRT_END`` which + is the end of the kernel image. + +* ``Z_VM_RESERVED`` is an area reserved to support kernel functions. For example, + some addresses are reserved to support demand paging. + + +Virtual Memory Mappings +*********************** + +Setting up Mappings at Boot +=========================== + +In general, most supported architectures set up the memory mappings at boot as +following: + +* ``.text`` section is read-only and executable. It is accessible in + both kernel and user modes. + +* ``.rodata`` section is read-only and non-executable. It is accessible + in both kernel and user modes. + +* Other kernel sections, such as ``.data``, ``.bss`` and ``.noinit``, are + read-write and non-executable. They are only accessible in kernel mode. + + * Stacks for user mode threads are automatically granted read-write access + to their corresponding user mode threads during thread creation. + + * Global variables, by default, are not accessible to user mode threads. + Refer to :ref:`Memory Domains and Partitions` on how to + use global variables in user mode threads, and on how to share data + between user mode threads. + +Caching modes for these mappings are architecture specific. They can be +none, write-back, or write-through. + +Note that SoCs have their own additional mappings required to boot where +these mappings are defined under their own SoC configurations. These mappings +usually include device MMIO regions needed to setup the hardware. + + +Mapping Anonymous Memory +======================== + +The unused physical memory can be mapped in virtual address space on demand. +This is conceptually similar to memory allocation from heap, but these +mappings must be aligned on page size and have finer access control. + +* :c:func:`k_mem_map` can be used to map unused physical memory: + + * The requested size must be multiple of page size. + + * The address returned is inside the virtual address space between + ``Z_FREE_VM_START`` and ``Z_VIRT_RAM_END``. + + * The mapped region is not guaranteed to be physically contiguous in memory. + + * Guard pages immediately before and after the mapped virtual region are + automatically allocated to catch access issue due to buffer underrun + or overrun. + +* The mapped region can be unmapped (i.e. freed) via :c:func:`k_mem_unmap`: + + * Caution must be exercised to give the pass the same region size to + both :c:func:`k_mem_map` and :c:func:`k_mem_unmap`. The unmapping + function does not check if it is a valid mapped region before unmapping. + + +API Reference +************* + +.. doxygengroup:: kernel_memory_management diff --git a/doc/kernel/services/interrupts.rst b/doc/kernel/services/interrupts.rst index 849e614a562..ea1f7935197 100644 --- a/doc/kernel/services/interrupts.rst +++ b/doc/kernel/services/interrupts.rst @@ -59,7 +59,7 @@ nesting support is enabled. .. _multi_level_interrupts: -Multi-level Interrupt handling +Multi-level Interrupt Handling ============================== A hardware platform can support more interrupt lines than natively-provided @@ -68,7 +68,7 @@ hardware interrupts are combined into one line that is then routed to the parent controller. If nested interrupt controllers are supported, :kconfig:option:`CONFIG_MULTI_LEVEL_INTERRUPTS` -should be set to 1, and :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPTS` and +should be enabled, and :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPTS` and :kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPTS` configured as well, based on the hardware architecture. @@ -399,7 +399,7 @@ being invoked each time interrupt 24 is triggered. If :kconfig:option:`CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS` is set to a value lower than 2 (current number of clients), a build error will be generated. -If dynamic interrupts are enabled, c:func:`irq_connect_dynamic` will allow sharing interrupts +If dynamic interrupts are enabled, :c:func:`irq_connect_dynamic` will allow sharing interrupts during runtime. Exceeding the configured maximum number of allowed clients will result in a failed assertion. @@ -457,6 +457,38 @@ Interrupt tables are set up at build time using some special build tools. The details laid out here apply to all architectures except x86, which are covered in the `x86 Details`_ section below. +The invocation of :c:macro:`IRQ_CONNECT` will declare an instance of +struct _isr_list wich is placed in a special .intList section. +This section is placed in compiled code on precompilation stages only. +It is meant to be used by Zephyr script to generate interrupt tables +and is removed from the final build. +The script implements different parsers to process the data from .intList section +and produce the required output. + +The default parser generates C arrays filled with arguments and interrupt +handlers in a form of addresses directly taken from .intList section entries. +It works with all the architectures and compillers (with the exception mentioned above). +The limitation of this parser is the fact that after the arrays are generated +it is expected for the code not to relocate. +Any relocation on this stage may lead to the situation where the entry in the interrupt array +is no longer pointing to the function that was expected. +It means that this parser, being more compatible is limiting us from using Link Time Optimization. + +The local isr declaration parser uses different approach to construct +the same arrays at binnary level. +All the entries to the arrays are declared and defined locally, +directly in the file where :c:macro:`IRQ_CONNECT` is used. +They are placed in a section with the unique, synthetized name. +The name of the section is then placed in .intList section and it is used to create linker script +to properly place the created entry in the right place in the memory. +This parser is now limited to the supported architectures and toolchains but in reward it keeps +the information about object relations for linker thus allowing the Link Time Optimization. + +Implementation using C arrays +----------------------------- + +This is the default configuration available for all Zephyr supported architectures. + Any invocation of :c:macro:`IRQ_CONNECT` will declare an instance of struct _isr_list which is placed in a special .intList section: @@ -500,7 +532,7 @@ do not support the notion of interrupt priority, in which case the priority argument is ignored. Vector Table ------------- +~~~~~~~~~~~~ A vector table is generated when :kconfig:option:`CONFIG_GEN_IRQ_VECTOR_TABLE` is enabled. This data structure is used natively by the CPU and is simply an array of function pointers, where each element n corresponds to the IRQ handler @@ -527,7 +559,7 @@ CONFIG_GEN_IRQ_START_VECTOR needs to be set to properly offset the indices in the table. SW ISR Table ------------- +~~~~~~~~~~~~ This is an array of struct _isr_table_entry: .. code-block:: c @@ -542,31 +574,104 @@ argument and execute it. The active IRQ line is looked up in an interrupt controller register and used to index this table. Shared SW ISR Table -------------------- +~~~~~~~~~~~~~~~~~~~ This is an array of struct z_shared_isr_table_entry: .. code-block:: c struct z_shared_isr_table_entry { - struct z_shared_isr_client clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; + struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; size_t client_num; }; This table keeps track of the registered clients for each of the interrupt -lines. Whenever an interrupt line becomes shared, c:func:`z_shared_isr` will +lines. Whenever an interrupt line becomes shared, :c:func:`z_shared_isr` will replace the currently registered ISR in _sw_isr_table. This special ISR will iterate through the list of registered clients and invoke the ISRs. -The definition for struct z_shared_isr_client is as follows: +Implementation using linker script +---------------------------------- + +This way of prepare and parse .isrList section to implement interrupt vectors arrays +is called local isr declaration. +The name comes from the fact that all the entries to the arrays that would create +interrupt vectors are created locally in place of invocation of :c:macro:`IRQ_CONNECT` macro. +Then automatically generated linker scripts are used to place it in the right place in the memory. + +This option requires enabling by the choose of :kconfig:option:`ISR_TABLES_LOCAL_DECLARATION`. +If this configuration is supported by the used architecture and toolchaing the +:kconfig:option:`ISR_TABLES_LOCAL_DECLARATION_SUPPORTED` is set. +See defails of this option for the information about currently supported configurations. + +Any invocation of :c:macro:`IRQ_CONNECT` or `IRQ_DIRECT_CONNECT` will declare an instance of struct +_isr_list_sname which is placde in a special .intList section: + +.. code-block:: c + + struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; + }; + +Note that the section name is placed in flexible array member. +It means that the size of the initialized structure will warry depending on the +structure name length. +The whole entry is used by the script during the build of the application +and has all the information needed for proper interrupt placement. + +Beside of the _isr_list_sname the :c:macro:`IRQ_CONNECT` macro generates an entry +that would be the part of the interrupt array: .. code-block:: c - struct z_shared_isr_client { - void (*isr)(const void *arg); + struct _isr_table_entry { const void *arg; + void (*isr)(const void *); }; +This array is placed in a section with the name saved in _isr_list_sname structure. + +The values created by :c:macro:`IRQ_DIRECT_CONNECT` macro depends on the architecture. +It can be changed to variable that points to a interrupt handler: + +.. code-block:: c + + static uintptr_t = ((uintptr_t)func); + +Or to actuall naked function that implements a jump to the interrupt handler: + +.. code-block:: c + + static void (void) + { + __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); + } + +Simillar like for :c:macro:`IRQ_CONNECT`, the created variable or function is placed +in a section, saved in _isr_list_sname section. + +Files generated by the script +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The interrupt tables generator script creates 3 files: +isr_tables.c, isr_tables_swi.ld, and isr_tables_vt.ld. + +The isr_tables.c will contain all the structures for interrupts, direct interrupts and +shared interrupts (if enabled). This file implements only all the structures that +are not implemented by the application, leaving a comment where the interrupt +not implemented here can be found. + +Then two linker files are used. The isr_tables_vt.ld file is included in place +where the interrupt vectors are required to be placed in the selected architecture. +The isr_tables_swi.ld file describes the placement of the software interrupt table +elements. The separated file is required as it might be placed in writable on nonwritable +section, depending on the current configuration. + x86 Details ----------- @@ -608,7 +713,7 @@ connected. Going Beyond the Default Supported Number of Interrupts ------------------------------------------------------- -When generating interrupts in the multilevel configuration, 8-bits per level is the default +When generating interrupts in the multi-level configuration, 8-bits per level is the default mask used when determining which level a given interrupt code belongs to. This can become a problem when dealing with CPUs that support more than 255 interrupts per single aggregator. In this case it may be desirable to override these defaults and use a custom @@ -616,11 +721,11 @@ number of bits per level. Regardless of how many bits used for each level, the s the total bits used between all levels must sum to be less than or equal to 32-bits, fitting into a single 32-bit integer. To modify the bit total per level, override the default 8 in `Kconfig.multilevel` by setting :kconfig:option:`CONFIG_1ST_LEVEL_INTERRUPT_BITS` -for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second tier and -:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third tier. These masks control the +for the first level, :kconfig:option:`CONFIG_2ND_LEVEL_INTERRUPT_BITS` for the second level and +:kconfig:option:`CONFIG_3RD_LEVEL_INTERRUPT_BITS` for the third level. These masks control the length of the bit masks and shift to apply when generating interrupt values, when checking the interrupts level and converting interrupts to a different level. The logic controlling -this can be found in `irq.h` +this can be found in :file:`irq_multilevel.h` Suggested Uses ************** diff --git a/doc/kernel/services/other/atomic.rst b/doc/kernel/services/other/atomic.rst index 6d739209ae6..3e589a4cad3 100644 --- a/doc/kernel/services/other/atomic.rst +++ b/doc/kernel/services/other/atomic.rst @@ -4,8 +4,8 @@ Atomic Services ############### An :dfn:`atomic variable` is one that can be read and modified -by threads and ISRs in an uninterruptible manner. It 32-bit on -32-bit machines and 64-bit on 64-bit machines. +by threads and ISRs in an uninterruptible manner. It is a 32-bit variable on +32-bit machines and a 64-bit variable on 64-bit machines. .. contents:: :local: diff --git a/doc/kernel/services/polling.rst b/doc/kernel/services/polling.rst index 84f7dbf4b6f..71937648a93 100644 --- a/doc/kernel/services/polling.rst +++ b/doc/kernel/services/polling.rst @@ -24,6 +24,8 @@ There is a limited set of such conditions: - a semaphore becomes available - a kernel FIFO contains data ready to be retrieved +- a kernel message queue contains data ready to be retrieved +- a kernel pipe contains data ready to be retrieved - a poll signal is raised A thread that wants to wait on multiple conditions must define an array of @@ -87,20 +89,26 @@ ignored, most likely temporarily, its type can be set to K_POLL_TYPE_IGNORE. .. code-block:: c - struct k_poll_event events[2] = { + struct k_poll_event events[4] = { K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &my_sem, 0), K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_FIFO_DATA_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &my_fifo, 0), + K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_msgq, 0), + K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_PIPE_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_pipe, 0), }; or at runtime .. code-block:: c - struct k_poll_event events[2]; + struct k_poll_event events[4]; void some_init(void) { k_poll_event_init(&events[0], @@ -113,6 +121,16 @@ or at runtime K_POLL_MODE_NOTIFY_ONLY, &my_fifo); + k_poll_event_init(&events[2], + K_POLL_TYPE_MSGQ_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_msgq); + + k_poll_event_init(&events[3], + K_POLL_TYPE_PIPE_DATA_AVAILABLE, + K_POLL_MODE_NOTIFY_ONLY, + &my_pipe); + // tags are left uninitialized if unused } @@ -145,6 +163,12 @@ In case of success, :c:func:`k_poll` returns 0. If it times out, it returns } else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) { data = k_fifo_get(events[1].fifo, 0); // handle data + } else if (events[2].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE) { + ret = k_msgq_get(events[2].msgq, buf, K_NO_WAIT); + // handle data + } else if (events[3].state == K_POLL_STATE_PIPE_DATA_AVAILABLE) { + ret = k_pipe_get(events[3].pipe, buf, bytes_to_read, &bytes_read, min_xfer, K_NO_WAIT); + // handle data } } else { // handle timeout @@ -165,9 +189,16 @@ to :c:macro:`K_POLL_STATE_NOT_READY` by the user. } else if (events[1].state == K_POLL_STATE_FIFO_DATA_AVAILABLE) { data = k_fifo_get(events[1].fifo, 0); // handle data - } + } else if (events[2].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE) { + ret = k_msgq_get(events[2].msgq, buf, K_NO_WAIT); + // handle data + } else if (events[3].state == K_POLL_STATE_PIPE_DATA_AVAILABLE) { + ret = k_pipe_get(events[3].pipe, buf, bytes_to_read, &bytes_read, min_xfer, K_NO_WAIT); + // handle data events[0].state = K_POLL_STATE_NOT_READY; events[1].state = K_POLL_STATE_NOT_READY; + events[2].state = K_POLL_STATE_NOT_READY; + events[3].state = K_POLL_STATE_NOT_READY; } } diff --git a/doc/kernel/services/smp/smp.rst b/doc/kernel/services/smp/smp.rst index 0f1e29c9f12..0a94ed022b0 100644 --- a/doc/kernel/services/smp/smp.rst +++ b/doc/kernel/services/smp/smp.rst @@ -302,7 +302,7 @@ registers only when :c:func:`arch_switch` is called to minimize context switching latency. Such architectures must use NULL as the argument to :c:func:`z_get_next_switch_handle` to determine if there is a new thread to schedule, and follow through with their own :c:func:`arch_switch` or -derrivative if so, or directly leave interrupt mode otherwise. +derivative if so, or directly leave interrupt mode otherwise. In the former case it is up to that switch code to store the handle resulting from the thread that is being switched out in that thread's "switch_handle" field after its context has fully been saved. diff --git a/doc/kernel/services/timing/timers.rst b/doc/kernel/services/timing/timers.rst index c5f6beca358..9b1e424921d 100644 --- a/doc/kernel/services/timing/timers.rst +++ b/doc/kernel/services/timing/timers.rst @@ -28,10 +28,10 @@ A timer has the following key properties: * A **period** specifying the time interval between all timer expirations after the first one, also a ``k_timeout_t``. It must be non-negative. A period of ``K_NO_WAIT`` (i.e. zero) or - ``K_FOREVER`` means that the timer is a one shot timer that stops + ``K_FOREVER`` means that the timer is a one-shot timer that stops after a single expiration. (For example then, if a timer is started with a duration of 200 and a period of 75, it will first expire - after 200ms and then every 75ms after that.) + after 200 ms and then every 75 ms after that.) * An **expiry function** that is executed each time the timer expires. The function is executed by the system clock interrupt handler. @@ -49,7 +49,7 @@ expiry function and stop function values, sets the timer's status to zero, and puts the timer into the **stopped** state. A timer is **started** by specifying a duration and a period. -The timer's status is reset to zero, then the timer enters +The timer's status is reset to zero, and then the timer enters the **running** state and begins counting down towards expiry. Note that the timer's duration and period parameters specify @@ -63,7 +63,7 @@ When a running timer expires its status is incremented and the timer executes its expiry function, if one exists; If a thread is waiting on the timer, it is unblocked. If the timer's period is zero the timer enters the stopped state; -otherwise the timer restarts with a new duration equal to its period. +otherwise, the timer restarts with a new duration equal to its period. A running timer can be stopped in mid-countdown, if desired. The timer's status is left unchanged, then the timer enters the stopped state @@ -128,7 +128,7 @@ Using a Timer Expiry Function ============================= The following code uses a timer to perform a non-trivial action on a periodic -basis. Since the required work cannot be done at interrupt level, +basis. Since the required work cannot be done at the interrupt level, the timer's expiry function submits a work item to the :ref:`system workqueue `, whose thread performs the work. @@ -151,14 +151,14 @@ the timer's expiry function submits a work item to the ... - /* start periodic timer that expires once every second */ + /* start a periodic timer that expires once every second */ k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1)); Reading Timer Status ==================== The following code reads a timer's status directly to determine -if the timer has expired on not. +if the timer has expired or not. .. code-block:: c @@ -166,7 +166,7 @@ if the timer has expired on not. ... - /* start one shot timer that expires after 200 ms */ + /* start a one-shot timer that expires after 200 ms */ k_timer_start(&my_status_timer, K_MSEC(200), K_NO_WAIT); /* do work */ @@ -197,7 +197,7 @@ are separated by the specified time interval. /* do first protocol operation */ ... - /* start one shot timer that expires after 500 ms */ + /* start a one-shot timer that expires after 500 ms */ k_timer_start(&my_sync_timer, K_MSEC(500), K_NO_WAIT); /* do other work */ diff --git a/doc/kernel/timing_functions/index.rst b/doc/kernel/timing_functions/index.rst index 5f21204c4e6..711ce319fcc 100644 --- a/doc/kernel/timing_functions/index.rst +++ b/doc/kernel/timing_functions/index.rst @@ -78,3 +78,6 @@ API documentation ***************** .. doxygengroup:: timing_api +.. doxygengroup:: timing_api_arch +.. doxygengroup:: timing_api_soc +.. doxygengroup:: timing_api_board diff --git a/doc/project/dev_env_and_tools.rst b/doc/project/dev_env_and_tools.rst index 8269e891d43..1678a455f17 100644 --- a/doc/project/dev_env_and_tools.rst +++ b/doc/project/dev_env_and_tools.rst @@ -111,7 +111,7 @@ TSC and Working Groups Changes that introduce new features or functionality or change the way the overall system works need to be reviewed by the TSC or the responsible Working -Group. For example for :ref:`stable API changes `, the +Group. For example for :ref:`breaking API changes `, the proposal needs to be presented in the Architecture meeting so that the relevant stakeholders are made aware of the change. @@ -323,7 +323,7 @@ Fix for an issue blocking development. * *Maintainer* -Maintainer review reqiured. +Maintainer review required. * *Security Review* @@ -383,10 +383,10 @@ following `TSC meeting`_ if time permits. .. _`TSC meeting`: https://github.com/zephyrproject-rtos/zephyr/wiki/Zephyr-Committee-and-Working-Group-Meetings#technical-steering-committee-tsc -* *Stable API Change* +* *Breaking API Change* -The issue or PR describes a change to a stable API. See additional information -in :ref:`stable_api_changes`. +The issue or PR describes a breaking change to a stable API. See additional information +in :ref:`breaking_api_changes`. * *Bug* diff --git a/doc/project/project_roles.rst b/doc/project/project_roles.rst index 2d1a74b573f..a57a7b46def 100644 --- a/doc/project/project_roles.rst +++ b/doc/project/project_roles.rst @@ -123,6 +123,8 @@ in addition to those listed for Contributors and Collaborators: * Responsibility to ensure all contributions of the project have been reviewed within reasonable time. * Responsibility to enforce the code of conduct. +* Responsibility to triage static analysis issues in their code area. + See :ref:`static_analysis`. Contributors or Collaborators are promoted to the Maintainer role by adding the GitHub user name to one or more ``maintainers`` sections of the @@ -168,6 +170,26 @@ the latter is not possible. * Solicit approvals from maintainers of the subsystems affected * Responsibility to drive the :ref:`pr_technical_escalation` process +Static Analysis Audit Team +++++++++++++++++++++++++++ + +The Static Analysis Audit team works closely with the release engineering +team to ensure that static analysis defects opened during a release +cycle are properly addressed. The team has the following rights and +responsibilities: + +* Right to revert any triage in a static analysis tool (e.g: Coverity) + that does not follow the project expectations. +* Responsibility to inform code owners about improper classifications. +* Responsibility to alert TSC if any issues are not adequately addressed by the + responsible code owners. + +Joining the Static Analysis Audit team + +* Contributors highly involved in the project with some expertise + in static analysis. + + .. _release-engineering-team: Release Engineering Team diff --git a/doc/project/release_process.rst b/doc/project/release_process.rst index e1e07c417c8..7523cb951a3 100644 --- a/doc/project/release_process.rst +++ b/doc/project/release_process.rst @@ -94,8 +94,8 @@ At that point, the whole process starts over again. Release Quality Criteria ************************ -The current backlog of prioritized bugs shall be used as a quality metric to -gate the final release. The following counts shall be used: +The current backlog of prioritized bugs shall also be used as a quality metric +to gate the final release. The following counts shall be used: .. csv-table:: Bug Count Release Thresholds :header: "High", "Medium", "Low" @@ -109,6 +109,10 @@ gate the final release. The following counts shall be used: The "low" bug count target of <50 will be a phased approach starting with 150 for release 2.4.0, 100 for release 2.5.0, and 50 for release 2.6.0 +The final release must not contain any static analysis high-critical issues +that can potentially compromise the functionality, security, or reliability of +our software. High-critical issues represent vulnerabilities that, if left +unresolved, could have severe consequences. Release Milestones @@ -269,8 +273,11 @@ components provided by the project: - Compliance with published coding guidelines, style guides and naming conventions and documentation of deviations. -- Regular static analysis on the complete tree using available commercial and - open-source tools and documentation of deviations and false positives. +- Static analysis reports + + - Regular static analysis on the complete tree using available commercial and + open-source tools, and documentation of deviations and false positives. + - Documented components and APIS - Requirements Catalog - Verification Plans diff --git a/doc/releases/migration-guide-3.5.rst b/doc/releases/migration-guide-3.5.rst index cda3602f19f..86d0fa51fcb 100644 --- a/doc/releases/migration-guide-3.5.rst +++ b/doc/releases/migration-guide-3.5.rst @@ -73,7 +73,7 @@ C Library * Picolibc has four different printf/scanf variants supported in Zephyr, 'double', 'long long', 'integer', and 'minimal. 'double' offers a complete printf implementation with exact floating point in decimal and - hexidecimal formats, full integer support including long long, C99 + hexadecimal formats, full integer support including long long, C99 integer size specifiers (j, z, t) and POSIX positional arguments. 'long long' mode removes float support, 'integer' removes long long support while 'minimal' mode also removes support for format modifiers and diff --git a/doc/releases/migration-guide-3.6.rst b/doc/releases/migration-guide-3.6.rst index eeac0a89b75..ceb57a40edf 100644 --- a/doc/releases/migration-guide-3.6.rst +++ b/doc/releases/migration-guide-3.6.rst @@ -14,9 +14,43 @@ the :ref:`release notes`. Required changes **************** +Boards +====== + +* The deprecated Nordic SoC Kconfig option ``NRF_STORE_REBOOT_TYPE_GPREGRET`` has been removed, + applications that use this should switch to using the :ref:`boot_mode_api` instead. + +Build System +============ + +* The deprecated ``prj_.conf`` Kconfig file support has been removed, projects that use + this should switch to using board Kconfig fragments instead (``boards/.conf``). + +* Until now ``_POSIX_C_SOURCE``, ``_XOPEN_SOURCE``, and ``_XOPEN_SOURCE_EXTENDED`` were defined + globally when building for the native (``ARCH_POSIX``) targets, and ``_POSIX_C_SOURCE`` when + building with PicolibC. Since this release, these are set only for the files that need them. + If your library or application needed this, you may start getting an "implicit declaration" + warning for functions whose prototypes are only exposed if one of these is defined. + If so, you can fix it by defining the corresponding macro in your C source file before any + include, or by adding the equivalent of + ``target_compile_definitions(app PRIVATE _POSIX_C_SOURCE=200809L)`` to your application + or ``zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L)`` to your library. + +* Build type by setting ``CONF_FILE`` to ``prj_.conf`` is now deprecated, users should + instead use the new ``-DFILE_SUFFIX`` feature :ref:`application-file-suffixes`. + Kernel ====== +* The system heap size and its availability is now determined by a ``K_HEAP_MEM_POOL_SIZE`` + define instead of the :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE` Kconfig option. Subsystems + can specify their own custom system heap size requirements by specifying Kconfig options with + the prefix ``CONFIG_HEAP_MEM_POOL_ADD_SIZE_``. The old Kconfig option still exists, but will be + overridden if the custom requirements are larger. To force the old Kconfig option to be used, + even when its value is less than the indicated custom requirements, a new + :kconfig:option:`CONFIG_HEAP_MEM_POOL_IGNORE_MIN` option has been introduced (which defaults + being disabled). + C Library ========= @@ -35,6 +69,35 @@ enable all optional modules, and then run ``west update`` again. Device Drivers and Device Tree ============================== +* The :dtcompatible:`nxp,pcf8574` driver has been renamed to + :dtcompatible:`nxp,pcf857x`. (:github:`67054`) to support pcf8574 and pcf8575. + The Kconfig option has been renamed from :kconfig:option:`CONFIG_GPIO_PCF8574` to + :kconfig:option:`CONFIG_GPIO_PCF857X`. + The Device Tree can be configured as follows: + + .. code-block:: devicetree + + &i2c { + status = "okay"; + pcf8574: pcf857x@20 { + compatible = "nxp,pcf857x"; + status = "okay"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + }; + + pcf8575: pcf857x@21 { + compatible = "nxp,pcf857x"; + status = "okay"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + }; + }; + * The :dtcompatible:`st,lsm6dsv16x` sensor driver has been changed to support configuration of both int1 and int2 pins. The DT attribute ``irq-gpios`` has been removed and substituted by two new attributes, ``int1-gpios`` and ``int2-gpios``. @@ -53,8 +116,246 @@ Device Drivers and Device Tree }; }; +* The optional :c:func:`setup()` function in the Bluetooth HCI driver API (enabled through + :kconfig:option:`CONFIG_BT_HCI_SETUP`) has gained a function parameter of type + :c:struct:`bt_hci_setup_params`. By default, the struct is empty, but drivers can opt-in to + :kconfig:option:`CONFIG_BT_HCI_SET_PUBLIC_ADDR` if they support setting the controller's public + identity address, which will then be passed in the ``public_addr`` field. + (:github:`62994`) +* Various deprecated macros related to the deprecated devicetree label property + were removed. These are listed in the following table. The table also + provides replacements. + + However, if you are still using code like + ``device_get_binding(DT_LABEL(node_id))``, consider replacing it with + something like ``DEVICE_DT_GET(node_id)`` instead. The ``DEVICE_DT_GET()`` + macro avoids run-time string comparisons, and is also safer because it will + fail the build if the device does not exist. + + .. list-table:: + :header-rows: 1 + + * - Removed macro + - Replacement + + * - ``DT_GPIO_LABEL(node_id, gpio_pha)`` + - ``DT_PROP(DT_GPIO_CTLR(node_id, gpio_pha), label)`` + + * - ``DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, idx)`` + - ``DT_PROP(DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, idx), label)`` + + * - ``DT_INST_GPIO_LABEL(inst, gpio_pha)`` + - ``DT_PROP(DT_GPIO_CTLR(DT_DRV_INST(inst), gpio_pha), label)`` + + * - ``DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, idx)`` + - ``DT_PROP(DT_GPIO_CTLR_BY_IDX(DT_DRV_INST(inst), gpio_pha, idx), label)`` + + * - ``DT_SPI_DEV_CS_GPIOS_LABEL(spi_dev)`` + - ``DT_PROP(DT_SPI_DEV_CS_GPIOS_CTLR(spi_dev), label)`` + + * - ``DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)`` + - ``DT_PROP(DT_SPI_DEV_CS_GPIOS_CTLR(DT_DRV_INST(inst)), label)`` + + * - ``DT_LABEL(node_id)`` + - ``DT_PROP(node_id, label)`` + + * - ``DT_BUS_LABEL(node_id)`` + - ``DT_PROP(DT_BUS(node_id), label)`` + + * - ``DT_INST_LABEL(inst)`` + - ``DT_INST_PROP(inst, label)`` + + * - ``DT_INST_BUS_LABEL(inst)`` + - ``DT_PROP(DT_BUS(DT_DRV_INST(inst)), label)`` + +* The :dtcompatible:`st,stm32-lptim` lptim which is selected for counting ticks during + low power modes is identified by **stm32_lp_tick_source** in the device tree as follows. + The stm32_lptim_timer driver has been changed to support this. + + .. code-block:: devicetree + + stm32_lp_tick_source: &lptim1 { + status = "okay"; + }; + + +* The :dtcompatible:`st,stm32-ospi-nor` and :dtcompatible:`st,stm32-qspi-nor` give the nor flash + base address and size (in Bytes) with the **reg** property as follows. + The property is not used anymore. + + .. code-block:: devicetree + + mx25lm51245: ospi-nor-flash@70000000 { + compatible = "st,stm32-ospi-nor"; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits*/ + }; + +* The native Linux SocketCAN driver, which can now be used in both :ref:`native_posix` + and :ref:`native_sim` with or without an embedded C-library, has been renamed to + reflect this: + + * The devicetree compatible was renamed from ``zephyr,native-posix-linux-can`` to + :dtcompatible:`zephyr,native-linux-can`. + * The main Kconfig option was renamed from ``CONFIG_CAN_NATIVE_POSIX_LINUX`` to + :kconfig:option:`CONFIG_CAN_NATIVE_LINUX`. + +* Two new structures for holding common CAN controller driver configuration (``struct + can_driver_config``) and data (``struct can_driver_data``) fields were introduced. Out-of-tree CAN + controller drivers need to be updated to use these new, common configuration and data structures + along with their initializer macros. + +* The optional ``can_get_max_bitrate_t`` CAN controller driver callback was removed in favor of a + common accessor function. Out-of-tree CAN controller drivers need to be updated to no longer + supply this callback. + +* The CAN transceiver API function :c:func:`can_transceiver_enable` now takes a :c:type:`can_mode_t` + argument for propagating the CAN controller operational mode to the CAN transceiver. Out-of-tree + CAN controller and CAN transceiver drivers need to be updated to match this new API function + signature. + +* The ``CAN_FILTER_FDF`` flag for filtering classic CAN/CAN FD frames was removed since no known CAN + controllers implement support for this. Applications can still filter on classic CAN/CAN FD frames + in their receive callback functions as needed. + +* The ``CAN_FILTER_DATA`` and ``CAN_FILTER_RTR`` flags for filtering between Data and Remote + Transmission Request (RTR) frames were removed since not all CAN controllers implement support for + individual RX filtering based on the RTR bit. Applications can now use + :kconfig:option:`CONFIG_CAN_ACCEPT_RTR` to either accept incoming RTR frames matching CAN filters + or reject all incoming CAN RTR frames (the default). When :kconfig:option:`CONFIG_CAN_ACCEPT_RTR` + is enabled, applications can still filter between Data and RTR frames in their receive callback + functions as needed. + +* The io-channel cells of the following devicetree bindings were reduced from 2 (``positive`` and + ``negative``) to the common ``input``, making it possible to use the various ADC DT macros with TI + LMP90xxx ADC devices: + + * :dtcompatible:`ti,lmp90077` + * :dtcompatible:`ti,lmp90078` + * :dtcompatible:`ti,lmp90079` + * :dtcompatible:`ti,lmp90080` + * :dtcompatible:`ti,lmp90097` + * :dtcompatible:`ti,lmp90098` + * :dtcompatible:`ti,lmp90099` + * :dtcompatible:`ti,lmp90100` + +* The io-channel cells of the :dtcompatible:`microchip,mcp3204` and + :dtcompatible:`microchip,mcp3208` devicetree bindings were renamed from ``channel`` to the common + ``input``, making it possible to use the various ADC DT macros with Microchip MCP320x ADC devices. + +* ILI9XXX based displays now use the MIPI DBI driver class. These displays + must now be declared within a MIPI DBI driver wrapper device, which will + manage interfacing with the display. For an example, see below: + + .. code-block:: devicetree + + /* Legacy ILI9XXX display definition */ + &spi2 { + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + spi-max-frequency = <32000000>; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + cmd-data-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; + + /* New display definition with MIPI DBI device */ + + mipi_dbi { + compatible = "zephyr,mipi-dbi-spi"; + reset-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + dc-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + spi-dev = <&spi2>; + #address-cells = <1>; + #size-cells = <0>; + + ili9340: ili9340@0 { + compatible = "ilitek,ili9340"; + reg = <0>; + mipi-max-frequency = <32000000>; + rotation = <270>; + width = <320>; + height = <240>; + }; + }; + +* The :dtcompatible:`st,stm32h7-fdcan` CAN controller driver now supports configuring the + domain/kernel clock via devicetree. Previously, the driver only supported using the PLL1_Q clock + for kernel clock, but now it defaults to the HSE clock, which is the chip default. Boards that + use the PLL1_Q clock for FDCAN will need to override the ``clocks`` property as follows: + + .. code-block:: devicetree + + &fdcan1 { + clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>, + <&rcc STM32_SRC_PLL1_Q FDCAN_SEL(1)>; + }; + +* Runtime configuration is now disabled by default for Nordic UART drivers. The motivation for the + change is that this feature is rarely used and disabling it significantly reduces the memory + footprint. + +* For platforms that enabled :kconfig:option:`CONFIG_MULTI_LEVEL_INTERRUPTS`, the ``IRQ`` variant + of the Devicetree macros now return the as-seen value in the devicetree instead of the Zephyr + multilevel-encoded IRQ number. To get the IRQ number in Zephyr multilevel-encoded format, use + ``IRQN`` variant instead. For example, consider the following devicetree: + + .. code-block:: devicetree + + plic: interrupt-controller@c000000 { + riscv,max-priority = <7>; + riscv,ndev = <1024>; + reg = <0x0c000000 0x04000000>; + interrupts-extended = <&hlic0 11>; + interrupt-controller; + compatible = "sifive,plic-1.0.0"; + #address-cells = <0x0>; + #interrupt-cells = <0x2>; + }; + + uart0: uart@10000000 { + interrupts = <10 1>; + interrupt-parent = <&plic>; + clock-frequency = <0x384000>; + reg = <0x10000000 0x100>; + compatible = "ns16550"; + reg-shift = <0>; + }; + + ``plic`` is a second level interrupt aggregator and ``uart0`` is a child of ``plic``. + ``DT_IRQ_BY_IDX(DT_NODELABEL(uart0), 0, irq)`` will return ``10`` + (as-seen value in the devicetree), while ``DT_IRQN_BY_IDX(DT_NODELABEL(uart0), 0)`` will return + ``(((10 + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) | 11)``. + + Drivers and applications that are supposed to work in multilevel-interrupt configurations should + be updated to use the ``IRQN`` variant, i.e.: + + * ``DT_IRQ(node_id, irq)`` -> ``DT_IRQN(node_id)`` + * ``DT_IRQ_BY_IDX(node_id, idx, irq)`` -> ``DT_IRQN_BY_IDX(node_id, idx)`` + * ``DT_IRQ_BY_NAME(node_id, name, irq)`` -> ``DT_IRQN_BY_NAME(node_id, name)`` + * ``DT_INST_IRQ(inst, irq)`` -> ``DT_INST_IRQN(inst)`` + * ``DT_INST_IRQ_BY_IDX(inst, idx, irq)`` -> ``DT_INST_IRQN_BY_IDX(inst, idx)`` + * ``DT_INST_IRQ_BY_NAME(inst, name, irq)`` -> ``DT_INST_IRQN_BY_NAME(inst, name)`` + +* Several Renesas RA series drivers Kconfig options have been renamed: + + * ``CONFIG_CLOCK_CONTROL_RA`` -> :kconfig:option:`CONFIG_CLOCK_CONTROL_RENESAS_RA` + * ``CONFIG_GPIO_RA`` -> :kconfig:option:`CONFIG_GPIO_RENESAS_RA` + * ``CONFIG_PINCTRL_RA`` -> :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` + * ``CONFIG_UART_RA`` -> :kconfig:option:`CONFIG_UART_RENESAS_RA` + +* The function signature of the ``isr_t`` callback function passed to the ``shared_irq`` + interrupt controller driver API via :c:func:`shared_irq_isr_register()` has changed. + The callback now takes an additional `irq_number` parameter. Out-of-tree users of + this API will need to be updated. + + (:github:`66427`) + Power Management ================ @@ -93,6 +394,10 @@ Shell * :kconfig:option:`CONFIG_W1_SHELL` * :kconfig:option:`CONFIG_WDT_SHELL` +* The ``SHELL_UART_DEFINE`` macro now only requires a ``_name`` argument. In the meantime, the + macro accepts additional arguments (ring buffer TX & RX size arguments) for compatibility with + previous Zephyr version, but they are ignored, and will be removed in future release. + Bootloader ========== @@ -103,6 +408,9 @@ Bootloader Bluetooth ========= +* ATT now has its own TX buffer pool. + If extra ATT buffers were configured using :kconfig:option:`CONFIG_BT_L2CAP_TX_BUF_COUNT`, + they now instead should be configured through :kconfig:option:`CONFIG_BT_ATT_TX_COUNT`. * The HCI implementation for both the Host and the Controller sides has been renamed for the IPC transport. The ``CONFIG_BT_RPMSG`` Kconfig option is now :kconfig:option:`CONFIG_BT_HCI_IPC`, and the ``zephyr,bt-hci-rpmsg-ipc`` @@ -118,6 +426,13 @@ Bluetooth Any pointer to a UUID must be prefixed with `const`, otherwise there will be a compilation warning. For example change ``struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)`` to ``const struct bt_uuid *uuid = BT_UUID_DECLARE_16(xx)``. (:github:`66136`) +* The :c:func:`bt_l2cap_chan_send` API no longer allocates buffers from the same pool as its `buf` + parameter when segmenting SDUs into PDUs. In order to reproduce the previous behavior, the + application should register the `alloc_seg` channel callback and allocate from the same pool as + `buf`. +* The :c:func:`bt_l2cap_chan_send` API now requires the application to reserve + enough bytes for the L2CAP headers. Call ``net_buf_reserve(buf, + BT_L2CAP_SDU_CHAN_SEND_RESERVE);`` at buffer allocation time to do so. * Mesh @@ -131,6 +446,25 @@ Bluetooth * Deprecated :kconfig:option:`CONFIG_BT_MESH_PROV_DEVICE`. This option is replaced by new option :kconfig:option:`CONFIG_BT_MESH_PROVISIONEE` to be aligned with Mesh Protocol Specification v1.1, section 5.4. (:github:`64252`) + * Removed the ``CONFIG_BT_MESH_V1d1`` Kconfig option. + * Removed the ``CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT``, + ``CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST``, + ``CONFIG_BT_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP``, ``CONFIG_BT_MESH_SEG_ACK_BASE_TIMEOUT``, + ``CONFIG_BT_MESH_SEG_ACK_PER_HOP_TIMEOUT``, ``BT_MESH_SEG_ACK_PER_SEGMENT_TIMEOUT`` + Kconfig options. They are superseded by the + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_SEG_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_WITHOUT_PROG_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_UNICAST_RETRANS_INT_INC`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_COUNT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_TX_MULTICAST_RETRANS_INT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_SEG_THRESHOLD`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_DELAY_INC`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_SEG_INT_STEP`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_DISCARD_TIMEOUT`, + :kconfig:option:`CONFIG_BT_MESH_SAR_RX_ACK_RETRANS_COUNT` Kconfig options. + LoRaWAN ======= @@ -176,6 +510,41 @@ Networking The IPv6 hop limit value is also changed so that unicast and multicast packets can have a different one. (:github:`65886`) +* The Ethernet phy APIs defined in ```` are removed from syscall list. + The APIs were marked as callable from usermode but in practice this does not work as the device + cannot be accessed from usermode thread. This means that the API calls will need to made + from supervisor mode thread. + +* The zperf ratio between mbps and kbps, kbps and bps is changed to 1000, instead of 1024, + to align with iperf ratios. + +zcbor +===== + +* If you have zcbor-generated code that relies on the zcbor libraries through Zephyr, you must + regenerate the files using zcbor 0.8.1. Note that the names of generated types and members has + been overhauled, so the code using the generated code must likely be changed. + For example: + + * Leading single underscores and all double underscores are largely gone, + * Names sometimes gain suffixes like ``_m`` or ``_l`` for disambiguation. + * All enum (choice) names have now gained a ``_c`` suffix, so the enum name no longer matches + the corresponding member name exactly (because this broke C++ namespace rules). + +* The function :c:func:`zcbor_new_state`, :c:func:`zcbor_new_decode_state` and the macro + :c:macro:`ZCBOR_STATE_D` have gained new parameters related to decoding of unordered maps. + Unless you are using that new functionality, these can all be set to NULL or 0. + +* The functions :c:func:`zcbor_bstr_put_term` and :c:func:`zcbor_tstr_put_term` have gained a new + parameter ``maxlen``, referring to the maximum length of the parameter ``str``. + This parameter is passed directly to :c:func:`strnlen` under the hood. + +* The function :c:func:`zcbor_tag_encode` has been renamed to :c:func:`zcbor_tag_put`. + +* Printing has been changed significantly, e.g. :c:func:`zcbor_print` is now called + :c:func:`zcbor_log`, and :c:func:`zcbor_trace` with no parameters is gone, and in its place are + :c:func:`zcbor_trace_file` and :c:func:`zcbor_trace`, both of which take a ``state`` parameter. + Other Subsystems ================ @@ -188,9 +557,24 @@ Other Subsystems respective ``reset-gpios``. This has been fixed so those signals now have to be flagged as :c:macro:`GPIO_ACTIVE_LOW` in the devicetree. (:github:`64800`) +* The :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` + and :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` + zbus options are renamed. Instead, the new :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` + and :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` options should be used. + +Xtensa +====== + +* :kconfig:option:`CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC` no longer has a default in + the architecture layer. Instead, SoCs or boards will need to define it. + Recommended Changes ******************* * New macros available for ST sensor DT properties setting. These macros have a self-explanatory name that helps in recognizing what the property setting means (e.g. LSM6DSV16X_DT_ODR_AT_60Hz). (:github:`65410`) + +* Users of :ref:`native_posix` are recommended to migrate to + :ref:`native_sim`. :ref:`native_sim` supports all its use cases, + and should be a drop-in replacement for most. diff --git a/doc/releases/release-notes-2.2.rst b/doc/releases/release-notes-2.2.rst index 097d0674999..3a9922f4f00 100644 --- a/doc/releases/release-notes-2.2.rst +++ b/doc/releases/release-notes-2.2.rst @@ -197,7 +197,7 @@ Kernel * Propagate a distinct error code if a workqueue item is submitted that has already been completed * Disable preemption when handing fatal errors -* Fix an issue with the sytsem call stack frame if the system call is +* Fix an issue with the system call stack frame if the system call is preempted and then later tries to Z_OOPS() * add k_thread_stack_space_get() system call for analyzing thread stack space. Older methods which had problems in some cases or on some @@ -636,7 +636,7 @@ Bluetooth address resolution support * Added dynamic TX power control, including a set of vendor-specific commands to read and write the TX power - * Added a Kconfig option, BT_CTLR_PARAM_CHECK, to enable addtional parameter + * Added a Kconfig option, BT_CTLR_PARAM_CHECK, to enable additional parameter checking * Added basic support for SMI (Stable Modulation Index) * Ticker: Implemented dynamic rescheduling diff --git a/doc/releases/release-notes-2.4.rst b/doc/releases/release-notes-2.4.rst index b2b22f8fae0..ca5f82561f6 100644 --- a/doc/releases/release-notes-2.4.rst +++ b/doc/releases/release-notes-2.4.rst @@ -73,7 +73,7 @@ API Changes * ```` has seen its callback normalized. It had its signature changed to add a struct device pointer as first parameter. Such callback - signature has been generalized throuh the addition of dma_callback_t. + signature has been generalized through the addition of dma_callback_t. 'callback_arg' argument has been renamed to 'user_data. All user code have been modified accordingly. @@ -98,7 +98,7 @@ API Changes * All device instances got a const qualifier. So this applies to all APIs manipulating ``struct device *`` (ADC, GPIO, I2C, ...). In order to avoid const qualifier loss on ISRs, all ISRs now take a ``const *void`` as a - paremeter as well. + parameter as well. * The ``_gatt_`` and ``_GATT_`` infixes have been removed for the HRS, DIS and BAS APIs and the Kconfig options. @@ -400,7 +400,7 @@ Drivers and Sensors * DMA - * STM32: Number of changes including k_malloc removal, driver piority init + * STM32: Number of changes including k_malloc removal, driver priority init increase, get_status API addition and various cleanups. * Added MCUX EDMA driver for i.MX RT and Kinetis K6x SoCs. * Added MCUX LPC driver for LPC and i.MX RT6xx SoCs. @@ -634,7 +634,7 @@ Networking * Added support for IPv6 multicast packet routing. * Added support to SOCK_DGRAM type sockets for AF_PACKET family. * Added support for using TLS sockets when using socket offloading. -* Added additonal checks in IPv6 to ensure that multicasts are only passed to the +* Added additional checks in IPv6 to ensure that multicasts are only passed to the upper layer if the originating interface actually joined the destination multicast group. * Allow user to specify TCP port number in HTTP request. diff --git a/doc/releases/release-notes-2.5.rst b/doc/releases/release-notes-2.5.rst index af2f414d7bb..5f4e7feaa11 100644 --- a/doc/releases/release-notes-2.5.rst +++ b/doc/releases/release-notes-2.5.rst @@ -453,7 +453,7 @@ Drivers and Sensors * I2C - * Added driver support for lmx6x, it8xxx2, and npcx7 plaforms. + * Added driver support for lmx6x, it8xxx2, and npcx7 platforms. * Added Atmel SAM4L TWIM driver. * Added I2C slave support in the microchip i2c driver. * Reversed 2.4 decision to downgrade I2C eeprom slave driver to a @@ -900,7 +900,7 @@ MCUBoot * Renamed single-image mode to single-slot mode, see ``CONFIG_SINGLE_APPLICATION_SLOT``. * Added patch for turning off cache for Cortex M7 before chain-loading. - * Fixed boostrapping in swap-move mode. + * Fixed bootstrapping in swap-move mode. * Fixed issue causing that interrupted swap-move operation might brick device if the primary image was padded. * Fixed issue causing that HW stack protection catches the chain-loaded diff --git a/doc/releases/release-notes-2.6.rst b/doc/releases/release-notes-2.6.rst index c4ad995f281..53864fa2508 100644 --- a/doc/releases/release-notes-2.6.rst +++ b/doc/releases/release-notes-2.6.rst @@ -259,7 +259,7 @@ Bluetooth * Added the ability to send HCI monitor traces over RTT. * Refactored the Bluetooth buffer configuration for simplicity. See the commit message of 6483e12a8ac4f495b28279a6b84014f633b0d374 for more info. - Note however that the aformentioned commit message has two typos; + Note however that the aforementioned commit message has two typos; * ``BT_CTLR_TX_BUFFER`` should be ``BT_CTLR_TX_BUFFERS`` * ``BT_CTLR_TX_BUFFERS_SIZE`` should be ``BT_CTLR_TX_BUFFER_SIZE`` @@ -611,7 +611,7 @@ Drivers and Sensors * Sensor * Added support for STM32 internal (CPU) temperature sensor. - * Refactored mulitple ST sensor drivers to use gpio_dt_spec macros and common + * Refactored multiple ST sensor drivers to use gpio_dt_spec macros and common stmemc routines, support multiple instances, and configure ODR/range properties in device tree. * Added SBS 1.1 compliant fuel gauge driver. @@ -1038,7 +1038,7 @@ Tests and Samples filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") * Add a feature which handles pytest script in twister and provide an example. -* Provide test excution time per ztest testcase. +* Provide test execution time per ztest testcase. * Added and refined some testcases, most of them are negative testcases, to improve the test code coverage: diff --git a/doc/releases/release-notes-2.7.rst b/doc/releases/release-notes-2.7.rst index c7e80d3d83f..91f6393197a 100644 --- a/doc/releases/release-notes-2.7.rst +++ b/doc/releases/release-notes-2.7.rst @@ -730,7 +730,7 @@ USB * Added new header file where all defines and structures from Chapter 9 (USB Device Framework) should be included. -* Revised configuraiton of USB device support. +* Revised configuration of USB device support. Removed Kconfig option ``CONFIG_USB`` and introduced Kconfig option ``CONFIG_USB_DEVICE_DRIVER`` to enable USB device controller drivers, which is selected when option ``CONFIG_USB_DEVICE_STACK`` is enabled. diff --git a/doc/releases/release-notes-3.0.rst b/doc/releases/release-notes-3.0.rst index 42280613749..a03beb7d0d5 100644 --- a/doc/releases/release-notes-3.0.rst +++ b/doc/releases/release-notes-3.0.rst @@ -380,7 +380,7 @@ Bluetooth * Updated the supported Bluetooth HCI version to 5.3 * Added support for Periodic Advertiser List * Added support for Periodic Advertising Synchronization Receive Enable - * Added support for filter access list filtering for exended scanning + * Added support for filter access list filtering for extended scanning * Added support for Advertising Extensions dynamic TX power control * Added handling of direct address type in extended adv reports * Implemented auxiliary PDU device address matching @@ -660,7 +660,7 @@ Networking * Added support for multiple LwM2M Firmware Update object instances. * Improved error handling in LwM2M content writers. * Added unit tests for LwM2M content writers. - * Implmented LwM2M Security, Server, Connection Monitor objects in version 1.1. + * Implemented LwM2M Security, Server, Connection Monitor objects in version 1.1. * Multiple minor bugfixes in the LwM2M stack. * Added support for the following objects: @@ -678,7 +678,7 @@ Networking unaliged access warnings from gcc. * Added automatic loopback addresses registration to loopback interface. * Fixed source address selection for ARP. - * Allow to implment a custom IEEE802154 L2 on top of existing drivers. + * Allow to implement a custom IEEE802154 L2 on top of existing drivers. * Introduced a network packet filtering framework. * MQTT: diff --git a/doc/releases/release-notes-3.1.rst b/doc/releases/release-notes-3.1.rst index 517ef1c6e3c..fe631d3c766 100644 --- a/doc/releases/release-notes-3.1.rst +++ b/doc/releases/release-notes-3.1.rst @@ -620,7 +620,7 @@ Networking * Added a :kconfig:option:`CONFIG_NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE` option, which allows to forward frames with unrecognised EtherType to the - netowrk stack. + network stack. * HTTP: @@ -1721,7 +1721,7 @@ Addressed issues * :github:`43344` - intel_adsp_cavs25: samples/subsys/logging/syst is failing with a timeout when the sample is enabled to run on intel_adsp_cavs25 * :github:`43333` - RFC: Bring zcbor as CBOR decoder/encoder in replacement for TinyCBOR * :github:`43326` - Unstable SD Card performance on Teensy 4.1 -* :github:`43319` - Hardware reset cause api sets reset pin bit everytime the api is called +* :github:`43319` - Hardware reset cause api sets reset pin bit every time the api is called * :github:`43316` - stm32wl55 cannot enable PLL source as MSI * :github:`43314` - LE Audio: BAP ``sent`` callback missing * :github:`43310` - disco_l475_iot1: BLE not working diff --git a/doc/releases/release-notes-3.2.rst b/doc/releases/release-notes-3.2.rst index d902ac4481b..11e923b0f8e 100644 --- a/doc/releases/release-notes-3.2.rst +++ b/doc/releases/release-notes-3.2.rst @@ -165,7 +165,7 @@ Deprecated in this release * Flash Map API macros :c:macro:`FLASH_MAP_`, which have been using DTS node label property to reference partitions, have been deprecated and replaced with - :c:macro:`FIXED_PARTITION_` whch use DTS node label instead. + :c:macro:`FIXED_PARTITION_` which use DTS node label instead. Replacement list: .. table:: @@ -270,7 +270,7 @@ Architectures * Reduced callee-saved registers for RV32E. * Introduced Zicsr, Zifencei and BitManip as separate extensions. * Introduced :kconfig:option:`CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL` for - plaforms that require every ``mret`` to be balanced by ``ecall``. + platforms that require every ``mret`` to be balanced by ``ecall``. * IRQ vector table is now used for vectored mode. * Disabled :kconfig:option:`CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE` for CLIC. * ``STRINGIFY`` macro is now used for CSR helpers. @@ -511,7 +511,7 @@ Drivers and Sensors * The STM32 CAN-FD CAN driver clock configuration has been moved from Kconfig to :ref:`devicetree `. See the :dtcompatible:`st,stm32-fdcan` devicetree binding for more information. * The filter handling of STM32 bxCAN driver has been simplified and made more reliable. - * The STM32 bxCAN driver now supports dual intances. + * The STM32 bxCAN driver now supports dual instances. * The CAN loopback driver now supports CAN-FD. * The CAN shell module has been rewritten to properly support the additions and changes to the CAN controller API. @@ -543,7 +543,7 @@ Drivers and Sensors * DFU - * Fixed fetch of the flash write block size from incorect device by + * Fixed fetch of the flash write block size from incorrect device by ``flash_img``. * Fixed possible build failure in the image manager for mcuboot on redefinitions of :c:macro:`BOOT_MAX_ALIGN` and :c:macro:`BOOT_MAGIC_SZ`. @@ -757,7 +757,7 @@ Drivers and Sensors for various drivers. * Various fixes on ``lpuart``. * Added a workaround on bytes dropping on ``nrfx_uarte``. - * Fixed compilation error on ``uart_pl011`` when interrupt is diabled. + * Fixed compilation error on ``uart_pl011`` when interrupt is disabled. * Added power management support on ``stm32``. * ``xlnx_ps`` has moved to using ``DEVICE_MMIO`` API. * ``gd32`` now supports using reset API to reset hardware and clock @@ -1166,7 +1166,7 @@ Devicetree * :dtcompatible:`zephyr,coredump` * :dtcompatible:`zephyr,ieee802154-uart-pipe` * :dtcompatible:`zephyr,native-posix-counter` - * :dtcompatible:`zephyr,native-posix-linux-can` + * ``zephyr,native-posix-linux-can`` * :dtcompatible:`zephyr,sdl-kscan` * :dtcompatible:`zephyr,sdmmc-disk` * :dtcompatible:`zephyr,w1-serial` @@ -1398,7 +1398,7 @@ Libraries / Subsystems response is now only used for mcumgr errors, shell command execution result codes are instead returned in the ``ret`` variable instead, see :ref:`mcumgr_smp_group_9` for updated - information. Legacy bahaviour can be restored by enabling + information. Legacy behaviour can be restored by enabling :kconfig:option:`CONFIG_MCUMGR_CMD_SHELL_MGMT_LEGACY_RC_RETURN_CODE`. * MCUMGR img_mgmt erase command now accepts an optional slot number to select which image will be erased, using the ``slot`` input diff --git a/doc/releases/release-notes-3.3.rst b/doc/releases/release-notes-3.3.rst index 312ad1e4754..b1590a5ee1d 100644 --- a/doc/releases/release-notes-3.3.rst +++ b/doc/releases/release-notes-3.3.rst @@ -742,7 +742,7 @@ Drivers and Sensors * STM32 OSPI: Now supports DMA transfer on STM32U5. - * STM32: Flash driver was revisited to simplify re-use of driver for new series, taking + * STM32: Flash driver was revisited to simplify reuse of driver for new series, taking advantage of device tree compatibles. * FPGA diff --git a/doc/releases/release-notes-3.4.rst b/doc/releases/release-notes-3.4.rst index 092fa251c6f..3b96c3e8bb8 100644 --- a/doc/releases/release-notes-3.4.rst +++ b/doc/releases/release-notes-3.4.rst @@ -776,7 +776,7 @@ Drivers and Sensors channel(s) to link a software channel configuration to. * MCUX LPADC driver ``voltage-ref`` and ``power-level`` devicetree properties were shifted to match the hardware as described in reference manual instead - of matching the NXP SDK enum identifers. + of matching the NXP SDK enum identifiers. * Added support for STM32C0 and STM32H5. * Added DMA support for STM32H7. * STM32: Resolutions are now listed in the device tree for each ADC instance diff --git a/doc/releases/release-notes-3.5.rst b/doc/releases/release-notes-3.5.rst index d7993bd7804..0ae90dd5c3e 100644 --- a/doc/releases/release-notes-3.5.rst +++ b/doc/releases/release-notes-3.5.rst @@ -260,7 +260,7 @@ Bluetooth * Fixed BIS payload sliding window overrun check * Fixed CIS Central FT calculation * Fixed CIS Central error handling - * Fixed CIS assymmetric PHY usage + * Fixed CIS asymmetric PHY usage * Fixed CIS encryption when DF support enabled * Fixed ISO-AL for quality tests and time stamps * Fixed PHY value in HCI LE CIS Established Event @@ -840,7 +840,7 @@ Networking When :kconfig:option:`CONFIG_LWM2M_COAP_BLOCK_TRANSFER` is enabled, any content that is larger than :kconfig:option:`CONFIG_LWM2M_COAP_MAX_MSG_SIZE` is split into a block-wise transfer. * Block-wise transfers don't require tokens to match anymore as this was not in line - with CoAP specification (CoAP doesn't require tokens re-use). + with CoAP specification (CoAP doesn't require tokens reuse). * Various fixes to bootstrap. Now client ensures that Bootstrap-Finish command is sent, before closing the DTLS pipe. Also allows Bootstrap server to close the DTLS pipe. Added timeout when waiting for bootstrap commands. @@ -2115,7 +2115,7 @@ Libraries / Subsystems * Added support of mounting littlefs on the block device from the shell/fs. * Added alignment parameter to FS_LITTLEFS_DECLARE_CUSTOM_CONFIG macro, it can speed up read/write operation for SDMMC devices in case when we align buffers on CONFIG_SDHC_BUFFER_ALIGNMENT, - because we can avoid extra copy of data from card bffer to read/prog buffer. + because we can avoid extra copy of data from card buffer to read/prog buffer. * Random diff --git a/doc/releases/release-notes-3.6.rst b/doc/releases/release-notes-3.6.rst index f4d813432b1..2bba24bdbed 100644 --- a/doc/releases/release-notes-3.6.rst +++ b/doc/releases/release-notes-3.6.rst @@ -37,6 +37,8 @@ Architectures * Xtensa + * Removed the unused Kconfig option ``CONFIG_XTENSA_NO_IPC``. + * x86 * POSIX @@ -50,12 +52,17 @@ Bluetooth * Host + * Added ``recycled()`` callback to :c:struct:`bt_conn_cb`, which notifies listeners when a + connection object has been freed, so it can be utilized for different purposes. No guarantees + are made to what listener will be granted the object, as only the first claim is served. + * Mesh * Added the delayable messages functionality to apply random delays for the transmitted responses on the Access layer. The functionality is enabled by the :kconfig:option:`CONFIG_BT_MESH_ACCESS_DELAYABLE_MSG` Kconfig option. + * The Bluetooth Mesh Protocol 1.1 is now supported by default. * Controller @@ -64,14 +71,21 @@ Boards & SoC Support * Added support for these SoC series: + * Added support for Renesas R-Car Gen4 series + * Removed support for these SoC series: * Made these changes in other SoC series: + * Nordic SoCs now imply :kconfig:option:`CONFIG_XIP` instead of selecting it, this allows for + creating RAM-based applications by disabling it. + * Added support for these ARC boards: * Added support for these ARM boards: + * Added support for Renesas R-Car Spider board CR52: ``rcar_spider_cr52`` + * Added support for these ARM64 boards: * Added support for these RISC-V boards: @@ -94,7 +108,27 @@ Boards & SoC Support * Made these changes for Xtensa boards: -* Made these changes for POSIX boards: +* Made these changes for native/POSIX boards: + + * The :ref:`simulated nrf5340 targets` now include the IPC and MUTEX peripherals, + and support OpenAMP to communicate between the cores. + It is now possible to run the BLE controller or 802.15.4 driver in the net core, and application + and BT host in the app core. + + * The nrf*_bsim simulated targets now include models of the UART peripheral. It is now possible + to connect a :ref:`nrf52_bsim` UART to another, or a UART in loopback, utilizing + both the new and legacy nRFx UART drivers, in any mode. + + * For the native simulator based targets it is now possible to set via Kconfig command line + options which will be handled by the executable as if they were provided from the invoking + shell. + + * For all native boards boards, the native logger backend will also be used even if the UART is + enabled. + + * Several bugfixes and other minor additions to the nRF5x HW models. + + * Multiple documentation updates and fixes for all native boards. * Removed support for these ARC boards: @@ -115,7 +149,41 @@ Boards & SoC Support Build system and infrastructure ******************************* -- Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. +* Dropped the ``COMPAT_INCLUDES`` option, it was unused since 3.0. + +* Fixed an issue whereby board revision ``0`` did not include overlay files for that revision. + +* Added ``PRE_IMAGE_CMAKE`` and ``POST_IMAGE_CMAKE`` hooks to sysbuild modules, which allows for + modules to run code after and before each image's cmake invocation. + +* Added :kconfig:option:`CONFIG_ROM_END_OFFSET` option which allows reducing the size of an image, + this is intended for use with firmware signing scripts which add additional data to the end of + images outside of the build itself. + +* Added MCUboot image size reduction to sysbuild images which include MCUboot which prevents + issues with building firmware images that are too large for MCUboot to swap. + +* Deprecated :kconfig:option:`CONFIG_BOOTLOADER_SRAM_SIZE`, users of this should transition to + having RAM set up properly in their board devicetree files. + +* Fixed an issue whereby shields were processed in order of the root they resided in rather than + the order they were supplied to cmake in. + +* Fixed an issue whereby using some shields with sysbuild would cause a cmake Kconfig error. + +* Fixed an issue where the macros ``_POSIX_C_SOURCE`` and ``_XOPEN_SOURCE`` would be defined + globally when building with Picolibc or for the native (``ARCH_POSIX``) targets. + After this change users may need to define them for their own applications or libraries if they + require them. + +* Added support for sysbuild setting a signing script (``SIGNING_SCRIPT``), see + :ref:`west-extending-signing` for details. + +* Added support for ``FILE_SUFFIX`` in the build system which allows for adding suffixes to + application Kconfig fragment file names and devicetree overlay file names, see + :ref:`application-file-suffixes` and :ref:`sysbuild_file_suffixes` for details. + +* Deprecated ``CONF_FILE`` ``prj_.conf`` build type. Drivers and Sensors ******************* @@ -124,10 +192,25 @@ Drivers and Sensors * CAN + * Added system call :c:func:`can_get_mode()` for getting the current operation mode of a CAN + controller. + + * Add system call :c:func:`can_get_transceiver()` for getting the CAN transceiver associated with + a CAN controller. + + * The "native linux" driver now supports being built with embedded C libraries. + * Clock control + * Renesas R-Car clock control driver now supports Gen4 SoCs + * Renamed ``CONFIG_CLOCK_CONTROL_RA`` to :kconfig:option:`CONFIG_CLOCK_CONTROL_RENESAS_RA` + * Counter + * The nRFx counter driver now works with simulated nrf*_bsim targets. + + * counter_native_posix driver: Added support for top value configuration, and a bugfix. + * DAC * Disk @@ -140,18 +223,33 @@ Drivers and Sensors * Entropy + * The "native_posix" entropy driver now accepts a new command line option ``seed-random``. + When used, the random generator will be seeded from ``/dev/urandom`` + * Ethernet + * The "native_posix" ethernet driver now supports being built with embedded C libraries. + * Flash + * ``spi_nor`` driver now sleeps between polls in ``spi_nor_wait_until_ready``. If this is not + desired (For example due to ROM constraints in a bootloader), + :kconfig:option:`CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY` can be disabled. + * GPIO + * Renesas R-Car GPIO driver now supports Gen4 SoCs + * Renamed ``CONFIG_GPIO_RA`` to :kconfig:option:`CONFIG_GPIO_RENESAS_RA` + * I2C * I2S * I3C + * The Legacy Virtual Register defines have been renamed from ``I3C_DCR_I2C_*`` + to ``I3C_LVR_I2C_*``. + * IEEE 802.15.4 * Removed :kconfig:option:`CONFIG_IEEE802154_SELECTIVE_TXPOWER` Kconfig option. @@ -166,6 +264,9 @@ Drivers and Sensors * Pin control + * Renesas R-Car pinctrl driver now supports Gen4 SoCs + * Renamed ``CONFIG_PINCTRL_RA`` to :kconfig:option:`CONFIG_PINCTRL_RENESAS_RA` + * PWM * Regulators @@ -174,6 +275,10 @@ Drivers and Sensors * Retained memory + * Retained memory driver backend for registers has been added. + + * Retained memory API status changed from experimental to unstable. + * RTC * SDHC @@ -182,6 +287,8 @@ Drivers and Sensors * Serial + * Renamed ``CONFIG_UART_RA`` to :kconfig:option:`CONFIG_UART_RENESAS_RA` + * SPI * Timer @@ -195,6 +302,8 @@ Networking * CoAP: + * Emit observer/service network events using the Network Event subsystem. + * Added new API functions: * :c:func:`coap_get_transmission_parameters` @@ -216,6 +325,16 @@ Networking * Misc: + * It is now possible to have separate IPv4 TTL value and IPv6 hop limit value for + unicast and multicast packets. This can be controlled in each socket via + :c:func:`setsockopt` API. + + * Added support for compile time network event handlers using the macro + :c:macro:`NET_MGMT_REGISTER_EVENT_HANDLER`. + + * The :kconfig:option:`CONFIG_NET_MGMT_EVENT_WORKER` choice is added to + allow emitting network events using the system work queue or synchronously. + * MQTT-SN: * OpenThread: @@ -224,6 +343,9 @@ Networking * Sockets: + * Added support for IPv4 multicast ``IP_ADD_MEMBERSHIP`` and ``IP_DROP_MEMBERSHIP`` socket options. + * Added support for IPv6 multicast ``IPV6_ADD_MEMBERSHIP`` and ``IPV6_DROP_MEMBERSHIP`` socket options. + * TCP: * TFTP: @@ -262,6 +384,15 @@ Libraries / Subsystems * Implemented datetime functionality in MCUmgr OS management group, this makes use of the RTC driver API. + * Fixed an issue in MCUmgr console UART input whereby the FIFO would be read outside of an ISR, + which is not supported in the next USB stack. + + * Fixed an issue whereby the ``mcuboot erase`` DFU shell command could be used to erase the + MCUboot or currently running application slot. + + * Fixed an issue whereby messages that were too large to be sent over the UDP transport would + wrongly return :c:enum:`MGMT_ERR_EINVAL` instead of :c:enum:`MGMT_ERR_EMSGSIZE`. + * File systems * Modem modules @@ -272,6 +403,17 @@ Libraries / Subsystems * Retention + * Fixed issue whereby :kconfig:option:`CONFIG_RETENTION_BUFFER_SIZE` values over 256 would cause + an infinite loop due to use of 8-bit variables. + +* Storage + + * File systems: LittleFS module has been updated to version 2.8.1. + + * Following Flash Map API macros, marked in 3.2 as deprecated, have been removed: + ``FLASH_AREA_ID``, ``FLASH_AREA_OFFSET``, ``FLASH_AREA_SIZE``, + ``FLASH_AREA_LABEL_EXISTS`` and ``FLASH_AREA_DEVICE``. + * Binary descriptors * POSIX API @@ -284,6 +426,11 @@ Libraries / Subsystems * ZBus + * Renamed :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` and + :kconfig:option:`ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` + with :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` and + :kconfig:option:`ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` + HALs **** @@ -293,6 +440,21 @@ MCUboot Nanopb ****** +zcbor +***** + +zcbor has been updated from 0.7.0 to 0.8.1. +Full release notes can be found at: +https://github.com/zephyrproject-rtos/zcbor/blob/0.8.0/RELEASE_NOTES.md and +https://github.com/zephyrproject-rtos/zcbor/blob/0.8.1/RELEASE_NOTES.md + +Highlights: + +* Add support for unordered maps +* Performance improvements +* Naming improvements for generated code +* Bugfixes + LVGL **** @@ -305,5 +467,19 @@ Documentation Tests and Samples ***************** +* :ref:`native_sim` has replaced :ref:`native_posix` as the default + test platform. + :ref:`native_posix` remains supported and used in testing but will be deprecated + in a future release. + +* Bluetooth split stacks tests, where the BT host and controller are run in separate MCUs, are + now run in CI based on the :ref:`nrf5340_bsim` targets. + Several other runtime AMP tests based on these targets have been added to CI, including tests + of OpenAMP, the mbox and IPC drivers/subsystem, and the logger multidomain functionality. + +* Runtime UART tests have been added to CI based on the :ref:`nrf52_bsim` target. + These include tests of the nRFx UART driver and networked BT stack tests with the host and + controller in separate devices communicating over the HCI UART driver. + * Fixed an issue in :zephyr:code-sample:`smp-svr` sample whereby if USB was already initialised, application would fail to boot properly. diff --git a/doc/requirements.txt b/doc/requirements.txt index 45bb461e518..e7747b5f13f 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -13,3 +13,6 @@ sphinx-togglebutton # YAML validation. Used by zephyr_module. PyYAML>=5.1 pykwalify + +# Used by pytest-twister-harness plugin +pytest diff --git a/doc/security/vulnerabilities.rst b/doc/security/vulnerabilities.rst index fde156983d3..a03b5202a02 100644 --- a/doc/security/vulnerabilities.rst +++ b/doc/security/vulnerabilities.rst @@ -1501,12 +1501,39 @@ This has been fixed in main for v3.4.0 CVE-2023-4424 ------------- -Under embargo until 2023/11/01 +bt: hci: DoS and possible RCE + +- `Zephyr project bug tracker GHSA-j4qm-xgpf-qjw3 + `_ + +This has been fixed in main for v3.5.0 + +- `PR 61651 fix for main + `_ + +- `PR 61696 fix for 3.4 + `_ + +- `PR 61695 fix for 3.3 + `_ + +- `PR 61694 fix for 2.7 + `_ + CVE-2023-5055 ------------- -Under embargo until 2023/11/01 +L2CAP: Possible Stack based buffer overflow in le_ecred_reconf_req() + +- `Zephyr project bug tracker GHSA-wr8r-7f8x-24jj + `_ + +This has been fixed in main for v3.5.0 + +- `PR 62381 fix for main + `_ + CVE-2023-5139 ------------- @@ -1569,3 +1596,19 @@ This has been fixed in main for v3.5.0 - `PR 63605 fix for main `_ + + +CVE-2023-5779 +------------- + +Under embargo until 2024-01-23 + +CVE-2023-6249 +------------- + +Under embargo until 2024-02-18 + +CVE-2023-6749 +------------- + +Under embargo until 2024-02-18 diff --git a/doc/services/binary_descriptors/index.rst b/doc/services/binary_descriptors/index.rst index ef44b8265af..9cd6f8fe2cc 100644 --- a/doc/services/binary_descriptors/index.rst +++ b/doc/services/binary_descriptors/index.rst @@ -5,7 +5,7 @@ Binary Descriptors Binary Descriptors are constant data objects storing information about the binary executable. Unlike "regular" constants, binary descriptors are linked to a known offset in the binary, making -them accesible to other programs, such as a different image running on the same device or a host tool. +them accessible to other programs, such as a different image running on the same device or a host tool. A few examples of constants that would make useful binary descriptors are: kernel version, app version, build time, compiler version, environment variables, compiling host name, etc. @@ -105,7 +105,7 @@ configs should be enabled: CONFIG_BINDESC_DEFINE_BUILD_TIME=y CONFIG_BINDESC_BUILD_DATE_TIME_STRING=y -To avoid collisions with user defined descriptors, the standard descriptors were alloted +To avoid collisions with user defined descriptors, the standard descriptors were allotted the range between ``0x800-0xfff``. This leaves ``0x000-0x7ff`` to users. For more information read the ``help`` sections of these Kconfig symbols. By convention, each Kconfig symbol corresponds to a binary descriptor whose diff --git a/doc/services/console.rst b/doc/services/console.rst new file mode 100644 index 00000000000..05e506bb14a --- /dev/null +++ b/doc/services/console.rst @@ -0,0 +1,6 @@ +.. _console: + +Console +####### + +.. doxygengroup:: console_api diff --git a/doc/services/debugging/debugmon.rst b/doc/services/debugging/debugmon.rst index f39f8335cf3..ccf5325d135 100644 --- a/doc/services/debugging/debugmon.rst +++ b/doc/services/debugging/debugmon.rst @@ -33,7 +33,7 @@ of the interrupt. Usage ***** -When monitor mode debuging is enabled, entering a breakpoint will not halt the +When monitor mode debugging is enabled, entering a breakpoint will not halt the processor, but rather generate an interrupt with ISR implemented under ``z_arm_debug_monitor`` symbol. :kconfig:option:`CONFIG_CORTEX_M_DEBUG_MONITOR_HOOK` config configures this interrupt to be the lowest available priority, which will allow other interrupts to execute diff --git a/doc/services/debugging/gdbstub.rst b/doc/services/debugging/gdbstub.rst index 50b830fb5b8..c2062ec304d 100644 --- a/doc/services/debugging/gdbstub.rst +++ b/doc/services/debugging/gdbstub.rst @@ -149,7 +149,7 @@ for its implementation as a Twister test. #1 0x00105068 in gdb_init (arg=0x0) at /subsys/debug/gdbstub.c:833 #2 0x00109d6f in z_sys_init_run_level (level=0x1) at /kernel/device.c:72 #3 0x0010a40b in z_cstart () at /kernel/init.c:423 - #4 0x00105383 in z_x86_prep_c (arg=0x9500) at /arch/x86/core/prep_c.c:58 + #4 0x00105383 in z_prep_c (arg=0x9500) at /arch/x86/core/prep_c.c:58 #5 0x001000a9 in __csSet () at /arch/x86/core/ia32/crt0.S:273 #. Use command ``list`` to show the source code and surroundings where diff --git a/doc/services/device_mgmt/index.rst b/doc/services/device_mgmt/index.rst index 96ba59e4a01..6094e49acc1 100644 --- a/doc/services/device_mgmt/index.rst +++ b/doc/services/device_mgmt/index.rst @@ -28,3 +28,4 @@ SMP Groups smp_groups/smp_group_3.rst smp_groups/smp_group_8.rst smp_groups/smp_group_9.rst + smp_groups/smp_group_63.rst diff --git a/doc/services/device_mgmt/mcumgr.rst b/doc/services/device_mgmt/mcumgr.rst index f868aaceb17..0b21ce0771a 100644 --- a/doc/services/device_mgmt/mcumgr.rst +++ b/doc/services/device_mgmt/mcumgr.rst @@ -12,9 +12,10 @@ The following management operations are available: * Image management * File System management * OS management +* Settings (config) management * Shell management * Statistic management -* Zephyr-basic management +* Zephyr management over the following transports: @@ -33,6 +34,85 @@ the Zephyr tree. Additionally, there is a :zephyr:code-sample:`sample ` sample that provides management functionality over BLE and serial. +.. _mcumgr_tools_libraries: + +Tools/libraries +*************** + +There are various tools and libraries available which enable usage of MCUmgr functionality on a +device which are listed below. Note that these tools are not part of or related to the Zephyr +project. + +.. only:: html + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+-------------------------------------------+--------------------------+--------------------------------------------------+---------------+------------+---------+ + | Name | OS support | Transports | Groups | Type | Language | License | + | +---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+ | | | + | | Windows | Linux | mac | Mobile | Embedded | Serial | Bluetooth | UDP | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | | + +================================================================================+=========+=======+=====+========+==========+========+===========+=====+====+=====+======+==========+====+=======+========+===============+============+=========+ + | `AuTerm `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Application | C++ (Qt) | GPLv3 | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-client `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Application | Rust | BSD | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | `mcumgr-web `_ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web page | Javascript | MIT | + | | | | | | | | | | | | | | | | | (chrome only) | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | nRF Connect Device Manager: |br| | | | | | | | | | | | | | | | | | | | + | `Android | ✕ | ✕ | ✕ | ✓ | ✕ | ✕ | ✓ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library and | Java, | Apache | + | `_ | | | | | | | | | | | | | | | | application | Kotlin, | | + | and `iOS | | | | | | | | | | | | | | | | | Swift | | + | `_ | | | | | | | | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + | Zephyr MCUmgr client (in-tree) | ✕ | ✓ | ✕ | ✕ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | Apache | + +--------------------------------------------------------------------------------+---------+-------+-----+--------+----------+--------+-----------+-----+----+-----+------+----------+----+-------+--------+---------------+------------+---------+ + +.. only:: latex + + .. raw:: latex + + \begin{landscape} + + .. table:: Tools and Libraries for MCUmgr + :align: center + + +--------------------------------------------------------------------------------+---------------+-----------------+--------------------------------------------------+---------------+------------+ + | Name | OS support | Transports | Groups | Type | Language | + | | | +----+-----+------+----------+----+-------+--------+ | | + | | | | OS | IMG | Stat | Settings | FS | Shell | Zephyr | | | + +================================================================================+===============+=================+====+=====+======+==========+====+=======+========+===============+============+ + | `AuTerm `_ | Windows, |br| | Serial, |br| | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | App | C++ (Qt) | + | | Linux, |br| | Bluetooth, |br| | | | | | | | | | | + | | macOS | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-client `_ | Windows, |br| | Serial | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | App | Rust | + | | Linux, |br| | | | | | | | | | | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | `mcumgr-web `_ | Windows, |br| | Bluetooth | ✕ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Web (chrome | Javascript | + | | Linux, |br| | | | | | | | | | only) | | + | | macOS | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | nRF Connect Device Manager: |br| | iOS, |br| | Bluetooth | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Library, App | Java, | + | `Android | Android | | | | | | | | | | Kotlin, | + | `_ | | | | | | | | | | | Swift | + | and `iOS | | | | | | | | | | | | + | `_ | | | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + | Zephyr MCUmgr client (in-tree) | Linux, |br| | Serial, |br| | ✓ | ✓ | ✕ | ✕ | ✕ | ✕ | ✕ | Library | C | + | | Zephyr | Bluetooth, |br| | | | | | | | | | | + | | | UDP | | | | | | | | | | + +--------------------------------------------------------------------------------+---------------+-----------------+----+-----+------+----------+----+-------+--------+---------------+------------+ + + .. raw:: latex + + \end{landscape} + +Note that a tick for a particular group indicates basic support for that group in the code, it is +possible that not all commands/features of a group are supported by the implementation. + .. _mcumgr_cli: Command-line Tool @@ -48,7 +128,8 @@ The tool is written in the Go programming language. aborting will, in some circumstances, sit in an endless loop of sending the same command over and over again. A universal replacement for this tool is currently in development and once released, support for the go tool will be - dropped entirely. + dropped entirely. It is recommended that usage of tools listed above in the + :ref:`mcumgr_tools_libraries` section are used instead of the go client. To install the tool: diff --git a/doc/services/device_mgmt/smp_groups/smp_group_3.rst b/doc/services/device_mgmt/smp_groups/smp_group_3.rst index c70897809e1..0636e72e3f6 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_3.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_3.rst @@ -132,7 +132,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Write setting request @@ -220,7 +220,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Delete setting command @@ -310,7 +310,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Commit settings command @@ -386,7 +386,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Load/Save settings command @@ -462,7 +462,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+-------------------------------------------------------------------------+ Save settings request @@ -532,7 +532,7 @@ where: | | non-zero (error condition) when using SMP version 2. | +------------------+------------------------------------------------------------------------+ | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | - | | using SMP version 1. | + | | using SMP version 1 or for SMP errors when using SMP version 2. | +------------------+------------------------------------------------------------------------+ Settings access callback diff --git a/doc/services/device_mgmt/smp_groups/smp_group_63.rst b/doc/services/device_mgmt/smp_groups/smp_group_63.rst new file mode 100644 index 00000000000..8d1f9015bcb --- /dev/null +++ b/doc/services/device_mgmt/smp_groups/smp_group_63.rst @@ -0,0 +1,92 @@ +.. _mcumgr_smp_group_63: + +Zephyr Management Group +####################### + +Zephyr management group defines the following commands: + +.. table:: + :align: center + + +----------------+------------------------------+ + | ``Command ID`` | Command description | + +================+==============================+ + | ``0`` | Erase storage | + +----------------+------------------------------+ + +Erase storage command +********************* + +Erase storage command allows clearing the ``storage_partition`` flash partition on a device, +generally this is used when switching to a new application build if the application uses storage +that should be cleared (application dependent). + +Erase storage request +===================== + +Erase storage request header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``2`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends sends empty CBOR map as data. + +Erase storage response +====================== + +Read setting response header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``3`` | ``63`` | ``0`` | + +--------+--------------+----------------+ + +The command sends an empty CBOR map as data if successful. In case of error the CBOR data takes +the form: + +.. tabs:: + + .. group-tab:: SMP version 2 + + .. code-block:: none + + { + (str)"err" : { + (str)"group" : (uint) + (str)"rc" : (uint) + } + } + + .. group-tab:: SMP version 1 + + .. code-block:: none + + { + (str)"rc" : (int) + } + +where: + +.. table:: + :align: center + + +------------------+-------------------------------------------------------------------------+ + | "err" -> "group" | :c:enum:`mcumgr_group_t` group of the group-based error code. Only | + | | appears if an error is returned when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "err" -> "rc" | contains the index of the group-based error code. Only appears if | + | | non-zero (error condition) when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ + | "rc" | :c:enum:`mcumgr_err_t` only appears if non-zero (error condition) when | + | | using SMP version 1 or for SMP errors when using SMP version 2. | + +------------------+-------------------------------------------------------------------------+ diff --git a/doc/services/device_mgmt/smp_protocol.rst b/doc/services/device_mgmt/smp_protocol.rst index 44c30f32d29..1ad4634d6e7 100644 --- a/doc/services/device_mgmt/smp_protocol.rst +++ b/doc/services/device_mgmt/smp_protocol.rst @@ -141,7 +141,7 @@ groups. The following table presents a list of common groups: +---------------+-----------------------------------------------+ | ``9`` | :ref:`mcumgr_smp_group_9` | +---------------+-----------------------------------------------+ - | ``63`` | Zephyr specific basic commands group | + | ``63`` | :ref:`mcumgr_smp_group_63` | +---------------+-----------------------------------------------+ | ``64`` | This is the base group for defining | | | an application specific management groups. | diff --git a/doc/services/index.rst b/doc/services/index.rst index c9055e8081f..9e4dc3c98dc 100644 --- a/doc/services/index.rst +++ b/doc/services/index.rst @@ -8,6 +8,7 @@ OS Services binary_descriptors/index.rst + console.rst crypto/index debugging/index.rst device_mgmt/index diff --git a/doc/services/input/diodes-cr.svg b/doc/services/input/diodes-cr.svg new file mode 100644 index 00000000000..d374b8e0c41 --- /dev/null +++ b/doc/services/input/diodes-cr.svg @@ -0,0 +1,6140 @@ + + + + SVG Image created as keyboard-matrix-testboard-diodes-cr.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/diodes-rc.svg b/doc/services/input/diodes-rc.svg new file mode 100644 index 00000000000..91e0f9607ab --- /dev/null +++ b/doc/services/input/diodes-rc.svg @@ -0,0 +1,6140 @@ + + + + SVG Image created as keyboard-matrix-testboard-diodes-rc.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D8 + + D8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D9 + + D9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D7 + + D7 + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D4 + + D4 + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 + + D1 + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D5 + + D5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D6 + + D6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D2 + + D2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D3 + + D3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/gpio-kbd.rst b/doc/services/input/gpio-kbd.rst new file mode 100644 index 00000000000..2910405bdd2 --- /dev/null +++ b/doc/services/input/gpio-kbd.rst @@ -0,0 +1,240 @@ +.. _gpio-kbd: + +GPIO Keyboard Matrix +#################### + +The :dtcompatible:`gpio-kbd-matrix` driver supports a large variety of keyboard +matrix hardware configurations and has numerous options to change its behavior. +This is an overview of some common setups and how they can be supported by the +driver. + +The conventional configuration for all of these is that the driver reads on the +row GPIOs (inputs) and selects on the columns GPIOs (output). + +Base use case, no isolation diodes, interrupt capable GPIOs +*********************************************************** + +This is the common configuration found on consumer keyboards with membrane +switches and flexible circuit boards, no isolation diodes, requires ghosting +detection (which is enabled by default). + +.. figure:: no-diodes.svg + :align: center + :width: 50% + + A 3x3 matrix, no diodes + +The system must support GPIO interrupts, and the interrupt can be enabled on all +row GPIOs at the same time. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>, + <&gpio0 5 GPIO_ACTIVE_LOW>; + }; + +In this configuration the matrix scanning library enters idle mode once all +keys are released, and the keyboard matrix thread only wakes up when a key has +been pressed. + +GPIOs for columns that are not currently selected are configured in high +impedance mode. This means that the row state may need some time to settle to +avoid misreading the key state from a column to the following one. The settle +time can be tweaked by changing the ``settle-time-us`` property. + +Isolation diodes +**************** + +If the matrix has isolation diodes for every key, then it's possible to: + + - disable ghosting detection, allowing any key combination to be detected + - configuring the driver to drive unselected columns GPIO to inactive state + rather than high impedance, this allows to reduce the settle time + (potentially down to 0), and use the more efficient port wide GPIO read APIs + (happens automatically if the GPIO pins are sequential) + +Matrixes with diodes going from rows to columns must use pull-ups on rows and +active low columns. + +.. figure:: diodes-rc.svg + :align: center + :width: 50% + + A 3x3 matrix with row to column isolation diodes. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>, + <&gpio0 2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>, + <&gpio0 4 GPIO_ACTIVE_LOW>, + <&gpio0 5 GPIO_ACTIVE_LOW>; + col-drive-inactive; + settle-time-us = <0>; + no-ghostkey-check; + }; + +Matrixes with diodes going from columns to rows must use pull-downs on rows and +active high columns. + +.. figure:: diodes-cr.svg + :align: center + :width: 50% + + A 3x3 matrix with column to row isolation diodes. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + row-gpios = <&gpio0 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpio0 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>, + <&gpio0 2 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + col-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>, + <&gpio0 4 GPIO_ACTIVE_HIGH>, + <&gpio0 5 GPIO_ACTIVE_HIGH>; + col-drive-inactive; + settle-time-us = <0>; + no-ghostkey-check; + }; + +GPIO with no interrupt support +****************************** + +Some GPIO controllers have limitations on GPIO interrupts, and may not support +enabling interrupts on all row GPIOs at the same time. + +In this case, the driver can be configured to not use interrupt at all, and +instead idle by selecting all columns and keep polling on the row GPIOs, which +is a single GPIO API operation if the pins are sequential. + +This configuration can be enabled by setting the ``idle-mode`` property to +``poll``: + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + idle-mode = "poll"; + }; + +GPIO multiplexer +**************** + +In more extreme cases, such as if the columns are using a multiplexer and it's +impossible to select all of them at the same time, the driver can be configured +to scan continuously. + +This can be done by setting ``idle-mode`` to ``scan`` and ``poll-timeout-ms`` +to ``0``. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + poll-timeout-ms = <0>; + idle-mode = "scan"; + }; + +Row and column GPIO selection +***************************** + +If the row GPIOs are sequential and on the same gpio controller, the driver +automatically switches API to read from the whole GPIO port rather than the +individual pins. This is particularly useful if the GPIOs are not memory +mapped, for example on an I2C or SPI port expander, as this significantly +reduces the number of transactions on the corresponding bus. + +The same is true for column GPIOs, but only if the matrix is configured for +``col-drive-inactive``, so that is only usable for matrixes with isolation +diodes. + +16-bit row support +****************** + +The driver uses an 8-bit datatype to store the row state by default, which +limits the matrix row size to 8. This can be increased to 16 by enabling the +:kconfig:option:`CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW` option. + +Actual key mask configuration +***************************** + +If the key matrix is not complete, a map of the keys that are actually +populated can be specified using the `actual-key-mask` property. This allows +the matrix state to be filtered to remove keys that are not present before +ghosting detection, potentially allowing key combinations that would otherwise +be blocked by it. + +For example for a 3x3 matrix missing a key: + +.. figure:: no-sw4.svg + :align: center + :width: 50% + + A 3x3 matrix missing a key. + +.. code-block:: devicetree + + kbd-matrix { + compatible = "gpio-kbd-matrix"; + ... + actual-key-mask = <0x07 0x05 0x07>; + }; + +This would allow, for example, to detect pressing ``Sw1``, ``SW2`` and ``SW4`` +at the same time without triggering anti ghosting. + +The actual key mask can be changed at runtime by enabling +:kconfig:option:`CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC` and the using the +:c:func:`input_kbd_matrix_actual_key_mask_set` API. + +Keyboard matrix shell commands +****************************** + +The shell command ``kbd_matrix_state_dump`` can be used to test the +functionality of any keyboard matrix driver implemented using the keyboard +matrix library. Once enabled it logs the state of the matrix every time it +changes, and once disabled it prints an or-mask of any key that has been +detected, which can be used to set the ``actual-key-mask`` property. + +The command can be enabled using the +:kconfig:option:`CONFIG_INPUT_SHELL_KBD_MATRIX_STATE`. + +Example usage: + +.. code-block:: console + + uart:~$ device list + devices: + - kbd-matrix (READY) + uart:~$ input kbd_matrix_state_dump kbd-matrix + Keyboard state logging enabled for kbd-matrix + [00:01:41.678,466] input: kbd-matrix state [01 -- -- --] (1) + [00:01:41.784,912] input: kbd-matrix state [-- -- -- --] (0) + ... + press more buttons + ... + uart:~$ input kbd_matrix_state_dump off + Keyboard state logging disabled + [00:01:47.967,651] input: kbd-matrix key-mask [07 05 07 --] (8) + +Keyboard matrix library +*********************** + +The GPIO keyboard matrix driver is based on a generic keyboard matrix library, +which implements the core functionalities such as scanning delays, debouncing, +idle mode etc. This can be reused to implement other keyboard matrix drivers, +potentially application specific. + +.. doxygengroup:: input_kbd_matrix diff --git a/doc/services/input/index.rst b/doc/services/input/index.rst index b18c57beb30..01d7d92b088 100644 --- a/doc/services/input/index.rst +++ b/doc/services/input/index.rst @@ -78,6 +78,15 @@ compatibility device node, for example: }; }; +Driver Documentation +******************** + +.. toctree:: + :maxdepth: 1 + + gpio-kbd.rst + + API Reference ************* @@ -88,7 +97,7 @@ Input Event Definitions .. doxygengroup:: input_events -Keyboard Matrix API Reference -***************************** +Analog Axis API Reference +************************* -.. doxygengroup:: input_kbd_matrix +.. doxygengroup:: input_analog_axis diff --git a/doc/services/input/no-diodes.svg b/doc/services/input/no-diodes.svg new file mode 100644 index 00000000000..ced8ad7ce78 --- /dev/null +++ b/doc/services/input/no-diodes.svg @@ -0,0 +1,2689 @@ + + + + SVG Image created as keyboard-matrix-testboard-no-diodes.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW5 + + SW5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/input/no-sw4.svg b/doc/services/input/no-sw4.svg new file mode 100644 index 00000000000..b79188fbe92 --- /dev/null +++ b/doc/services/input/no-sw4.svg @@ -0,0 +1,2496 @@ + + + + SVG Image created as keyboard-matrix-testboard-no-sw4.svg date 2023/12/18 09:58:32 + Image generated by Eeschema-SVG + + + + + + + + + + + + + + + + + + + + + + + + + SW7 + + SW7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW3 + + SW3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW8 + + SW8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW1 + + SW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW6 + + SW6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW2 + + SW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW4 + + SW4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SW9 + + SW9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL2 + + + COL2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL0 + + + COL0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COL1 + + + COL1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW0 + + ROW0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW1 + + ROW1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ROW2 + + ROW2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/ipc/ipc_service/ipc_service.rst b/doc/services/ipc/ipc_service/ipc_service.rst index 286ded75801..ec8551fe9ce 100644 --- a/doc/services/ipc/ipc_service/ipc_service.rst +++ b/doc/services/ipc/ipc_service/ipc_service.rst @@ -67,7 +67,7 @@ See the following example: static void bound_cb(void *priv) { - /* Endpint bounded */ + /* Endpoint bounded */ } static void recv_cb(const void *data, size_t len, void *priv) @@ -93,7 +93,7 @@ See the following example: ret = ipc_service_open_instance(inst0); ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg); - /* Wait for endpint bound (bound_cb called) */ + /* Wait for endpoint bound (bound_cb called) */ unsigned char message[] = "hello world"; ret = ipc_service_send(&ept0, &message, sizeof(message)); @@ -117,7 +117,7 @@ See the following example: static void bound_cb(void *priv) { - /* Endpint bounded */ + /* Endpoint bounded */ } static void recv_cb_nocopy(const void *data, size_t len, void *priv) @@ -146,7 +146,7 @@ See the following example: ret = ipc_service_open_instance(inst0); ret = ipc_service_register_endpoint(inst0, &ept0, &ept0_cfg); - /* Wait for endpint bound (bound_cb called) */ + /* Wait for endpoint bound (bound_cb called) */ void *data; unsigned char message[] = "hello world"; uint32_t len = sizeof(message); diff --git a/doc/services/logging/index.rst b/doc/services/logging/index.rst index 2b9fe9a707a..84d862b9076 100644 --- a/doc/services/logging/index.rst +++ b/doc/services/logging/index.rst @@ -124,9 +124,9 @@ allocated. :kconfig:option:`CONFIG_LOG_PRINTK`: Redirect printk calls to the logging. -:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When number of buffered log -messages reaches the threshold dedicated thread (see :c:func:`log_thread_set`) -is waken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this +:kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When the number of buffered log +messages reaches the threshold, the dedicated thread (see :c:func:`log_thread_set`) +is woken up. If :kconfig:option:`CONFIG_LOG_PROCESS_THREAD` is enabled then this threshold is used by the internal thread. :kconfig:option:`CONFIG_LOG_PROCESS_THREAD`: When enabled, logging thread is created @@ -242,7 +242,7 @@ Logging in a module instance ============================ In case of modules which are multi-instance and instances are widely used -across the system enabling logs will lead to flooding. Logger provide the tools +across the system enabling logs will lead to flooding. The logger provides the tools which can be used to provide filtering on instance level rather than module level. In that case logging can be enabled for particular instance. @@ -305,16 +305,16 @@ By default, logging processing in deferred mode is handled internally by the dedicated task which starts automatically. However, it might not be available if multithreading is disabled. It can also be disabled by unsetting :kconfig:option:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`. In that case, logging can -be controlled using API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. -Logging must be initialized before it can be used. Optionally, user can provide -function which returns timestamp value. If not provided, :c:macro:`k_cycle_get` +be controlled using the API defined in :zephyr_file:`include/zephyr/logging/log_ctrl.h`. +Logging must be initialized before it can be used. Optionally, the user can provide +a function which returns the timestamp value. If not provided, :c:macro:`k_cycle_get` or :c:macro:`k_cycle_get_32` is used for timestamping. -:c:func:`log_process` function is used to trigger processing of one log -message (if pending). Function returns true if there is more messages pending. +The :c:func:`log_process` function is used to trigger processing of one log +message (if pending), and returns true if there are more messages pending. However, it is recommended to use macro wrappers (:c:macro:`LOG_INIT` and -:c:macro:`LOG_PROCESS`) which handles case when logging is disabled. +:c:macro:`LOG_PROCESS`) which handle the case where logging is disabled. -Following snippet shows how logging can be processed in simple forever loop. +The following snippet shows how logging can be processed in simple forever loop. .. code-block:: c @@ -356,16 +356,17 @@ that moment all logs are processed in a blocking way. Printk ****** -Typically, logging and :c:func:`printk` is using the same output for which they -compete. This can lead to issues if the output does not support preemption but -also it may result in the corrupted output because logging data is interleaved -with printk data. However, it is possible to redirect printk messages to the +Typically, logging and :c:func:`printk` use the same output, which they compete +for. This can lead to issues if the output does not support preemption but it may +also result in corrupted output because logging data is interleaved with printk +data. However, it is possible to redirect printk messages to the logging subsystem by enabling :kconfig:option:`CONFIG_LOG_PRINTK`. In that case, printk entries are treated as log messages with level 0 (they cannot be disabled). When enabled, logging manages the output so there is no interleaving. However, -in the deferred mode it changes the behavior of the printk because output is delayed -until logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` is by -default enabled. +in deferred mode the printk behaviour is changed since the output is delayed +until the logging thread processes the data. :kconfig:option:`CONFIG_LOG_PRINTK` +is enabled by default. + .. _log_architecture: @@ -384,27 +385,27 @@ instance of a module. Default Frontend ================ -Default frontend is engaged when logging API is called in a source of logging (e.g. +Default frontend is engaged when the logging API is called in a source of logging (e.g. :c:macro:`LOG_INF`) and is responsible for filtering a message (compile and run -time), allocating buffer for the message, creating the message and committing that -message. Since logging API can be called in an interrupt, frontend is optimized +time), allocating a buffer for the message, creating the message and committing that +message. Since the logging API can be called in an interrupt, the frontend is optimized to log the message as fast as possible. Log message ----------- -Log message contains message descriptor (source, domain and level), timestamp, +A log message contains a message descriptor (source, domain and level), timestamp, formatted string details (see :ref:`cbprintf_packaging`) and optional data. Log messages are stored in a continuous block of memory. -Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`). It has -few consequences: +Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`), which has +a few consequences: - * Each message is self-contained, continuous block of memory thus it is suited + * Each message is a self-contained, continuous block of memory thus it is suited for copying the message (e.g. for offline processing). * Messages must be sequentially freed. Backend processing is synchronous. Backend can make a copy for deferred processing. -Log message has following format: +A log message has following format: +------------------+----------------------------------------------------+ | Message Header | 2 bits: MPSC packet buffer header | @@ -446,12 +447,12 @@ Log message has following format: Log message allocation ---------------------- -It may happen that frontend cannot allocate a message. It happens if system is -generating more log messages than it can process in certain time frame. There -are two strategies to handle that case: +It may happen that the frontend cannot allocate a message. This happens if the +system is generating more log messages than it can process in certain time +frame. There are two strategies to handle that case: -- No overflow - new log is dropped if space for a message cannot be allocated. -- Overflow - oldest pending messages are freed, until new message can be +- No overflow - the new log is dropped if space for a message cannot be allocated. +- Overflow - the oldest pending messages are freed, until the new message can be allocated. Enabled by :kconfig:option:`CONFIG_LOG_MODE_OVERFLOW`. Note that it degrades performance thus it is recommended to adjust buffer size and amount of enabled logs to limit dropping. diff --git a/doc/services/mem_mgmt/index.rst b/doc/services/mem_mgmt/index.rst index eb689c409d1..d42b72ebe51 100644 --- a/doc/services/mem_mgmt/index.rst +++ b/doc/services/mem_mgmt/index.rst @@ -84,7 +84,112 @@ one by renaming the property and changing its value according to the following l "IO" -> <( DT_ARM_MPU(ATTR_MPU_IO) )> "EXTMEM" -> <( DT_ARM_MPU(ATTR_MPU_EXTMEM) )> +Memory Attributes Heap Allocator +******************************** + +It is possible to leverage the memory attribute property ``zephyr,memory-attr`` +to define and create a set of memory heaps from which the user can allocate +memory from with certain attributes / capabilities. + +When the :kconfig:option:`CONFIG_MEM_ATTR_HEAP` is set, every region marked +with one of the memory attributes listed in in +:zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h` is added +to a pool of memory heaps used for dynamic allocation of memory buffers with +certain attributes. + +Here a non exhaustive list of possible attributes: + +.. code-block:: none + + DT_MEM_SW_ALLOC_CACHE + DT_MEM_SW_ALLOC_NON_CACHE + DT_MEM_SW_ALLOC_DMA + +For example we can define several memory regions with different attributes and +use the appropriate attribute to indicate that it is possible to dynamically +allocate memory from those regions: + +.. code-block:: devicetree + + mem_cacheable: memory@10000000 { + compatible = "mmio-sram"; + reg = <0x10000000 0x1000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_non_cacheable: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x1000>; + zephyr,memory-attr = <( DT_MEM_NON_CACHEABLE | ATTR_SW_ALLOC_NON_CACHE )>; + }; + + mem_cacheable_big: memory@30000000 { + compatible = "mmio-sram"; + reg = <0x30000000 0x10000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_OOO | DT_MEM_SW_ALLOC_CACHE )>; + }; + + mem_cacheable_dma: memory@40000000 { + compatible = "mmio-sram"; + reg = <0x40000000 0x10000>; + zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_DMA | + DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA )>; + }; + +The user can then dynamically carve memory out of those regions using the +provided functions, the library will take care of allocating memory from the +correct heap depending on the provided attribute and size: + +.. code-block:: c + + // Init the pool + mem_attr_heap_pool_init(); + + // Allocate 0x100 bytes of cacheable memory from `mem_cacheable` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + + // Allocate 0x200 bytes of non-cacheable memory aligned to 32 bytes + // from `mem_non_cacheable` + block = mem_attr_heap_aligned_alloc(ATTR_SW_ALLOC_NON_CACHE, 0x100, 32); + + // Allocate 0x100 bytes of cacheable and dma-able memory from `mem_cacheable_dma` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100); + +When several regions are marked with the same attributes, the memory is allocated: + +1. From the regions where the ``zephyr,memory-attr`` property has the requested + property (or properties). + +2. Among the regions as at point 1, from the smallest region if there is any + unallocated space left for the requested size + +3. If there is not enough space, from the next bigger region able to + accommodate the requested size + +The following example shows the point 3: + +.. code-block:: c + + // This memory is allocated from `mem_non_cacheable` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); + + // This memory is allocated from `mem_cacheable_big` + block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x5000); + +.. note:: + + The framework is assuming that the memory regions used to create the heaps + are usable by the code and available at init time. The user must take of + initializing and setting the memory area before calling + :c:func:`mem_attr_heap_pool_init`. + + That means that the region must be correctly configured in terms of MPU / + MMU (if needed) and that an actual heap can be created out of it, for + example by leveraging the ``zephyr,memory-region`` property to create a + proper linker section to accommodate the heap. + API Reference ************* .. doxygengroup:: memory_attr_interface +.. doxygengroup:: memory_attr_heap diff --git a/doc/services/pm/device_runtime.rst b/doc/services/pm/device_runtime.rst index 5d9df2d8706..b0dd57db02e 100644 --- a/doc/services/pm/device_runtime.rst +++ b/doc/services/pm/device_runtime.rst @@ -224,5 +224,5 @@ asynchronous API: ... /* "put" device (decreases usage count, schedule suspend if no more users) */ - return pm_device_runtime_put_async(dev); + return pm_device_runtime_put_async(dev, K_NO_WAIT); } diff --git a/doc/services/pm/system.rst b/doc/services/pm/system.rst index 989fcdb4a91..b71b793c94d 100644 --- a/doc/services/pm/system.rst +++ b/doc/services/pm/system.rst @@ -24,7 +24,6 @@ The following diagram describes system power management: Some handful examples using different power management features: * :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/` -* :zephyr_file:`samples/boards/nrf/system_off/` * :zephyr_file:`samples/boards/esp32/deep_sleep/` * :zephyr_file:`samples/subsys/pm/device_pm/` * :zephyr_file:`tests/subsys/pm/power_mgmt/` diff --git a/doc/services/portability/index.rst b/doc/services/portability/index.rst index 18b1a83c95f..357aa778514 100644 --- a/doc/services/portability/index.rst +++ b/doc/services/portability/index.rst @@ -14,6 +14,6 @@ supported by the Zephyr RTOS. .. toctree:: :maxdepth: 1 - posix.rst + posix/index.rst cmsis_rtos_v1.rst cmsis_rtos_v2.rst diff --git a/doc/services/portability/posix.rst b/doc/services/portability/posix.rst deleted file mode 100644 index 392147594c8..00000000000 --- a/doc/services/portability/posix.rst +++ /dev/null @@ -1,483 +0,0 @@ -.. _posix_support: - -POSIX Support -############# - -The Portable Operating System Interface (POSIX) is a family of standards -specified by the IEEE Computer Society for maintaining compatibility between -operating systems. Zephyr implements a subset of the embedded profiles PSE51 -and PSE52, and BSD Sockets API. - -With the POSIX support available in Zephyr, an existing POSIX compliant -application can be ported to run on the Zephyr kernel, and therefore leverage -Zephyr features and functionality. Additionally, a library designed for use with -POSIX threading compatible operating systems can be ported to Zephyr kernel -based applications with minimal or no changes. - -.. figure:: posix.svg - :align: center - :alt: POSIX Support in Zephyr - - POSIX support in Zephyr - -The POSIX API subset is an increasingly popular OSAL (operating system -abstraction layer) for IoT and embedded applications, as can be seen in -Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. - -Benefits of POSIX support in Zephyr include: - -- Offering a familiar API to non-embedded programmers, especially from Linux -- Enabling reuse (portability) of existing libraries based on POSIX APIs -- Providing an efficient API subset appropriate for small (MCU) embedded systems - - -System Overview -=============== - -Units of Functionality -++++++++++++++++++++++ - -The system profile is defined in terms of component profiles that specify Units -of Functionality that can be combined to realize the application platform. A Unit -of Functionality is a defined set of services which can be implemented. If -implemented, the standard prescribes that all services in the Unit must -be implemented. - -A Minimal Realtime System Profile implementation must support the -following Units of Functionality as defined in IEEE Std. 1003.1 (also referred to -as POSIX.1-2017). - - -.. csv-table:: Units of Functionality - :header: Requirements, Supported, Remarks - :widths: 50,10,60 - - - POSIX_C_LANG_JUMP, - POSIX_C_LANG_SUPPORT,yes - POSIX_DEVICE_IO, - POSIX_FILE_LOCKING, - POSIX_SIGNALS, - POSIX_SINGLE_PROCESS, - POSIX_SPIN_LOCKS,yes - POSIX_THREADS_BASE,yes - XSI_THREAD_MUTEX_EXT,yes - XSI_THREADS_EXT,yes - - -Option Requirements -++++++++++++++++++++ - -An implementation supporting the Minimal Realtime System -Profile must support the POSIX.1 Option Requirements which are defined in the -standard. Options Requirements are used for further sub-profiling within the -units of functionality: they further define the functional behavior of the -system service (normally adding extra functionality). Depending on the profile -to which the POSIX implementation complies,parameters and/or the precise -functionality of certain services may differ. - -The following list shows the option requirements that are implemented in -Zephyr. - - -.. csv-table:: Option Requirements - :header: Requirements, Supported - :widths: 50,10 - - _POSIX_BARRIERS,yes - _POSIX_CLOCK_SELECTION,yes - _POSIX_FSYNC, - _POSIX_MEMLOCK, - _POSIX_MEMLOCK_RANGE, - _POSIX_MONOTONIC_CLOCK,yes - _POSIX_NO_TRUNC, - _POSIX_REALTIME_SIGNALS, - _POSIX_SEMAPHORES,yes - _POSIX_SHARED_MEMORY_OBJECTS, - _POSIX_SPIN_LOCKS,yes - _POSIX_SYNCHRONIZED_IO, - _POSIX_THREAD_ATTR_STACKADDR,yes - _POSIX_THREAD_ATTR_STACKSIZE,yes - _POSIX_THREAD_CPUTIME, - _POSIX_THREAD_PRIO_INHERIT, - _POSIX_THREAD_PRIO_PROTECT, - _POSIX_THREAD_PRIORITY_SCHEDULING,yes - _POSIX_THREAD_SPORADIC_SERVER, - _POSIX_TIMEOUTS, - _POSIX_TIMERS,yes - _POSIX2_C_DEV, - _POSIX2_SW_DEV, - - - -Units of Functionality -====================== - -This section describes the Units of Functionality (fixed sets of interfaces) -which are implemented (partially or completely) in Zephyr. Please refer to the -standard for a full description of each listed interface. - -POSIX_THREADS_BASE -+++++++++++++++++++ - -The basic assumption in this profile is that the system -consists of a single (implicit) process with multiple threads. Therefore, the -standard requires all basic thread services, except those related to -multiple processes. - - -.. csv-table:: POSIX_THREADS_BASE - :header: API, Supported - :widths: 50,10 - - pthread_atfork(), - pthread_attr_destroy(),yes - pthread_attr_getdetachstate(),yes - pthread_attr_getschedparam(),yes - pthread_attr_init(),yes - pthread_attr_setdetachstate(),yes - pthread_attr_setschedparam(),yes - pthread_barrier_destroy(),yes - pthread_barrier_init(),yes - pthread_barrier_wait(),yes - pthread_barrierattr_destroy(),yes - pthread_barrierattr_getpshared(),yes - pthread_barrierattr_init(),yes - pthread_barrierattr_setpshared(),yes - pthread_cancel(),yes - pthread_cleanup_pop(), - pthread_cleanup_push(), - pthread_cond_broadcast(),yes - pthread_cond_destroy(),yes - pthread_cond_init(),yes - pthread_cond_signal(),yes - pthread_cond_timedwait(),yes - pthread_cond_wait(),yes - pthread_condattr_destroy(),yes - pthread_condattr_init(),yes - pthread_create(),yes - pthread_detach(),yes - pthread_equal(),yes - pthread_exit(),yes - pthread_getspecific(),yes - pthread_join(),yes - pthread_key_create(),yes - pthread_key_delete(),yes - pthread_kill(), - pthread_mutex_destroy(),yes - pthread_mutex_init(),yes - pthread_mutex_lock(),yes - pthread_mutex_trylock(),yes - pthread_mutex_unlock(),yes - pthread_mutexattr_destroy(),yes - pthread_mutexattr_init(),yes - pthread_once(),yes - pthread_self(),yes - pthread_setcancelstate(),yes - pthread_setcanceltype(), - pthread_setspecific(),yes - pthread_sigmask(), - pthread_testcancel(), - - - -XSI_THREAD_EXT -++++++++++++++ - -The XSI_THREADS_EXT Unit of Functionality is required because it provides -functions to control a thread's stack. This is considered useful for any -real-time application. - -This table lists service support status in Zephyr: - -.. csv-table:: XSI_THREAD_EXT - :header: API, Supported - :widths: 50,10 - - pthread_attr_getguardsize(), - pthread_attr_getstack(),yes - pthread_attr_setguardsize(), - pthread_attr_setstack(),yes - pthread_getconcurrency(), - pthread_setconcurrency() - - -XSI_THREAD_MUTEX_EXT -++++++++++++++++++++ - -The XSI_THREAD_MUTEX_EXT Unit of Functionality is required because it has -options for controlling the behavior of mutexes under erroneous application use. - - -This table lists service support status in Zephyr: - -.. csv-table:: XSI_THREAD_MUTEX_EXT - :header: API, Supported - :widths: 50,10 - - pthread_mutexattr_gettype(),yes - pthread_mutexattr_settype(),yes - - -POSIX_C_LANG_SUPPORT -++++++++++++++++++++ - -The POSIX_C_LANG_SUPPORT Unit of Functionality contains the general ISO C -Library. - -This is implemented as part of the minimal C library available in Zephyr. - - -.. csv-table:: POSIX_C_LANG_SUPPORT - :header: API, Supported - :widths: 50,10 - - abs(),yes - asctime(), - asctime_r(), - atof(), - atoi(),yes - atol(), - atoll(), - bsearch(),yes - calloc(),yes - ctime(), - ctime_r(), - difftime(), - div(), - feclearexcept(), - fegetenv(), - fegetexceptflag(), - fegetround(), - feholdexcept(), - feraiseexcept(), - fesetenv(), - fesetexceptflag(), - fesetround(), - fetestexcept(), - feupdateenv(), - free(),yes - gmtime(),yes - gmtime_r(),yes - imaxabs(), - imaxdiv(), - isalnum(),yes - isalpha(),yes - isblank(), - iscntrl(),yes - isdigit(),yes - isgraph(),yes - islower(), - isprint(),yes - ispunct(), - isspace(),yes - isupper(),yes - isxdigit(),yes - labs(),yes - ldiv(), - llabs(),yes - lldiv(), - localeconv(), - localtime(),yes - localtime_r(), - malloc(),yes - memchr(),yes - memcmp(),yes - memcpy(),yes - memmove(),yes - memset(),yes - mktime(),yes - qsort(),yes - rand(),yes - rand_r(),yes - realloc(),yes - setlocale(), - snprintf(),yes - sprintf(),yes - srand(),yes - sscanf(), - strcat(),yes - strchr(),yes - strcmp(),yes - strcoll(), - strcpy(),yes - strcspn(),yes - strerror(),yes - strerror_r(),yes - strftime(), - strlen(),yes - strncat(),yes - strncmp(),yes - strncpy(),yes - strpbrk(), - strrchr(),yes - strspn(),yes - strstr(),yes - strtod(), - strtof(), - strtoimax(), - strtok(),yes - strtok_r(),yes - strtol(),yes - strtold(), - strtoll(),yes - strtoul(),yes - strtoull(),yes - strtoumax(), - strxfrm(), - time(),yes - tolower(),yes - toupper(),yes - tzname(), - tzset(), - va_arg(),yes - va_copy(),yes - va_end(),yes - va_start(),yes - vsnprintf(),yes - vsprintf(),yes - vsscanf(), - - -POSIX_SINGLE_PROCESS -+++++++++++++++++++++ - -The POSIX_SINGLE_PROCESS Unit of Functionality contains services for single -process applications. - -.. csv-table:: POSIX_SINGLE_PROCESS - :header: API, Supported - :widths: 50,10 - - confstr(), - environ, - errno,yes - getenv(), - setenv(), - sysconf(), - uname(),yes - unsetenv() - - -POSIX_SIGNALS -+++++++++++++ - -Signal services are a basic mechanism within POSIX-based systems and are -required for error and event handling. - -.. csv-table:: POSIX_SIGNALS - :header: API, Supported - :widths: 50,10 - - - abort(),yes - alarm(), - kill(), - pause(), - raise(), - sigaction(), - sigaddset(),yes - sigdelset(),yes - sigemptyset(),yes - sigfillset(),yes - sigismember(),yes - signal(), - sigpending(), - sigprocmask(), - igsuspend(), - sigwait(), - strsignal(),yes - -.. csv-table:: POSIX_SPIN_LOCKS - :header: API, Supported - :widths: 50,10 - - pthread_spin_destroy(),yes - pthread_spin_init(),yes - pthread_spin_lock(),yes - pthread_spin_trylock(),yes - pthread_spin_unlock(),yes - - -POSIX_DEVICE_IO -+++++++++++++++ - -.. csv-table:: POSIX_DEVICE_IO - :header: API, Supported - :widths: 50,10 - - flockfile(), - ftrylockfile(), - funlockfile(), - getc_unlocked(), - getchar_unlocked(),yes - putc_unlocked(), - putchar_unlocked() - clearerr(), - close(),yes - fclose(), - fdopen(), - feof(), - ferror(), - fflush(), - fgetc(), - fgets(), - fileno(), - fopen(), - fprintf(),yes - fputc(),yes - fputs(),yes - fread(), - freopen(), - fscanf(), - fwrite(),yes - getc(), - getchar(), - gets(), - open(),yes - perror(),yes - printf(),yes - putc(),yes - putchar(),yes - puts(),yes - read(),yes - scanf(), - setbuf(), - setvbuf(), - stderr,yes - stdin,yes - stdout,yes - ungetc(), - vfprintf(),yes - vfscanf(), - vprintf(),yes - vscanf(), - write(),yes - -POSIX_TIMERS -++++++++++++ - -.. csv-table:: POSIX_TIMERS - :header: API, Supported - :widths: 50,10 - - clock_getres(), - clock_gettime(),yes - clock_settime(),yes - nanosleep(),yes - timer_create(),yes - timer_delete(),yes - timer_gettime(),yes - timer_getoverrun(),yes - timer_settime(),yes - -POSIX_CLOCK_SELECTION -+++++++++++++++++++++ - -.. csv-table:: POSIX_CLOCK_SELECTION - :header: API, Supported - :widths: 50,10 - - pthread_condattr_getclock(),yes - pthread_condattr_setclock(),yes - clock_nanosleep(),yes diff --git a/doc/services/portability/posix.svg b/doc/services/portability/posix.svg deleted file mode 100644 index c21ecba2ae5..00000000000 --- a/doc/services/portability/posix.svg +++ /dev/null @@ -1,2 +0,0 @@ - -
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
<div>POSIX PSE52</div>
Networking
Networking
BSD Sockets
<div>BSD Sockets<br></div>
 Middleware
 Middleware
Application
Application
\ No newline at end of file diff --git a/doc/services/portability/posix/aep/index.rst b/doc/services/portability/posix/aep/index.rst new file mode 100644 index 00000000000..5e28fa10397 --- /dev/null +++ b/doc/services/portability/posix/aep/index.rst @@ -0,0 +1,188 @@ +.. _posix_aep: + +POSIX Application Environment Profiles (AEP) +############################################ + +Although inactive, `IEEE 1003.13-2003`_ defined a number of AEP that inspired the modern +subprofiling options of `IEEE 1003.1-2017`_. The single-purpose realtime system profiles +are listed below, for reference, in terms that agree with the current POSIX-1 standard. PSE54 +is not considered at this time. + +.. _posix_aep_pse51: + +Minimal Realtime System Profile (PSE51) +======================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_MINIMAL to the value 200312L + +.. csv-table:: PSE51 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_MINIMAL, -1, + +.. csv-table:: PSE51 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FILE_LOCKING,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE51 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` (will fail with ``ENOSYS``:ref:`†`) + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + +.. _posix_aep_pse52: + +Realtime Controller System Profile (PSE52) +========================================== + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_CONTROLLER to the value 200312L + +.. csv-table:: PSE52 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_CONTROLLER, -1, + +.. csv-table:: PSE52 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` + POSIX_C_LANG_MATH, yes, :ref:`POSIX_C_LANG_MATH ` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_SIGNALS,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE52 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _posix_aep_pse53: + +Dedicated Realtime System Profile (PSE53) +========================================= + +.. Conforming implementations shall define _POSIX_AEP_REALTIME_DEDICATED to the value 200312L + +.. csv-table:: PSE53 System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_AEP_REALTIME_DEDICATED, -1, + +.. csv-table:: PSE53 Option Groups + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + POSIX_C_LANG_JUMP, yes, :ref:`POSIX_C_LANG_JUMP ` + POSIX_C_LANG_MATH, yes, :ref:`POSIX_C_LANG_MATH ` + POSIX_C_LANG_SUPPORT, yes, :ref:`POSIX_C_LANG_SUPPORT ` + POSIX_DEVICE_IO,, :ref:`†` + POSIX_FD_MGMT,, + POSIX_FILE_LOCKING,, + POSIX_FILE_SYSTEM,, + POSIX_MULTI_PROCESS,, :ref:`†` + POSIX_NETWORKING, yes, :ref:`†` + POSIX_PIPE,, :ref:`†` + POSIX_SIGNALS,, :ref:`†` + POSIX_SIGNAL_JUMP,, :ref:`†` + POSIX_SINGLE_PROCESS,, :ref:`†` + POSIX_THREADS_BASE, yes, :ref:`†` + XSI_THREADS_EXT, yes, :ref:`†` + +.. csv-table:: PSE53 Option Requirements + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ASYNCHRONOUS_IO, -1, + _POSIX_CLOCK_SELECTION, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_MAPPED_FILES, -1, + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + _POSIX_MEMORY_PROTECTION, -1, + _POSIX_MESSAGE_PASSING, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + _POSIX_PRIORITY_SCHEDULING, -1, + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_REALTIME_SIGNALS, -1, + _POSIX_SEMAPHORES, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + _POSIX_THREAD_ATTR_STACKADDR, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_ATTR_STACKSIZE, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + _POSIX_THREAD_PRIORITY_SCHEDULING, -1, + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TIMEOUTS, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_TIMERS, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_LOG, -1, + +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ diff --git a/doc/services/portability/posix/conformance/index.rst b/doc/services/portability/posix/conformance/index.rst new file mode 100644 index 00000000000..0c38955337e --- /dev/null +++ b/doc/services/portability/posix/conformance/index.rst @@ -0,0 +1,154 @@ +.. _posix_conformance: + +POSIX Conformance +################# + +As per `IEEE 1003.1-2017`, this section details Zephyr's POSIX conformance. + +.. _posix_undefined_behaviour: + +.. note:: + As per POSIX 1003.13, single process mode is supported directly by both PSE51 and PSE52 + profiles. While Zephyr includes support for many features found in PSE53, PSE53 itself requires + supporting multiple processes. Since supporting multiple processes is beyond the scope of + Zephyr's current design, some features requiring multi-process capabilities may exhibit + undefined behaviour, which we denote with the † (obelus) symbol. + +.. _posix_libc_provided: + +.. note:: + Features listed in various POSIX Options or Option Groups may be provided in whole or in part + by a conformant C library implementation. This includes (but is not limited to) POSIX + Extensions to the ISO C Standard (`CX`_). + +.. _posix_system_interfaces: + +POSIX System Interfaces +======================= + +.. The following have values greater than -1 in Zephyr, conformant with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_CHOWN_RESTRICTED, 0, + _POSIX_NO_TRUNC, 0, + _POSIX_VDISABLE, 0, + +.. The following should be valued greater than zero in Zephyr, in order to be strictly conformant + with the POSIX specification. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_JOB_CONTROL, -1, :ref:`†` + _POSIX_REGEXP, -1, :ref:`†` + _POSIX_SAVED_IDS, -1, :ref:`†` + _POSIX_SHELL, -1, :ref:`†` + +.. TODO: POSIX_ASYNCHRONOUS_IO, and other interfaces below, are mandatory. That means that a + strictly conforming application need not be modified in order to compile against Zephyr. + However, we may add implementations that simply fail with ENOSYS as long as the functional + modification is clearly documented. The implementation is not required for PSE51 or PSE52 + and beyond that POSIX async I/O functions are rarely used in practice. + +.. csv-table:: POSIX System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_VERSION, 200809L, + _POSIX_ASYNCHRONOUS_IO, -1, :ref:`†` + :ref:`_POSIX_BARRIERS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_BARRIER` + :ref:`_POSIX_CLOCK_SELECTION`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_MAPPED_FILES, -1, :ref:`†` + _POSIX_MEMORY_PROTECTION, -1, :ref:`†` + :ref:`_POSIX_READER_WRITER_LOCKS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + _POSIX_REALTIME_SIGNALS, -1, :ref:`†` + :ref:`_POSIX_SEMAPHORES`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_SPIN_LOCKS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` + :ref:`_POSIX_THREAD_SAFE_FUNCTIONS`, -1, + :ref:`_POSIX_THREADS`, -1, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMEOUTS`, 200809L, :kconfig:option:`CONFIG_PTHREAD_IPC` + :ref:`_POSIX_TIMERS`, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX2_C_BIND, 200809L, + +.. csv-table:: POSIX System Interfaces (Optional) + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_ADVISORY_INFO, -1, + _POSIX_CPUTIME, -1, + _POSIX_FSYNC, -1, + _POSIX_IPV6, 200809L, :kconfig:option:`CONFIG_NET_IPV6` + _POSIX_MEMLOCK, -1, + _POSIX_MEMLOCK_RANGE, -1, + :ref:`_POSIX_MESSAGE_PASSING`, 200809L, :kconfig:option:`CONFIG_POSIX_MQUEUE` + _POSIX_MONOTONIC_CLOCK, 200809L, :kconfig:option:`CONFIG_POSIX_CLOCK` + _POSIX_PRIORITIZED_IO, -1, + :ref:`_POSIX_PRIORITY_SCHEDULING`, -1, :kconfig:option:`CONFIG_POSIX_PRIORITY_SCHEDULING` (will fail with ``ENOSYS``:ref:`†`) + _POSIX_RAW_SOCKETS, 200809L, :kconfig:option:`CONFIG_NET_SOCKETS` + _POSIX_SHARED_MEMORY_OBJECTS, -1, + _POSIX_SPAWN, -1, + _POSIX_SPORADIC_SERVER, -1, + _POSIX_SYNCHRONIZED_IO, -1, + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_CPUTIME, -1, + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PRIO_INHERIT, 200809L, :kconfig:option:`CONFIG_PTHREAD_MUTEX` + _POSIX_THREAD_PRIO_PROTECT, -1, + :ref:`_POSIX_THREAD_PRIORITY_SCHEDULING`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, + _POSIX_THREAD_SPORADIC_SERVER, -1, + _POSIX_TRACE, -1, + _POSIX_TRACE_EVENT_FILTER, -1, + _POSIX_TRACE_INHERIT, -1, + _POSIX_TRACE_LOG, -1, + _POSIX_TYPED_MEMORY_OBJECTS, -1, + _XOPEN_CRYPT, -1, + _XOPEN_REALTIME, -1, + _XOPEN_REALTIME_THREADS, -1, + :ref:`_XOPEN_STREAMS`, -1, :kconfig:option:`CONFIG_NET_SOCKETS` + _XOPEN_UNIX, -1, + +POSIX Shell and Utilities +========================= + +Zephyr does not support a POSIX shell or utilities at this time. + +.. csv-table:: POSIX Shell and Utilities + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX2_C_DEV, -1, :ref:`†` + _POSIX2_CHAR_TERM, -1, :ref:`†` + _POSIX2_FORT_DEV, -1, :ref:`†` + _POSIX2_FORT_RUN, -1, :ref:`†` + _POSIX2_LOCALEDEF, -1, :ref:`†` + _POSIX2_PBS, -1, :ref:`†` + _POSIX2_PBS_ACCOUNTING, -1, :ref:`†` + _POSIX2_PBS_LOCATE, -1, :ref:`†` + _POSIX2_PBS_MESSAGE, -1, :ref:`†` + _POSIX2_PBS_TRACK, -1, :ref:`†` + _POSIX2_SW_DEV, -1, :ref:`†` + _POSIX2_UPE, -1, :ref:`†` + _POSIX2_UNIX, -1, :ref:`†` + _POSIX2_UUCP, -1, :ref:`†` + +XSI Conformance +############### + +XSI System Interfaces +===================== + +.. csv-table:: XSI System Interfaces + :header: Symbol, Support, Remarks + :widths: 50, 10, 50 + + _POSIX_FSYNC, -1, :ref:`†` + :ref:`_POSIX_THREAD_ATTR_STACKADDR`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + :ref:`_POSIX_THREAD_ATTR_STACKSIZE`, 200809L, :kconfig:option:`CONFIG_PTHREAD` + _POSIX_THREAD_PROCESS_SHARED, -1, + +.. _CX: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap01.html diff --git a/doc/services/portability/posix/implementation/index.rst b/doc/services/portability/posix/implementation/index.rst new file mode 100644 index 00000000000..361b0405576 --- /dev/null +++ b/doc/services/portability/posix/implementation/index.rst @@ -0,0 +1,77 @@ +.. _posix_details: + +Implementation Details +###################### + +In many ways, Zephyr provides support like any POSIX OS; API bindings are provided in the C +programming language, POSIX headers are available in the standard include path, when configured. + +Unlike other multi-purpose POSIX operating systems + +- Zephyr is not "a POSIX OS". The Zephyr kernel was not designed around the POSIX standard, and + POSIX support is an opt-in feature +- Zephyr apps are not linked separately, nor do they execute as subprocesses +- Zephyr, libraries, and application code are compiled and linked together, running similarly to + a single-process application, in a single (possibly virtual) address space +- Zephyr does not provide a POSIX shell, compiler, utilities, and is not self-hosting. + +.. note:: + Unlike the Linux kernel or FreeBSD, Zephyr does not maintain a static table of system call + numbers for each supported architecture, but instead generates system calls dynamically at + build time. See `System Calls ` for more information. + +Design +====== + +As a library, Zephyr's POSIX API implementation makes an effort to be a thin abstraction layer +between the application, middleware, and the Zephyr kernel. + +Some general design considerations: + +- The POSIX interface and implementations should be part of Zephyr's POSIX library, and not + elsewhere, unless required both by the POSIX API implementation and some other feature. An + example where the implementation should remain part of the POSIX implementation is + ``getopt()``. Examples where the implementation should be part of separate libraries are + multithreading and networking. + +- When the POSIX API and another Zephyr subsystem both rely on a feature, the implementation of + that feature should be as a separate Zephyr library that can be used by both the POSIX API and + the other library or subsystem. This reduces the likelihood of dependency cycles in code. When + practical, that rule should expand to include macros. In the example below, ``libposix`` + depends on ``libzfoo`` for the implementation of some functionality "foo" in Zephyr. If + ``libzfoo`` also depends on ``libposix``, then there is a dependency cycle. The cycle can be + removed via mutual dependency, ``libcommon``. + +.. graphviz:: + :caption: Dependency cycle between POSIX and another Zephyr library + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + + libposix -> libzfoo; + libzfoo -> libposix; + } + +.. graphviz:: + :caption: Mutual dependencies between POSIX and other Zephyr libraries + + digraph { + node [shape=rect, style=rounded]; + rankdir=LR; + + libposix [fillcolor="#d5e8d4"]; + libzfoo [fillcolor="#dae8fc"]; + libcommon [fillcolor="#f8cecc"]; + + libposix -> libzfoo; + libposix -> libcommon; + libzfoo -> libcommon; + } + +- POSIX API calls should be provided as regular callable C functions; if a Zephyr + `System Call ` is needed as part of the implementation, the declaration and the + implementation of that system call should be hidden behind the POSIX API. diff --git a/doc/services/portability/posix/index.rst b/doc/services/portability/posix/index.rst new file mode 100644 index 00000000000..5fc5117df44 --- /dev/null +++ b/doc/services/portability/posix/index.rst @@ -0,0 +1,14 @@ +.. _posix_support: + +POSIX +##### + +.. toctree:: + :maxdepth: 2 + + overview/index.rst + conformance/index.rst + aep/index.rst + implementation/index.rst + option_groups/index.rst + kconfig/index.rst diff --git a/doc/services/portability/posix/kconfig/index.rst b/doc/services/portability/posix/kconfig/index.rst new file mode 100644 index 00000000000..0ce0e5bb4b4 --- /dev/null +++ b/doc/services/portability/posix/kconfig/index.rst @@ -0,0 +1,51 @@ +.. _posix_kconfig_options: + +Configuration Options +********************* + +This is a non-exhaustive list of specific :ref:`kconfig` options relating to Zephyr's +implementation of the POSIX API. + +* :kconfig:option:`CONFIG_EVENTFD` +* :kconfig:option:`CONFIG_EVENTFD_MAX` +* :kconfig:option:`CONFIG_FDTABLE` +* :kconfig:option:`CONFIG_FNMATCH` +* :kconfig:option:`CONFIG_GETOPT` +* :kconfig:option:`CONFIG_GETOPT_LONG` +* :kconfig:option:`CONFIG_MAX_PTHREAD_BARRIER_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_KEY_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_MUTEX_COUNT` +* :kconfig:option:`CONFIG_MAX_PTHREAD_SPINLOCK_COUNT` +* :kconfig:option:`CONFIG_MAX_TIMER_COUNT` +* :kconfig:option:`CONFIG_MQUEUE_NAMELEN_MAX` +* :kconfig:option:`CONFIG_MSG_COUNT_MAX` +* :kconfig:option:`CONFIG_MSG_SIZE_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETPAIR` +* :kconfig:option:`CONFIG_NET_SOCKETS` +* :kconfig:option:`CONFIG_NET_SOCKETS_POLL_MAX` +* :kconfig:option:`CONFIG_NET_SOCKETS_POSIX_NAMES` +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_POSIX_CLOCK` +* :kconfig:option:`CONFIG_POSIX_FS` +* :kconfig:option:`CONFIG_POSIX_LIMITS_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_MAX_FDS` +* :kconfig:option:`CONFIG_POSIX_MAX_OPEN_FILES` +* :kconfig:option:`CONFIG_POSIX_MQUEUE` +* :kconfig:option:`CONFIG_POSIX_RTSIG_MAX` +* :kconfig:option:`CONFIG_POSIX_SIGNAL` +* :kconfig:option:`CONFIG_POSIX_SIGNAL_STRING_DESC` +* :kconfig:option:`CONFIG_POSIX_UNAME` +* :kconfig:option:`CONFIG_POSIX_UNAME_NODENAME_LEN` +* :kconfig:option:`CONFIG_POSIX_UNAME_VERSION_LEN` +* :kconfig:option:`CONFIG_PTHREAD` +* :kconfig:option:`CONFIG_PTHREAD_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_COND` +* :kconfig:option:`CONFIG_PTHREAD_CREATE_BARRIER` +* :kconfig:option:`CONFIG_PTHREAD_IPC` +* :kconfig:option:`CONFIG_PTHREAD_KEY` +* :kconfig:option:`CONFIG_PTHREAD_MUTEX` +* :kconfig:option:`CONFIG_PTHREAD_RECYCLER_DELAY_MS` +* :kconfig:option:`CONFIG_PTHREAD_SPINLOCK` +* :kconfig:option:`CONFIG_SEM_VALUE_MAX` +* :kconfig:option:`CONFIG_TIMER` diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst new file mode 100644 index 00000000000..55b11d3da20 --- /dev/null +++ b/doc/services/portability/posix/option_groups/index.rst @@ -0,0 +1,517 @@ +.. _posix_option_groups: + +Subprofiling Option Groups +########################## + +.. _posix_option_group_threads_base: + +POSIX_THREADS_BASE +================== + +The basic assumption in this profile is that the system +consists of a single (implicit) process with multiple threads. Therefore, the +standard requires all basic thread services, except those related to +multiple processes. + +.. csv-table:: POSIX_THREADS_BASE + :header: API, Supported + :widths: 50,10 + + pthread_atfork(),yes + pthread_attr_destroy(),yes + pthread_attr_getdetachstate(),yes + pthread_attr_getschedparam(),yes + pthread_attr_init(),yes + pthread_attr_setdetachstate(),yes + pthread_attr_setschedparam(),yes + pthread_barrier_destroy(),yes + pthread_barrier_init(),yes + pthread_barrier_wait(),yes + pthread_barrierattr_destroy(),yes + pthread_barrierattr_getpshared(),yes + pthread_barrierattr_init(),yes + pthread_barrierattr_setpshared(),yes + pthread_cancel(),yes + pthread_cleanup_pop(),yes + pthread_cleanup_push(),yes + pthread_cond_broadcast(),yes + pthread_cond_destroy(),yes + pthread_cond_init(),yes + pthread_cond_signal(),yes + pthread_cond_timedwait(),yes + pthread_cond_wait(),yes + pthread_condattr_destroy(),yes + pthread_condattr_init(),yes + pthread_create(),yes + pthread_detach(),yes + pthread_equal(),yes + pthread_exit(),yes + pthread_getspecific(),yes + pthread_join(),yes + pthread_key_create(),yes + pthread_key_delete(),yes + pthread_kill(), + pthread_mutex_destroy(),yes + pthread_mutex_init(),yes + pthread_mutex_lock(),yes + pthread_mutex_trylock(),yes + pthread_mutex_unlock(),yes + pthread_mutexattr_destroy(),yes + pthread_mutexattr_init(),yes + pthread_once(),yes + pthread_self(),yes + pthread_setcancelstate(),yes + pthread_setcanceltype(),yes + pthread_setspecific(),yes + pthread_sigmask(),yes + pthread_testcancel(),yes + +.. _posix_option_group_posix_threads_ext: + +POSIX_THREADS_EXT +================= + +This table lists service support status in Zephyr: + +.. csv-table:: POSIX_THREADS_EXT + :header: API, Supported + :widths: 50,10 + + pthread_attr_getguardsize(),yes + pthread_attr_setguardsize(),yes + pthread_mutexattr_gettype(),yes + pthread_mutexattr_settype(),yes + +.. _posix_option_group_xsi_threads_ext: + +XSI_THREADS_EXT +=============== + +The XSI_THREADS_EXT option group is required because it provides +functions to control a thread's stack. This is considered useful for any +real-time application. + +This table lists service support status in Zephyr: + +.. csv-table:: XSI_THREADS_EXT + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstack(),yes + pthread_attr_setstack(),yes + pthread_getconcurrency(),yes + pthread_setconcurrency(),yes + +.. _posix_option_group_c_lang_jump: + +POSIX_C_LANG_JUMP +================= + +The ``POSIX_C_LANG_JUMP`` Option Group is included in the ISO C standard. + +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the + ``POSIX_C_LANG_JUMP`` Option Group is considered supported. + +.. csv-table:: POSIX_C_LANG_JUMP + :header: API, Supported + :widths: 50,10 + + setjmp(), yes + longjmp(), yes + +.. _posix_option_group_c_lang_math: + +POSIX_C_LANG_MATH +================= + +The ``POSIX_C_LANG_MATH`` Option Group is included in the ISO C standard. + +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the + ``POSIX_C_LANG_MATH`` Option Group is considered supported. + +Please refer to `Subprofiling Considerations`_ for details on the ``POSIX_C_LANG_MATH`` Option +Group. + +.. _posix_option_group_c_lang_support: + +POSIX_C_LANG_SUPPORT +==================== + +The POSIX_C_LANG_SUPPORT option group contains the general ISO C Library. + +.. note:: + When using Newlib, Picolibc, or other C libraries conforming to the ISO C Standard, the entire + ``POSIX_C_LANG_SUPPORT`` Option Group is considered supported. + +Please refer to `Subprofiling Considerations`_ for details on the ``POSIX_C_LANG_SUPPORT`` Option +Group. + +For more information on developing Zephyr applications in the C programming language, please refer +to :ref:`details`. + +.. _posix_option_group_single_process: + +POSIX_SINGLE_PROCESS +==================== + +The POSIX_SINGLE_PROCESS option group contains services for single +process applications. + +.. csv-table:: POSIX_SINGLE_PROCESS + :header: API, Supported + :widths: 50,10 + + confstr(), + environ, + errno,yes + getenv(), + setenv(), + sysconf(),yes + uname(),yes + unsetenv() + +.. _posix_option_group_signals: + +POSIX_SIGNALS +============= + +Signal services are a basic mechanism within POSIX-based systems and are +required for error and event handling. + +.. csv-table:: POSIX_SIGNALS + :header: API, Supported + :widths: 50,10 + + abort(),yes + alarm(), + kill(), + pause(), + raise(), + sigaction(), + sigaddset(),yes + sigdelset(),yes + sigemptyset(),yes + sigfillset(),yes + sigismember(),yes + signal(), + sigpending(), + sigprocmask(),yes + sigsuspend(), + sigwait(), + strsignal(),yes + +.. _posix_option_group_device_io: + +POSIX_DEVICE_IO +=============== + +.. csv-table:: POSIX_DEVICE_IO + :header: API, Supported + :widths: 50,10 + + FD_CLR(),yes + FD_ISSET(),yes + FD_SET(),yes + FD_ZERO(),yes + clearerr(),yes + close(),yes + fclose(), + fdopen(), + feof(), + ferror(), + fflush(), + fgetc(), + fgets(), + fileno(), + fopen(), + fprintf(),yes + fputc(),yes + fputs(),yes + fread(), + freopen(), + fscanf(), + fwrite(),yes + getc(), + getchar(), + gets(), + open(),yes + perror(),yes + poll(),yes + printf(),yes + pread(), + pselect(), + putc(),yes + putchar(),yes + puts(),yes + pwrite(), + read(),yes + scanf(), + select(),yes + setbuf(), + setvbuf(), + stderr, + stdin, + stdout, + ungetc(), + vfprintf(),yes + vfscanf(), + vprintf(),yes + vscanf(), + write(),yes + +.. _posix_option_group_barriers: + +POSIX_BARRIERS +============== + +.. csv-table:: POSIX_BARRIERS + :header: API, Supported + :widths: 50,10 + + pthread_barrier_destroy(),yes + pthread_barrier_init(),yes + pthread_barrier_wait(),yes + pthread_barrierattr_destroy(),yes + pthread_barrierattr_init(),yes + +.. _posix_option_group_clock_selection: + +POSIX_CLOCK_SELECTION +===================== + +.. csv-table:: POSIX_CLOCK_SELECTION + :header: API, Supported + :widths: 50,10 + + pthread_condattr_getclock(),yes + pthread_condattr_setclock(),yes + clock_nanosleep(),yes + +.. _posix_option_group_semaphores: + +POSIX_SEMAPHORES +================ + +.. csv-table:: POSIX_SEMAPHORES + :header: API, Supported + :widths: 50,10 + + sem_close(),yes + sem_destroy(),yes + sem_getvalue(),yes + sem_init(),yes + sem_open(),yes + sem_post(),yes + sem_trywait(),yes + sem_unlink(),yes + sem_wait(),yes + +.. _posix_option_group_spin_locks: + +POSIX_SPIN_LOCKS +================ + +.. csv-table:: POSIX_SPIN_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_spin_destroy(),yes + pthread_spin_init(),yes + pthread_spin_lock(),yes + pthread_spin_trylock(),yes + pthread_spin_unlock(),yes + +.. _posix_option_group_timers: + +POSIX_TIMERS +============ + +.. csv-table:: POSIX_TIMERS + :header: API, Supported + :widths: 50,10 + + clock_getres(), + clock_gettime(),yes + clock_settime(),yes + nanosleep(),yes + timer_create(),yes + timer_delete(),yes + timer_gettime(),yes + timer_getoverrun(),yes + timer_settime(),yes + + +.. _posix_options: + +Additional POSIX Options +======================== + +.. _posix_option_message_passing: + +_POSIX_MESSAGE_PASSING +++++++++++++++++++++++ + +.. csv-table:: _POSIX_MESSAGE_PASSING + :header: API, Supported + :widths: 50,10 + + mq_close(),yes + mq_getattr(),yes + mq_notify(),yes + mq_open(),yes + mq_receive(),yes + mq_send(),yes + mq_setattr(),yes + mq_unlink(),yes + +_POSIX_PRIORITY_SCHEDULING +++++++++++++++++++++++++++ + +.. _posix_option_priority_scheduling: + +.. csv-table:: _POSIX_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + sched_get_priority_max(),yes + sched_get_priority_min(),yes + sched_getparam(),yes + sched_getscheduler(),yes + sched_rr_get_interval(),yes + sched_setparam(),yes + sched_setscheduler(),yes + sched_yield(),yes + +.. _posix_option_reader_writer_locks: + +_POSIX_READER_WRITER_LOCKS +++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_READER_WRITER_LOCKS + :header: API, Supported + :widths: 50,10 + + pthread_rwlock_destroy(),yes + pthread_rwlock_init(),yes + pthread_rwlock_rdlock(),yes + pthread_rwlock_tryrdlock(),yes + pthread_rwlock_trywrlock(),yes + pthread_rwlock_unlock(),yes + pthread_rwlock_wrlock(),yes + pthread_rwlockattr_destroy(),yes + pthread_rwlockattr_getpshared(), + pthread_rwlockattr_init(),yes + pthread_rwlockattr_setpshared(), + +.. _posix_option_thread_attr_stackaddr: + +_POSIX_THREAD_ATTR_STACKADDR +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKADDR + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstackaddr(),yes + pthread_attr_setstackaddr(),yes + +.. _posix_option_thread_attr_stacksize: + +_POSIX_THREAD_ATTR_STACKSIZE +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_ATTR_STACKSIZE + :header: API, Supported + :widths: 50,10 + + pthread_attr_getstacksize(),yes + pthread_attr_setstacksize(),yes + +.. _posix_option_thread_priority_scheduling: + +_POSIX_THREAD_PRIORITY_SCHEDULING ++++++++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_PRIORITY_SCHEDULING + :header: API, Supported + :widths: 50,10 + + pthread_attr_getinheritsched(), + pthread_attr_getschedpolicy(),yes + pthread_attr_getscope(), + pthread_attr_setinheritsched(), + pthread_attr_setschedpolicy(),yes + pthread_attr_setscope(), + pthread_getschedparam(),yes + pthread_setschedparam(),yes + pthread_setschedprio(),yes + +.. _posix_thread_safe_functions: + +_POSIX_THREAD_SAFE_FUNCTIONS +++++++++++++++++++++++++++++ + +.. csv-table:: _POSIX_THREAD_SAFE_FUNCTIONS + :header: API, Supported + :widths: 50,10 + + asctime_r(), + ctime_r(), + flockfile(), + ftrylockfile(), + funlockfile(), + getc_unlocked(), yes + getchar_unlocked(), yes + getgrgid_r(), + getgrnam_r(), + getpwnam_r(), + getpwuid_r(), + gmtime_r(), yes + localtime_r(), + putc_unlocked(), yes + putchar_unlocked(), yes + rand_r(), yes + readdir_r(), + strerror_r(), yes + strtok_r(), yes + +.. _posix_option_timeouts: + +_POSIX_TIMEOUTS ++++++++++++++++ + +.. csv-table:: _POSIX_TIMEOUTS + :header: API, Supported + :widths: 50,10 + + mq_timedreceive(),yes + mq_timedsend(),yes + pthread_mutex_timedlock(),yes + pthread_rwlock_timedrdlock(),yes + pthread_rwlock_timedwrlock(),yes + sem_timedwait(),yes + posix_trace_timedgetnext_event(), + +.. _posix_option_xopen_streams: + +_XOPEN_STREAMS +++++++++++++++ + +.. csv-table:: _XOPEN_STREAMS + :header: API, Supported + :widths: 50,10 + + fattach(), + fdetach(), + getmsg(), + getpmsg(), + ioctl(),yes + isastream(), + putmsg(), + putpmsg(), + + +.. _Subprofiling Considerations: + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html diff --git a/doc/services/portability/posix/overview/index.rst b/doc/services/portability/posix/overview/index.rst new file mode 100644 index 00000000000..4ef1f9a596d --- /dev/null +++ b/doc/services/portability/posix/overview/index.rst @@ -0,0 +1,138 @@ +.. _posix_overview: + +Overview +######## + +The Portable Operating System Interface (POSIX) is a family of standards specified by the +`IEEE Computer Society`_ for maintaining compatibility between operating systems. Zephyr +implements a subset of the standard POSIX API specified by `IEEE 1003.1-2017`_ (also known as +POSIX-1.2017). + +.. figure:: posix.svg + :align: center + :alt: POSIX Support in Zephyr + + POSIX support in Zephyr + +.. note:: + This page does not document Zephyr's :ref:`POSIX architecture`, which is used to + run Zephyr as a native application under the host operating system for prototyping, + test, and diagnostic purposes. + +With the POSIX support available in Zephyr, an existing POSIX conformant +application can be ported to run on the Zephyr kernel, and therefore leverage +Zephyr features and functionality. Additionally, a library designed to be +POSIX conformant can be ported to Zephyr kernel based applications with no changes. + +The POSIX API is an increasingly popular OSAL (operating system abstraction layer) for IoT and +embedded applications, as can be seen in Zephyr, AWS:FreeRTOS, TI-RTOS, and NuttX. + +Benefits of POSIX support in Zephyr include: + +- Offering a familiar API to non-embedded programmers, especially from Linux +- Enabling reuse (portability) of existing libraries based on POSIX APIs +- Providing an efficient API subset appropriate for small (MCU) embedded systems + +.. _posix_subprofiles: + +POSIX Subprofiles +================= + +While Zephyr supports running multiple `threads ` (possibly in an `SMP ` +configuration), as well as `Virtual Memory and MMUs `, Zephyr code and data +normally share a common address space. The Zephyr kernel executable code and the application +executable code are typically compiled into the same binary artifact. From that perspective, Zephyr +apps can be seen as running in the context of a single process. + +While multi-purpose operating systems (OS) offer full POSIX conformance, Real-Time Operating +Systems (RTOS) such as Zephyr typically serve a fixed-purpose, have limited hardware resources, +and experience limited user interaction. In such systems, full POSIX conformance can be +impractical and unnecessary. + +For that reason, POSIX defined the following :ref:`Application Environment Profiles (AEP)` +as part of `IEEE 1003.13-2003`_ (also known as POSIX.13-2003). + +* Minimal Realtime System Profile (:ref:`PSE51 `) +* Realtime Controller System Profile (:ref:`PSE52 `) +* Dedicated Realtime System Profile (:ref:`PSE53 `) +* Multi-Purpose Realtime System (PSE54) + +POSIX.13-2003 AEP were formalized in 2003 via "Units of Functionality" but the specification is now +inactive (for reference only). Nevertheless, the intent is still captured as part of POSIX-1.2017 +via :ref:`Options` and :ref:`Option Groups`. + +For more information, please see `IEEE 1003.1-2017, Section E, Subprofiling Considerations`_. + +.. _posix_apps: + +POSIX Applications in Zephyr +============================ + +A POSIX app in Zephyr is :ref:`built like any other app` and therefore requires the +usual :file:`prj.conf`, :file:`CMakeLists.txt`, and source code. For example, the app below +leverages the ``nanosleep()`` and ``perror()`` POSIX functions. + +.. code-block:: cfg + :caption: `prj.conf` for a simple POSIX app in Zephyr + + CONFIG_POSIX_API=y + +.. code-block:: c + :caption: A simple app that uses Zephyr's POSIX API + + #include + #include + #include + + void megasleep(size_t megaseconds) + { + struct timespec ts = { + .tv_sec = megaseconds * 1000000, + .tv_nsec = 0, + }; + + printf("See you in a while!\n"); + if (nanosleep(&ts, NULL) == -1) { + perror("nanosleep"); + } + } + + int main() + { + megasleep(42); + return 0; + } + +For more examples of POSIX applications, please see the :ref:`POSIX sample applications`. + +.. _posix_config: + +Configuration +============= + +Like most features in Zephyr, POSIX features are +:ref:`highly configurable` but disabled by default. Users must +explicitly choose to enable POSIX options via :ref:`Kconfig` selection. Indeed, there are +:ref:`many Kconfig options in Zephyr` for the POSIX API to allow for +feature selection at various levels of granularity. + +Alternatively, users may enable one of the Kconfig options below as a shortcut to enable multiple +:ref:`Option Groups`. + +* :kconfig:option:`CONFIG_POSIX_API` +* :kconfig:option:`CONFIG_PTHREAD_IPC` + +.. note:: + Since the POSIX environment in Zephyr is fully configurable via :ref:`Kconfig`, + configurations that require modifying features should not be made if strict compliance is + required (POSIX-1.2017, section 2.1.3.1). + +.. + TODO: create Kconfig shortcuts for PSE51, PSE52, and PSE53 + +.. _IEEE: https://www.ieee.org/ +.. _IEEE Computer Society: https://www.computer.org/ +.. _IEEE 1003.1-2017: https://standards.ieee.org/ieee/1003.1/7101/ +.. _IEEE 1003.13-2003: https://standards.ieee.org/ieee/1003.13/3322/ +.. _IEEE 1003.1-2017, Section E, Subprofiling Considerations: + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html diff --git a/doc/services/portability/posix/overview/posix.svg b/doc/services/portability/posix/overview/posix.svg new file mode 100644 index 00000000000..a62be70994e --- /dev/null +++ b/doc/services/portability/posix/overview/posix.svg @@ -0,0 +1,2 @@ + +
Hardware
Hardware
BSP
BSP
Zephyr Kernel
Zephyr Kernel
POSIX PSE51
POSIX PSE51
File System
File System
POSIX PSE52
POSIX PSE52
Networking
Networking
POSIX PSE53
POSIX PSE53
 Middleware
 Middleware
Application
Application
\ No newline at end of file diff --git a/doc/services/rtio/index.rst b/doc/services/rtio/index.rst index 88c5f29a075..df6e75d7702 100644 --- a/doc/services/rtio/index.rst +++ b/doc/services/rtio/index.rst @@ -178,7 +178,7 @@ by calling :c:func:`rtio_sqe_rx_buf` like so: } Finally, the consumer will be able to access the allocated buffer via -c:func:`rtio_cqe_get_mempool_buffer`. +:c:func:`rtio_cqe_get_mempool_buffer`. .. code-block:: C diff --git a/doc/services/shell/index.rst b/doc/services/shell/index.rst index 7f8f6f0fd57..504bef139fe 100644 --- a/doc/services/shell/index.rst +++ b/doc/services/shell/index.rst @@ -654,7 +654,7 @@ RTT Backend Channel Selection ***************************** Instead of using the shell as a logger backend, RTT shell backend and RTT log -backend can also be used simulatenously, but over different channels. By +backend can also be used simultaneously, but over different channels. By separating them, the log can be captured or monitored without shell output or the shell may be scripted without log interference. Enabling both the Shell RTT backend and the Log RTT backend does not work by default, because both default diff --git a/doc/services/storage/disk/nvme.rst b/doc/services/storage/disk/nvme.rst index 4f8f94818f2..efb6a3d7e1f 100644 --- a/doc/services/storage/disk/nvme.rst +++ b/doc/services/storage/disk/nvme.rst @@ -36,18 +36,13 @@ NVMe configuration DTS === -Any board exposing an NVMe disk should provide a DTS overlay to enable its use whitin Zephyr +Any board exposing an NVMe disk should provide a DTS overlay to enable its use within Zephyr .. code-block:: devicetree #include / { pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - nvme0: nvme0 { compatible = "nvme-controller"; vendor-id = ; diff --git a/doc/services/tfm/overview.rst b/doc/services/tfm/overview.rst index 7b2f8db51de..ef71b53a113 100644 --- a/doc/services/tfm/overview.rst +++ b/doc/services/tfm/overview.rst @@ -8,7 +8,7 @@ It defines and implements an architecture and a set of software components that aim to address some of the main security concerns in IoT products. Zephyr RTOS has been PSA Certified since Zephyr 2.0.0 with TF-M 1.0, and -is currently integrated with TF-M 1.8.0. +is currently integrated with TF-M 2.0.0. What Does TF-M Offer? ********************* diff --git a/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg b/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg new file mode 100644 index 00000000000..fcd9f64c581 --- /dev/null +++ b/doc/services/zbus/images/zbus_publishing_process_example_HLP.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/services/zbus/index.rst b/doc/services/zbus/index.rst index ca8ab6142a8..7d69835c954 100644 --- a/doc/services/zbus/index.rst +++ b/doc/services/zbus/index.rst @@ -56,12 +56,10 @@ The bus comprises: ZBus anatomy. The bus makes the publish, read, claim, finish, notify, and subscribe actions available over -channels. Publishing, reading, claiming, and finishing are available in all RTOS thread contexts. -However, it cannot run inside Interrupt Service Routines (ISR) because it uses mutexes to control -channel access, and mutexes cannot work appropriately inside ISRs. The publish and read operations -are simple and fast; the procedure is a mutex locking followed by a memory copy to and from a shared -memory region and then a mutex unlocking. Another essential aspect of zbus is the observers. There -are three types of observers: +channels. Publishing, reading, claiming, and finishing are available in all RTOS thread contexts, +including ISRs. The publish and read operations are simple and fast; the procedure is channel +locking followed by a memory copy to and from a shared memory region and then a channel unlocking. +Another essential aspect of zbus is the observers. There are three types of observers: .. figure:: images/zbus_type_of_observers.svg :alt: ZBus observers type @@ -146,12 +144,12 @@ the solutions that can be done with zbus and make it a good fit as an open-sourc Virtual Distributed Event Dispatcher ==================================== -The VDED execution always happens in the publishing's (thread) context. So it cannot occur inside an -Interrupt Service Routine (ISR). Therefore, the IRSs must only access channels indirectly. The basic -description of the execution is as follows: +The VDED execution always happens in the publisher's context. It can be a thread or an ISR. Be +careful with publications inside ISR because the scheduler won't preempt the VDED. Use that wisely. +The basic description of the execution is as follows: -* The channel mutex is acquired; +* The channel lock is acquired; * The channel receives the new message via direct copy (by a raw :c:func:`memcpy`); * The event dispatcher logic executes the listeners, sends a copy of the message to the message subscribers, and pushes the channel's reference to the subscribers' notification message queue in @@ -216,7 +214,7 @@ priority. * - a - T1 starts and, at some point, publishes to channel A. * - b - - The publishing (VDED) process starts. The VDED locks the channel A's mutex. + - The publishing (VDED) process starts. The VDED locks the channel A. * - c - The VDED copies the T1 message to the channel A message. @@ -273,7 +271,7 @@ Thus, the table below describes the activities (represented by a letter) of the * - a - T1 starts and, at some point, publishes to channel A. * - b - - The publishing (VDED) process starts. The VDED locks the channel A's mutex. + - The publishing (VDED) process starts. The VDED locks the channel A. * - c - The VDED copies the T1 message to the channel A message. @@ -291,13 +289,7 @@ Thus, the table below describes the activities (represented by a letter) of the After that, the T1 regain MCU. * - h - - The VDED pushes the notification message to the queue of S1. Notice the thread gets ready to - execute right after receiving the notification. However, it goes to a pending state because - it cannot access the channel since it is still locked. At that moment, the T1 thread gets its - priority elevated (priority inheritance due to the mutex) to the highest pending thread - (caused by channel A unavailability). In that case, S1's priority. It ensures the T1 will - finish the VDED execution as quickly as possible without preemption from threads with - priority below the engaged ones. + - The VDED pushes the notification message to the queue of S1. * - i - VDED finishes the publishing by unlocking channel A. @@ -308,6 +300,81 @@ Thus, the table below describes the activities (represented by a letter) of the (as simple as lock, memory copy, unlock), continues its execution, and goes out the CPU. +HLP priority boost +------------------ +ZBus implements the Highest Locker Protocol that relies on the observers' thread priority to +determine a temporary publisher priority. The protocol considers the channel's Highest Observer +Priority (HOP); even if the observer is not waiting for a message on the channel, it is considered +in the calculation. The VDED will elevate the publisher's priority based on the HOP to ensure small +latency and as few preemptions as possible. + +.. note:: + The priority boost is enabled by default. To deactivate it, you must set the + :kconfig:option:`CONFIG_ZBUS_PRIORITY_BOOST` configuration. + +.. warning:: + ZBus priority boost does not consider runtime observers on the HOP calculations. + +The figure below illustrates the actions performed during the VDED execution when T1 publishes to +channel A. The scenario considers the priority boost feature and the following priorities: T1 < MS1 +< MS2 < S1. + +.. figure:: images/zbus_publishing_process_example_HLP.svg + :alt: ZBus publishing process details using priority boost. + :width: 85% + + ZBus VDED execution detail with priority boost enabled and for priority T1 < MS1 < MS2 < S1. + +To properly use the priority boost, attaching the observer to a thread is necessary. When the +subscriber is attached to a thread, it assumes its priority, and the priority boost algorithm will +consider the observer's priority. The following code illustrates the thread-attaching function. + + +.. code-block:: c + :emphasize-lines: 10 + + ZBUS_SUBSCRIBER_DEFINE(s1, 4); + void s1_thread(void *ptr1, void *ptr2, void *ptr3) + { + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + + zbus_obs_attach_to_thread(&s1); + + while (1) { + zbus_sub_wait(&s1, &chan, K_FOREVER); + + /* Subscriber implementation */ + + } + } + K_THREAD_DEFINE(s1_id, CONFIG_MAIN_STACK_SIZE, s1_thread, NULL, NULL, NULL, 2, 0, 0); + +On the above code, the :c:func:`zbus_obs_attach_to_thread` will set the ``s1`` observer with +priority two as the thread has that priority. It is possible to reverse that by detaching the +observer using the :c:func:`zbus_obs_detach_from_thread`. Only enabled observers and observations +will be considered on the channel HOP calculation. Masking a specific observation of a channel will +affect the channel HOP. + +In summary, the benefits of the feature are: + +* The HLP is more effective for zbus than the mutexes priority inheritance; +* No bounded priority inversion will happen among the publisher and the observers; +* No other threads (that are not involved in the communication) with priority between T1 and S1 can + preempt T1, avoiding unbounded priority inversion; +* Message subscribers will wait for the VDED to finish the message delivery process. So the VDED + execution will be faster and more consistent; +* The HLP priority is dynamic and can change in execution; +* ZBus operations can be used inside ISRs; +* The priority boosting feature can be turned off, and plain semaphores can be used as the channel + lock mechanism; +* The Highest Locker Protocol's major disadvantage, the Inheritance-related Priority Inversion, is + acceptable in the zbus scenario since it will ensure a small bus latency. + + Limitations =========== @@ -335,7 +402,7 @@ rate by following design tips: subscribers. So, chose carefully the configurations :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE` and :kconfig:option:`CONFIG_HEAP_MEM_POOL_SIZE`. They are crucial to a proper VDED execution - (delivery garantee) considering message subscribers. + (delivery guarantee) considering message subscribers. .. warning:: Subscribers will receive only the reference of the changing channel. A data loss may be perceived @@ -424,8 +491,11 @@ exchanges accelerometer data, for example. K_THREAD_DEFINE(subscriber_task_id, 512, subscriber_task, NULL, NULL, NULL, 3, 0, 0); ZBUS_MSG_SUBSCRIBER_DEFINE(my_msg_subscriber); - static void msg_subscriber_task(void *sub) + static void msg_subscriber_task(void *ptr1, void *ptr2, void *ptr3) { + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); const struct zbus_channel *chan; struct acc_msg acc = {0}; @@ -505,7 +575,7 @@ sample, it's OK to use stack allocated messages since VDED copies the data inter zbus_chan_pub(&acc_chan, &acc1, K_SECONDS(1)); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. .. _reading from a channel: @@ -522,7 +592,7 @@ read the message. Otherwise, the operation fails. zbus_chan_read(&acc_chan, &acc, K_MSEC(500)); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. .. warning:: Choose the timeout of :c:func:`zbus_chan_read` after receiving a notification from @@ -545,7 +615,7 @@ exchange. See the code example under `Claim and finish a channel`_ where this ma zbus_chan_notify(&acc_chan, K_NO_WAIT); .. warning:: - Do not use this function inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. Declaring channels and observers ================================ @@ -665,7 +735,7 @@ Listeners message access ------------------------ For performance purposes, listeners can access the receiving channel message directly since they -already have the mutex lock for it. To access the channel's message, the listener should use the +already have the channel locked for it. To access the channel's message, the listener should use the :c:func:`zbus_chan_const_msg` because the channel passed as an argument to the listener function is a constant pointer to the channel. The const pointer return type tells developers not to modify the message. @@ -706,7 +776,7 @@ channel, all the actions are available again. inconsistencies and scheduling issues. .. warning:: - Do not use these functions inside an ISR. + Only use this function inside an ISR with a :c:macro:`K_NO_WAIT` timeout. The following code builds on the examples above and claims the ``acc_chan`` to set the ``user_data`` to the channel. Suppose we would like to count how many times the channels exchange messages. We @@ -763,9 +833,9 @@ following example illustrates the runtime registration usage. void thread_entry(void) { // ... /* Adding the observer to channel chan1 */ - zbus_chan_add_obs(&chan1, &my_listener); + zbus_chan_add_obs(&chan1, &my_listener, K_NO_WAIT); /* Removing the observer from channel chan1 */ - zbus_chan_rm_obs(&chan1, &my_listener); + zbus_chan_rm_obs(&chan1, &my_listener, K_NO_WAIT); Samples @@ -785,6 +855,8 @@ available: a host via serial; * :zephyr:code-sample:`zbus-remote-mock` illustrates how to implement an external mock (on the host) to send and receive messages to and from the bus; +* :zephyr:code-sample:`zbus-priority-boost` illustrates zbus priority boost feature with a priority + inversion scenario; * :zephyr:code-sample:`zbus-runtime-obs-registration` illustrates a way of using the runtime observer registration feature; * :zephyr:code-sample:`zbus-confirmed-channel` implements a way of implement confirmed channel only @@ -813,6 +885,7 @@ For enabling zbus, it is necessary to enable the :kconfig:option:`CONFIG_ZBUS` o Related configuration options: +* :kconfig:option:`CONFIG_ZBUS_PRIORITY_BOOST` zbus Highest Locker Protocol implementation; * :kconfig:option:`CONFIG_ZBUS_CHANNELS_SYS_INIT_PRIORITY` determine the :c:macro:`SYS_INIT` priority used by zbus to organize the channels observations by channel; * :kconfig:option:`CONFIG_ZBUS_CHANNEL_NAME` enables the name of channels to be available inside the @@ -820,9 +893,9 @@ Related configuration options: * :kconfig:option:`CONFIG_ZBUS_OBSERVER_NAME` enables the name of observers to be available inside the channels metadata; * :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER` enables the message subscriber observer type; -* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC` uses the heap to allocate message +* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC` uses the heap to allocate message buffers; -* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC` uses the stack to allocate message +* :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC` uses the stack to allocate message buffers; * :kconfig:option:`CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_POOL_SIZE` the available number of message buffers to be used simultaneously; diff --git a/doc/zephyr.doxyfile.in b/doc/zephyr.doxyfile.in index 1f8a6af46c4..29b4651765b 100644 --- a/doc/zephyr.doxyfile.in +++ b/doc/zephyr.doxyfile.in @@ -286,6 +286,7 @@ ALIASES = "rst=\verbatim embed:rst:leading-asterisk" \ "isr_ok=\htmlonly isr-ok \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_isr-ok` \endxmlonly" \ "pre_kernel_ok=\htmlonly pre-kernel-ok \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_pre-kernel-ok` \endxmlonly" \ "async=\htmlonly async \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_async` \endxmlonly" \ + "atomic_api=As for all atomic APIs, includes a full/sequentially-consistent memory barrier (where applicable)." \ "supervisor=\htmlonly supervisor \endhtmlonly \xmlonly embed:rst:inline :ref:`api_term_supervisor` \endxmlonly" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources @@ -923,6 +924,9 @@ WARN_LOGFILE = INPUT = @ZEPHYR_BASE@/doc/_doxygen/mainpage.md \ @ZEPHYR_BASE@/doc/_doxygen/groups.dox \ @ZEPHYR_BASE@/kernel/include/kernel_arch_interface.h \ + @ZEPHYR_BASE@/include/zephyr/arch/cache.h \ + @ZEPHYR_BASE@/include/zephyr/sys/arch_interface.h \ + @ZEPHYR_BASE@/include/zephyr/sys/atomic.h \ @ZEPHYR_BASE@/include/ \ @ZEPHYR_BASE@/lib/libc/minimal/include/ \ @ZEPHYR_BASE@/subsys/testsuite/include/ \ @@ -2395,6 +2399,7 @@ PREDEFINED = __DOXYGEN__ \ XEN_GUEST_HANDLE_64(x)= \ _LINKER \ __deprecated= \ + __sparse_cache= \ __packed= \ __aligned(x)= \ __attribute_nonnull(...)= \ diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 6310146bb3d..f0236ef653a 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -56,6 +56,7 @@ add_subdirectory_ifdef(CONFIG_MBOX mbox) add_subdirectory_ifdef(CONFIG_MDIO mdio) add_subdirectory_ifdef(CONFIG_MEMC memc) add_subdirectory_ifdef(CONFIG_MFD mfd) +add_subdirectory_ifdef(CONFIG_MIPI_DBI mipi_dbi) add_subdirectory_ifdef(CONFIG_MIPI_DSI mipi_dsi) add_subdirectory_ifdef(CONFIG_MM_DRV mm) add_subdirectory_ifdef(CONFIG_MODEM modem) diff --git a/drivers/Kconfig b/drivers/Kconfig index 45b03e4829c..ac07add3c1f 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -52,6 +52,7 @@ source "drivers/mbox/Kconfig" source "drivers/mdio/Kconfig" source "drivers/memc/Kconfig" source "drivers/mfd/Kconfig" +source "drivers/mipi_dbi/Kconfig" source "drivers/mipi_dsi/Kconfig" source "drivers/misc/Kconfig" source "drivers/mm/Kconfig" diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 34536f4c4e0..808fb1a6698 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -48,3 +48,4 @@ zephyr_library_sources_ifdef(CONFIG_ADC_MAX1125X adc_max1125x.c) zephyr_library_sources_ifdef(CONFIG_ADC_MAX11102_17 adc_max11102_17.c) zephyr_library_sources_ifdef(CONFIG_ADC_AD5592 adc_ad5592.c) zephyr_library_sources_ifdef(CONFIG_ADC_LTC2451 adc_ltc2451.c) +zephyr_library_sources_ifdef(CONFIG_ADC_NUMAKER adc_numaker.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 6dd41582bd0..721de86c98f 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -119,4 +119,6 @@ source "drivers/adc/Kconfig.ad5592" source "drivers/adc/Kconfig.ltc2451" +source "drivers/adc/Kconfig.numaker" + endif # ADC diff --git a/drivers/adc/Kconfig.numaker b/drivers/adc/Kconfig.numaker new file mode 100644 index 00000000000..ea5f1288beb --- /dev/null +++ b/drivers/adc/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER ADC Driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +config ADC_NUMAKER + bool "Nuvoton NuMaker MCU ADC driver" + default y + select HAS_NUMAKER_ADC + depends on DT_HAS_NUVOTON_NUMAKER_ADC_ENABLED + help + This option enables the ADC driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker ADC. diff --git a/drivers/adc/Kconfig.stm32 b/drivers/adc/Kconfig.stm32 index f185e7664b6..4672a6396a4 100644 --- a/drivers/adc/Kconfig.stm32 +++ b/drivers/adc/Kconfig.stm32 @@ -23,15 +23,4 @@ config ADC_STM32_DMA Enable the ADC DMA mode for ADC instances that enable dma channels in their device tree node. -if SOC_SERIES_STM32F2X || (SOC_SERIES_STM32F3X && !SOC_STM32F373XC) || SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32G4X - -config ADC_STM32_SHARED_IRQS - bool "STM32 ADC shared interrupts" - default y - depends on ADC_STM32 && !ADC_STM32_DMA - help - Enable the use of shared interrupts for families that only have a single interrupt for all ADC's - -endif - endif diff --git a/drivers/adc/Kconfig.tla2021 b/drivers/adc/Kconfig.tla2021 index fff48ed82af..9c09b74536e 100644 --- a/drivers/adc/Kconfig.tla2021 +++ b/drivers/adc/Kconfig.tla2021 @@ -13,7 +13,7 @@ if ADC_TLA2021 config ADC_TLA2021_INIT_PRIORITY int "Priority for the driver initialization" - default ADC_INIT_PRIORITY + default 80 help Fine tune the priority for the driver initialization. Make sure it's higher (-> lower priority) than I2C_INIT_PRIORITY. diff --git a/drivers/adc/adc_ad5592.c b/drivers/adc/adc_ad5592.c index 422fd549868..69f7b773258 100644 --- a/drivers/adc/adc_ad5592.c +++ b/drivers/adc/adc_ad5592.c @@ -245,7 +245,7 @@ static const struct adc_driver_api adc_ad5592_api = { .mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ }; \ \ - struct adc_ad5592_data adc_ad5592_data##inst; \ + static struct adc_ad5592_data adc_ad5592_data##inst; \ \ DEVICE_DT_INST_DEFINE(inst, adc_ad5592_init, NULL, \ &adc_ad5592_data##inst, &adc_ad5592_config##inst, \ diff --git a/drivers/adc/adc_ads114s0x.c b/drivers/adc/adc_ads114s0x.c index e5ab699bcbd..936aecf6f1a 100644 --- a/drivers/adc/adc_ads114s0x.c +++ b/drivers/adc/adc_ads114s0x.c @@ -23,15 +23,15 @@ LOG_MODULE_REGISTER(ads114s0x, CONFIG_ADC_LOG_LEVEL); -#define ADS114S0X_CLK_FREQ_IN_KHZ 4096 -#define ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 +#define ADS114S0X_CLK_FREQ_IN_KHZ 4096 +#define ADS114S0X_RESET_LOW_TIME_IN_CLOCK_CYCLES 4 #define ADS114S0X_START_SYNC_PULSE_DURATION_IN_CLOCK_CYCLES 4 -#define ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 -#define ADS114S0X_INPUT_SELECTION_AINCOM 12 -#define ADS114S0X_RESOLUTION 16 -#define ADS114S0X_REF_INTERNAL 2500 -#define ADS114S0X_GPIO_MAX 3 -#define ADS114S0X_POWER_ON_RESET_TIME_IN_US 2200 +#define ADS114S0X_SETUP_TIME_IN_CLOCK_CYCLES 32 +#define ADS114S0X_INPUT_SELECTION_AINCOM 12 +#define ADS114S0X_RESOLUTION 16 +#define ADS114S0X_REF_INTERNAL 2500 +#define ADS114S0X_GPIO_MAX 3 +#define ADS114S0X_POWER_ON_RESET_TIME_IN_US 2200 /* Not mentioned in the datasheet, but instead determined experimentally. */ #define ADS114S0X_RESET_DELAY_TIME_SAFETY_MARGIN_IN_US 1000 @@ -94,7 +94,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_ID_DEV_ID_POS, \ ADS114S0X_REGISTER_ID_DEV_ID_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_POR_POS 7 +#define ADS114S0X_REGISTER_STATUS_FL_POR_POS 7 #define ADS114S0X_REGISTER_STATUS_FL_POR_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) @@ -102,7 +102,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_POR_POS, \ ADS114S0X_REGISTER_STATUS_FL_POR_LENGTH) #define ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_NOT_RDY_POS 6 +#define ADS114S0X_REGISTER_STATUS_NOT_RDY_POS 6 #define ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_NOT_RDY_POS, \ ADS114S0X_REGISTER_STATUS_NOT_RDY_LENGTH) @@ -142,7 +142,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_N_RAILN_POS, \ ADS114S0X_REGISTER_STATUS_FL_N_RAILN_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS 1 +#define ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS 1 #define ADS114S0X_REGISTER_STATUS_FL_REF_L1_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) @@ -150,7 +150,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_STATUS_FL_REF_L1_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L1_LENGTH) #define ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH 1 -#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS 0 +#define ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS 0 #define ADS114S0X_REGISTER_STATUS_FL_REF_L0_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_STATUS_FL_REF_L0_POS, \ ADS114S0X_REGISTER_STATUS_FL_REF_L0_LENGTH) @@ -190,7 +190,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_PGA_EN_POS, \ ADS114S0X_REGISTER_PGA_PGA_EN_LENGTH) #define ADS114S0X_REGISTER_PGA_GAIN_LENGTH 3 -#define ADS114S0X_REGISTER_PGA_GAIN_POS 0 +#define ADS114S0X_REGISTER_PGA_GAIN_POS 0 #define ADS114S0X_REGISTER_PGA_GAIN_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ ADS114S0X_REGISTER_PGA_GAIN_LENGTH) @@ -198,7 +198,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_PGA_GAIN_POS, \ ADS114S0X_REGISTER_PGA_GAIN_LENGTH) #define ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_G_CHOP_POS 7 +#define ADS114S0X_REGISTER_DATARATE_G_CHOP_POS 7 #define ADS114S0X_REGISTER_DATARATE_G_CHOP_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_G_CHOP_POS, \ ADS114S0X_REGISTER_DATARATE_G_CHOP_LENGTH) @@ -214,7 +214,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_CLK_POS, \ ADS114S0X_REGISTER_DATARATE_CLK_LENGTH) #define ADS114S0X_REGISTER_DATARATE_MODE_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_MODE_POS 5 +#define ADS114S0X_REGISTER_DATARATE_MODE_POS 5 #define ADS114S0X_REGISTER_DATARATE_MODE_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) @@ -222,7 +222,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_MODE_POS, \ ADS114S0X_REGISTER_DATARATE_MODE_LENGTH) #define ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH 1 -#define ADS114S0X_REGISTER_DATARATE_FILTER_POS 4 +#define ADS114S0X_REGISTER_DATARATE_FILTER_POS 4 #define ADS114S0X_REGISTER_DATARATE_FILTER_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_DATARATE_FILTER_POS, \ ADS114S0X_REGISTER_DATARATE_FILTER_LENGTH) @@ -238,7 +238,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_DATARATE_DR_POS, \ ADS114S0X_REGISTER_DATARATE_DR_LENGTH) #define ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH 2 -#define ADS114S0X_REGISTER_REF_FL_REF_EN_POS 6 +#define ADS114S0X_REGISTER_REF_FL_REF_EN_POS 6 #define ADS114S0X_REGISTER_REF_FL_REF_EN_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) @@ -246,7 +246,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_FL_REF_EN_POS, \ ADS114S0X_REGISTER_REF_FL_REF_EN_LENGTH) #define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 +#define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS 5 #define ADS114S0X_REGISTER_REF_NOT_REFP_BUF_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) @@ -254,7 +254,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_REF_NOT_REFP_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFP_BUF_LENGTH) #define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH 1 -#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 +#define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS 4 #define ADS114S0X_REGISTER_REF_NOT_REFN_BUF_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_REF_NOT_REFN_BUF_POS, \ ADS114S0X_REGISTER_REF_NOT_REFN_BUF_LENGTH) @@ -302,7 +302,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMAG_IMAG_POS, \ ADS114S0X_REGISTER_IDACMAG_IMAG_LENGTH) #define ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I2MUX_POS 4 +#define ADS114S0X_REGISTER_IDACMUX_I2MUX_POS 4 #define ADS114S0X_REGISTER_IDACMUX_I2MUX_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) @@ -310,7 +310,7 @@ enum ads114s0x_register { ADS114S0X_REGISTER_SET_VALUE(target, value, ADS114S0X_REGISTER_IDACMUX_I2MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I2MUX_LENGTH) #define ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH 4 -#define ADS114S0X_REGISTER_IDACMUX_I1MUX_POS 0 +#define ADS114S0X_REGISTER_IDACMUX_I1MUX_POS 0 #define ADS114S0X_REGISTER_IDACMUX_I1MUX_GET(value) \ ADS114S0X_REGISTER_GET_VALUE(value, ADS114S0X_REGISTER_IDACMUX_I1MUX_POS, \ ADS114S0X_REGISTER_IDACMUX_I1MUX_LENGTH) @@ -424,10 +424,10 @@ struct ads114s0x_data { int16_t *buffer_ptr; #if CONFIG_ADC_ADS114S0X_GPIO struct k_mutex gpio_lock; - uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ + uint8_t gpio_enabled; /* one bit per GPIO, 1 = enabled */ uint8_t gpio_direction; /* one bit per GPIO, 1 = input */ - uint8_t gpio_value; /* one bit per GPIO, 1 = high */ -#endif /* CONFIG_ADC_ADS114S0X_GPIO */ + uint8_t gpio_value; /* one bit per GPIO, 1 = high */ +#endif /* CONFIG_ADC_ADS114S0X_GPIO */ }; static void ads114s0x_data_ready_handler(const struct device *dev, struct gpio_callback *gpio_cb, @@ -442,9 +442,10 @@ static void ads114s0x_data_ready_handler(const struct device *dev, struct gpio_c k_sem_give(&data->data_ready_signal); } -static int ads114s0x_read_register(const struct spi_dt_spec *bus, +static int ads114s0x_read_register(const struct device *dev, enum ads114s0x_register register_address, uint8_t *value) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[3]; uint8_t buffer_rx[ARRAY_SIZE(buffer_tx)]; const struct spi_buf tx_buf[] = {{ @@ -468,22 +469,23 @@ static int ads114s0x_read_register(const struct spi_dt_spec *bus, /* read one register */ buffer_tx[1] = 0x00; - int result = spi_transceive_dt(bus, &tx, &rx); + int result = spi_transceive_dt(&config->bus, &tx, &rx); if (result != 0) { - LOG_ERR("spi_transceive failed with error %i", result); + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); return result; } *value = buffer_rx[2]; - LOG_DBG("read from register 0x%02X value 0x%02X", register_address, *value); + LOG_DBG("%s: read from register 0x%02X value 0x%02X", dev->name, register_address, *value); return 0; } -static int ads114s0x_write_register(const struct spi_dt_spec *bus, +static int ads114s0x_write_register(const struct device *dev, enum ads114s0x_register register_address, uint8_t value) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[3]; const struct spi_buf tx_buf[] = {{ .buf = buffer_tx, @@ -499,21 +501,22 @@ static int ads114s0x_write_register(const struct spi_dt_spec *bus, buffer_tx[1] = 0x00; buffer_tx[2] = value; - LOG_DBG("writing to register 0x%02X value 0x%02X", register_address, value); - int result = spi_write_dt(bus, &tx); + LOG_DBG("%s: writing to register 0x%02X value 0x%02X", dev->name, register_address, value); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } return 0; } -static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, +static int ads114s0x_write_multiple_registers(const struct device *dev, enum ads114s0x_register *register_addresses, uint8_t *values, size_t count) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[2]; const struct spi_buf tx_buf[] = { { @@ -531,7 +534,7 @@ static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, }; if (count == 0) { - LOG_WRN("ignoring the command to write 0 registers"); + LOG_WRN("%s: ignoring the command to write 0 registers", dev->name); return -EINVAL; } @@ -547,18 +550,19 @@ static int ads114s0x_write_multiple_registers(const struct spi_dt_spec *bus, "register addresses are not consecutive"); } - int result = spi_write_dt(bus, &tx); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } return 0; } -static int ads114s0x_send_command(const struct spi_dt_spec *bus, enum ads114s0x_command command) +static int ads114s0x_send_command(const struct device *dev, enum ads114s0x_command command) { + const struct ads114s0x_config *config = dev->config; uint8_t buffer_tx[1]; const struct spi_buf tx_buf[] = {{ .buf = buffer_tx, @@ -571,11 +575,11 @@ static int ads114s0x_send_command(const struct spi_dt_spec *bus, enum ads114s0x_ buffer_tx[0] = (uint8_t)command; - LOG_DBG("sending command 0x%02X", command); - int result = spi_write_dt(bus, &tx); + LOG_DBG("%s: sending command 0x%02X", dev->name, command); + int result = spi_write_dt(&config->bus, &tx); if (result != 0) { - LOG_ERR("spi_write failed with error %i", result); + LOG_ERR("%s: spi_write failed with error %i", dev->name, result); return result; } @@ -608,7 +612,7 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_IDACMUX_SET_DEFAULTS(idac_mux); if (channel_cfg->channel_id != 0) { - LOG_ERR("only one channel is supported"); + LOG_ERR("%s: only one channel is supported", dev->name); return -EINVAL; } @@ -619,7 +623,8 @@ static int ads114s0x_channel_setup(const struct device *dev, */ if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT && acquisition_time_unit != ADC_ACQ_TIME_TICKS) { - LOG_ERR("invalid acquisition time %i", channel_cfg->acquisition_time); + LOG_ERR("%s: invalid acquisition time %i", dev->name, + channel_cfg->acquisition_time); return -EINVAL; } @@ -655,25 +660,29 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_REF_REFSEL_SET(reference_control, 0b01); break; default: - LOG_ERR("reference %i is not supported", channel_cfg->reference); + LOG_ERR("%s: reference %i is not supported", dev->name, channel_cfg->reference); return -EINVAL; } if (channel_cfg->differential) { + LOG_DBG("%s: configuring channel for a differential measurement from the pins (p, " + "n) (%i, %i)", + dev->name, channel_cfg->input_positive, channel_cfg->input_negative); if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("positive channel input %i is invalid", + LOG_ERR("%s: positive channel input %i is invalid", dev->name, channel_cfg->input_positive); return -EINVAL; } if (channel_cfg->input_negative >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("negative channel input %i is invalid", + LOG_ERR("%s: negative channel input %i is invalid", dev->name, channel_cfg->input_negative); return -EINVAL; } if (channel_cfg->input_positive == channel_cfg->input_negative) { - LOG_ERR("negative and positive channel inputs must be different"); + LOG_ERR("%s: negative and positive channel inputs must be different", + dev->name); return -EINVAL; } @@ -682,8 +691,11 @@ static int ads114s0x_channel_setup(const struct device *dev, pin_selections[0] = channel_cfg->input_positive; pin_selections[1] = channel_cfg->input_negative; } else { + LOG_DBG("%s: configuring channel for single ended measurement from input %i", + dev->name, channel_cfg->input_positive); if (channel_cfg->input_positive >= ADS114S0X_INPUT_SELECTION_AINCOM) { - LOG_ERR("channel input %i is invalid", channel_cfg->input_positive); + LOG_ERR("%s: channel input %i is invalid", dev->name, + channel_cfg->input_positive); return -EINVAL; } @@ -720,7 +732,7 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_PGA_GAIN_SET(gain, 0b111); break; default: - LOG_ERR("gain value %i not supported", channel_cfg->gain); + LOG_ERR("%s: gain value %i not supported", dev->name, channel_cfg->gain); return -EINVAL; } @@ -761,19 +773,21 @@ static int ads114s0x_channel_setup(const struct device *dev, ADS114S0X_REGISTER_IDACMAG_IMAG_SET(idac_magnitude, 0b1001); break; default: - LOG_ERR("IDAC magnitude %i not supported", config->idac_current); + LOG_ERR("%s: IDAC magnitude %i not supported", dev->name, config->idac_current); return -EINVAL; } if (channel_cfg->current_source_pin_set) { + LOG_DBG("%s: current source pin set to %i and %i", dev->name, + channel_cfg->current_source_pin[0], channel_cfg->current_source_pin[1]); if (channel_cfg->current_source_pin[0] > 0b1111) { - LOG_ERR("invalid selection %i for I1MUX", + LOG_ERR("%s: invalid selection %i for I1MUX", dev->name, channel_cfg->current_source_pin[0]); return -EINVAL; } if (channel_cfg->current_source_pin[1] > 0b1111) { - LOG_ERR("invalid selection %i for I2MUX", + LOG_ERR("%s: invalid selection %i for I2MUX", dev->name, channel_cfg->current_source_pin[1]); return -EINVAL; } @@ -784,6 +798,7 @@ static int ads114s0x_channel_setup(const struct device *dev, pin_selections[3] = channel_cfg->current_source_pin[1]; pin_selections_size = 4; } else { + LOG_DBG("%s: current source pins not set", dev->name); pin_selections_size = 2; } @@ -798,7 +813,8 @@ static int ads114s0x_channel_setup(const struct device *dev, } if (pin_selections[i] == pin_selections[j]) { - LOG_ERR("pins for inputs and current sources must be different"); + LOG_ERR("%s: pins for inputs and current sources must be different", + dev->name); return -EINVAL; } } @@ -819,11 +835,11 @@ static int ads114s0x_channel_setup(const struct device *dev, values[5] = idac_mux; BUILD_ASSERT(ARRAY_SIZE(values) == 6); - result = ads114s0x_write_multiple_registers(&config->bus, register_addresses, values, + result = ads114s0x_write_multiple_registers(dev, register_addresses, values, ARRAY_SIZE(values)); if (result != 0) { - LOG_ERR("unable to configure registers"); + LOG_ERR("%s: unable to configure registers", dev->name); return result; } @@ -849,17 +865,17 @@ static int ads114s0x_validate_sequence(const struct device *dev, const struct adc_sequence *sequence) { if (sequence->resolution != ADS114S0X_RESOLUTION) { - LOG_ERR("invalid resolution"); + LOG_ERR("%s: invalid resolution", dev->name); return -EINVAL; } if (sequence->channels != BIT(0)) { - LOG_ERR("invalid channel"); + LOG_ERR("%s: invalid channel", dev->name); return -EINVAL; } if (sequence->oversampling) { - LOG_ERR("oversampling is not supported"); + LOG_ERR("%s: oversampling is not supported", dev->name); return -EINVAL; } @@ -892,7 +908,7 @@ static int ads114s0x_adc_start_read(const struct device *dev, const struct adc_s result = ads114s0x_validate_sequence(dev, sequence); if (result != 0) { - LOG_ERR("sequence validation failed"); + LOG_ERR("%s: sequence validation failed", dev->name); return result; } @@ -913,16 +929,16 @@ static int ads114s0x_send_start_read(const struct device *dev) int result; if (config->gpio_start_sync.port == 0) { - result = ads114s0x_send_command(&config->bus, ADS114S0X_COMMAND_START); + result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_START); if (result != 0) { - LOG_ERR("unable to send START/SYNC command"); + LOG_ERR("%s: unable to send START/SYNC command", dev->name); return result; } } else { result = gpio_pin_set_dt(&config->gpio_start_sync, 1); if (result != 0) { - LOG_ERR("unable to start ADC operation"); + LOG_ERR("%s: unable to start ADC operation", dev->name); return result; } @@ -932,7 +948,7 @@ static int ads114s0x_send_start_read(const struct device *dev) result = gpio_pin_set_dt(&config->gpio_start_sync, 0); if (result != 0) { - LOG_ERR("unable to start ADC operation"); + LOG_ERR("%s: unable to start ADC operation", dev->name); return result; } } @@ -974,11 +990,12 @@ static int ads114s0x_read_sample(const struct device *dev, uint16_t *buffer) int result = spi_transceive_dt(&config->bus, &tx, &rx); if (result != 0) { - LOG_ERR("spi_transceive failed with error %i", result); + LOG_ERR("%s: spi_transceive failed with error %i", dev->name, result); return result; } *buffer = sys_get_be16(buffer_rx + 1); + LOG_DBG("%s: read ADC sample %i", dev->name, *buffer); return 0; } @@ -992,21 +1009,21 @@ static int ads114s0x_adc_perform_read(const struct device *dev) result = ads114s0x_send_start_read(dev); if (result != 0) { - LOG_ERR("unable to start ADC conversion"); + LOG_ERR("%s: unable to start ADC conversion", dev->name); adc_context_complete(&data->ctx, result); return result; } result = ads114s0x_wait_data_ready(dev); if (result != 0) { - LOG_ERR("waiting for data to be ready failed"); + LOG_ERR("%s: waiting for data to be ready failed", dev->name); adc_context_complete(&data->ctx, result); return result; } result = ads114s0x_read_sample(dev, data->buffer); if (result != 0) { - LOG_ERR("reading sample failed"); + LOG_ERR("%s: reading sample failed", dev->name); adc_context_complete(&data->ctx, result); return result; } @@ -1079,7 +1096,6 @@ static void ads114s0x_acquisition_thread(void *p1, void *p2, void *p3) static int ads114s0x_gpio_write_config(const struct device *dev) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; enum ads114s0x_register register_addresses[2]; uint8_t register_values[ARRAY_SIZE(register_addresses)]; uint8_t gpio_dat = 0; @@ -1093,20 +1109,19 @@ static int ads114s0x_gpio_write_config(const struct device *dev) register_values[1] = gpio_con; register_addresses[0] = ADS114S0X_REGISTER_GPIODAT; register_addresses[1] = ADS114S0X_REGISTER_GPIOCON; - return ads114s0x_write_multiple_registers(&config->bus, register_addresses, register_values, + return ads114s0x_write_multiple_registers(dev, register_addresses, register_values, ARRAY_SIZE(register_values)); } static int ads114s0x_gpio_write_value(const struct device *dev) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; uint8_t gpio_dat = 0; ADS114S0X_REGISTER_GPIODAT_DAT_SET(gpio_dat, data->gpio_value); ADS114S0X_REGISTER_GPIODAT_DIR_SET(gpio_dat, data->gpio_direction); - return ads114s0x_write_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, gpio_dat); + return ads114s0x_write_register(dev, ADS114S0X_REGISTER_GPIODAT, gpio_dat); } int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initial_value) @@ -1115,7 +1130,7 @@ int ads114s0x_gpio_set_output(const struct device *dev, uint8_t pin, bool initia int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1143,7 +1158,7 @@ int ads114s0x_gpio_set_input(const struct device *dev, uint8_t pin) int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1166,7 +1181,7 @@ int ads114s0x_gpio_deconfigure(const struct device *dev, uint8_t pin) int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } @@ -1189,17 +1204,17 @@ int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool val int result = 0; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } k_mutex_lock(&data->gpio_lock, K_FOREVER); if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("gpio pin %i not configured", pin); + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); result = -EINVAL; } else if ((BIT(pin) & data->gpio_direction) != 0) { - LOG_ERR("gpio pin %i not configured as output", pin); + LOG_ERR("%s: gpio pin %i not configured as output", dev->name, pin); result = -EINVAL; } else { data->gpio_value |= BIT(pin); @@ -1215,26 +1230,24 @@ int ads114s0x_gpio_set_pin_value(const struct device *dev, uint8_t pin, bool val int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *value) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; int result = 0; uint8_t gpio_dat; if (pin > ADS114S0X_GPIO_MAX) { - LOG_ERR("invalid pin %i", pin); + LOG_ERR("%s: invalid pin %i", dev->name, pin); return -EINVAL; } k_mutex_lock(&data->gpio_lock, K_FOREVER); if ((BIT(pin) & data->gpio_enabled) == 0) { - LOG_ERR("gpio pin %i not configured", pin); + LOG_ERR("%s: gpio pin %i not configured", dev->name, pin); result = -EINVAL; } else if ((BIT(pin) & data->gpio_direction) == 0) { - LOG_ERR("gpio pin %i not configured as input", pin); + LOG_ERR("%s: gpio pin %i not configured as input", dev->name, pin); result = -EINVAL; } else { - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, - &gpio_dat); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); *value = (BIT(pin) & data->gpio_value) != 0; } @@ -1247,13 +1260,12 @@ int ads114s0x_gpio_get_pin_value(const struct device *dev, uint8_t pin, bool *va int ads114s0x_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) { struct ads114s0x_data *data = dev->data; - const struct ads114s0x_config *config = dev->config; int result = 0; uint8_t gpio_dat; k_mutex_lock(&data->gpio_lock, K_FOREVER); - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_GPIODAT, &gpio_dat); data->gpio_value = ADS114S0X_REGISTER_GPIODAT_DAT_GET(gpio_dat); *value = data->gpio_value; @@ -1315,14 +1327,14 @@ static int ads114s0x_init(const struct device *dev) #endif /* CONFIG_ADC_ADS114S0X_GPIO */ if (!spi_is_ready_dt(&config->bus)) { - LOG_ERR("SPI device is not ready"); + LOG_ERR("%s: SPI device is not ready", dev->name); return -ENODEV; } if (config->gpio_reset.port != NULL) { result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); if (result != 0) { - LOG_ERR("failed to initialize GPIO for reset"); + LOG_ERR("%s: failed to initialize GPIO for reset", dev->name); return result; } } @@ -1330,20 +1342,20 @@ static int ads114s0x_init(const struct device *dev) if (config->gpio_start_sync.port != NULL) { result = gpio_pin_configure_dt(&config->gpio_start_sync, GPIO_OUTPUT_INACTIVE); if (result != 0) { - LOG_ERR("failed to initialize GPIO for start/sync"); + LOG_ERR("%s: failed to initialize GPIO for start/sync", dev->name); return result; } } result = gpio_pin_configure_dt(&config->gpio_data_ready, GPIO_INPUT); if (result != 0) { - LOG_ERR("failed to initialize GPIO for data ready"); + LOG_ERR("%s: failed to initialize GPIO for data ready", dev->name); return result; } result = gpio_pin_interrupt_configure_dt(&config->gpio_data_ready, GPIO_INT_EDGE_TO_ACTIVE); if (result != 0) { - LOG_ERR("failed to configure data ready interrupt"); + LOG_ERR("%s: failed to configure data ready interrupt", dev->name); return -EIO; } @@ -1351,24 +1363,24 @@ static int ads114s0x_init(const struct device *dev) BIT(config->gpio_data_ready.pin)); result = gpio_add_callback(config->gpio_data_ready.port, &data->callback_data_ready); if (result != 0) { - LOG_ERR("failed to add data ready callback"); + LOG_ERR("%s: failed to add data ready callback", dev->name); return -EIO; } #if CONFIG_ADC_ASYNC - k_tid_t tid = k_thread_create( - &data->thread, config->stack, CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, - ads114s0x_acquisition_thread, (void *)dev, NULL, NULL, - CONFIG_ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); + k_tid_t tid = k_thread_create(&data->thread, config->stack, + CONFIG_ADC_ADS114S0X_ACQUISITION_THREAD_STACK_SIZE, + ads114s0x_acquisition_thread, (void *)dev, NULL, NULL, + CONFIG_ADC_ADS114S0X_ASYNC_THREAD_INIT_PRIO, 0, K_NO_WAIT); k_thread_name_set(tid, "adc_ads114s0x"); #endif k_busy_wait(ADS114S0X_POWER_ON_RESET_TIME_IN_US); if (config->gpio_reset.port == NULL) { - result = ads114s0x_send_command(&config->bus, ADS114S0X_COMMAND_RESET); + result = ads114s0x_send_command(dev, ADS114S0X_COMMAND_RESET); if (result != 0) { - LOG_ERR("unable to send RESET command"); + LOG_ERR("%s: unable to send RESET command", dev->name); return result; } } else { @@ -1378,14 +1390,14 @@ static int ads114s0x_init(const struct device *dev) k_busy_wait(ADS114S0X_RESET_DELAY_TIME_IN_US); - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_STATUS, &status); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_STATUS, &status); if (result != 0) { - LOG_ERR("unable to read status register"); + LOG_ERR("%s: unable to read status register", dev->name); return result; } if (ADS114S0X_REGISTER_STATUS_NOT_RDY_GET(status) == 0x01) { - LOG_ERR("ADS114 is not yet ready"); + LOG_ERR("%s: ADS114 is not yet ready", dev->name); return -EBUSY; } @@ -1395,24 +1407,24 @@ static int ads114s0x_init(const struct device *dev) */ ADS114S0X_REGISTER_REF_SET_DEFAULTS(reference_control); - result = ads114s0x_write_register(&config->bus, ADS114S0X_REGISTER_REF, reference_control); + result = ads114s0x_write_register(dev, ADS114S0X_REGISTER_REF, reference_control); if (result != 0) { - LOG_ERR("unable to set default reference control values"); + LOG_ERR("%s: unable to set default reference control values", dev->name); return result; } /* * Ensure that the internal voltage reference is active. */ - result = ads114s0x_read_register(&config->bus, ADS114S0X_REGISTER_REF, - &reference_control_read); + result = ads114s0x_read_register(dev, ADS114S0X_REGISTER_REF, &reference_control_read); if (result != 0) { - LOG_ERR("unable to read reference control values"); + LOG_ERR("%s: unable to read reference control values", dev->name); return result; } if (reference_control != reference_control_read) { - LOG_ERR("reference control register is incorrect: 0x%02X", reference_control_read); + LOG_ERR("%s: reference control register is incorrect: 0x%02X", dev->name, + reference_control_read); return -EIO; } @@ -1424,7 +1436,7 @@ static int ads114s0x_init(const struct device *dev) result = ads114s0x_gpio_write_config(dev); if (result != 0) { - LOG_ERR("unable to configure defaults for GPIOs"); + LOG_ERR("%s: unable to configure defaults for GPIOs", dev->name); return result; } #endif @@ -1460,7 +1472,7 @@ BUILD_ASSERT(CONFIG_ADC_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, .gpio_reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ .gpio_data_ready = GPIO_DT_SPEC_INST_GET(n, drdy_gpios), \ .gpio_start_sync = GPIO_DT_SPEC_INST_GET_OR(n, start_sync_gpios, {0}), \ - .idac_current = DT_INST_PROP(n, idac_current), \ + .idac_current = DT_INST_PROP(n, idac_current), \ }; \ static struct ads114s0x_data data_##n; \ DEVICE_DT_INST_DEFINE(n, ads114s0x_init, NULL, &data_##n, &config_##n, POST_KERNEL, \ diff --git a/drivers/adc/adc_ite_it8xxx2.c b/drivers/adc/adc_ite_it8xxx2.c index 87c010933d4..53aec279fd2 100644 --- a/drivers/adc/adc_ite_it8xxx2.c +++ b/drivers/adc/adc_ite_it8xxx2.c @@ -43,6 +43,12 @@ LOG_MODULE_REGISTER(adc_ite_it8xxx2); #define ADC_13_16_FULL_SCALE_MASK GENMASK(3, 0) #endif +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +/* Select analog clock division factor */ +#define ADC_SACLKDIV_MASK GENMASK(6, 4) +#define ADC_SACLKDIV(div) FIELD_PREP(ADC_SACLKDIV_MASK, div) +#endif + /* List of ADC channels. */ enum chip_adc_channel { CHIP_ADC_CH0 = 0, @@ -451,6 +457,11 @@ static int adc_it8xxx2_init(const struct device *dev) * SCLKDIV has to be equal to or greater than 1h; */ adc_regs->ADCCTL = 1; + +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + adc_regs->ADCCTL1 = + (adc_regs->ADCCTL1 & ~ADC_SACLKDIV_MASK) | ADC_SACLKDIV(2); +#endif /* * Enable this bit, and data of VCHxDATL/VCHxDATM will be * kept until data valid is cleared. diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c index 72a20f47fc9..6d1973ca0aa 100644 --- a/drivers/adc/adc_nrfx_saadc.c +++ b/drivers/adc/adc_nrfx_saadc.c @@ -170,7 +170,7 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, if (!repeat) { nrf_saadc_buffer_pointer_set( NRF_SAADC, - nrf_saadc_buffer_pointer_get(NRF_SAADC) + + (uint16_t *)nrf_saadc_buffer_pointer_get(NRF_SAADC) + nrf_saadc_amount_get(NRF_SAADC)); } } @@ -256,7 +256,7 @@ static int check_buffer_size(const struct adc_sequence *sequence, { size_t needed_buffer_size; - needed_buffer_size = active_channels * sizeof(nrf_saadc_value_t); + needed_buffer_size = active_channels * sizeof(uint16_t); if (sequence->options) { needed_buffer_size *= (1 + sequence->options->extra_samplings); } diff --git a/drivers/adc/adc_numaker.c b/drivers/adc/adc_numaker.c new file mode 100644 index 00000000000..4fae17f422d --- /dev/null +++ b/drivers/adc/adc_numaker.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_adc + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +LOG_MODULE_REGISTER(adc_numaker, CONFIG_ADC_LOG_LEVEL); + +/* Device config */ +struct adc_numaker_config { + /* eadc base address */ + EADC_T *eadc_base; + uint8_t channel_cnt; + const struct reset_dt_spec reset; + /* clock configuration */ + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + const struct pinctrl_dev_config *pincfg; + void (*irq_config_func)(const struct device *dev); +}; + +/* Driver context/data */ +struct adc_numaker_data { + struct adc_context ctx; + const struct device *dev; + uint16_t *buffer; + uint16_t *buf_end; + uint16_t *repeat_buffer; + bool is_differential; + uint32_t channels; +}; + +static int adc_numaker_channel_setup(const struct device *dev, + const struct adc_channel_cfg *chan_cfg) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + + if (chan_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + LOG_ERR("Not support acquisition time"); + return -ENOTSUP; + } + + if (chan_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Not support channel gain"); + return -ENOTSUP; + } + + if (chan_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Not support channel reference"); + return -ENOTSUP; + } + + if (chan_cfg->channel_id >= cfg->channel_cnt) { + LOG_ERR("Invalid channel (%u)", chan_cfg->channel_id); + return -EINVAL; + } + + data->is_differential = (chan_cfg->differential) ? true : false; + + return 0; +} + +static int m_adc_numaker_validate_buffer_size(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct adc_numaker_config *cfg = dev->config; + uint8_t channel_cnt = 0; + uint32_t mask; + size_t needed_size; + + for (mask = BIT(cfg->channel_cnt - 1); mask != 0; mask >>= 1) { + if (mask & sequence->channels) { + channel_cnt++; + } + } + + needed_size = channel_cnt * sizeof(uint16_t); + if (sequence->options) { + needed_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_size) { + return -ENOBUFS; + } + + return 0; +} + +static void adc_numaker_isr(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + EADC_T *eadc = cfg->eadc_base; + struct adc_numaker_data *const data = dev->data; + uint32_t channel_mask = data->channels; + uint32_t module_mask = channel_mask; + uint32_t module_id; + uint16_t conv_data; + uint32_t pend_flag; + + /* Clear pending flag first */ + pend_flag = eadc->PENDSTS; + eadc->PENDSTS = pend_flag; + LOG_DBG("ADC ISR pend flag: 0x%X\n", pend_flag); + LOG_DBG("ADC ISR STATUS2[0x%x] STATUS3[0x%x]", eadc->STATUS2, eadc->STATUS3); + /* Complete the conversion of channels. + * Check EAC idle by EADC_STATUS2_BUSY_Msk + * Check trigger source coming by EADC_STATUS2_ADOVIF_Msk + * Confirm all sample modules are idle by EADC_STATUS2_ADOVIF_Msk + */ + if (!(eadc->STATUS2 & EADC_STATUS2_BUSY_Msk) && + ((eadc->STATUS3 & EADC_STATUS3_CURSPL_Msk) == EADC_STATUS3_CURSPL_Msk)) { + /* Stop the conversion for sample module */ + EADC_STOP_CONV(eadc, module_mask); + + /* Disable sample module A/D ADINT0 interrupt. */ + EADC_DISABLE_INT(eadc, BIT0); + + /* Disable the sample module ADINT0 interrupt source */ + EADC_DISABLE_SAMPLE_MODULE_INT(eadc, 0, module_mask); + + /* Get conversion data of each sample module for selected channel */ + while (module_mask) { + module_id = find_lsb_set(module_mask) - 1; + + conv_data = EADC_GET_CONV_DATA(eadc, module_id); + if (data->buffer < data->buf_end) { + *data->buffer++ = conv_data; + LOG_DBG("ADC ISR id=%d, data=0x%x", module_id, conv_data); + } + module_mask &= ~BIT(module_id); + + /* Disable all channels on each sample module */ + eadc->SCTL[module_id] = 0; + } + + /* Disable ADC */ + EADC_Close(eadc); + + /* Inform sampling is done */ + adc_context_on_sampling_done(&data->ctx, data->dev); + } + + /* Clear the A/D ADINT0 interrupt flag */ + EADC_CLR_INT_FLAG(eadc, EADC_STATUS2_ADIF0_Msk); +} + +static void m_adc_numaker_start_scan(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + EADC_T *eadc = cfg->eadc_base; + struct adc_numaker_data *const data = dev->data; + uint32_t channel_mask = data->channels; + uint32_t module_mask = channel_mask; + uint32_t channel_id; + uint32_t module_id; + + /* Configure the sample module, analog input channel and software trigger source */ + while (channel_mask) { + channel_id = find_lsb_set(channel_mask) - 1; + module_id = channel_id; + channel_mask &= ~BIT(channel_id); + EADC_ConfigSampleModule(eadc, module_id, + EADC_SOFTWARE_TRIGGER, channel_id); + } + + /* Clear the A/D ADINT0 interrupt flag for safe */ + EADC_CLR_INT_FLAG(eadc, EADC_STATUS2_ADIF0_Msk); + + /* Enable sample module A/D ADINT0 interrupt. */ + EADC_ENABLE_INT(eadc, BIT0); + + /* Enable sample module interrupt ADINT0. */ + EADC_ENABLE_SAMPLE_MODULE_INT(eadc, 0, module_mask); + + /* Start conversion */ + EADC_START_CONV(eadc, module_mask); +} + +/* Implement ADC API functions of adc_context.h + * - adc_context_start_sampling() + * - adc_context_update_buffer_pointer() + */ +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_numaker_data *const data = + CONTAINER_OF(ctx, struct adc_numaker_data, ctx); + + data->repeat_buffer = data->buffer; + data->channels = ctx->sequence.channels; + + /* Start ADC conversion for sample modules/channels */ + m_adc_numaker_start_scan(data->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_numaker_data *data = + CONTAINER_OF(ctx, struct adc_numaker_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static int m_adc_numaker_start_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + EADC_T *eadc = cfg->eadc_base; + int err; + + err = m_adc_numaker_validate_buffer_size(dev, sequence); + if (err) { + LOG_ERR("ADC provided buffer is too small"); + return err; + } + + if (!sequence->resolution) { + LOG_ERR("ADC resolution is not valid"); + return -EINVAL; + } + LOG_DBG("Configure resolution=%d", sequence->resolution); + + /* Enable the A/D converter */ + if (data->is_differential) { + err = EADC_Open(eadc, EADC_CTL_DIFFEN_DIFFERENTIAL); + } else { + err = EADC_Open(eadc, EADC_CTL_DIFFEN_SINGLE_END); + } + + if (err) { + LOG_ERR("ADC Open fail (%u)", err); + return -ENODEV; + } + + data->buffer = sequence->buffer; + data->buf_end = data->buffer + sequence->buffer_size / sizeof(uint16_t); + + /* Start ADC conversion */ + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static int adc_numaker_read(const struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_numaker_data *data = dev->data; + int err; + + adc_context_lock(&data->ctx, false, NULL); + err = m_adc_numaker_start_read(dev, sequence); + adc_context_release(&data->ctx, err); + + return err; +} + +#ifdef CONFIG_ADC_ASYNC +static int adc_numaker_read_async(const struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_numaker_data *data = dev->data; + int err; + + adc_context_lock(&data->ctx, true, async); + err = m_adc_numaker_start_read(dev, sequence); + adc_context_release(&data->ctx, err); + + return err; +} +#endif + +static const struct adc_driver_api adc_numaker_driver_api = { + .channel_setup = adc_numaker_channel_setup, + .read = adc_numaker_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_numaker_read_async, +#endif +}; + +static int adc_numaker_init(const struct device *dev) +{ + const struct adc_numaker_config *cfg = dev->config; + struct adc_numaker_data *data = dev->data; + int err; + struct numaker_scc_subsys scc_subsys; + + /* Validate this module's reset object */ + if (!device_is_ready(cfg->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + data->dev = dev; + + SYS_UnlockReg(); + + /* CLK controller */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = cfg->clk_modidx; + scc_subsys.pcc.clk_src = cfg->clk_src; + scc_subsys.pcc.clk_div = cfg->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + err = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys); + if (err != 0) { + goto done; + } + /* Equivalent to CLK_SetModuleClock() */ + err = clock_control_configure(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys, NULL); + if (err != 0) { + goto done; + } + + err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + LOG_ERR("Failed to apply pinctrl state"); + goto done; + } + + /* Reset EADC to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&cfg->reset); + + /* Enable NVIC */ + cfg->irq_config_func(dev); + + /* Init mutex of adc_context */ + adc_context_unlock_unconditionally(&data->ctx); + +done: + SYS_LockReg(); + return err; +} + +#define ADC_NUMAKER_IRQ_CONFIG_FUNC(n) \ + static void adc_numaker_irq_config_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + adc_numaker_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define ADC_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + ADC_NUMAKER_IRQ_CONFIG_FUNC(inst) \ + \ + static const struct adc_numaker_config adc_numaker_cfg_##inst = { \ + .eadc_base = (EADC_T *)DT_INST_REG_ADDR(inst), \ + .channel_cnt = DT_INST_PROP(inst, channels), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .irq_config_func = adc_numaker_irq_config_func_##inst, \ + }; \ + \ + static struct adc_numaker_data adc_numaker_data_##inst = { \ + ADC_CONTEXT_INIT_TIMER(adc_numaker_data_##inst, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_numaker_data_##inst, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_numaker_data_##inst, ctx), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &adc_numaker_init, NULL, \ + &adc_numaker_data_##inst, &adc_numaker_cfg_##inst, \ + POST_KERNEL, CONFIG_ADC_INIT_PRIORITY, \ + &adc_numaker_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ADC_NUMAKER_INIT) diff --git a/drivers/adc/adc_rpi_pico.c b/drivers/adc/adc_rpi_pico.c index ec13b0d7b6d..76c3a52a15b 100644 --- a/drivers/adc/adc_rpi_pico.c +++ b/drivers/adc/adc_rpi_pico.c @@ -8,7 +8,9 @@ #define DT_DRV_COMPAT raspberrypi_pico_adc #include +#include #include +#include #include #include @@ -36,6 +38,12 @@ struct adc_rpi_config { const struct pinctrl_dev_config *pcfg; /** function pointer to irq setup */ void (*irq_configure)(void); + /** Pointer to clock controller device */ + const struct device *clk_dev; + /** Clock id of ADC clock */ + clock_control_subsys_t clk_id; + /** Reset controller config */ + const struct reset_dt_spec reset; }; /** @@ -299,6 +307,16 @@ static int adc_rpi_init(const struct device *dev) return ret; } + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } + config->irq_configure(); /* @@ -332,31 +350,34 @@ static int adc_rpi_init(const struct device *dev) #define IRQ_CONFIGURE_DEFINE(idx) .irq_configure = adc_rpi_configure_func_##idx -#define ADC_RPI_INIT(idx) \ - IRQ_CONFIGURE_FUNC(idx) \ - PINCTRL_DT_INST_DEFINE(idx); \ - static struct adc_driver_api adc_rpi_api_##idx = { \ - .channel_setup = adc_rpi_channel_setup, \ - .read = adc_rpi_read, \ - .ref_internal = DT_INST_PROP(idx, vref_mv), \ - IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = adc_rpi_read_async,)) \ - }; \ - static const struct adc_rpi_config adc_rpi_config_##idx = { \ - .num_channels = ADC_RPI_CHANNEL_NUM, \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ - IRQ_CONFIGURE_DEFINE(idx), \ - }; \ - static struct adc_rpi_data adc_rpi_data_##idx = { \ - ADC_CONTEXT_INIT_TIMER(adc_rpi_data_##idx, ctx), \ - ADC_CONTEXT_INIT_LOCK(adc_rpi_data_##idx, ctx), \ - ADC_CONTEXT_INIT_SYNC(adc_rpi_data_##idx, ctx), \ - .dev = DEVICE_DT_INST_GET(idx), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, adc_rpi_init, NULL, \ - &adc_rpi_data_##idx, \ - &adc_rpi_config_##idx, POST_KERNEL, \ - CONFIG_ADC_INIT_PRIORITY, \ +#define ADC_RPI_INIT(idx) \ + IRQ_CONFIGURE_FUNC(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + static struct adc_driver_api adc_rpi_api_##idx = { \ + .channel_setup = adc_rpi_channel_setup, \ + .read = adc_rpi_read, \ + .ref_internal = DT_INST_PROP(idx, vref_mv), \ + IF_ENABLED(CONFIG_ADC_ASYNC, (.read_async = adc_rpi_read_async,)) \ + }; \ + static const struct adc_rpi_config adc_rpi_config_##idx = { \ + .num_channels = ADC_RPI_CHANNEL_NUM, \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + IRQ_CONFIGURE_DEFINE(idx), \ + }; \ + static struct adc_rpi_data adc_rpi_data_##idx = { \ + ADC_CONTEXT_INIT_TIMER(adc_rpi_data_##idx, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_rpi_data_##idx, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_rpi_data_##idx, ctx), \ + .dev = DEVICE_DT_INST_GET(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, adc_rpi_init, NULL, \ + &adc_rpi_data_##idx, \ + &adc_rpi_config_##idx, POST_KERNEL, \ + CONFIG_ADC_INIT_PRIORITY, \ &adc_rpi_api_##idx) DT_INST_FOREACH_STATUS_OKAY(ADC_RPI_INIT); diff --git a/drivers/adc/adc_shell.c b/drivers/adc/adc_shell.c index 81b0d0d3d2f..bc002d76972 100644 --- a/drivers/adc/adc_shell.c +++ b/drivers/adc/adc_shell.c @@ -74,37 +74,73 @@ static struct adc_hdl { struct adc_channel_cfg channel_config; uint8_t resolution; } adc_list[] = { + /* zephyr-keep-sorted-start */ + DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(atmel_sam0_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(atmel_sam_afec, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(espressif_esp32_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(atmel_sam_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(atmel_sam0_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(gd_gd32_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(infineon_cat1_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(infineon_xmc4xxx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ite_it8xxx2_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(lltc_ltc2451, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11102, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11103, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11105, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11106, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11110, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11111, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11253, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(maxim_max11254, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(microchip_mcp3204, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(microchip_mcp3208, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(microchip_xec_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nordic_nrf_saadc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nxp_mcux_12b1msps_sar, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nuvoton_npcx_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nuvoton_numaker_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc12, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_kinetis_adc16, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_lpc_lpadc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_mcux_12b1msps_sar, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(nxp_s32_adc_sar, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(nxp_vf610_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(raspberrypi_pico_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(renesas_smartbond_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(renesas_smartbond_sdadc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(silabs_gecko_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(silabs_gecko_iadc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(st_stm32_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nuvoton_npcx_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(st_stm32f1_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(st_stm32f4_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(telink_b91_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1013, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1014, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1015, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1112, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1113, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1114, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads1115, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads1119, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_ads114s08, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_ads7052, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_cc13xx_cc26xx_adc, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(ti_cc32xx_adc, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(raspberrypi_pico_adc, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90077, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90078, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90079, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90080, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90097, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90098, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90099, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_lmp90100, ADC_HDL_LIST_ENTRY) + DT_FOREACH_STATUS_OKAY(ti_tla2021, ADC_HDL_LIST_ENTRY) DT_FOREACH_STATUS_OKAY(zephyr_adc_emul, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(nxp_s32_adc_sar, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11102, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11103, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11105, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11106, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11110, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11111, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11115, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11116, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(maxim_max11117, ADC_HDL_LIST_ENTRY) - DT_FOREACH_STATUS_OKAY(adi_ad5592_adc, ADC_HDL_LIST_ENTRY) + /* zephyr-keep-sorted-stop */ }; static struct adc_hdl *get_adc(const char *device_label) diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c index 12a38c415fd..0dcb8a77c78 100644 --- a/drivers/adc/adc_stm32.c +++ b/drivers/adc/adc_stm32.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #if defined(CONFIG_SOC_SERIES_STM32U5X) #include @@ -189,7 +190,7 @@ struct adc_stm32_data { uint32_t channels; uint8_t channel_count; uint8_t samples_count; - int8_t acq_time_index; + int8_t acq_time_index[2]; #ifdef CONFIG_ADC_STM32_DMA volatile int dma_error; @@ -211,11 +212,40 @@ struct adc_stm32_cfg { const uint32_t res_table[]; }; -#ifdef CONFIG_ADC_STM32_SHARED_IRQS -static bool init_irq = true; +#ifdef CONFIG_ADC_STM32_DMA +static void adc_stm32_enable_dma_support(ADC_TypeDef *adc) +{ + /* Allow ADC to create DMA request and set to one-shot mode as implemented in HAL drivers */ + +#if defined(CONFIG_SOC_SERIES_STM32H7X) + +#if defined(ADC_VER_V5_V90) + if (adc == ADC3) { + LL_ADC_REG_SetDMATransferMode(adc, + ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + LL_ADC_EnableDMAReq(adc); + } else { + LL_ADC_REG_SetDataTransferMode(adc, + ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); + } +#elif defined(ADC_VER_V5_X) + LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); +#else +#error "Unsupported ADC version" #endif -#ifdef CONFIG_ADC_STM32_DMA +#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) /* defined(CONFIG_SOC_SERIES_STM32H7X) */ + +#error "The STM32F1 ADC + DMA is not yet supported" + +#else /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ + + /* Default mechanism for other MCUs */ + LL_ADC_REG_SetDMATransfer(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); + +#endif +} + static int adc_stm32_dma_start(const struct device *dev, void *buffer, size_t channel_count) { @@ -257,21 +287,7 @@ static int adc_stm32_dma_start(const struct device *dev, return ret; } - /* Allow ADC to create DMA request and set to one-shot mode, - * as implemented in HAL drivers, if applicable. - */ -#if defined(ADC_VER_V5_V90) - if (adc == ADC3) { - LL_ADC_REG_SetDMATransferMode(adc, - ADC3_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - LL_ADC_EnableDMAReq(adc); - } else { - LL_ADC_REG_SetDataTransferMode(adc, - ADC_CFGR_DMACONTREQ(LL_ADC_REG_DMA_TRANSFER_LIMITED)); - } -#elif defined(ADC_VER_V5_X) - LL_ADC_REG_SetDataTransferMode(adc, LL_ADC_REG_DMA_TRANSFER_LIMITED); -#endif + adc_stm32_enable_dma_support(adc); data->dma_error = 0; ret = dma_start(data->dma.dma_dev, data->dma.channel); @@ -547,7 +563,8 @@ static int adc_stm32_calibrate(const struct device *dev) adc_stm32_calibration_start(dev); #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f1_adc) */ -#ifdef CONFIG_SOC_SERIES_STM32H7X +#if defined(CONFIG_SOC_SERIES_STM32H7X) && \ + defined(CONFIG_CPU_CORTEX_M7) /* * To ensure linearity the factory calibration values * should be loaded on initialization. @@ -659,7 +676,7 @@ static void adc_stm32_oversampling_ratioshift(ADC_TypeDef *adc, uint32_t ratio, } /* - * Function to configure the oversampling ratio and shit using stm32 LL + * Function to configure the oversampling ratio and shift using stm32 LL * ratio is directly the sequence->oversampling (a 2^n value) * shift is the corresponding LL_ADC_OVS_SHIFT_RIGHT_x constant */ @@ -741,6 +758,12 @@ static void dma_callback(const struct device *dev, void *user_data, * the address is in a non-cacheable SRAM region. */ adc_context_on_sampling_done(&data->ctx, dev); + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, + PM_ALL_SUBSTATES); + } } else if (status < 0) { LOG_ERR("DMA sampling complete, but DMA reported error %d", status); data->dma_error = status; @@ -1041,6 +1064,12 @@ static void adc_stm32_isr(const struct device *dev) if (++data->samples_count == data->channel_count) { data->samples_count = 0; adc_context_on_sampling_done(&data->ctx, dev); + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, + PM_ALL_SUBSTATES); + } } } @@ -1057,18 +1086,15 @@ static void adc_context_on_complete(struct adc_context *ctx, int status) ARG_UNUSED(status); - adc_stm32_disable(adc); - /* Reset acquisition time used for the sequence */ - data->acq_time_index = -1; - - /* Reset internal channels */ - LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc), - LL_ADC_PATH_INTERNAL_NONE); + data->acq_time_index[0] = -1; + data->acq_time_index[1] = -1; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X) /* Reset channel preselection register */ LL_ADC_SetChannelPreselection(adc, 0); +#else + ARG_UNUSED(adc); #endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32U5X */ } @@ -1079,6 +1105,10 @@ static int adc_stm32_read(const struct device *dev, int error; adc_context_lock(&data->ctx, false, NULL); + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } error = start_read(dev, sequence); adc_context_release(&data->ctx, error); @@ -1094,6 +1124,10 @@ static int adc_stm32_read_async(const struct device *dev, int error; adc_context_lock(&data->ctx, true, async); + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } error = start_read(dev, sequence); adc_context_release(&data->ctx, error); @@ -1101,7 +1135,7 @@ static int adc_stm32_read_async(const struct device *dev, } #endif -static int adc_stm32_check_acq_time(const struct device *dev, uint16_t acq_time) +static int adc_stm32_sampling_time_check(const struct device *dev, uint16_t acq_time) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; @@ -1121,16 +1155,24 @@ static int adc_stm32_check_acq_time(const struct device *dev, uint16_t acq_time) } } - LOG_ERR("Conversion time not supported."); + LOG_ERR("Sampling time value not supported."); return -EINVAL; } -static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, - uint8_t acq_time_index) +static int adc_stm32_sampling_time_setup(const struct device *dev, uint8_t id, + uint16_t acq_time) { const struct adc_stm32_cfg *config = (const struct adc_stm32_cfg *)dev->config; ADC_TypeDef *adc = config->base; + struct adc_stm32_data *data = dev->data; + + int acq_time_index; + + acq_time_index = adc_stm32_sampling_time_check(dev, acq_time); + if (acq_time_index < 0) { + return acq_time_index; + } /* * For all series we use the fact that the macros LL_ADC_SAMPLINGTIME_* @@ -1141,25 +1183,60 @@ static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, switch (config->num_sampling_time_common_channels) { case 0: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(0) + ARG_UNUSED(data); LL_ADC_SetChannelSamplingTime(adc, - __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), - acq_time_index); + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + (uint32_t)acq_time_index); #endif break; case 1: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(1) - LL_ADC_SetSamplingTimeCommonChannels(adc, - acq_time_index); + /* Only one sampling time can be selected for all channels. + * The first one we find is used, all others must match. + */ + if ((data->acq_time_index[0] == -1) || + (acq_time_index == data->acq_time_index[0])) { + /* Reg is empty or value matches */ + data->acq_time_index[0] = acq_time_index; + LL_ADC_SetSamplingTimeCommonChannels(adc, + (uint32_t)acq_time_index); + } else { + /* Reg is used and value does not match */ + LOG_ERR("Multiple sampling times not supported"); + return -EINVAL; + } #endif break; case 2: #if ANY_NUM_COMMON_SAMPLING_TIME_CHANNELS_IS(2) - LL_ADC_SetChannelSamplingTime(adc, - __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), - LL_ADC_SAMPLINGTIME_COMMON_1); - LL_ADC_SetSamplingTimeCommonChannels(adc, - LL_ADC_SAMPLINGTIME_COMMON_1, - acq_time_index); + /* Two different sampling times can be selected for all channels. + * The first two we find are used, all others must match either one. + */ + if ((data->acq_time_index[0] == -1) || + (acq_time_index == data->acq_time_index[0])) { + /* 1st reg is empty or value matches 1st reg */ + data->acq_time_index[0] = acq_time_index; + LL_ADC_SetChannelSamplingTime(adc, + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + LL_ADC_SAMPLINGTIME_COMMON_1); + LL_ADC_SetSamplingTimeCommonChannels(adc, + LL_ADC_SAMPLINGTIME_COMMON_1, + (uint32_t)acq_time_index); + } else if ((data->acq_time_index[1] == -1) || + (acq_time_index == data->acq_time_index[1])) { + /* 2nd reg is empty or value matches 2nd reg */ + data->acq_time_index[1] = acq_time_index; + LL_ADC_SetChannelSamplingTime(adc, + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + LL_ADC_SAMPLINGTIME_COMMON_2); + LL_ADC_SetSamplingTimeCommonChannels(adc, + LL_ADC_SAMPLINGTIME_COMMON_2, + (uint32_t)acq_time_index); + } else { + /* Both regs are used, value does not match any of them */ + LOG_ERR("Only two different sampling times supported"); + return -EINVAL; + } #endif break; default: @@ -1172,32 +1249,6 @@ static int adc_stm32_setup_speed(const struct device *dev, uint8_t id, static int adc_stm32_channel_setup(const struct device *dev, const struct adc_channel_cfg *channel_cfg) { - const struct adc_stm32_cfg *config = - (const struct adc_stm32_cfg *)dev->config; - - struct adc_stm32_data *data = dev->data; - int acq_time_index; - - acq_time_index = adc_stm32_check_acq_time(dev, - channel_cfg->acquisition_time); - if (acq_time_index < 0) { - return acq_time_index; - } - if (config->num_sampling_time_common_channels) { - if (data->acq_time_index == -1) { - data->acq_time_index = acq_time_index; - } else { - /* - * All families that use common channel must have - * identical acquisition time. - */ - if (acq_time_index != data->acq_time_index) { - LOG_ERR("Multiple sampling times not supported"); - return -EINVAL; - } - } - } - if (channel_cfg->differential) { LOG_ERR("Differential channels are not supported"); return -EINVAL; @@ -1213,8 +1264,8 @@ static int adc_stm32_channel_setup(const struct device *dev, return -EINVAL; } - if (adc_stm32_setup_speed(dev, channel_cfg->channel_id, - acq_time_index) != 0) { + if (adc_stm32_sampling_time_setup(dev, channel_cfg->channel_id, + channel_cfg->acquisition_time) != 0) { LOG_ERR("Invalid sampling time"); return -EINVAL; } @@ -1301,12 +1352,13 @@ static int adc_stm32_init(const struct device *dev) * For series that use common channels for sampling time, all * conversion time for all channels on one ADC instance has to * be the same. - * For series that use two common channels, currently only one - * of the two available common channel conversion times is used. - * This additional variable is for checking if the conversion time - * selection of all channels on one ADC instance is the same. + * For series that use two common channels, there can be up to two + * conversion times selected for all channels in a sequence. + * This additional table is for checking that the conversion time + * selection of all channels respects these requirements. */ - data->acq_time_index = -1; + data->acq_time_index[0] = -1; + data->acq_time_index[1] = -1; adc_stm32_set_clock(dev); @@ -1356,10 +1408,13 @@ static int adc_stm32_init(const struct device *dev) k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); #endif - config->irq_cfg_func(); + if (config->irq_cfg_func) { + config->irq_cfg_func(); + } #if defined(HAS_CALIBRATION) adc_stm32_calibrate(dev); + LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE); #endif /* HAS_CALIBRATION */ adc_context_unlock_unconditionally(&data->ctx); @@ -1478,111 +1533,148 @@ static const struct adc_driver_api api_stm32_driver_api = { _CONCAT(ADC_STM32_CLOCK_PREFIX(x), ADC_STM32_DIV(x)) #endif -#ifdef CONFIG_ADC_STM32_SHARED_IRQS - -bool adc_stm32_is_irq_active(ADC_TypeDef *adc) -{ -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) - return LL_ADC_IsActiveFlag_EOCS(adc) || -#else - return LL_ADC_IsActiveFlag_EOC(adc) || -#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_adc) */ - LL_ADC_IsActiveFlag_OVR(adc) || - LL_ADC_IsActiveFlag_JEOS(adc) || - LL_ADC_IsActiveFlag_AWD1(adc); -} +#if defined(CONFIG_ADC_STM32_DMA) -#define HANDLE_IRQS(index) \ - static const struct device *const dev_##index = \ - DEVICE_DT_INST_GET(index); \ - const struct adc_stm32_cfg *cfg_##index = dev_##index->config; \ - ADC_TypeDef *adc_##index = (ADC_TypeDef *)(cfg_##index->base); \ - \ - if (adc_stm32_is_irq_active(adc_##index)) { \ - adc_stm32_isr(dev_##index); \ - } - -static void adc_stm32_shared_irq_handler(void) -{ - DT_INST_FOREACH_STATUS_OKAY(HANDLE_IRQS); -} - -static void adc_stm32_irq_init(void) -{ - if (init_irq) { - init_irq = false; - IRQ_CONNECT(DT_INST_IRQN(0), - DT_INST_IRQ(0, priority), - adc_stm32_shared_irq_handler, NULL, 0); - irq_enable(DT_INST_IRQN(0)); - } -} - -#define ADC_STM32_IRQ_CONFIG(index) -#define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_irq_init, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) - -#elif defined(CONFIG_ADC_STM32_DMA) /* !CONFIG_ADC_STM32_SHARED_IRQS */ - -#define ADC_DMA_CHANNEL_INIT(index, name, dir_cap, src_dev, dest_dev) \ +#define ADC_DMA_CHANNEL_INIT(index, src_dev, dest_dev) \ .dma = { \ - .dma_dev = DEVICE_DT_GET(STM32_DMA_CTLR(index, name)), \ - .channel = DT_INST_DMAS_CELL_BY_NAME(index, name, channel), \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(index, 0)), \ + .channel = STM32_DMA_SLOT_BY_IDX(index, 0, channel), \ .dma_cfg = { \ - .dma_slot = STM32_DMA_SLOT(index, name, slot), \ + .dma_slot = STM32_DMA_SLOT_BY_IDX(index, 0, slot), \ .channel_direction = STM32_DMA_CONFIG_DIRECTION( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_data_size = STM32_DMA_CONFIG_##src_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dest_data_size = STM32_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .source_burst_length = 1, /* SINGLE transfer */ \ .dest_burst_length = 1, /* SINGLE transfer */ \ .channel_priority = STM32_DMA_CONFIG_PRIORITY( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dma_callback = dma_callback, \ .block_count = 2, \ }, \ .src_addr_increment = STM32_DMA_CONFIG_##src_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ .dst_addr_increment = STM32_DMA_CONFIG_##dest_dev##_ADDR_INC( \ - STM32_DMA_CHANNEL_CONFIG(index, name)), \ + STM32_DMA_CHANNEL_CONFIG_BY_IDX(index, 0)), \ } -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) \ - COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \ - (ADC_DMA_CHANNEL_INIT(id, dir, DIR, src, dest)), \ - (EMPTY)) - -#define ADC_STM32_IRQ_CONFIG(index) \ -static void adc_stm32_cfg_func_##index(void){ EMPTY } #define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_cfg_func_##index, + .irq_cfg_func = NULL, #else /* CONFIG_ADC_STM32_DMA */ -#define ADC_STM32_IRQ_CONFIG(index) \ -static void adc_stm32_cfg_func_##index(void) \ -{ \ - IRQ_CONNECT(DT_INST_IRQN(index), \ - DT_INST_IRQ(index, priority), \ - adc_stm32_isr, DEVICE_DT_INST_GET(index), 0); \ - irq_enable(DT_INST_IRQN(index)); \ -} -#define ADC_STM32_IRQ_FUNC(index) \ - .irq_cfg_func = adc_stm32_cfg_func_##index, -#define ADC_DMA_CHANNEL(id, dir, DIR, src, dest) +/* + * For series that share interrupt lines for multiple ADC instances + * and have separate interrupt lines for other ADCs (example, + * STM32G473 has 5 ADC instances, ADC1 and ADC2 share IRQn 18 while + * ADC3, ADC4 and ADC5 use IRQns 47, 61 and 62 respectively), generate + * a single common ISR function for each IRQn and call adc_stm32_isr + * for each device using that interrupt line for all enabled ADCs. + * + * To achieve the above, a "first" ADC instance must be chosen for all + * ADC instances sharing the same IRQn. This "first" ADC instance + * generates the code for the common ISR and for installing and + * enabling it while any other ADC sharing the same IRQn skips this + * code generation and does nothing. The common ISR code is generated + * to include calls to adc_stm32_isr for all instances using that same + * IRQn. From the example above, four ISR functions would be generated + * for IRQn 18, 47, 61 and 62, with possible "first" ADC instances + * being ADC1, ADC3, ADC4 and ADC5 if all ADCs were enabled, with the + * ISR function 18 calling adc_stm32_isr for both ADC1 and ADC2. + * + * For some of the macros below, pseudo-code is provided to describe + * its function. + */ + +/* + * return (irqn == device_irqn(index)) ? index : NULL + */ +#define FIRST_WITH_IRQN_INTERNAL(index, irqn) \ + COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (index,), (EMPTY,)) + +/* + * Returns the "first" instance's index: + * + * instances = [] + * for instance in all_active_adcs: + * instances.append(first_with_irqn_internal(device_irqn(index))) + * for instance in instances: + * if instance == NULL: + * instances.remove(instance) + * return instances[0] + */ +#define FIRST_WITH_IRQN(index) \ + GET_ARG_N(1, LIST_DROP_EMPTY(DT_INST_FOREACH_STATUS_OKAY_VARGS(FIRST_WITH_IRQN_INTERNAL, \ + DT_INST_IRQN(index)))) + +/* + * Provides code for calling adc_stm32_isr for an instance if its IRQn + * matches: + * + * if (irqn == device_irqn(index)): + * return "adc_stm32_isr(DEVICE_DT_INST_GET(index));" + */ +#define HANDLE_IRQS(index, irqn) \ + COND_CODE_1(IS_EQ(irqn, DT_INST_IRQN(index)), (adc_stm32_isr(DEVICE_DT_INST_GET(index));), \ + (EMPTY)) -#endif /* CONFIG_ADC_STM32_DMA && CONFIG_ADC_STM32_SHARED_IRQS */ +/* + * Name of the common ISR for a given IRQn (taken from a device with a + * given index). Example, for an ADC instance with IRQn 18, returns + * "adc_stm32_isr_18". + */ +#define ISR_FUNC(index) UTIL_CAT(adc_stm32_isr_, DT_INST_IRQN(index)) + +/* + * Macro for generating code for the common ISRs (by looping of all + * ADC instances that share the same IRQn as that of the given device + * by index) and the function for setting up the ISR. + * + * Here is where both "first" and non-"first" instances have code + * generated for their interrupts via HANDLE_IRQS. + */ +#define GENERATE_ISR_CODE(index) \ + static void ISR_FUNC(index)(void) \ + { \ + DT_INST_FOREACH_STATUS_OKAY_VARGS(HANDLE_IRQS, DT_INST_IRQN(index)) \ + } \ + \ + static void UTIL_CAT(ISR_FUNC(index), _init)(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), ISR_FUNC(index), \ + NULL, 0); \ + irq_enable(DT_INST_IRQN(index)); \ + } + +/* + * Limit generating code to only the "first" instance: + * + * if (first_with_irqn(index) == index): + * generate_isr_code(index) + */ +#define GENERATE_ISR(index) \ + COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)), (GENERATE_ISR_CODE(index)), (EMPTY)) + +DT_INST_FOREACH_STATUS_OKAY(GENERATE_ISR) +/* Only "first" instances need to call the ISR setup function */ +#define ADC_STM32_IRQ_FUNC(index) \ + .irq_cfg_func = COND_CODE_1(IS_EQ(index, FIRST_WITH_IRQN(index)), \ + (UTIL_CAT(ISR_FUNC(index), _init)), (NULL)), + +#endif /* CONFIG_ADC_STM32_DMA */ + +#define ADC_DMA_CHANNEL(id, src, dest) \ + COND_CODE_1(DT_INST_DMAS_HAS_IDX(id, 0), \ + (ADC_DMA_CHANNEL_INIT(id, src, dest)), \ + (/* Required for other adc instances without dma */)) #define ADC_STM32_INIT(index) \ \ PINCTRL_DT_INST_DEFINE(index); \ \ -ADC_STM32_IRQ_CONFIG(index) \ - \ static const struct stm32_pclken pclken_##index[] = \ STM32_DT_INST_CLOCKS(index); \ \ @@ -1605,7 +1697,7 @@ static struct adc_stm32_data adc_stm32_data_##index = { \ ADC_CONTEXT_INIT_TIMER(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_LOCK(adc_stm32_data_##index, ctx), \ ADC_CONTEXT_INIT_SYNC(adc_stm32_data_##index, ctx), \ - ADC_DMA_CHANNEL(index, dmamux, NULL, PERIPHERAL, MEMORY) \ + ADC_DMA_CHANNEL(index, PERIPHERAL, MEMORY) \ }; \ \ PM_DEVICE_DT_INST_DEFINE(index, adc_stm32_pm_action); \ diff --git a/drivers/adc/iadc_gecko.c b/drivers/adc/iadc_gecko.c index 1317a4e4729..d9dc542a5bf 100644 --- a/drivers/adc/iadc_gecko.c +++ b/drivers/adc/iadc_gecko.c @@ -20,7 +20,7 @@ LOG_MODULE_REGISTER(iadc_gecko, CONFIG_ADC_LOG_LEVEL); /* Number of channels available. */ #define GECKO_CHANNEL_COUNT 16 #define GECKO_INTERNAL_REFERENCE_mV 1210 -#define GECKO_DATA_RES12BIT(DATA) ((DATA & 0xFFF0) >> 4); +#define GECKO_DATA_RES12BIT(DATA) ((DATA) & 0x0FFF) struct adc_gecko_channel_config { IADC_CfgAnalogGain_t gain; diff --git a/drivers/audio/CMakeLists.txt b/drivers/audio/CMakeLists.txt index 98544d6218c..c38c35c8807 100644 --- a/drivers/audio/CMakeLists.txt +++ b/drivers/audio/CMakeLists.txt @@ -8,3 +8,4 @@ zephyr_library_sources_ifdef(CONFIG_AUDIO_MPXXDTYY mpxxdtyy-i2s.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_NRFX_PDM dmic_nrfx_pdm.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_TAS6422DAC tas6422dac.c) zephyr_library_sources_ifdef(CONFIG_AUDIO_CODEC_SHELL codec_shell.c) +zephyr_library_sources_ifdef(CONFIG_AUDIO_DMIC_MCUX dmic_mcux.c) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index a9d11331676..500e36e7e44 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -59,6 +59,7 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/audio/Kconfig.mpxxdtyy" source "drivers/audio/Kconfig.dmic_pdm_nrfx" +source "drivers/audio/Kconfig.dmic_mcux" endif # AUDIO_DMIC diff --git a/drivers/audio/Kconfig.dmic_mcux b/drivers/audio/Kconfig.dmic_mcux new file mode 100644 index 00000000000..993e30fdb53 --- /dev/null +++ b/drivers/audio/Kconfig.dmic_mcux @@ -0,0 +1,32 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config AUDIO_DMIC_MCUX + bool "DMIC driver for MCUX" + default y + depends on DT_HAS_NXP_DMIC_ENABLED + select DMA + help + Enable support for DMIC on NXP MCUX SoC's + +if AUDIO_DMIC_MCUX + +config DMIC_MCUX_DMA_BUFFERS + int "Number of buffers to reserve for DMIC DMA" + default 2 + range 2 16 + help + This determines how many buffers the driver should allocate and + reserve for the DMA engine. The memory slab used with the DMIC + API should provide at least one more buffer than this value, since + a buffer will always be in the RX queue. + +config DMIC_MCUX_QUEUE_SIZE + int "Size of DMIC buffer queue" + default 8 + help + This sets the size of the RX buffer queue for the DMIC. Up to this + many buffers may be queued by the DMIC once it is triggered, before + the application must read buffers to avoid data being dropped. + +endif # AUDIO_DMIC_MCUX diff --git a/drivers/audio/codec_shell.c b/drivers/audio/codec_shell.c index 6fb47d11184..b5c3421bf26 100644 --- a/drivers/audio/codec_shell.c +++ b/drivers/audio/codec_shell.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -55,7 +56,7 @@ static const struct args_index args_indx = { .value = 4, }; -static int parse_named_int(const char *name, const char *keystack[], size_t count) +static int parse_named_int(const char *name, const char *const keystack[], size_t count) { char *endptr; int i; diff --git a/drivers/audio/dmic_mcux.c b/drivers/audio/dmic_mcux.c new file mode 100644 index 00000000000..ff357fda9bb --- /dev/null +++ b/drivers/audio/dmic_mcux.c @@ -0,0 +1,727 @@ +/* + * Copyright 2023 NXP + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * based on dmic_nrfx_pdm.c + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +LOG_MODULE_REGISTER(dmic_mcux, CONFIG_AUDIO_DMIC_LOG_LEVEL); + +#define DT_DRV_COMPAT nxp_dmic + +struct mcux_dmic_pdm_chan { + dmic_channel_config_t dmic_channel_cfg; + const struct device *dma; + uint8_t dma_chan; +}; + +struct mcux_dmic_drv_data { + struct k_mem_slab *mem_slab; + void *dma_bufs[CONFIG_DMIC_MCUX_DMA_BUFFERS]; + uint8_t active_buf_idx; + uint32_t block_size; + DMIC_Type *base_address; + struct mcux_dmic_pdm_chan **pdm_channels; + uint8_t act_num_chan; + struct k_msgq *rx_queue; + uint32_t chan_map_lo; + uint32_t chan_map_hi; + enum dmic_state dmic_state; +}; + +struct mcux_dmic_cfg { + const struct pinctrl_dev_config *pcfg; + const struct device *clock_dev; + clock_control_subsys_t clock_name; + bool use2fs; +}; + +static int dmic_mcux_get_osr(uint32_t pcm_rate, uint32_t bit_clk, bool use_2fs) +{ + uint32_t use2fs_div = use_2fs ? 1 : 2; + + /* Note that the below calculation assumes the following: + * - DMIC DIVHFCLK is set to 0x0 (divide by 1) + * - DMIC PHY_HALF is set to 0x0 (standard sample rate) + */ + return (uint32_t)(bit_clk / (2 * pcm_rate * use2fs_div)); +} + +/* Gets hardware channel index from logical channel */ +static uint8_t dmic_mcux_hw_chan(struct mcux_dmic_drv_data *drv_data, + uint8_t log_chan) +{ + enum pdm_lr lr; + uint8_t hw_chan; + + /* This function assigns hardware channel "n" to the left channel, + * and hardware channel "n+1" to the right channel. This choice is + * arbitrary, but must be followed throughout the driver. + */ + dmic_parse_channel_map(drv_data->chan_map_lo, + drv_data->chan_map_hi, + log_chan, &hw_chan, &lr); + if (lr == PDM_CHAN_LEFT) { + return hw_chan * 2; + } else { + return (hw_chan * 2) + 1; + } +} + +static void dmic_mcux_activate_channels(struct mcux_dmic_drv_data *drv_data, + bool enable) +{ + + /* PDM channel 0 must always be enabled, as the RM states: + * "In order to output 8 channels of PDM Data, PDM_CLK01 must be used" + * therefore, even if we don't intend to capture PDM data from the + * channel 0 FIFO, we still enable the channel so the clock is active. + */ + uint32_t mask = 0x1; + + for (uint8_t chan = 0; chan < drv_data->act_num_chan; chan++) { + /* Set bitmask of hw channel to enable */ + mask |= BIT(dmic_mcux_hw_chan(drv_data, chan)); + } + + if (enable) { + DMIC_EnableChannnel(drv_data->base_address, mask); + } else { + /* No function to disable channels, we must bypass HAL here */ + drv_data->base_address->CHANEN &= ~mask; + } +} + +static int dmic_mcux_enable_dma(struct mcux_dmic_drv_data *drv_data, bool enable) +{ + struct mcux_dmic_pdm_chan *pdm_channel; + uint8_t num_chan = drv_data->act_num_chan; + uint8_t hw_chan; + int ret = 0; + + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + pdm_channel = drv_data->pdm_channels[hw_chan]; + if (enable) { + ret = dma_start(pdm_channel->dma, pdm_channel->dma_chan); + if (ret < 0) { + LOG_ERR("Could not start DMA for HW channel %d", + hw_chan); + return ret; + } + } else { + if (dma_stop(pdm_channel->dma, pdm_channel->dma_chan)) { + ret = -EIO; + } + } + DMIC_EnableChannelDma(drv_data->base_address, + (dmic_channel_t)hw_chan, enable); + } + + return ret; +} + +/* Helper to reload DMA engine for all active channels with new buffer */ +static void dmic_mcux_reload_dma(struct mcux_dmic_drv_data *drv_data, + void *buffer) +{ + int ret; + uint8_t hw_chan; + struct mcux_dmic_pdm_chan *pdm_channel; + uint8_t num_chan = drv_data->act_num_chan; + uint32_t dma_buf_size = drv_data->block_size / num_chan; + uint32_t src, dst; + + /* This function reloads the DMA engine for all active DMA channels + * with the provided buffer. Each DMA channel will start + * at a different initial address to interleave channel data. + */ + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + pdm_channel = drv_data->pdm_channels[hw_chan]; + src = DMIC_FifoGetAddress(drv_data->base_address, hw_chan); + dst = (uint32_t)(((uint16_t *)buffer) + chan); + ret = dma_reload(pdm_channel->dma, pdm_channel->dma_chan, + src, dst, dma_buf_size); + if (ret < 0) { + LOG_ERR("Could not reload DMIC HW channel %d", hw_chan); + return; + } + } +} + +/* Helper to get next buffer index for DMA */ +static uint8_t dmic_mcux_next_buf_idx(uint8_t current_idx) +{ + if ((current_idx + 1) == CONFIG_DMIC_MCUX_DMA_BUFFERS) { + return 0; + } + return current_idx + 1; +} + +static int dmic_mcux_stop(struct mcux_dmic_drv_data *drv_data) +{ + /* Disable active channels */ + dmic_mcux_activate_channels(drv_data, false); + /* Disable DMA */ + dmic_mcux_enable_dma(drv_data, false); + + /* Free all memory slabs */ + for (uint32_t i = 0; i < CONFIG_DMIC_MCUX_DMA_BUFFERS; i++) { + k_mem_slab_free(drv_data->mem_slab, drv_data->dma_bufs[i]); + } + + /* Purge the RX queue as well. */ + k_msgq_purge(drv_data->rx_queue); + + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + + return 0; +} + +static void dmic_mcux_dma_cb(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + + struct mcux_dmic_drv_data *drv_data = (struct mcux_dmic_drv_data *)user_data; + int ret; + void *done_buffer = drv_data->dma_bufs[drv_data->active_buf_idx]; + void *new_buffer; + + LOG_DBG("CB: channel is %u", channel); + + if (status < 0) { + /* DMA has failed, free allocated blocks */ + LOG_ERR("DMA reports error"); + dmic_mcux_enable_dma(drv_data, false); + dmic_mcux_activate_channels(drv_data, false); + /* Free all allocated DMA buffers */ + dmic_mcux_stop(drv_data); + drv_data->dmic_state = DMIC_STATE_ERROR; + return; + } + + /* Before we queue the current buffer, make sure we can allocate + * another one to replace it. + */ + ret = k_mem_slab_alloc(drv_data->mem_slab, &new_buffer, K_NO_WAIT); + if (ret < 0) { + /* We can't allocate a new buffer to replace the current + * one, so we cannot release the current buffer to the + * rx queue (or the DMA would stave). Therefore, we just + * leave the current buffer in place to be overwritten + * by the DMA. + */ + LOG_ERR("Could not allocate RX buffer. Dropping RX data"); + drv_data->dmic_state = DMIC_STATE_ERROR; + /* Reload DMA */ + dmic_mcux_reload_dma(drv_data, done_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = + dmic_mcux_next_buf_idx(drv_data->active_buf_idx); + return; + } + + /* DMA issues an interrupt at the completion of every block. + * we should put the active buffer into the rx queue for the + * application to read. The application is responsible for + * freeing this buffer once it processes it. + */ + ret = k_msgq_put(drv_data->rx_queue, &done_buffer, K_NO_WAIT); + if (ret < 0) { + /* Free the newly allocated buffer, we won't need it. */ + k_mem_slab_free(drv_data->mem_slab, new_buffer); + /* We cannot enqueue the current buffer, so we will drop + * the current buffer data and leave the current buffer + * in place to be overwritten by the DMA + */ + LOG_ERR("RX queue overflow, dropping RX buffer data"); + drv_data->dmic_state = DMIC_STATE_ERROR; + /* Reload DMA */ + dmic_mcux_reload_dma(drv_data, done_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = + dmic_mcux_next_buf_idx(drv_data->active_buf_idx); + return; + } + + /* Previous buffer was enqueued, and new buffer is allocated. + * Replace pointer to previous buffer in our dma slots array, + * and reload DMA with next buffer. + */ + drv_data->dma_bufs[drv_data->active_buf_idx] = new_buffer; + dmic_mcux_reload_dma(drv_data, new_buffer); + /* Advance active buffer index */ + drv_data->active_buf_idx = dmic_mcux_next_buf_idx(drv_data->active_buf_idx); +} + +static int dmic_mcux_setup_dma(const struct device *dev) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + struct mcux_dmic_pdm_chan *pdm_channel; + struct dma_block_config blk_cfg[CONFIG_DMIC_MCUX_DMA_BUFFERS] = {0}; + struct dma_config dma_cfg = {0}; + uint8_t num_chan = drv_data->act_num_chan; + uint32_t dma_buf_size = drv_data->block_size / num_chan; + uint8_t dma_buf_idx = 0; + void *dma_buf = drv_data->dma_bufs[dma_buf_idx]; + uint8_t hw_chan; + int ret = 0; + + + /* Setup DMA configuration common between all channels */ + dma_cfg.user_data = drv_data; + dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY; + dma_cfg.source_data_size = sizeof(uint16_t); /* Each sample is 16 bits */ + dma_cfg.dest_data_size = sizeof(uint16_t); + dma_cfg.block_count = CONFIG_DMIC_MCUX_DMA_BUFFERS; + dma_cfg.head_block = &blk_cfg[0]; + dma_cfg.complete_callback_en = 1; /* Callback at each block */ + dma_cfg.dma_callback = dmic_mcux_dma_cb; + + /* When multiple channels are enabled simultaneously, the DMA + * completion interrupt from one channel will signal that DMA data + * from multiple channels may be collected, provided the same + * amount of data was transferred. Therefore, we only enable the + * DMA completion callback for the first channel we setup + */ + for (uint8_t chan = 0; chan < num_chan; chan++) { + /* Parse the channel map data */ + hw_chan = dmic_mcux_hw_chan(drv_data, chan); + /* Configure blocks for hw_chan */ + for (uint32_t blk = 0; blk < CONFIG_DMIC_MCUX_DMA_BUFFERS; blk++) { + blk_cfg[blk].source_address = + DMIC_FifoGetAddress(drv_data->base_address, hw_chan); + /* We interleave samples within the output buffer + * based on channel map. So for a channel map like so: + * [pdm0_l, pdm0_r, pdm1_r, pdm1_l] + * the resulting DMA buffer would look like: + * [pdm0_l_s0, pdm0_r_s0, pdm1_r_s0, pdm1_l_s0, + * pdm0_l_s1, pdm0_r_s1, pdm1_r_s1, pdm1_l_s1, ...] + * Each sample is 16 bits wide. + */ + blk_cfg[blk].dest_address = + (uint32_t)(((uint16_t *)dma_buf) + chan); + blk_cfg[blk].dest_scatter_interval = + num_chan * sizeof(uint16_t); + blk_cfg[blk].dest_scatter_en = 1; + blk_cfg[blk].source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + blk_cfg[blk].dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + blk_cfg[blk].block_size = dma_buf_size; + /* Enable circular mode- when the final DMA block + * is exhausted, we want the DMA controller + * to restart with the first one. + */ + blk_cfg[blk].source_reload_en = 1; + blk_cfg[blk].dest_reload_en = 1; + if (blk < (CONFIG_DMIC_MCUX_DMA_BUFFERS - 1)) { + blk_cfg[blk].next_block = &blk_cfg[blk + 1]; + } else { + /* Last block, enable circular reload */ + blk_cfg[blk].next_block = NULL; + } + /* Select next dma buffer in array */ + dma_buf_idx = dmic_mcux_next_buf_idx(dma_buf_idx); + dma_buf = drv_data->dma_bufs[dma_buf_idx]; + } + pdm_channel = drv_data->pdm_channels[hw_chan]; + /* Set configuration for hw_chan_0 */ + ret = dma_config(pdm_channel->dma, pdm_channel->dma_chan, &dma_cfg); + if (ret < 0) { + LOG_ERR("Could not configure DMIC channel %d", hw_chan); + return ret; + } + /* First channel is configured. Do not install callbacks for + * other channels. + */ + dma_cfg.dma_callback = NULL; + } + + return 0; +} + +/* Initializes a DMIC hardware channel */ +static int dmic_mcux_init_channel(const struct device *dev, uint32_t osr, + uint8_t chan, enum pdm_lr lr) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + + if (!drv_data->pdm_channels[chan]) { + /* Channel disabled at devicetree level */ + return -EINVAL; + } + + drv_data->pdm_channels[chan]->dmic_channel_cfg.osr = osr; + /* Configure channel settings */ + DMIC_ConfigChannel(drv_data->base_address, (dmic_channel_t)chan, + lr == PDM_CHAN_LEFT ? kDMIC_Left : kDMIC_Right, + &drv_data->pdm_channels[chan]->dmic_channel_cfg); + /* Setup channel FIFO. We use maximum threshold to avoid triggering + * DMA too frequently + */ + DMIC_FifoChannel(drv_data->base_address, chan, 15, true, true); + /* Disable interrupts. DMA will be enabled in dmic_mcux_trigger. */ + DMIC_EnableChannelInterrupt(drv_data->base_address, chan, false); + return 0; +} + +static int mcux_dmic_init(const struct device *dev) +{ + const struct mcux_dmic_cfg *config = dev->config; + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + DMIC_Init(drv_data->base_address); + DMIC_Use2fs(drv_data->base_address, config->use2fs); +#if !(defined(FSL_FEATURE_DMIC_HAS_NO_IOCFG) && FSL_FEATURE_DMIC_HAS_NO_IOCFG) + /* Set IO to dual mode */ + DMIC_SetIOCFG(drv_data->base_address, kDMIC_PdmDual); +#endif + drv_data->dmic_state = DMIC_STATE_INITIALIZED; + return 0; +} + +static int dmic_mcux_configure(const struct device *dev, + struct dmic_cfg *config) +{ + + const struct mcux_dmic_cfg *drv_config = dev->config; + struct mcux_dmic_drv_data *drv_data = dev->data; + struct pdm_chan_cfg *channel = &config->channel; + struct pcm_stream_cfg *stream = &config->streams[0]; + enum pdm_lr lr_0 = 0, lr_1 = 0; + uint8_t hw_chan_0 = 0, hw_chan_1 = 0; + uint32_t bit_clk_rate, osr; + int ret; + + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + LOG_ERR("Cannot configure device while it is active"); + return -EBUSY; + } + + /* Only one active channel is supported */ + if (channel->req_num_streams != 1) { + return -EINVAL; + } + + /* DMIC supports up to 8 active channels. Verify user is not + * requesting more + */ + if (channel->req_num_chan > FSL_FEATURE_DMIC_CHANNEL_NUM) { + LOG_ERR("DMIC only supports 8 channels or less"); + return -ENOTSUP; + } + + if (stream->pcm_rate == 0 || stream->pcm_width == 0) { + if (drv_data->dmic_state == DMIC_STATE_CONFIGURED) { + DMIC_DeInit(drv_data->base_address); + drv_data->dmic_state = DMIC_STATE_UNINIT; + } + return 0; + } + + /* If DMIC was deinitialized, reinit here */ + if (drv_data->dmic_state == DMIC_STATE_UNINIT) { + ret = mcux_dmic_init(dev); + if (ret < 0) { + LOG_ERR("Could not reinit DMIC"); + return ret; + } + } + + /* Currently, we only support 16 bit samples. This is because the DMIC + * API dictates that samples should be interleaved between channels, + * IE: {C0, C1, C2, C0, C1, C2}. To achieve this we must use the + * "destination address increment" function of the LPC DMA IP. Since + * the LPC DMA IP does not support 3 byte wide transfers, we cannot + * effectively use destination address increments to interleave 24 + * bit samples. + */ + if (stream->pcm_width != 16) { + LOG_ERR("Only 16 bit samples are supported"); + return -ENOTSUP; + } + + ret = clock_control_get_rate(drv_config->clock_dev, + drv_config->clock_name, &bit_clk_rate); + if (ret < 0) { + return ret; + } + + /* Check bit clock rate versus what user requested */ + if ((config->io.min_pdm_clk_freq > bit_clk_rate) || + (config->io.max_pdm_clk_freq < bit_clk_rate)) { + return -EINVAL; + } + /* Calculate the required OSR divider based on the PCM bit clock + * rate to the DMIC. + */ + osr = dmic_mcux_get_osr(stream->pcm_rate, bit_clk_rate, drv_config->use2fs); + /* Now, parse the channel map and set up each channel we should + * make active. We parse two channels at once, that way we can + * check to make sure that the L/R channels of each PDM controller + * are adjacent. + */ + channel->act_num_chan = 0; + /* Save channel request data */ + drv_data->chan_map_lo = channel->req_chan_map_lo; + drv_data->chan_map_hi = channel->req_chan_map_hi; + for (uint8_t chan = 0; chan < channel->req_num_chan; chan += 2) { + /* Get the channel map data for channel pair */ + dmic_parse_channel_map(channel->req_chan_map_lo, + channel->req_chan_map_hi, + chan, &hw_chan_0, &lr_0); + if ((chan + 1) < channel->req_num_chan) { + /* Paired channel is enabled */ + dmic_parse_channel_map(channel->req_chan_map_lo, + channel->req_chan_map_hi, + chan + 1, &hw_chan_1, &lr_1); + /* Verify that paired channels use same hardware index */ + if ((lr_0 == lr_1) || + (hw_chan_0 != hw_chan_1)) { + return -EINVAL; + } + } + /* Configure selected channels in DMIC */ + ret = dmic_mcux_init_channel(dev, osr, + dmic_mcux_hw_chan(drv_data, chan), + lr_0); + if (ret < 0) { + return ret; + } + channel->act_num_chan++; + if ((chan + 1) < channel->req_num_chan) { + /* Paired channel is enabled */ + ret = dmic_mcux_init_channel(dev, osr, + dmic_mcux_hw_chan(drv_data, + chan + 1), + lr_1); + if (ret < 0) { + return ret; + } + channel->act_num_chan++; + } + } + + channel->act_chan_map_lo = channel->req_chan_map_lo; + channel->act_chan_map_hi = channel->req_chan_map_hi; + + drv_data->mem_slab = stream->mem_slab; + drv_data->block_size = stream->block_size; + drv_data->act_num_chan = channel->act_num_chan; + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + + return 0; +} + +static int dmic_mcux_start(const struct device *dev) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + /* Allocate the initial set of buffers reserved for use by the hardware. + * We queue buffers so that when the DMA is operating on buffer "n", + * buffer "n+1" is already queued in the DMA hardware. When buffer "n" + * completes, we allocate another buffer and add it to the tail of the + * DMA descriptor chain. This approach requires the driver to allocate + * a minimum of two buffers + */ + + for (uint32_t i = 0; i < CONFIG_DMIC_MCUX_DMA_BUFFERS; i++) { + /* Allocate buffers for DMA */ + ret = k_mem_slab_alloc(drv_data->mem_slab, + &drv_data->dma_bufs[i], K_NO_WAIT); + if (ret < 0) { + LOG_ERR("failed to allocate buffer"); + return -ENOBUFS; + } + } + + ret = dmic_mcux_setup_dma(dev); + if (ret < 0) { + return ret; + } + + ret = dmic_mcux_enable_dma(drv_data, true); + if (ret < 0) { + return ret; + } + dmic_mcux_activate_channels(drv_data, true); + + return 0; +} + +static int dmic_mcux_trigger(const struct device *dev, + enum dmic_trigger cmd) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + + switch (cmd) { + case DMIC_TRIGGER_PAUSE: + /* Disable active channels */ + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + dmic_mcux_activate_channels(drv_data, false); + } + drv_data->dmic_state = DMIC_STATE_PAUSED; + break; + case DMIC_TRIGGER_STOP: + if (drv_data->dmic_state == DMIC_STATE_ACTIVE) { + dmic_mcux_stop(drv_data); + } + drv_data->dmic_state = DMIC_STATE_CONFIGURED; + break; + case DMIC_TRIGGER_RELEASE: + /* Enable active channels */ + if (drv_data->dmic_state == DMIC_STATE_PAUSED) { + dmic_mcux_activate_channels(drv_data, true); + } + drv_data->dmic_state = DMIC_STATE_ACTIVE; + break; + case DMIC_TRIGGER_START: + if ((drv_data->dmic_state != DMIC_STATE_CONFIGURED) && + (drv_data->dmic_state != DMIC_STATE_ACTIVE)) { + LOG_ERR("Device is not configured"); + return -EIO; + } else if (drv_data->dmic_state != DMIC_STATE_ACTIVE) { + if (dmic_mcux_start(dev) < 0) { + LOG_ERR("Could not start DMIC"); + return -EIO; + } + drv_data->dmic_state = DMIC_STATE_ACTIVE; + } + break; + case DMIC_TRIGGER_RESET: + /* Reset DMIC to uninitialized state */ + DMIC_DeInit(drv_data->base_address); + drv_data->dmic_state = DMIC_STATE_UNINIT; + break; + default: + LOG_ERR("Invalid command: %d", cmd); + return -EINVAL; + } + return 0; +} + +static int dmic_mcux_read(const struct device *dev, + uint8_t stream, + void **buffer, size_t *size, int32_t timeout) +{ + struct mcux_dmic_drv_data *drv_data = dev->data; + int ret; + + ARG_UNUSED(stream); + + if (drv_data->dmic_state == DMIC_STATE_ERROR) { + LOG_ERR("Device reports an error, please reset and reconfigure it"); + return -EIO; + } + + if ((drv_data->dmic_state != DMIC_STATE_CONFIGURED) && + (drv_data->dmic_state != DMIC_STATE_ACTIVE) && + (drv_data->dmic_state != DMIC_STATE_PAUSED)) { + LOG_ERR("Device state is not valid for read"); + return -EIO; + } + + ret = k_msgq_get(drv_data->rx_queue, buffer, SYS_TIMEOUT_MS(timeout)); + if (ret < 0) { + return ret; + } + *size = drv_data->block_size; + + LOG_DBG("read buffer = %p", *buffer); + return 0; +} + +static const struct _dmic_ops dmic_ops = { + .configure = dmic_mcux_configure, + .trigger = dmic_mcux_trigger, + .read = dmic_mcux_read, +}; + +/* Converts integer gainshift into 5 bit 2's complement value for GAINSHIFT reg */ +#define PDM_DMIC_GAINSHIFT(val) \ + (val >= 0) ? (val & 0xF) : (BIT(4) | (0x10 - (val & 0xF))) + +/* Defines structure for a given PDM channel node */ +#define PDM_DMIC_CHAN_DEFINE(pdm_node) \ + static struct mcux_dmic_pdm_chan \ + pdm_channel_##pdm_node = { \ + .dma = DEVICE_DT_GET(DT_DMAS_CTLR(pdm_node)), \ + .dma_chan = DT_DMAS_CELL_BY_IDX(pdm_node, 0, channel), \ + .dmic_channel_cfg = { \ + .gainshft = PDM_DMIC_GAINSHIFT(DT_PROP(pdm_node, \ + gainshift)), \ + .preac2coef = DT_ENUM_IDX(pdm_node, compensation_2fs), \ + .preac4coef = DT_ENUM_IDX(pdm_node, compensation_4fs), \ + .dc_cut_level = DT_ENUM_IDX(pdm_node, dc_cutoff), \ + .post_dc_gain_reduce = DT_PROP(pdm_node, dc_gain), \ + .sample_rate = kDMIC_PhyFullSpeed, \ + .saturate16bit = 1U, \ + }, \ + }; + +/* Defines structures for all enabled PDM channels */ +#define PDM_DMIC_CHANNELS_DEFINE(idx) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, PDM_DMIC_CHAN_DEFINE) + +/* Gets pointer for a given PDM channel node */ +#define PDM_DMIC_CHAN_GET(pdm_node) \ + COND_CODE_1(DT_NODE_HAS_STATUS(pdm_node, okay), \ + (&pdm_channel_##pdm_node), (NULL)), + +/* Gets array of pointers to PDM channels */ +#define PDM_DMIC_CHANNELS_GET(idx) \ + DT_INST_FOREACH_CHILD(idx, PDM_DMIC_CHAN_GET) + +#define MCUX_DMIC_DEVICE(idx) \ + PDM_DMIC_CHANNELS_DEFINE(idx); \ + static struct mcux_dmic_pdm_chan \ + *pdm_channels##idx[FSL_FEATURE_DMIC_CHANNEL_NUM] = { \ + PDM_DMIC_CHANNELS_GET(idx) \ + }; \ + K_MSGQ_DEFINE(dmic_msgq##idx, sizeof(void *), \ + CONFIG_DMIC_MCUX_QUEUE_SIZE, 1); \ + static struct mcux_dmic_drv_data mcux_dmic_data##idx = { \ + .pdm_channels = pdm_channels##idx, \ + .base_address = (DMIC_Type *) DT_INST_REG_ADDR(idx), \ + .dmic_state = DMIC_STATE_UNINIT, \ + .rx_queue = &dmic_msgq##idx, \ + .active_buf_idx = 0U, \ + }; \ + \ + PINCTRL_DT_INST_DEFINE(idx); \ + static struct mcux_dmic_cfg mcux_dmic_cfg##idx = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clock_name = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(idx, name), \ + .use2fs = DT_INST_PROP(idx, use2fs), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, mcux_dmic_init, NULL, \ + &mcux_dmic_data##idx, &mcux_dmic_cfg##idx, \ + POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \ + &dmic_ops); + +/* Existing SoCs only have one PDM instance. */ +DT_INST_FOREACH_STATUS_OKAY(MCUX_DMIC_DEVICE) diff --git a/drivers/audio/tas6422dac.c b/drivers/audio/tas6422dac.c index 91c36de2897..cb1efb597ed 100644 --- a/drivers/audio/tas6422dac.c +++ b/drivers/audio/tas6422dac.c @@ -123,7 +123,9 @@ static void codec_mute_output(const struct device *dev, enum tas6422dac_channel_ #if TAS6422DAC_MUTE_GPIO_SUPPORT const struct codec_driver_config *const dev_cfg = dev->config; - gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE); + if (channel == TAS6422DAC_CHANNEL_ALL) { + gpio_pin_configure_dt(&dev_cfg->mute_gpio, GPIO_OUTPUT_ACTIVE); + } #endif codec_read_reg(dev, CH_STATE_CTRL_ADDR, &val); diff --git a/drivers/auxdisplay/auxdisplay_serlcd.c b/drivers/auxdisplay/auxdisplay_serlcd.c index f3c0e764869..19c7154de29 100644 --- a/drivers/auxdisplay/auxdisplay_serlcd.c +++ b/drivers/auxdisplay/auxdisplay_serlcd.c @@ -28,16 +28,6 @@ LOG_MODULE_REGISTER(auxdisplay_serlcd, CONFIG_AUXDISPLAY_LOG_LEVEL); */ #define SERLCD_BEGIN_SPECIAL_COMMAND 0xFE -/* - * delay in milliseconds after a normal command was sent - */ -#define SERLCD_COMMAND_DELAY_MS 10 - -/* - * delay in milliseconds after a special command was sent - */ -#define SERLCD_SPECIAL_COMMAND_DELAY_MS 50 - /* * maximum amount of custom chars the display supports */ @@ -89,6 +79,8 @@ struct auxdisplay_serlcd_data { struct auxdisplay_serlcd_config { struct auxdisplay_capabilities capabilities; struct i2c_dt_spec bus; + uint16_t command_delay_ms; + uint16_t special_command_delay_ms; }; enum auxdisplay_serlcd_command { @@ -111,7 +103,7 @@ static int auxdisplay_serlcd_send_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -124,7 +116,7 @@ auxdisplay_serlcd_send_special_command(const struct device *dev, int rc = i2c_write_dt(&config->bus, buffer, sizeof(buffer)); - k_sleep(K_MSEC(SERLCD_SPECIAL_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->special_command_delay_ms)); return rc; } @@ -269,9 +261,11 @@ static int auxdisplay_serlcd_capabilities_get(const struct device *dev, static int auxdisplay_serlcd_clear(const struct device *dev) { + const struct auxdisplay_serlcd_config *config = dev->config; + int rc = auxdisplay_serlcd_send_command(dev, SERLCD_COMMAND_CLEAR); - k_sleep(K_MSEC(SERLCD_COMMAND_DELAY_MS)); + k_sleep(K_MSEC(config->command_delay_ms)); return rc; } @@ -425,7 +419,10 @@ static const struct auxdisplay_driver_api auxdisplay_serlcd_auxdisplay_api = { .custom_character_width = SERLCD_CUSTOM_CHAR_WIDTH, \ .custom_character_height = SERLCD_CUSTOM_CHAR_HEIGHT, \ }, \ - .bus = I2C_DT_SPEC_INST_GET(inst)}; \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + .command_delay_ms = DT_INST_PROP(inst, command_delay_ms), \ + .special_command_delay_ms = DT_INST_PROP(inst, special_command_delay_ms), \ + }; \ \ static struct auxdisplay_serlcd_data auxdisplay_serlcd_data_##inst; \ \ diff --git a/drivers/bbram/CMakeLists.txt b/drivers/bbram/CMakeLists.txt index 538384e9d14..9027ab548b3 100644 --- a/drivers/bbram/CMakeLists.txt +++ b/drivers/bbram/CMakeLists.txt @@ -7,8 +7,13 @@ zephyr_library_sources_ifdef(CONFIG_BBRAM_SHELL bbram_shell.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE bbram_handlers.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX bbram_npcx.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_NPCX_EMUL bbram_npcx_emul.c) +zephyr_library_include_directories_ifdef(CONFIG_BBRAM_NPCX .) zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2 bbram_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_IT8XXX2_EMUL bbram_it8xxx2_emul.c) +zephyr_library_include_directories_ifdef(CONFIG_BBRAM_IT8XXX2 .) zephyr_library_sources_ifdef(CONFIG_BBRAM_EMUL bbram_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N bbram_microchip_mcp7940n.c) +zephyr_library_sources_ifdef(CONFIG_BBRAM_MICROCHIP_MCP7940N_EMUL bbram_microchip_mcp7940n_emul.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_XEC bbram_xec.c) zephyr_library_sources_ifdef(CONFIG_BBRAM_STM32 bbram_stm32.c) diff --git a/drivers/bbram/Kconfig.it8xxx2 b/drivers/bbram/Kconfig.it8xxx2 index a3af7e9537b..64ed29f1a52 100644 --- a/drivers/bbram/Kconfig.it8xxx2 +++ b/drivers/bbram/Kconfig.it8xxx2 @@ -8,3 +8,11 @@ config BBRAM_IT8XXX2 help This option enables the BBRAM driver for RISCV_ITE family of processors. + +config BBRAM_IT8XXX2_EMUL + bool "Emulator for the ITE IT81202 BBRAM driver" + default y + depends on BBRAM_IT8XXX2 + depends on EMUL + help + Enable the emulator for the ITE IT81202 BBRAM. diff --git a/drivers/bbram/Kconfig.microchip b/drivers/bbram/Kconfig.microchip index 015b2bcb124..35fd828e6a5 100644 --- a/drivers/bbram/Kconfig.microchip +++ b/drivers/bbram/Kconfig.microchip @@ -8,3 +8,12 @@ config BBRAM_MICROCHIP_MCP7940N select I2C help Enable driver for Microchip MCP7940N SRAM based battery-backed RAM. + +config BBRAM_MICROCHIP_MCP7940N_EMUL + bool "Emulator for the Microchip MCP7940N SRAM BBRAM driver" + default y + depends on BBRAM_MICROCHIP_MCP7940N + depends on EMUL + help + Enable the emulator for the Microchip MCP7940N SRAM based + battery-backed RAM. diff --git a/drivers/bbram/Kconfig.npcx b/drivers/bbram/Kconfig.npcx index 4b5cc135b72..e529022213e 100644 --- a/drivers/bbram/Kconfig.npcx +++ b/drivers/bbram/Kconfig.npcx @@ -7,3 +7,11 @@ config BBRAM_NPCX depends on DT_HAS_NUVOTON_NPCX_BBRAM_ENABLED help This option enables the BBRAM driver for NPCX family of processors. + +config BBRAM_NPCX_EMUL + bool "Emulator for the NPCX BBRAM driver" + default y + depends on BBRAM_NPCX + depends on EMUL + help + Enable the emulator for the NPCX BBRAM. diff --git a/drivers/bbram/bbram_it8xxx2.c b/drivers/bbram/bbram_it8xxx2.c index cae7715e702..cecf555ee8d 100644 --- a/drivers/bbram/bbram_it8xxx2.c +++ b/drivers/bbram/bbram_it8xxx2.c @@ -12,30 +12,34 @@ #include #include +#ifndef CONFIG_BBRAM_IT8XXX2_EMUL #include +#else +/* Emulation register values */ +enum bram_indices { + BRAM_IDX_VALID_FLAGS0, + BRAM_IDX_VALID_FLAGS1, + BRAM_IDX_VALID_FLAGS2, + BRAM_IDX_VALID_FLAGS3, +}; +#endif + +#include "it8xxx2.h" -LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); +LOG_MODULE_REGISTER(it8xxx2_bbram, CONFIG_BBRAM_LOG_LEVEL); -#define BRAM_VALID_MAGIC 0x4252414D /* "BRAM" */ +#define BRAM_VALID_MAGIC 0x4252414D /* "BRAM" */ #define BRAM_VALID_MAGIC_FIELD0 (BRAM_VALID_MAGIC & 0xff) #define BRAM_VALID_MAGIC_FIELD1 ((BRAM_VALID_MAGIC >> 8) & 0xff) #define BRAM_VALID_MAGIC_FIELD2 ((BRAM_VALID_MAGIC >> 16) & 0xff) #define BRAM_VALID_MAGIC_FIELD3 ((BRAM_VALID_MAGIC >> 24) & 0xff) -/** Device config */ -struct bbram_it8xxx2_config { - /** BBRAM base address */ - uintptr_t base_addr; - /** BBRAM size (Unit:bytes) */ - int size; -}; - static int bbram_it8xxx2_read(const struct device *dev, size_t offset, size_t size, uint8_t *data) { const struct bbram_it8xxx2_config *config = dev->config; if (size < 1 || offset + size > config->size) { - return -EFAULT; + return -EINVAL; } bytecpy(data, ((uint8_t *)config->base_addr + offset), size); @@ -48,16 +52,25 @@ static int bbram_it8xxx2_write(const struct device *dev, size_t offset, size_t s const struct bbram_it8xxx2_config *config = dev->config; if (size < 1 || offset + size > config->size) { - return -EFAULT; + return -EINVAL; } bytecpy(((uint8_t *)config->base_addr + offset), data, size); return 0; } +static int bbram_it8xxx2_size(const struct device *dev, size_t *size) +{ + const struct bbram_it8xxx2_config *config = dev->config; + + *size = config->size; + return 0; +} + static const struct bbram_driver_api bbram_it8xxx2_driver_api = { .read = bbram_it8xxx2_read, .write = bbram_it8xxx2_write, + .get_size = bbram_it8xxx2_size, }; static int bbram_it8xxx2_init(const struct device *dev) @@ -91,10 +104,7 @@ static int bbram_it8xxx2_init(const struct device *dev) } #define BBRAM_INIT(inst) \ - static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ - .base_addr = DT_INST_REG_ADDR(inst), \ - .size = DT_INST_REG_SIZE(inst), \ - }; \ + BBRAM_IT8XXX2_DECL_CONFIG(inst); \ DEVICE_DT_INST_DEFINE(inst, bbram_it8xxx2_init, NULL, NULL, &bbram_cfg_##inst, \ PRE_KERNEL_1, CONFIG_BBRAM_INIT_PRIORITY, \ &bbram_it8xxx2_driver_api); diff --git a/drivers/bbram/bbram_it8xxx2_emul.c b/drivers/bbram/bbram_it8xxx2_emul.c new file mode 100644 index 00000000000..901a09835f1 --- /dev/null +++ b/drivers/bbram/bbram_it8xxx2_emul.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "it8xxx2.h" + +#define DT_DRV_COMPAT ite_it8xxx2_bbram + +struct bbram_it8xxx2_emul_config { + const struct device *dev; +}; + +#define GET_CONFIG(target) \ + ((const struct bbram_it8xxx2_config \ + *)(((const struct bbram_it8xxx2_emul_config *)((target)->cfg))->dev->config)) + +static int it8xxx2_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + const struct bbram_it8xxx2_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(((uint8_t *)config->base_addr + offset), buffer, count); + return 0; +} + +static int it8xxx2_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + const struct bbram_it8xxx2_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(buffer, ((uint8_t *)config->base_addr + offset), count); + return 0; +} + +static const struct emul_bbram_backend_api it8xxx2_emul_backend_api = { + .set_data = it8xxx2_emul_backend_set_data, + .get_data = it8xxx2_emul_backend_get_data, +}; + +#define BBRAM_EMUL_INIT(inst) \ + static struct bbram_it8xxx2_emul_config bbram_it8xxx2_emul_config_##inst = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ + EMUL_DT_INST_DEFINE(inst, NULL, NULL, &bbram_it8xxx2_emul_config_##inst, NULL, \ + &it8xxx2_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(BBRAM_EMUL_INIT); diff --git a/drivers/bbram/bbram_microchip_mcp7940n.c b/drivers/bbram/bbram_microchip_mcp7940n.c index c3b538c842f..ff5b7850576 100644 --- a/drivers/bbram/bbram_microchip_mcp7940n.c +++ b/drivers/bbram/bbram_microchip_mcp7940n.c @@ -153,7 +153,7 @@ static int microchip_mcp7940n_bbram_read(const struct device *dev, size_t offset size_t i = 0; int32_t rc = 0; - if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { + if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { return -EINVAL; } @@ -186,7 +186,7 @@ static int microchip_mcp7940n_bbram_write(const struct device *dev, size_t offse size_t i = 0; int32_t rc = 0; - if ((offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { + if (size == 0 || (offset + size) > MICROCHIP_MCP7940N_SRAM_SIZE) { return -EINVAL; } diff --git a/drivers/bbram/bbram_microchip_mcp7940n_emul.c b/drivers/bbram/bbram_microchip_mcp7940n_emul.c new file mode 100644 index 00000000000..56a84825948 --- /dev/null +++ b/drivers/bbram/bbram_microchip_mcp7940n_emul.c @@ -0,0 +1,150 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mcp7940n + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(bbram_microchip_mcp7940n, CONFIG_BBRAM_LOG_LEVEL); + +#define MICROCHIP_MCP7940N_SRAM_OFFSET 0x20 +#define MICROCHIP_MCP7940N_SRAM_SIZE 64 +#define MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS 0x03 +#define MICROCHIP_MCP7940N_RTCWKDAY_VBATEN_BIT BIT(3) +#define MICROCHIP_MCP7940N_RTCWKDAY_PWRFAIL_BIT BIT(4) + +struct mcp7940n_emul_cfg { +}; + +struct mcp7940n_emul_data { + uint8_t rtcwkday; + uint8_t data[MICROCHIP_MCP7940N_SRAM_SIZE]; +}; + +static int mcp7940n_emul_init(const struct emul *target, const struct device *parent) +{ + ARG_UNUSED(target); + ARG_UNUSED(parent); + return 0; +} + +static int mcp7940n_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + struct mcp7940n_emul_data *data = target->data; + + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + + if (num_msgs < 1) { + LOG_ERR("Invalid number of messages: %d", num_msgs); + return -EIO; + } + if (FIELD_GET(I2C_MSG_READ, msgs->flags)) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len < 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + + uint8_t regn = msgs->buf[0]; + bool is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1; + bool is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1; + + if (!is_stop && !is_read) { + /* First message was a write with the register number, check next message */ + msgs++; + is_read = FIELD_GET(I2C_MSG_READ, msgs->flags) == 1; + is_stop = FIELD_GET(I2C_MSG_STOP, msgs->flags) == 1; + } + + if (is_read) { + /* Read data */ + if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) { + msgs->buf[0] = data->rtcwkday; + return 0; + } + if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET && + regn + msgs->len <= + MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) { + for (int i = 0; i < msgs->len; ++i) { + msgs->buf[i] = + data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET]; + } + return 0; + } + } else { + /* Write data */ + if (regn == MICROCHIP_MCP7940N_RTCWKDAY_REGISTER_ADDRESS) { + data->rtcwkday = msgs->buf[1]; + return 0; + } + if (regn >= MICROCHIP_MCP7940N_SRAM_OFFSET && + regn + msgs->len - 1 <= + MICROCHIP_MCP7940N_SRAM_OFFSET + MICROCHIP_MCP7940N_SRAM_SIZE) { + for (int i = 0; i < msgs->len; ++i) { + data->data[regn + i - MICROCHIP_MCP7940N_SRAM_OFFSET] = + msgs->buf[1 + i]; + } + return 0; + } + } + + return -EIO; +} + +static const struct i2c_emul_api mcp7940n_emul_api_i2c = { + .transfer = mcp7940n_emul_transfer_i2c, +}; + +static int mcp7940n_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + struct mcp7940n_emul_data *data = target->data; + + if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) { + return -ERANGE; + } + + for (size_t i = 0; i < count; ++i) { + data->data[offset + i] = buffer[i]; + } + return 0; +} + +static int mcp7940n_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + struct mcp7940n_emul_data *data = target->data; + + if (offset + count > MICROCHIP_MCP7940N_SRAM_SIZE) { + return -ERANGE; + } + + for (size_t i = 0; i < count; ++i) { + buffer[i] = data->data[offset + i]; + } + return 0; +} + +static const struct emul_bbram_backend_api mcp7940n_emul_backend_api = { + .set_data = mcp7940n_emul_backend_set_data, + .get_data = mcp7940n_emul_backend_get_data, +}; + +#define MCP7940N_EMUL(inst) \ + static const struct mcp7940n_emul_cfg mcp7940n_emul_cfg_##inst; \ + static struct mcp7940n_emul_data mcp7940n_emul_data_##inst; \ + EMUL_DT_INST_DEFINE(inst, mcp7940n_emul_init, &mcp7940n_emul_data_##inst, \ + &mcp7940n_emul_cfg_##inst, &mcp7940n_emul_api_i2c, \ + &mcp7940n_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(MCP7940N_EMUL) diff --git a/drivers/bbram/bbram_npcx.c b/drivers/bbram/bbram_npcx.c index b9b02f90eb3..ba9500ae6f1 100644 --- a/drivers/bbram/bbram_npcx.c +++ b/drivers/bbram/bbram_npcx.c @@ -11,17 +11,9 @@ #include #include -LOG_MODULE_REGISTER(bbram, CONFIG_BBRAM_LOG_LEVEL); - -/** Device config */ -struct bbram_npcx_config { - /** BBRAM base address */ - uintptr_t base_addr; - /** BBRAM size (Unit:bytes) */ - int size; - /** Status register base address */ - uintptr_t status_reg_addr; -}; +LOG_MODULE_REGISTER(npcx_bbram, CONFIG_BBRAM_LOG_LEVEL); + +#include "npcx.h" #define NPCX_STATUS_IBBR BIT(7) #define NPCX_STATUS_VSBY BIT(1) @@ -35,7 +27,7 @@ static int get_bit_and_reset(const struct device *dev, int mask) int result = DRV_STATUS(dev) & mask; /* Clear the bit(s) */ - DRV_STATUS(dev) = mask; + DRV_STATUS(dev) &= ~mask; return result; } @@ -69,7 +61,7 @@ static int bbram_npcx_read(const struct device *dev, size_t offset, size_t size, const struct bbram_npcx_config *config = dev->config; if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) { - return -EFAULT; + return -EINVAL; } @@ -83,7 +75,7 @@ static int bbram_npcx_write(const struct device *dev, size_t offset, size_t size const struct bbram_npcx_config *config = dev->config; if (size < 1 || offset + size > config->size || bbram_npcx_check_invalid(dev)) { - return -EFAULT; + return -EINVAL; } bytecpy(((uint8_t *)config->base_addr + offset), data, size); @@ -100,14 +92,8 @@ static const struct bbram_driver_api bbram_npcx_driver_api = { }; #define BBRAM_INIT(inst) \ - static struct { \ - } bbram_data_##inst; \ - static const struct bbram_npcx_config bbram_cfg_##inst = { \ - .base_addr = DT_INST_REG_ADDR_BY_NAME(inst, memory), \ - .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ - .status_reg_addr = DT_INST_REG_ADDR_BY_NAME(inst, status), \ - }; \ - DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &bbram_data_##inst, &bbram_cfg_##inst, \ - PRE_KERNEL_1, CONFIG_BBRAM_INIT_PRIORITY, &bbram_npcx_driver_api); + BBRAM_NPCX_DECL_CONFIG(inst); \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, &bbram_cfg_##inst, PRE_KERNEL_1, \ + CONFIG_BBRAM_INIT_PRIORITY, &bbram_npcx_driver_api); DT_INST_FOREACH_STATUS_OKAY(BBRAM_INIT); diff --git a/drivers/bbram/bbram_npcx_emul.c b/drivers/bbram/bbram_npcx_emul.c new file mode 100644 index 00000000000..799e158eefd --- /dev/null +++ b/drivers/bbram/bbram_npcx_emul.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "npcx.h" + +#define DT_DRV_COMPAT nuvoton_npcx_bbram + +struct bbram_npcx_emul_config { + const struct device *dev; +}; + +#define GET_CONFIG(target) \ + ((const struct bbram_npcx_config \ + *)(((const struct bbram_npcx_emul_config *)((target)->cfg))->dev->config)) + +static int npcx_emul_backend_set_data(const struct emul *target, size_t offset, size_t count, + const uint8_t *buffer) +{ + const struct bbram_npcx_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(((uint8_t *)config->base_addr + offset), buffer, count); + return 0; +} + +static int npcx_emul_backend_get_data(const struct emul *target, size_t offset, size_t count, + uint8_t *buffer) +{ + const struct bbram_npcx_config *config = GET_CONFIG(target); + + if (offset + count > config->size) { + return -ERANGE; + } + + bytecpy(buffer, ((uint8_t *)config->base_addr + offset), count); + return 0; +} + +static const struct emul_bbram_backend_api npcx_emul_backend_api = { + .set_data = npcx_emul_backend_set_data, + .get_data = npcx_emul_backend_get_data, +}; + +#define BBRAM_EMUL_INIT(inst) \ + static struct bbram_npcx_emul_config bbram_npcx_emul_config_##inst = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ + EMUL_DT_INST_DEFINE(inst, NULL, NULL, &bbram_npcx_emul_config_##inst, NULL, \ + &npcx_emul_backend_api) + +DT_INST_FOREACH_STATUS_OKAY(BBRAM_EMUL_INIT); diff --git a/drivers/bbram/it8xxx2.h b/drivers/bbram/it8xxx2.h new file mode 100644 index 00000000000..d5e905d4f72 --- /dev/null +++ b/drivers/bbram/it8xxx2.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ +#define INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ + +#include + +#include + +/** Device config */ +struct bbram_it8xxx2_config { + /** BBRAM base address */ + uintptr_t base_addr; + /** BBRAM size (Unit:bytes) */ + int size; +}; + +#ifdef CONFIG_BBRAM_IT8XXX2_EMUL +#define BBRAM_IT8XXX2_DECL_CONFIG(inst) \ + static uint8_t bbram_it8xxx2_emul_buffer_##inst[DT_INST_REG_SIZE(inst)]; \ + static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ + .base_addr = (uintptr_t)bbram_it8xxx2_emul_buffer_##inst, \ + .size = DT_INST_REG_SIZE(inst), \ + } +#else +#define BBRAM_IT8XXX2_DECL_CONFIG(inst) \ + static const struct bbram_it8xxx2_config bbram_cfg_##inst = { \ + .base_addr = DT_INST_REG_ADDR(inst), \ + .size = DT_INST_REG_SIZE(inst), \ + } +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_BBRAM_IT8XXX2_H_ */ diff --git a/drivers/bbram/npcx.h b/drivers/bbram/npcx.h new file mode 100644 index 00000000000..b177a94f32a --- /dev/null +++ b/drivers/bbram/npcx.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Google Inc + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ +#define INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ + +#include + +#include + +/** Device config */ +struct bbram_npcx_config { + /** BBRAM base address */ + uintptr_t base_addr; + /** BBRAM size (Unit:bytes) */ + int size; + /** Status register base address */ + uintptr_t status_reg_addr; +}; + +#ifdef CONFIG_BBRAM_NPCX_EMUL +#define BBRAM_NPCX_DECL_CONFIG(inst) \ + static uint8_t bbram_npcx_emul_buffer_##inst[DT_INST_REG_SIZE_BY_NAME(inst, memory)]; \ + static uint8_t bbram_npcx_emul_status_##inst; \ + static const struct bbram_npcx_config bbram_cfg_##inst = { \ + .base_addr = (uintptr_t)bbram_npcx_emul_buffer_##inst, \ + .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ + .status_reg_addr = (uintptr_t)&bbram_npcx_emul_status_##inst, \ + } +#else +#define BBRAM_NPCX_DECL_CONFIG(inst) \ + static const struct bbram_npcx_config bbram_cfg_##inst = { \ + .base_addr = DT_INST_REG_ADDR_BY_NAME(inst, memory), \ + .size = DT_INST_REG_SIZE_BY_NAME(inst, memory), \ + .status_reg_addr = DT_INST_REG_ADDR_BY_NAME(inst, status), \ + } +#endif + +#endif /* INCLUDE_ZEPHYR_DRIVERS_BBRAM_NPCX_H_ */ diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index 6aaf5205b0d..adda6ea0e2a 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -19,9 +19,17 @@ zephyr_library_sources_ifdef(CONFIG_BT_ESP32 hci_esp32.c) zephyr_library_sources_ifdef(CONFIG_BT_H4 h4.c) zephyr_library_sources_ifdef(CONFIG_BT_H5 h5.c) zephyr_library_sources_ifdef(CONFIG_BT_HCI_IPC ipc.c) -zephyr_library_sources_ifdef(CONFIG_BT_SPI spi.c) +if(CONFIG_BT_SPI) + if ((CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED) OR (CONFIG_DT_HAS_ST_HCI_SPI_V2_ENABLED)) + zephyr_library_sources(hci_spi_st.c) + else() + zephyr_library_sources(spi.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_BT_STM32_IPM ipm_stm32wb.c) +zephyr_library_sources_ifdef(CONFIG_BT_STM32WBA hci_stm32wba.c) zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) zephyr_library_sources_ifdef(CONFIG_BT_SILABS_HCI slz_hci.c) zephyr_library_sources_ifdef(CONFIG_BT_PSOC6_BLESS hci_psoc6_bless.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf53_support.c) +zephyr_library_sources_ifdef(CONFIG_BT_AMBIQ_HCI hci_ambiq.c apollox_blue.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 0f792b58b08..ad1d9da2df2 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -62,6 +62,12 @@ config BT_STM32_IPM help TODO +config BT_STM32WBA + bool "STM32WBA HCI driver" + select HAS_STM32LIB + help + ST STM32WBA HCI Bluetooth interface + config BT_SILABS_HCI bool "Silicon Labs Bluetooth interface" depends on SOC_SERIES_EFR32BG22 || SOC_SERIES_EFR32MG24 || SOC_SERIES_EFR32BG27 @@ -110,6 +116,16 @@ config BT_NO_DRIVER This is intended for unit tests where no internal driver should be selected. +config BT_AMBIQ_HCI + bool "AMBIQ BT HCI driver" + select SPI + select GPIO + select CLOCK_CONTROL + select BT_HCI_SETUP + help + Supports Ambiq Bluetooth SoC using SPI as the communication protocol. + HCI packets are sent and received as single Byte transfers. + endchoice if BT_SPI @@ -120,17 +136,23 @@ config BT_SPI_INIT_PRIORITY config BT_BLUENRG_ACI bool "ACI message with with BlueNRG-based devices" + select BT_HCI_SET_PUBLIC_ADDR help Enable support for devices compatible with the BlueNRG Bluetooth Stack. Current driver supports: ST BLUENRG-MS. -config BT_SPI_BLUENRG - bool "Compatibility with BlueNRG-based devices" +endif # BT_SPI + +if BT_AMBIQ_HCI + +config BT_HCI_INIT_PRIORITY + int "BT HCI init priority" + default 75 help - Enable support for devices compatible with the BlueNRG Bluetooth - Stack. Current driver supports: ST BLUENRG-MS. + The priority of BT HCI driver initialization needs to be lower than + the SPI, GPIO, clock controller drivers initialization priorities. -endif # BT_SPI +endif # BT_AMBIQ_HCI config BT_STM32_IPM_RX_STACK_SIZE int "STM32 IPM stack size for RX thread" @@ -164,6 +186,19 @@ config BT_DRIVER_QUIRK_NO_AUTO_DLE This has to be enabled when the BLE controller connected is Zephyr open source controller. +config BT_HCI_SET_PUBLIC_ADDR + bool + select BT_HCI_SETUP + help + Pass the controller's public address to the HCI driver in setup() + + This option should be enabled by drivers for controllers that support setting the + public identity through vendor-specific commands. They can then implement the + setup() HCI driver API function and get the address to set from the public_addr field. + + From the application side, the public address is set using the first call to + bt_id_create(), before calling bt_enable(). + config BT_HCI_SETUP bool help @@ -185,7 +220,7 @@ config BT_DRV_TX_STACK_SIZE config BT_DRV_RX_STACK_SIZE int - default 512 if BT_SPI + default 640 if (BT_SPI || BT_AMBIQ_HCI) default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4) default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM default 256 diff --git a/drivers/bluetooth/hci/Kconfig.infineon b/drivers/bluetooth/hci/Kconfig.infineon index 1f4193bd28a..6204ed4f8a2 100644 --- a/drivers/bluetooth/hci/Kconfig.infineon +++ b/drivers/bluetooth/hci/Kconfig.infineon @@ -129,11 +129,6 @@ config AIROC_CUSTOM_FIRMWARE_HCD_BLOB config BT_BUF_CMD_TX_SIZE default 255 -# Disable ATT_ENFORCE_FLOW feature, CYW43XX informs about frees buffer -# (HCL Number Of Completed Packets event) after second packet. -config BT_ATT_ENFORCE_FLOW - default n - endif # BT_AIROC if BT_PSOC6_BLESS diff --git a/drivers/bluetooth/hci/apollox_blue.c b/drivers/bluetooth/hci/apollox_blue.c new file mode 100644 index 00000000000..eff8d8fbd81 --- /dev/null +++ b/drivers/bluetooth/hci/apollox_blue.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Ambiq Apollox Blue SoC extended driver for SPI based HCI. + */ + +#define DT_DRV_COMPAT ambiq_bt_hci_spi + +#include +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_apollox_driver); + +#include +#include + +#include "apollox_blue.h" +#include "am_devices_cooper.h" + +#define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi) +#define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE) +#define CLK_32M_NODE DT_NODELABEL(xo32m) +#define CLK_32K_NODE DT_NODELABEL(xo32k) + +/* Command/response for SPI operation */ +#define SPI_WRITE 0x80 +#define SPI_READ 0x04 +#define READY_BYTE0 0x68 +#define READY_BYTE1 0xA8 + +/* Maximum attempts of SPI write */ +#define SPI_WRITE_TIMEOUT 200 + +#define SPI_MAX_RX_MSG_LEN 258 + +static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, irq_gpios); +static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, reset_gpios); +static const struct gpio_dt_spec cs_gpio = GPIO_DT_SPEC_GET(SPI_DEV_NODE, cs_gpios); +static const struct gpio_dt_spec clkreq_gpio = GPIO_DT_SPEC_GET(HCI_SPI_NODE, clkreq_gpios); + +static struct gpio_callback irq_gpio_cb; +static struct gpio_callback clkreq_gpio_cb; + +static const struct device *clk32m_dev = DEVICE_DT_GET(CLK_32M_NODE); +static const struct device *clk32k_dev = DEVICE_DT_GET(CLK_32K_NODE); + +extern void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3); + +static bool irq_pin_state(void) +{ + int pin_state; + + pin_state = gpio_pin_get_dt(&irq_gpio); + LOG_DBG("IRQ Pin: %d", pin_state); + return pin_state > 0; +} + +static bool clkreq_pin_state(void) +{ + int pin_state; + + pin_state = gpio_pin_get_dt(&clkreq_gpio); + LOG_DBG("CLKREQ Pin: %d", pin_state); + return pin_state > 0; +} + +static void bt_clkreq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3) +{ + if (clkreq_pin_state()) { + /* Enable XO32MHz */ + clock_control_on(clk32m_dev, + (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_FALLING); + } else { + /* Disable XO32MHz */ + clock_control_off(clk32m_dev, + (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING); + } +} + +static void bt_apollo_controller_ready_wait(void) +{ + /* The CS pin is used to wake up the controller as well. If the controller is not ready + * to receive the SPI packet, need to inactivate the CS at first and reconfigure the pin + * to CS function again before next sending attempt. + */ + gpio_pin_configure_dt(&cs_gpio, GPIO_OUTPUT_INACTIVE); + k_busy_wait(200); + PINCTRL_DT_DEFINE(SPI_DEV_NODE); + pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(SPI_DEV_NODE), PINCTRL_STATE_DEFAULT); + k_busy_wait(2000); +} + +static void bt_apollo_controller_reset(void) +{ + /* Reset the controller*/ + gpio_pin_set_dt(&rst_gpio, 1); + + /* Take controller out of reset */ + k_sleep(K_MSEC(10)); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Give the controller some time to boot */ + k_sleep(K_MSEC(500)); +} + +int bt_apollo_spi_send(uint8_t *data, uint16_t len, bt_spi_transceive_fun transceive) +{ + int ret; + uint8_t command[1] = {SPI_WRITE}; + uint8_t response[2] = {0, 0}; + uint16_t fail_count = 0; + + do { + /* Check if the controller is ready to receive the HCI packets. */ + ret = transceive(command, 1, response, 2); + if ((response[0] != READY_BYTE0) || (response[1] != READY_BYTE1) || ret) { + bt_apollo_controller_ready_wait(); + } else { + /* Transmit the message */ + ret = transceive(data, len, NULL, 0); + if (ret) { + LOG_ERR("SPI write error %d", ret); + } + break; + } + } while (fail_count++ < SPI_WRITE_TIMEOUT); + + return ret; +} + +int bt_apollo_spi_rcv(uint8_t *data, uint16_t *len, bt_spi_transceive_fun transceive) +{ + int ret; + uint8_t command[1] = {SPI_READ}; + uint8_t response[2] = {0, 0}; + uint16_t read_size = 0; + + do { + /* Skip if the IRQ pin is not in high state */ + if (!irq_pin_state()) { + ret = -1; + break; + } + + /* Check the available packet bytes */ + ret = transceive(command, 1, response, 2); + if (ret) { + break; + } + + /* Check if the read size is acceptable */ + read_size = (uint16_t)(response[0] | response[1] << 8); + if ((read_size == 0) || (read_size > SPI_MAX_RX_MSG_LEN)) { + ret = -1; + break; + } + + *len = read_size; + + /* Read the HCI data from controller */ + ret = transceive(NULL, 0, data, read_size); + + if (ret) { + LOG_ERR("SPI read error %d", ret); + break; + } + } while (0); + + return ret; +} + +bool bt_apollo_vnd_rcv_ongoing(uint8_t *data, uint16_t len) +{ + /* The vendor specific handshake command/response is incompatible with + * standard Bluetooth HCI format, need to handle the received packets + * specifically. + */ + if (am_devices_cooper_get_initialize_state() != AM_DEVICES_COOPER_STATE_INITIALIZED) { + am_devices_cooper_handshake_recv(data, len); + return true; + } else { + return false; + } +} + +int bt_hci_transport_setup(const struct device *dev) +{ + ARG_UNUSED(dev); + + int ret; + + /* Configure the XO32MHz and XO32kHz clocks.*/ + clock_control_configure(clk32k_dev, NULL, NULL); + clock_control_configure(clk32m_dev, NULL, NULL); + + /* Enable XO32kHz for Controller */ + clock_control_on(clk32k_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL); + + /* Enable XO32MHz for Controller */ + clock_control_on(clk32m_dev, (clock_control_subsys_t)CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE); + + /* Configure RST pin and hold BLE in Reset */ + ret = gpio_pin_configure_dt(&rst_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + + /* Configure IRQ pin and register the callback */ + ret = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + if (ret) { + return ret; + } + + gpio_init_callback(&irq_gpio_cb, bt_packet_irq_isr, BIT(irq_gpio.pin)); + ret = gpio_add_callback(irq_gpio.port, &irq_gpio_cb); + if (ret) { + return ret; + } + + /* Configure CLKREQ pin and register the callback */ + ret = gpio_pin_configure_dt(&clkreq_gpio, GPIO_INPUT); + if (ret) { + return ret; + } + + gpio_init_callback(&clkreq_gpio_cb, bt_clkreq_isr, BIT(clkreq_gpio.pin)); + ret = gpio_add_callback(clkreq_gpio.port, &clkreq_gpio_cb); + if (ret) { + return ret; + } + + /* Configure the interrupt edge for CLKREQ pin */ + gpio_pin_interrupt_configure_dt(&clkreq_gpio, GPIO_INT_EDGE_RISING); + + /* Take controller out of reset */ + k_sleep(K_MSEC(10)); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Give the controller some time to boot */ + k_sleep(K_MSEC(500)); + + /* Configure the interrupt edge for IRQ pin */ + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_RISING); + + return 0; +} + +int bt_apollo_controller_init(spi_transmit_fun transmit) +{ + int ret; + am_devices_cooper_callback_t cb = { + .write = transmit, + .reset = bt_apollo_controller_reset, + }; + + /* Initialize the BLE controller */ + ret = am_devices_cooper_init(&cb); + if (ret == AM_DEVICES_COOPER_STATUS_SUCCESS) { + am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZED); + LOG_INF("BT controller initialized"); + } else { + am_devices_cooper_set_initialize_state(AM_DEVICES_COOPER_STATE_INITIALIZE_FAIL); + LOG_ERR("BT controller initialization fail"); + } + + return ret; +} + +static int bt_apollo_set_nvds(void) +{ + int ret; + struct net_buf *buf; + +#if defined(CONFIG_BT_HCI_RAW) + struct bt_hci_cmd_hdr hdr; + + hdr.opcode = sys_cpu_to_le16(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE); + hdr.param_len = HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH; + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_mem(buf, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + ret = bt_send(buf); + + if (!ret) { + /* Give some time to make NVDS take effect in BLE controller */ + k_sleep(K_MSEC(5)); + + /* Need to send reset command to make the NVDS take effect */ + hdr.opcode = sys_cpu_to_le16(BT_HCI_OP_RESET); + hdr.param_len = 0; + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr)); + if (!buf) { + return -ENOBUFS; + } + + ret = bt_send(buf); + } +#else + uint8_t *p; + + buf = bt_hci_cmd_create(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE, + HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + if (!buf) { + return -ENOBUFS; + } + + p = net_buf_add(buf, HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + memcpy(p, &am_devices_cooper_nvds[0], HCI_VSC_UPDATE_NVDS_CFG_CMD_LENGTH); + ret = bt_hci_cmd_send_sync(HCI_VSC_UPDATE_NVDS_CFG_CMD_OPCODE, buf, NULL); + + if (!ret) { + /* Give some time to make NVDS take effect in BLE controller */ + k_sleep(K_MSEC(5)); + } +#endif /* defined(CONFIG_BT_HCI_RAW) */ + + return ret; +} + +int bt_apollo_vnd_setup(void) +{ + int ret; + + /* Set the NVDS parameters to BLE controller */ + ret = bt_apollo_set_nvds(); + + return ret; +} + +int bt_apollo_dev_init(void) +{ + if (!gpio_is_ready_dt(&irq_gpio)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&rst_gpio)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&clkreq_gpio)) { + LOG_ERR("CLKREQ GPIO device not ready"); + return -ENODEV; + } + + return 0; +} diff --git a/drivers/bluetooth/hci/apollox_blue.h b/drivers/bluetooth/hci/apollox_blue.h new file mode 100644 index 00000000000..a05238657e5 --- /dev/null +++ b/drivers/bluetooth/hci/apollox_blue.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Header file of Ambiq Apollox Blue SoC extended driver + * for SPI based HCI. + */ +#ifndef ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ +#define ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @typedef bt_spi_transceive_fun + * @brief SPI transceive function for Bluetooth packet. + * + * @param tx Pointer of transmission packet. + * @param tx_len Length of transmission packet. + * @param rx Pointer of reception packet. + * @param rx_len Length of reception packet. + * + * @return 0 on success or negative error number on failure. + */ +typedef int (*bt_spi_transceive_fun)(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len); + +/** + * @typedef spi_transmit_fun + * @brief Define the SPI transmission function. + * + * @param data Pointer of transmission packet. + * @param len Length of transmission packet. + * + * @return 0 on success or negative error number on failure. + */ +typedef int (*spi_transmit_fun)(uint8_t *data, uint16_t len); + +/** + * @brief Initialize the required devices for HCI driver. + * + * The devices mainly include the required gpio (e.g. reset-gpios, + * irq-gpios). + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_dev_init(void); + +/** + * @brief Send the packets to BLE controller from host via SPI. + * + * @param data Pointer of transmission packet. + * @param len Length of transmission packet. + * @param transceive SPI transceive function for Bluetooth packet. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_spi_send(uint8_t *data, uint16_t len, bt_spi_transceive_fun transceive); + +/** + * @brief Receive the packets sent from BLE controller to host via SPI. + * + * @param data Pointer of reception packet. + * @param len Pointer of reception packet length. + * @param transceive SPI transceive function for Bluetooth packet. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_spi_rcv(uint8_t *data, uint16_t *len, bt_spi_transceive_fun transceive); + +/** + * @brief Initialize the BLE controller. + * + * This step may do the necessary handshaking with the controller before + * @param transmit SPI transmit function + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_controller_init(spi_transmit_fun transmit); + +/** + * @brief Vendor specific setup before general HCI command sequence for + * Bluetooth application. + * + * @return 0 on success or negative error number on failure. + */ +int bt_apollo_vnd_setup(void); + +/** + * @brief Check if vendor specific receiving handling is ongoing. + * + * @param data Pointer of received packet. + * + * @return true indicates if vendor specific receiving handling is ongoing. + */ +bool bt_apollo_vnd_rcv_ongoing(uint8_t *data, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_BLUETOOTH_HCI_APOLLOX_BLUE_H_ */ diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index c263c3f0c5d..e5cd81a06b8 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -346,7 +346,8 @@ static inline void read_payload(void) bt_recv_prio(buf); } - if (evt_flags & BT_HCI_EVT_FLAG_RECV) { + if ((evt_flags & BT_HCI_EVT_FLAG_RECV) || + !IS_ENABLED(CONFIG_BT_RECV_BLOCKING)) { LOG_DBG("Putting buf %p to rx fifo", buf); net_buf_put(&rx.fifo, buf); } @@ -529,8 +530,10 @@ static int h4_open(void) } #if defined(CONFIG_BT_HCI_SETUP) -static int h4_setup(void) +static int h4_setup(const struct bt_hci_setup_params *params) { + ARG_UNUSED(params); + /* Extern bt_h4_vnd_setup function. * This function executes vendor-specific commands sequence to * initialize BT Controller before BT Host executes Reset sequence. diff --git a/drivers/bluetooth/hci/hci_ambiq.c b/drivers/bluetooth/hci/hci_ambiq.c new file mode 100644 index 00000000000..b0c6ee43337 --- /dev/null +++ b/drivers/bluetooth/hci/hci_ambiq.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Ambiq SPI based Bluetooth HCI driver. + */ + +#define DT_DRV_COMPAT ambiq_bt_hci_spi + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_hci_driver); + +#include "apollox_blue.h" + +#define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi) +#define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE) + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 + +/* Offset of special item */ +#define PACKET_TYPE 0 +#define PACKET_TYPE_SIZE 1 +#define EVT_HEADER_TYPE 0 +#define EVT_HEADER_EVENT 1 +#define EVT_HEADER_SIZE 2 +#define EVT_VENDOR_CODE_LSB 3 +#define EVT_VENDOR_CODE_MSB 4 +#define CMD_OGF 1 +#define CMD_OCF 2 + +#define EVT_OK 0 +#define EVT_DISCARD 1 +#define EVT_NOP 2 + +/* Max SPI buffer length for transceive operations. + * The maximum TX packet number is 512 bytes data + 12 bytes header. + * The maximum RX packet number is 255 bytes data + 3 header. + */ +#define SPI_MAX_TX_MSG_LEN 524 +#define SPI_MAX_RX_MSG_LEN 258 + +static uint8_t __noinit rxmsg[SPI_MAX_RX_MSG_LEN]; +static const struct device *spi_dev = DEVICE_DT_GET(SPI_DEV_NODE); +static struct spi_config spi_cfg = { + .operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA | + SPI_WORD_SET(8), +}; +static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); +static struct k_thread spi_rx_thread_data; + +static struct spi_buf spi_tx_buf; +static struct spi_buf spi_rx_buf; +static const struct spi_buf_set spi_tx = {.buffers = &spi_tx_buf, .count = 1}; +static const struct spi_buf_set spi_rx = {.buffers = &spi_rx_buf, .count = 1}; + +static K_SEM_DEFINE(sem_irq, 0, 1); +static K_SEM_DEFINE(sem_spi_available, 1, 1); + +void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2, + uint32_t unused3) +{ + k_sem_give(&sem_irq); +} + +static inline int bt_spi_transceive(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len) +{ + spi_tx_buf.buf = tx; + spi_tx_buf.len = (size_t)tx_len; + spi_rx_buf.buf = rx; + spi_rx_buf.len = (size_t)rx_len; + return spi_transceive(spi_dev, &spi_cfg, &spi_tx, &spi_rx); +} + +static int spi_send_packet(uint8_t *data, uint16_t len) +{ + int ret; + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_spi_available, K_FOREVER); + + /* Send the SPI packet to controller */ + ret = bt_apollo_spi_send(data, len, bt_spi_transceive); + + /* Free the SPI bus */ + k_sem_give(&sem_spi_available); + + return ret; +} + +static int spi_receive_packet(uint8_t *data, uint16_t *len) +{ + int ret; + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_spi_available, K_FOREVER); + + /* Receive the SPI packet from controller */ + ret = bt_apollo_spi_rcv(data, len, bt_spi_transceive); + + /* Free the SPI bus */ + k_sem_give(&sem_spi_available); + + return ret; +} + +static int hci_event_filter(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return EVT_DISCARD; + default: + return EVT_OK; + } + } + case BT_HCI_EVT_CMD_COMPLETE: { + uint16_t opcode = (uint16_t)(evt_data[3] + (evt_data[4] << 8)); + + switch (opcode) { + case BT_OP_NOP: + return EVT_NOP; + default: + return EVT_OK; + } + } + default: + return EVT_OK; + } +} + +static struct net_buf *bt_hci_evt_recv(uint8_t *data, size_t len) +{ + int evt_filter; + bool discardable = false; + struct bt_hci_evt_hdr hdr = {0}; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for event header"); + return NULL; + } + + evt_filter = hci_event_filter(data); + if (evt_filter == EVT_NOP) { + /* The controller sends NOP event when wakes up based on + * hardware specific requirement, do not post this event to + * host stack. + */ + return NULL; + } else if (evt_filter == EVT_DISCARD) { + discardable = true; + } + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + if (len != hdr.len) { + LOG_ERR("Event payload length is not correct"); + return NULL; + } + + buf = bt_buf_get_evt(hdr.evt, discardable, K_NO_WAIT); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + } else { + LOG_ERR("No available event buffers!"); + } + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static struct net_buf *bt_hci_acl_recv(uint8_t *data, size_t len) +{ + struct bt_hci_acl_hdr hdr = {0}; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (len != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static void bt_spi_rx_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct net_buf *buf; + int ret; + uint16_t len = 0; + + while (true) { + /* Wait for controller interrupt */ + k_sem_take(&sem_irq, K_FOREVER); + + do { + /* Recevive the HCI packet via SPI */ + ret = spi_receive_packet(&rxmsg[0], &len); + if (ret) { + break; + } + + /* Check if needs to handle the vendor specific events which are + * incompatible with the standard Bluetooth HCI format. + */ + if (bt_apollo_vnd_rcv_ongoing(&rxmsg[0], len)) { + break; + } + + switch (rxmsg[PACKET_TYPE]) { + case HCI_EVT: + buf = bt_hci_evt_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], + (len - PACKET_TYPE_SIZE)); + break; + case HCI_ACL: + buf = bt_hci_acl_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE], + (len - PACKET_TYPE_SIZE)); + break; + default: + buf = NULL; + LOG_WRN("Unknown BT buf type %d", rxmsg[PACKET_TYPE]); + break; + } + + /* Post the RX message to host stack to process */ + if (buf) { + bt_recv(buf); + } + } while (0); + } +} + +static int bt_hci_send(struct net_buf *buf) +{ + int ret = 0; + + /* Buffer needs an additional byte for type */ + if (buf->len >= SPI_MAX_TX_MSG_LEN) { + LOG_ERR("Message too long"); + return -EINVAL; + } + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + net_buf_push_u8(buf, HCI_ACL); + break; + case BT_BUF_CMD: + net_buf_push_u8(buf, HCI_CMD); + break; + default: + LOG_ERR("Unsupported type"); + net_buf_unref(buf); + return -EINVAL; + } + + /* Send the SPI packet */ + ret = spi_send_packet(buf->data, buf->len); + + net_buf_unref(buf); + + return ret; +} + +static int bt_hci_open(void) +{ + int ret; + + ret = bt_hci_transport_setup(spi_dev); + if (ret) { + return ret; + } + + /* Start RX thread */ + k_thread_create(&spi_rx_thread_data, spi_rx_stack, K_KERNEL_STACK_SIZEOF(spi_rx_stack), + (k_thread_entry_t)bt_spi_rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); + + ret = bt_apollo_controller_init(spi_send_packet); + + return ret; +} + +static int bt_spi_setup(const struct bt_hci_setup_params *params) +{ + ARG_UNUSED(params); + + int ret; + + ret = bt_apollo_vnd_setup(); + + return ret; +} + +static const struct bt_hci_driver drv = { + .name = "ambiq hci", + .bus = BT_HCI_DRIVER_BUS_SPI, + .open = bt_hci_open, + .send = bt_hci_send, + .setup = bt_spi_setup, +}; + +static int bt_hci_init(void) +{ + int ret; + + if (!device_is_ready(spi_dev)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + ret = bt_apollo_dev_init(); + if (ret) { + return ret; + } + + bt_hci_driver_register(&drv); + + LOG_DBG("BT HCI initialized"); + + return 0; +} + +SYS_INIT(bt_hci_init, POST_KERNEL, CONFIG_BT_HCI_INIT_PRIORITY); diff --git a/drivers/bluetooth/hci/hci_esp32.c b/drivers/bluetooth/hci/hci_esp32.c index 8dae220dd94..121157d41bb 100644 --- a/drivers/bluetooth/hci/hci_esp32.c +++ b/drivers/bluetooth/hci/hci_esp32.c @@ -303,6 +303,25 @@ static int bt_esp32_ble_init(void) return 0; } +static int bt_esp32_ble_deinit(void) +{ + int ret; + + ret = esp_bt_controller_disable(); + if (ret) { + LOG_ERR("Bluetooth controller disable failed %d", ret); + return ret; + } + + ret = esp_bt_controller_deinit(); + if (ret) { + LOG_ERR("Bluetooth controller deinit failed %d", ret); + return ret; + } + + return 0; +} + static int bt_esp32_open(void) { int err; @@ -317,10 +336,25 @@ static int bt_esp32_open(void) return 0; } +static int bt_esp32_close(void) +{ + int err; + + err = bt_esp32_ble_deinit(); + if (err) { + return err; + } + + LOG_DBG("ESP32 BT stopped"); + + return 0; +} + static const struct bt_hci_driver drv = { .name = "BT ESP32", .open = bt_esp32_open, .send = bt_esp32_send, + .close = bt_esp32_close, .bus = BT_HCI_DRIVER_BUS_IPM, #if defined(CONFIG_BT_DRIVER_QUIRK_NO_AUTO_DLE) .quirks = BT_QUIRK_NO_AUTO_DLE, @@ -329,7 +363,6 @@ static const struct bt_hci_driver drv = { static int bt_esp32_init(void) { - bt_hci_driver_register(&drv); return 0; diff --git a/drivers/bluetooth/hci/hci_psoc6_bless.c b/drivers/bluetooth/hci/hci_psoc6_bless.c index 3a5fddb1000..9f56eba7f60 100644 --- a/drivers/bluetooth/hci/hci_psoc6_bless.c +++ b/drivers/bluetooth/hci/hci_psoc6_bless.c @@ -196,8 +196,9 @@ static int psoc6_bless_send(struct net_buf *buf) return 0; } -static int psoc6_bless_setup(void) +static int psoc6_bless_setup(const struct bt_hci_setup_params *params) { + ARG_UNUSED(params); struct net_buf *buf; int err; uint8_t *addr = (uint8_t *)&SFLASH_BLE_DEVICE_ADDRESS[0]; diff --git a/drivers/bluetooth/hci/hci_spi_st.c b/drivers/bluetooth/hci/hci_spi_st.c new file mode 100644 index 00000000000..36263757684 --- /dev/null +++ b/drivers/bluetooth/hci/hci_spi_st.c @@ -0,0 +1,614 @@ +/* hci_spi_st.c - STMicroelectronics HCI SPI Bluetooth driver */ + +/* + * Copyright (c) 2017 Linaro Ltd. + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED) +#define DT_DRV_COMPAT st_hci_spi_v1 + +#elif defined(CONFIG_DT_HAS_ST_HCI_SPI_V2_ENABLED) +#define DT_DRV_COMPAT st_hci_spi_v2 + +#endif /* CONFIG_DT_HAS_ST_HCI_SPI_V1_ENABLED */ + +#include +#include +#include +#include +#include + +#include +#include + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_driver); + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 +/* ST Proprietary extended event */ +#define HCI_EXT_EVT 0x82 + +/* Special Values */ +#define SPI_WRITE 0x0A +#define SPI_READ 0x0B +#define READY_NOW 0x02 + +#define EVT_BLUE_INITIALIZED 0x01 + +/* Offsets */ +#define STATUS_HEADER_READY 0 +#define STATUS_HEADER_TOREAD 3 +#define STATUS_HEADER_TOWRITE 1 + +#define PACKET_TYPE 0 +#define EVT_HEADER_TYPE 0 +#define EVT_HEADER_EVENT 1 +#define EVT_HEADER_SIZE 2 +#define EVT_LE_META_SUBEVENT 3 +#define EVT_VENDOR_CODE_LSB 3 +#define EVT_VENDOR_CODE_MSB 4 + +#define CMD_OGF 1 +#define CMD_OCF 2 + +#define SPI_MAX_MSG_LEN 255 + +/* Single byte header denoting the buffer type */ +#define H4_HDR_SIZE 1 + +/* Maximum L2CAP MTU that can fit in a single packet */ +#define MAX_MTU (SPI_MAX_MSG_LEN - H4_HDR_SIZE - BT_L2CAP_HDR_SIZE - BT_HCI_ACL_HDR_SIZE) + +#if CONFIG_BT_L2CAP_TX_MTU > MAX_MTU +#warning CONFIG_BT_L2CAP_TX_MTU is too large and can result in packets that cannot \ + be transmitted across this HCI link +#endif /* CONFIG_BT_L2CAP_TX_MTU > MAX_MTU */ + +static uint8_t __noinit rxmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit txmsg[SPI_MAX_MSG_LEN]; + +static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios); +static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios); + +static struct gpio_callback gpio_cb; + +static K_SEM_DEFINE(sem_initialised, 0, 1); +static K_SEM_DEFINE(sem_request, 0, 1); +static K_SEM_DEFINE(sem_busy, 1, 1); + +static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); +static struct k_thread spi_rx_thread_data; + +#if defined(CONFIG_BT_BLUENRG_ACI) +#define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) +#define BLUENRG_CONFIG_PUBADDR_OFFSET 0x00 +#define BLUENRG_CONFIG_PUBADDR_LEN 0x06 +#define BLUENRG_CONFIG_LL_ONLY_OFFSET 0x2C +#define BLUENRG_CONFIG_LL_ONLY_LEN 0x01 + +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len); +#endif /* CONFIG_BT_BLUENRG_ACI */ + +static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( + 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0); + +static struct spi_buf spi_tx_buf; +static struct spi_buf spi_rx_buf; +static const struct spi_buf_set spi_tx = { + .buffers = &spi_tx_buf, + .count = 1 +}; +static const struct spi_buf_set spi_rx = { + .buffers = &spi_rx_buf, + .count = 1 +}; + +struct bt_hci_ext_evt_hdr { + uint8_t evt; + uint16_t len; +} __packed; + +static inline int bt_spi_transceive(void *tx, uint32_t tx_len, + void *rx, uint32_t rx_len) +{ + spi_tx_buf.buf = tx; + spi_tx_buf.len = (size_t)tx_len; + spi_rx_buf.buf = rx; + spi_rx_buf.len = (size_t)rx_len; + return spi_transceive_dt(&bus, &spi_tx, &spi_rx); +} + +static inline uint16_t bt_spi_get_cmd(uint8_t *msg) +{ + return (msg[CMD_OCF] << 8) | msg[CMD_OGF]; +} + +static inline uint16_t bt_spi_get_evt(uint8_t *msg) +{ + return (msg[EVT_VENDOR_CODE_MSB] << 8) | msg[EVT_VENDOR_CODE_LSB]; +} + +static void bt_spi_isr(const struct device *unused1, + struct gpio_callback *unused2, + uint32_t unused3) +{ + LOG_DBG(""); + + k_sem_give(&sem_request); +} + +static bool bt_spi_handle_vendor_evt(uint8_t *msg) +{ + bool handled = false; + + switch (bt_spi_get_evt(msg)) { + case EVT_BLUE_INITIALIZED: { + k_sem_give(&sem_initialised); +#if defined(CONFIG_BT_BLUENRG_ACI) + /* force BlueNRG to be on controller mode */ + uint8_t data = 1; + + bt_spi_send_aci_config(BLUENRG_CONFIG_LL_ONLY_OFFSET, &data, 1); +#endif + handled = true; + } + default: + break; + } + return handled; +} + +#define IS_IRQ_HIGH gpio_pin_get_dt(&irq_gpio) + +#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) + +/* Define a limit when reading IRQ high */ +#define IRQ_HIGH_MAX_READ 15 + +/* On BlueNRG-MS, host is expected to read */ +/* as long as IRQ pin is high */ +#define READ_CONDITION IS_IRQ_HIGH + +static void assert_cs(void) +{ + gpio_pin_set_dt(&bus.config.cs.gpio, 0); + gpio_pin_set_dt(&bus.config.cs.gpio, 1); +} + +static void release_cs(bool data_transaction) +{ + ARG_UNUSED(data_transaction); + gpio_pin_set_dt(&bus.config.cs.gpio, 0); +} + +static int bt_spi_get_header(uint8_t op, uint16_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint8_t size_offset, attempts; + int ret; + + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; + } + attempts = IRQ_HIGH_MAX_READ; + do { + if (op == SPI_READ) { + /* Keep checking that IRQ is still high, if we need to read */ + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + } + assert_cs(); + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + if (ret) { + /* SPI transaction failed */ + break; + } + + *size = (header_slave[STATUS_HEADER_READY] == READY_NOW) ? + header_slave[size_offset] : 0; + attempts--; + } while ((*size == 0) && attempts); + + return ret; +} + +#elif DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) + +#define READ_CONDITION false + +static void assert_cs(uint16_t delay) +{ + gpio_pin_set_dt(&bus.config.cs.gpio, 0); + if (delay) { + k_sleep(K_USEC(delay)); + } + gpio_pin_set_dt(&bus.config.cs.gpio, 1); + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_DISABLE); +} + +static void release_cs(bool data_transaction) +{ + /* Consume possible event signals */ + while (k_sem_take(&sem_request, K_NO_WAIT) == 0) { + } + if (data_transaction) { + /* Wait for IRQ to become low only when data phase has been performed */ + while (IS_IRQ_HIGH) { + } + } + gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + gpio_pin_set_dt(&bus.config.cs.gpio, 0); +} + +static int bt_spi_get_header(uint8_t op, uint16_t *size) +{ + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + uint16_t cs_delay; + uint8_t size_offset; + int ret; + + if (op == SPI_READ) { + if (!IS_IRQ_HIGH) { + *size = 0; + return 0; + } + cs_delay = 0; + size_offset = STATUS_HEADER_TOREAD; + } else if (op == SPI_WRITE) { + /* To make sure we have a minimum delay from previous release cs */ + cs_delay = 100; + size_offset = STATUS_HEADER_TOWRITE; + } else { + return -EINVAL; + } + + assert_cs(cs_delay); + /* Wait up to a maximum time of 100 ms */ + if (!WAIT_FOR(IS_IRQ_HIGH, 100000, k_usleep(100))) { + LOG_ERR("IRQ pin did not raise"); + return -EIO; + } + + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + *size = header_slave[size_offset] | (header_slave[size_offset + 1] << 8); + return ret; +} +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) */ + +#if defined(CONFIG_BT_BLUENRG_ACI) +static int bt_spi_send_aci_config(uint8_t offset, const uint8_t *value, size_t value_len) +{ + struct net_buf *buf; + uint8_t *cmd_data; + size_t data_len = 2 + value_len; + + buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, data_len); + if (!buf) { + return -ENOBUFS; + } + + cmd_data = net_buf_add(buf, data_len); + cmd_data[0] = offset; + cmd_data[1] = value_len; + memcpy(&cmd_data[2], value, value_len); + + return bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); +} + +static int bt_spi_bluenrg_setup(const struct bt_hci_setup_params *params) +{ + int ret; + const bt_addr_t *addr = ¶ms->public_addr; + + if (!bt_addr_eq(addr, BT_ADDR_NONE) && !bt_addr_eq(addr, BT_ADDR_ANY)) { + ret = bt_spi_send_aci_config( + BLUENRG_CONFIG_PUBADDR_OFFSET, + addr->val, sizeof(addr->val)); + + if (ret != 0) { + LOG_ERR("Failed to set BlueNRG public address (%d)", ret); + return ret; + } + } + + return 0; +} +#endif /* CONFIG_BT_BLUENRG_ACI */ + +static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) +{ + bool discardable = false; + k_timeout_t timeout = K_FOREVER; + struct bt_hci_acl_hdr acl_hdr; + struct net_buf *buf; + int len; + + switch (msg[PACKET_TYPE]) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) + case HCI_EXT_EVT: + struct bt_hci_ext_evt_hdr *evt = (struct bt_hci_ext_evt_hdr *) (msg + 1); + struct bt_hci_evt_hdr *evt2 = (struct bt_hci_evt_hdr *) (msg + 1); + + if (evt->len > 0xff) { + return NULL; + } + /* Use memmove instead of memcpy due to buffer overlapping */ + memmove(msg + (1 + sizeof(*evt2)), msg + (1 + sizeof(*evt)), evt2->len); + /* Manage event as regular HCI_EVT */ + __fallthrough; +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ + case HCI_EVT: + switch (msg[EVT_HEADER_EVENT]) { + case BT_HCI_EVT_VENDOR: + /* Run event through interface handler */ + if (bt_spi_handle_vendor_evt(msg)) { + return NULL; + } + /* Event has not yet been handled */ + __fallthrough; + default: + if (msg[EVT_HEADER_EVENT] == BT_HCI_EVT_LE_META_EVENT && + (msg[EVT_LE_META_SUBEVENT] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { + discardable = true; + timeout = K_NO_WAIT; + } + buf = bt_buf_get_evt(msg[EVT_HEADER_EVENT], + discardable, timeout); + if (!buf) { + LOG_DBG("Discard adv report due to insufficient buf"); + return NULL; + } + } + + len = sizeof(struct bt_hci_evt_hdr) + msg[EVT_HEADER_SIZE]; + if (len > net_buf_tailroom(buf)) { + LOG_ERR("Event too long: %d", len); + net_buf_unref(buf); + return NULL; + } + net_buf_add_mem(buf, &msg[1], len); + break; + case HCI_ACL: + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); + memcpy(&acl_hdr, &msg[1], sizeof(acl_hdr)); + len = sizeof(acl_hdr) + sys_le16_to_cpu(acl_hdr.len); + if (len > net_buf_tailroom(buf)) { + LOG_ERR("ACL too long: %d", len); + net_buf_unref(buf); + return NULL; + } + net_buf_add_mem(buf, &msg[1], len); + break; + default: + LOG_ERR("Unknown BT buf type %d", msg[0]); + return NULL; + } + + return buf; +} + +static void bt_spi_rx_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p1); + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + struct net_buf *buf; + uint16_t size = 0U; + int ret; + + (void)memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); + while (true) { + + /* Wait for interrupt pin to be active */ + k_sem_take(&sem_request, K_FOREVER); + + LOG_DBG(""); + + do { + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + ret = bt_spi_get_header(SPI_READ, &size); + + /* Read data */ + if (ret == 0 && size != 0) { + ret = bt_spi_transceive(&txmsg, size, &rxmsg, size); + } + + release_cs(size > 0); + + k_sem_give(&sem_busy); + + if (ret || size == 0) { + if (ret) { + LOG_ERR("Error %d", ret); + } + continue; + } + + LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); + + /* Construct net_buf from SPI data */ + buf = bt_spi_rx_buf_construct(rxmsg); + if (buf) { + /* Handle the received HCI data */ + bt_recv(buf); + } + } while (READ_CONDITION); + } +} + +static int bt_spi_send(struct net_buf *buf) +{ + uint16_t size; + uint8_t rx_first[1]; + int ret; + + LOG_DBG(""); + + /* Buffer needs an additional byte for type */ + if (buf->len >= SPI_MAX_MSG_LEN) { + LOG_ERR("Message too long (%d)", buf->len); + return -EINVAL; + } + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + net_buf_push_u8(buf, HCI_ACL); + break; + case BT_BUF_CMD: + net_buf_push_u8(buf, HCI_CMD); + break; + default: + LOG_ERR("Unsupported type"); + return -EINVAL; + } + + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + + ret = bt_spi_get_header(SPI_WRITE, &size); + size = MIN(buf->len, size); + + if (size < buf->len) { + LOG_WRN("Unable to write full data, skipping"); + size = 0; + ret = -ECANCELED; + } + + if (!ret) { + /* Transmit the message */ + ret = bt_spi_transceive(buf->data, size, + rx_first, 1); + } + + release_cs(size > 0); + + k_sem_give(&sem_busy); + + if (ret) { + LOG_ERR("Error %d", ret); + return ret; + } + + LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); + +#if (DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2)) + /* + * Since a RESET has been requested, the chip will now restart. + * Unfortunately the BlueNRG will reply with "reset received" but + * since it does not send back a NOP, we have no way to tell when the + * RESET has actually taken place. Instead, we use the vendor command + * EVT_BLUE_INITIALIZED as an indication that it is safe to proceed. + */ + if (bt_spi_get_cmd(buf->data) == BT_HCI_OP_RESET) { + k_sem_take(&sem_initialised, K_FOREVER); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v1) || DT_HAS_COMPAT_STATUS_OKAY(st_hci_spi_v2) */ + net_buf_unref(buf); + + return ret; +} + +static int bt_spi_open(void) +{ + int err; + + /* Configure RST pin and hold BLE in Reset */ + err = gpio_pin_configure_dt(&rst_gpio, GPIO_OUTPUT_ACTIVE); + if (err) { + return err; + } + + /* Configure IRQ pin and the IRQ call-back/handler */ + err = gpio_pin_configure_dt(&irq_gpio, GPIO_INPUT); + if (err) { + return err; + } + + gpio_init_callback(&gpio_cb, bt_spi_isr, BIT(irq_gpio.pin)); + err = gpio_add_callback(irq_gpio.port, &gpio_cb); + if (err) { + return err; + } + + /* Enable the interrupt line */ + err = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + return err; + } + + /* Take BLE out of reset */ + k_sleep(K_MSEC(DT_INST_PROP_OR(0, reset_assert_duration_ms, 0))); + gpio_pin_set_dt(&rst_gpio, 0); + + /* Start RX thread */ + k_thread_create(&spi_rx_thread_data, spi_rx_stack, + K_KERNEL_STACK_SIZEOF(spi_rx_stack), + bt_spi_rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), + 0, K_NO_WAIT); + + /* Device will let us know when it's ready */ + k_sem_take(&sem_initialised, K_FOREVER); + + return 0; +} + +static const struct bt_hci_driver drv = { + .name = DEVICE_DT_NAME(DT_DRV_INST(0)), + .bus = BT_HCI_DRIVER_BUS_SPI, +#if defined(CONFIG_BT_BLUENRG_ACI) + .quirks = BT_QUIRK_NO_RESET, + .setup = bt_spi_bluenrg_setup, +#endif /* CONFIG_BT_BLUENRG_ACI */ + .open = bt_spi_open, + .send = bt_spi_send, +}; + +static int bt_spi_init(void) +{ + + if (!spi_is_ready_dt(&bus)) { + LOG_ERR("SPI device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&irq_gpio)) { + LOG_ERR("IRQ GPIO device not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&rst_gpio)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + bt_hci_driver_register(&drv); + + + LOG_DBG("BT SPI initialized"); + + return 0; +} + +SYS_INIT(bt_spi_init, POST_KERNEL, CONFIG_BT_SPI_INIT_PRIORITY); diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c new file mode 100644 index 00000000000..fd718d5efb6 --- /dev/null +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -0,0 +1,383 @@ +/* hci_stm32wba.c - HCI driver for stm32wba */ + +/* + * Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "blestack.h" +#include "app_conf.h" +#include "ll_sys.h" +#include "flash_driver.h" + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(hci_wba); + +static K_SEM_DEFINE(hci_sem, 1, 1); + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 +#define HCI_ISO 0x05 + +#define BLE_CTRLR_STACK_BUFFER_SIZE 300 + +#define MBLOCK_COUNT (BLE_MBLOCKS_CALC(PREP_WRITE_LIST_SIZE, \ + CFG_BLE_ATT_MTU_MAX, \ + CFG_BLE_NUM_LINK) \ + + CFG_BLE_MBLOCK_COUNT_MARGIN) + +#define BLE_DYN_ALLOC_SIZE \ + (BLE_TOTAL_BUFFER_SIZE(CFG_BLE_NUM_LINK, MBLOCK_COUNT)) + +#define DIVC(x, y) (((x)+(y)-1)/(y)) + +static uint32_t __noinit buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)]; + +extern uint8_t ll_state_busy; + +static bool is_hci_event_discardable(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { +#if defined(CONFIG_BT_BREDR) + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: + return true; +#endif + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return true; + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *treat_evt(const uint8_t *data, size_t len) +{ + bool discardable; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for event header"); + return NULL; + } + + discardable = is_hci_event_discardable(data); + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + if (len != hdr.len) { + LOG_ERR("Event payload length is not correct.\n"); + LOG_ERR("len: %d, hdr.len: %d\n", len, hdr.len); + return NULL; + } + LOG_DBG("len %u", hdr.len); + + buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(3)); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + } else { + LOG_ERR("No available event buffers!"); + + } + __ASSERT_NO_MSG(buf); + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static struct net_buf *treat_acl(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (ext_len != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %u", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static struct net_buf *treat_iso(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ISO header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ISO buffers!"); + return NULL; + } + + if (ext_len != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { + LOG_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %zu", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static int receive_data(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + uint8_t pkt_indicator; + struct net_buf *buf; + int err = 0; + + LOG_HEXDUMP_DBG(data, len, "host packet data:"); + LOG_HEXDUMP_DBG(ext_data, ext_len, "host packet ext_data:"); + + pkt_indicator = *data++; + len -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case HCI_EVT: + buf = treat_evt(data, len); + break; + case HCI_ACL: + buf = treat_acl(data, len + 1, ext_data, ext_len); + break; + case HCI_ISO: + case HCI_SCO: + buf = treat_iso(data, len + 1, ext_data, ext_len); + break; + default: + buf = NULL; + LOG_ERR("Unknown HCI type %u", pkt_indicator); + } + + if (buf) { + bt_recv(buf); + } else { + err = -ENOMEM; + ll_state_busy = 1; + } + + return err; +} + +uint8_t BLECB_Indication(const uint8_t *data, uint16_t length, + const uint8_t *ext_data, uint16_t ext_length) +{ + int ret = 0; + int err; + + LOG_DBG("length: %d", length); + if (ext_length != 0) { + LOG_DBG("ext_length: %d", ext_length); + } + + k_sem_take(&hci_sem, K_FOREVER); + + err = receive_data(data, (size_t)length - 1, + ext_data, (size_t)ext_length); + + k_sem_give(&hci_sem); + + HostStack_Process(); + + if (err) { + ret = 1; + } + + return ret; +} + +static int bt_hci_stm32wba_send(struct net_buf *buf) +{ + uint16_t event_length; + uint8_t pkt_indicator; + uint8_t tx_buffer[BLE_CTRLR_STACK_BUFFER_SIZE]; + + k_sem_take(&hci_sem, K_FOREVER); + + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + pkt_indicator = HCI_ACL; + break; + case BT_BUF_CMD: + pkt_indicator = HCI_CMD; + break; + case BT_BUF_ISO_OUT: + pkt_indicator = HCI_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + k_sem_give(&hci_sem); + return -EIO; + } + net_buf_push_u8(buf, pkt_indicator); + + memcpy(&tx_buffer, buf->data, buf->len); + + event_length = BleStack_Request(tx_buffer); + LOG_DBG("event_length: %u", event_length); + + if (event_length) { + receive_data((uint8_t *)&tx_buffer, (size_t)event_length, NULL, 0); + } + + k_sem_give(&hci_sem); + + net_buf_unref(buf); + + return 0; +} + +static int bt_ble_ctlr_init(void) +{ + BleStack_init_t init_params_p = {0}; + + init_params_p.numAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES; + init_params_p.numAttrServ = CFG_BLE_NUM_GATT_SERVICES; + init_params_p.attrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE; + init_params_p.prWriteListSize = CFG_BLE_ATTR_PREPARE_WRITE_VALUE_SIZE; + init_params_p.attMtu = CFG_BLE_ATT_MTU_MAX; + init_params_p.max_coc_nbr = CFG_BLE_COC_NBR_MAX; + init_params_p.max_coc_mps = CFG_BLE_COC_MPS_MAX; + init_params_p.max_coc_initiator_nbr = CFG_BLE_COC_INITIATOR_NBR_MAX; + init_params_p.numOfLinks = CFG_BLE_NUM_LINK; + init_params_p.mblockCount = CFG_BLE_MBLOCK_COUNT; + init_params_p.bleStartRamAddress = (uint8_t *)buffer; + init_params_p.total_buffer_size = BLE_DYN_ALLOC_SIZE; + init_params_p.bleStartRamAddress_GATT = NULL; + init_params_p.total_buffer_size_GATT = 0; + init_params_p.options = CFG_BLE_OPTIONS; + init_params_p.debug = 0U; + + if (BleStack_Init(&init_params_p) != BLE_STATUS_SUCCESS) { + return -EIO; + } + + return 0; +} + +static int bt_hci_stm32wba_open(void) +{ + int ret = 0; + + link_layer_register_isr(); + + ll_sys_config_params(); + + ret = bt_ble_ctlr_init(); + + /* TODO. Enable Flash manager once available */ + if (IS_ENABLED(CONFIG_FLASH)) { + FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_DISABLE); + } + + return ret; +} + +static const struct bt_hci_driver drv = { + .name = "BT IPM", + .bus = BT_HCI_DRIVER_BUS_IPM, + .open = bt_hci_stm32wba_open, + .send = bt_hci_stm32wba_send, +}; + +static int bt_stm32wba_hci_init(void) +{ + bt_hci_driver_register(&drv); + + return 0; +} + +SYS_INIT(bt_stm32wba_hci_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/bluetooth/hci/ipm_stm32wb.c b/drivers/bluetooth/hci/ipm_stm32wb.c index 59fef02b2c1..85fc875f139 100644 --- a/drivers/bluetooth/hci/ipm_stm32wb.c +++ b/drivers/bluetooth/hci/ipm_stm32wb.c @@ -99,8 +99,8 @@ static void stm32wb_start_ble(uint32_t rf_clock) CFG_BLE_PREPARE_WRITE_LIST_SIZE, CFG_BLE_MBLOCK_COUNT, CFG_BLE_MAX_ATT_MTU, - CFG_BLE_SLAVE_SCA, - CFG_BLE_MASTER_SCA, + CFG_BLE_PERIPHERAL_SCA, + CFG_BLE_CENTRAL_SCA, (rf_clock == STM32_SRC_LSE) ? CFG_BLE_LS_SOURCE : 0, CFG_BLE_MAX_CONN_EVENT_LENGTH, CFG_BLE_HSE_STARTUP_TIME, diff --git a/drivers/bluetooth/hci/spi.c b/drivers/bluetooth/hci/spi.c index 32b50ea191f..8177e059261 100644 --- a/drivers/bluetooth/hci/spi.c +++ b/drivers/bluetooth/hci/spi.c @@ -36,6 +36,7 @@ LOG_MODULE_REGISTER(bt_driver); /* Offsets */ #define STATUS_HEADER_READY 0 #define STATUS_HEADER_TOREAD 3 +#define STATUS_HEADER_TOWRITE 1 #define PACKET_TYPE 0 #define EVT_HEADER_TYPE 0 @@ -70,8 +71,8 @@ LOG_MODULE_REGISTER(bt_driver); be transmitted across this HCI link #endif /* CONFIG_BT_L2CAP_TX_MTU > MAX_MTU */ -static uint8_t rxmsg[SPI_MAX_MSG_LEN]; -static uint8_t txmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit rxmsg[SPI_MAX_MSG_LEN]; +static uint8_t __noinit txmsg[SPI_MAX_MSG_LEN]; static const struct gpio_dt_spec irq_gpio = GPIO_DT_SPEC_INST_GET(0, irq_gpios); static const struct gpio_dt_spec rst_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios); @@ -85,27 +86,6 @@ static K_SEM_DEFINE(sem_busy, 1, 1); static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE); static struct k_thread spi_rx_thread_data; -#if defined(CONFIG_BT_SPI_BLUENRG) -/* Define a limit when reading IRQ high */ -/* It can be required to be increased for */ -/* some particular cases. */ -#define IRQ_HIGH_MAX_READ 3 -static uint8_t attempts; -#endif /* CONFIG_BT_SPI_BLUENRG */ - -#if defined(CONFIG_BT_BLUENRG_ACI) -#define BLUENRG_ACI_WRITE_CONFIG_DATA BT_OP(BT_OGF_VS, 0x000C) -#define BLUENRG_ACI_WRITE_CONFIG_CMD_LL 0x2C -#define BLUENRG_ACI_LL_MODE 0x01 - -struct bluenrg_aci_cmd_ll_param { - uint8_t cmd; - uint8_t length; - uint8_t value; -}; -static int bt_spi_send_aci_config_data_controller_mode(void); -#endif /* CONFIG_BT_BLUENRG_ACI */ - static const struct spi_dt_spec bus = SPI_DT_SPEC_INST_GET( 0, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0); @@ -154,97 +134,52 @@ static bool bt_spi_handle_vendor_evt(uint8_t *msg) bool handled = false; switch (bt_spi_get_evt(msg)) { - case EVT_BLUE_INITIALIZED: + case EVT_BLUE_INITIALIZED: { k_sem_give(&sem_initialised); -#if defined(CONFIG_BT_BLUENRG_ACI) - /* force BlueNRG to be on controller mode */ - bt_spi_send_aci_config_data_controller_mode(); -#endif handled = true; + } default: break; } return handled; } -#if defined(CONFIG_BT_SPI_BLUENRG) -/* BlueNRG has a particuliar way to wake up from sleep and be ready. - * All is done through its CS line: - * If it is in sleep mode, the first transaction will not return ready - * status. At this point, it's necessary to release the CS and retry - * within 2ms the same transaction. And again when it's required to - * know the amount of byte to read. - * (See section 5.2 of BlueNRG-MS datasheet) - */ -static void kick_cs(void) -{ - gpio_pin_set_dt(&bus.config.cs.gpio, 0); - gpio_pin_set_dt(&bus.config.cs.gpio, 1); -} - -static void release_cs(void) +static int bt_spi_get_header(uint8_t op, uint16_t *size) { - gpio_pin_set_dt(&bus.config.cs.gpio, 0); -} - -static bool irq_pin_high(void) -{ - int pin_state; - - pin_state = gpio_pin_get_dt(&irq_gpio); - - LOG_DBG("IRQ Pin: %d", pin_state); - - return pin_state > 0; -} - -static void init_irq_high_loop(void) -{ - attempts = IRQ_HIGH_MAX_READ; -} - -static bool exit_irq_high_loop(void) -{ - /* Limit attempts on BlueNRG-MS as we might */ - /* enter this loop with nothing to read */ - - attempts--; - - return attempts; -} - -#else - -#define kick_cs(...) -#define release_cs(...) -#define irq_pin_high(...) 0 -#define init_irq_high_loop(...) -#define exit_irq_high_loop(...) 1 - -#endif /* CONFIG_BT_SPI_BLUENRG */ - -#if defined(CONFIG_BT_BLUENRG_ACI) -static int bt_spi_send_aci_config_data_controller_mode(void) -{ - struct bluenrg_aci_cmd_ll_param *param; - struct net_buf *buf; + uint8_t header_master[5] = {op, 0, 0, 0, 0}; + uint8_t header_slave[5]; + bool reading = (op == SPI_READ); + bool loop_cond; + uint8_t size_offset; + int ret; - buf = bt_hci_cmd_create(BLUENRG_ACI_WRITE_CONFIG_DATA, sizeof(*param)); - if (!buf) { - return -ENOBUFS; + if (!(op == SPI_READ || op == SPI_WRITE)) { + return -EINVAL; + } + if (reading) { + size_offset = STATUS_HEADER_TOREAD; } - param = net_buf_add(buf, sizeof(*param)); - param->cmd = BLUENRG_ACI_WRITE_CONFIG_CMD_LL; - param->length = 0x1; - /* Force BlueNRG-MS roles to Link Layer only mode */ - param->value = BLUENRG_ACI_LL_MODE; + do { + ret = bt_spi_transceive(header_master, 5, header_slave, 5); + if (ret) { + break; + } + if (reading) { + /* When reading, keep looping if read buffer is not valid */ + loop_cond = ((header_slave[STATUS_HEADER_TOREAD] == 0U) || + (header_slave[STATUS_HEADER_TOREAD] == 0xFF)); + } else { + /* When writing, keep looping if all bytes are zero */ + loop_cond = ((header_slave[1] | header_slave[2] | header_slave[3] | + header_slave[4]) == 0U); + } + } while ((header_slave[STATUS_HEADER_READY] != READY_NOW) || loop_cond); - bt_hci_cmd_send(BLUENRG_ACI_WRITE_CONFIG_DATA, buf); + *size = (reading ? header_slave[size_offset] : SPI_MAX_MSG_LEN); - return 0; + return ret; } -#endif /* CONFIG_BT_BLUENRG_ACI */ static struct net_buf *bt_spi_rx_buf_construct(uint8_t *msg) { @@ -311,10 +246,8 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) ARG_UNUSED(p2); ARG_UNUSED(p3); - uint8_t header_master[5] = { SPI_READ, 0x00, 0x00, 0x00, 0x00 }; - uint8_t header_slave[5]; struct net_buf *buf; - uint8_t size = 0U; + uint16_t size = 0U; int ret; (void)memset(&txmsg, 0xFF, SPI_MAX_MSG_LEN); @@ -325,65 +258,50 @@ static void bt_spi_rx_thread(void *p1, void *p2, void *p3) LOG_DBG(""); - do { - /* Wait for SPI bus to be available */ - k_sem_take(&sem_busy, K_FOREVER); - init_irq_high_loop(); - do { - kick_cs(); - ret = bt_spi_transceive(header_master, 5, - header_slave, 5); - } while ((((header_slave[STATUS_HEADER_TOREAD] == 0U || - header_slave[STATUS_HEADER_TOREAD] == 0xFF) && - !ret)) && exit_irq_high_loop()); - - /* Delay here is rounded up to next tick */ - k_sleep(K_USEC(DATA_DELAY_US)); - size = header_slave[STATUS_HEADER_TOREAD]; - if (ret == 0 && size != 0) { - do { - ret = bt_spi_transceive(&txmsg, size, - &rxmsg, size); - if (rxmsg[0] == 0U) { - /* Consider increasing controller-data-delay-us - * if this message is extremely common. - */ - LOG_DBG("Controller not ready for SPI transaction " - "of %d bytes", size); - } - } while (rxmsg[0] == 0U && ret == 0); - } - - release_cs(); + /* Wait for SPI bus to be available */ + k_sem_take(&sem_busy, K_FOREVER); + ret = bt_spi_get_header(SPI_READ, &size); - k_sem_give(&sem_busy); - - if (ret || size == 0) { - if (ret) { - LOG_ERR("Error %d", ret); + /* Delay here is rounded up to next tick */ + k_sleep(K_USEC(DATA_DELAY_US)); + /* Read data */ + if (ret == 0 && size != 0) { + do { + ret = bt_spi_transceive(&txmsg, size, + &rxmsg, size); + if (rxmsg[0] == 0U) { + /* Consider increasing controller-data-delay-us + * if this message is extremely common. + */ + LOG_DBG("Controller not ready for SPI transaction " + "of %d bytes", size); } - continue; - } + } while (rxmsg[0] == 0U && ret == 0); + } - LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); + k_sem_give(&sem_busy); - /* Construct net_buf from SPI data */ - buf = bt_spi_rx_buf_construct(rxmsg); - if (buf) { - /* Handle the received HCI data */ - bt_recv(buf); + if (ret || size == 0) { + if (ret) { + LOG_ERR("Error %d", ret); } + continue; + } + + LOG_HEXDUMP_DBG(rxmsg, size, "SPI RX"); - /* On BlueNRG-MS, host is expected to read */ - /* as long as IRQ pin is high */ - } while (irq_pin_high()); + /* Construct net_buf from SPI data */ + buf = bt_spi_rx_buf_construct(rxmsg); + if (buf) { + /* Handle the received HCI data */ + bt_recv(buf); + } } } static int bt_spi_send(struct net_buf *buf) { - uint8_t header_tx[5] = { SPI_WRITE, 0x00, 0x00, 0x00, 0x00 }; - uint8_t header_rx[5]; + uint16_t size; uint8_t rx_first[1]; int ret; @@ -411,25 +329,21 @@ static int bt_spi_send(struct net_buf *buf) return -EINVAL; } - /* Poll sanity values until device has woken-up */ - do { - kick_cs(); - ret = bt_spi_transceive(header_tx, 5, header_rx, 5); + ret = bt_spi_get_header(SPI_WRITE, &size); + size = MIN(buf->len, size); - /* - * RX Header must contain a sanity check Byte and size - * information. If it does not contain BOTH then it is - * sleeping or still in the initialisation stage (waking-up). - */ - } while ((header_rx[STATUS_HEADER_READY] != READY_NOW || - (header_rx[1] | header_rx[2] | header_rx[3] | header_rx[4]) == 0U) && !ret); + if (size < buf->len) { + LOG_WRN("Unable to write full data, skipping"); + size = 0; + ret = -ECANCELED; + } if (!ret) { /* Delay here is rounded up to next tick */ k_sleep(K_USEC(DATA_DELAY_US)); /* Transmit the message */ while (true) { - ret = bt_spi_transceive(buf->data, buf->len, + ret = bt_spi_transceive(buf->data, size, rx_first, 1); if (rx_first[0] != 0U || ret) { break; @@ -437,12 +351,10 @@ static int bt_spi_send(struct net_buf *buf) /* Consider increasing controller-data-delay-us * if this message is extremely common. */ - LOG_DBG("Controller not ready for SPI transaction of %d bytes", buf->len); + LOG_DBG("Controller not ready for SPI transaction of %d bytes", size); } } - release_cs(); - k_sem_give(&sem_busy); if (ret) { @@ -452,18 +364,6 @@ static int bt_spi_send(struct net_buf *buf) LOG_HEXDUMP_DBG(buf->data, buf->len, "SPI TX"); -#if defined(CONFIG_BT_SPI_BLUENRG) - /* - * Since a RESET has been requested, the chip will now restart. - * Unfortunately the BlueNRG will reply with "reset received" but - * since it does not send back a NOP, we have no way to tell when the - * RESET has actually taken place. Instead, we use the vendor command - * EVT_BLUE_INITIALIZED as an indication that it is safe to proceed. - */ - if (bt_spi_get_cmd(buf->data) == BT_HCI_OP_RESET) { - k_sem_take(&sem_initialised, K_FOREVER); - } -#endif /* CONFIG_BT_SPI_BLUENRG */ out: net_buf_unref(buf); @@ -493,7 +393,10 @@ static int bt_spi_open(void) } /* Enable the interrupt line */ - gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + err = gpio_pin_interrupt_configure_dt(&irq_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (err) { + return err; + } /* Take BLE out of reset */ k_sleep(K_MSEC(DT_INST_PROP_OR(0, reset_assert_duration_ms, 0))); @@ -515,9 +418,6 @@ static int bt_spi_open(void) static const struct bt_hci_driver drv = { .name = DEVICE_DT_NAME(DT_DRV_INST(0)), .bus = BT_HCI_DRIVER_BUS_SPI, -#if defined(CONFIG_BT_BLUENRG_ACI) - .quirks = BT_QUIRK_NO_RESET, -#endif /* CONFIG_BT_BLUENRG_ACI */ .open = bt_spi_open, .send = bt_spi_send, }; diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt index 47c790f0a89..23cb11afb6a 100644 --- a/drivers/cache/CMakeLists.txt +++ b/drivers/cache/CMakeLists.txt @@ -7,3 +7,4 @@ zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_CACHE_ASPEED cache_aspeed.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE cache_handlers.c) +zephyr_library_sources_ifdef(CONFIG_CACHE_NRF_CACHE cache_nrf.c) diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 834cc49e181..4dcb64f488a 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -19,5 +19,6 @@ source "subsys/logging/Kconfig.template.log_config" comment "Device Drivers" source "drivers/cache/Kconfig.aspeed" +source "drivers/cache/Kconfig.nrf" endif # CACHE diff --git a/drivers/cache/Kconfig.nrf b/drivers/cache/Kconfig.nrf new file mode 100644 index 00000000000..820445db432 --- /dev/null +++ b/drivers/cache/Kconfig.nrf @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config CACHE_NRF_CACHE + bool "nRF cache driver" + select CACHE_HAS_DRIVER + depends on HAS_NRFX && CACHE_MANAGEMENT + help + Enable support for the nRF cache driver. diff --git a/drivers/cache/cache_nrf.c b/drivers/cache/cache_nrf.c new file mode 100644 index 00000000000..63d76a47d6e --- /dev/null +++ b/drivers/cache/cache_nrf.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include + +LOG_MODULE_REGISTER(cache_nrfx, CONFIG_CACHE_LOG_LEVEL); + +#if !defined(NRF_ICACHE) && defined(NRF_CACHE) +#define NRF_ICACHE NRF_CACHE +#endif + +#define CACHE_LINE_SIZE 32 +#define CACHE_BUSY_RETRY_INTERVAL_US 10 + +static struct k_spinlock lock; + +enum k_nrf_cache_op { + /* + * Sequentially loop through all dirty lines and write those data units to + * memory. + * + * This is FLUSH in Zephyr nomenclature. + */ + K_NRF_CACHE_CLEAN, + + /* + * Mark all lines as invalid, ignoring any dirty data. + * + * This is INVALIDATE in Zephyr nomenclature. + */ + K_NRF_CACHE_INVD, + + /* + * Clean followed by invalidate + * + * This is FLUSH_AND_INVALIDATE in Zephyr nomenclature. + */ + K_NRF_CACHE_FLUSH, +}; + +static inline bool is_cache_busy(NRF_CACHE_Type *cache) +{ +#if NRF_CACHE_HAS_STATUS + return nrf_cache_busy_check(cache); +#else + return false; +#endif +} + +static inline void wait_for_cache(NRF_CACHE_Type *cache) +{ + while (is_cache_busy(cache)) { + k_busy_wait(CACHE_BUSY_RETRY_INTERVAL_US); + } +} + +static inline int _cache_all(NRF_CACHE_Type *cache, enum k_nrf_cache_op op) +{ + /* + * We really do not want to invalidate the whole cache. + */ + if (op == K_NRF_CACHE_INVD) { + return -ENOTSUP; + } + + k_spinlock_key_t key = k_spin_lock(&lock); + + /* + * Invalidating the whole cache is dangerous. For good measure + * disable the cache. + */ + nrf_cache_disable(cache); + + wait_for_cache(cache); + + switch (op) { + +#if NRF_CACHE_HAS_TASK_CLEAN + case K_NRF_CACHE_CLEAN: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_CLEANCACHE); + break; +#endif + + case K_NRF_CACHE_INVD: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_INVALIDATECACHE); + break; + +#if NRF_CACHE_HAS_TASK_FLUSH + case K_NRF_CACHE_FLUSH: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_FLUSHCACHE); + break; +#endif + + default: + break; + } + + wait_for_cache(cache); + + nrf_cache_enable(cache); + + k_spin_unlock(&lock, key); + + return 0; +} + +static inline void _cache_line(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, uintptr_t line_addr) +{ + wait_for_cache(cache); + + nrf_cache_lineaddr_set(cache, line_addr); + + switch (op) { + +#if NRF_CACHE_HAS_TASK_CLEAN + case K_NRF_CACHE_CLEAN: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_CLEANLINE); + break; +#endif + + case K_NRF_CACHE_INVD: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_INVALIDATELINE); + break; + +#if NRF_CACHE_HAS_TASK_FLUSH + case K_NRF_CACHE_FLUSH: + nrf_cache_task_trigger(cache, NRF_CACHE_TASK_FLUSHLINE); + break; +#endif + + default: + break; + } + + wait_for_cache(cache); +} + +static inline int _cache_range(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, void *addr, + size_t size) +{ + uintptr_t line_addr = (uintptr_t)addr; + uintptr_t end_addr = line_addr + size; + + /* + * Align address to line size + */ + line_addr &= ~(CACHE_LINE_SIZE - 1); + + do { + k_spinlock_key_t key = k_spin_lock(&lock); + + _cache_line(cache, op, line_addr); + + k_spin_unlock(&lock, key); + + line_addr += CACHE_LINE_SIZE; + + } while (line_addr < end_addr); + + return 0; +} + +static inline int _cache_checks(NRF_CACHE_Type *cache, enum k_nrf_cache_op op, void *addr, + size_t size, bool is_range) +{ + /* Check if the cache is enabled */ + if (!(cache->ENABLE & CACHE_ENABLE_ENABLE_Enabled)) { + return -EAGAIN; + } + + if (!is_range) { + return _cache_all(cache, op); + } + + /* Check for invalid address or size */ + if ((!addr) || (!size)) { + return -EINVAL; + } + + return _cache_range(cache, op, addr, size); +} + +#if defined(NRF_DCACHE) && NRF_CACHE_HAS_TASKS + +void cache_data_enable(void) +{ + nrf_cache_enable(NRF_DCACHE); +} + +void cache_data_disable(void) +{ + nrf_cache_disable(NRF_DCACHE); +} + +int cache_data_flush_all(void) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_CLEAN, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_data_invd_all(void) +{ + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_INVD, NULL, 0, false); +} + +int cache_data_flush_and_invd_all(void) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_FLUSH, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_data_flush_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_CLEAN, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +int cache_data_invd_range(void *addr, size_t size) +{ + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_INVD, addr, size, true); +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_DCACHE, K_NRF_CACHE_FLUSH, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +#else + +void cache_data_enable(void) +{ + /* Nothing */ +} + +void cache_data_disable(void) +{ + /* Nothing */ +} + +int cache_data_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_data_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_data_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_data_flush_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_data_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_data_flush_and_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +#endif /* NRF_DCACHE */ + +#if defined(NRF_ICACHE) && NRF_CACHE_HAS_TASKS + +void cache_instr_enable(void) +{ + nrf_cache_enable(NRF_ICACHE); +} + +void cache_instr_disable(void) +{ + nrf_cache_disable(NRF_ICACHE); +} + +int cache_instr_flush_all(void) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_CLEAN, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_invd_all(void) +{ + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_INVD, NULL, 0, false); +} + +int cache_instr_flush_and_invd_all(void) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_FLUSH, NULL, 0, false); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_flush_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_CLEAN + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_CLEAN, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_INVD, addr, size, true); +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ +#if NRF_CACHE_HAS_TASK_FLUSH + return _cache_checks(NRF_ICACHE, K_NRF_CACHE_FLUSH, addr, size, true); +#else + return -ENOTSUP; +#endif +} + +#else + +void cache_instr_enable(void) +{ + /* Nothing */ +} + +void cache_instr_disable(void) +{ + /* Nothing */ +} + +int cache_instr_flush_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_all(void) +{ + return -ENOTSUP; +} + +int cache_instr_flush_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_instr_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +int cache_instr_flush_and_invd_range(void *addr, size_t size) +{ + return -ENOTSUP; +} + +#endif /* NRF_ICACHE */ diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index c7d9de93f2e..f53cf7d2c1e 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -20,22 +20,7 @@ zephyr_library_sources_ifdef(CONFIG_CAN_STM32H7_FDCAN can_stm32h7_fdcan.c) zephyr_library_sources_ifdef(CONFIG_CAN_TCAN4X5X can_tcan4x5x.c) zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c) zephyr_library_sources_ifdef(CONFIG_CAN_NUMAKER can_numaker.c) - -if(CONFIG_CAN_NATIVE_POSIX_LINUX) - if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) - zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2) - zephyr_library_compile_definitions(NO_POSIX_CHEATS) - zephyr_library_compile_definitions(_BSD_SOURCE) - zephyr_library_compile_definitions(_DEFAULT_SOURCE) - zephyr_library_sources( - can_native_posix_linux.c - can_native_posix_linux_socketcan.c - ) - else() - message(FATAL_ERROR "CONFIG_CAN_NATIVE_POSIX_LINUX only available on Linux") - endif() -endif() - +zephyr_library_sources_ifdef(CONFIG_CAN_XMC4XXX can_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_CAN_SJA1000 can_sja1000.c) zephyr_library_sources_ifdef(CONFIG_CAN_ESP32_TWAI can_esp32_twai.c) zephyr_library_sources_ifdef(CONFIG_CAN_KVASER_PCI can_kvaser_pci.c) @@ -44,4 +29,22 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c) zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) zephyr_library_sources_ifdef(CONFIG_CAN_NXP_S32_CANXL can_nxp_s32_canxl.c) +if(CONFIG_CAN_NATIVE_LINUX) + if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) + zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2) + zephyr_library_sources(can_native_linux.c) + + if (CONFIG_NATIVE_APPLICATION) + set_source_files_properties(can_native_linux_adapt.c + PROPERTIES COMPILE_DEFINITIONS + "NO_POSIX_CHEATS;_BSD_SOURCE;_DEFAULT_SOURCE") + zephyr_library_sources(can_native_linux_adapt.c) + else() + target_sources(native_simulator INTERFACE can_native_linux_adapt.c) + endif() + else() + message(FATAL_ERROR "CONFIG_CAN_NATIVE_LINUX is only available on Linux") + endif() +endif() + add_subdirectory(transceiver) diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index ed0818d3508..702676c09a3 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -54,6 +54,13 @@ config CAN_STATS help Enable CAN controller device statistics. +config CAN_ACCEPT_RTR + bool "Accept Remote Transmission Requests (RTR) frames" + help + Accept incoming Remote Transmission Request (RTR) frames matching CAN RX filters. Unless + enabled, all incoming Remote Transmission Request (RTR) frames are rejected at the driver + level. + config CAN_FD_MODE bool "CAN FD" help @@ -93,7 +100,7 @@ source "drivers/can/Kconfig.mcan" source "drivers/can/Kconfig.rcar" source "drivers/can/Kconfig.numaker" source "drivers/can/Kconfig.loopback" -source "drivers/can/Kconfig.native_posix_linux" +source "drivers/can/Kconfig.native_linux" source "drivers/can/Kconfig.sja1000" source "drivers/can/Kconfig.esp32" source "drivers/can/Kconfig.kvaser" @@ -101,6 +108,7 @@ source "drivers/can/Kconfig.fake" source "drivers/can/Kconfig.nxp_s32" source "drivers/can/Kconfig.tcan4x5x" source "drivers/can/Kconfig.mcp251xfd" +source "drivers/can/Kconfig.xmc4xxx" source "drivers/can/transceiver/Kconfig" diff --git a/drivers/can/Kconfig.mcux b/drivers/can/Kconfig.mcux index 5983be36c8a..7df67684e8a 100644 --- a/drivers/can/Kconfig.mcux +++ b/drivers/can/Kconfig.mcux @@ -31,8 +31,10 @@ config CAN_MCUX_FLEXCAN_WAIT_TIMEOUT config CAN_MAX_MB int "Maximum number of message buffers for concurrent active instances" default 16 - depends on SOC_SERIES_S32K3XX - range 1 96 + depends on SOC_SERIES_S32K3XX || SOC_SERIES_S32K1XX + range 1 96 if SOC_SERIES_S32K3XX + range 1 32 if SOC_SERIES_S32K1XX && !SOC_S32K142W && !SOC_S32K144W + range 1 64 if SOC_S32K142W || SOC_S32K144W help Defines maximum number of message buffers for concurrent active instances. @@ -43,6 +45,8 @@ config CAN_MAX_FILTER range 1 13 if SOC_SERIES_IMX_RT && CAN_MCUX_FLEXCAN_FD range 1 63 if SOC_SERIES_IMX_RT range 1 96 if SOC_SERIES_S32K3XX + range 1 32 if SOC_SERIES_S32K1XX && !SOC_S32K142W && !SOC_S32K144W + range 1 64 if SOC_S32K142W || SOC_S32K144W help Defines maximum number of concurrent active RX filters diff --git a/drivers/can/Kconfig.native_linux b/drivers/can/Kconfig.native_linux new file mode 100644 index 00000000000..54969fd7de1 --- /dev/null +++ b/drivers/can/Kconfig.native_linux @@ -0,0 +1,31 @@ +# Native Linux SocketCAN configuration options + +# Copyright (c) 2022 Martin Jäger +# SPDX-License-Identifier: Apache-2.0 + +config CAN_NATIVE_LINUX + bool "Native Linux SocketCAN Driver" + default y + depends on DT_HAS_ZEPHYR_NATIVE_LINUX_CAN_ENABLED + depends on ARCH_POSIX + help + Enable native Linux SocketCAN Driver + +if CAN_NATIVE_LINUX + +config CAN_NATIVE_LINUX_RX_THREAD_PRIORITY + int "Priority for internal RX thread" + default 2 + help + Priority level of the internal thread which is run for + handling of incoming packets. + +config CAN_MAX_FILTER + int "Maximum number of concurrent active filters" + default 5 + range 1 32 + help + Defines the array size of the callback/msgq pointers. + Must be at least the size of concurrent reads. + +endif # CAN_NATIVE_LINUX diff --git a/drivers/can/Kconfig.native_posix_linux b/drivers/can/Kconfig.native_posix_linux deleted file mode 100644 index c6719e1de49..00000000000 --- a/drivers/can/Kconfig.native_posix_linux +++ /dev/null @@ -1,30 +0,0 @@ -# Native Linux SocketCAN configuration options - -# Copyright (c) 2022 Martin Jäger -# SPDX-License-Identifier: Apache-2.0 - -config CAN_NATIVE_POSIX_LINUX - bool "Native Linux SocketCAN Driver" - default y - depends on DT_HAS_ZEPHYR_NATIVE_POSIX_LINUX_CAN_ENABLED - help - Enable native Linux SocketCAN Driver - -if CAN_NATIVE_POSIX_LINUX - -config CAN_NATIVE_POSIX_LINUX_RX_THREAD_PRIORITY - int "Priority for internal RX thread" - default 2 - help - Priority level of the internal thread which is run for - handling of incoming packets. - -config CAN_MAX_FILTER - int "Maximum number of concurrent active filters" - default 5 - range 1 32 - help - Defines the array size of the callback/msgq pointers. - Must be at least the size of concurrent reads. - -endif # CAN_NATIVE_POSIX_LINUX diff --git a/drivers/can/Kconfig.nxp_s32 b/drivers/can/Kconfig.nxp_s32 index 53c1ffc2b8b..09727d719ef 100644 --- a/drivers/can/Kconfig.nxp_s32 +++ b/drivers/can/Kconfig.nxp_s32 @@ -1,4 +1,4 @@ -# Copyright 2022-2023 NXP +# Copyright 2022-2024 NXP # SPDX-License-Identifier: Apache-2.0 config CAN_NXP_S32_CANXL @@ -10,17 +10,23 @@ config CAN_NXP_S32_CANXL Enable support for NXP S32 CANXL driver. if CAN_NXP_S32_CANXL +config CAN_NXP_S32_RX_FIFO + bool "NXP S32 CANXL uses RX FIFO" + default y + help + If this is enabled, NXP S32 CANXL uses RX FIFO. + Otherwise NXP S32 CANXL uses RX Message Descriptor. + config CAN_NXP_S32_MAX_RX int "Maximum number of RX descriptors" - depends on CAN_NXP_S32_CANXL default 16 - range 1 128 + range 1 32 if CAN_NXP_S32_RX_FIFO + range 1 128 if !CAN_NXP_S32_RX_FIFO help Maximum number of RX descriptors. config CAN_NXP_S32_MAX_TX int "Maximum number of TX descriptors" - depends on CAN_NXP_S32_CANXL default 16 range 1 128 help diff --git a/drivers/can/Kconfig.xmc4xxx b/drivers/can/Kconfig.xmc4xxx new file mode 100644 index 00000000000..2fbb5df7064 --- /dev/null +++ b/drivers/can/Kconfig.xmc4xxx @@ -0,0 +1,43 @@ +# Infineon XMC4xxx CAN configuration options +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 + +config CAN_XMC4XXX + bool "Infineon XMC4xxx CAN Driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_CAN_NODE_ENABLED + help + Enable Infineon XMC4xxx CAN Driver + +if CAN_XMC4XXX + +config CAN_XMC4XXX_MAX_TX_QUEUE + int "Maximum number of queued messages" + default 8 + range 1 32 + help + Defines the array size of transmit callback pointers and semaphores, + as well as the number of messages in the TX queue. + +config CAN_XMC4XXX_RX_FIFO_ITEMS + int "Number of CAN messages allocated to each RX FIFO" + default 8 + range 1 32 + help + Defines the number of CAN messages in each RX FIFO. A separate RX FIFO + is created for each RX filter. + +config CAN_XMC4XXX_INTERNAL_BUS_MODE + bool "Internal bus mode" + help + Connects all XMC4XXX CAN devices to an internal bus. Enables + message exchange between MCU CAN devices without any external connectors. + +config CAN_MAX_FILTER + int "Maximum number of concurrent active filters" + default 4 + range 1 32 + help + Maximum number of filters supported by the can_add_rx_callback() API call. + +endif # CAN_XMC4XXX diff --git a/drivers/can/can_esp32_twai.c b/drivers/can/can_esp32_twai.c index 2fd379d0049..11c30a2338c 100644 --- a/drivers/can/can_esp32_twai.c +++ b/drivers/can/can_esp32_twai.c @@ -119,7 +119,7 @@ static int can_esp32_twai_set_timing(const struct device *dev, const struct can_ uint8_t btr0; uint8_t btr1; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -130,7 +130,7 @@ static int can_esp32_twai_set_timing(const struct device *dev, const struct can_ btr1 = TWAI_TIME_SEG1_PREP(timing->phase_seg1 - 1) | TWAI_TIME_SEG2_PREP(timing->phase_seg2 - 1); - if ((data->mode & CAN_MODE_3_SAMPLES) != 0) { + if ((data->common.mode & CAN_MODE_3_SAMPLES) != 0) { btr1 |= TWAI_TIME_SAMP; } @@ -224,7 +224,6 @@ const struct can_driver_api can_esp32_twai_driver_api = { .set_state_change_callback = can_sja1000_set_state_change_callback, .get_core_clock = can_esp32_twai_get_core_clock, .get_max_filters = can_sja1000_get_max_filters, - .get_max_bitrate = can_sja1000_get_max_bitrate, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY .recover = can_sja1000_recover, #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ diff --git a/drivers/can/can_fake.c b/drivers/can/can_fake.c index 88d7780eaad..097a614a35e 100644 --- a/drivers/can/can_fake.c +++ b/drivers/can/can_fake.c @@ -15,6 +15,14 @@ #define DT_DRV_COMPAT zephyr_fake_can +struct fake_can_config { + const struct can_driver_config common; +}; + +struct fake_can_data { + struct can_driver_data common; +}; + DEFINE_FAKE_VALUE_FUNC(int, fake_can_start, const struct device *); DEFINE_FAKE_VALUE_FUNC(int, fake_can_stop, const struct device *); @@ -46,6 +54,17 @@ DEFINE_FAKE_VOID_FUNC(fake_can_set_state_change_callback, const struct device *, DEFINE_FAKE_VALUE_FUNC(int, fake_can_get_max_filters, const struct device *, bool); +DEFINE_FAKE_VALUE_FUNC(int, fake_can_get_core_clock, const struct device *, uint32_t *); + +static int fake_can_get_core_clock_delegate(const struct device *dev, uint32_t *rate) +{ + ARG_UNUSED(dev); + + *rate = 16000000; + + return 0; +} + #ifdef CONFIG_ZTEST static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void *fixture) { @@ -65,29 +84,15 @@ static void fake_can_reset_rule_before(const struct ztest_unit_test *test, void RESET_FAKE(fake_can_recover); RESET_FAKE(fake_can_set_state_change_callback); RESET_FAKE(fake_can_get_max_filters); + RESET_FAKE(fake_can_get_core_clock); + + /* Re-install default delegate for reporting the core clock */ + fake_can_get_core_clock_fake.custom_fake = fake_can_get_core_clock_delegate; } ZTEST_RULE(fake_can_reset_rule, fake_can_reset_rule_before, NULL); #endif /* CONFIG_ZTEST */ -static int fake_can_get_core_clock(const struct device *dev, uint32_t *rate) -{ - ARG_UNUSED(dev); - - *rate = 16000000; - - return 0; -} - -static int fake_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - ARG_UNUSED(dev); - - *max_bitrate = 5000000; - - return 0; -} - static const struct can_driver_api fake_can_driver_api = { .start = fake_can_start, .stop = fake_can_stop, @@ -104,7 +109,6 @@ static const struct can_driver_api fake_can_driver_api = { .set_state_change_callback = fake_can_set_state_change_callback, .get_core_clock = fake_can_get_core_clock, .get_max_filters = fake_can_get_max_filters, - .get_max_bitrate = fake_can_get_max_bitrate, .timing_min = { .sjw = 0x01, .prop_seg = 0x01, @@ -139,7 +143,14 @@ static const struct can_driver_api fake_can_driver_api = { }; #define FAKE_CAN_INIT(inst) \ - CAN_DEVICE_DT_INST_DEFINE(inst, NULL, NULL, NULL, NULL, POST_KERNEL, \ + static const struct fake_can_config fake_can_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0U), \ + }; \ + \ + static struct fake_can_data fake_can_data_##inst; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &fake_can_data_##inst, \ + &fake_can_config_##inst, POST_KERNEL, \ CONFIG_CAN_INIT_PRIORITY, \ &fake_can_driver_api); diff --git a/drivers/can/can_handlers.c b/drivers/can/can_handlers.c index 57201ce6eca..aa0a62674cb 100644 --- a/drivers/can/can_handlers.c +++ b/drivers/can/can_handlers.c @@ -48,7 +48,6 @@ static inline int z_vrfy_can_get_core_clock(const struct device *dev, static inline int z_vrfy_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { - /* Optional API function */ K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); K_OOPS(K_SYSCALL_MEMORY_WRITE(max_bitrate, sizeof(*max_bitrate))); @@ -147,6 +146,14 @@ static inline int z_vrfy_can_get_capabilities(const struct device *dev, can_mode } #include +static inline const struct device *z_vrfy_can_get_transceiver(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_get_transceiver(dev); +} +#include + static inline int z_vrfy_can_start(const struct device *dev) { K_OOPS(K_SYSCALL_DRIVER_CAN(dev, start)); @@ -171,6 +178,14 @@ static inline int z_vrfy_can_set_mode(const struct device *dev, can_mode_t mode) } #include +static inline can_mode_t z_vrfy_can_get_mode(const struct device *dev) +{ + K_OOPS(K_SYSCALL_OBJ(dev, K_OBJ_DRIVER_CAN)); + + return z_impl_can_get_mode(dev); +} +#include + static inline int z_vrfy_can_set_bitrate(const struct device *dev, uint32_t bitrate) { K_OOPS(K_SYSCALL_DRIVER_CAN(dev, set_timing)); diff --git a/drivers/can/can_kvaser_pci.c b/drivers/can/can_kvaser_pci.c index 2aa002efd8c..909b29a0a34 100644 --- a/drivers/can/can_kvaser_pci.c +++ b/drivers/can/can_kvaser_pci.c @@ -143,7 +143,6 @@ const struct can_driver_api can_kvaser_pci_driver_api = { .set_state_change_callback = can_sja1000_set_state_change_callback, .get_core_clock = can_kvaser_pci_get_core_clock, .get_max_filters = can_sja1000_get_max_filters, - .get_max_bitrate = can_sja1000_get_max_bitrate, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY .recover = can_sja1000_recover, #endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index 863bf3a69ac..ffab53b315e 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -28,17 +28,17 @@ struct can_loopback_filter { struct can_filter filter; }; +struct can_loopback_config { + const struct can_driver_config common; +}; + struct can_loopback_data { + struct can_driver_data common; struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex mtx; struct k_msgq tx_msgq; char msgq_buffer[CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE * sizeof(struct can_loopback_frame)]; struct k_thread tx_thread_data; - bool started; - bool loopback; -#ifdef CONFIG_CAN_FD_MODE - bool fd; -#endif /* CONFIG_CAN_FD_MODE */ K_KERNEL_STACK_MEMBER(tx_thread_stack, CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE); @@ -77,10 +77,16 @@ static void tx_thread(void *arg1, void *arg2, void *arg3) } frame.cb(dev, 0, frame.cb_arg); - if (!data->loopback) { + if ((data->common.mode & CAN_MODE_LOOPBACK) == 0U) { continue; } +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + k_mutex_lock(&data->mtx, K_FOREVER); for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { @@ -120,7 +126,7 @@ static int can_loopback_send(const struct device *dev, } if ((frame->flags & CAN_FRAME_FDF) != 0) { - if (!data->fd) { + if ((data->common.mode & CAN_MODE_FD) == 0U) { return -ENOTSUP; } @@ -138,7 +144,7 @@ static int can_loopback_send(const struct device *dev, return -EINVAL; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -176,12 +182,7 @@ static int can_loopback_add_rx_filter(const struct device *dev, can_rx_callback_ LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, filter->mask); -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | - CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0) { -#else - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { -#endif + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -239,11 +240,11 @@ static int can_loopback_start(const struct device *dev) { struct can_loopback_data *data = dev->data; - if (data->started) { + if (data->common.started) { return -EALREADY; } - data->started = true; + data->common.started = true; return 0; } @@ -252,11 +253,11 @@ static int can_loopback_stop(const struct device *dev) { struct can_loopback_data *data = dev->data; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; k_msgq_purge(&data->tx_msgq); @@ -267,7 +268,7 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) { struct can_loopback_data *data = dev->data; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -276,8 +277,6 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) LOG_ERR("unsupported mode: 0x%08x", mode); return -ENOTSUP; } - - data->fd = (mode & CAN_MODE_FD) != 0; #else if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) { LOG_ERR("unsupported mode: 0x%08x", mode); @@ -285,7 +284,7 @@ static int can_loopback_set_mode(const struct device *dev, can_mode_t mode) } #endif /* CONFIG_CAN_FD_MODE */ - data->loopback = (mode & CAN_MODE_LOOPBACK) != 0; + data->common.mode = mode; return 0; } @@ -297,7 +296,7 @@ static int can_loopback_set_timing(const struct device *dev, ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -312,7 +311,7 @@ static int can_loopback_set_timing_data(const struct device *dev, ARG_UNUSED(timing); - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -326,7 +325,7 @@ static int can_loopback_get_state(const struct device *dev, enum can_state *stat struct can_loopback_data *data = dev->data; if (state != NULL) { - if (data->started) { + if (data->common.started) { *state = CAN_STATE_ERROR_ACTIVE; } else { *state = CAN_STATE_STOPPED; @@ -348,7 +347,7 @@ static int can_loopback_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -457,12 +456,17 @@ static int can_loopback_init(const struct device *dev) return 0; } -#define CAN_LOOPBACK_INIT(inst) \ - static struct can_loopback_data can_loopback_dev_data_##inst; \ - \ - CAN_DEVICE_DT_INST_DEFINE(inst, can_loopback_init, NULL, \ - &can_loopback_dev_data_##inst, NULL, \ - POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,\ +#define CAN_LOOPBACK_INIT(inst) \ + static const struct can_loopback_config can_loopback_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0U), \ + }; \ + \ + static struct can_loopback_data can_loopback_data_##inst; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, can_loopback_init, NULL, \ + &can_loopback_data_##inst, \ + &can_loopback_config_##inst, \ + POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ &can_loopback_driver_api); DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT) diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 529f2ed7dff..886f959b29a 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -200,7 +200,7 @@ int can_mcan_set_timing(const struct device *dev, const struct can_timing *timin uint32_t nbtp = 0U; int err; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -229,7 +229,7 @@ int can_mcan_set_timing_data(const struct device *dev, const struct can_timing * uint32_t dbtp = 0U; int err; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -271,12 +271,12 @@ int can_mcan_start(const struct device *dev) struct can_mcan_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -290,15 +290,15 @@ int can_mcan_start(const struct device *dev) if (err != 0) { LOG_ERR("failed to leave init mode"); - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } return -EIO; } - data->started = true; + data->common.started = true; return 0; } @@ -312,7 +312,7 @@ int can_mcan_stop(const struct device *dev) uint32_t tx_idx; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -323,8 +323,8 @@ int can_mcan_stop(const struct device *dev) return -EIO; } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -333,7 +333,7 @@ int can_mcan_stop(const struct device *dev) can_mcan_enable_configuration_change(dev); - data->started = false; + data->common.started = false; for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) { tx_cb = cbs->tx[tx_idx].function; @@ -367,7 +367,7 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) } #endif /* !CONFIG_CAN_FD_MODE */ - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -401,10 +401,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) #ifdef CONFIG_CAN_FD_MODE if ((mode & CAN_MODE_FD) != 0) { cccr |= CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE; - data->fd = true; } else { cccr &= ~(CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE); - data->fd = false; } #endif /* CONFIG_CAN_FD_MODE */ @@ -418,6 +416,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) goto unlock; } + data->common.mode = mode; + unlock: k_mutex_unlock(&data->lock); @@ -427,8 +427,8 @@ int can_mcan_set_mode(const struct device *dev, can_mode_t mode) static void can_mcan_state_change_handler(const struct device *dev) { struct can_mcan_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; struct can_bus_err_cnt err_cnt; enum can_state state; @@ -615,7 +615,6 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, struct can_frame frame = {0}; can_rx_callback_t cb; void *user_data; - uint8_t flags; uint32_t get_idx; uint32_t filt_idx; int data_length; @@ -666,30 +665,8 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, if (hdr.xtd != 0) { frame.id = hdr.ext_id; frame.flags |= CAN_FRAME_IDE; - flags = cbs->ext[filt_idx].flags; } else { frame.id = hdr.std_id; - flags = cbs->std[filt_idx].flags; - } - - if (((frame.flags & CAN_FRAME_RTR) == 0U && (flags & CAN_FILTER_DATA) == 0U) || - ((frame.flags & CAN_FRAME_RTR) != 0U && (flags & CAN_FILTER_RTR) == 0U)) { - /* RTR bit does not match filter, drop frame */ - err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); - if (err != 0) { - return; - } - goto ack; - } - - if (((frame.flags & CAN_FRAME_FDF) != 0U && (flags & CAN_FILTER_FDF) == 0U) || - ((frame.flags & CAN_FRAME_FDF) == 0U && (flags & CAN_FILTER_FDF) != 0U)) { - /* FDF bit does not match filter, drop frame */ - err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); - if (err != 0) { - return; - } - goto ack; } data_length = can_dlc_to_bytes(frame.dlc); @@ -728,7 +705,6 @@ static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset, LOG_ERR("Frame is too big"); } -ack: err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx); if (err != 0) { return; @@ -802,7 +778,7 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state, return err; } - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else if ((reg & CAN_MCAN_PSR_BO) != 0U) { *state = CAN_STATE_BUS_OFF; @@ -833,7 +809,7 @@ int can_mcan_recover(const struct device *dev, k_timeout_t timeout) { struct can_mcan_data *data = dev->data; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -881,7 +857,8 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim return -ENOTSUP; } - if (!data->fd && ((frame->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0U)) { + if ((data->common.mode & CAN_MODE_FD) == 0U && + ((frame->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0U)) { LOG_ERR("CAN FD format not supported in non-FD mode"); return -ENOTSUP; } @@ -910,7 +887,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim } } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -1051,7 +1028,6 @@ int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callb __ASSERT_NO_MSG(filter_id <= cbs->num_std); cbs->std[filter_id].function = callback; cbs->std[filter_id].user_data = user_data; - cbs->std[filter_id].flags = filter->flags; return filter_id; } @@ -1104,7 +1080,6 @@ static int can_mcan_add_rx_filter_ext(const struct device *dev, can_rx_callback_ __ASSERT_NO_MSG(filter_id <= cbs->num_ext); cbs->ext[filter_id].function = callback; cbs->ext[filter_id].user_data = user_data; - cbs->ext[filter_id].flags = filter->flags; return filter_id; } @@ -1120,12 +1095,7 @@ int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, return -EINVAL; } -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & - ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0U) { -#else /* CONFIG_CAN_FD_MODE */ - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0U) { -#endif /* !CONFIG_CAN_FD_MODE */ + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0U) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -1193,17 +1163,8 @@ void can_mcan_set_state_change_callback(const struct device *dev, { struct can_mcan_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; -} - -int can_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_mcan_config *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } /* helper function allowing mcan drivers without access to private mcan @@ -1354,8 +1315,8 @@ int can_mcan_init(const struct device *dev) k_mutex_init(&data->tx_mtx); k_sem_init(&data->tx_sem, cbs->num_tx, cbs->num_tx); - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1444,14 +1405,18 @@ int can_mcan_init(const struct device *dev) } reg |= FIELD_PREP(CAN_MCAN_GFC_ANFE, 0x2) | FIELD_PREP(CAN_MCAN_GFC_ANFS, 0x2); + if (!IS_ENABLED(CONFIG_CAN_ACCEPT_RTR)) { + reg |= CAN_MCAN_GFC_RRFS | CAN_MCAN_GFC_RRFE; + } err = can_mcan_write_reg(dev, CAN_MCAN_GFC, reg); if (err != 0) { return err; } - if (config->sample_point) { - err = can_calc_timing(dev, &timing, config->bus_speed, config->sample_point); + if (config->common.sample_point) { + err = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1464,15 +1429,15 @@ int can_mcan_init(const struct device *dev) timing.prop_seg = 0U; timing.phase_seg1 = config->prop_ts1; timing.phase_seg2 = config->ts2; - err = can_calc_prescaler(dev, &timing, config->bus_speed); + err = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (err != 0) { LOG_WRN("Bitrate error: %d", err); } } #ifdef CONFIG_CAN_FD_MODE - if (config->sample_point_data) { - err = can_calc_timing_data(dev, &timing_data, config->bus_speed_data, - config->sample_point_data); + if (config->common.sample_point_data) { + err = can_calc_timing_data(dev, &timing_data, config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing for given dataphase param"); return -EIO; @@ -1484,7 +1449,7 @@ int can_mcan_init(const struct device *dev) timing_data.prop_seg = 0U; timing_data.phase_seg1 = config->prop_ts1_data; timing_data.phase_seg2 = config->ts2_data; - err = can_calc_prescaler(dev, &timing_data, config->bus_speed_data); + err = can_calc_prescaler(dev, &timing_data, config->common.bus_speed_data); if (err != 0) { LOG_WRN("Dataphase bitrate error: %d", err); } diff --git a/drivers/can/can_mcp2515.c b/drivers/can/can_mcp2515.c index 0a610fba601..750273fc715 100644 --- a/drivers/can/can_mcp2515.c +++ b/drivers/can/can_mcp2515.c @@ -334,15 +334,6 @@ static int mcp2515_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcp2515_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcp2515_config *dev_cfg = dev->config; - - *max_bitrate = dev_cfg->max_bitrate; - - return 0; -} - static int mcp2515_set_timing(const struct device *dev, const struct can_timing *timing) { @@ -353,7 +344,7 @@ static int mcp2515_set_timing(const struct device *dev, return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -439,12 +430,12 @@ static int mcp2515_start(const struct device *dev) struct mcp2515_data *dev_data = dev->data; int ret; - if (dev_data->started) { + if (dev_data->common.started) { return -EALREADY; } - if (dev_cfg->phy != NULL) { - ret = can_transceiver_enable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); if (ret != 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; @@ -459,12 +450,12 @@ static int mcp2515_start(const struct device *dev) if (ret < 0) { LOG_ERR("Failed to set the mode [%d]", ret); - if (dev_cfg->phy != NULL) { + if (dev_cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(dev_cfg->phy); + (void)can_transceiver_disable(dev_cfg->common.phy); } } else { - dev_data->started = true; + dev_data->common.started = true; } k_mutex_unlock(&dev_data->mutex); @@ -479,7 +470,7 @@ static int mcp2515_stop(const struct device *dev) int ret; int i; - if (!dev_data->started) { + if (!dev_data->common.started) { return -EALREADY; } @@ -504,7 +495,7 @@ static int mcp2515_stop(const struct device *dev) return ret; } - dev_data->started = false; + dev_data->common.started = false; k_mutex_unlock(&dev_data->mutex); @@ -512,8 +503,8 @@ static int mcp2515_stop(const struct device *dev) mcp2515_tx_done(dev, i, -ENETDOWN); } - if (dev_cfg->phy != NULL) { - ret = can_transceiver_disable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); if (ret != 0) { LOG_ERR("Failed to disable CAN transceiver [%d]", ret); return ret; @@ -527,7 +518,7 @@ static int mcp2515_set_mode(const struct device *dev, can_mode_t mode) { struct mcp2515_data *dev_data = dev->data; - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -546,6 +537,8 @@ static int mcp2515_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } + dev_data->common.mode = mode; + return 0; } @@ -574,7 +567,7 @@ static int mcp2515_send(const struct device *dev, return -ENOTSUP; } - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -629,7 +622,7 @@ static int mcp2515_add_rx_filter(const struct device *dev, __ASSERT(rx_cb != NULL, "response_ptr can not be null"); - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -679,8 +672,8 @@ static void mcp2515_set_state_change_callback(const struct device *dev, { struct mcp2515_data *dev_data = dev->data; - dev_data->state_change_cb = cb; - dev_data->state_change_cb_data = user_data; + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; } static void mcp2515_rx_filter(const struct device *dev, @@ -691,6 +684,12 @@ static void mcp2515_rx_filter(const struct device *dev, can_rx_callback_t callback; struct can_frame tmp_frame; +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + k_mutex_lock(&dev_data->mutex, K_FOREVER); for (; filter_id < CONFIG_CAN_MAX_FILTER; filter_id++) { @@ -744,7 +743,7 @@ static int mcp2515_get_state(const struct device *dev, enum can_state *state, } if (state != NULL) { - if (!dev_data->started) { + if (!dev_data->common.started) { *state = CAN_STATE_STOPPED; } else if (eflg & MCP2515_EFLG_TXBO) { *state = CAN_STATE_BUS_OFF; @@ -789,8 +788,8 @@ static int mcp2515_get_state(const struct device *dev, enum can_state *state, static void mcp2515_handle_errors(const struct device *dev) { struct mcp2515_data *dev_data = dev->data; - can_state_change_callback_t state_change_cb = dev_data->state_change_cb; - void *state_change_cb_data = dev_data->state_change_cb_data; + can_state_change_callback_t state_change_cb = dev_data->common.state_change_cb; + void *state_change_cb_data = dev_data->common.state_change_cb_user_data; enum can_state state; struct can_bus_err_cnt err_cnt; int err; @@ -814,7 +813,7 @@ static int mcp2515_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -928,7 +927,6 @@ static const struct can_driver_api can_api_funcs = { .set_state_change_callback = mcp2515_set_state_change_callback, .get_core_clock = mcp2515_get_core_clock, .get_max_filters = mcp2515_get_max_filters, - .get_max_bitrate = mcp2515_get_max_bitrate, .timing_min = { .sjw = 0x1, .prop_seg = 0x01, @@ -958,8 +956,8 @@ static int mcp2515_init(const struct device *dev) k_mutex_init(&dev_data->mutex); k_sem_init(&dev_data->tx_sem, MCP2515_TX_CNT, MCP2515_TX_CNT); - if (dev_cfg->phy != NULL) { - if (!device_is_ready(dev_cfg->phy)) { + if (dev_cfg->common.phy != NULL) { + if (!device_is_ready(dev_cfg->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1011,9 +1009,9 @@ static int mcp2515_init(const struct device *dev) (void)memset(dev_data->filter, 0, sizeof(dev_data->filter)); dev_data->old_state = CAN_STATE_ERROR_ACTIVE; - if (dev_cfg->sample_point && USE_SP_ALGO) { - ret = can_calc_timing(dev, &timing, dev_cfg->bus_speed, - dev_cfg->sample_point); + if (dev_cfg->common.sample_point && USE_SP_ALGO) { + ret = can_calc_timing(dev, &timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1026,7 +1024,7 @@ static int mcp2515_init(const struct device *dev) timing.prop_seg = dev_cfg->tq_prop; timing.phase_seg1 = dev_cfg->tq_bs1; timing.phase_seg2 = dev_cfg->tq_bs2; - ret = can_calc_prescaler(dev, &timing, dev_cfg->bus_speed); + ret = can_calc_prescaler(dev, &timing, dev_cfg->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -1055,6 +1053,7 @@ static int mcp2515_init(const struct device *dev) }; \ \ static const struct mcp2515_config mcp2515_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ .bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ .int_thread_stack_size = CONFIG_CAN_MCP2515_INT_THREAD_STACK_SIZE, \ @@ -1063,11 +1062,7 @@ static int mcp2515_init(const struct device *dev) .tq_prop = DT_INST_PROP_OR(inst, prop_seg, 0), \ .tq_bs1 = DT_INST_PROP_OR(inst, phase_seg1, 0), \ .tq_bs2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ - .bus_speed = DT_INST_PROP(inst, bus_speed), \ .osc_freq = DT_INST_PROP(inst, osc_freq), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ }; \ \ CAN_DEVICE_DT_INST_DEFINE(inst, mcp2515_init, NULL, &mcp2515_data_##inst, \ diff --git a/drivers/can/can_mcp2515.h b/drivers/can/can_mcp2515.h index f8e2921ba63..2582e19daa3 100644 --- a/drivers/can/can_mcp2515.h +++ b/drivers/can/can_mcp2515.h @@ -22,6 +22,8 @@ struct mcp2515_tx_cb { }; struct mcp2515_data { + struct can_driver_data common; + /* interrupt data */ struct gpio_callback int_gpio_cb; struct k_thread int_thread; @@ -38,17 +40,16 @@ struct mcp2515_data { can_rx_callback_t rx_cb[CONFIG_CAN_MAX_FILTER]; void *cb_arg[CONFIG_CAN_MAX_FILTER]; struct can_filter filter[CONFIG_CAN_MAX_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; /* general data */ struct k_mutex mutex; enum can_state old_state; uint8_t mcp2515_mode; - bool started; }; struct mcp2515_config { + const struct can_driver_config common; + /* spi configuration */ struct spi_dt_spec bus; @@ -62,13 +63,7 @@ struct mcp2515_config { uint8_t tq_prop; uint8_t tq_bs1; uint8_t tq_bs2; - uint32_t bus_speed; uint32_t osc_freq; - uint16_t sample_point; - - /* CAN transceiver */ - const struct device *phy; - uint32_t max_bitrate; }; /* diff --git a/drivers/can/can_mcp251xfd.c b/drivers/can/can_mcp251xfd.c index 7b788ec2b6c..81d2820f1f7 100644 --- a/drivers/can/can_mcp251xfd.c +++ b/drivers/can/can_mcp251xfd.c @@ -297,6 +297,7 @@ static int mcp251xfd_reg_check_value_wtimeout(const struct device *dev, uint16_t static int mcp251xfd_set_tdc(const struct device *dev, bool is_enabled, int tdc_offset) { uint32_t *reg; + uint32_t tmp; if (is_enabled && (tdc_offset < MCP251XFD_REG_TDC_TDCO_MIN || tdc_offset > MCP251XFD_REG_TDC_TDCO_MAX)) { @@ -306,13 +307,13 @@ static int mcp251xfd_set_tdc(const struct device *dev, bool is_enabled, int tdc_ reg = mcp251xfd_get_spi_buf_ptr(dev); if (is_enabled) { - *reg = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_AUTO); - *reg |= FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdc_offset); + tmp = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_AUTO); + tmp |= FIELD_PREP(MCP251XFD_REG_TDC_TDCO_MASK, tdc_offset); } else { - *reg = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_DISABLED); + tmp = FIELD_PREP(MCP251XFD_REG_TDC_TDCMOD_MASK, MCP251XFD_REG_TDC_TDCMOD_DISABLED); } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TDC, MCP251XFD_REG_SIZE); } @@ -379,7 +380,7 @@ static int mcp251xfd_set_mode(const struct device *dev, can_mode_t mode) { struct mcp251xfd_data *dev_data = dev->data; - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -408,7 +409,7 @@ static int mcp251xfd_set_mode(const struct device *dev, can_mode_t mode) dev_data->next_mcp251xfd_mode = MCP251XFD_REG_CON_MODE_EXT_LOOPBACK; } - dev_data->mode = mode; + dev_data->common.mode = mode; return 0; } @@ -417,24 +418,26 @@ static int mcp251xfd_set_timing(const struct device *dev, const struct can_timin { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret; if (!timing) { return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } k_mutex_lock(&dev_data->mutex, K_FOREVER); reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = FIELD_PREP(MCP251XFD_REG_NBTCFG_BRP_MASK, timing->prescaler - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG1_MASK, + tmp = FIELD_PREP(MCP251XFD_REG_NBTCFG_BRP_MASK, timing->prescaler - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG1_MASK, timing->prop_seg + timing->phase_seg1 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_NBTCFG_SJW_MASK, timing->sjw - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_NBTCFG_SJW_MASK, timing->sjw - 1); + *reg = tmp; ret = mcp251xfd_write(dev, MCP251XFD_REG_NBTCFG, MCP251XFD_REG_SIZE); if (ret < 0) { @@ -452,13 +455,14 @@ static int mcp251xfd_set_timing_data(const struct device *dev, const struct can_ { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret; if (!timing) { return -EINVAL; } - if (dev_data->started) { + if (dev_data->common.started) { return -EBUSY; } @@ -466,13 +470,13 @@ static int mcp251xfd_set_timing_data(const struct device *dev, const struct can_ reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = FIELD_PREP(MCP251XFD_REG_DBTCFG_BRP_MASK, timing->prescaler - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG1_MASK, - timing->prop_seg + timing->phase_seg1 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_DBTCFG_SJW_MASK, timing->sjw - 1); + tmp = FIELD_PREP(MCP251XFD_REG_DBTCFG_BRP_MASK, timing->prescaler - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG1_MASK, + timing->prop_seg + timing->phase_seg1 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_TSEG2_MASK, timing->phase_seg2 - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_DBTCFG_SJW_MASK, timing->sjw - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); dev_data->tdco = timing->prescaler * (timing->prop_seg + timing->phase_seg1); @@ -502,7 +506,7 @@ static int mcp251xfd_send(const struct device *dev, const struct can_frame *msg, __ASSERT_NO_MSG(callback != NULL); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -515,7 +519,7 @@ static int mcp251xfd_send(const struct device *dev, const struct can_frame *msg, return -EINVAL; } - if ((msg->flags & CAN_FRAME_FDF) && !(dev_data->mode & CAN_MODE_FD)) { + if ((msg->flags & CAN_FRAME_FDF) && !(dev_data->common.mode & CAN_MODE_FD)) { return -ENOTSUP; } @@ -558,6 +562,7 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; uint8_t *reg_byte; int filter_idx; int ret; @@ -576,22 +581,17 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r goto done; } - if ((filter->flags & CAN_FILTER_RTR) != 0) { - filter_idx = -ENOTSUP; - goto done; - } - reg = mcp251xfd_get_spi_buf_ptr(dev); if ((filter->flags & CAN_FILTER_IDE) != 0) { - *reg = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id >> 18); - *reg |= FIELD_PREP(MCP251XFD_REG_FLTOBJ_EID_MASK, filter->id); - *reg |= MCP251XFD_REG_FLTOBJ_EXIDE; + tmp = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id >> 18); + tmp |= FIELD_PREP(MCP251XFD_REG_FLTOBJ_EID_MASK, filter->id); + tmp |= MCP251XFD_REG_FLTOBJ_EXIDE; } else { - *reg = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id); + tmp = FIELD_PREP(MCP251XFD_REG_FLTOBJ_SID_MASK, filter->id); } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_FLTOBJ(filter_idx), MCP251XFD_REG_SIZE); if (ret < 0) { LOG_ERR("Failed to write FLTOBJ register [%d]", ret); @@ -600,14 +600,14 @@ static int mcp251xfd_add_rx_filter(const struct device *dev, can_rx_callback_t r reg = mcp251xfd_get_spi_buf_ptr(dev); if ((filter->flags & CAN_FILTER_IDE) != 0) { - *reg = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask >> 18); - *reg |= FIELD_PREP(MCP251XFD_REG_MASK_MEID_MASK, filter->mask); + tmp = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask >> 18); + tmp |= FIELD_PREP(MCP251XFD_REG_MASK_MEID_MASK, filter->mask); } else { - *reg = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask); + tmp = FIELD_PREP(MCP251XFD_REG_MASK_MSID_MASK, filter->mask); } - *reg |= MCP251XFD_REG_MASK_MIDE; + tmp |= MCP251XFD_REG_MASK_MIDE; - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_FLTMASK(filter_idx), MCP251XFD_REG_SIZE); if (ret < 0) { @@ -678,8 +678,8 @@ static void mcp251xfd_set_state_change_callback(const struct device *dev, { struct mcp251xfd_data *dev_data = dev->data; - dev_data->state_change_cb = cb; - dev_data->state_change_cb_data = user_data; + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; } static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, @@ -687,6 +687,7 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, { struct mcp251xfd_data *dev_data = dev->data; uint32_t *reg; + uint32_t tmp; int ret = 0; k_mutex_lock(&dev_data->mutex, K_FOREVER); @@ -697,31 +698,31 @@ static int mcp251xfd_get_state(const struct device *dev, enum can_state *state, goto done; } - *reg = sys_le32_to_cpu(*reg); + tmp = sys_le32_to_cpu(*reg); if (err_cnt != NULL) { - err_cnt->tx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, *reg); - err_cnt->rx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, *reg); + err_cnt->tx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_TEC_MASK, tmp); + err_cnt->rx_err_cnt = FIELD_GET(MCP251XFD_REG_TREC_REC_MASK, tmp); } if (state == NULL) { goto done; } - if (!dev_data->started) { + if (!dev_data->common.started) { *state = CAN_STATE_STOPPED; goto done; } - if ((*reg & MCP251XFD_REG_TREC_TXBO) != 0) { + if ((tmp & MCP251XFD_REG_TREC_TXBO) != 0) { *state = CAN_STATE_BUS_OFF; - } else if ((*reg & MCP251XFD_REG_TREC_TXBP) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_TXBP) != 0) { *state = CAN_STATE_ERROR_PASSIVE; - } else if ((*reg & MCP251XFD_REG_TREC_RXBP) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_RXBP) != 0) { *state = CAN_STATE_ERROR_PASSIVE; - } else if ((*reg & MCP251XFD_REG_TREC_TXWARN) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_TXWARN) != 0) { *state = CAN_STATE_ERROR_WARNING; - } else if ((*reg & MCP251XFD_REG_TREC_RXWARN) != 0) { + } else if ((tmp & MCP251XFD_REG_TREC_RXWARN) != 0) { *state = CAN_STATE_ERROR_WARNING; } else { *state = CAN_STATE_ERROR_ACTIVE; @@ -747,15 +748,6 @@ static int mcp251xfd_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcp251xfd_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcp251xfd_config *dev_cfg = dev->config; - - *max_bitrate = dev_cfg->max_bitrate; - - return 0; -} - #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY static int mcp251xfd_recover(const struct device *dev, k_timeout_t timeout) { @@ -763,7 +755,7 @@ static int mcp251xfd_recover(const struct device *dev, k_timeout_t timeout) ARG_UNUSED(timeout); - if (!dev_data->started) { + if (!dev_data->common.started) { return -ENETDOWN; } @@ -919,7 +911,7 @@ static int mcp251xfd_handle_cerrif(const struct device *dev) enum can_state new_state; struct mcp251xfd_data *dev_data = dev->data; struct can_bus_err_cnt err_cnt; - int ret = 0; + int ret; k_mutex_lock(&dev_data->mutex, K_FOREVER); @@ -941,8 +933,9 @@ static int mcp251xfd_handle_cerrif(const struct device *dev) mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); } - if (dev_data->state_change_cb) { - dev_data->state_change_cb(dev, new_state, err_cnt, dev_data->state_change_cb_data); + if (dev_data->common.state_change_cb) { + dev_data->common.state_change_cb(dev, new_state, err_cnt, + dev_data->common.state_change_cb_user_data); } done: @@ -973,7 +966,7 @@ static int mcp251xfd_handle_modif(const struct device *dev) } /* try to transition back into our target mode */ - if (dev_data->started) { + if (dev_data->common.started) { LOG_INF("Switching back into mode %d", dev_data->next_mcp251xfd_mode); ret = mcp251xfd_set_mode_internal(dev, dev_data->next_mcp251xfd_mode); } @@ -1037,7 +1030,7 @@ static void mcp251xfd_handle_interrupts(const struct device *dev) reg_int = *reg_int_hw; /* these interrupt flags need to be explicitly cleared */ - if (*reg_int_hw & MCP251XFD_REG_INT_IF_CLEARABLE_MASK) { + if (reg_int & MCP251XFD_REG_INT_IF_CLEARABLE_MASK) { *reg_int_hw &= ~MCP251XFD_REG_INT_IF_CLEARABLE_MASK; @@ -1169,15 +1162,15 @@ static int mcp251xfd_start(const struct device *dev) const struct mcp251xfd_config *dev_cfg = dev->config; int ret; - if (dev_data->started) { + if (dev_data->common.started) { return -EALREADY; } /* in case of a race between mcp251xfd_send() and mcp251xfd_stop() */ mcp251xfd_reset_tx_fifos(dev, -ENETDOWN); - if (dev_cfg->phy != NULL) { - ret = can_transceiver_enable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); if (ret < 0) { LOG_ERR("Failed to enable CAN transceiver [%d]", ret); return ret; @@ -1189,12 +1182,12 @@ static int mcp251xfd_start(const struct device *dev) ret = mcp251xfd_set_mode_internal(dev, dev_data->next_mcp251xfd_mode); if (ret < 0) { LOG_ERR("Failed to set the mode [%d]", ret); - if (dev_cfg->phy != NULL) { + if (dev_cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(dev_cfg->phy); + (void)can_transceiver_disable(dev_cfg->common.phy); } } else { - dev_data->started = true; + dev_data->common.started = true; } k_mutex_unlock(&dev_data->mutex); @@ -1209,7 +1202,7 @@ static int mcp251xfd_stop(const struct device *dev) uint8_t *reg_byte; int ret; - if (!dev_data->started) { + if (!dev_data->common.started) { return -EALREADY; } @@ -1243,11 +1236,11 @@ static int mcp251xfd_stop(const struct device *dev) return ret; } - dev_data->started = false; + dev_data->common.started = false; k_mutex_unlock(&dev_data->mutex); - if (dev_cfg->phy != NULL) { - ret = can_transceiver_disable(dev_cfg->phy); + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); if (ret < 0) { LOG_ERR("Failed to disable CAN transceiver [%d]", ret); return ret; @@ -1266,6 +1259,12 @@ static void mcp251xfd_rx_fifo_handler(const struct device *dev, void *data) mcp251xfd_rxobj_to_canframe(rxobj, &dst); +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((dst.flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + filhit = FIELD_GET(MCP251XFD_OBJ_FILHIT_MASK, rxobj->flags); if ((dev_data->filter_usage & BIT(filhit)) != 0) { LOG_DBG("Received msg CAN id: 0x%x", dst.id); @@ -1297,21 +1296,48 @@ static void mcp251xfd_tef_fifo_handler(const struct device *dev, void *data) k_sem_give(&dev_data->tx_sem); } +#if defined(CONFIG_CAN_FD_MODE) +static int mcp251xfd_init_timing_struct_data(struct can_timing *timing, + const struct device *dev, + const struct mcp251xfd_timing_params *timing_params) +{ + const struct mcp251xfd_config *dev_cfg = dev->config; + int ret; + + if (USE_SP_ALGO && dev_cfg->common.sample_point_data > 0) { + ret = can_calc_timing_data(dev, timing, dev_cfg->common.bus_speed_data, + dev_cfg->common.sample_point_data); + if (ret < 0) { + return ret; + } + LOG_DBG("Data phase Presc: %d, BS1: %d, BS2: %d", timing->prescaler, + timing->phase_seg1, timing->phase_seg2); + LOG_DBG("Data phase Sample-point err : %d", ret); + } else { + timing->sjw = timing_params->sjw; + timing->prop_seg = timing_params->prop_seg; + timing->phase_seg1 = timing_params->phase_seg1; + timing->phase_seg2 = timing_params->phase_seg2; + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed_data); + if (ret > 0) { + LOG_WRN("Data phase Bitrate error: %d", ret); + } + } + + return ret; +} +#endif + static int mcp251xfd_init_timing_struct(struct can_timing *timing, const struct device *dev, - const struct mcp251xfd_timing_params *timing_params, - bool is_nominal) + const struct mcp251xfd_timing_params *timing_params) { + const struct mcp251xfd_config *dev_cfg = dev->config; int ret; - if (USE_SP_ALGO && timing_params->sample_point > 0) { - if (is_nominal) { - ret = can_calc_timing(dev, timing, timing_params->bus_speed, - timing_params->sample_point); - } else { - ret = can_calc_timing_data(dev, timing, timing_params->bus_speed, - timing_params->sample_point); - } + if (USE_SP_ALGO && dev_cfg->common.sample_point > 0) { + ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); if (ret < 0) { return ret; } @@ -1323,7 +1349,7 @@ static int mcp251xfd_init_timing_struct(struct can_timing *timing, timing->prop_seg = timing_params->prop_seg; timing->phase_seg1 = timing_params->phase_seg1; timing->phase_seg2 = timing_params->phase_seg2; - ret = can_calc_prescaler(dev, timing, timing_params->bus_speed); + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed); if (ret > 0) { LOG_WRN("Bitrate error: %d", ret); } @@ -1335,12 +1361,14 @@ static int mcp251xfd_init_timing_struct(struct can_timing *timing, static inline int mcp251xfd_init_con_reg(const struct device *dev) { uint32_t *reg; + uint32_t tmp; reg = mcp251xfd_get_spi_buf_ptr(dev); - *reg = MCP251XFD_REG_CON_ISOCRCEN | MCP251XFD_REG_CON_WAKFIL | MCP251XFD_REG_CON_TXQEN | - MCP251XFD_REG_CON_STEF; - *reg |= FIELD_PREP(MCP251XFD_REG_CON_WFT_MASK, MCP251XFD_REG_CON_WFT_T11FILTER) | + tmp = MCP251XFD_REG_CON_ISOCRCEN | MCP251XFD_REG_CON_WAKFIL | MCP251XFD_REG_CON_TXQEN | + MCP251XFD_REG_CON_STEF; + tmp |= FIELD_PREP(MCP251XFD_REG_CON_WFT_MASK, MCP251XFD_REG_CON_WFT_T11FILTER) | FIELD_PREP(MCP251XFD_REG_CON_REQOP_MASK, MCP251XFD_REG_CON_MODE_CONFIG); + *reg = tmp; return mcp251xfd_write(dev, MCP251XFD_REG_CON, MCP251XFD_REG_SIZE); } @@ -1351,14 +1379,15 @@ static inline int mcp251xfd_init_osc_reg(const struct device *dev) const struct mcp251xfd_config *dev_cfg = dev->config; uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); uint32_t reg_value = MCP251XFD_REG_OSC_OSCRDY; + uint32_t tmp; - *reg = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, dev_cfg->clko_div); + tmp = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK, dev_cfg->clko_div); if (dev_cfg->pll_enable) { - *reg |= MCP251XFD_REG_OSC_PLLEN; + tmp |= MCP251XFD_REG_OSC_PLLEN; reg_value |= MCP251XFD_REG_OSC_PLLRDY; } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); ret = mcp251xfd_write(dev, MCP251XFD_REG_OSC, MCP251XFD_REG_SIZE); if (ret < 0) { @@ -1374,6 +1403,7 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) { const struct mcp251xfd_config *dev_cfg = dev->config; uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; /* * MCP2518FD Errata: DS80000789 @@ -1383,14 +1413,14 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) * to do single byte writes instead. */ - *reg = MCP251XFD_REG_IOCON_TRIS0 | MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_PM0 | - MCP251XFD_REG_IOCON_PM1; + tmp = MCP251XFD_REG_IOCON_TRIS0 | MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_PM0 | + MCP251XFD_REG_IOCON_PM1; if (dev_cfg->sof_on_clko) { - *reg |= MCP251XFD_REG_IOCON_SOF; + tmp |= MCP251XFD_REG_IOCON_SOF; } - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_IOCON, MCP251XFD_REG_SIZE); } @@ -1398,11 +1428,12 @@ static inline int mcp251xfd_init_iocon_reg(const struct device *dev) static inline int mcp251xfd_init_int_reg(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_INT_RXIE | MCP251XFD_REG_INT_MODIE | MCP251XFD_REG_INT_TEFIE | - MCP251XFD_REG_INT_CERRIE; + tmp = MCP251XFD_REG_INT_RXIE | MCP251XFD_REG_INT_MODIE | MCP251XFD_REG_INT_TEFIE | + MCP251XFD_REG_INT_CERRIE; - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_INT, MCP251XFD_REG_SIZE); } @@ -1410,11 +1441,12 @@ static inline int mcp251xfd_init_int_reg(const struct device *dev) static inline int mcp251xfd_init_tef_fifo(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_TEFCON_TEFNEIE | MCP251XFD_REG_TEFCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); + tmp = MCP251XFD_REG_TEFCON_TEFNEIE | MCP251XFD_REG_TEFCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_TEFCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TEFCON, MCP251XFD_REG_SIZE); } @@ -1422,14 +1454,15 @@ static inline int mcp251xfd_init_tef_fifo(const struct device *dev) static inline int mcp251xfd_init_tx_queue(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_TXQCON_TXEN | MCP251XFD_REG_TXQCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_TXAT_MASK, MCP251XFD_REG_TXQCON_TXAT_UNLIMITED); - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_TXQCON_PLSIZE_MASK, - can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); + tmp = MCP251XFD_REG_TXQCON_TXEN | MCP251XFD_REG_TXQCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_TXAT_MASK, MCP251XFD_REG_TXQCON_TXAT_UNLIMITED); + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_FSIZE_MASK, MCP251XFD_TX_QUEUE_ITEMS - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_TXQCON_PLSIZE_MASK, + can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TXQCON, MCP251XFD_REG_SIZE); } @@ -1437,16 +1470,17 @@ static inline int mcp251xfd_init_tx_queue(const struct device *dev) static inline int mcp251xfd_init_rx_fifo(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); + uint32_t tmp; - *reg = MCP251XFD_REG_FIFOCON_TFNRFNIE | MCP251XFD_REG_FIFOCON_FRESET; - *reg |= FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, MCP251XFD_RX_FIFO_ITEMS - 1); - *reg |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, - can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); + tmp = MCP251XFD_REG_FIFOCON_TFNRFNIE | MCP251XFD_REG_FIFOCON_FRESET; + tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_FSIZE_MASK, MCP251XFD_RX_FIFO_ITEMS - 1); + tmp |= FIELD_PREP(MCP251XFD_REG_FIFOCON_PLSIZE_MASK, + can_bytes_to_dlc(MCP251XFD_PAYLOAD_SIZE) - 8); #if defined(CONFIG_CAN_RX_TIMESTAMP) - *reg |= MCP251XFD_REG_FIFOCON_RXTSEN; + tmp |= MCP251XFD_REG_FIFOCON_RXTSEN; #endif - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO_IDX), MCP251XFD_REG_SIZE); @@ -1457,12 +1491,13 @@ static int mcp251xfd_init_tscon(const struct device *dev) { uint32_t *reg = mcp251xfd_get_spi_buf_ptr(dev); const struct mcp251xfd_config *dev_cfg = dev->config; + uint32_t tmp; - *reg = MCP251XFD_REG_TSCON_TBCEN; - *reg |= FIELD_PREP(MCP251XFD_REG_TSCON_TBCPRE_MASK, - dev_cfg->timestamp_prescaler - 1); + tmp = MCP251XFD_REG_TSCON_TBCEN; + tmp |= FIELD_PREP(MCP251XFD_REG_TSCON_TBCPRE_MASK, + dev_cfg->timestamp_prescaler - 1); - *reg = sys_cpu_to_le32(*reg); + *reg = sys_cpu_to_le32(tmp); return mcp251xfd_write(dev, MCP251XFD_REG_TSCON, MCP251XFD_REG_SIZE); } @@ -1558,16 +1593,16 @@ static int mcp251xfd_init(const struct device *dev) goto done; } - ret = mcp251xfd_init_timing_struct(&timing, dev, &dev_cfg->timing_params, true); + ret = mcp251xfd_init_timing_struct(&timing, dev, &dev_cfg->timing_params); if (ret < 0) { LOG_ERR("Can't find timing for given param"); goto done; } #if defined(CONFIG_CAN_FD_MODE) - ret = mcp251xfd_init_timing_struct(&timing_data, dev, &dev_cfg->timing_params_data, false); + ret = mcp251xfd_init_timing_struct_data(&timing_data, dev, &dev_cfg->timing_params_data); if (ret < 0) { - LOG_ERR("Can't find timing for given param"); + LOG_ERR("Can't find data timing for given param"); goto done; } #endif @@ -1678,7 +1713,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .set_state_change_callback = mcp251xfd_set_state_change_callback, .get_core_clock = mcp251xfd_get_core_clock, .get_max_filters = mcp251xfd_get_max_filters, - .get_max_bitrate = mcp251xfd_get_max_bitrate, .timing_min = { .sjw = 1, .prop_seg = 0, @@ -1717,8 +1751,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .prop_seg = DT_INST_PROP_OR(inst, prop_seg##type, 0), \ .phase_seg1 = DT_INST_PROP_OR(inst, phase_seg1##type, 0), \ .phase_seg2 = DT_INST_PROP_OR(inst, phase_seg2##type, 0), \ - .bus_speed = DT_INST_PROP(inst, bus_speed##type), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point##type, 0), \ } #if defined(CONFIG_CAN_FD_MODE) @@ -1744,6 +1776,7 @@ static const struct can_driver_api mcp251xfd_api_funcs = { .int_thread_stack = mcp251xfd_int_stack_##inst, \ }; \ static const struct mcp251xfd_config mcp251xfd_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 8000000), \ .bus = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .int_gpio_dt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ \ @@ -1754,8 +1787,6 @@ static const struct can_driver_api mcp251xfd_api_funcs = { \ .osc_freq = DT_INST_PROP(inst, osc_freq), \ MCP251XFD_SET_TIMING(inst), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 8000000), \ .rx_fifo = {.ram_start_addr = MCP251XFD_RX_FIFO_START_ADDR, \ .reg_fifocon_addr = MCP251XFD_REG_FIFOCON(MCP251XFD_RX_FIFO_IDX), \ .capacity = MCP251XFD_RX_FIFO_ITEMS, \ @@ -1769,7 +1800,7 @@ static const struct can_driver_api mcp251xfd_api_funcs = { MCP251XFD_SET_CLOCK(inst) \ }; \ \ - CAN_DEVICE_DT_INST_DEFINE(inst, &mcp251xfd_init, NULL, &mcp251xfd_data_##inst, \ + CAN_DEVICE_DT_INST_DEFINE(inst, mcp251xfd_init, NULL, &mcp251xfd_data_##inst, \ &mcp251xfd_config_##inst, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ &mcp251xfd_api_funcs); diff --git a/drivers/can/can_mcp251xfd.h b/drivers/can/can_mcp251xfd.h index b87c6ae53dd..475f91583c2 100644 --- a/drivers/can/can_mcp251xfd.h +++ b/drivers/can/can_mcp251xfd.h @@ -478,6 +478,8 @@ struct mcp251xfd_fifo { }; struct mcp251xfd_data { + struct can_driver_data common; + /* Interrupt Data */ struct gpio_callback int_gpio_cb; struct k_thread int_thread; @@ -486,8 +488,6 @@ struct mcp251xfd_data { /* General */ enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct k_mutex mutex; /* TX Callback */ @@ -503,13 +503,10 @@ struct mcp251xfd_data { const struct device *dev; - bool started; uint8_t next_mcp251xfd_mode; uint8_t current_mcp251xfd_mode; int tdco; - can_mode_t mode; - struct mcp251xfd_spi_data spi_data; }; @@ -519,11 +516,11 @@ struct mcp251xfd_timing_params { uint8_t prop_seg; uint8_t phase_seg1; uint8_t phase_seg2; - uint32_t bus_speed; - uint16_t sample_point; }; struct mcp251xfd_config { + const struct can_driver_config common; + /* spi configuration */ struct spi_dt_spec bus; struct gpio_dt_spec int_gpio_dt; @@ -543,10 +540,6 @@ struct mcp251xfd_config { struct mcp251xfd_timing_params timing_params_data; #endif - /* CAN transceiver */ - const struct device *phy; - uint32_t max_bitrate; - const struct device *clk_dev; uint8_t clk_id; diff --git a/drivers/can/can_mcux_flexcan.c b/drivers/can/can_mcux_flexcan.c index 4138678911c..cf09ef23ec7 100644 --- a/drivers/can/can_mcux_flexcan.c +++ b/drivers/can/can_mcux_flexcan.c @@ -85,20 +85,17 @@ LOG_MODULE_REGISTER(can_mcux_flexcan, CONFIG_CAN_LOG_LEVEL); >> CAN_ID_EXT_SHIFT)) struct mcux_flexcan_config { + const struct can_driver_config common; CAN_Type *base; const struct device *clock_dev; clock_control_subsys_t clock_subsys; int clk_source; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t prop_seg; uint32_t phase_seg1; uint32_t phase_seg2; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD bool flexcan_fd; - uint32_t bitrate_data; - uint32_t sample_point_data; uint32_t sjw_data; uint32_t prop_seg_data; uint32_t phase_seg1_data; @@ -107,8 +104,6 @@ struct mcux_flexcan_config { void (*irq_config_func)(const struct device *dev); void (*irq_enable_func)(void); void (*irq_disable_func)(void); - const struct device *phy; - uint32_t max_bitrate; const struct pinctrl_dev_config *pincfg; }; @@ -120,9 +115,6 @@ struct mcux_flexcan_rx_callback { flexcan_fd_frame_t fd; #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ } frame; -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - bool fdf; -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ can_rx_callback_t function; void *arg; }; @@ -133,6 +125,7 @@ struct mcux_flexcan_tx_callback { }; struct mcux_flexcan_data { + struct can_driver_data common; const struct device *dev; flexcan_handle_t handle; @@ -145,14 +138,10 @@ struct mcux_flexcan_data { struct k_mutex tx_mutex; struct mcux_flexcan_tx_callback tx_cbs[MCUX_FLEXCAN_MAX_TX]; enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct can_timing timing; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD struct can_timing timing_data; - bool fd_mode; #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - bool started; }; static int mcux_flexcan_get_core_clock(const struct device *dev, uint32_t *rate) @@ -169,15 +158,6 @@ static int mcux_flexcan_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -static int mcux_flexcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct mcux_flexcan_config *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; -} - static int mcux_flexcan_set_timing(const struct device *dev, const struct can_timing *timing) { @@ -187,7 +167,7 @@ static int mcux_flexcan_set_timing(const struct device *dev, return -EINVAL; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -206,7 +186,7 @@ static int mcux_flexcan_set_timing_data(const struct device *dev, return -EINVAL; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -241,7 +221,7 @@ static status_t mcux_flexcan_mb_start(const struct device *dev, int alloc) xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { xfer.framefd = &data->rx_cbs[alloc].frame.fd; FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), &data->rx_cbs[alloc].mb_config, true); @@ -267,7 +247,7 @@ static void mcux_flexcan_mb_stop(const struct device *dev, int alloc) __ASSERT_NO_MSG(alloc >= 0 && alloc < ARRAY_SIZE(data->rx_cbs)); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortReceive(config->base, &data->handle, ALLOC_IDX_TO_RXMB_IDX(alloc)); FLEXCAN_SetFDRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), @@ -290,12 +270,12 @@ static int mcux_flexcan_start(const struct device *dev) flexcan_timing_config_t timing; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -349,7 +329,7 @@ static int mcux_flexcan_start(const struct device *dev) } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - data->started = true; + data->common.started = true; return 0; } @@ -363,11 +343,11 @@ static int mcux_flexcan_stop(const struct device *dev) int alloc; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; /* Abort any pending TX frames before entering freeze mode */ for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) { @@ -376,7 +356,7 @@ static int mcux_flexcan_stop(const struct device *dev) if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortSend(config->base, &data->handle, ALLOC_IDX_TO_TXMB_IDX(alloc)); } else { @@ -410,8 +390,8 @@ static int mcux_flexcan_stop(const struct device *dev) k_mutex_unlock(&data->rx_mutex); } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -429,7 +409,7 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) uint32_t ctrl1; uint32_t mcr; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -481,7 +461,6 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) if ((mode & CAN_MODE_FD) != 0) { /* Enable CAN FD mode */ mcr |= CAN_MCR_FDEN_MASK; - data->fd_mode = true; /* Transceiver Delay Compensation must be disabled in loopback mode */ if ((mode & CAN_MODE_LOOPBACK) != 0) { @@ -492,7 +471,6 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) } else { /* Disable CAN FD mode */ mcr &= ~(CAN_MCR_FDEN_MASK); - data->fd_mode = false; } } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -500,6 +478,8 @@ static int mcux_flexcan_set_mode(const struct device *dev, can_mode_t mode) config->base->CTRL1 = ctrl1; config->base->MCR = mcr; + data->common.mode = mode; + return 0; } @@ -636,8 +616,7 @@ static void mcux_flexcan_can_filter_to_mbconfig(const struct can_filter *src, uint32_t *mask) { static const uint32_t ide_mask = 1U; - uint32_t rtr_mask = (src->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + static const uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); if ((src->flags & CAN_FILTER_IDE) != 0) { dest->format = kFLEXCAN_FrameFormatExtend; @@ -649,11 +628,7 @@ static void mcux_flexcan_can_filter_to_mbconfig(const struct can_filter *src, *mask = FLEXCAN_RX_MB_STD_MASK(src->mask, rtr_mask, ide_mask); } - if ((src->flags & CAN_FILTER_RTR) != 0) { - dest->type = kFLEXCAN_FrameTypeRemote; - } else { - dest->type = kFLEXCAN_FrameTypeData; - } + dest->type = kFLEXCAN_FrameTypeData; } static int mcux_flexcan_get_state(const struct device *dev, enum can_state *state, @@ -664,7 +639,7 @@ static int mcux_flexcan_get_state(const struct device *dev, enum can_state *stat uint64_t status_flags; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { status_flags = FLEXCAN_GetStatusFlags(config->base); @@ -705,7 +680,8 @@ static int mcux_flexcan_send(const struct device *dev, __ASSERT_NO_MSG(callback != NULL); - if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), data->fd_mode)) { + if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), + ((data->common.mode & CAN_MODE_FD) != 0U))) { if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); @@ -727,7 +703,7 @@ static int mcux_flexcan_send(const struct device *dev, return -EINVAL; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -752,7 +728,7 @@ static int mcux_flexcan_send(const struct device *dev, xfer.mbIdx = ALLOC_IDX_TO_TXMB_IDX(alloc); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_SetFDTxMbConfig(config->base, xfer.mbIdx, true); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -765,7 +741,7 @@ static int mcux_flexcan_send(const struct device *dev, config->irq_disable_func(); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { flexcan_fd_frame_t flexcan_frame; mcux_flexcan_fd_from_can_frame(frame, &flexcan_frame); @@ -796,7 +772,6 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, void *user_data, const struct can_filter *filter) { - uint8_t supported = CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR; const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; status_t status; @@ -806,11 +781,7 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, __ASSERT_NO_MSG(callback); - if (UTIL_AND(IS_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD), config->flexcan_fd)) { - supported |= CAN_FILTER_FDF; - } - - if ((filter->flags & ~(supported)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -835,22 +806,17 @@ static int mcux_flexcan_add_rx_filter(const struct device *dev, data->rx_cbs[alloc].arg = user_data; data->rx_cbs[alloc].function = callback; -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - /* FDF filtering not supported in hardware, must be handled in driver */ - data->rx_cbs[alloc].fdf = (filter->flags & CAN_FILTER_FDF) != 0; -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - /* The indidual RX mask registers can only be written in freeze mode */ FLEXCAN_EnterFreezeMode(config->base); config->base->RXIMR[ALLOC_IDX_TO_RXMB_IDX(alloc)] = mask; - if (data->started) { + if (data->common.started) { FLEXCAN_ExitFreezeMode(config->base); } #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD /* Defer starting FlexCAN FD MBs unless started */ - if (!config->flexcan_fd || data->started) { + if (!config->flexcan_fd || data->common.started) { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ status = mcux_flexcan_mb_start(dev, alloc); if (status != kStatus_Success) { @@ -874,8 +840,8 @@ static void mcux_flexcan_set_state_change_callback(const struct device *dev, { struct mcux_flexcan_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY @@ -887,7 +853,7 @@ static int mcux_flexcan_recover(const struct device *dev, k_timeout_t timeout) uint64_t start_time; int ret = 0; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -934,7 +900,7 @@ static void mcux_flexcan_remove_rx_filter(const struct device *dev, int filter_i const struct mcux_flexcan_config *config = dev->config; /* Stop FlexCAN FD MBs unless already in stopped mode */ - if (!config->flexcan_fd || data->started) { + if (!config->flexcan_fd || data->common.started) { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ mcux_flexcan_mb_stop(dev, filter_id); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD @@ -955,8 +921,8 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev, { const struct mcux_flexcan_config *config = dev->config; struct mcux_flexcan_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; can_tx_callback_t function; void *arg; int alloc; @@ -1005,7 +971,7 @@ static inline void mcux_flexcan_transfer_error_status(const struct device *dev, if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortSend(config->base, &data->handle, ALLOC_IDX_TO_TXMB_IDX(alloc)); } else { @@ -1061,25 +1027,20 @@ static inline void mcux_flexcan_transfer_rx_idle(const struct device *dev, if (atomic_test_bit(data->rx_allocs, alloc)) { #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { mcux_flexcan_fd_to_can_frame(&data->rx_cbs[alloc].frame.fd, &frame); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ mcux_flexcan_to_can_frame(&data->rx_cbs[alloc].frame.classic, &frame); -#ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - } - - if (!!(frame.flags & CAN_FRAME_FDF) == data->rx_cbs[alloc].fdf) { -#endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ - function(dev, &frame, arg); #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD } #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ + function(dev, &frame, arg); /* Setup RX message buffer to receive next message */ xfer.mbIdx = mb; #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { xfer.framefd = &data->rx_cbs[alloc].frame.fd; status = FLEXCAN_TransferFDReceiveNonBlocking(config->base, &data->handle, @@ -1125,7 +1086,7 @@ static FLEXCAN_CALLBACK(mcux_flexcan_transfer_callback) break; case kStatus_FLEXCAN_TxSwitchToRx: #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD - if (data->fd_mode) { + if ((data->common.mode & CAN_MODE_FD) != 0U) { FLEXCAN_TransferFDAbortReceive(config->base, &data->handle, mb); } else { #endif /* CONFIG_CAN_MCUX_FLEXCAN_FD */ @@ -1168,8 +1129,8 @@ static int mcux_flexcan_init(const struct device *dev) uint32_t clock_freq; int err; - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1186,9 +1147,9 @@ static int mcux_flexcan_init(const struct device *dev) MCUX_FLEXCAN_MAX_TX); data->timing.sjw = config->sjw; - if (config->sample_point && USE_SP_ALGO) { - err = can_calc_timing(dev, &data->timing, config->bitrate, - config->sample_point); + if (config->common.sample_point && USE_SP_ALGO) { + err = can_calc_timing(dev, &data->timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1202,7 +1163,7 @@ static int mcux_flexcan_init(const struct device *dev) data->timing.prop_seg = config->prop_seg; data->timing.phase_seg1 = config->phase_seg1; data->timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &data->timing, config->bitrate); + err = can_calc_prescaler(dev, &data->timing, config->common.bus_speed); if (err) { LOG_WRN("Bitrate error: %d", err); } @@ -1218,9 +1179,10 @@ static int mcux_flexcan_init(const struct device *dev) #ifdef CONFIG_CAN_MCUX_FLEXCAN_FD if (config->flexcan_fd) { data->timing_data.sjw = config->sjw_data; - if (config->sample_point_data && USE_SP_ALGO) { - err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data, - config->sample_point_data); + if (config->common.sample_point_data && USE_SP_ALGO) { + err = can_calc_timing_data(dev, &data->timing_data, + config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1234,7 +1196,8 @@ static int mcux_flexcan_init(const struct device *dev) data->timing_data.prop_seg = config->prop_seg_data; data->timing_data.phase_seg1 = config->phase_seg1_data; data->timing_data.phase_seg2 = config->phase_seg2_data; - err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data); + err = can_calc_prescaler(dev, &data->timing_data, + config->common.bus_speed_data); if (err) { LOG_WRN("Bitrate error: %d", err); } @@ -1338,7 +1301,6 @@ __maybe_unused static const struct can_driver_api mcux_flexcan_driver_api = { .set_state_change_callback = mcux_flexcan_set_state_change_callback, .get_core_clock = mcux_flexcan_get_core_clock, .get_max_filters = mcux_flexcan_get_max_filters, - .get_max_bitrate = mcux_flexcan_get_max_bitrate, /* * FlexCAN timing limits are specified in the "FLEXCANx_CTRL1 field * descriptions" table in the SoC reference manual. @@ -1382,7 +1344,6 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { .set_state_change_callback = mcux_flexcan_set_state_change_callback, .get_core_clock = mcux_flexcan_get_core_clock, .get_max_filters = mcux_flexcan_get_max_filters, - .get_max_bitrate = mcux_flexcan_get_max_bitrate, /* * FlexCAN FD timing limits are specified in the "CAN Bit Timing * Register (CBT)" and "CAN FD Bit Timing Register" field description @@ -1469,32 +1430,26 @@ static const struct can_driver_api mcux_flexcan_fd_driver_api = { static void mcux_flexcan_irq_disable_##id(void); \ \ static const struct mcux_flexcan_config mcux_flexcan_config_##id = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(id, FLEXCAN_MAX_BITRATE(id)), \ .base = (CAN_Type *)DT_INST_REG_ADDR(id), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(id)), \ .clock_subsys = (clock_control_subsys_t) \ DT_INST_CLOCKS_CELL(id, name), \ .clk_source = DT_INST_PROP(id, clk_source), \ - .bitrate = DT_INST_PROP(id, bus_speed), \ .sjw = DT_INST_PROP(id, sjw), \ .prop_seg = DT_INST_PROP_OR(id, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(id, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(id, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(id, sample_point, 0), \ IF_ENABLED(CONFIG_CAN_MCUX_FLEXCAN_FD, ( \ .flexcan_fd = DT_NODE_HAS_COMPAT(DT_DRV_INST(id), FLEXCAN_FD_DRV_COMPAT), \ - .bitrate_data = DT_INST_PROP_OR(id, bus_speed_data, 0), \ .sjw_data = DT_INST_PROP_OR(id, sjw_data, 0), \ .prop_seg_data = DT_INST_PROP_OR(id, prop_seg_data, 0), \ .phase_seg1_data = DT_INST_PROP_OR(id, phase_seg1_data, 0), \ .phase_seg2_data = DT_INST_PROP_OR(id, phase_seg2_data, 0), \ - .sample_point_data = DT_INST_PROP_OR(id, sample_point_data, 0), \ )) \ .irq_config_func = mcux_flexcan_irq_config_##id, \ .irq_enable_func = mcux_flexcan_irq_enable_##id, \ .irq_disable_func = mcux_flexcan_irq_disable_##id, \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(id, phys)),\ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(id, \ - FLEXCAN_MAX_BITRATE(id)), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ }; \ \ diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index eb382c95292..28a709a023c 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -139,7 +139,6 @@ static const struct can_driver_api mcux_mcan_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = mcux_mcan_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, /* * MCUX MCAN timing limits are specified in the "Nominal bit timing and * prescaler register (NBTP)" table in the SoC reference manual. @@ -217,17 +216,17 @@ static const struct can_mcan_ops mcux_mcan_ops = { \ static void mcux_mcan_irq_config_##n(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \ - DT_INST_IRQ_BY_IDX(n, 0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int0, irq), \ + DT_INST_IRQ_BY_NAME(n, int0, priority), \ can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int0, irq)); \ \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq), \ - DT_INST_IRQ_BY_IDX(n, 1, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int1, irq), \ + DT_INST_IRQ_BY_NAME(n, int1, priority), \ can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int1, irq)); \ } DT_INST_FOREACH_STATUS_OKAY(MCUX_MCAN_INIT) diff --git a/drivers/can/can_native_linux.c b/drivers/can/can_native_linux.c new file mode 100644 index 00000000000..940123bdd92 --- /dev/null +++ b/drivers/can/can_native_linux.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2022 Martin Jäger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_native_linux_can + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "can_native_linux_adapt.h" +#include "nsi_host_trampolines.h" + +LOG_MODULE_REGISTER(can_native_linux, CONFIG_CAN_LOG_LEVEL); + +struct can_filter_context { + can_rx_callback_t rx_cb; + void *cb_arg; + struct can_filter filter; +}; + +struct can_native_linux_data { + struct can_driver_data common; + struct can_filter_context filters[CONFIG_CAN_MAX_FILTER]; + struct k_mutex filter_mutex; + struct k_sem tx_idle; + can_tx_callback_t tx_callback; + void *tx_user_data; + int dev_fd; /* Linux socket file descriptor */ + struct k_thread rx_thread; + + K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); +}; + +struct can_native_linux_config { + const struct can_driver_config common; + const char *if_name; +}; + +static void dispatch_frame(const struct device *dev, struct can_frame *frame) +{ + struct can_native_linux_data *data = dev->data; + can_rx_callback_t callback; + struct can_frame tmp_frame; + + k_mutex_lock(&data->filter_mutex, K_FOREVER); + + for (int filter_id = 0; filter_id < ARRAY_SIZE(data->filters); filter_id++) { + if (data->filters[filter_id].rx_cb == NULL) { + continue; + } + + if (!can_frame_matches_filter(frame, &data->filters[filter_id].filter)) { + continue; + } + + /* Make a temporary copy in case the user modifies the message */ + tmp_frame = *frame; + + callback = data->filters[filter_id].rx_cb; + callback(dev, &tmp_frame, data->filters[filter_id].cb_arg); + } + + k_mutex_unlock(&data->filter_mutex); +} + +static void rx_thread(void *arg1, void *arg2, void *arg3) +{ + const struct device *dev = arg1; + struct can_native_linux_data *data = dev->data; + struct socketcan_frame sframe; + struct can_frame frame; + bool msg_confirm; + int count; + + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + LOG_DBG("Starting Linux SocketCAN RX thread"); + + while (true) { + while (linux_socketcan_poll_data(data->dev_fd) == 0) { + count = linux_socketcan_read_data(data->dev_fd, (void *)(&sframe), + sizeof(sframe), &msg_confirm); + if (msg_confirm) { + data->tx_callback(dev, 0, data->tx_user_data); + k_sem_give(&data->tx_idle); + + if ((data->common.mode & CAN_MODE_LOOPBACK) == 0U) { + continue; + } + } + if ((count <= 0) || !data->common.started) { + break; + } + + socketcan_to_can_frame(&sframe, &frame); + +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR*/ + + LOG_DBG("Received %d bytes. Id: 0x%x, ID type: %s %s", + frame.dlc, frame.id, + (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", + (frame.flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : ""); + + dispatch_frame(dev, &frame); + } + + /* short sleep required to avoid blocking the whole native process */ + k_sleep(K_MSEC(1)); + } +} + +static int can_native_linux_send(const struct device *dev, const struct can_frame *frame, + k_timeout_t timeout, can_tx_callback_t callback, void *user_data) +{ + struct can_native_linux_data *data = dev->data; + struct socketcan_frame sframe; + uint8_t max_dlc = CAN_MAX_DLC; + size_t mtu = CAN_MTU; + int ret = -EIO; + + LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s", + frame->dlc, dev->name, frame->id, + (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", + (frame->flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : ""); + + __ASSERT_NO_MSG(callback != NULL); + +#ifdef CONFIG_CAN_FD_MODE + if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR | + CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { + LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); + return -ENOTSUP; + } + + if ((frame->flags & CAN_FRAME_FDF) != 0) { + if ((data->common.mode & CAN_MODE_FD) == 0U) { + return -ENOTSUP; + } + + max_dlc = CANFD_MAX_DLC; + mtu = CANFD_MTU; + } +#else /* CONFIG_CAN_FD_MODE */ + if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) { + LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); + return -ENOTSUP; + } +#endif /* !CONFIG_CAN_FD_MODE */ + + if (frame->dlc > max_dlc) { + LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, max_dlc); + return -EINVAL; + } + + if (data->dev_fd <= 0) { + LOG_ERR("No file descriptor: %d", data->dev_fd); + return -EIO; + } + + if (!data->common.started) { + return -ENETDOWN; + } + + socketcan_from_can_frame(frame, &sframe); + + if (k_sem_take(&data->tx_idle, timeout) != 0) { + return -EAGAIN; + } + + data->tx_callback = callback; + data->tx_user_data = user_data; + + ret = nsi_host_write(data->dev_fd, &sframe, mtu); + if (ret < 0) { + LOG_ERR("Cannot send CAN data len %d (%d)", sframe.len, -errno); + } + + return 0; +} + +static int can_native_linux_add_rx_filter(const struct device *dev, can_rx_callback_t cb, + void *cb_arg, const struct can_filter *filter) +{ + struct can_native_linux_data *data = dev->data; + struct can_filter_context *filter_ctx; + int filter_id = -ENOSPC; + + LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, + filter->mask); + + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { + LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); + return -ENOTSUP; + } + + k_mutex_lock(&data->filter_mutex, K_FOREVER); + + for (int i = 0; i < ARRAY_SIZE(data->filters); i++) { + if (data->filters[i].rx_cb == NULL) { + filter_id = i; + break; + } + } + + if (filter_id < 0) { + LOG_ERR("No free filter left"); + k_mutex_unlock(&data->filter_mutex); + return filter_id; + } + + filter_ctx = &data->filters[filter_id]; + filter_ctx->rx_cb = cb; + filter_ctx->cb_arg = cb_arg; + filter_ctx->filter = *filter; + + k_mutex_unlock(&data->filter_mutex); + + LOG_DBG("Filter added. ID: %d", filter_id); + + return filter_id; +} + +static void can_native_linux_remove_rx_filter(const struct device *dev, int filter_id) +{ + struct can_native_linux_data *data = dev->data; + + if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) { + LOG_ERR("filter ID %d out of bounds"); + return; + } + + k_mutex_lock(&data->filter_mutex, K_FOREVER); + data->filters[filter_id].rx_cb = NULL; + k_mutex_unlock(&data->filter_mutex); + + LOG_DBG("Filter removed. ID: %d", filter_id); +} + +static int can_native_linux_get_capabilities(const struct device *dev, can_mode_t *cap) +{ + ARG_UNUSED(dev); + + *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK; + +#if CONFIG_CAN_FD_MODE + *cap |= CAN_MODE_FD; +#endif /* CONFIG_CAN_FD_MODE */ + + return 0; +} + +static int can_native_linux_start(const struct device *dev) +{ + struct can_native_linux_data *data = dev->data; + + if (data->common.started) { + return -EALREADY; + } + + data->common.started = true; + + return 0; +} + +static int can_native_linux_stop(const struct device *dev) +{ + struct can_native_linux_data *data = dev->data; + + if (!data->common.started) { + return -EALREADY; + } + + data->common.started = false; + + return 0; +} + +static int can_native_linux_set_mode(const struct device *dev, can_mode_t mode) +{ + struct can_native_linux_data *data = dev->data; + int err; + +#ifdef CONFIG_CAN_FD_MODE + if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { + LOG_ERR("unsupported mode: 0x%08x", mode); + return -ENOTSUP; + } +#else + if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) { + LOG_ERR("unsupported mode: 0x%08x", mode); + return -ENOTSUP; + } +#endif /* CONFIG_CAN_FD_MODE */ + + if (data->common.started) { + return -EBUSY; + } + + err = linux_socketcan_set_mode_fd(data->dev_fd, (mode & CAN_MODE_FD) != 0); + if (err != 0) { + LOG_ERR("failed to set mode"); + return -EIO; + } + + data->common.mode = mode; + + return 0; +} + +static int can_native_linux_set_timing(const struct device *dev, const struct can_timing *timing) +{ + struct can_native_linux_data *data = dev->data; + + ARG_UNUSED(timing); + + if (data->common.started) { + return -EBUSY; + } + + return 0; +} + +#ifdef CONFIG_CAN_FD_MODE +static int can_native_linux_set_timing_data(const struct device *dev, + const struct can_timing *timing) +{ + struct can_native_linux_data *data = dev->data; + + ARG_UNUSED(timing); + + if (data->common.started) { + return -EBUSY; + } + + return 0; +} +#endif /* CONFIG_CAN_FD_MODE */ + +static int can_native_linux_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) +{ + struct can_native_linux_data *data = dev->data; + + if (state != NULL) { + if (!data->common.started) { + *state = CAN_STATE_STOPPED; + } else { + /* SocketCAN does not forward error frames by default */ + *state = CAN_STATE_ERROR_ACTIVE; + } + } + + if (err_cnt) { + err_cnt->tx_err_cnt = 0; + err_cnt->rx_err_cnt = 0; + } + + return 0; +} + +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY +static int can_native_linux_recover(const struct device *dev, k_timeout_t timeout) +{ + struct can_native_linux_data *data = dev->data; + + ARG_UNUSED(timeout); + + if (!data->common.started) { + return -ENETDOWN; + } + + return 0; +} +#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ + +static void can_native_linux_set_state_change_callback(const struct device *dev, + can_state_change_callback_t cb, + void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(cb); + ARG_UNUSED(user_data); +} + +static int can_native_linux_get_core_clock(const struct device *dev, uint32_t *rate) +{ + /* Return 16MHz as an realistic value for the testcases */ + *rate = 16000000; + + return 0; +} + +static int can_native_linux_get_max_filters(const struct device *dev, bool ide) +{ + ARG_UNUSED(ide); + + return CONFIG_CAN_MAX_FILTER; +} + +static const struct can_driver_api can_native_linux_driver_api = { + .start = can_native_linux_start, + .stop = can_native_linux_stop, + .get_capabilities = can_native_linux_get_capabilities, + .set_mode = can_native_linux_set_mode, + .set_timing = can_native_linux_set_timing, + .send = can_native_linux_send, + .add_rx_filter = can_native_linux_add_rx_filter, + .remove_rx_filter = can_native_linux_remove_rx_filter, + .get_state = can_native_linux_get_state, +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY + .recover = can_native_linux_recover, +#endif + .set_state_change_callback = can_native_linux_set_state_change_callback, + .get_core_clock = can_native_linux_get_core_clock, + .get_max_filters = can_native_linux_get_max_filters, + .timing_min = { + .sjw = 0x1, + .prop_seg = 0x01, + .phase_seg1 = 0x01, + .phase_seg2 = 0x01, + .prescaler = 0x01 + }, + .timing_max = { + .sjw = 0x0F, + .prop_seg = 0x0F, + .phase_seg1 = 0x0F, + .phase_seg2 = 0x0F, + .prescaler = 0xFFFF + }, +#ifdef CONFIG_CAN_FD_MODE + .set_timing_data = can_native_linux_set_timing_data, + .timing_data_min = { + .sjw = 0x1, + .prop_seg = 0x01, + .phase_seg1 = 0x01, + .phase_seg2 = 0x01, + .prescaler = 0x01 + }, + .timing_data_max = { + .sjw = 0x0F, + .prop_seg = 0x0F, + .phase_seg1 = 0x0F, + .phase_seg2 = 0x0F, + .prescaler = 0xFFFF + }, +#endif /* CONFIG_CAN_FD_MODE */ +}; + +static int can_native_linux_init(const struct device *dev) +{ + const struct can_native_linux_config *cfg = dev->config; + struct can_native_linux_data *data = dev->data; + + k_mutex_init(&data->filter_mutex); + k_sem_init(&data->tx_idle, 1, 1); + + data->dev_fd = linux_socketcan_iface_open(cfg->if_name); + if (data->dev_fd < 0) { + LOG_ERR("Cannot open %s (%d)", cfg->if_name, data->dev_fd); + return -ENODEV; + } + + k_thread_create(&data->rx_thread, data->rx_thread_stack, + K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), + rx_thread, (void *)dev, NULL, NULL, + CONFIG_CAN_NATIVE_LINUX_RX_THREAD_PRIORITY, + 0, K_NO_WAIT); + + LOG_DBG("Init of %s done", dev->name); + + return 0; +} + +#define CAN_NATIVE_LINUX_INIT(inst) \ + \ +static const struct can_native_linux_config can_native_linux_cfg_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 0), \ + .if_name = DT_INST_PROP(inst, host_interface), \ +}; \ + \ +static struct can_native_linux_data can_native_linux_data_##inst; \ + \ +CAN_DEVICE_DT_INST_DEFINE(inst, can_native_linux_init, NULL, \ + &can_native_linux_data_##inst, \ + &can_native_linux_cfg_##inst, \ + POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ + &can_native_linux_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CAN_NATIVE_LINUX_INIT) diff --git a/drivers/can/can_native_linux_adapt.c b/drivers/can/can_native_linux_adapt.c new file mode 100644 index 00000000000..1ec6f399e07 --- /dev/null +++ b/drivers/can/can_native_linux_adapt.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019 Intel Corporation + * Copyright (c) 2022 Martin Jäger + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * Routines setting up the host system. Those are placed in separate file + * because there is naming conflicts between host and zephyr network stacks. + */ + +#include +#include +#include +#include +#include +#include + +/* Linux host include files. */ +#ifdef __linux +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#error "This driver can only be built on Linux systems" +#endif + +#include "can_native_linux_adapt.h" + +#ifndef CANFD_FDF +/* Linux kernels before v5.14 do not define CANFD_FDF */ +#define CANFD_FDF 0x04 +#endif /* CANFD_FDF */ + +int linux_socketcan_iface_open(const char *if_name) +{ + struct sockaddr_can addr; + struct ifreq ifr; + int fd, opt, ret = -EINVAL; + + fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (fd < 0) { + return -errno; + } + + (void)memset(&ifr, 0, sizeof(ifr)); + (void)memset(&addr, 0, sizeof(addr)); + + strncpy(ifr.ifr_name, if_name, IFNAMSIZ - 1); + + ret = ioctl(fd, SIOCGIFINDEX, (void *)&ifr); + if (ret < 0) { + close(fd); + return -errno; + } + + addr.can_ifindex = ifr.ifr_ifindex; + addr.can_family = PF_CAN; + + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + close(fd); + return -errno; + } + + /* this option must always be enabled in order to receive TX confirmations */ + opt = 1; + ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &opt, sizeof(opt)); + if (ret < 0) { + close(fd); + return -errno; + } + + return fd; +} + +int linux_socketcan_iface_close(int fd) +{ + return close(fd); +} + +int linux_socketcan_poll_data(int fd) +{ + struct timeval timeout; + fd_set rset; + int ret; + + FD_ZERO(&rset); + + FD_SET(fd, &rset); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + ret = select(fd + 1, &rset, NULL, NULL, &timeout); + if (ret < 0 && errno != EINTR) { + return -errno; + } else if (ret > 0) { + if (FD_ISSET(fd, &rset)) { + return 0; + } + } + + return -EAGAIN; +} + +int linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm) +{ + struct canfd_frame *frame = (struct canfd_frame *)buf; + struct msghdr msg = {0}; + + struct iovec iov = { + .iov_base = buf, + .iov_len = buf_len, + }; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + int ret = (int)recvmsg(fd, &msg, MSG_WAITALL); + + if (msg_confirm != NULL) { + *msg_confirm = (msg.msg_flags & MSG_CONFIRM) != 0; + } + + /* Make sure to set the flags for all frames received via the Linux API. + * + * Zephyr relies on defined flags field of the SocketCAN data for both FD and classical CAN + * frames. In Linux the flags field is undefined for legacy frames. + */ + if (ret == CANFD_MTU) { + frame->flags |= CANFD_FDF; + } else if (ret == CAN_MTU) { + frame->flags = 0; + } + + return ret; +} + +int linux_socketcan_set_mode_fd(int fd, bool mode_fd) +{ + int opt = mode_fd ? 1 : 0; + + return setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &opt, sizeof(opt)); +} diff --git a/drivers/can/can_native_linux_adapt.h b/drivers/can/can_native_linux_adapt.h new file mode 100644 index 00000000000..8d19b34a198 --- /dev/null +++ b/drivers/can/can_native_linux_adapt.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Private functions for native posix canbus driver. + */ + +#ifndef ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ +#define ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ + +int linux_socketcan_iface_open(const char *if_name); + +int linux_socketcan_iface_close(int fd); + +int linux_socketcan_poll_data(int fd); + +int linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm); + +int linux_socketcan_set_mode_fd(int fd, bool mode_fd); + +#endif /* ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ */ diff --git a/drivers/can/can_native_posix_linux.c b/drivers/can/can_native_posix_linux.c deleted file mode 100644 index 7f8a0ea494f..00000000000 --- a/drivers/can/can_native_posix_linux.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) 2022 Martin Jäger - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT zephyr_native_posix_linux_can - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "can_native_posix_linux_socketcan.h" - -LOG_MODULE_REGISTER(can_npl, CONFIG_CAN_LOG_LEVEL); - -struct can_filter_context { - can_rx_callback_t rx_cb; - void *cb_arg; - struct can_filter filter; -}; - -struct can_npl_data { - struct can_filter_context filters[CONFIG_CAN_MAX_FILTER]; - struct k_mutex filter_mutex; - struct k_sem tx_idle; - can_tx_callback_t tx_callback; - void *tx_user_data; - bool loopback; - bool mode_fd; - int dev_fd; /* Linux socket file descriptor */ - struct k_thread rx_thread; - bool started; - - K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); -}; - -struct can_npl_config { - const char *if_name; -}; - -static void dispatch_frame(const struct device *dev, struct can_frame *frame) -{ - struct can_npl_data *data = dev->data; - can_rx_callback_t callback; - struct can_frame tmp_frame; - - k_mutex_lock(&data->filter_mutex, K_FOREVER); - - for (int filter_id = 0; filter_id < ARRAY_SIZE(data->filters); filter_id++) { - if (data->filters[filter_id].rx_cb == NULL) { - continue; - } - - if (!can_frame_matches_filter(frame, &data->filters[filter_id].filter)) { - continue; - } - - /* Make a temporary copy in case the user modifies the message */ - tmp_frame = *frame; - - callback = data->filters[filter_id].rx_cb; - callback(dev, &tmp_frame, data->filters[filter_id].cb_arg); - } - - k_mutex_unlock(&data->filter_mutex); -} - -static void rx_thread(void *arg1, void *arg2, void *arg3) -{ - const struct device *dev = arg1; - struct can_npl_data *data = dev->data; - struct socketcan_frame sframe; - struct can_frame frame; - bool msg_confirm; - int count; - - ARG_UNUSED(arg2); - ARG_UNUSED(arg3); - - LOG_DBG("Starting Linux SocketCAN RX thread"); - - while (true) { - while (linux_socketcan_poll_data(data->dev_fd) == 0) { - count = linux_socketcan_read_data(data->dev_fd, (void *)(&sframe), - sizeof(sframe), &msg_confirm); - if (msg_confirm) { - data->tx_callback(dev, 0, data->tx_user_data); - k_sem_give(&data->tx_idle); - - if (!data->loopback) { - continue; - } - } - if ((count <= 0) || !data->started) { - break; - } - - socketcan_to_can_frame(&sframe, &frame); - - LOG_DBG("Received %d bytes. Id: 0x%x, ID type: %s %s", - frame.dlc, frame.id, - (frame.flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", - (frame.flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : ""); - - dispatch_frame(dev, &frame); - } - - /* short sleep required to avoid blocking the whole native_posix process */ - k_sleep(K_MSEC(1)); - } -} - -static int can_npl_send(const struct device *dev, const struct can_frame *frame, - k_timeout_t timeout, can_tx_callback_t callback, void *user_data) -{ - struct can_npl_data *data = dev->data; - struct socketcan_frame sframe; - uint8_t max_dlc = CAN_MAX_DLC; - size_t mtu = CAN_MTU; - int ret = -EIO; - - LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s", - frame->dlc, dev->name, frame->id, - (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", - (frame->flags & CAN_FRAME_RTR) != 0 ? ", RTR frame" : ""); - - __ASSERT_NO_MSG(callback != NULL); - -#ifdef CONFIG_CAN_FD_MODE - if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR | - CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { - LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); - return -ENOTSUP; - } - - if ((frame->flags & CAN_FRAME_FDF) != 0) { - if (!data->mode_fd) { - return -ENOTSUP; - } - - max_dlc = CANFD_MAX_DLC; - mtu = CANFD_MTU; - } -#else /* CONFIG_CAN_FD_MODE */ - if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) { - LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); - return -ENOTSUP; - } -#endif /* !CONFIG_CAN_FD_MODE */ - - if (frame->dlc > max_dlc) { - LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, max_dlc); - return -EINVAL; - } - - if (data->dev_fd <= 0) { - LOG_ERR("No file descriptor: %d", data->dev_fd); - return -EIO; - } - - if (!data->started) { - return -ENETDOWN; - } - - socketcan_from_can_frame(frame, &sframe); - - if (k_sem_take(&data->tx_idle, timeout) != 0) { - return -EAGAIN; - } - - data->tx_callback = callback; - data->tx_user_data = user_data; - - ret = linux_socketcan_write_data(data->dev_fd, &sframe, mtu); - if (ret < 0) { - LOG_ERR("Cannot send CAN data len %d (%d)", sframe.len, -errno); - } - - return 0; -} - -static int can_npl_add_rx_filter(const struct device *dev, can_rx_callback_t cb, - void *cb_arg, const struct can_filter *filter) -{ - struct can_npl_data *data = dev->data; - struct can_filter_context *filter_ctx; - int filter_id = -ENOSPC; - - LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id, - filter->mask); - -#ifdef CONFIG_CAN_FD_MODE - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | - CAN_FILTER_RTR | CAN_FILTER_FDF)) != 0) { -#else - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { -#endif - LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); - return -ENOTSUP; - } - - k_mutex_lock(&data->filter_mutex, K_FOREVER); - - for (int i = 0; i < ARRAY_SIZE(data->filters); i++) { - if (data->filters[i].rx_cb == NULL) { - filter_id = i; - break; - } - } - - if (filter_id < 0) { - LOG_ERR("No free filter left"); - k_mutex_unlock(&data->filter_mutex); - return filter_id; - } - - filter_ctx = &data->filters[filter_id]; - filter_ctx->rx_cb = cb; - filter_ctx->cb_arg = cb_arg; - filter_ctx->filter = *filter; - - k_mutex_unlock(&data->filter_mutex); - - LOG_DBG("Filter added. ID: %d", filter_id); - - return filter_id; -} - -static void can_npl_remove_rx_filter(const struct device *dev, int filter_id) -{ - struct can_npl_data *data = dev->data; - - if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) { - LOG_ERR("filter ID %d out of bounds"); - return; - } - - k_mutex_lock(&data->filter_mutex, K_FOREVER); - data->filters[filter_id].rx_cb = NULL; - k_mutex_unlock(&data->filter_mutex); - - LOG_DBG("Filter removed. ID: %d", filter_id); -} - -static int can_npl_get_capabilities(const struct device *dev, can_mode_t *cap) -{ - ARG_UNUSED(dev); - - *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK; - -#if CONFIG_CAN_FD_MODE - *cap |= CAN_MODE_FD; -#endif /* CONFIG_CAN_FD_MODE */ - - return 0; -} - -static int can_npl_start(const struct device *dev) -{ - struct can_npl_data *data = dev->data; - - if (data->started) { - return -EALREADY; - } - - data->started = true; - - return 0; -} - -static int can_npl_stop(const struct device *dev) -{ - struct can_npl_data *data = dev->data; - - if (!data->started) { - return -EALREADY; - } - - data->started = false; - - return 0; -} - -static int can_npl_set_mode(const struct device *dev, can_mode_t mode) -{ - struct can_npl_data *data = dev->data; - -#ifdef CONFIG_CAN_FD_MODE - if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { - LOG_ERR("unsupported mode: 0x%08x", mode); - return -ENOTSUP; - } -#else - if ((mode & ~(CAN_MODE_LOOPBACK)) != 0) { - LOG_ERR("unsupported mode: 0x%08x", mode); - return -ENOTSUP; - } -#endif /* CONFIG_CAN_FD_MODE */ - - if (data->started) { - return -EBUSY; - } - - /* loopback is handled internally in rx_thread */ - data->loopback = (mode & CAN_MODE_LOOPBACK) != 0; - - data->mode_fd = (mode & CAN_MODE_FD) != 0; - linux_socketcan_set_mode_fd(data->dev_fd, data->mode_fd); - - return 0; -} - -static int can_npl_set_timing(const struct device *dev, const struct can_timing *timing) -{ - struct can_npl_data *data = dev->data; - - ARG_UNUSED(timing); - - if (data->started) { - return -EBUSY; - } - - return 0; -} - -#ifdef CONFIG_CAN_FD_MODE -static int can_npl_set_timing_data(const struct device *dev, const struct can_timing *timing) -{ - struct can_npl_data *data = dev->data; - - ARG_UNUSED(timing); - - if (data->started) { - return -EBUSY; - } - - return 0; -} -#endif /* CONFIG_CAN_FD_MODE */ - -static int can_npl_get_state(const struct device *dev, enum can_state *state, - struct can_bus_err_cnt *err_cnt) -{ - struct can_npl_data *data = dev->data; - - if (state != NULL) { - if (!data->started) { - *state = CAN_STATE_STOPPED; - } else { - /* SocketCAN does not forward error frames by default */ - *state = CAN_STATE_ERROR_ACTIVE; - } - } - - if (err_cnt) { - err_cnt->tx_err_cnt = 0; - err_cnt->rx_err_cnt = 0; - } - - return 0; -} - -#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY -static int can_npl_recover(const struct device *dev, k_timeout_t timeout) -{ - struct can_npl_data *data = dev->data; - - ARG_UNUSED(timeout); - - if (!data->started) { - return -ENETDOWN; - } - - return 0; -} -#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ - -static void can_npl_set_state_change_callback(const struct device *dev, - can_state_change_callback_t cb, - void *user_data) -{ - ARG_UNUSED(dev); - ARG_UNUSED(cb); - ARG_UNUSED(user_data); -} - -static int can_npl_get_core_clock(const struct device *dev, uint32_t *rate) -{ - /* Return 16MHz as an realistic value for the testcases */ - *rate = 16000000; - - return 0; -} - -static int can_npl_get_max_filters(const struct device *dev, bool ide) -{ - ARG_UNUSED(ide); - - return CONFIG_CAN_MAX_FILTER; -} - -static const struct can_driver_api can_npl_driver_api = { - .start = can_npl_start, - .stop = can_npl_stop, - .get_capabilities = can_npl_get_capabilities, - .set_mode = can_npl_set_mode, - .set_timing = can_npl_set_timing, - .send = can_npl_send, - .add_rx_filter = can_npl_add_rx_filter, - .remove_rx_filter = can_npl_remove_rx_filter, - .get_state = can_npl_get_state, -#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY - .recover = can_npl_recover, -#endif - .set_state_change_callback = can_npl_set_state_change_callback, - .get_core_clock = can_npl_get_core_clock, - .get_max_filters = can_npl_get_max_filters, - .timing_min = { - .sjw = 0x1, - .prop_seg = 0x01, - .phase_seg1 = 0x01, - .phase_seg2 = 0x01, - .prescaler = 0x01 - }, - .timing_max = { - .sjw = 0x0F, - .prop_seg = 0x0F, - .phase_seg1 = 0x0F, - .phase_seg2 = 0x0F, - .prescaler = 0xFFFF - }, -#ifdef CONFIG_CAN_FD_MODE - .set_timing_data = can_npl_set_timing_data, - .timing_data_min = { - .sjw = 0x1, - .prop_seg = 0x01, - .phase_seg1 = 0x01, - .phase_seg2 = 0x01, - .prescaler = 0x01 - }, - .timing_data_max = { - .sjw = 0x0F, - .prop_seg = 0x0F, - .phase_seg1 = 0x0F, - .phase_seg2 = 0x0F, - .prescaler = 0xFFFF - }, -#endif /* CONFIG_CAN_FD_MODE */ -}; - -static int can_npl_init(const struct device *dev) -{ - const struct can_npl_config *cfg = dev->config; - struct can_npl_data *data = dev->data; - - k_mutex_init(&data->filter_mutex); - k_sem_init(&data->tx_idle, 1, 1); - - data->dev_fd = linux_socketcan_iface_open(cfg->if_name); - if (data->dev_fd < 0) { - LOG_ERR("Cannot open %s (%d)", cfg->if_name, data->dev_fd); - return -ENODEV; - } - - k_thread_create(&data->rx_thread, data->rx_thread_stack, - K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), - rx_thread, (void *)dev, NULL, NULL, - CONFIG_CAN_NATIVE_POSIX_LINUX_RX_THREAD_PRIORITY, - 0, K_NO_WAIT); - - LOG_DBG("Init of %s done", dev->name); - - return 0; -} - -#define CAN_NATIVE_POSIX_LINUX_INIT(inst) \ - \ -static const struct can_npl_config can_npl_cfg_##inst = { \ - .if_name = DT_INST_PROP(inst, host_interface), \ -}; \ - \ -static struct can_npl_data can_npl_data_##inst; \ - \ -CAN_DEVICE_DT_INST_DEFINE(inst, can_npl_init, NULL, \ - &can_npl_data_##inst, &can_npl_cfg_##inst, \ - POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ - &can_npl_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(CAN_NATIVE_POSIX_LINUX_INIT) diff --git a/drivers/can/can_native_posix_linux_socketcan.c b/drivers/can/can_native_posix_linux_socketcan.c deleted file mode 100644 index 56295a8f843..00000000000 --- a/drivers/can/can_native_posix_linux_socketcan.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * Copyright (c) 2022 Martin Jäger - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * - * Routines setting up the host system. Those are placed in separate file - * because there is naming conflicts between host and zephyr network stacks. - */ - -#include -#include -#include -#include -#include -#include - -/* Linux host include files. */ -#ifdef __linux -#include -#include -#include -#include -#include -#include -#include -#include -#else -#error "This driver can only be built on Linux systems" -#endif - -#include "can_native_posix_linux_socketcan.h" - -#ifndef CANFD_FDF -/* Linux kernels before v5.14 do not define CANFD_FDF */ -#define CANFD_FDF 0x04 -#endif /* CANFD_FDF */ - -int linux_socketcan_iface_open(const char *if_name) -{ - struct sockaddr_can addr; - struct ifreq ifr; - int fd, opt, ret = -EINVAL; - - fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); - if (fd < 0) { - return -errno; - } - - (void)memset(&ifr, 0, sizeof(ifr)); - (void)memset(&addr, 0, sizeof(addr)); - - strncpy(ifr.ifr_name, if_name, IFNAMSIZ); - - ret = ioctl(fd, SIOCGIFINDEX, (void *)&ifr); - if (ret < 0) { - close(fd); - return -errno; - } - - addr.can_ifindex = ifr.ifr_ifindex; - addr.can_family = PF_CAN; - - ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret < 0) { - close(fd); - return -errno; - } - - /* this option must always be enabled in order to receive TX confirmations */ - opt = 1; - ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &opt, sizeof(opt)); - if (ret < 0) { - close(fd); - return -errno; - } - - return fd; -} - -int linux_socketcan_iface_close(int fd) -{ - return close(fd); -} - -int linux_socketcan_poll_data(int fd) -{ - struct timeval timeout; - fd_set rset; - int ret; - - FD_ZERO(&rset); - - FD_SET(fd, &rset); - - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - ret = select(fd + 1, &rset, NULL, NULL, &timeout); - if (ret < 0 && errno != EINTR) { - return -errno; - } else if (ret > 0) { - if (FD_ISSET(fd, &rset)) { - return 0; - } - } - - return -EAGAIN; -} - -ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm) -{ - struct canfd_frame *frame = (struct canfd_frame *)buf; - struct msghdr msg = {0}; - - struct iovec iov = { - .iov_base = buf, - .iov_len = buf_len, - }; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - int ret = recvmsg(fd, &msg, MSG_WAITALL); - - if (msg_confirm != NULL) { - *msg_confirm = (msg.msg_flags & MSG_CONFIRM) != 0; - } - - /* Make sure to set the flags for all frames received via the Linux API. - * - * Zephyr relies on defined flags field of the SocketCAN data for both FD and classical CAN - * frames. In Linux the flags field is undefined for legacy frames. - */ - if (ret == CANFD_MTU) { - frame->flags |= CANFD_FDF; - } else if (ret == CAN_MTU) { - frame->flags = 0; - } - - return ret; -} - -ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len) -{ - return write(fd, buf, buf_len); -} - -int linux_socketcan_setsockopt(int fd, int level, int optname, - const void *optval, socklen_t optlen) -{ - return setsockopt(fd, level, optname, optval, optlen); -} - -int linux_socketcan_getsockopt(int fd, int level, int optname, - void *optval, socklen_t *optlen) -{ - return getsockopt(fd, level, optname, optval, optlen); -} - -int linux_socketcan_set_mode_fd(int fd, bool mode_fd) -{ - int opt = mode_fd ? 1 : 0; - - return setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &opt, sizeof(opt)); -} diff --git a/drivers/can/can_native_posix_linux_socketcan.h b/drivers/can/can_native_posix_linux_socketcan.h deleted file mode 100644 index 76db602af98..00000000000 --- a/drivers/can/can_native_posix_linux_socketcan.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** @file - * @brief Private functions for native posix canbus driver. - */ - -#ifndef ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ -#define ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ - -int linux_socketcan_iface_open(const char *if_name); - -int linux_socketcan_iface_close(int fd); - -int linux_socketcan_poll_data(int fd); - -ssize_t linux_socketcan_read_data(int fd, void *buf, size_t buf_len, bool *msg_confirm); - -ssize_t linux_socketcan_write_data(int fd, void *buf, size_t buf_len); - -int linux_socketcan_setsockopt(int fd, int level, int optname, const void *optval, - socklen_t optlen); - -int linux_socketcan_getsockopt(int fd, int level, int optname, void *optval, - socklen_t *optlen); - -int linux_socketcan_set_mode_fd(int fd, bool mode_fd); - -#endif /* ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_LINUX_SOCKETCAN_H_ */ diff --git a/drivers/can/can_numaker.c b/drivers/can/can_numaker.c index 0bb47d78a04..ba51b8b82fd 100644 --- a/drivers/can/can_numaker.c +++ b/drivers/can/can_numaker.c @@ -176,7 +176,6 @@ static const struct can_driver_api can_numaker_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = can_numaker_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, #ifdef CONFIG_CAN_FD_MODE @@ -249,18 +248,18 @@ static const struct can_mcan_ops can_numaker_ops = { \ static void can_numaker_irq_config_func_##inst(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 0, irq), \ - DT_INST_IRQ_BY_IDX(inst, 0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), \ can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(inst), \ 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(inst, 0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, 1, irq), \ - DT_INST_IRQ_BY_IDX(inst, 1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), \ can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(inst), \ 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(inst, 1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } \ \ static const struct can_numaker_config can_numaker_config_##inst = { \ @@ -288,7 +287,7 @@ static const struct can_mcan_ops can_numaker_ops = { CAN_MCAN_DATA_INITIALIZER(&can_numaker_data_ ## inst); \ \ CAN_DEVICE_DT_INST_DEFINE(inst, \ - &can_numaker_init, \ + can_numaker_init, \ NULL, \ &can_mcan_data_##inst, \ &can_mcan_config_##inst, \ diff --git a/drivers/can/can_nxp_s32_canxl.c b/drivers/can/can_nxp_s32_canxl.c index 211e901055f..2076429e279 100644 --- a/drivers/can/can_nxp_s32_canxl.c +++ b/drivers/can/can_nxp_s32_canxl.c @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,14 @@ * Convert from RX message buffer index to allocated filter ID and * vice versa. */ +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +#define RX_MBIDX_TO_ALLOC_IDX(x) (x) +#define ALLOC_IDX_TO_RXMB_IDX(x) (x) +#else #define RX_MBIDX_TO_ALLOC_IDX(x) (x - CONFIG_CAN_NXP_S32_MAX_TX) #define ALLOC_IDX_TO_RXMB_IDX(x) (x + CONFIG_CAN_NXP_S32_MAX_TX) +#endif + /* * Convert from TX message buffer index to allocated TX ID and vice @@ -37,6 +43,17 @@ #define CAN_NXP_S32_MAX_BITRATE 8000000 #define CAN_NXP_S32_DATA_LENGTH 64 +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +/* RX FIFO depth is fixed to the maximum value */ +#define CAN_NXP_S32_RX_FIFO_DEPTH 32 +/* RX FIFO water mark equal 1 that allows the interrupt is generated after 1 message received */ +#define CAN_NXP_S32_RX_FIFO_WATERMARK 1 +#endif + +#if defined(CONFIG_CAN_FD_MODE) && defined(CONFIG_CAN_NXP_S32_RX_FIFO) +#define CAN_NXP_S32_FD_MODE 1 +#endif + LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #define SP_AND_TIMING_NOT_SET(inst) \ @@ -49,7 +66,7 @@ LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #error You must either set a sampling-point or timings (phase-seg* and prop-seg) #endif -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE #define SP_AND_TIMING_DATA_NOT_SET(inst) \ (!DT_INST_NODE_HAS_PROP(inst, sample_point_data) && \ @@ -63,28 +80,27 @@ LOG_MODULE_REGISTER(nxp_s32_canxl, CONFIG_CAN_LOG_LEVEL); #endif struct can_nxp_s32_config { + const struct can_driver_config common; CANXL_SIC_Type *base_sic; CANXL_GRP_CONTROL_Type *base_grp_ctrl; CANXL_DSC_CONTROL_Type *base_dsc_ctrl; +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + CANXL_RXFIFO_Type * base_rx_fifo; + CANXL_RXFIFO_CONTROL_Type *base_rx_fifo_ctrl; +#endif uint8 instance; const struct device *clock_dev; clock_control_subsys_t clock_subsys; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t prop_seg; uint32_t phase_seg1; uint32_t phase_seg2; -#ifdef CONFIG_CAN_FD_MODE - uint32_t bitrate_data; - uint32_t sample_point_data; +#ifdef CAN_NXP_S32_FD_MODE uint32_t sjw_data; uint32_t prop_seg_data; uint32_t phase_seg1_data; uint32_t phase_seg2_data; #endif - uint32_t max_bitrate; - const struct device *phy; const struct pinctrl_dev_config *pin_cfg; Canexcel_Ip_ConfigType *can_cfg; void (*irq_config_func)(void); @@ -98,18 +114,23 @@ struct can_nxp_s32_tx_callback { struct can_nxp_s32_rx_callback { struct can_filter filter; +#ifndef CONFIG_CAN_NXP_S32_RX_FIFO Canexcel_Ip_DataInfoType rx_info; +#endif can_rx_callback_t function; void *arg; }; struct can_nxp_s32_data { + struct can_driver_data common; Canexcel_Ip_StateType *can_state; ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_NXP_S32_MAX_RX); struct k_mutex rx_mutex; struct can_nxp_s32_rx_callback rx_cbs[CONFIG_CAN_NXP_S32_MAX_RX]; +#ifndef CONFIG_CAN_NXP_S32_RX_FIFO Canexcel_RxFdMsg *rx_msg; +#endif ATOMIC_DEFINE(tx_allocs, CONFIG_CAN_NXP_S32_MAX_TX); struct k_sem tx_allocs_sem; @@ -117,14 +138,16 @@ struct can_nxp_s32_data { struct can_nxp_s32_tx_callback tx_cbs[CONFIG_CAN_NXP_S32_MAX_TX]; Canexcel_TxFdMsgType *tx_msg; +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + Canexcel_Ip_RxFifoFilterID_ADDR * rx_fifo_filter; + Canexcel_RxFdMsg *rx_fifo; +#endif + struct can_timing timing; -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE struct can_timing timing_data; #endif enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; - bool started; }; static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *cap) @@ -133,32 +156,76 @@ static int can_nxp_s32_get_capabilities(const struct device *dev, can_mode_t *ca *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY; -#if CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE *cap |= CAN_MODE_FD; #endif return 0; } +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO +static void can_nxp_s32_config_rx_fifo_filter(const struct device *dev, int filter_id) +{ + const struct can_nxp_s32_config *config = dev->config; + struct can_nxp_s32_data *data = dev->data; + + /* Lock the RxFIFO by System by reading register */ + (void)config->base_rx_fifo_ctrl->RXFSYSLOCK; + + CanXL_ConfigIDFilter(config->base_rx_fifo, + &data->rx_fifo_filter[filter_id], filter_id); + + if ((config->base_rx_fifo_ctrl->RXFCSTA & CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) + == CANXL_RXFIFO_CONTROL_RXFCSTA_SYSLOCK_MASK) { + /* Clear the sys lock to enable transfers */ + config->base_rx_fifo_ctrl->RXFSYSLOCK = + CANXL_RXFIFO_CONTROL_RXFSYSLOCK_SYSLOCK_MASK; + } +} + +/* Get the RxFiFO filter matched with the received RxFIFO message queue */ +static inline int can_nxp_s32_get_rx_fifo_filter(struct can_nxp_s32_data *data) +{ + int alloc = -ENOSPC; + uint32_t mask; + + for (int filter_id = 0; filter_id < CONFIG_CAN_NXP_S32_MAX_RX; filter_id++) { + mask = data->rx_fifo_filter[filter_id].idAddrFilterL; + + if (mask == 0) { + continue; + } + + if ((data->rx_fifo[0].Header.Id & mask) == + (data->rx_fifo_filter[filter_id].idAddrFilterH & mask)) { + alloc = filter_id; + break; + } + } + + return alloc; +} +#endif + static int can_nxp_s32_start(const struct device *dev) { const struct can_nxp_s32_config *config = dev->config; struct can_nxp_s32_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; } } - data->started = true; + data->common.started = true; return 0; } @@ -201,11 +268,11 @@ static int can_nxp_s32_stop(const struct device *dev) int alloc; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } - data->started = false; + data->common.started = false; /* Abort any pending TX frames before entering freeze mode */ for (alloc = 0; alloc < CONFIG_CAN_NXP_S32_MAX_TX; alloc++) { @@ -223,8 +290,8 @@ static int can_nxp_s32_stop(const struct device *dev) } } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; @@ -243,10 +310,10 @@ static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode) bool canfd = false; bool brs = false; - if (data->started) { + if (data->common.started) { return -EBUSY; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_FD)) != 0) { #else if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY)) != 0) { @@ -279,6 +346,8 @@ static int can_nxp_s32_set_mode(const struct device *dev, can_mode_t mode) Canexcel_Ip_ExitFreezeMode(config->instance); + data->common.mode = mode; + return 0; } @@ -298,15 +367,6 @@ static int can_nxp_s32_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_NXP_S32_MAX_RX; } -static int can_nxp_s32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_nxp_s32_config *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; -} - static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state, struct can_bus_err_cnt *err_cnt) { @@ -315,7 +375,7 @@ static int can_nxp_s32_get_state(const struct device *dev, enum can_state *state uint32_t sys_status = config->base_sic->SYSS; if (state) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { if (sys_status & CANXL_SIC_SYSS_CBOFF_MASK) { @@ -346,8 +406,8 @@ static void can_nxp_s32_set_state_change_callback(const struct device *dev, { struct can_nxp_s32_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY @@ -359,7 +419,7 @@ static int can_nxp_s32_recover(const struct device *dev, k_timeout_t timeout) uint64_t start_time; int ret = 0; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -404,9 +464,20 @@ static void can_nxp_s32_remove_rx_filter(const struct device *dev, int filter_id k_mutex_lock(&data->rx_mutex, K_FOREVER); if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) { +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + data->rx_fifo_filter[mb_indx].idAddrFilterL = 0; + data->rx_fifo_filter[mb_indx].idAddrFilterH = 0; + + Canexcel_Ip_EnterFreezeMode(config->instance); + + can_nxp_s32_config_rx_fifo_filter(dev, mb_indx); + + Canexcel_Ip_ExitFreezeMode(config->instance); +#else if (can_nxp_s32_abort_msg(config, mb_indx)) { LOG_ERR("Can't abort message !"); }; +#endif data->rx_cbs[filter_id].function = NULL; data->rx_cbs[filter_id].arg = NULL; @@ -430,11 +501,8 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, uint32_t mask; __ASSERT_NO_MSG(callback != NULL); -#if defined(CONFIG_CAN_FD_MODE) - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_FDF)) != 0) { -#else - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) { -#endif + + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -458,24 +526,42 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, data->rx_cbs[alloc].arg = user_data; data->rx_cbs[alloc].filter = *filter; - data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) { - .frame = !!(filter->flags & CAN_FILTER_FDF) ? - CANEXCEL_FD_FRAME : CANEXCEL_CLASIC_FRAME, - .idType = !!(filter->flags & CAN_FILTER_IDE) ? - CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD, - .dataLength = CAN_NXP_S32_DATA_LENGTH, - }; - /* Set Rx Mb individual mask for */ mb_indx = ALLOC_IDX_TO_RXMB_IDX(alloc); if (!!(filter->flags & CAN_FILTER_IDE)) { - mask = (filter->mask & CANXL_IP_ID_EXT_MASK); + mask = filter->mask & CANXL_IP_ID_EXT_MASK; } else { - mask = ((filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK); + mask = (filter->mask << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK; } +#ifndef CONFIG_CAN_ACCEPT_RTR + mask |= CANXL_MSG_DESCRIPTORS_MDFLT1FD_RTRMSK_MASK; +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + Canexcel_Ip_EnterFreezeMode(config->instance); +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + uint32_t filter_id; + + if (!!(filter->flags & CAN_FILTER_IDE)) { + filter_id = filter->id & CANXL_IP_ID_EXT_MASK; + } else { + filter_id = (filter->id << CANXL_IP_ID_STD_SHIFT) & CANXL_IP_ID_STD_MASK; + } + + data->rx_fifo_filter[mb_indx].filterType = CANEXCEL_IP_RX_FIFO_MASK_FILTER; + data->rx_fifo_filter[mb_indx].idAddrFilterL = mask; + data->rx_fifo_filter[mb_indx].idAddrFilterH = filter_id; + + can_nxp_s32_config_rx_fifo_filter(dev, mb_indx); +#else + data->rx_cbs[alloc].rx_info = (Canexcel_Ip_DataInfoType) { + .frame = CANEXCEL_CLASIC_FRAME, + .idType = !!(filter->flags & CAN_FILTER_IDE) ? + CANEXCEL_MSG_ID_EXT : CANEXCEL_MSG_ID_STD, + .dataLength = CAN_NXP_S32_DATA_LENGTH, + }; + Canexcel_Ip_SetRxIndividualMask(config->instance, mb_indx, data->rx_cbs[alloc].rx_info.frame, mask); @@ -483,6 +569,7 @@ static int can_nxp_s32_add_rx_filter(const struct device *dev, &data->rx_cbs[alloc].rx_info); Canexcel_Ip_ReceiveFD(config->instance, mb_indx, &data->rx_msg[alloc], FALSE); +#endif Canexcel_Ip_ExitFreezeMode(config->instance); @@ -506,7 +593,7 @@ static int can_nxp_s32_send(const struct device *dev, __ASSERT_NO_MSG(callback != NULL); -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags); return -ENOTSUP; @@ -541,7 +628,7 @@ static int can_nxp_s32_send(const struct device *dev, LOG_ERR("DLC of %d for non-FD format frame", frame->dlc); return -EINVAL; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE } else { if (frame->dlc > CANFD_MAX_DLC) { LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc); @@ -550,7 +637,7 @@ static int can_nxp_s32_send(const struct device *dev, #endif } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -630,7 +717,7 @@ static int can_nxp_s32_set_timing(const struct device *dev, struct can_nxp_s32_data *data = dev->data; Canexcel_Ip_TimeSegmentType can_time_segment = {0}; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -642,7 +729,7 @@ static int can_nxp_s32_set_timing(const struct device *dev, return 0; } -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE static int can_nxp_s32_set_timing_data(const struct device *dev, const struct can_timing *timing_data) { @@ -650,7 +737,7 @@ static int can_nxp_s32_set_timing_data(const struct device *dev, struct can_nxp_s32_data *data = dev->data; Canexcel_Ip_TimeSegmentType can_fd_time_segment = {0}; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -672,7 +759,7 @@ static void can_nxp_s32_err_callback(const struct device *dev, struct can_nxp_s32_data *data = dev->data; enum can_state state; struct can_bus_err_cnt err_cnt; - void *cb_data = data->state_change_cb_data; + void *cb_data = data->common.state_change_cb_user_data; can_tx_callback_t function; int alloc; void *arg; @@ -703,8 +790,8 @@ static void can_nxp_s32_err_callback(const struct device *dev, can_nxp_s32_get_state(dev, &state, &err_cnt); if (data->state != state) { data->state = state; - if (data->state_change_cb) { - data->state_change_cb(dev, state, err_cnt, cb_data); + if (data->common.state_change_cb) { + data->common.state_change_cb(dev, state, err_cnt, cb_data); } } @@ -775,7 +862,6 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, struct can_frame frame = {0}; can_tx_callback_t tx_func; can_rx_callback_t rx_func; - Canexcel_Ip_StatusType status; int alloc; if (eventType == CANEXCEL_EVENT_TX_COMPLETE) { @@ -786,6 +872,33 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, tx_func(dev, 0, data->tx_cbs[alloc].arg); k_sem_give(&data->tx_allocs_sem); } +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + } else if (eventType == CANEXCEL_EVENT_RXFIFO_COMPLETE) { + alloc = can_nxp_s32_get_rx_fifo_filter(data); + + if (alloc != -ENOSPC) { + rx_func = data->rx_cbs[alloc].function; + if (atomic_test_bit(data->rx_allocs, alloc)) { + nxp_s32_msg_data_to_zcan_frame(data->rx_fifo[0], &frame); + + LOG_DBG("%s: Received %d bytes Rx FiFo %d, " + "Rx Id: 0x%x, " + "Id type: %s %s %s %s", + dev->name, can_dlc_to_bytes(frame.dlc), + alloc, frame.id, + !!(frame.flags & CAN_FRAME_IDE) ? + "extended" : "standard", + !!(frame.flags & CAN_FRAME_RTR) ? "RTR" : "", + !!(frame.flags & CAN_FRAME_FDF) ? "FD frame" : "", + !!(frame.flags & CAN_FRAME_BRS) ? "BRS" : ""); + + rx_func(dev, &frame, data->rx_cbs[alloc].arg); + } + } + + /* Pop 1 (= RXFSYSPOP + 1) received RxFIFO message queue */ + config->base_rx_fifo_ctrl->RXFSYSPOP = 0; +#else } else if (eventType == CANEXCEL_EVENT_RX_COMPLETE) { alloc = RX_MBIDX_TO_ALLOC_IDX(buffidx); rx_func = data->rx_cbs[alloc].function; @@ -805,12 +918,12 @@ static void can_nxp_s32_ctrl_callback(const struct device *dev, rx_func(dev, &frame, data->rx_cbs[alloc].arg); - status = Canexcel_Ip_ReceiveFD(config->instance, buffidx, - &data->rx_msg[alloc], FALSE); - if (status != CANEXCEL_STATUS_SUCCESS) { + if (Canexcel_Ip_ReceiveFD(config->instance, buffidx, + &data->rx_msg[alloc], FALSE) != CANEXCEL_STATUS_SUCCESS) { LOG_ERR("MB %d is not ready for receiving next message", buffidx); } } +#endif } } @@ -827,8 +940,8 @@ static int can_nxp_s32_init(const struct device *dev) }; #endif - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -859,9 +972,9 @@ static int can_nxp_s32_init(const struct device *dev) ~(MC_RGM_PRST_0_PERIPH_16_RST_MASK | MC_RGM_PRST_0_PERIPH_24_RST_MASK); data->timing.sjw = config->sjw; - if (config->sample_point) { - err = can_calc_timing(dev, &data->timing, config->bitrate, - config->sample_point); + if (config->common.sample_point) { + err = can_calc_timing(dev, &data->timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -873,20 +986,20 @@ static int can_nxp_s32_init(const struct device *dev) data->timing.prop_seg = config->prop_seg; data->timing.phase_seg1 = config->phase_seg1; data->timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &data->timing, config->bitrate); + err = can_calc_prescaler(dev, &data->timing, config->common.bus_speed); if (err) { LOG_WRN("Bitrate error: %d", err); } } - LOG_DBG("Setting CAN bitrate %d:", config->bitrate); + LOG_DBG("Setting CAN bitrate %d:", config->common.bus_speed); nxp_s32_zcan_timing_to_canxl_timing(&data->timing, &config->can_cfg->bitrate); -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE data->timing_data.sjw = config->sjw_data; - if (config->sample_point_data) { - err = can_calc_timing_data(dev, &data->timing_data, config->bitrate_data, - config->sample_point_data); + if (config->common.sample_point_data) { + err = can_calc_timing_data(dev, &data->timing_data, config->common.bus_speed_data, + config->common.sample_point_data); if (err == -EINVAL) { LOG_ERR("Can't find timing data for given param"); return -EIO; @@ -898,13 +1011,13 @@ static int can_nxp_s32_init(const struct device *dev) data->timing_data.prop_seg = config->prop_seg_data; data->timing_data.phase_seg1 = config->phase_seg1_data; data->timing_data.phase_seg2 = config->phase_seg2_data; - err = can_calc_prescaler(dev, &data->timing_data, config->bitrate_data); + err = can_calc_prescaler(dev, &data->timing_data, config->common.bus_speed_data); if (err) { LOG_WRN("Bitrate data error: %d", err); } } - LOG_DBG("Setting CAN FD bitrate %d:", config->bitrate_data); + LOG_DBG("Setting CAN FD bitrate %d:", config->common.bus_speed_data); nxp_s32_zcan_timing_to_canxl_timing(&data->timing_data, &config->can_cfg->Fd_bitrate); #endif @@ -925,6 +1038,13 @@ static int can_nxp_s32_init(const struct device *dev) CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_ERR, TRUE); CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_BUSOFF, TRUE); CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_PASIVE_ERR, TRUE); +#ifdef CONFIG_CAN_NXP_S32_RX_FIFO + CanXL_SetErrIntCmd(config->base_sic, CANXL_INT_RXFIFO_OVER, TRUE); + + /* Configure number of ID acceptance filters*/ + config->base_rx_fifo->AFCFG = + CANXL_RXFIFO_AFCFG_ACPTID(CONFIG_CAN_NXP_S32_MAX_RX - 1); +#endif config->irq_config_func(); @@ -963,7 +1083,6 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .set_state_change_callback = can_nxp_s32_set_state_change_callback, .get_core_clock = can_nxp_s32_get_core_clock, .get_max_filters = can_nxp_s32_get_max_filters, - .get_max_bitrate = can_nxp_s32_get_max_bitrate, .timing_min = { .sjw = 0x01, .prop_seg = 0x01, @@ -978,7 +1097,7 @@ static const struct can_driver_api can_nxp_s32_driver_api = { .phase_seg2 = 0x08, .prescaler = 0x100 }, -#ifdef CONFIG_CAN_FD_MODE +#ifdef CAN_NXP_S32_FD_MODE .set_timing_data = can_nxp_s32_set_timing_data, .timing_data_min = { .sjw = 0x01, @@ -1030,19 +1149,15 @@ static const struct can_driver_api can_nxp_s32_driver_api = { can_nxp_s32_ctrl_callback(dev, eventType, buffIdx, canexcelState); \ } -#if defined(CONFIG_CAN_FD_MODE) +#if defined(CAN_NXP_S32_FD_MODE) #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .bitrate_data = DT_INST_PROP(n, bus_speed_data), \ .sjw_data = DT_INST_PROP(n, sjw_data), \ .prop_seg_data = DT_INST_PROP_OR(n, prop_seg_data, 0), \ .phase_seg1_data = DT_INST_PROP_OR(n, phase_seg1_data, 0), \ - .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), \ - .sample_point_data = DT_INST_PROP_OR(n, sample_point_data, 0), -#define CAN_NXP_S32_FD_MODE 1 + .phase_seg2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), #define CAN_NXP_S32_BRS 1 #else #define CAN_NXP_S32_TIMING_DATA_CONFIG(n) -#define CAN_NXP_S32_FD_MODE 0 #define CAN_NXP_S32_BRS 0 #endif @@ -1063,44 +1178,67 @@ static const struct can_driver_api can_nxp_s32_driver_api = { CAN_NXP_S32_ERR_CALLBACK(n) \ CAN_NXP_S32_IRQ_CONFIG(n) \ PINCTRL_DT_INST_DEFINE(n); \ + \ + __nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \ + __nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \ + IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (__nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (__nocache Canexcel_RxFdMsg rx_fifo_##n[CAN_NXP_S32_RX_FIFO_DEPTH]; \ + static Canexcel_Ip_RxFifoFilterID_ADDR \ + rx_fifo_filter##n[CONFIG_CAN_NXP_S32_MAX_RX];)) \ Canexcel_Ip_ConfigType can_nxp_s32_default_config##n = { \ - .rx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_RX, \ + .rx_mbdesc = (uint8)IS_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO) ? \ + 0 : CONFIG_CAN_NXP_S32_MAX_RX, \ .tx_mbdesc = (uint8)CONFIG_CAN_NXP_S32_MAX_TX, \ .CanxlMode = CANEXCEL_LISTEN_ONLY_MODE, \ - .fd_enable = (boolean)CAN_NXP_S32_FD_MODE, \ + .fd_enable = (boolean)IS_ENABLED(CAN_NXP_S32_FD_MODE), \ .bitRateSwitch = (boolean)CAN_NXP_S32_BRS, \ .ctrlOptions = (uint32)CAN_NXP_S32_CTRL_OPTIONS, \ .Callback = nxp_s32_can_##n##_ctrl_callback, \ - .ErrorCallback = nxp_s32_can_##n##_err_callback \ + .ErrorCallback = nxp_s32_can_##n##_err_callback, \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.is_rx_fifo_needed = (boolean)TRUE, \ + .pRxFifoConfig = { \ + .Rx_Fifo_Depth = CAN_NXP_S32_RX_FIFO_DEPTH, \ + .Rx_Fifo_Watermark = CAN_NXP_S32_RX_FIFO_WATERMARK, \ + .Rx_Fifo_Msg_Size = CAN_NXP_S32_DATA_LENGTH, \ + .Rx_Fifo_KeepLast = (boolean)FALSE, \ + .isPolling = (boolean)FALSE, \ + .MsgBuffersPtr = (uint32 *)rx_fifo_##n, \ + },)) \ }; \ - __nocache Canexcel_Ip_StateType can_nxp_s32_state##n; \ - __nocache Canexcel_TxFdMsgType tx_msg##n[CONFIG_CAN_NXP_S32_MAX_TX]; \ - __nocache Canexcel_RxFdMsg rx_msg_##n[CONFIG_CAN_NXP_S32_MAX_RX]; \ static struct can_nxp_s32_data can_nxp_s32_data_##n = { \ .can_state = (Canexcel_Ip_StateType *)&can_nxp_s32_state##n, \ .tx_msg = tx_msg##n, \ - .rx_msg = rx_msg_##n, \ + IF_DISABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.rx_msg = rx_msg_##n,)) \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.rx_fifo = rx_fifo_##n, \ + .rx_fifo_filter = \ + (Canexcel_Ip_RxFifoFilterID_ADDR *)&rx_fifo_filter##n,))\ }; \ static struct can_nxp_s32_config can_nxp_s32_config_##n = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(n, CAN_NXP_S32_MAX_BITRATE), \ .base_sic = (CANXL_SIC_Type *)DT_INST_REG_ADDR_BY_NAME(n, sic), \ .base_grp_ctrl = (CANXL_GRP_CONTROL_Type *) \ DT_INST_REG_ADDR_BY_NAME(n, grp_ctrl), \ .base_dsc_ctrl = (CANXL_DSC_CONTROL_Type *) \ DT_INST_REG_ADDR_BY_NAME(n, dsc_ctrl), \ + IF_ENABLED(CONFIG_CAN_NXP_S32_RX_FIFO, \ + (.base_rx_fifo = (CANXL_RXFIFO_Type *) \ + DT_INST_REG_ADDR_BY_NAME(n, rx_fifo), \ + .base_rx_fifo_ctrl = (CANXL_RXFIFO_CONTROL_Type *) \ + DT_INST_REG_ADDR_BY_NAME(n, rx_fifo_ctrl),)) \ .instance = CAN_NXP_S32_HW_INSTANCE(n), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = (clock_control_subsys_t) \ DT_INST_CLOCKS_CELL(n, name), \ - .bitrate = DT_INST_PROP(n, bus_speed), \ .sjw = DT_INST_PROP(n, sjw), \ .prop_seg = DT_INST_PROP_OR(n, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(n, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(n, sample_point, 0), \ CAN_NXP_S32_TIMING_DATA_CONFIG(n) \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, \ - CAN_NXP_S32_MAX_BITRATE), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ .pin_cfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .can_cfg = (Canexcel_Ip_ConfigType *)&can_nxp_s32_default_config##n, \ .irq_config_func = can_irq_config_##n \ diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index f015407c22f..55bbdb981d9 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -166,21 +166,18 @@ LOG_MODULE_REGISTER(can_rcar, CONFIG_CAN_LOG_LEVEL); typedef void (*init_func_t)(const struct device *dev); struct can_rcar_cfg { + const struct can_driver_config common; uint32_t reg_addr; int reg_size; init_func_t init_func; const struct device *clock_dev; struct rcar_cpg_clk mod_clk; struct rcar_cpg_clk bus_clk; - uint32_t bus_speed; uint8_t sjw; uint8_t prop_seg; uint8_t phase_seg1; uint8_t phase_seg2; - uint16_t sample_point; const struct pinctrl_dev_config *pcfg; - const struct device *phy; - uint32_t max_bitrate; }; struct can_rcar_tx_cb { @@ -189,6 +186,7 @@ struct can_rcar_tx_cb { }; struct can_rcar_data { + struct can_driver_data common; struct k_mutex inst_mutex; struct k_sem tx_sem; struct can_rcar_tx_cb tx_cb[RCAR_CAN_FIFO_DEPTH]; @@ -199,10 +197,7 @@ struct can_rcar_data { can_rx_callback_t rx_callback[CONFIG_CAN_RCAR_MAX_FILTER]; void *rx_callback_arg[CONFIG_CAN_RCAR_MAX_FILTER]; struct can_filter filter[CONFIG_CAN_RCAR_MAX_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; enum can_state state; - bool started; }; static inline uint16_t can_rcar_read16(const struct can_rcar_cfg *config, @@ -244,8 +239,8 @@ static void can_rcar_state_change(const struct device *dev, uint32_t newstate) { const struct can_rcar_cfg *config = dev->config; struct can_rcar_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *state_change_cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *state_change_cb_data = data->common.state_change_cb_user_data; struct can_bus_err_cnt err_cnt; if (data->state == newstate) { @@ -367,6 +362,12 @@ static void can_rcar_rx_filter_isr(const struct device *dev, struct can_frame tmp_frame; uint8_t i; +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame->flags & CAN_FRAME_RTR) != 0U) { + return; + } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + for (i = 0; i < CONFIG_CAN_RCAR_MAX_FILTER; i++) { if (data->rx_callback[i] == NULL) { continue; @@ -578,12 +579,12 @@ static int can_rcar_start(const struct device *dev) struct can_rcar_data *data = dev->data; int ret; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - ret = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + ret = can_transceiver_enable(config->common.phy, data->common.mode); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); return ret; @@ -598,12 +599,12 @@ static int can_rcar_start(const struct device *dev) if (ret != 0) { LOG_ERR("failed to enter operation mode (err %d)", ret); - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } } else { - data->started = true; + data->common.started = true; } k_mutex_unlock(&data->inst_mutex); @@ -617,7 +618,7 @@ static int can_rcar_stop(const struct device *dev) struct can_rcar_data *data = dev->data; int ret; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -630,12 +631,12 @@ static int can_rcar_stop(const struct device *dev) return ret; } - data->started = false; + data->common.started = false; k_mutex_unlock(&data->inst_mutex); - if (config->phy != NULL) { - ret = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + ret = can_transceiver_disable(config->common.phy); if (ret != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", ret); return ret; @@ -666,7 +667,7 @@ static int can_rcar_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -690,6 +691,8 @@ static int can_rcar_set_mode(const struct device *dev, can_mode_t mode) sys_write8(tcr, config->reg_addr + RCAR_CAN_TCR); + data->common.mode = mode; + unlock: k_mutex_unlock(&data->inst_mutex); @@ -735,7 +738,7 @@ static int can_rcar_set_timing(const struct device *dev, struct reg_backup regs[3] = { { RCAR_CAN_TCR, 0 }, { RCAR_CAN_TFCR, 0 } , { RCAR_CAN_RFCR, 0 } }; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -781,8 +784,8 @@ static void can_rcar_set_state_change_callback(const struct device *dev, { struct can_rcar_data *data = dev->data; - data->state_change_cb = cb; - data->state_change_cb_data = user_data; + data->common.state_change_cb = cb; + data->common.state_change_cb_user_data = user_data; } static int can_rcar_get_state(const struct device *dev, enum can_state *state, @@ -792,7 +795,7 @@ static int can_rcar_get_state(const struct device *dev, enum can_state *state, struct can_rcar_data *data = dev->data; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { *state = data->state; @@ -814,7 +817,7 @@ static int can_rcar_recover(const struct device *dev, k_timeout_t timeout) int64_t start_time; int ret; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -880,7 +883,7 @@ static int can_rcar_send(const struct device *dev, const struct can_frame *frame return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -960,7 +963,7 @@ static int can_rcar_add_rx_filter(const struct device *dev, can_rx_callback_t cb struct can_rcar_data *data = dev->data; int filter_id; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -1004,11 +1007,11 @@ static int can_rcar_init(const struct device *dev) memset(data->rx_callback, 0, sizeof(data->rx_callback)); data->state = CAN_STATE_ERROR_ACTIVE; - data->state_change_cb = NULL; - data->state_change_cb_data = NULL; + data->common.state_change_cb = NULL; + data->common.state_change_cb_user_data = NULL; - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -1056,9 +1059,9 @@ static int can_rcar_init(const struct device *dev) return ret; } - if (config->sample_point) { - ret = can_calc_timing(dev, &timing, config->bus_speed, - config->sample_point); + if (config->common.sample_point) { + ret = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -1071,7 +1074,7 @@ static int can_rcar_init(const struct device *dev) timing.prop_seg = config->prop_seg; timing.phase_seg1 = config->phase_seg1; timing.phase_seg2 = config->phase_seg2; - ret = can_calc_prescaler(dev, &timing, config->bus_speed); + ret = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -1143,15 +1146,6 @@ static int can_rcar_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_RCAR_MAX_FILTER; } -static int can_rcar_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_rcar_cfg *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; -} - static const struct can_driver_api can_rcar_driver_api = { .get_capabilities = can_rcar_get_capabilities, .start = can_rcar_start, @@ -1168,7 +1162,6 @@ static const struct can_driver_api can_rcar_driver_api = { .set_state_change_callback = can_rcar_set_state_change_callback, .get_core_clock = can_rcar_get_core_clock, .get_max_filters = can_rcar_get_max_filters, - .get_max_bitrate = can_rcar_get_max_bitrate, .timing_min = { .sjw = 0x1, .prop_seg = 0x00, @@ -1190,6 +1183,7 @@ static const struct can_driver_api can_rcar_driver_api = { PINCTRL_DT_INST_DEFINE(n); \ static void can_rcar_##n##_init(const struct device *dev); \ static const struct can_rcar_cfg can_rcar_cfg_##n = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(n, 1000000), \ .reg_addr = DT_INST_REG_ADDR(n), \ .reg_size = DT_INST_REG_SIZE(n), \ .init_func = can_rcar_##n##_init, \ @@ -1203,15 +1197,11 @@ static const struct can_driver_api can_rcar_driver_api = { .bus_clk.domain = \ DT_INST_CLOCKS_CELL_BY_IDX(n, 1, domain), \ .bus_clk.rate = 40000000, \ - .bus_speed = DT_INST_PROP(n, bus_speed), \ .sjw = DT_INST_PROP(n, sjw), \ .prop_seg = DT_INST_PROP_OR(n, prop_seg, 0), \ .phase_seg1 = DT_INST_PROP_OR(n, phase_seg1, 0), \ .phase_seg2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ - .sample_point = DT_INST_PROP_OR(n, sample_point, 0), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 1000000), \ }; \ static struct can_rcar_data can_rcar_data_##n; \ \ diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index e081e57c794..4f0f32bce91 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -131,7 +131,6 @@ static const struct can_driver_api can_sam_driver_api = { #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_sam_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, @@ -154,14 +153,14 @@ static const struct can_mcan_ops can_sam_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN##inst## IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), can_mcan_line_0_isr, \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), can_mcan_line_0_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_1, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_1, priority), can_mcan_line_1_isr, \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), can_mcan_line_1_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } #define CAN_SAM_CFG_INST(inst) \ diff --git a/drivers/can/can_sam0.c b/drivers/can/can_sam0.c index ac322fe936e..0a8bacda05c 100644 --- a/drivers/can/can_sam0.c +++ b/drivers/can/can_sam0.c @@ -2,6 +2,7 @@ * Copyright (c) 2022 Vestas Wind Systems A/S * Copyright (c) 2021 Alexander Wachter * Copyright (c) 2022 Kamil Serwus + * Copyright (c) 2023 Sebastian Schlupp * * SPDX-License-Identifier: Apache-2.0 */ @@ -95,7 +96,13 @@ static int can_sam0_get_core_clock(const struct device *dev, uint32_t *rate) const struct can_mcan_config *mcan_cfg = dev->config; const struct can_sam0_config *sam_cfg = mcan_cfg->custom; +#if defined(CONFIG_SOC_SERIES_SAME51) || defined(CONFIG_SOC_SERIES_SAME54) + /*DFFL has to be used as clock source for the ATSAME51/54 family of SoCs*/ + *rate = SOC_ATMEL_SAM0_DFLL48_FREQ_HZ / (sam_cfg->divider); +#elif defined(CONFIG_SOC_SERIES_SAMC21) + /*OSC48M has to be used as clock source for the ATSAMC21 family of SoCs*/ *rate = SOC_ATMEL_SAM0_OSC48M_FREQ_HZ / (sam_cfg->divider); +#endif return 0; } @@ -103,9 +110,17 @@ static int can_sam0_get_core_clock(const struct device *dev, uint32_t *rate) static void can_sam0_clock_enable(const struct can_sam0_config *cfg) { /* Enable the GLCK7 with DIV*/ +#if defined(CONFIG_SOC_SERIES_SAME51) || defined(CONFIG_SOC_SERIES_SAME54) + /*DFFL has to be used as clock source for the ATSAME51/54 family of SoCs*/ + GCLK->GENCTRL[7].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) + | GCLK_GENCTRL_DIV(cfg->divider) + | GCLK_GENCTRL_GENEN; +#elif defined(CONFIG_SOC_SERIES_SAMC21) + /*OSC48M has to be used as clock source for the ATSAMC21 family of SoCs*/ GCLK->GENCTRL[7].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSC48M) | GCLK_GENCTRL_DIV(cfg->divider) | GCLK_GENCTRL_GENEN; +#endif /* Route channel */ GCLK->PCHCTRL[cfg->gclk_core_id].reg = GCLK_PCHCTRL_GEN_GCLK7 @@ -161,7 +176,6 @@ static const struct can_driver_api can_sam0_driver_api = { #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_sam0_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, @@ -184,10 +198,10 @@ static const struct can_mcan_ops can_sam0_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN##inst## IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), can_sam0_line_x_isr, \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), can_sam0_line_x_isr, \ DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ } #define CAN_SAM0_CFG_INST(inst) \ diff --git a/drivers/can/can_shell.c b/drivers/can/can_shell.c index 46dac3fb06a..3bb74f9552c 100644 --- a/drivers/can/can_shell.c +++ b/drivers/can/can_shell.c @@ -202,7 +202,7 @@ static const char *can_shell_state_to_string(enum can_state state) } } -static void can_shell_print_capabilities(const struct shell *sh, can_mode_t cap) +static void can_shell_print_extended_modes(const struct shell *sh, can_mode_t cap) { int bit; int i; @@ -273,6 +273,7 @@ static int cmd_can_stop(const struct shell *sh, size_t argc, char **argv) static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); + const struct device *phy; const struct can_timing *timing_min; const struct can_timing *timing_max; struct can_bus_err_cnt err_cnt; @@ -331,7 +332,11 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) shell_print(sh, "max ext filters: %d", max_ext_filters); shell_fprintf(sh, SHELL_NORMAL, "capabilities: normal "); - can_shell_print_capabilities(sh, cap); + can_shell_print_extended_modes(sh, cap); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + shell_fprintf(sh, SHELL_NORMAL, "mode: normal "); + can_shell_print_extended_modes(sh, can_get_mode(dev)); shell_fprintf(sh, SHELL_NORMAL, "\n"); shell_print(sh, "state: %s", can_shell_state_to_string(state)); @@ -362,6 +367,9 @@ static int cmd_can_show(const struct shell *sh, size_t argc, char **argv) timing_min->prescaler, timing_max->prescaler); } + phy = can_get_transceiver(dev); + shell_print(sh, "transceiver: %s", phy != NULL ? phy->name : "passive/none"); + #ifdef CONFIG_CAN_STATS shell_print(sh, "statistics:"); shell_print(sh, " bit errors: %u", can_stats_get_bit_errors(dev)); @@ -801,7 +809,7 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) /* Defaults */ max_id = CAN_MAX_STD_ID; - filter.flags = CAN_FILTER_DATA; + filter.flags = 0U; /* Parse options */ while (argidx < argc && strncmp(argv[argidx], "-", 1) == 0) { @@ -812,16 +820,6 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) filter.flags |= CAN_FILTER_IDE; max_id = CAN_MAX_EXT_ID; argidx++; - } else if (strcmp(argv[argidx], "-f") == 0) { - filter.flags |= CAN_FILTER_FDF; - argidx++; - } else if (strcmp(argv[argidx], "-r") == 0) { - filter.flags |= CAN_FILTER_RTR; - argidx++; - } else if (strcmp(argv[argidx], "-R") == 0) { - filter.flags &= ~(CAN_FILTER_DATA); - filter.flags |= CAN_FILTER_RTR; - argidx++; } else { shell_error(sh, "unsupported argument %s", argv[argidx]); shell_help(sh); @@ -877,15 +875,11 @@ static int cmd_can_filter_add(const struct shell *sh, size_t argc, char **argv) return err; } - shell_print(sh, "adding filter with %s (%d-bit) CAN ID 0x%0*x, " - "CAN ID mask 0x%0*x, data frames %d, RTR frames %d, CAN FD frames %d", + shell_print(sh, "adding filter with %s (%d-bit) CAN ID 0x%0*x, CAN ID mask 0x%0*x", (filter.flags & CAN_FILTER_IDE) != 0 ? "extended" : "standard", (filter.flags & CAN_FILTER_IDE) != 0 ? 29 : 11, (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.id, - (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.mask, - (filter.flags & CAN_FILTER_DATA) != 0 ? 1 : 0, - (filter.flags & CAN_FILTER_RTR) != 0 ? 1 : 0, - (filter.flags & CAN_FILTER_FDF) != 0 ? 1 : 0); + (filter.flags & CAN_FILTER_IDE) != 0 ? 8 : 3, filter.mask); err = can_add_rx_filter_msgq(dev, &can_shell_rx_msgq, &filter); if (err < 0) { @@ -1003,12 +997,9 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_can_device_name_mode, cmd_can_device_name_mode); SHELL_STATIC_SUBCMD_SET_CREATE(sub_can_filter_cmds, SHELL_CMD_ARG(add, &dsub_can_device_name, "Add rx filter\n" - "Usage: can filter add [-e] [-f] [-r] [-R] [CAN ID mask]\n" - "-e use extended (29-bit) CAN ID/CAN ID mask\n" - "-f match CAN FD format frames\n" - "-r also match Remote Transmission Request (RTR) frames\n" - "-R only match Remote Transmission Request (RTR) frames", - cmd_can_filter_add, 3, 5), + "Usage: can filter add [-e] [CAN ID mask]\n" + "-e use extended (29-bit) CAN ID/CAN ID mask\n", + cmd_can_filter_add, 3, 2), SHELL_CMD_ARG(remove, &dsub_can_device_name, "Remove rx filter\n" "Usage: can filter remove ", diff --git a/drivers/can/can_sja1000.c b/drivers/can/can_sja1000.c index 571fc2fb040..c764251f628 100644 --- a/drivers/can/can_sja1000.c +++ b/drivers/can/can_sja1000.c @@ -111,7 +111,7 @@ int can_sja1000_set_timing(const struct device *dev, const struct can_timing *ti uint8_t btr0; uint8_t btr1; - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -122,7 +122,7 @@ int can_sja1000_set_timing(const struct device *dev, const struct can_timing *ti btr1 = CAN_SJA1000_BTR1_TSEG1_PREP(timing->phase_seg1 - 1) | CAN_SJA1000_BTR1_TSEG2_PREP(timing->phase_seg2 - 1); - if ((data->mode & CAN_MODE_3_SAMPLES) != 0) { + if ((data->common.mode & CAN_MODE_3_SAMPLES) != 0) { btr1 |= CAN_SJA1000_BTR1_SAM; } @@ -150,12 +150,12 @@ int can_sja1000_start(const struct device *dev) struct can_sja1000_data *data = dev->data; int err; - if (data->started) { + if (data->common.started) { return -EALREADY; } - if (config->phy != NULL) { - err = can_transceiver_enable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_enable(config->common.phy, data->common.mode); if (err != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", err); return err; @@ -167,15 +167,15 @@ int can_sja1000_start(const struct device *dev) err = can_sja1000_leave_reset_mode(dev); if (err != 0) { - if (config->phy != NULL) { + if (config->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(config->phy); + (void)can_transceiver_disable(config->common.phy); } return err; } - data->started = true; + data->common.started = true; return 0; } @@ -186,7 +186,7 @@ int can_sja1000_stop(const struct device *dev) struct can_sja1000_data *data = dev->data; int err; - if (!data->started) { + if (!data->common.started) { return -EALREADY; } @@ -196,15 +196,15 @@ int can_sja1000_stop(const struct device *dev) return err; } - if (config->phy != NULL) { - err = can_transceiver_disable(config->phy); + if (config->common.phy != NULL) { + err = can_transceiver_disable(config->common.phy); if (err != 0) { LOG_ERR("failed to disable CAN transceiver (err %d)", err); return err; } } - data->started = false; + data->common.started = false; can_sja1000_tx_done(dev, -ENETDOWN); @@ -223,7 +223,7 @@ int can_sja1000_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -255,7 +255,7 @@ int can_sja1000_set_mode(const struct device *dev, can_mode_t mode) can_sja1000_write_reg(dev, CAN_SJA1000_MOD, mod); can_sja1000_write_reg(dev, CAN_SJA1000_BTR1, btr1); - data->mode = mode; + data->common.mode = mode; k_mutex_unlock(&data->mod_lock); @@ -381,7 +381,7 @@ int can_sja1000_send(const struct device *dev, const struct can_frame *frame, k_ return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -405,13 +405,13 @@ int can_sja1000_send(const struct device *dev, const struct can_frame *frame, k_ can_sja1000_write_frame(dev, frame); - if ((data->mode & CAN_MODE_LOOPBACK) != 0) { + if ((data->common.mode & CAN_MODE_LOOPBACK) != 0) { cmr = CAN_SJA1000_CMR_SRR; } else { cmr = CAN_SJA1000_CMR_TR; } - if ((data->mode & CAN_MODE_ONE_SHOT) != 0) { + if ((data->common.mode & CAN_MODE_ONE_SHOT) != 0) { cmr |= CAN_SJA1000_CMR_AT; } @@ -427,7 +427,7 @@ int can_sja1000_add_rx_filter(const struct device *dev, can_rx_callback_t callba int filter_id = -ENOSPC; int i; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -472,7 +472,7 @@ int can_sja1000_recover(const struct device *dev, k_timeout_t timeout) uint8_t sr; int err; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -517,7 +517,7 @@ int can_sja1000_get_state(const struct device *dev, enum can_state *state, struct can_sja1000_data *data = dev->data; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else { *state = data->state; @@ -537,8 +537,8 @@ void can_sja1000_set_state_change_callback(const struct device *dev, { struct can_sja1000_data *data = dev->data; - data->state_change_cb = callback; - data->state_change_cb_data = user_data; + data->common.state_change_cb = callback; + data->common.state_change_cb_user_data = user_data; } int can_sja1000_get_max_filters(const struct device *dev, bool ide) @@ -549,15 +549,6 @@ int can_sja1000_get_max_filters(const struct device *dev, bool ide) return CONFIG_CAN_MAX_FILTER; } -int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_sja1000_config *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; -} - static void can_sja1000_handle_receive_irq(const struct device *dev) { struct can_sja1000_data *data = dev->data; @@ -569,18 +560,24 @@ static void can_sja1000_handle_receive_irq(const struct device *dev) do { can_sja1000_read_frame(dev, &frame); - for (i = 0; i < ARRAY_SIZE(data->filters); i++) { - if (!atomic_test_bit(data->rx_allocs, i)) { - continue; - } +#ifndef CONFIG_CAN_ACCEPT_RTR + if ((frame.flags & CAN_FRAME_RTR) == 0U) { +#endif /* !CONFIG_CAN_ACCEPT_RTR */ + for (i = 0; i < ARRAY_SIZE(data->filters); i++) { + if (!atomic_test_bit(data->rx_allocs, i)) { + continue; + } - if (can_frame_matches_filter(&frame, &data->filters[i].filter)) { - callback = data->filters[i].callback; - if (callback != NULL) { - callback(dev, &frame, data->filters[i].user_data); + if (can_frame_matches_filter(&frame, &data->filters[i].filter)) { + callback = data->filters[i].callback; + if (callback != NULL) { + callback(dev, &frame, data->filters[i].user_data); + } } } +#ifndef CONFIG_CAN_ACCEPT_RTR } +#endif /* !CONFIG_CAN_ACCEPT_RTR */ can_sja1000_write_reg(dev, CAN_SJA1000_CMR, CAN_SJA1000_CMR_RRB); sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR); @@ -663,7 +660,7 @@ static void can_sja1000_handle_error_warning_irq(const struct device *dev) data->state = CAN_STATE_BUS_OFF; can_sja1000_tx_done(dev, -ENETUNREACH); #ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY - if (data->started) { + if (data->common.started) { can_sja1000_leave_reset_mode_nowait(dev); } #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ @@ -688,8 +685,8 @@ static void can_sja1000_handle_error_passive_irq(const struct device *dev) void can_sja1000_isr(const struct device *dev) { struct can_sja1000_data *data = dev->data; - const can_state_change_callback_t cb = data->state_change_cb; - void *cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *cb_data = data->common.state_change_cb_user_data; enum can_state prev_state = data->state; struct can_bus_err_cnt err_cnt; uint8_t ir; @@ -739,8 +736,8 @@ int can_sja1000_init(const struct device *dev) __ASSERT_NO_MSG(config->read_reg != NULL); __ASSERT_NO_MSG(config->write_reg != NULL); - if (config->phy != NULL) { - if (!device_is_ready(config->phy)) { + if (config->common.phy != NULL) { + if (!device_is_ready(config->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -773,8 +770,9 @@ int can_sja1000_init(const struct device *dev) can_sja1000_write_reg(dev, CAN_SJA1000_AMR2, 0xFF); can_sja1000_write_reg(dev, CAN_SJA1000_AMR3, 0xFF); - if (config->sample_point != 0) { - err = can_calc_timing(dev, &timing, config->bitrate, config->sample_point); + if (config->common.sample_point != 0) { + err = can_calc_timing(dev, &timing, config->common.bus_speed, + config->common.sample_point); if (err == -EINVAL) { LOG_ERR("bitrate/sample point cannot be met (err %d)", err); return err; @@ -787,7 +785,7 @@ int can_sja1000_init(const struct device *dev) timing.phase_seg1 = config->phase_seg1; timing.phase_seg2 = config->phase_seg2; - err = can_calc_prescaler(dev, &timing, config->bitrate); + err = can_calc_prescaler(dev, &timing, config->common.bus_speed); if (err != 0) { LOG_WRN("initial bitrate error: %d", err); } @@ -810,7 +808,7 @@ int can_sja1000_init(const struct device *dev) can_sja1000_write_reg(dev, CAN_SJA1000_EWLR, 96); /* Set normal mode */ - data->mode = CAN_MODE_NORMAL; + data->common.mode = CAN_MODE_NORMAL; err = can_sja1000_set_mode(dev, CAN_MODE_NORMAL); if (err != 0) { return err; diff --git a/drivers/can/can_stm32_bxcan.c b/drivers/can/can_stm32_bxcan.c index 58df8f1db5d..557079e2e3c 100644 --- a/drivers/can/can_stm32_bxcan.c +++ b/drivers/can/can_stm32_bxcan.c @@ -5,19 +5,18 @@ * SPDX-License-Identifier: Apache-2.0 */ +/* Include soc.h prior to Zephyr CAN headers to pull in HAL fixups */ +#include +#include #include -#include + #include +#include #include -#include -#include +#include #include -#include -#include -#include -#include #include -#include +#include LOG_MODULE_REGISTER(can_stm32, CONFIG_CAN_LOG_LEVEL); @@ -66,6 +65,7 @@ struct can_stm32_mailbox { }; struct can_stm32_data { + struct can_driver_data common; struct k_mutex inst_mutex; struct k_sem tx_int_sem; struct can_stm32_mailbox mb0; @@ -75,25 +75,19 @@ struct can_stm32_data { can_rx_callback_t rx_cb_ext[CONFIG_CAN_MAX_EXT_ID_FILTER]; void *cb_arg_std[CONFIG_CAN_MAX_STD_ID_FILTER]; void *cb_arg_ext[CONFIG_CAN_MAX_EXT_ID_FILTER]; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; enum can_state state; - bool started; }; struct can_stm32_config { + const struct can_driver_config common; CAN_TypeDef *can; /*!< CAN Registers*/ CAN_TypeDef *master_can; /*!< CAN Registers for shared filter */ - uint32_t bus_speed; - uint16_t sample_point; uint8_t sjw; uint8_t prop_ts1; uint8_t ts2; struct stm32_pclken pclken; void (*config_irq)(CAN_TypeDef *can); const struct pinctrl_dev_config *pcfg; - const struct device *phy; - uint32_t max_bitrate; }; /* @@ -187,7 +181,7 @@ static int can_stm32_get_state(const struct device *dev, enum can_state *state, CAN_TypeDef *can = cfg->can; if (state != NULL) { - if (!data->started) { + if (!data->common.started) { *state = CAN_STATE_STOPPED; } else if (can->ESR & CAN_ESR_BOFF) { *state = CAN_STATE_BUS_OFF; @@ -215,8 +209,8 @@ static inline void can_stm32_bus_state_change_isr(const struct device *dev) struct can_stm32_data *data = dev->data; struct can_bus_err_cnt err_cnt; enum can_state state; - const can_state_change_callback_t cb = data->state_change_cb; - void *state_change_cb_data = data->state_change_cb_data; + const can_state_change_callback_t cb = data->common.state_change_cb; + void *state_change_cb_data = data->common.state_change_cb_user_data; #ifdef CONFIG_CAN_STATS const struct can_stm32_config *cfg = dev->config; @@ -418,13 +412,13 @@ static int can_stm32_start(const struct device *dev) k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (data->started) { + if (data->common.started) { ret = -EALREADY; goto unlock; } - if (cfg->phy != NULL) { - ret = can_transceiver_enable(cfg->phy); + if (cfg->common.phy != NULL) { + ret = can_transceiver_enable(cfg->common.phy, data->common.mode); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); goto unlock; @@ -437,16 +431,16 @@ static int can_stm32_start(const struct device *dev) if (ret < 0) { LOG_ERR("Failed to leave init mode"); - if (cfg->phy != NULL) { + if (cfg->common.phy != NULL) { /* Attempt to disable the CAN transceiver in case of error */ - (void)can_transceiver_disable(cfg->phy); + (void)can_transceiver_disable(cfg->common.phy); } ret = -EIO; goto unlock; } - data->started = true; + data->common.started = true; unlock: k_mutex_unlock(&data->inst_mutex); @@ -463,7 +457,7 @@ static int can_stm32_stop(const struct device *dev) k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (!data->started) { + if (!data->common.started) { ret = -EALREADY; goto unlock; } @@ -481,15 +475,15 @@ static int can_stm32_stop(const struct device *dev) can_stm32_signal_tx_complete(dev, &data->mb2, -ENETDOWN); can->TSR |= CAN_TSR_ABRQ2 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ0; - if (cfg->phy != NULL) { - ret = can_transceiver_disable(cfg->phy); + if (cfg->common.phy != NULL) { + ret = can_transceiver_disable(cfg->common.phy); if (ret != 0) { LOG_ERR("failed to enable CAN transceiver (err %d)", ret); goto unlock; } } - data->started = false; + data->common.started = false; unlock: k_mutex_unlock(&data->inst_mutex); @@ -510,7 +504,7 @@ static int can_stm32_set_mode(const struct device *dev, can_mode_t mode) return -ENOTSUP; } - if (data->started) { + if (data->common.started) { return -EBUSY; } @@ -537,6 +531,8 @@ static int can_stm32_set_mode(const struct device *dev, can_mode_t mode) can->MCR &= ~CAN_MCR_NART; } + data->common.mode = mode; + k_mutex_unlock(&data->inst_mutex); return 0; @@ -551,7 +547,7 @@ static int can_stm32_set_timing(const struct device *dev, k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (data->started) { + if (data->common.started) { k_mutex_unlock(&data->inst_mutex); return -EBUSY; } @@ -587,15 +583,6 @@ static int can_stm32_get_core_clock(const struct device *dev, uint32_t *rate) return 0; } -static int can_stm32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) -{ - const struct can_stm32_config *config = dev->config; - - *max_bitrate = config->max_bitrate; - - return 0; -} - static int can_stm32_get_max_filters(const struct device *dev, bool ide) { ARG_UNUSED(dev); @@ -621,8 +608,8 @@ static int can_stm32_init(const struct device *dev) k_mutex_init(&data->inst_mutex); k_sem_init(&data->tx_int_sem, 0, 1); - if (cfg->phy != NULL) { - if (!device_is_ready(cfg->phy)) { + if (cfg->common.phy != NULL) { + if (!device_is_ready(cfg->common.phy)) { LOG_ERR("CAN transceiver not ready"); return -ENODEV; } @@ -673,9 +660,9 @@ static int can_stm32_init(const struct device *dev) #ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY can->MCR |= CAN_MCR_ABOM; #endif - if (cfg->sample_point && USE_SP_ALGO) { - ret = can_calc_timing(dev, &timing, cfg->bus_speed, - cfg->sample_point); + if (cfg->common.sample_point && USE_SP_ALGO) { + ret = can_calc_timing(dev, &timing, cfg->common.bus_speed, + cfg->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); return -EIO; @@ -688,7 +675,7 @@ static int can_stm32_init(const struct device *dev) timing.prop_seg = 0; timing.phase_seg1 = cfg->prop_ts1; timing.phase_seg2 = cfg->ts2; - ret = can_calc_prescaler(dev, &timing, cfg->bus_speed); + ret = can_calc_prescaler(dev, &timing, cfg->common.bus_speed); if (ret) { LOG_WRN("Bitrate error: %d", ret); } @@ -720,8 +707,8 @@ static void can_stm32_set_state_change_callback(const struct device *dev, const struct can_stm32_config *cfg = dev->config; CAN_TypeDef *can = cfg->can; - data->state_change_cb = cb; - data->state_change_cb_data = user_data; + data->common.state_change_cb = cb; + data->common.state_change_cb_user_data = user_data; if (cb == NULL) { can->IER &= ~(CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE); @@ -739,7 +726,7 @@ static int can_stm32_recover(const struct device *dev, k_timeout_t timeout) int ret = -EAGAIN; int64_t start_time; - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -809,7 +796,7 @@ static int can_stm32_send(const struct device *dev, const struct can_frame *fram return -ENOTSUP; } - if (!data->started) { + if (!data->common.started) { return -ENETDOWN; } @@ -891,8 +878,7 @@ static void can_stm32_set_filter_bank(int filter_id, CAN_FilterRegister_TypeDef static inline uint32_t can_stm32_filter_to_std_mask(const struct can_filter *filter) { - uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); return (filter->mask << CAN_STM32_FIRX_STD_ID_POS) | (rtr_mask << CAN_STM32_FIRX_STD_RTR_POS) | @@ -901,8 +887,7 @@ static inline uint32_t can_stm32_filter_to_std_mask(const struct can_filter *fil static inline uint32_t can_stm32_filter_to_ext_mask(const struct can_filter *filter) { - uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U; + uint32_t rtr_mask = !IS_ENABLED(CONFIG_CAN_ACCEPT_RTR); return (filter->mask << CAN_STM32_FIRX_EXT_EXT_ID_POS) | (rtr_mask << CAN_STM32_FIRX_EXT_RTR_POS) | @@ -911,15 +896,12 @@ static inline uint32_t can_stm32_filter_to_ext_mask(const struct can_filter *fil static inline uint32_t can_stm32_filter_to_std_id(const struct can_filter *filter) { - return (filter->id << CAN_STM32_FIRX_STD_ID_POS) | - (((filter->flags & CAN_FILTER_RTR) != 0) ? (1U << CAN_STM32_FIRX_STD_RTR_POS) : 0U); + return (filter->id << CAN_STM32_FIRX_STD_ID_POS); } static inline uint32_t can_stm32_filter_to_ext_id(const struct can_filter *filter) { return (filter->id << CAN_STM32_FIRX_EXT_EXT_ID_POS) | - (((filter->flags & CAN_FILTER_RTR) != 0) ? - (1U << CAN_STM32_FIRX_EXT_RTR_POS) : 0U) | (1U << CAN_STM32_FIRX_EXT_IDE_POS); } @@ -1000,7 +982,7 @@ static int can_stm32_add_rx_filter(const struct device *dev, can_rx_callback_t c struct can_stm32_data *data = dev->data; int filter_id; - if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) { + if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } @@ -1107,7 +1089,6 @@ static const struct can_driver_api can_api_funcs = { #endif .set_state_change_callback = can_stm32_set_state_change_callback, .get_core_clock = can_stm32_get_core_clock, - .get_max_bitrate = can_stm32_get_max_bitrate, .get_max_filters = can_stm32_get_max_filters, .timing_min = { .sjw = 0x1, @@ -1167,11 +1148,10 @@ static void config_can_##inst##_irq(CAN_TypeDef *can) \ #define CAN_STM32_CONFIG_INST(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ static const struct can_stm32_config can_stm32_cfg_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ .can = (CAN_TypeDef *)DT_INST_REG_ADDR(inst), \ .master_can = (CAN_TypeDef *)DT_INST_PROP_OR(inst, \ master_can_reg, DT_INST_REG_ADDR(inst)), \ - .bus_speed = DT_INST_PROP(inst, bus_speed), \ - .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ .sjw = DT_INST_PROP_OR(inst, sjw, 1), \ .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \ DT_INST_PROP_OR(inst, phase_seg1, 0), \ @@ -1182,8 +1162,6 @@ static const struct can_stm32_config can_stm32_cfg_##inst = { \ }, \ .config_irq = config_can_##inst##_irq, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ - .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ }; #define CAN_STM32_DATA_INST(inst) \ diff --git a/drivers/can/can_stm32_fdcan.c b/drivers/can/can_stm32_fdcan.c index e17fce0e1b9..fffd291778d 100644 --- a/drivers/can/can_stm32_fdcan.c +++ b/drivers/can/can_stm32_fdcan.c @@ -590,7 +590,6 @@ static const struct can_driver_api can_stm32fd_driver_api = { .recover = can_mcan_recover, #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ .get_core_clock = can_stm32fd_get_core_clock, - .get_max_bitrate = can_mcan_get_max_bitrate, .get_max_filters = can_mcan_get_max_filters, .set_state_change_callback = can_mcan_set_state_change_callback, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, @@ -630,14 +629,14 @@ static const struct can_mcan_ops can_stm32fd_ops = { static void config_can_##inst##_irq(void) \ { \ LOG_DBG("Enable CAN" #inst " IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int0, irq), \ + DT_INST_IRQ_BY_NAME(inst, int0, priority), \ can_mcan_line_0_isr, DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_1, irq), \ - DT_INST_IRQ_BY_NAME(inst, line_1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, int1, irq), \ + DT_INST_IRQ_BY_NAME(inst, int1, priority), \ can_mcan_line_1_isr, DEVICE_DT_INST_GET(inst), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(inst, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, int1, irq)); \ } #define CAN_STM32FD_CFG_INST(inst) \ diff --git a/drivers/can/can_stm32h7_fdcan.c b/drivers/can/can_stm32h7_fdcan.c index 291bcfe8091..e4965f32a92 100644 --- a/drivers/can/can_stm32h7_fdcan.c +++ b/drivers/can/can_stm32h7_fdcan.c @@ -14,18 +14,31 @@ #include #include #include +#include LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); #define DT_DRV_COMPAT st_stm32h7_fdcan +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with a domain clock */ +#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT +#define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 1 +#else +#define STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT 0 +#endif + +#define VOS0_MAX_FREQ MHZ(125) + struct can_stm32h7_config { mm_reg_t base; mem_addr_t mrba; mem_addr_t mram; void (*config_irq)(void); const struct pinctrl_dev_config *pcfg; - struct stm32_pclken pclken; + size_t pclk_len; + const struct stm32_pclken *pclken; + uint8_t clock_divider; }; static int can_stm32h7_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) @@ -72,6 +85,7 @@ static int can_stm32h7_clear_mram(const struct device *dev, uint16_t offset, siz static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) { const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); + uint32_t cdiv; ARG_UNUSED(dev); @@ -80,9 +94,12 @@ static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) return -EIO; } - *rate = rate_tmp; - - LOG_DBG("rate=%d", *rate); + cdiv = FIELD_GET(FDCANCCU_CCFG_CDIV, FDCAN_CCU->CCFG); + if (cdiv == 0U) { + *rate = rate_tmp; + } else { + *rate = rate_tmp / (cdiv << 1U); + } return 0; } @@ -92,24 +109,53 @@ static int can_stm32h7_clock_enable(const struct device *dev) const struct can_mcan_config *mcan_cfg = dev->config; const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + uint32_t fdcan_clock = 0xffffffff; int ret; - LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PLL1Q); - if (!device_is_ready(clk)) { LOG_ERR("clock control device not ready"); return -ENODEV; } - ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken); + if (IS_ENABLED(STM32H7_FDCAN_DOMAIN_CLOCK_SUPPORT) && (stm32h7_cfg->pclk_len > 1)) { + ret = clock_control_configure(clk, + (clock_control_subsys_t)&stm32h7_cfg->pclken[1], + NULL); + if (ret < 0) { + LOG_ERR("Could not select can_stm32fd domain clock"); + return ret; + } + + /* Check if clock has correct range according to chosen regulator voltage + * scaling (Table 62 of RM0399 Rev 4). + * There is no need to test HSE case, since it's value is in range of + * 4 to 50 MHz (please refer to CubeMX clock control). + */ + ret = clock_control_get_rate(clk, + (clock_control_subsys_t)&stm32h7_cfg->pclken[1], &fdcan_clock); + if (ret != 0) { + LOG_ERR("failure getting clock rate"); + return ret; + } + + if (fdcan_clock > VOS0_MAX_FREQ) { + LOG_ERR("FDCAN Clock source %d exceeds max allowed %d", + fdcan_clock, VOS0_MAX_FREQ); + return -ENODEV; + } + } + + ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken[0]); if (ret != 0) { LOG_ERR("failure enabling clock"); return ret; } - if (!LL_RCC_PLL1Q_IsEnabled()) { - LOG_ERR("PLL1Q clock must be enabled!"); - return -EIO; + if (stm32h7_cfg->clock_divider != 0U) { + can_mcan_enable_configuration_change(dev); + + FDCAN_CCU->CCFG = FDCANCCU_CCFG_BCC | + FIELD_PREP(FDCANCCU_CCFG_CDIV, stm32h7_cfg->clock_divider >> 1U); } return 0; @@ -162,7 +208,6 @@ static const struct can_driver_api can_stm32h7_driver_api = { .recover = can_mcan_recover, #endif .get_core_clock = can_stm32h7_get_core_clock, - .get_max_bitrate = can_mcan_get_max_bitrate, .get_max_filters = can_mcan_get_max_filters, .set_state_change_callback = can_mcan_set_state_change_callback, /* Timing limits are per the STM32H7 Reference Manual (RM0433 Rev 7), @@ -204,16 +249,18 @@ static const struct can_mcan_ops can_stm32h7_ops = { PINCTRL_DT_INST_DEFINE(n); \ CAN_MCAN_DT_INST_CALLBACKS_DEFINE(n, can_stm32h7_cbs_##n); \ \ + static const struct stm32_pclken can_stm32h7_pclken_##n[] = \ + STM32_DT_INST_CLOCKS(n); \ + \ static const struct can_stm32h7_config can_stm32h7_cfg_##n = { \ .base = CAN_MCAN_DT_INST_MCAN_ADDR(n), \ .mrba = CAN_MCAN_DT_INST_MRBA(n), \ .mram = CAN_MCAN_DT_INST_MRAM_ADDR(n), \ .config_irq = stm32h7_mcan_irq_config_##n, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ - .pclken = { \ - .enr = DT_INST_CLOCKS_CELL(n, bits), \ - .bus = DT_INST_CLOCKS_CELL(n, bus), \ - }, \ + .pclken = can_stm32h7_pclken_##n, \ + .pclk_len = DT_INST_NUM_CLOCKS(n), \ + .clock_divider = DT_INST_PROP_OR(n, clk_divider, 0) \ }; \ \ static const struct can_mcan_config can_mcan_cfg_##n = \ @@ -233,14 +280,14 @@ static const struct can_mcan_ops can_stm32h7_ops = { static void stm32h7_mcan_irq_config_##n(void) \ { \ LOG_DBG("Enable CAN inst" #n " IRQ"); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_0, irq), \ - DT_INST_IRQ_BY_NAME(n, line_0, priority), \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int0, irq), \ + DT_INST_IRQ_BY_NAME(n, int0, priority), \ can_mcan_line_0_isr, DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(n, line_0, irq)); \ - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_1, irq), \ - DT_INST_IRQ_BY_NAME(n, line_1, priority), \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, int1, irq), \ + DT_INST_IRQ_BY_NAME(n, int1, priority), \ can_mcan_line_1_isr, DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_NAME(n, line_1, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(n, int1, irq)); \ } DT_INST_FOREACH_STATUS_OKAY(CAN_STM32H7_MCAN_INIT) diff --git a/drivers/can/can_tcan4x5x.c b/drivers/can/can_tcan4x5x.c index d80f8e77526..8d8a1a612ad 100644 --- a/drivers/can/can_tcan4x5x.c +++ b/drivers/can/can_tcan4x5x.c @@ -729,7 +729,6 @@ static const struct can_driver_api tcan4x5x_driver_api = { .set_state_change_callback = can_mcan_set_state_change_callback, .get_core_clock = tcan4x5x_get_core_clock, .get_max_filters = can_mcan_get_max_filters, - .get_max_bitrate = can_mcan_get_max_bitrate, .timing_min = CAN_MCAN_TIMING_MIN_INITIALIZER, .timing_max = CAN_MCAN_TIMING_MAX_INITIALIZER, #ifdef CONFIG_CAN_FD_MODE diff --git a/drivers/can/can_xmc4xxx.c b/drivers/can/can_xmc4xxx.c new file mode 100644 index 00000000000..b6c578595ea --- /dev/null +++ b/drivers/can/can_xmc4xxx.c @@ -0,0 +1,999 @@ +/* + * Copyright (c) 2023 Andriy Gelman + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_can_node + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(can_xmc4xxx, CONFIG_CAN_LOG_LEVEL); + +#define SP_IS_SET(inst) DT_INST_NODE_HAS_PROP(inst, sample_point) || + +/* + * Macro to exclude the sample point algorithm from compilation if not used + * Without the macro, the algorithm would always waste ROM + */ +#define USE_SP_ALGO (DT_INST_FOREACH_STATUS_OKAY(SP_IS_SET) 0) + +#define CAN_XMC4XXX_MULTICAN_NODE DT_INST(0, infineon_xmc4xxx_can) + +#define CAN_XMC4XXX_NUM_MESSAGE_OBJECTS DT_PROP(CAN_XMC4XXX_MULTICAN_NODE, message_objects) +#define CAN_XMC4XXX_CLOCK_PRESCALER DT_PROP(CAN_XMC4XXX_MULTICAN_NODE, clock_prescaler) + +static CAN_GLOBAL_TypeDef *const can_xmc4xxx_global_reg = + (CAN_GLOBAL_TypeDef *)DT_REG_ADDR(CAN_XMC4XXX_MULTICAN_NODE); + +static bool can_xmc4xxx_global_init; +static uint32_t can_xmc4xxx_clock_frequency; + +SYS_BITARRAY_DEFINE_STATIC(mo_usage_bitarray, CAN_XMC4XXX_NUM_MESSAGE_OBJECTS); +static int can_xmc4xxx_num_free_mo = CAN_XMC4XXX_NUM_MESSAGE_OBJECTS; + +#define CAN_XMC4XXX_IRQ_MIN 76 +#define CAN_XMC4XXX_MAX_DLC 8 + +#define CAN_XMC4XXX_REG_TO_NODE_IND(reg) (((uint32_t)(reg) - (uint32_t)CAN_NODE0_BASE) / 0x100) + +struct can_xmc4xxx_tx_callback { + can_tx_callback_t function; + void *user_data; +}; + +struct can_xmc4xxx_rx_callback { + can_rx_callback_t function; + void *user_data; +}; + +struct can_xmc4xxx_rx_fifo { + CAN_MO_TypeDef *base; + CAN_MO_TypeDef *top; + CAN_MO_TypeDef *tail; + CAN_MO_TypeDef *head; +}; + +struct can_xmc4xxx_data { + struct can_driver_data common; + + enum can_state state; + struct k_mutex mutex; + + struct k_sem tx_sem; + struct can_xmc4xxx_tx_callback tx_callbacks[CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE]; + + uint32_t filter_usage; + struct can_xmc4xxx_rx_callback rx_callbacks[CONFIG_CAN_MAX_FILTER]; + struct can_xmc4xxx_rx_fifo rx_fifos[CONFIG_CAN_MAX_FILTER]; +#if defined(CONFIG_CAN_ACCEPT_RTR) + struct can_xmc4xxx_rx_fifo rtr_fifos[CONFIG_CAN_MAX_FILTER]; +#endif + + CAN_MO_TypeDef *tx_mo[CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE]; +}; + +struct can_xmc4xxx_config { + struct can_driver_config common; + + CAN_NODE_TypeDef *can; + bool clock_div8; + + uint8_t sjw; + uint8_t prop_seg; + uint8_t phase_seg1; + uint8_t phase_seg2; + + uint8_t service_request; + void (*irq_config_func)(void); + + uint8_t input_src; + const struct pinctrl_dev_config *pcfg; +}; + +static int can_xmc4xxx_set_mode(const struct device *dev, can_mode_t mode) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + if (dev_data->common.started) { + return -EBUSY; + } + + if ((mode & (CAN_MODE_3_SAMPLES | CAN_MODE_ONE_SHOT | + CAN_MODE_LOOPBACK | CAN_MODE_FD)) != 0) { + return -ENOTSUP; + } + + if ((mode & CAN_MODE_LISTENONLY) != 0) { + XMC_CAN_NODE_SetAnalyzerMode(dev_cfg->can); + } else { + XMC_CAN_NODE_ReSetAnalyzerMode(dev_cfg->can); + } + + dev_data->common.mode = mode; + + return 0; +} + +static int can_xmc4xxx_set_timing(const struct device *dev, const struct can_timing *timing) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t reg; + + if (!timing) { + return -EINVAL; + } + + if (dev_data->common.started) { + return -EBUSY; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + reg = FIELD_PREP(CAN_NODE_NBTR_DIV8_Msk, dev_cfg->clock_div8); + reg |= FIELD_PREP(CAN_NODE_NBTR_BRP_Msk, timing->prescaler - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_TSEG1_Msk, timing->prop_seg + timing->phase_seg1 - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_TSEG2_Msk, timing->phase_seg2 - 1); + reg |= FIELD_PREP(CAN_NODE_NBTR_SJW_Msk, timing->sjw - 1); + + dev_cfg->can->NBTR = reg; + + k_mutex_unlock(&dev_data->mutex); + + return 0; +} + +static int can_xmc4xxx_send(const struct device *dev, const struct can_frame *msg, + k_timeout_t timeout, can_tx_callback_t callback, void *callback_arg) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + uint8_t mailbox_idx; + struct can_xmc4xxx_tx_callback *callbacks = &dev_data->tx_callbacks[0]; + CAN_MO_TypeDef *mo; + unsigned int key; + + LOG_DBG("Sending %d bytes. Id: 0x%x, ID type: %s %s %s %s", can_dlc_to_bytes(msg->dlc), + msg->id, msg->flags & CAN_FRAME_IDE ? "extended" : "standard", + msg->flags & CAN_FRAME_RTR ? "RTR" : "", + msg->flags & CAN_FRAME_FDF ? "FD frame" : "", + msg->flags & CAN_FRAME_BRS ? "BRS" : ""); + + __ASSERT_NO_MSG(callback != NULL); + + if (msg->dlc > CAN_XMC4XXX_MAX_DLC) { + return -EINVAL; + } + + if (!dev_data->common.started) { + return -ENETDOWN; + } + + if (dev_data->state == CAN_STATE_BUS_OFF) { + return -ENETUNREACH; + } + + if ((msg->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0) { + return -ENOTSUP; + } + + if (k_sem_take(&dev_data->tx_sem, timeout) != 0) { + return -EAGAIN; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + for (mailbox_idx = 0; mailbox_idx < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; mailbox_idx++) { + if (callbacks[mailbox_idx].function == NULL) { + break; + } + } + + __ASSERT_NO_MSG(mailbox_idx < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE); + + key = irq_lock(); + /* critical section in case can_xmc4xxx_reset_tx_fifos() called in isr */ + /* so that callback function and callback_arg are consistent */ + callbacks[mailbox_idx].function = callback; + callbacks[mailbox_idx].user_data = callback_arg; + irq_unlock(key); + + mo = dev_data->tx_mo[mailbox_idx]; + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + + if ((msg->flags & CAN_FRAME_IDE) != 0) { + /* MOAR - message object arbitration register */ + mo->MOAR = FIELD_PREP(CAN_MO_MOAR_PRI_Msk, 1) | + FIELD_PREP(CAN_MO_MOAR_ID_Msk, msg->id) | CAN_MO_MOAR_IDE_Msk; + } else { + mo->MOAR = FIELD_PREP(CAN_MO_MOAR_PRI_Msk, 1) | + FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, msg->id); + } + + mo->MOFCR &= ~CAN_MO_MOFCR_DLC_Msk; + mo->MOFCR |= FIELD_PREP(CAN_MO_MOFCR_DLC_Msk, msg->dlc); + + if ((msg->flags & CAN_FRAME_RTR) != 0) { + mo->MOCTR = CAN_MO_MOCTR_RESDIR_Msk; + } else { + mo->MOCTR = CAN_MO_MOCTR_SETDIR_Msk; + memcpy((void *)&mo->MODATAL, &msg->data[0], sizeof(uint32_t)); + memcpy((void *)&mo->MODATAH, &msg->data[4], sizeof(uint32_t)); + } + + mo->MOCTR = CAN_MO_MOCTR_SETTXEN0_Msk | CAN_MO_MOCTR_SETTXEN1_Msk | + CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_RESRXEN_Msk | + CAN_MO_MOCTR_RESRTSEL_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETTXRQ_Msk; + + k_mutex_unlock(&dev_data->mutex); + return 0; +} + +static CAN_MO_TypeDef *can_xmc4xxx_get_mo(uint8_t *mo_index) +{ + int i; + + for (i = 0; i < CAN_XMC4XXX_NUM_MESSAGE_OBJECTS; i++) { + int prev_val; + + sys_bitarray_test_and_set_bit(&mo_usage_bitarray, i, &prev_val); + if (prev_val == 0) { + *mo_index = i; + can_xmc4xxx_num_free_mo--; + return &CAN_MO->MO[i]; + } + } + + return NULL; +} + +static void can_xmc4xxx_deinit_fifo(const struct device *dev, struct can_xmc4xxx_rx_fifo *fifo) +{ + CAN_MO_TypeDef *mo = fifo->base; + + while (mo != NULL) { + int next_index; + int index; + + /* invalidate message */ + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + + next_index = FIELD_GET(CAN_MO_MOSTAT_PNEXT_Msk, mo->MOSTAT); + index = ((uint32_t)mo - (uint32_t)&CAN_MO->MO[0]) / sizeof(*mo); + + if ((uint32_t)mo == (uint32_t)fifo->top) { + mo = NULL; + } else { + mo = &CAN_MO->MO[next_index]; + } + + /* we need to move the node back to the list of unallocated message objects, */ + /* which is list index = 0. 255 gets rolled over to 0 in the function below */ + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, 255, index); + + sys_bitarray_clear_bit(&mo_usage_bitarray, index); + can_xmc4xxx_num_free_mo++; + } +} + +static int can_xmc4xxx_init_fifo(const struct device *dev, const struct can_filter *filter, + struct can_xmc4xxx_rx_fifo *fifo, bool is_rtr) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + CAN_MO_TypeDef *mo; + uint32_t reg; + uint8_t mo_index = 0, base_index; + + if (can_xmc4xxx_num_free_mo < CONFIG_CAN_XMC4XXX_RX_FIFO_ITEMS) { + return -ENOMEM; + } + + mo = can_xmc4xxx_get_mo(&mo_index); + __ASSERT_NO_MSG(mo != NULL); + + base_index = mo_index; + fifo->base = mo; + fifo->tail = mo; + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + /* setup the base object - this controls the filtering for the fifo */ + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + mo->MOAMR &= ~(CAN_MO_MOAMR_AM_Msk | CAN_MO_MOAMR_MIDE_Msk); + mo->MOAR = 0; + + if ((filter->flags & CAN_FILTER_IDE) != 0) { + mo->MOAMR |= FIELD_PREP(CAN_MO_MOAMR_AM_Msk, filter->mask) | CAN_MO_MOAMR_MIDE_Msk; + mo->MOAR |= FIELD_PREP(CAN_MO_MOAR_ID_Msk, filter->id) | CAN_MO_MOAR_IDE_Msk; + } else { + mo->MOAMR |= FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, filter->mask); + mo->MOAR |= FIELD_PREP(XMC_CAN_MO_MOAR_STDID_Msk, filter->id); + } + + mo->MOFCR = FIELD_PREP(CAN_MO_MOFCR_MMC_Msk, 1) | CAN_MO_MOFCR_RXIE_Msk; + if (is_rtr) { + mo->MOFCR |= CAN_MO_MOFCR_RMM_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETDIR_Msk; + } else { + mo->MOCTR = CAN_MO_MOCTR_RESDIR_Msk; + } + + /* Writing to MOCTR sets or resets message object properties */ + mo->MOCTR = CAN_MO_MOCTR_RESTXEN0_Msk | CAN_MO_MOCTR_RESTXEN1_Msk | + CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_SETRXEN_Msk | + CAN_MO_MOCTR_RESRTSEL_Msk; + + mo->MOIPR = FIELD_PREP(CAN_MO_MOIPR_RXINP_Msk, dev_cfg->service_request); + + /* setup the remaining message objects in the fifo */ + for (int i = 1; i < CONFIG_CAN_XMC4XXX_RX_FIFO_ITEMS; i++) { + mo = can_xmc4xxx_get_mo(&mo_index); + __ASSERT_NO_MSG(mo != NULL); + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + mo->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + mo->MOCTR = CAN_MO_MOCTR_SETMSGVAL_Msk | CAN_MO_MOCTR_RESRXEN_Msk; + + /* all the other message objects in the fifo must point to the base object */ + mo->MOFGPR = FIELD_PREP(CAN_MO_MOFGPR_CUR_Msk, base_index); + } + + reg = 0; + reg |= FIELD_PREP(CAN_MO_MOFGPR_CUR_Msk, base_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_TOP_Msk, mo_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_BOT_Msk, base_index); + reg |= FIELD_PREP(CAN_MO_MOFGPR_SEL_Msk, base_index); + + fifo->base->MOFGPR = reg; + fifo->top = mo; + + return 0; +} + +static int can_xmc4xxx_add_rx_filter(const struct device *dev, can_rx_callback_t callback, + void *user_data, const struct can_filter *filter) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + int filter_idx; + + if ((filter->flags & ~CAN_FILTER_IDE) != 0) { + LOG_ERR("Unsupported CAN filter flags 0x%02x", filter->flags); + return -ENOTSUP; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + for (filter_idx = 0; filter_idx < CONFIG_CAN_MAX_FILTER; filter_idx++) { + if ((BIT(filter_idx) & dev_data->filter_usage) == 0) { + break; + } + } + + if (filter_idx >= CONFIG_CAN_MAX_FILTER) { + filter_idx = -ENOSPC; + } else { + unsigned int key = irq_lock(); + int ret; + + ret = can_xmc4xxx_init_fifo(dev, filter, &dev_data->rx_fifos[filter_idx], false); + if (ret < 0) { + irq_unlock(key); + k_mutex_unlock(&dev_data->mutex); + return ret; + } + +#if defined(CONFIG_CAN_ACCEPT_RTR) + ret = can_xmc4xxx_init_fifo(dev, filter, &dev_data->rtr_fifos[filter_idx], true); + if (ret < 0) { + can_xmc4xxx_deinit_fifo(dev, &dev_data->rx_fifos[filter_idx]); + irq_unlock(key); + k_mutex_unlock(&dev_data->mutex); + return ret; + } +#endif + + dev_data->filter_usage |= BIT(filter_idx); + dev_data->rx_callbacks[filter_idx].function = callback; + dev_data->rx_callbacks[filter_idx].user_data = user_data; + + irq_unlock(key); + } + + k_mutex_unlock(&dev_data->mutex); + + return filter_idx; +} + +static void can_xmc4xxx_remove_rx_filter(const struct device *dev, int filter_idx) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + unsigned int key; + + if (filter_idx < 0 || filter_idx >= CONFIG_CAN_MAX_FILTER) { + LOG_ERR("Filter ID %d out of bounds", filter_idx); + return; + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + if ((dev_data->filter_usage & BIT(filter_idx)) == 0) { + k_mutex_unlock(&dev_data->mutex); + return; + } + + key = irq_lock(); + can_xmc4xxx_deinit_fifo(dev, &dev_data->rx_fifos[filter_idx]); +#if defined(CONFIG_CAN_ACCEPT_RTR) + can_xmc4xxx_deinit_fifo(dev, &dev_data->rtr_fifos[filter_idx]); +#endif + + dev_data->filter_usage &= ~BIT(filter_idx); + dev_data->rx_callbacks[filter_idx].function = NULL; + dev_data->rx_callbacks[filter_idx].user_data = NULL; + irq_unlock(key); + + k_mutex_unlock(&dev_data->mutex); +} + +static void can_xmc4xxx_set_state_change_callback(const struct device *dev, + can_state_change_callback_t cb, void *user_data) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + unsigned int key; + + key = irq_lock(); + /* critical section so that state_change_cb and state_change_cb_data are consistent */ + dev_data->common.state_change_cb = cb; + dev_data->common.state_change_cb_user_data = user_data; + irq_unlock(key); +} + +static void can_xmc4xxx_get_state_from_status(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt, uint32_t *status) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint8_t tec = XMC_CAN_NODE_GetTransmitErrorCounter(dev_cfg->can); + uint8_t rec = XMC_CAN_NODE_GetTransmitErrorCounter(dev_cfg->can); + + if (err_cnt != NULL) { + err_cnt->tx_err_cnt = tec; + err_cnt->rx_err_cnt = rec; + } + + if (state == NULL) { + return; + } + + if (!dev_data->common.started) { + *state = CAN_STATE_STOPPED; + return; + } + + if ((*status & XMC_CAN_NODE_STATUS_BUS_OFF) != 0) { + *state = CAN_STATE_BUS_OFF; + } else if (tec >= 128 || rec >= 128) { + *state = CAN_STATE_ERROR_PASSIVE; + } else if ((*status & XMC_CAN_NODE_STATUS_ERROR_WARNING_STATUS) != 0) { + *state = CAN_STATE_ERROR_WARNING; + } else { + *state = CAN_STATE_ERROR_ACTIVE; + } +} + +static int can_xmc4xxx_get_state(const struct device *dev, enum can_state *state, + struct can_bus_err_cnt *err_cnt) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t status; + + status = XMC_CAN_NODE_GetStatus(dev_cfg->can); + + can_xmc4xxx_get_state_from_status(dev, state, err_cnt, &status); + + return 0; +} + +static int can_xmc4xxx_get_core_clock(const struct device *dev, uint32_t *rate) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + *rate = can_xmc4xxx_clock_frequency; + if (dev_cfg->clock_div8) { + *rate /= 8; + } + + return 0; +} + +static int can_xmc4xxx_get_max_filters(const struct device *dev, bool ide) +{ + ARG_UNUSED(ide); + + return CONFIG_CAN_MAX_FILTER; +} + +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY +static int can_xmc4xxx_recover(const struct device *dev, k_timeout_t timeout) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + + ARG_UNUSED(timeout); + + if (!dev_data->common.started) { + return -ENETDOWN; + } + + return -ENOTSUP; +} +#endif + +static void can_xmc4xxx_reset_tx_fifos(const struct device *dev, int status) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + struct can_xmc4xxx_tx_callback *tx_callbacks = &dev_data->tx_callbacks[0]; + + LOG_DBG("All Tx message objects reset"); + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + can_tx_callback_t callback; + void *user_data; + + callback = tx_callbacks[i].function; + user_data = tx_callbacks[i].user_data; + + tx_callbacks[i].function = NULL; + + if (callback) { + dev_data->tx_mo[i]->MOCTR = CAN_MO_MOCTR_RESMSGVAL_Msk; + callback(dev, status, user_data); + k_sem_give(&dev_data->tx_sem); + } + } +} + +static void can_xmc4xxx_tx_handler(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + struct can_xmc4xxx_tx_callback *tx_callbacks = &dev_data->tx_callbacks[0]; + + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + CAN_MO_TypeDef *mo = dev_data->tx_mo[i]; + + if ((mo->MOSTAT & XMC_CAN_MO_STATUS_TX_PENDING) != 0) { + can_tx_callback_t callback; + void *user_data; + + mo->MOCTR = XMC_CAN_MO_RESET_STATUS_TX_PENDING; + + callback = tx_callbacks[i].function; + user_data = tx_callbacks[i].user_data; + + tx_callbacks[i].function = NULL; + + if (callback) { + callback(dev, 0, user_data); + k_sem_give(&dev_data->tx_sem); + } + } + } +} + +static inline void can_xmc4xxx_increment_fifo_tail(struct can_xmc4xxx_rx_fifo *fifo) +{ + uint8_t next_index; + + if ((uint32_t)fifo->tail == (uint32_t)fifo->top) { + fifo->tail = fifo->base; + return; + } + + next_index = FIELD_GET(CAN_MO_MOSTAT_PNEXT_Msk, fifo->tail->MOSTAT); + fifo->tail = &CAN_MO->MO[next_index]; +} + +static inline bool can_xmc4xxx_is_fifo_empty(struct can_xmc4xxx_rx_fifo *fifo) +{ + if (fifo->tail->MOSTAT & XMC_CAN_MO_STATUS_RX_PENDING) { + return false; + } + + return true; +} + +static inline void can_xmc4xxx_update_fifo_head(struct can_xmc4xxx_rx_fifo *fifo) +{ + uint32_t reg = fifo->base->MOFGPR; + uint8_t top_index, bot_index, cur_index; + uint8_t head_index = FIELD_GET(CAN_MO_MOFGPR_CUR_Msk, reg); + + fifo->head = &CAN_MO->MO[head_index]; + top_index = FIELD_GET(CAN_MO_MOFGPR_TOP_Msk, reg); + bot_index = FIELD_GET(CAN_MO_MOFGPR_BOT_Msk, reg); + cur_index = FIELD_GET(CAN_MO_MOFGPR_CUR_Msk, reg); + + LOG_DBG("Fifo: top %d, bot %d, cur %d", top_index, bot_index, cur_index); +} + +static void can_xmc4xxx_rx_fifo_handler(const struct device *dev, struct can_xmc4xxx_rx_fifo *fifo, + struct can_xmc4xxx_rx_callback *rx_callback) +{ + bool is_rtr = (fifo->base->MOSTAT & CAN_MO_MOSTAT_DIR_Msk) != 0; + + while (!can_xmc4xxx_is_fifo_empty(fifo)) { + struct can_frame frame; + CAN_MO_TypeDef *mo_tail = fifo->tail; + + memset(&frame, 0, sizeof(frame)); + + if ((mo_tail->MOAR & CAN_MO_MOAR_IDE_Msk) != 0) { + frame.flags |= CAN_FRAME_IDE; + frame.id = FIELD_GET(CAN_MO_MOAR_ID_Msk, mo_tail->MOAR); + } else { + frame.id = FIELD_GET(XMC_CAN_MO_MOAR_STDID_Msk, mo_tail->MOAR); + } + + frame.dlc = FIELD_GET(CAN_MO_MOFCR_DLC_Msk, mo_tail->MOFCR); + + if (!is_rtr) { + memcpy(&frame.data[0], (void *)&mo_tail->MODATAL, sizeof(uint32_t)); + memcpy(&frame.data[4], (void *)&mo_tail->MODATAH, sizeof(uint32_t)); + } else { + frame.flags |= CAN_FRAME_RTR; + memset(&frame.data[0], 0, CAN_MAX_DLEN); + } + + if (rx_callback->function != NULL) { + rx_callback->function(dev, &frame, rx_callback->user_data); + } + + /* reset the rx pending bit on the tail */ + mo_tail->MOCTR = XMC_CAN_MO_RESET_STATUS_RX_PENDING; + can_xmc4xxx_increment_fifo_tail(fifo); + } +} + +static void can_xmc4xxx_rx_handler(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + + for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { + if ((BIT(i) & dev_data->filter_usage) == 0) { + continue; + } + + can_xmc4xxx_update_fifo_head(&dev_data->rx_fifos[i]); + can_xmc4xxx_rx_fifo_handler(dev, &dev_data->rx_fifos[i], + &dev_data->rx_callbacks[i]); +#if defined(CONFIG_CAN_ACCEPT_RTR) + can_xmc4xxx_update_fifo_head(&dev_data->rtr_fifos[i]); + can_xmc4xxx_rx_fifo_handler(dev, &dev_data->rtr_fifos[i], + &dev_data->rx_callbacks[i]); +#endif + } +} + +static void can_xmc4xxx_state_change_handler(const struct device *dev, uint32_t status) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + struct can_xmc4xxx_data *dev_data = dev->data; + enum can_state new_state; + struct can_bus_err_cnt err_cnt; + + can_xmc4xxx_get_state_from_status(dev, &new_state, &err_cnt, &status); + if (dev_data->state != new_state) { + if (dev_data->common.state_change_cb) { + dev_data->common.state_change_cb( + dev, new_state, err_cnt, + dev_data->common.state_change_cb_user_data); + } + + if (dev_data->state != CAN_STATE_STOPPED && new_state == CAN_STATE_BUS_OFF) { + /* re-enable the node after auto bus-off recovery completes */ + XMC_CAN_NODE_ResetInitBit(dev_cfg->can); + } + + dev_data->state = new_state; + + if (dev_data->state == CAN_STATE_BUS_OFF) { + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + } + } +} + +static void can_xmc4xxx_isr(const struct device *dev) +{ + const struct can_xmc4xxx_config *dev_cfg = dev->config; + uint32_t status; + + status = XMC_CAN_NODE_GetStatus(dev_cfg->can); + XMC_CAN_NODE_ClearStatus(dev_cfg->can, status); + + if ((status & XMC_CAN_NODE_STATUS_TX_OK) != 0) { + can_xmc4xxx_tx_handler(dev); + } + + if ((status & XMC_CAN_NODE_STATUS_RX_OK) != 0) { + can_xmc4xxx_rx_handler(dev); + } + + if ((status & XMC_CAN_NODE_STATUS_ALERT_WARNING) != 0) { + /* change of bit NSRx.BOFF */ + /* change of bit NSRx.EWRN */ + can_xmc4xxx_state_change_handler(dev, status); + } +} + +static int can_xmc4xxx_get_capabilities(const struct device *dev, can_mode_t *cap) +{ + ARG_UNUSED(dev); + + *cap = CAN_MODE_NORMAL | CAN_MODE_LISTENONLY; + + return 0; +} + +static int can_xmc4xxx_start(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret = 0; + unsigned int key; + + if (dev_data->common.started) { + return -EALREADY; + } + + key = irq_lock(); + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + irq_unlock(key); + + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_enable(dev_cfg->common.phy, dev_data->common.mode); + if (ret < 0) { + LOG_ERR("Failed to enable CAN transceiver [%d]", ret); + return ret; + } + } + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + XMC_CAN_NODE_DisableConfigurationChange(dev_cfg->can); + + dev_data->common.started = true; + XMC_CAN_NODE_ResetInitBit(dev_cfg->can); + + k_mutex_unlock(&dev_data->mutex); + + return ret; +} + +static int can_xmc4xxx_stop(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret = 0; + unsigned int key; + + if (!dev_data->common.started) { + return -EALREADY; + } + + key = irq_lock(); + XMC_CAN_NODE_SetInitBit(dev_cfg->can); + + XMC_CAN_NODE_EnableConfigurationChange(dev_cfg->can); + + can_xmc4xxx_reset_tx_fifos(dev, -ENETDOWN); + dev_data->common.started = false; + irq_unlock(key); + + if (dev_cfg->common.phy != NULL) { + ret = can_transceiver_disable(dev_cfg->common.phy); + if (ret < 0) { + LOG_ERR("Failed to disable CAN transceiver [%d]", ret); + return ret; + } + } + + return 0; +} + +static int can_xmc4xxx_init_timing_struct(struct can_timing *timing, const struct device *dev) +{ + int ret; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + + if (USE_SP_ALGO && dev_cfg->common.sample_point > 0) { + ret = can_calc_timing(dev, timing, dev_cfg->common.bus_speed, + dev_cfg->common.sample_point); + if (ret < 0) { + return ret; + } + LOG_DBG("Presc: %d, BS1: %d, BS2: %d", timing->prescaler, timing->phase_seg1, + timing->phase_seg2); + LOG_DBG("Sample-point err : %d", ret); + } else { + timing->sjw = dev_cfg->sjw; + timing->prop_seg = dev_cfg->prop_seg; + timing->phase_seg1 = dev_cfg->phase_seg1; + timing->phase_seg2 = dev_cfg->phase_seg2; + ret = can_calc_prescaler(dev, timing, dev_cfg->common.bus_speed); + if (ret > 0) { + LOG_WRN("Bitrate error: %d", ret); + } + } + + return ret; +} + +static int can_xmc4xxx_init(const struct device *dev) +{ + struct can_xmc4xxx_data *dev_data = dev->data; + const struct can_xmc4xxx_config *dev_cfg = dev->config; + int ret; + struct can_timing timing = {0}; + CAN_MO_TypeDef *mo; + uint8_t mo_index = 0; + + k_sem_init(&dev_data->tx_sem, CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE, + CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE); + k_mutex_init(&dev_data->mutex); + + if (!can_xmc4xxx_global_init) { + uint32_t fdr_step; + uint32_t clk_module; + + XMC_CAN_Enable(can_xmc4xxx_global_reg); + XMC_CAN_SetBaudrateClockSource(can_xmc4xxx_global_reg, XMC_CAN_CANCLKSRC_FPERI); + + clk_module = XMC_CAN_GetBaudrateClockFrequency(can_xmc4xxx_global_reg); + fdr_step = 1024 - CAN_XMC4XXX_CLOCK_PRESCALER; + can_xmc4xxx_clock_frequency = clk_module / CAN_XMC4XXX_CLOCK_PRESCALER; + + LOG_DBG("Clock frequency %dHz\n", can_xmc4xxx_clock_frequency); + + can_xmc4xxx_global_reg->FDR &= ~(CAN_FDR_DM_Msk | CAN_FDR_STEP_Msk); + can_xmc4xxx_global_reg->FDR |= FIELD_PREP(CAN_FDR_DM_Msk, XMC_CAN_DM_NORMAL) | + FIELD_PREP(CAN_FDR_STEP_Msk, fdr_step); + + can_xmc4xxx_global_init = true; + } + + XMC_CAN_NODE_EnableConfigurationChange(dev_cfg->can); + + XMC_CAN_NODE_SetReceiveInput(dev_cfg->can, dev_cfg->input_src); + + XMC_CAN_NODE_SetInitBit(dev_cfg->can); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_ALERT, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_LEC, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_TRANSFER_OK, + dev_cfg->service_request); + + XMC_CAN_NODE_SetEventNodePointer(dev_cfg->can, XMC_CAN_NODE_POINTER_EVENT_FRAME_COUNTER, + dev_cfg->service_request); + + XMC_CAN_NODE_EnableEvent(dev_cfg->can, XMC_CAN_NODE_EVENT_TX_INT | + XMC_CAN_NODE_EVENT_ALERT); + + /* set up tx messages */ + for (int i = 0; i < CONFIG_CAN_XMC4XXX_MAX_TX_QUEUE; i++) { + mo = can_xmc4xxx_get_mo(&mo_index); + if (mo == NULL) { + return -ENOMEM; + } + + dev_data->tx_mo[i] = mo; + + XMC_CAN_AllocateMOtoNodeList(can_xmc4xxx_global_reg, + CAN_XMC4XXX_REG_TO_NODE_IND(dev_cfg->can), mo_index); + + mo->MOIPR = FIELD_PREP(CAN_MO_MOIPR_TXINP_Msk, dev_cfg->service_request); + mo->MOFCR = FIELD_PREP(CAN_MO_MOFCR_MMC_Msk, 0) | CAN_MO_MOFCR_TXIE_Msk; + } + +#ifdef CONFIG_CAN_XMC4XXX_INTERNAL_BUS_MODE + /* The name of this function is misleading. It doesn't actually enable */ + /* loopback on a single node, but connects all CAN devices to an internal bus. */ + XMC_CAN_NODE_EnableLoopBack(dev_cfg->can); +#endif + + dev_cfg->irq_config_func(); + + dev_data->state = CAN_STATE_STOPPED; + +#ifndef CONFIG_CAN_XMC4XXX_INTERNAL_BUS_MODE + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } +#endif + + ret = can_xmc4xxx_init_timing_struct(&timing, dev); + if (ret < 0) { + return ret; + } + + return can_set_timing(dev, &timing); +} + +static const struct can_driver_api can_xmc4xxx_api_funcs = { + .get_capabilities = can_xmc4xxx_get_capabilities, + .set_mode = can_xmc4xxx_set_mode, + .set_timing = can_xmc4xxx_set_timing, + .start = can_xmc4xxx_start, + .stop = can_xmc4xxx_stop, + .send = can_xmc4xxx_send, + .add_rx_filter = can_xmc4xxx_add_rx_filter, + .remove_rx_filter = can_xmc4xxx_remove_rx_filter, +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY + .recover = can_xmc4xxx_recover, +#endif + .get_state = can_xmc4xxx_get_state, + .set_state_change_callback = can_xmc4xxx_set_state_change_callback, + .get_core_clock = can_xmc4xxx_get_core_clock, + .get_max_filters = can_xmc4xxx_get_max_filters, + .timing_min = { + .sjw = 1, + .prop_seg = 0, + .phase_seg1 = 3, + .phase_seg2 = 2, + .prescaler = 1, + }, + .timing_max = { + .sjw = 4, + .prop_seg = 0, + .phase_seg1 = 16, + .phase_seg2 = 8, + .prescaler = 64, + }, +}; + +#define CAN_XMC4XXX_INIT(inst) \ + static void can_xmc4xxx_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), can_xmc4xxx_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static struct can_xmc4xxx_data can_xmc4xxx_data_##inst; \ + static const struct can_xmc4xxx_config can_xmc4xxx_config_##inst = { \ + .common = CAN_DT_DRIVER_CONFIG_INST_GET(inst, 1000000), \ + .can = (CAN_NODE_TypeDef *)DT_INST_REG_ADDR(inst), \ + .clock_div8 = DT_INST_PROP(inst, clock_div8), \ + .sjw = DT_INST_PROP(inst, sjw), \ + .prop_seg = DT_INST_PROP_OR(inst, prop_seg, 0), \ + .phase_seg1 = DT_INST_PROP_OR(inst, phase_seg1, 0), \ + .phase_seg2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ + .irq_config_func = can_xmc4xxx_irq_config_##inst, \ + .service_request = DT_INST_IRQN(inst) - CAN_XMC4XXX_IRQ_MIN, \ + .input_src = DT_INST_ENUM_IDX(inst, input_src), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + }; \ + \ + CAN_DEVICE_DT_INST_DEFINE(inst, can_xmc4xxx_init, NULL, &can_xmc4xxx_data_##inst, \ + &can_xmc4xxx_config_##inst, POST_KERNEL, \ + CONFIG_CAN_INIT_PRIORITY, &can_xmc4xxx_api_funcs); + +DT_INST_FOREACH_STATUS_OKAY(CAN_XMC4XXX_INIT) diff --git a/drivers/can/transceiver/can_transceiver_gpio.c b/drivers/can/transceiver/can_transceiver_gpio.c index 9f036599f31..e6aaacc8c34 100644 --- a/drivers/can/transceiver/can_transceiver_gpio.c +++ b/drivers/can/transceiver/can_transceiver_gpio.c @@ -58,8 +58,10 @@ static int can_transceiver_gpio_set_state(const struct device *dev, bool enabled return 0; } -static int can_transceiver_gpio_enable(const struct device *dev) +static int can_transceiver_gpio_enable(const struct device *dev, can_mode_t mode) { + ARG_UNUSED(mode); + return can_transceiver_gpio_set_state(dev, true); } diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index ce70f0590c6..60b80b0ed25 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_library() zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h) zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c) +zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ25180 charger_bq25180.c) zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c) zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 9c7873168a5..ce2c3d8b8d3 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -21,6 +21,7 @@ config CHARGER_INIT_PRIORITY source "drivers/charger/Kconfig.sbs_charger" source "drivers/charger/Kconfig.bq24190" +source "drivers/charger/Kconfig.bq25180" source "drivers/charger/Kconfig.max20335" endif # CHARGER diff --git a/drivers/charger/Kconfig.bq25180 b/drivers/charger/Kconfig.bq25180 new file mode 100644 index 00000000000..44bdc9b32ee --- /dev/null +++ b/drivers/charger/Kconfig.bq25180 @@ -0,0 +1,11 @@ +# Copyright 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +config CHARGER_BQ25180 + bool "BQ25180 Battery Charger" + default y + depends on DT_HAS_TI_BQ25180_ENABLED + select I2C + help + Enable BQ25180 battery charger driver. diff --git a/drivers/charger/charger_bq24190.c b/drivers/charger/charger_bq24190.c index 0661bd92796..9b313136fef 100644 --- a/drivers/charger/charger_bq24190.c +++ b/drivers/charger/charger_bq24190.c @@ -471,8 +471,8 @@ static int bq24190_init(const struct device *dev) } static const struct charger_driver_api bq24190_driver_api = { - .get_property = &bq24190_get_prop, - .set_property = &bq24190_set_prop, + .get_property = bq24190_get_prop, + .set_property = bq24190_set_prop, }; #define BQ24190_INIT(inst) \ @@ -486,7 +486,7 @@ static const struct charger_driver_api bq24190_driver_api = { .vreg_uv = DT_INST_PROP(inst, constant_charge_voltage_max_microvolt), \ }; \ \ - DEVICE_DT_INST_DEFINE(inst, &bq24190_init, NULL, &bq24190_data_##inst, \ + DEVICE_DT_INST_DEFINE(inst, bq24190_init, NULL, &bq24190_data_##inst, \ &bq24190_config_##inst, POST_KERNEL, CONFIG_CHARGER_INIT_PRIORITY, \ &bq24190_driver_api); diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c new file mode 100644 index 00000000000..dbc20b30b06 --- /dev/null +++ b/drivers/charger/charger_bq25180.c @@ -0,0 +1,287 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + * + * BQ25180 Datasheet: https://www.ti.com/lit/gpn/bq25180 + */ + +#define DT_DRV_COMPAT ti_bq25180 + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bq25180, CONFIG_CHARGER_LOG_LEVEL); + +#define BQ25180_STAT0 0x00 +#define BQ25180_STAT1 0x01 +#define BQ25180_FLAG0 0x02 +#define BQ25180_VBAT_CTRL 0x03 +#define BQ25180_ICHG_CTRL 0x04 +#define BQ25180_IC_CTRL 0x07 +#define BQ25180_SHIP_RST 0x09 +#define BQ25180_MASK_ID 0x0c + +#define BQ25180_STAT0_CHG_STAT_MASK GENMASK(6, 5) +#define BQ25180_STAT0_CHG_STAT_NOT_CHARGING 0x00 +#define BQ25180_STAT0_CHG_STAT_CONSTANT_CURRENT 0x01 +#define BQ25180_STAT0_CHG_STAT_CONSTANT_VOLTAGE 0x02 +#define BQ25180_STAT0_CHG_STAT_DONE 0x03 +#define BQ25180_STAT0_VIN_PGOOD_STAT BIT(0) +#define BQ25180_ICHG_CHG_DIS BIT(7) +#define BQ25180_ICHG_MSK GENMASK(6, 0) +#define BQ25180_WATCHDOG_SEL_1_MSK GENMASK(1, 0) +#define BQ25180_WATCHDOG_DISABLE 0x03 +#define BQ25180_DEVICE_ID_MSK GENMASK(3, 0) +#define BQ25180_DEVICE_ID 0x00 +#define BQ25180_SHIP_RST_EN_RST_SHIP_MSK GENMASK(6, 5) +#define BQ25180_SHIP_RST_EN_RST_SHIP_ADAPTER 0x20 +#define BQ25180_SHIP_RST_EN_RST_SHIP_BUTTON 0x40 + +/* Charging current limits */ +#define BQ25180_CURRENT_MIN_MA 5 +#define BQ25180_CURRENT_MAX_MA 1000 + +struct bq25180_config { + struct i2c_dt_spec i2c; + uint32_t initial_current_microamp; +}; + +/* + * For ICHG <= 35mA = ICHGCODE + 5mA + * For ICHG > 35mA = 40 + ((ICHGCODE-31)*10)mA. + * Maximum programmable current = 1000mA + * + * Return: value between 0 and 127, negative on error. + */ +static int bq25180_ma_to_ichg(uint32_t current_ma, uint8_t *ichg) +{ + if (!IN_RANGE(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA)) { + LOG_WRN("charging current out of range: %dmA, " + "clamping to the nearest limit", current_ma); + } + current_ma = CLAMP(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA); + + if (current_ma <= 35) { + *ichg = current_ma - 5; + return 0; + } + + *ichg = (current_ma - 40) / 10 + 31; + + return 0; +} + +static uint32_t bq25180_ichg_to_ma(uint8_t ichg) +{ + ichg &= BQ25180_ICHG_MSK; + + if (ichg <= 30) { + return (ichg + 5); + } + + return (ichg - 31) * 10 + 40; +} + +static int bq25183_charge_enable(const struct device *dev, const bool enable) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t value = enable ? 0 : BQ25180_ICHG_CHG_DIS; + int ret; + + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, + BQ25180_ICHG_CHG_DIS, value); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int bq25180_set_charge_current(const struct device *dev, + uint32_t const_charge_current_ua) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = bq25180_ma_to_ichg(const_charge_current_ua / 1000, &val); + if (ret < 0) { + return ret; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, + BQ25180_ICHG_MSK, val); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int bq25180_get_charge_current(const struct device *dev, + uint32_t *const_charge_current_ua) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &val); + if (ret < 0) { + return ret; + } + + *const_charge_current_ua = bq25180_ichg_to_ma(val) * 1000; + + return 0; +} + +static int bq25180_get_online(const struct device *dev, + enum charger_online *online) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_STAT0, &val); + if (ret < 0) { + return ret; + } + + if ((val & BQ25180_STAT0_VIN_PGOOD_STAT) != 0x00) { + *online = CHARGER_ONLINE_FIXED; + } else { + *online = CHARGER_ONLINE_OFFLINE; + } + + return 0; +} + +static int bq25180_get_status(const struct device *dev, + enum charger_status *status) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t stat0; + uint8_t ichg_ctrl; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_STAT0, &stat0); + if (ret < 0) { + return ret; + } + + if ((stat0 & BQ25180_STAT0_VIN_PGOOD_STAT) == 0x00) { + *status = CHARGER_STATUS_DISCHARGING; + return 0; + } + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &ichg_ctrl); + if (ret < 0) { + return ret; + } + + if ((ichg_ctrl & BQ25180_ICHG_CHG_DIS) != 0x00) { + *status = CHARGER_STATUS_NOT_CHARGING; + return 0; + } + + switch (FIELD_GET(BQ25180_STAT0_CHG_STAT_MASK, stat0)) { + case BQ25180_STAT0_CHG_STAT_NOT_CHARGING: + *status = CHARGER_STATUS_NOT_CHARGING; + break; + case BQ25180_STAT0_CHG_STAT_CONSTANT_CURRENT: + case BQ25180_STAT0_CHG_STAT_CONSTANT_VOLTAGE: + *status = CHARGER_STATUS_CHARGING; + break; + case BQ25180_STAT0_CHG_STAT_DONE: + *status = CHARGER_STATUS_FULL; + break; + } + + return 0; +} + +static int bq25180_get_prop(const struct device *dev, charger_prop_t prop, + union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_ONLINE: + return bq25180_get_online(dev, &val->online); + case CHARGER_PROP_STATUS: + return bq25180_get_status(dev, &val->status); + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return bq25180_get_charge_current(dev, &val->const_charge_current_ua); + default: + return -ENOTSUP; + } +} + +static int bq25180_set_prop(const struct device *dev, charger_prop_t prop, + const union charger_propval *val) +{ + switch (prop) { + case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: + return bq25180_set_charge_current(dev, val->const_charge_current_ua); + default: + return -ENOTSUP; + } +} + +static const struct charger_driver_api bq25180_api = { + .get_property = bq25180_get_prop, + .set_property = bq25180_set_prop, + .charge_enable = bq25183_charge_enable, +}; + +static int bq25180_init(const struct device *dev) +{ + const struct bq25180_config *cfg = dev->config; + uint8_t val; + int ret; + + ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_MASK_ID, &val); + if (ret < 0) { + return ret; + } + + val &= BQ25180_DEVICE_ID_MSK; + if (val != BQ25180_DEVICE_ID) { + LOG_ERR("Invalid device id: %02x", val); + return -EINVAL; + } + + /* Disable the watchdog */ + ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_IC_CTRL, + BQ25180_WATCHDOG_SEL_1_MSK, + BQ25180_WATCHDOG_DISABLE); + if (ret < 0) { + return ret; + } + + if (cfg->initial_current_microamp > 0) { + bq25180_set_charge_current(dev, cfg->initial_current_microamp); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +#define CHARGER_BQ25180_INIT(inst) \ + static const struct bq25180_config bq25180_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .initial_current_microamp = DT_INST_PROP( \ + inst, constant_charge_current_max_microamp), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, bq25180_init, NULL, NULL, \ + &bq25180_config_##inst, POST_KERNEL, \ + CONFIG_CHARGER_INIT_PRIORITY, \ + &bq25180_api); + +DT_INST_FOREACH_STATUS_OKAY(CHARGER_BQ25180_INIT) diff --git a/drivers/charger/charger_handlers.c b/drivers/charger/charger_handlers.c index 417991f9f5f..4fdf6ca7140 100644 --- a/drivers/charger/charger_handlers.c +++ b/drivers/charger/charger_handlers.c @@ -36,3 +36,12 @@ static inline int z_vrfy_charger_set_prop(const struct device *dev, const charge } #include + +static inline int z_vrfy_charger_charge_enable(const struct device *dev, const bool enable) +{ + K_OOPS(K_SYSCALL_DRIVER_CHARGER(dev, charge_enable)); + + return z_impl_charger_charge_enable(dev, enable); +} + +#include diff --git a/drivers/charger/charger_max20335.c b/drivers/charger/charger_max20335.c index 75eae16f888..b4f98de69f2 100644 --- a/drivers/charger/charger_max20335.c +++ b/drivers/charger/charger_max20335.c @@ -235,15 +235,6 @@ static int max20335_set_prop(const struct device *dev, charger_prop_t prop, const union charger_propval *val) { switch (prop) { - case CHARGER_PROP_STATUS: - switch (val->status) { - case CHARGER_STATUS_CHARGING: - return max20335_set_enabled(dev, true); - case CHARGER_STATUS_NOT_CHARGING: - return max20335_set_enabled(dev, false); - default: - return -ENOTSUP; - } case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA: return max20335_set_constant_charge_current(dev, val->const_charge_current_ua); @@ -253,7 +244,6 @@ static int max20335_set_prop(const struct device *dev, charger_prop_t prop, default: return -ENOTSUP; } - } static int max20335_init(const struct device *dev) @@ -270,6 +260,7 @@ static int max20335_init(const struct device *dev) static const struct charger_driver_api max20335_driver_api = { .get_property = max20335_get_prop, .set_property = max20335_set_prop, + .charge_enable = max20335_set_enabled, }; #define MAX20335_DEFINE(inst) \ diff --git a/drivers/charger/emul_sbs_charger.c b/drivers/charger/emul_sbs_charger.c index 34d432c8fbb..90c64b908ab 100644 --- a/drivers/charger/emul_sbs_charger.c +++ b/drivers/charger/emul_sbs_charger.c @@ -25,10 +25,20 @@ struct sbs_charger_emul_cfg { uint16_t addr; }; +/** Run-time data used by the emulator */ +struct sbs_charger_emul_data { + uint16_t reg_charger_mode; +}; + static int emul_sbs_charger_reg_write(const struct emul *target, int reg, int val) { + struct sbs_charger_emul_data *data = target->data; + LOG_INF("write %x = %x", reg, val); switch (reg) { + case SBS_CHARGER_REG_CHARGER_MODE: + data->reg_charger_mode = val; + break; default: LOG_ERR("Unknown write %x", reg); return -EIO; @@ -132,10 +142,12 @@ static int emul_sbs_sbs_charger_init(const struct emul *target, const struct dev * Main instantiation macro. SBS Charger Emulator only implemented for I2C */ #define SBS_CHARGER_EMUL(n) \ + static struct sbs_charger_emul_data sbs_charger_emul_data_##n; \ + \ static const struct sbs_charger_emul_cfg sbs_charger_emul_cfg_##n = { \ .addr = DT_INST_REG_ADDR(n), \ }; \ - EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_charger_init, NULL, &sbs_charger_emul_cfg_##n, \ - &sbs_charger_emul_api_i2c, NULL) + EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_charger_init, &sbs_charger_emul_data_##n, \ + &sbs_charger_emul_cfg_##n, &sbs_charger_emul_api_i2c, NULL) DT_INST_FOREACH_STATUS_OKAY(SBS_CHARGER_EMUL) diff --git a/drivers/charger/sbs_charger.c b/drivers/charger/sbs_charger.c index 7cdc99b2a73..9017e1e60b8 100644 --- a/drivers/charger/sbs_charger.c +++ b/drivers/charger/sbs_charger.c @@ -66,6 +66,20 @@ static int sbs_cmd_reg_update(const struct device *dev, uint8_t reg_addr, uint16 return sbs_cmd_reg_write(dev, reg_addr, new_val); } +static int sbs_charger_charge_enable(const struct device *dev, const bool enable) +{ + uint16_t reg_val; + + if (!enable) { + reg_val = SBS_CHARGER_MODE_INHIBIT_CHARGE; + } else { + reg_val = 0; + } + + return sbs_cmd_reg_update(dev, SBS_CHARGER_REG_CHARGER_MODE, + SBS_CHARGER_MODE_INHIBIT_CHARGE, reg_val); +} + static int sbs_charger_get_prop(const struct device *dev, const charger_prop_t prop, union charger_propval *val) { @@ -123,18 +137,7 @@ static int sbs_charger_get_prop(const struct device *dev, const charger_prop_t p static int sbs_charger_set_prop(const struct device *dev, const charger_prop_t prop, const union charger_propval *val) { - uint16_t reg_val = 0; - - switch (prop) { - case CHARGER_PROP_STATUS: - if (val->status != CHARGER_STATUS_CHARGING) { - reg_val = SBS_CHARGER_MODE_INHIBIT_CHARGE; - } - return sbs_cmd_reg_update(dev, SBS_CHARGER_REG_CHARGER_MODE, - SBS_CHARGER_MODE_INHIBIT_CHARGE, reg_val); - default: - return -ENOTSUP; - } + return -ENOTSUP; } /** @@ -157,6 +160,7 @@ static int sbs_charger_init(const struct device *dev) static const struct charger_driver_api sbs_charger_driver_api = { .get_property = &sbs_charger_get_prop, .set_property = &sbs_charger_set_prop, + .charge_enable = &sbs_charger_charge_enable, }; #define SBS_CHARGER_INIT(inst) \ diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index a1f553fc134..596b07676e0 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -26,9 +26,10 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SMARTBOND clock_control_smartbond.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NUMAKER_SCC clock_control_numaker_scc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NXP_S32 clock_control_nxp_s32.c) -zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RA clock_control_ra.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RENESAS_RA clock_control_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AMBIQ clock_control_ambiq.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_PWM clock_control_pwm.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RPI_PICO clock_control_rpi_pico.c) if(CONFIG_CLOCK_CONTROL_STM32_CUBE) @@ -71,6 +72,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AGILEX5 clock_control_agilex5. if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) zephyr_library_sources(clock_control_renesas_cpg_mssr.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED clock_control_r8a7795_cpg_mssr.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_RENESAS_R8A779F0_CPG_MSSR_ENABLED clock_control_r8a779f0_cpg_mssr.c) endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 37cbb2e2895..b0c6cf8de48 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -80,10 +80,12 @@ source "drivers/clock_control/Kconfig.nxp_s32" source "drivers/clock_control/Kconfig.agilex5" -source "drivers/clock_control/Kconfig.ra" +source "drivers/clock_control/Kconfig.renesas_ra" source "drivers/clock_control/Kconfig.ambiq" source "drivers/clock_control/Kconfig.pwm" +source "drivers/clock_control/Kconfig.rpi_pico" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.ra b/drivers/clock_control/Kconfig.ra deleted file mode 100644 index 2b4aea0fb81..00000000000 --- a/drivers/clock_control/Kconfig.ra +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 TOKITA Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -config CLOCK_CONTROL_RA - bool "Renesas RA series clock generation circuit driver" - default y - depends on DT_HAS_RENESAS_RA_CLOCK_GENERATION_CIRCUIT_ENABLED - help - Enable Renesas RA series clock generation circuit driver. diff --git a/drivers/clock_control/Kconfig.rcar b/drivers/clock_control/Kconfig.rcar index b4a69a47e35..0caa0723554 100644 --- a/drivers/clock_control/Kconfig.rcar +++ b/drivers/clock_control/Kconfig.rcar @@ -1,9 +1,9 @@ -# Copyright (c) 2021-2022 IoT.bzh +# Copyright (c) 2021-2023 IoT.bzh # SPDX-License-Identifier: Apache-2.0 config CLOCK_CONTROL_RCAR_CPG_MSSR bool "RCar CPG MSSR driver" default y - depends on DT_HAS_RENESAS_R8A7795_CPG_MSSR_ENABLED + depends on SOC_FAMILY_RCAR help Enable support for Renesas RCar CPG MSSR driver. diff --git a/drivers/clock_control/Kconfig.renesas_ra b/drivers/clock_control/Kconfig.renesas_ra new file mode 100644 index 00000000000..5a14f593f9b --- /dev/null +++ b/drivers/clock_control/Kconfig.renesas_ra @@ -0,0 +1,9 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_RENESAS_RA + bool "Renesas RA series clock generation circuit driver" + default y + depends on DT_HAS_RENESAS_RA_CLOCK_GENERATION_CIRCUIT_ENABLED + help + Enable Renesas RA series clock generation circuit driver. diff --git a/drivers/clock_control/Kconfig.rpi_pico b/drivers/clock_control/Kconfig.rpi_pico new file mode 100644 index 00000000000..3c7c87121fd --- /dev/null +++ b/drivers/clock_control/Kconfig.rpi_pico @@ -0,0 +1,19 @@ +# Raspberry Pi Pico Clock Controller Driver configuration options + +# Copyright (c) 2022 Andrei-Edward Popa +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_RPI_PICO + bool "Raspberry Pi Pico Clock Controller Driver" + default y + depends on DT_HAS_RASPBERRYPI_PICO_CLOCK_CONTROLLER_ENABLED + +if CLOCK_CONTROL_RPI_PICO + +config RPI_PICO_ROSC_USE_MEASURED_FREQ + bool "Use measured frequency for ring oscillator" + help + Instead of the dts value, use the value measured by + the frequency counter as the rosc frequency. + +endif # CLOCK_CONTROL_RPI_PICO diff --git a/drivers/clock_control/Kconfig.stm32 b/drivers/clock_control/Kconfig.stm32 index 8d7890d1fdf..cccbe5e2e74 100644 --- a/drivers/clock_control/Kconfig.stm32 +++ b/drivers/clock_control/Kconfig.stm32 @@ -10,6 +10,8 @@ menuconfig CLOCK_CONTROL_STM32_CUBE select USE_STM32_LL_UTILS select USE_STM32_LL_RCC if (SOC_SERIES_STM32MP1X || SOC_SERIES_STM32H7X || \ SOC_SERIES_STM32F4X || SOC_SERIES_STM32F7X) + select RUNTIME_NMI if ($(dt_nodelabel_enabled,clk_hse) && \ + $(dt_nodelabel_has_prop,clk_hse,css-enabled)) help Enable driver for Reset & Clock Control subsystem found in STM32 family of MCUs diff --git a/drivers/clock_control/clock_control_esp32.c b/drivers/clock_control/clock_control_esp32.c index fba7091b871..4b8b01f521e 100644 --- a/drivers/clock_control/clock_control_esp32.c +++ b/drivers/clock_control/clock_control_esp32.c @@ -9,7 +9,7 @@ #define CPU_RESET_REASON RTC_SW_CPU_RESET -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) #define DT_CPU_COMPAT cdns_tensilica_xtensa_lx6 #undef CPU_RESET_REASON #define CPU_RESET_REASON SW_CPU_RESET @@ -56,7 +56,6 @@ struct esp32_clock_config { static uint8_t const xtal_freq[] = { #if defined(CONFIG_SOC_SERIES_ESP32) || \ - defined(CONFIG_SOC_SERIES_ESP32_NET) || \ defined(CONFIG_SOC_SERIES_ESP32S3) [ESP32_CLK_XTAL_24M] = 24, [ESP32_CLK_XTAL_26M] = 26, @@ -126,7 +125,7 @@ static int clock_control_esp32_get_rate(const struct device *dev, return 0; } -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) static void esp32_clock_perip_init(void) { uint32_t common_perip_clk; @@ -602,9 +601,3 @@ DEVICE_DT_DEFINE(DT_NODELABEL(rtc), PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_esp32_api); - -#ifndef CONFIG_SOC_SERIES_ESP32C3 -BUILD_ASSERT((CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) == - DT_PROP(DT_INST(0, DT_CPU_COMPAT), clock_frequency), - "SYS_CLOCK_HW_CYCLES_PER_SEC Value must be equal to CPU_Freq"); -#endif diff --git a/drivers/clock_control/clock_control_litex.c b/drivers/clock_control/clock_control_litex.c index b2d04a3cc92..2eb0c6b3589 100644 --- a/drivers/clock_control/clock_control_litex.c +++ b/drivers/clock_control/clock_control_litex.c @@ -18,6 +18,8 @@ #include #include +#include + LOG_MODULE_REGISTER(CLK_CTRL_LITEX, CONFIG_CLOCK_CONTROL_LOG_LEVEL); static struct litex_clk_device *ldev; /* global struct for whole driver */ diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index ab90602d2a4..6245788961c 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -106,6 +106,12 @@ static int mcux_ccm_on(const struct device *dev, CLOCK_EnableClock(lpuart_clocks[instance]); return 0; #endif + +#if defined(CONFIG_ETH_NXP_ENET) + case IMX_CCM_ENET_CLK: + CLOCK_EnableClock(kCLOCK_Enet); + return 0; +#endif default: (void)instance; return 0; @@ -231,6 +237,17 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, break; #endif +#ifdef CONFIG_ETH_NXP_ENET + case IMX_CCM_ENET_CLK: + *rate = CLOCK_GetIpgFreq(); + break; +#endif +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + case IMX_CCM_ENET_PLL: + *rate = CLOCK_GetPllFreq(kCLOCK_PllEnet); + break; +#endif + #ifdef CONFIG_UART_MCUX_IUART case IMX_CCM_UART1_CLK: case IMX_CCM_UART2_CLK: @@ -299,16 +316,64 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, / (CLOCK_GetDiv(kCLOCK_Sai3PreDiv) + 1) / (CLOCK_GetDiv(kCLOCK_Sai3Div) + 1); break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) + case IMX_CCM_FLEXSPI_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot); + break; +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + *rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot); + break; #endif } return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC Flexspi driver is enabled. + */ +#ifdef CONFIG_MEMC_MCUX_FLEXSPI +#define CCM_SET_FUNC_ATTR __ramfunc +#else +#define CCM_SET_FUNC_ATTR +#endif + +static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev, + clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + uint32_t clock_name = (uintptr_t)subsys; + uint32_t clock_rate = (uintptr_t)rate; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + __fallthrough; + case IMX_CCM_FLEXSPI2_CLK: +#if defined(CONFIG_SOC_SERIES_IMX_RT10XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI) + /* The SOC is using the FlexSPI for XIP. Therefore, + * the FlexSPI itself must be managed within the function, + * which is SOC specific. + */ + return flexspi_clock_set_freq(clock_name, clock_rate); +#endif + default: + /* Silence unused variable warning */ + ARG_UNUSED(clock_rate); + return -ENOTSUP; + } +} + + + static const struct clock_control_driver_api mcux_ccm_driver_api = { .on = mcux_ccm_on, .off = mcux_ccm_off, .get_rate = mcux_ccm_get_subsys_rate, + .set_rate = mcux_ccm_set_subsys_rate, }; static int mcux_ccm_init(const struct device *dev) diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev2.c b/drivers/clock_control/clock_control_mcux_ccm_rev2.c index 9a88a36823a..c99741a78f2 100644 --- a/drivers/clock_control/clock_control_mcux_ccm_rev2.c +++ b/drivers/clock_control/clock_control_mcux_ccm_rev2.c @@ -17,6 +17,11 @@ LOG_MODULE_REGISTER(clock_control); static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sub_system) { +#ifdef CONFIG_ETH_NXP_ENET + if ((uint32_t)sub_system == IMX_CCM_ENET_CLK) { + CLOCK_EnableClock(kCLOCK_Enet); + } +#endif return 0; } @@ -103,6 +108,39 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, clock_root = kCLOCK_Root_Sai4; break; #endif + +#ifdef CONFIG_ETH_NXP_ENET + case IMX_CCM_ENET_CLK: + clock_root = kCLOCK_Root_Bus; + break; +#endif + +#if defined(CONFIG_SOC_MIMX93_A55) && defined(CONFIG_DAI_NXP_SAI) + case IMX_CCM_SAI1_CLK: + case IMX_CCM_SAI2_CLK: + case IMX_CCM_SAI3_CLK: + clock_root = kCLOCK_Root_Sai1 + instance; + uint32_t mux = CLOCK_GetRootClockMux(clock_root); + uint32_t divider = CLOCK_GetRootClockDiv(clock_root); + + /* assumption: SAI's SRC is AUDIO_PLL */ + if (mux != 1) { + return -EINVAL; + } + + /* assumption: AUDIO_PLL's frequency is 393216000 Hz */ + *rate = 393216000 / divider; + + return 0; +#endif +#ifdef CONFIG_MEMC_MCUX_FLEXSPI + case IMX_CCM_FLEXSPI_CLK: + clock_root = kCLOCK_Root_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + clock_root = kCLOCK_Root_Flexspi2; + break; +#endif default: return -EINVAL; } @@ -114,10 +152,46 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev, return 0; } +/* + * Since this function is used to reclock the FlexSPI when running in + * XIP, it must be located in RAM when MEMC driver is enabled. + */ +#ifdef CONFIG_MEMC_MCUX_FLEXSPI +#define CCM_SET_FUNC_ATTR __ramfunc +#else +#define CCM_SET_FUNC_ATTR +#endif + +static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev, + clock_control_subsys_t subsys, + clock_control_subsys_rate_t rate) +{ + uint32_t clock_name = (uintptr_t)subsys; + uint32_t clock_rate = (uintptr_t)rate; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + __fallthrough; + case IMX_CCM_FLEXSPI2_CLK: +#if defined(CONFIG_SOC_SERIES_IMX_RT11XX) && defined(CONFIG_MEMC_MCUX_FLEXSPI) + /* The SOC is using the FlexSPI for XIP. Therefore, + * the FlexSPI itself must be managed within the function, + * which is SOC specific. + */ + return flexspi_clock_set_freq(clock_name, clock_rate); +#endif + default: + /* Silence unused variable warning */ + ARG_UNUSED(clock_rate); + return -ENOTSUP; + } +} + static const struct clock_control_driver_api mcux_ccm_driver_api = { .on = mcux_ccm_on, .off = mcux_ccm_off, .get_rate = mcux_ccm_get_subsys_rate, + .set_rate = mcux_ccm_set_subsys_rate, }; DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, diff --git a/drivers/clock_control/clock_control_mcux_sim.c b/drivers/clock_control/clock_control_mcux_sim.c index ce589c9a6bf..ed74ff941f5 100644 --- a/drivers/clock_control/clock_control_mcux_sim.c +++ b/drivers/clock_control/clock_control_mcux_sim.c @@ -20,6 +20,12 @@ static int mcux_sim_on(const struct device *dev, { clock_ip_name_t clock_ip_name = (clock_ip_name_t) sub_system; +#ifdef CONFIG_ETH_NXP_ENET + if ((uint32_t)sub_system == KINETIS_SIM_ENET_CLK) { + clock_ip_name = kCLOCK_Enet0; + } +#endif + CLOCK_EnableClock(clock_ip_name); return 0; @@ -45,6 +51,9 @@ static int mcux_sim_get_subsys_rate(const struct device *dev, case KINETIS_SIM_LPO_CLK: clock_name = kCLOCK_LpoClk; break; + case KINETIS_SIM_ENET_CLK: + clock_name = kCLOCK_CoreSysClk; + break; default: clock_name = (clock_name_t) sub_system; break; diff --git a/drivers/clock_control/clock_control_mcux_syscon.c b/drivers/clock_control/clock_control_mcux_syscon.c index 3dcc073954c..a0a7db57d28 100644 --- a/drivers/clock_control/clock_control_mcux_syscon.c +++ b/drivers/clock_control/clock_control_mcux_syscon.c @@ -178,6 +178,11 @@ static int mcux_lpc_syscon_clock_control_get_subsys_rate( case MCUX_LCDIF_PIXEL_CLK: *rate = CLOCK_GetDcPixelClkFreq(); break; +#endif +#if defined(CONFIG_AUDIO_DMIC_MCUX) + case MCUX_DMIC_CLK: + *rate = CLOCK_GetDmicClkFreq(); + break; #endif } diff --git a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c index 26b0b1959c6..a796c6efc6c 100644 --- a/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c +++ b/drivers/clock_control/clock_control_r8a7795_cpg_mssr.c @@ -19,12 +19,12 @@ LOG_MODULE_DECLARE(clock_control_rcar); -#define R8A7795_CLK_SD_STOP_BIT 8 -#define R8A7795_CLK_SD_DIV_MASK 0x3 +#define R8A7795_CLK_SD_STOP_BIT 8 +#define R8A7795_CLK_SD_DIV_MASK 0x3 #define R8A7795_CLK_SD_DIV_SHIFT 0 -#define R8A7795_CLK_SDH_STOP_BIT 9 -#define R8A7795_CLK_SDH_DIV_MASK 0x7 +#define R8A7795_CLK_SDH_STOP_BIT 9 +#define R8A7795_CLK_SDH_DIV_MASK 0x7 #define R8A7795_CLK_SDH_DIV_SHIFT 2 #define R8A7795_CLK_CANFD_STOP_BIT 8 @@ -40,8 +40,8 @@ struct r8a7795_cpg_mssr_data { /* NOTE: the array MUST be sorted by module field */ static struct cpg_clk_info_table core_props[] = { - RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S3D4, RCAR_CPG_NONE, - RCAR_CPG_NONE, RCAR_CPG_KHZ(66600)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S3D4, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66600)), RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0H, 0x0074, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_SD0, 0x0074, R8A7795_CLK_SD0H, RCAR_CPG_MHZ(800)), @@ -57,8 +57,8 @@ static struct cpg_clk_info_table core_props[] = { RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_CANFD, 0x0244, RCAR_CPG_NONE, RCAR_CPG_MHZ(800)), - RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S0D12, RCAR_CPG_NONE, - RCAR_CPG_NONE, RCAR_CPG_KHZ(66600)), + RCAR_CORE_CLK_INFO_ITEM(R8A7795_CLK_S0D12, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66600)), }; /* NOTE: the array MUST be sorted by module field */ @@ -72,8 +72,7 @@ static struct cpg_clk_info_table mod_props[] = { }; static int r8a7795_cpg_enable_disable_core(const struct device *dev, - struct cpg_clk_info_table *clk_info, - uint32_t enable) + struct cpg_clk_info_table *clk_info, uint32_t enable) { int ret = 0; uint32_t reg; @@ -113,14 +112,12 @@ static int r8a7795_cpg_enable_disable_core(const struct device *dev, return ret; } -static int r8a7795_cpg_core_clock_endisable(const struct device *dev, - struct rcar_cpg_clk *clk, +static int r8a7795_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk, bool enable) { struct cpg_clk_info_table *clk_info; struct r8a7795_cpg_mssr_data *data = dev->data; k_spinlock_key_t key; - int ret = 0; clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); if (!clk_info) { @@ -129,10 +126,11 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, if (enable) { if (clk->rate > 0) { + int ret; uintptr_t rate = clk->rate; ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, - (clock_control_subsys_rate_t)rate); + (clock_control_subsys_rate_t)rate); if (ret < 0) { return ret; } @@ -143,15 +141,14 @@ static int r8a7795_cpg_core_clock_endisable(const struct device *dev, r8a7795_cpg_enable_disable_core(dev, clk_info, enable); k_spin_unlock(&data->cmn.lock, key); - return ret; + return 0; } -static int r8a7795_cpg_mssr_start_stop(const struct device *dev, - clock_control_subsys_t sys, +static int r8a7795_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) { struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; - int ret = -EINVAL; + int ret; if (!dev || !sys) { return -EINVAL; @@ -166,6 +163,8 @@ static int r8a7795_cpg_mssr_start_stop(const struct device *dev, k_spin_unlock(&data->cmn.lock, key); } else if (clk->domain == CPG_CORE) { ret = r8a7795_cpg_core_clock_endisable(dev, clk, enable); + } else { + ret = -EINVAL; } return ret; @@ -173,8 +172,6 @@ static int r8a7795_cpg_mssr_start_stop(const struct device *dev, static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module) { - uint32_t divider = RCAR_CPG_NONE; - switch (module) { case R8A7795_CLK_SD0H: case R8A7795_CLK_SD1H: @@ -183,35 +180,29 @@ static uint32_t r8a7795_get_div_helper(uint32_t reg_val, uint32_t module) reg_val >>= R8A7795_CLK_SDH_DIV_SHIFT; /* setting of value bigger than 4 is prohibited */ if ((reg_val & R8A7795_CLK_SDH_DIV_MASK) < 5) { - divider = 1 << (reg_val & R8A7795_CLK_SDH_DIV_MASK); + return 1 << (reg_val & R8A7795_CLK_SDH_DIV_MASK); + } else { + return RCAR_CPG_NONE; } - break; case R8A7795_CLK_SD0: case R8A7795_CLK_SD1: case R8A7795_CLK_SD2: case R8A7795_CLK_SD3: /* convert only two possible values 0,1 to 2,4 */ - divider = 1 << ((reg_val & R8A7795_CLK_SD_DIV_MASK) + 1); - break; + return 1 << ((reg_val & R8A7795_CLK_SD_DIV_MASK) + 1); case R8A7795_CLK_CANFD: /* according to documentation, divider value stored in reg is equal to: val + 1 */ - divider = (reg_val & R8A7795_CLK_CANFD_DIV_MASK) + 1; - break; + return (reg_val & R8A7795_CLK_CANFD_DIV_MASK) + 1; case R8A7795_CLK_S3D4: case R8A7795_CLK_S0D12: - divider = 1; - break; + return 1; default: - break; + return RCAR_CPG_NONE; } - - return divider; } static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) { - int ret = -ENOTSUP; - switch (module) { case R8A7795_CLK_SD0: case R8A7795_CLK_SD1: @@ -222,50 +213,43 @@ static int r8a7795_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t /* convert 2/4 to 0/1 */ *divider >>= 2; *div_mask = R8A7795_CLK_SD_DIV_MASK << R8A7795_CLK_SD_DIV_SHIFT; - ret = 0; + return 0; } else { - ret = -EINVAL; + return -EINVAL; } - break; case R8A7795_CLK_SD0H: case R8A7795_CLK_SD1H: case R8A7795_CLK_SD2H: case R8A7795_CLK_SD3H: /* divider should be power of two and max possible value 16 */ if (!is_power_of_two(*divider) || *divider > 16) { - ret = -EINVAL; + return -EINVAL; break; } - ret = 0; /* 1,2,4,8,16 have to be converted to 0,1,2,3,4 and then shifted */ *divider = (find_lsb_set(*divider) - 1) << R8A7795_CLK_SDH_DIV_SHIFT; *div_mask = R8A7795_CLK_SDH_DIV_MASK << R8A7795_CLK_SDH_DIV_SHIFT; - break; + return 0; case R8A7795_CLK_CANFD: /* according to documentation, divider value stored in reg is equal to: val + 1 */ *divider -= 1; if (*divider <= R8A7795_CLK_CANFD_DIV_MASK) { - ret = 0; *div_mask = R8A7795_CLK_CANFD_DIV_MASK; + return 0; } else { - ret = -EINVAL; + return -EINVAL; } - break; default: - break; + return -ENOTSUP; } - - return ret; } -static int r8a7795_cpg_mssr_start(const struct device *dev, - clock_control_subsys_t sys) +static int r8a7795_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) { return r8a7795_cpg_mssr_start_stop(dev, sys, true); } -static int r8a7795_cpg_mssr_stop(const struct device *dev, - clock_control_subsys_t sys) +static int r8a7795_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys) { return r8a7795_cpg_mssr_start_stop(dev, sys, false); } diff --git a/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c new file mode 100644 index 00000000000..c0d9f15cd58 --- /dev/null +++ b/drivers/clock_control/clock_control_r8a779f0_cpg_mssr.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 EPAM Systems + * Copyright (c) 2023 IoT.bzh + * + * r8a779f0 Clock Pulse Generator / Module Standby and Software Reset + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_r8a779f0_cpg_mssr + +#include +#include +#include +#include +#include +#include +#include +#include "clock_control_renesas_cpg_mssr.h" + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_DECLARE(clock_control_rcar); + +struct r8a779f0_cpg_mssr_cfg { + DEVICE_MMIO_ROM; /* Must be first */ +}; + +struct r8a779f0_cpg_mssr_data { + struct rcar_cpg_mssr_data cmn; /* Must be first */ +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table core_props[] = { + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_S0D12_PER, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(66660)), + + RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE, + RCAR_CPG_KHZ(16660)), +}; + +/* NOTE: the array MUST be sorted by module field */ +static struct cpg_clk_info_table mod_props[] = { + RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER), + RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER), + + RCAR_MOD_CLK_INFO_ITEM(915, R8A779F0_CLK_CL16M), +}; + +static int r8a779f0_cpg_enable_disable_core(const struct device *dev, + struct cpg_clk_info_table *clk_info, uint32_t enable) +{ + ARG_UNUSED(dev); + ARG_UNUSED(clk_info); + ARG_UNUSED(enable); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk, + bool enable) +{ + struct cpg_clk_info_table *clk_info; + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module); + if (!clk_info) { + return -EINVAL; + } + + if (enable) { + if (clk->rate > 0) { + int ret; + uintptr_t rate = clk->rate; + + ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk, + (clock_control_subsys_rate_t)rate); + if (ret < 0) { + return ret; + } + } + } + + key = k_spin_lock(&data->cmn.lock); + r8a779f0_cpg_enable_disable_core(dev, clk_info, enable); + k_spin_unlock(&data->cmn.lock, key); + + return 0; +} + +int r8a779f0_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable) +{ + struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys; + int ret; + + if (!dev || !sys) { + return -EINVAL; + } + + if (clk->domain == CPG_MOD) { + struct r8a779f0_cpg_mssr_data *data = dev->data; + k_spinlock_key_t key; + + key = k_spin_lock(&data->cmn.lock); + ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable); + k_spin_unlock(&data->cmn.lock, key); + } else if (clk->domain == CPG_CORE) { + ret = r8a779f0_cpg_core_clock_endisable(dev, clk, enable); + } else { + ret = -EINVAL; + } + + return ret; +} + +static uint32_t r8a779f0_get_div_helper(uint32_t reg_val, uint32_t module) +{ + switch (module) { + case R8A779F0_CLK_S0D12_PER: + case R8A779F0_CLK_CL16M: + return 1; + default: + return RCAR_CPG_NONE; + } +} + +static int r8a779f0_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask) +{ + ARG_UNUSED(module); + ARG_UNUSED(divider); + ARG_UNUSED(div_mask); + + return -ENOTSUP; +} + +static int r8a779f0_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, true); +} + +static int r8a779f0_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys) +{ + return r8a779f0_cpg_mssr_start_stop(dev, sys, false); +} + +static int r8a779f0_cpg_mssr_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + rcar_cpg_build_clock_relationship(dev); + rcar_cpg_update_all_in_out_freq(dev); + return 0; +} + +static const struct clock_control_driver_api r8a779f0_cpg_mssr_api = { + .on = r8a779f0_cpg_mssr_start, + .off = r8a779f0_cpg_mssr_stop, + .get_rate = rcar_cpg_get_rate, + .set_rate = rcar_cpg_set_rate, +}; + +#define R8A779F0_MSSR_INIT(inst) \ + static struct r8a779f0_cpg_mssr_cfg cpg_mssr##inst##_cfg = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ + }; \ + \ + static struct r8a779f0_cpg_mssr_data cpg_mssr##inst##_data = { \ + .cmn.clk_info_table[CPG_CORE] = core_props, \ + .cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props), \ + .cmn.clk_info_table[CPG_MOD] = mod_props, \ + .cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props), \ + .cmn.get_div_helper = r8a779f0_get_div_helper, \ + .cmn.set_rate_helper = r8a779f0_set_rate_helper \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &r8a779f0_cpg_mssr_init, \ + NULL, \ + &cpg_mssr##inst##_data, \ + &cpg_mssr##inst##_cfg, \ + PRE_KERNEL_1, \ + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ + &r8a779f0_cpg_mssr_api); + +DT_INST_FOREACH_STATUS_OKAY(R8A779F0_MSSR_INIT) diff --git a/drivers/clock_control/clock_control_ra.c b/drivers/clock_control/clock_control_ra.c deleted file mode 100644 index b1008e3bf83..00000000000 --- a/drivers/clock_control/clock_control_ra.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (c) 2023 TOKITA Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#define DT_DRV_COMPAT renesas_ra_clock_generation_circuit - -#include -#include -#include -#include - -#if DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, pll)) -#define SYSCLK_SRC pll -#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, mosc)) -#define SYSCLK_SRC moco -#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, sosc)) -#define SYSCLK_SRC soco -#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, hoco)) -#define SYSCLK_SRC hoco -#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, moco)) -#define SYSCLK_SRC moco -#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, loco)) -#define SYSCLK_SRC loco -#else -#error Unknown clock source -#endif - -#define FREQ_iclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, iclk_div)) -#define FREQ_pclka (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclka_div)) -#define FREQ_pclkb (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkb_div)) -#define FREQ_pclkc (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkc_div)) -#define FREQ_pclkd (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkd_div)) -#define FREQ_fclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, fclk_div)) - -#define CLKSRC_FREQ(clk) DT_PROP(DT_PATH(clocks, clk), clock_frequency) - -#define IS_CLKSRC_ENABLED(clk) DT_NODE_HAS_STATUS(DT_PATH(clocks, clk), okay) - -#define SCKSCR_INIT_VALUE _CONCAT(CLKSRC_, SYSCLK_SRC) - -#define SCKDIV_ENABLED(clk) DT_INST_NODE_HAS_PROP(0, clk##_div) -#define SCKDIV_VAL(clk) _CONCAT(SCKDIV_, DT_INST_PROP(0, clk##_div)) -#define SCKDIV_POS(clk) _CONCAT(SCKDIV_POS_, clk) - -#define SCKDIVCR_BITS(clk) \ - COND_CODE_1(SCKDIV_ENABLED(clk), ((SCKDIV_VAL(clk) & 0xFU) << SCKDIV_POS(clk)), (0U)) - -#define SCKDIVCR_INIT_VALUE \ - (SCKDIVCR_BITS(iclk) | SCKDIVCR_BITS(pclka) | SCKDIVCR_BITS(pclkb) | \ - SCKDIVCR_BITS(pclkc) | SCKDIVCR_BITS(pclkd) | SCKDIVCR_BITS(bclk) | SCKDIVCR_BITS(fclk)) - -#define HOCOWTCR_INIT_VALUE (6) - -/* - * Required cycles for sub-clokc stabilizing. - */ -#define SUBCLK_STABILIZE_CYCLES 5 - -extern int z_clock_hw_cycles_per_sec; - -enum { - CLKSRC_hoco = 0, - CLKSRC_moco, - CLKSRC_loco, - CLKSRC_mosc, - CLKSRC_sosc, - CLKSRC_pll, -}; - -enum { - SCKDIV_1 = 0, - SCKDIV_2, - SCKDIV_4, - SCKDIV_8, - SCKDIV_16, - SCKDIV_32, - SCKDIV_64, - SCKDIV_128, - SCKDIV_3, - SCKDIV_6, - SCKDIV_12 -}; - -enum { - SCKDIV_POS_pclkd = 0x0U, - SCKDIV_POS_pclkc = 0x4U, - SCKDIV_POS_pclkb = 0x8U, - SCKDIV_POS_pclka = 0xcU, - SCKDIV_POS_bclk = 0x10U, - SCKDIV_POS_pclke = 0x14U, - SCKDIV_POS_iclk = 0x18U, - SCKDIV_POS_fclk = 0x1cU -}; - -enum { - OSCSF_HOCOSF_POS = 0, - OSCSF_MOSCSF_POS = 3, - OSCSF_PLLSF_POS = 5, -}; - -enum { - OPCCR_OPCMTSF_POS = 4, -}; - -static const uint32_t PRCR_KEY = 0xA500U; -static const uint32_t PRCR_CLOCKS = 0x1U; -static const uint32_t PRCR_LOW_POWER = 0x2U; - -enum { -#if DT_INST_REG_SIZE_BY_NAME(0, mstp) == 16 - MSTPCRA_OFFSET = -0x4, -#else - MSTPCRA_OFFSET = 0x0, -#endif - MSTPCRB_OFFSET = (MSTPCRA_OFFSET + 0x4), - MSTPCRC_OFFSET = (MSTPCRB_OFFSET + 0x4), - MSTPCRD_OFFSET = (MSTPCRC_OFFSET + 0x4), - MSTPCRE_OFFSET = (MSTPCRD_OFFSET + 0x4), -}; - -enum { - SCKDIVCR_OFFSET = 0x021, - SCKSCR_OFFSET = 0x026, - MEMWAIT_OFFSET = 0x031, - MOSCCR_OFFSET = 0x032, - HOCOCR_OFFSET = 0x036, - OSCSF_OFFSET = 0x03C, - CKOCR_OFFSET = 0x03E, - OPCCR_OFFSET = 0x0A0, - HOCOWTCR_OFFSET = 0x0A5, - PRCR_OFFSET = 0x3FE, - SOSCCR_OFFSET = 0x480, -}; - -enum { - SCRSCK_hoco, - SCRSCK_moco, - SCRSCK_loco, - SCRSCK_mosc, - SCRSCK_sosc, - SCRSCK_pll, -}; - -static const int clock_freqs[] = { - COND_CODE_1(IS_CLKSRC_ENABLED(hoco), (CLKSRC_FREQ(hoco)), (0)), - COND_CODE_1(IS_CLKSRC_ENABLED(moco), (CLKSRC_FREQ(moco)), (0)), - COND_CODE_1(IS_CLKSRC_ENABLED(loco), (CLKSRC_FREQ(loco)), (0)), - COND_CODE_1(IS_CLKSRC_ENABLED(mosc), (CLKSRC_FREQ(mosc)), (0)), - COND_CODE_1(IS_CLKSRC_ENABLED(sosc), (CLKSRC_FREQ(sosc)), (0)), - COND_CODE_1(IS_CLKSRC_ENABLED(pll), - (DT_PROP(DT_PHANDLE_BY_IDX(DT_PATH(clocks, pll), clocks, 0), clock_frequency) * - DT_PROP(DT_PATH(clocks, pll), clock_mult) / - DT_PROP(DT_PATH(clocks, pll), clock_div)), - (0)), -}; - -static uint32_t MSTP_read(size_t offset) -{ - return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset); -} - -static void MSTP_write(size_t offset, uint32_t value) -{ - sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset); -} - -static uint8_t SYSTEM_read8(size_t offset) -{ - return sys_read8(DT_INST_REG_ADDR_BY_NAME(0, system) + offset); -} - -static void SYSTEM_write8(size_t offset, uint8_t value) -{ - sys_write8(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); -} - -static void SYSTEM_write16(size_t offset, uint16_t value) -{ - sys_write16(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); -} - -static void SYSTEM_write32(size_t offset, uint32_t value) -{ - sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); -} - -static int clock_control_ra_on(const struct device *dev, clock_control_subsys_t subsys) -{ - uint32_t clkid = (uint32_t)subsys; - int lock = irq_lock(); - - MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid), - MSTP_read(MSTPCRB_OFFSET) & ~RA_CLOCK_BIT(clkid)); - irq_unlock(lock); - - return 0; -} - -static int clock_control_ra_off(const struct device *dev, clock_control_subsys_t subsys) -{ - uint32_t clkid = (uint32_t)subsys; - int lock = irq_lock(); - - MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid), - MSTP_read(MSTPCRB_OFFSET) | RA_CLOCK_BIT(clkid)); - irq_unlock(lock); - - return 0; -} - -static int clock_control_ra_get_rate(const struct device *dev, clock_control_subsys_t subsys, - uint32_t *rate) -{ - uint32_t clkid = (uint32_t)subsys; - - switch (clkid & 0xFFFFFF00) { - case RA_CLOCK_SCI(0): - *rate = FREQ_pclka; - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct clock_control_driver_api ra_clock_control_driver_api = { - .on = clock_control_ra_on, - .off = clock_control_ra_off, - .get_rate = clock_control_ra_get_rate, -}; - -static void crude_busy_loop_impl(uint32_t cycles) -{ - __asm__ volatile(".align 8\n" - "busy_loop:\n" - " sub r0, r0, #1\n" - " cmp r0, #0\n" - " bne.n busy_loop\n"); -} - -static inline void crude_busy_loop(uint32_t wait_us) -{ - static const uint64_t cycles_per_loop = 4; - - crude_busy_loop_impl(sys_clock_hw_cycles_per_sec() * wait_us / USEC_PER_SEC / - cycles_per_loop); -} - -static int clock_control_ra_init(const struct device *dev) -{ - uint8_t sysclk = SYSTEM_read8(SCKSCR_OFFSET); - - z_clock_hw_cycles_per_sec = clock_freqs[sysclk]; - - SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER); - - if (clock_freqs[SCRSCK_hoco] == 64000000) { - SYSTEM_write8(HOCOWTCR_OFFSET, HOCOWTCR_INIT_VALUE); - } - - SYSTEM_write8(SOSCCR_OFFSET, !IS_CLKSRC_ENABLED(sosc)); - SYSTEM_write8(MOSCCR_OFFSET, !IS_CLKSRC_ENABLED(mosc)); - SYSTEM_write8(HOCOCR_OFFSET, !IS_CLKSRC_ENABLED(hoco)); - - if (IS_CLKSRC_ENABLED(sosc)) { - crude_busy_loop(z_clock_hw_cycles_per_sec / clock_freqs[CLKSRC_sosc] * - SUBCLK_STABILIZE_CYCLES); - } - - if (IS_CLKSRC_ENABLED(mosc)) { - while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_MOSCSF_POS)) != - BIT(OSCSF_MOSCSF_POS)) { - ; - } - } - - if (IS_CLKSRC_ENABLED(hoco)) { - while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_HOCOSF_POS)) != - BIT(OSCSF_HOCOSF_POS)) { - ; - } - } - - SYSTEM_write32(SCKDIVCR_OFFSET, SCKDIVCR_INIT_VALUE); - SYSTEM_write8(SCKSCR_OFFSET, SCKSCR_INIT_VALUE); - - z_clock_hw_cycles_per_sec = clock_freqs[sysclk]; - - SYSTEM_write8(OPCCR_OFFSET, 0); - while ((SYSTEM_read8(OPCCR_OFFSET) & BIT(OPCCR_OPCMTSF_POS)) != 0) { - ; - } - - SYSTEM_write8(MEMWAIT_OFFSET, 1); - SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER); - - return 0; -} - -DEVICE_DT_INST_DEFINE(0, &clock_control_ra_init, NULL, NULL, NULL, PRE_KERNEL_1, - CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &ra_clock_control_driver_api); diff --git a/drivers/clock_control/clock_control_renesas_cpg_mssr.h b/drivers/clock_control/clock_control_renesas_cpg_mssr.h index d616567763e..6829d5a96b6 100644 --- a/drivers/clock_control/clock_control_renesas_cpg_mssr.h +++ b/drivers/clock_control/clock_control_renesas_cpg_mssr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 IoT.bzh + * Copyright (c) 2022-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -95,20 +95,34 @@ static const uint16_t srcr[] = { 0x0BC, 0x0C4, 0x1C8, 0x1CC, 0x920, 0x924, 0x928, 0x92C, }; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +/* Software Reset Clearing Register offsets */ +#define SRSTCLR(i) (0x2C80 + (i) * 4) -/* CAN FD Clock Frequency Control Register */ -#define CANFDCKCR 0x244 - -/* Clock stop bit */ -#define CANFDCKCR_CKSTP BIT(8) +/* CPG write protect offset */ +#define CPGWPR 0x0 -/* CANFD Clock */ -#define CANFDCKCR_PARENT_CLK_RATE 800000000 -#define CANFDCKCR_DIVIDER_MASK 0x1FF +/* Realtime Module Stop Control Register offsets */ +static const uint16_t mstpcr[] = { + 0x2D00, 0x2D04, 0x2D08, 0x2D0C, + 0x2D10, 0x2D14, 0x2D18, 0x2D1C, + 0x2D20, 0x2D24, 0x2D28, 0x2D2C, + 0x2D30, 0x2D34, 0x2D38, 0x2D3C, + 0x2D40, 0x2D44, 0x2D48, 0x2D4C, + 0x2D50, 0x2D54, 0x2D58, 0x2D5C, + 0x2D60, 0x2D64, 0x2D68, 0x2D6C, +}; -/* Peripherals Clocks */ -#define S3D4_CLK_RATE 66600000 /* SCIF */ -#define S0D12_CLK_RATE 66600000 /* PWM */ +/* Software Reset Register offsets */ +static const uint16_t srcr[] = { + 0x2C00, 0x2C04, 0x2C08, 0x2C0C, + 0x2C10, 0x2C14, 0x2C18, 0x2C1C, + 0x2C20, 0x2C24, 0x2C28, 0x2C2C, + 0x2C30, 0x2C34, 0x2C38, 0x2C3C, + 0x2C40, 0x2C44, 0x2C48, 0x2C4C, + 0x2C50, 0x2C54, 0x2C58, 0x2C5C, + 0x2C60, 0x2C64, 0x2C68, 0x2C6C, +}; #endif /* CONFIG_SOC_SERIES_RCAR_GEN3 */ void rcar_cpg_write(uint32_t base_address, uint32_t reg, uint32_t val); diff --git a/drivers/clock_control/clock_control_renesas_ra.c b/drivers/clock_control/clock_control_renesas_ra.c new file mode 100644 index 00000000000..382625c2a2f --- /dev/null +++ b/drivers/clock_control/clock_control_renesas_ra.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define DT_DRV_COMPAT renesas_ra_clock_generation_circuit + +#include +#include +#include +#include + +#if DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, pll)) +#define SYSCLK_SRC pll +#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, mosc)) +#define SYSCLK_SRC mosc +#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, sosc)) +#define SYSCLK_SRC soco +#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, hoco)) +#define SYSCLK_SRC hoco +#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, moco)) +#define SYSCLK_SRC moco +#elif DT_SAME_NODE(DT_INST_PROP(0, clock_source), DT_PATH(clocks, loco)) +#define SYSCLK_SRC loco +#else +#error Unknown clock source +#endif + +#define FREQ_iclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, iclk_div)) +#define FREQ_pclka (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclka_div)) +#define FREQ_pclkb (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkb_div)) +#define FREQ_pclkc (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkc_div)) +#define FREQ_pclkd (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, pclkd_div)) +#define FREQ_fclk (clock_freqs[_CONCAT(SCRSCK_, SYSCLK_SRC)] / DT_INST_PROP(0, fclk_div)) + +#define CLKSRC_FREQ(clk) DT_PROP(DT_PATH(clocks, clk), clock_frequency) + +#define IS_CLKSRC_ENABLED(clk) DT_NODE_HAS_STATUS(DT_PATH(clocks, clk), okay) + +#define SCKSCR_INIT_VALUE _CONCAT(CLKSRC_, SYSCLK_SRC) + +#define SCKDIV_ENABLED(clk) DT_INST_NODE_HAS_PROP(0, clk##_div) +#define SCKDIV_VAL(clk) _CONCAT(SCKDIV_, DT_INST_PROP(0, clk##_div)) +#define SCKDIV_POS(clk) _CONCAT(SCKDIV_POS_, clk) + +#define SCKDIVCR_BITS(clk) \ + COND_CODE_1(SCKDIV_ENABLED(clk), ((SCKDIV_VAL(clk) & 0xFU) << SCKDIV_POS(clk)), (0U)) + +#define SCKDIVCR_INIT_VALUE \ + (SCKDIVCR_BITS(iclk) | SCKDIVCR_BITS(pclka) | SCKDIVCR_BITS(pclkb) | \ + SCKDIVCR_BITS(pclkc) | SCKDIVCR_BITS(pclkd) | SCKDIVCR_BITS(bclk) | SCKDIVCR_BITS(fclk)) + +#define HOCOWTCR_INIT_VALUE (6) + +/* + * Required cycles for sub-clokc stabilizing. + */ +#define SUBCLK_STABILIZE_CYCLES 5 + +extern int z_clock_hw_cycles_per_sec; + +enum { + CLKSRC_hoco = 0, + CLKSRC_moco, + CLKSRC_loco, + CLKSRC_mosc, + CLKSRC_sosc, + CLKSRC_pll, +}; + +enum { + SCKDIV_1 = 0, + SCKDIV_2, + SCKDIV_4, + SCKDIV_8, + SCKDIV_16, + SCKDIV_32, + SCKDIV_64, + SCKDIV_128, + SCKDIV_3, + SCKDIV_6, + SCKDIV_12 +}; + +enum { + SCKDIV_POS_pclkd = 0x0U, + SCKDIV_POS_pclkc = 0x4U, + SCKDIV_POS_pclkb = 0x8U, + SCKDIV_POS_pclka = 0xcU, + SCKDIV_POS_bclk = 0x10U, + SCKDIV_POS_pclke = 0x14U, + SCKDIV_POS_iclk = 0x18U, + SCKDIV_POS_fclk = 0x1cU +}; + +enum { + OSCSF_HOCOSF_POS = 0, + OSCSF_MOSCSF_POS = 3, + OSCSF_PLLSF_POS = 5, +}; + +enum { + OPCCR_OPCMTSF_POS = 4, +}; + +static const uint32_t PRCR_KEY = 0xA500U; +static const uint32_t PRCR_CLOCKS = 0x1U; +static const uint32_t PRCR_LOW_POWER = 0x2U; + +enum { +#if DT_INST_REG_SIZE_BY_NAME(0, mstp) == 16 + MSTPCRA_OFFSET = -0x4, +#else + MSTPCRA_OFFSET = 0x0, +#endif + MSTPCRB_OFFSET = (MSTPCRA_OFFSET + 0x4), + MSTPCRC_OFFSET = (MSTPCRB_OFFSET + 0x4), + MSTPCRD_OFFSET = (MSTPCRC_OFFSET + 0x4), + MSTPCRE_OFFSET = (MSTPCRD_OFFSET + 0x4), +}; + +enum { + SCKDIVCR_OFFSET = 0x020, + SCKSCR_OFFSET = 0x026, + MEMWAIT_OFFSET = 0x031, + MOSCCR_OFFSET = 0x032, + HOCOCR_OFFSET = 0x036, + OSCSF_OFFSET = 0x03C, + CKOCR_OFFSET = 0x03E, + OPCCR_OFFSET = 0x0A0, + HOCOWTCR_OFFSET = 0x0A5, + PRCR_OFFSET = 0x3FE, + SOSCCR_OFFSET = 0x480, +}; + +enum { + SCRSCK_hoco, + SCRSCK_moco, + SCRSCK_loco, + SCRSCK_mosc, + SCRSCK_sosc, + SCRSCK_pll, +}; + +static const int clock_freqs[] = { + COND_CODE_1(IS_CLKSRC_ENABLED(hoco), (CLKSRC_FREQ(hoco)), (0)), + COND_CODE_1(IS_CLKSRC_ENABLED(moco), (CLKSRC_FREQ(moco)), (0)), + COND_CODE_1(IS_CLKSRC_ENABLED(loco), (CLKSRC_FREQ(loco)), (0)), + COND_CODE_1(IS_CLKSRC_ENABLED(mosc), (CLKSRC_FREQ(mosc)), (0)), + COND_CODE_1(IS_CLKSRC_ENABLED(sosc), (CLKSRC_FREQ(sosc)), (0)), + COND_CODE_1(IS_CLKSRC_ENABLED(pll), + (DT_PROP(DT_PHANDLE_BY_IDX(DT_PATH(clocks, pll), clocks, 0), clock_frequency) * + DT_PROP(DT_PATH(clocks, pll), clock_mult) / + DT_PROP(DT_PATH(clocks, pll), clock_div)), + (0)), +}; + +static uint32_t MSTP_read(size_t offset) +{ + return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset); +} + +static void MSTP_write(size_t offset, uint32_t value) +{ + sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, mstp) + offset); +} + +static uint8_t SYSTEM_read8(size_t offset) +{ + return sys_read8(DT_INST_REG_ADDR_BY_NAME(0, system) + offset); +} + +static void SYSTEM_write8(size_t offset, uint8_t value) +{ + sys_write8(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); +} + +static void SYSTEM_write16(size_t offset, uint16_t value) +{ + sys_write16(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); +} + +static void SYSTEM_write32(size_t offset, uint32_t value) +{ + sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, system) + offset); +} + +static int clock_control_ra_on(const struct device *dev, clock_control_subsys_t subsys) +{ + uint32_t clkid = (uint32_t)subsys; + int lock = irq_lock(); + + MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid), + MSTP_read(MSTPCRB_OFFSET) & ~RA_CLOCK_BIT(clkid)); + irq_unlock(lock); + + return 0; +} + +static int clock_control_ra_off(const struct device *dev, clock_control_subsys_t subsys) +{ + uint32_t clkid = (uint32_t)subsys; + int lock = irq_lock(); + + MSTP_write(MSTPCRA_OFFSET + RA_CLOCK_GROUP(clkid), + MSTP_read(MSTPCRB_OFFSET) | RA_CLOCK_BIT(clkid)); + irq_unlock(lock); + + return 0; +} + +static int clock_control_ra_get_rate(const struct device *dev, clock_control_subsys_t subsys, + uint32_t *rate) +{ + uint32_t clkid = (uint32_t)subsys; + + switch (clkid & 0xFFFFFF00) { + case RA_CLOCK_SCI(0): + *rate = FREQ_pclka; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct clock_control_driver_api ra_clock_control_driver_api = { + .on = clock_control_ra_on, + .off = clock_control_ra_off, + .get_rate = clock_control_ra_get_rate, +}; + +static void crude_busy_loop_impl(uint32_t cycles) +{ + __asm__ volatile(".align 8\n" + "busy_loop:\n" + " sub r0, r0, #1\n" + " cmp r0, #0\n" + " bne.n busy_loop\n"); +} + +static inline void crude_busy_loop(uint32_t wait_us) +{ + static const uint64_t cycles_per_loop = 4; + + crude_busy_loop_impl(sys_clock_hw_cycles_per_sec() * wait_us / USEC_PER_SEC / + cycles_per_loop); +} + +static int clock_control_ra_init(const struct device *dev) +{ + uint8_t sysclk = SYSTEM_read8(SCKSCR_OFFSET); + + z_clock_hw_cycles_per_sec = clock_freqs[sysclk]; + + SYSTEM_write16(PRCR_OFFSET, PRCR_KEY | PRCR_CLOCKS | PRCR_LOW_POWER); + + if (clock_freqs[SCRSCK_hoco] == 64000000) { + SYSTEM_write8(HOCOWTCR_OFFSET, HOCOWTCR_INIT_VALUE); + } + + SYSTEM_write8(SOSCCR_OFFSET, !IS_CLKSRC_ENABLED(sosc)); + SYSTEM_write8(MOSCCR_OFFSET, !IS_CLKSRC_ENABLED(mosc)); + SYSTEM_write8(HOCOCR_OFFSET, !IS_CLKSRC_ENABLED(hoco)); + + if (IS_CLKSRC_ENABLED(sosc)) { + crude_busy_loop(z_clock_hw_cycles_per_sec / clock_freqs[CLKSRC_sosc] * + SUBCLK_STABILIZE_CYCLES); + } + + if (IS_CLKSRC_ENABLED(mosc)) { + while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_MOSCSF_POS)) != + BIT(OSCSF_MOSCSF_POS)) { + ; + } + } + + if (IS_CLKSRC_ENABLED(hoco)) { + while ((SYSTEM_read8(OSCSF_OFFSET) & BIT(OSCSF_HOCOSF_POS)) != + BIT(OSCSF_HOCOSF_POS)) { + ; + } + } + + SYSTEM_write32(SCKDIVCR_OFFSET, SCKDIVCR_INIT_VALUE); + SYSTEM_write8(SCKSCR_OFFSET, SCKSCR_INIT_VALUE); + + /* re-read system clock setting and apply to hw_cycles */ + sysclk = SYSTEM_read8(SCKSCR_OFFSET); + z_clock_hw_cycles_per_sec = clock_freqs[sysclk]; + + SYSTEM_write8(OPCCR_OFFSET, 0); + while ((SYSTEM_read8(OPCCR_OFFSET) & BIT(OPCCR_OPCMTSF_POS)) != 0) { + ; + } + + SYSTEM_write8(MEMWAIT_OFFSET, 1); + SYSTEM_write16(PRCR_OFFSET, PRCR_KEY); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, &clock_control_ra_init, NULL, NULL, NULL, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &ra_clock_control_driver_api); diff --git a/drivers/clock_control/clock_control_rpi_pico.c b/drivers/clock_control/clock_control_rpi_pico.c new file mode 100644 index 00000000000..4deec67423b --- /dev/null +++ b/drivers/clock_control/clock_control_rpi_pico.c @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2022 Andrei-Edward Popa + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT raspberrypi_pico_clock_controller + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Undefine to prevent conflicts with header definitions */ +#undef pll_sys +#undef pll_usb + +#define CTRL_SRC_LSB CLOCKS_CLK_REF_CTRL_SRC_LSB +#define CTRL_SRC_BITS CLOCKS_CLK_REF_CTRL_SRC_BITS +#define CTRL_AUXSRC_LSB CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_LSB +#define CTRL_AUXSRC_BITS CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_BITS +#define CTRL_ENABLE_BITS CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS +#define DIV_FRAC_BITS CLOCKS_CLK_GPOUT0_DIV_FRAC_BITS +#define DIV_INT_BITS CLOCKS_CLK_GPOUT0_DIV_INT_BITS +#define DIV_INT_LSB CLOCKS_CLK_GPOUT0_DIV_INT_LSB + +#define PLL_VCO_FREQ_MIN 750000000 +#define PLL_VCO_FREQ_MAX 1600000000 +#define PLL_FB_DIV_MIN 16 +#define PLL_FB_DIV_MAX 320 +#define PLL_POST_DIV_MIN 1 +#define PLL_POST_DIV_MAX 7 + +#define ROSC_PHASE_PASSWD_VALUE_PASS _u(0xAA) + +#define STAGE_DS(n) \ + (COND_CODE_1( \ + DT_PROP_HAS_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n), \ + (DT_PROP_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), stage_drive_strength, n) & \ + ROSC_FREQA_DS0_BITS), \ + (0)) \ + << (n * 3)) + +#define CLK_SRC_IS(clk, src) \ + DT_SAME_NODE(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), 0), \ + DT_INST_CLOCKS_CTLR_BY_NAME(0, src)) + +#define REF_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), clock_div) +#define FB_DIV(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), fb_div) +#define POST_DIV1(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div1) +#define POST_DIV2(pll) DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), post_div2) +#define VCO_FREQ(pll) ((CLOCK_FREQ_xosc / REF_DIV(pll)) * FB_DIV(pll)) + +/* + * Using the 'clock-names[0]' for expanding macro to frequency value. + * The 'clock-names[0]' is set same as label value that given to the node itself. + * Use it for traverse clock tree to find root of clock source. + */ +#define CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, clk) +#define SRC_CLOCK(clk) DT_STRING_TOKEN_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk), \ + clock_names, 0) +#define SRC_CLOCK_FREQ(clk) _CONCAT(CLOCK_FREQ_, SRC_CLOCK(clk)) + +#define PLL_FREQ(pll) \ + (DT_PROP(DT_CLOCKS_CTLR_BY_IDX(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll), 0), clock_frequency) / \ + REF_DIV(pll) * FB_DIV(pll) / POST_DIV1(pll) / POST_DIV2(pll)) + +#define CLOCK_FREQ_clk_gpout0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout0), clock_frequency) +#define CLOCK_FREQ_clk_gpout1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout1), clock_frequency) +#define CLOCK_FREQ_clk_gpout2 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout2), clock_frequency) +#define CLOCK_FREQ_clk_gpout3 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_gpout3), clock_frequency) +#define CLOCK_FREQ_clk_ref DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_ref), clock_frequency) +#define CLOCK_FREQ_clk_sys DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_sys), clock_frequency) +#define CLOCK_FREQ_clk_usb DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_usb), clock_frequency) +#define CLOCK_FREQ_clk_adc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_adc), clock_frequency) +#define CLOCK_FREQ_clk_rtc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_rtc), clock_frequency) +#define CLOCK_FREQ_clk_peri DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, clk_peri), clock_frequency) +#define CLOCK_FREQ_xosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, xosc), clock_frequency) +#define CLOCK_FREQ_rosc DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency) +#define CLOCK_FREQ_rosc_ph DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_frequency) +#define CLOCK_FREQ_gpin0 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), clock_frequency) +#define CLOCK_FREQ_gpin1 DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), clock_frequency) +#define CLOCK_FREQ_pll_sys PLL_FREQ(pll_sys) +#define CLOCK_FREQ_pll_usb PLL_FREQ(pll_usb) + +#define CLOCK_AUX_SOURCE(clk) _CONCAT(_CONCAT(AUXSTEM_, clk), _CONCAT(AUXSRC_, SRC_CLOCK(clk))) + +#define AUXSRC_xosc XOSC_CLKSRC +#define AUXSRC_rosc ROSC_CLKSRC +#define AUXSRC_rosc_ph ROSC_CLKSRC_PH +#define AUXSRC_pll_sys CLKSRC_PLL_SYS +#define AUXSRC_pll_usb CLKSRC_PLL_USB +#define AUXSRC_clk_ref CLK_REF +#define AUXSRC_clk_sys CLK_SYS +#define AUXSRC_clk_usb CLK_USB +#define AUXSRC_clk_adc CLK_ADC +#define AUXSRC_clk_rtc CLK_RTC +#define AUXSRC_clk_gpin0 CLKSRC_GPIN0 +#define AUXSRC_clk_gpin1 CLKSRC_GPIN1 + +#define AUXSTEM_clk_gpout0 CLOCKS_CLK_GPOUT0_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout1 CLOCKS_CLK_GPOUT1_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout2 CLOCKS_CLK_GPOUT2_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_gpout3 CLOCKS_CLK_GPOUT3_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_ref CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_sys CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_usb CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_adc CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_rtc CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ +#define AUXSTEM_clk_peri CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ + +#define TUPLE_ENTRY(n, p, i) \ + { \ + _CONCAT(RPI_PICO_CLKID_, DT_INST_STRING_UPPER_TOKEN_BY_IDX(0, clock_names, i)), \ + COND_CODE_1( \ + DT_PROP_HAS_IDX(DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \ + clocks, 0), \ + (_CONCAT(RPI_PICO_CLKID_, \ + DT_STRING_UPPER_TOKEN_BY_IDX( \ + DT_CLOCKS_CTLR_BY_IDX(DT_NODELABEL(clocks), i), \ + clock_names, 0))), \ + (-1)) \ + } + +enum rpi_pico_clkid { + rpi_pico_clkid_none = -1, + rpi_pico_clkid_clk_gpout0 = RPI_PICO_CLKID_CLK_GPOUT0, + rpi_pico_clkid_clk_gpout1 = RPI_PICO_CLKID_CLK_GPOUT1, + rpi_pico_clkid_clk_gpout2 = RPI_PICO_CLKID_CLK_GPOUT2, + rpi_pico_clkid_clk_gpout3 = RPI_PICO_CLKID_CLK_GPOUT3, + rpi_pico_clkid_clk_ref = RPI_PICO_CLKID_CLK_REF, + rpi_pico_clkid_clk_sys = RPI_PICO_CLKID_CLK_SYS, + rpi_pico_clkid_clk_peri = RPI_PICO_CLKID_CLK_PERI, + rpi_pico_clkid_clk_usb = RPI_PICO_CLKID_CLK_USB, + rpi_pico_clkid_clk_adc = RPI_PICO_CLKID_CLK_ADC, + rpi_pico_clkid_clk_rtc = RPI_PICO_CLKID_CLK_RTC, + rpi_pico_clkid_pll_sys = RPI_PICO_CLKID_PLL_SYS, + rpi_pico_clkid_pll_usb = RPI_PICO_CLKID_PLL_USB, + rpi_pico_clkid_xosc = RPI_PICO_CLKID_XOSC, + rpi_pico_clkid_rosc = RPI_PICO_CLKID_ROSC, + rpi_pico_clkid_rosc_ph = RPI_PICO_CLKID_ROSC_PH, + rpi_pico_clkid_gpin0 = RPI_PICO_CLKID_GPIN0, + rpi_pico_clkid_gpin1 = RPI_PICO_CLKID_GPIN1, + END_OF_RPI_PICO_CLKID, +}; + +struct rpi_pico_clkid_tuple { + enum rpi_pico_clkid clk; + enum rpi_pico_clkid parent; +}; + +struct rpi_pico_clk_config { + uint32_t source; + uint32_t aux_source; + uint32_t rate; + uint32_t source_rate; +}; + +struct rpi_pico_pll_config { + uint32_t ref_div; + uint32_t fb_div; + uint32_t post_div1; + uint32_t post_div2; +}; + +struct rpi_pico_rosc_config { + uint32_t phase; + uint32_t range; + uint32_t div; + uint32_t code; +}; + +struct rpi_pico_gpin_config { + uint32_t frequency; +}; + +struct clock_control_rpi_pico_config { + clocks_hw_t *const clocks_regs; + xosc_hw_t *const xosc_regs; + pll_hw_t *const pll_sys_regs; + pll_hw_t *const pll_usb_regs; + rosc_hw_t *const rosc_regs; + const struct pinctrl_dev_config *pcfg; + struct rpi_pico_pll_config plls_data[RPI_PICO_PLL_COUNT]; + struct rpi_pico_clk_config clocks_data[RPI_PICO_CLOCK_COUNT]; + struct rpi_pico_rosc_config rosc_data; + struct rpi_pico_gpin_config gpin_data[RPI_PICO_GPIN_COUNT]; +}; + +struct clock_control_rpi_pico_data { + uint32_t rosc_freq; + uint32_t rosc_ph_freq; +}; + +uint64_t rpi_pico_frequency_count(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + fc_hw_t *fc0 = &config->clocks_regs->fc0; + uint32_t fc0_id; + + switch (clkid) { + case rpi_pico_clkid_clk_ref: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_REF; + break; + case rpi_pico_clkid_clk_sys: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_SYS; + break; + case rpi_pico_clkid_clk_peri: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_PERI; + break; + case rpi_pico_clkid_clk_usb: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_USB; + break; + case rpi_pico_clkid_clk_adc: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_ADC; + break; + case rpi_pico_clkid_clk_rtc: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLK_RTC; + break; + case rpi_pico_clkid_pll_sys: + fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY; + break; + case rpi_pico_clkid_pll_usb: + fc0_id = CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY; + break; + case rpi_pico_clkid_xosc: + fc0_id = CLOCKS_FC0_SRC_VALUE_XOSC_CLKSRC; + break; + case rpi_pico_clkid_rosc: + fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC; + break; + case rpi_pico_clkid_rosc_ph: + fc0_id = CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC_PH; + break; + case rpi_pico_clkid_gpin0: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0; + break; + case rpi_pico_clkid_gpin1: + fc0_id = CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0; + break; + default: + return -1; + } + + (void)frequency_count_khz(fc0_id); + + return ((fc0->result >> CLOCKS_FC0_RESULT_KHZ_LSB) * 1000) + + ((fc0->result & CLOCKS_FC0_RESULT_FRAC_BITS) * 1000 / CLOCKS_FC0_RESULT_FRAC_BITS); +} + +static int rpi_pico_rosc_write(const struct device *dev, io_rw_32 *addr, uint32_t value) +{ + hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + *addr = value; + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + return 0; +} + +/** + * Get source clock id of this clock + * + * @param dev pointer to clock device + * @param id id of this clock + * @return parent clock id + */ +static enum rpi_pico_clkid rpi_pico_get_clock_src(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid srcid = rpi_pico_clkid_none; + + if (id == rpi_pico_clkid_clk_gpout0 || id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || id == rpi_pico_clkid_clk_gpout3) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_clk_sys, + rpi_pico_clkid_clk_usb, + rpi_pico_clkid_clk_adc, + rpi_pico_clkid_clk_rtc, + rpi_pico_clkid_clk_ref, + }; + + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_clk_ref) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS); + + if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH) { + srcid = rpi_pico_clkid_rosc_ph; + } else if (src == CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC) { + srcid = rpi_pico_clkid_xosc; + } else { + srcid = table[aux]; + } + } else if (id == rpi_pico_clkid_clk_sys) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + uint32_t src = ((clock_hw->ctrl >> CTRL_SRC_LSB) & CTRL_SRC_BITS); + + if (src == CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF) { + srcid = rpi_pico_clkid_clk_ref; + } else { + srcid = table[aux]; + } + } else if (id == rpi_pico_clkid_clk_peri) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_clk_sys, + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_clk_usb || id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc) { + const static enum rpi_pico_clkid table[] = { + rpi_pico_clkid_pll_usb, + rpi_pico_clkid_pll_sys, + rpi_pico_clkid_rosc_ph, + rpi_pico_clkid_xosc, + rpi_pico_clkid_gpin0, + rpi_pico_clkid_gpin1, + }; + + clock_hw_t *clock_hw = &clocks_hw->clk[id]; + uint32_t aux = ((clock_hw->ctrl & CTRL_AUXSRC_BITS) >> CTRL_AUXSRC_LSB); + + srcid = table[aux]; + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + srcid = rpi_pico_clkid_xosc; + } + + return srcid; +} + +/** + * Query clock is enabled or not + * + * @param dev pointer to clock device + * @param id id of clock + * @return true if the clock enabled, otherwith false + */ +static bool rpi_pico_is_clock_enabled(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + + if (id == rpi_pico_clkid_clk_sys || id == rpi_pico_clkid_clk_ref) { + return true; + } else if (id == rpi_pico_clkid_clk_usb || + id == rpi_pico_clkid_clk_peri || + id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc || + id == rpi_pico_clkid_clk_gpout0 || + id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || + id == rpi_pico_clkid_clk_gpout3) { + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + + if (clock_hw->ctrl & CTRL_ENABLE_BITS) { + return true; + } + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs + : config->pll_usb_regs; + + if (!(pll->pwr & (PLL_PWR_VCOPD_BITS | PLL_PWR_POSTDIVPD_BITS | PLL_PWR_PD_BITS))) { + return true; + } + } else if (id == rpi_pico_clkid_xosc) { + if (config->xosc_regs->status & XOSC_STATUS_ENABLED_BITS) { + return true; + } + } else if (id == rpi_pico_clkid_rosc || id == rpi_pico_clkid_rosc_ph) { + return true; + } + + return false; +} + +/** + * Calculate clock frequency with traversing clock tree. + * + * @param dev pointer to clock device + * @param id id of clock + * @return frequency value or 0 if disabled + */ +static float rpi_pico_calc_clock_freq(const struct device *dev, enum rpi_pico_clkid id) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + struct clock_control_rpi_pico_data *data = dev->data; + float freq = 0.f; + + if (!rpi_pico_is_clock_enabled(dev, id)) { + return freq; + } + + if (id == rpi_pico_clkid_clk_sys || + id == rpi_pico_clkid_clk_usb || + id == rpi_pico_clkid_clk_adc || + id == rpi_pico_clkid_clk_rtc || + id == rpi_pico_clkid_clk_ref || + id == rpi_pico_clkid_clk_gpout0 || + id == rpi_pico_clkid_clk_gpout1 || + id == rpi_pico_clkid_clk_gpout2 || + id == rpi_pico_clkid_clk_gpout3) { + clock_hw_t *clock_hw = &config->clocks_regs->clk[id]; + + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) / + (((clock_hw->div & DIV_INT_BITS) >> DIV_INT_LSB) + + ((clock_hw->div & DIV_FRAC_BITS) / (float)DIV_FRAC_BITS)); + } else if (id == rpi_pico_clkid_clk_peri) { + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)); + } else if (id == rpi_pico_clkid_pll_sys || id == rpi_pico_clkid_pll_usb) { + pll_hw_t *pll = (id == rpi_pico_clkid_pll_sys) ? config->pll_sys_regs + : config->pll_usb_regs; + freq = rpi_pico_calc_clock_freq(dev, rpi_pico_get_clock_src(dev, id)) * + (pll->fbdiv_int) / (pll->cs & PLL_CS_REFDIV_BITS) / + ((pll->prim & PLL_PRIM_POSTDIV1_BITS) >> PLL_PRIM_POSTDIV1_LSB) / + ((pll->prim & PLL_PRIM_POSTDIV2_BITS) >> PLL_PRIM_POSTDIV2_LSB); + } else if (id == rpi_pico_clkid_xosc) { + freq = CLOCK_FREQ_xosc; + } else if (id == rpi_pico_clkid_rosc) { + freq = data->rosc_freq; + } else if (id == rpi_pico_clkid_rosc_ph) { + freq = data->rosc_ph_freq; + } + + return freq; +} + +static int rpi_pico_is_valid_clock_index(enum rpi_pico_clkid index) +{ + if (index >= END_OF_RPI_PICO_CLKID) { + return -EINVAL; + } + + return 0; +} + +static int clock_control_rpi_pico_on(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + clocks_hw_t *clocks_regs = config->clocks_regs; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + hw_set_bits(&clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS); + + return 0; +} + +static int clock_control_rpi_pico_off(const struct device *dev, clock_control_subsys_t sys) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + clocks_hw_t *clocks_regs = config->clocks_regs; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + hw_clear_bits(&clocks_regs->clk[clkid].ctrl, CTRL_ENABLE_BITS); + + return 0; +} + +static enum clock_control_status clock_control_rpi_pico_get_status(const struct device *dev, + clock_control_subsys_t sys) +{ + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + if (rpi_pico_is_clock_enabled(dev, clkid)) { + return CLOCK_CONTROL_STATUS_ON; + } + + return CLOCK_CONTROL_STATUS_OFF; +} + +static int clock_control_rpi_pico_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + struct clock_control_rpi_pico_data *data = dev->data; + enum rpi_pico_clkid clkid = (enum rpi_pico_clkid)sys; + + if (rpi_pico_is_valid_clock_index(clkid) < 0) { + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) { + if (clkid == rpi_pico_clkid_rosc) { + data->rosc_freq = rpi_pico_frequency_count(dev, sys); + } else if (clkid == rpi_pico_clkid_rosc_ph) { + data->rosc_ph_freq = rpi_pico_frequency_count(dev, sys); + } + } + + *rate = (int)rpi_pico_calc_clock_freq(dev, clkid); + + return 0; +} + +void rpi_pico_clkid_tuple_swap(struct rpi_pico_clkid_tuple *lhs, struct rpi_pico_clkid_tuple *rhs) +{ + struct rpi_pico_clkid_tuple tmp = *lhs; + *lhs = *rhs; + *rhs = tmp; +} + +void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *tuples, size_t len) +{ + uint32_t sorted_idx = 0; + uint32_t checked_idx = 0; + uint32_t target = -1; + + while (sorted_idx < len) { + for (uint32_t i = sorted_idx; i < len; i++) { + if (tuples[i].parent == target) { + rpi_pico_clkid_tuple_swap(&tuples[sorted_idx], &tuples[i]); + sorted_idx++; + } + } + target = tuples[checked_idx++].clk; + } +} + +static int clock_control_rpi_pico_init(const struct device *dev) +{ + const struct clock_control_rpi_pico_config *config = dev->config; + struct clock_control_rpi_pico_data *data = dev->data; + clocks_hw_t *clocks_regs = config->clocks_regs; + rosc_hw_t *rosc_regs = config->rosc_regs; + pll_hw_t *plls[] = {config->pll_sys_regs, config->pll_usb_regs}; + struct rpi_pico_clkid_tuple tuples[] = { + DT_INST_FOREACH_PROP_ELEM_SEP(0, clock_names, TUPLE_ENTRY, (,))}; + uint32_t rosc_div; + int ret; + + /* Reset all function before clock configuring */ + reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS | + RESETS_RESET_PLL_USB_BITS | RESETS_RESET_USBCTRL_BITS | + RESETS_RESET_PLL_USB_BITS | RESETS_RESET_SYSCFG_BITS | + RESETS_RESET_PLL_SYS_BITS)); + + unreset_block_wait(RESETS_RESET_BITS & + ~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS | + RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS | + RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS | + RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS)); + + /* Start tick in watchdog */ + watchdog_hw->tick = ((CLOCK_FREQ_xosc/1000000) | WATCHDOG_TICK_ENABLE_BITS); + + clocks_regs->resus.ctrl = 0; + + /* Configure xosc */ + xosc_init(); + + /* Before we touch PLLs, switch sys and ref cleanly away from their aux sources. */ + clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].ctrl &= ~CTRL_SRC_BITS; + while (clocks_hw->clk[RPI_PICO_CLKID_CLK_SYS].selected != 0x1) { + ; + } + clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].ctrl &= ~CTRL_SRC_BITS; + while (clocks_hw->clk[RPI_PICO_CLKID_CLK_REF].selected != 0x1) { + ; + } + + /* Configure pll */ + for (uint32_t i = 0; i < RPI_PICO_PLL_COUNT; i++) { + pll_init(plls[i], config->plls_data[i].ref_div, + CLOCK_FREQ_xosc * config->plls_data[i].fb_div, + config->plls_data[i].post_div1, config->plls_data[i].post_div2); + } + + /* Configure clocks */ + rpi_pico_clkid_tuple_reorder_by_dependencies(tuples, ARRAY_SIZE(tuples)); + for (uint32_t i = 0; i < ARRAY_SIZE(tuples); i++) { + if (tuples[i].clk < 0 || tuples[i].clk >= RPI_PICO_CLOCK_COUNT) { + continue; + } + + if (!(clock_configure(tuples[i].clk, config->clocks_data[tuples[i].clk].source, + config->clocks_data[tuples[i].clk].aux_source, + config->clocks_data[tuples[i].clk].source_rate, + config->clocks_data[tuples[i].clk].rate))) { + return -EINVAL; + } + } + + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout0].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout1].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout2].ctrl, CTRL_ENABLE_BITS); + hw_clear_bits(&clocks_regs->clk[rpi_pico_clkid_clk_gpout3].ctrl, CTRL_ENABLE_BITS); + + /* Configure rosc */ + ret = rpi_pico_rosc_write(dev, &rosc_regs->phase, + (ROSC_PHASE_PASSWD_VALUE_PASS << ROSC_PHASE_PASSWD_LSB) | + config->rosc_data.phase); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->ctrl, + (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | + config->rosc_data.range); + if (ret < 0) { + return ret; + } + + if (config->rosc_data.div <= 0) { + rosc_div = ROSC_DIV_VALUE_PASS + 1; + } else if (config->rosc_data.div > 31) { + rosc_div = ROSC_DIV_VALUE_PASS; + } else { + rosc_div = ROSC_DIV_VALUE_PASS + config->rosc_data.div; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->div, rosc_div); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->freqa, + (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | + (config->rosc_data.code & UINT16_MAX)); + if (ret < 0) { + return ret; + } + + ret = rpi_pico_rosc_write(dev, &rosc_regs->freqb, + (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | + (config->rosc_data.code >> 16)); + if (ret < 0) { + return ret; + } + + unreset_block_wait(RESETS_RESET_BITS); + + if (IS_ENABLED(CONFIG_RPI_PICO_ROSC_USE_MEASURED_FREQ)) { + data->rosc_freq = + rpi_pico_frequency_count(dev, (clock_control_subsys_t)rpi_pico_clkid_rosc); + data->rosc_ph_freq = rpi_pico_frequency_count( + dev, (clock_control_subsys_t)rpi_pico_clkid_rosc_ph); + } + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + return 0; +} + +static const struct clock_control_driver_api clock_control_rpi_pico_api = { + .on = clock_control_rpi_pico_on, + .off = clock_control_rpi_pico_off, + .get_rate = clock_control_rpi_pico_get_rate, + .get_status = clock_control_rpi_pico_get_status, +}; + +BUILD_ASSERT((VCO_FREQ(pll_sys) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_sys) <= PLL_VCO_FREQ_MAX) && + (VCO_FREQ(pll_sys) >= (CLOCK_FREQ_xosc / REF_DIV(pll_sys) * 16)), + "pll_sys: vco_freq is out of range"); +BUILD_ASSERT((FB_DIV(pll_sys) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_sys) <= PLL_FB_DIV_MAX), + "pll_sys: fb-div is out of range"); +BUILD_ASSERT((POST_DIV1(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_sys) <= PLL_POST_DIV_MAX), + "pll_sys: post-div1 is out of range"); +BUILD_ASSERT((POST_DIV2(pll_sys) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_sys) <= PLL_POST_DIV_MAX), + "pll_sys: post-div2 is out of range"); + +BUILD_ASSERT((VCO_FREQ(pll_usb) >= PLL_VCO_FREQ_MIN) && (VCO_FREQ(pll_usb) <= PLL_VCO_FREQ_MAX) && + (VCO_FREQ(pll_usb) >= (CLOCK_FREQ_xosc / REF_DIV(pll_usb) * 16)), + "pll_usb: vco_freq is out of range"); +BUILD_ASSERT((FB_DIV(pll_usb) >= PLL_FB_DIV_MIN) && (FB_DIV(pll_usb) <= PLL_FB_DIV_MAX), + "pll_usb: fb-div is out of range"); +BUILD_ASSERT((POST_DIV1(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV1(pll_usb) <= PLL_POST_DIV_MAX), + "pll_usb: post-div is out of range"); +BUILD_ASSERT((POST_DIV2(pll_usb) >= PLL_POST_DIV_MIN) && (POST_DIV2(pll_usb) <= PLL_POST_DIV_MAX), + "pll_usb: post-div is out of range"); + +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_ref) >= CLOCK_FREQ_clk_ref, + "clk_ref: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_sys) >= CLOCK_FREQ_clk_sys, + "clk_sys: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_usb) >= CLOCK_FREQ_clk_usb, + "clk_usb: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_adc) >= CLOCK_FREQ_clk_adc, + "clk_adc: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_rtc) >= CLOCK_FREQ_clk_rtc, + "clk_rtc: clock divider is out of range"); +BUILD_ASSERT(SRC_CLOCK_FREQ(clk_peri) >= CLOCK_FREQ_clk_peri, + "clk_peri: clock divider is out of range"); + +BUILD_ASSERT(CLOCK_FREQ(rosc_ph) == CLOCK_FREQ(rosc), "rosc_ph: frequency must be equal to rosc"); + +PINCTRL_DT_INST_DEFINE(0); + +static const struct clock_control_rpi_pico_config clock_control_rpi_pico_config = { + .clocks_regs = (clocks_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, clocks), + .xosc_regs = (xosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, xosc), + .pll_sys_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_sys), + .pll_usb_regs = (pll_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, pll_usb), + .rosc_regs = (rosc_hw_t *)DT_INST_REG_ADDR_BY_NAME(0, rosc), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .clocks_data = { + [RPI_PICO_CLKID_CLK_GPOUT0] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout0), + .source_rate = SRC_CLOCK_FREQ(clk_gpout0), + .rate = CLOCK_FREQ(clk_gpout0), + }, + [RPI_PICO_CLKID_CLK_GPOUT1] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout1), + .source_rate = SRC_CLOCK_FREQ(clk_gpout1), + .rate = CLOCK_FREQ(clk_gpout1), + }, + [RPI_PICO_CLKID_CLK_GPOUT2] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout2), + .source_rate = SRC_CLOCK_FREQ(clk_gpout2), + .rate = CLOCK_FREQ(clk_gpout2), + }, + [RPI_PICO_CLKID_CLK_GPOUT3] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_gpout3), + .source_rate = SRC_CLOCK_FREQ(clk_gpout3), + .rate = CLOCK_FREQ(clk_gpout3), + }, + [RPI_PICO_CLKID_CLK_REF] = { +#if CLK_SRC_IS(clk_ref, rosc_ph) + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH, + .aux_source = 0, +#elif CLK_SRC_IS(clk_ref, xosc) + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, + .aux_source = 0, +#else + .source = CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX, +#endif + .source_rate = SRC_CLOCK_FREQ(clk_ref), + .rate = CLOCK_FREQ(clk_ref), + }, + [RPI_PICO_CLKID_CLK_SYS] = { +#if CLK_SRC_IS(clk_sys, clk_ref) + .source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF, + .aux_source = 0, +#else + .source = CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX, + .aux_source = CLOCK_AUX_SOURCE(clk_sys), +#endif + .source_rate = SRC_CLOCK_FREQ(clk_sys), + .rate = CLOCK_FREQ(clk_sys), + }, + [RPI_PICO_CLKID_CLK_PERI] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_peri), + .source_rate = SRC_CLOCK_FREQ(clk_peri), + .rate = CLOCK_FREQ(clk_peri), + }, + [RPI_PICO_CLKID_CLK_USB] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_usb), + .source_rate = SRC_CLOCK_FREQ(clk_usb), + .rate = CLOCK_FREQ(clk_usb), + }, + [RPI_PICO_CLKID_CLK_ADC] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_adc), + .source_rate = SRC_CLOCK_FREQ(clk_adc), + .rate = CLOCK_FREQ(clk_adc), + }, + [RPI_PICO_CLKID_CLK_RTC] = { + .source = 0, + .aux_source = CLOCK_AUX_SOURCE(clk_rtc), + .source_rate = SRC_CLOCK_FREQ(clk_rtc), + .rate = CLOCK_FREQ(clk_rtc), + }, + }, + .plls_data = { + [RPI_PICO_PLL_SYS] = { + .ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), clock_div), + .fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), fb_div), + .post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div1), + .post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_sys), post_div2), + }, + [RPI_PICO_PLL_USB] = { + .ref_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), clock_div), + .fb_div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), fb_div), + .post_div1 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div1), + .post_div2 = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, pll_usb), post_div2), + }, + }, + .rosc_data = { + .phase = (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), + phase_flip), + (ROSC_PHASE_FLIP_BITS), (0x0)) | + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), + phase), + ((DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), phase) & + ROSC_PHASE_SHIFT_BITS) | ROSC_PHASE_ENABLE_BITS), (0x0))), + .div = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), clock_div), + .range = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, rosc), range), + .code = (STAGE_DS(0) | STAGE_DS(1) | STAGE_DS(2) | STAGE_DS(3) | + STAGE_DS(4) | STAGE_DS(5) | STAGE_DS(6) | STAGE_DS(7)), + }, + .gpin_data = { + [RPI_PICO_GPIN_0] = { + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), + clock_frequency), + (.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin0), + clock_frequency),), + (.frequency = 0,)) + }, + [RPI_PICO_GPIN_1] = { + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), + clock_frequency), + (.frequency = DT_PROP(DT_INST_CLOCKS_CTLR_BY_NAME(0, gpin1), + clock_frequency),), + (.frequency = 0,)) + }, + }, +}; + +static struct clock_control_rpi_pico_data clock_control_rpi_pico_data = { + .rosc_freq = CLOCK_FREQ(rosc), + .rosc_ph_freq = CLOCK_FREQ(rosc_ph), +}; + +DEVICE_DT_INST_DEFINE(0, &clock_control_rpi_pico_init, NULL, &clock_control_rpi_pico_data, + &clock_control_rpi_pico_config, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &clock_control_rpi_pico_api); diff --git a/drivers/clock_control/clock_control_smartbond.c b/drivers/clock_control/clock_control_smartbond.c index c5ce8a77f22..60c98f8668a 100644 --- a/drivers/clock_control/clock_control_smartbond.c +++ b/drivers/clock_control/clock_control_smartbond.c @@ -73,8 +73,8 @@ static void smartbond_start_rc32k(void) { if ((CRG_TOP->CLK_RC32K_REG & CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk) == 0) { CRG_TOP->CLK_RC32K_REG |= CRG_TOP_CLK_RC32K_REG_RC32K_ENABLE_Msk; - lpc_clock_state.rc32k_started = true; } + lpc_clock_state.rc32k_started = true; if (!lpc_clock_state.rc32k_ready && (CALIBRATION_INTERVAL > 0)) { if (!k_work_is_pending(&calibration_work.work)) { k_work_schedule(&calibration_work, diff --git a/drivers/clock_control/clock_stm32_ll_common.c b/drivers/clock_control/clock_stm32_ll_common.c index ba5ba2e4673..d3adbe62535 100644 --- a/drivers/clock_control/clock_stm32_ll_common.c +++ b/drivers/clock_control/clock_stm32_ll_common.c @@ -567,6 +567,11 @@ static void set_up_fixed_clock_sources(void) while (LL_RCC_HSE_IsReady() != 1) { /* Wait for HSE ready */ } + /* Check if we need to enable HSE clock security system or not */ +#if STM32_HSE_CSS + z_arm_nmi_set_handler(HAL_RCC_NMI_IRQHandler); + LL_RCC_HSE_EnableCSS(); +#endif /* STM32_HSE_CSS */ } if (IS_ENABLED(STM32_HSI_ENABLED)) { @@ -817,6 +822,16 @@ int stm32_clock_control_init(const struct device *dev) return 0; } +#if defined(STM32_HSE_CSS) +void __weak stm32_hse_css_callback(void) {} + +/* Called by the HAL in response to an HSE CSS interrupt */ +void HAL_RCC_CSSCallback(void) +{ + stm32_hse_css_callback(); +} +#endif + /** * @brief RCC device, note that priority is intentionally set to 1 so * that the device init runs just after SOC init diff --git a/drivers/clock_control/clock_stm32_ll_h5.c b/drivers/clock_control/clock_stm32_ll_h5.c index a5a6a055f44..f6f0bbb0033 100644 --- a/drivers/clock_control/clock_stm32_ll_h5.c +++ b/drivers/clock_control/clock_stm32_ll_h5.c @@ -348,7 +348,11 @@ static int get_vco_input_range(uint32_t m_div, uint32_t *range, size_t pll_id) vco_freq = get_pllsrc_frequency(pll_id) / m_div; - if (MHZ(4) <= vco_freq && vco_freq <= MHZ(8)) { + if (MHZ(1) <= vco_freq && vco_freq <= MHZ(2)) { + *range = LL_RCC_PLLINPUTRANGE_1_2; + } else if (MHZ(2) < vco_freq && vco_freq <= MHZ(4)) { + *range = LL_RCC_PLLINPUTRANGE_2_4; + } else if (MHZ(4) < vco_freq && vco_freq <= MHZ(8)) { *range = LL_RCC_PLLINPUTRANGE_4_8; } else if (MHZ(8) < vco_freq && vco_freq <= MHZ(16)) { *range = LL_RCC_PLLINPUTRANGE_8_16; diff --git a/drivers/clock_control/clock_stm32_ll_h7.c b/drivers/clock_control/clock_stm32_ll_h7.c index dc9127d277d..9d76004c92f 100644 --- a/drivers/clock_control/clock_stm32_ll_h7.c +++ b/drivers/clock_control/clock_stm32_ll_h7.c @@ -586,6 +586,11 @@ static void set_up_fixed_clock_sources(void) LL_RCC_HSE_Enable(); while (LL_RCC_HSE_IsReady() != 1) { } + /* Check if we need to enable HSE clock security system or not */ +#if STM32_HSE_CSS + z_arm_nmi_set_handler(HAL_RCC_NMI_IRQHandler); + LL_RCC_HSE_EnableCSS(); +#endif /* STM32_HSE_CSS */ } if (IS_ENABLED(STM32_HSI_ENABLED)) { @@ -819,14 +824,13 @@ static int set_up_plls(void) return 0; } -#if defined(CONFIG_CPU_CORTEX_M7) int stm32_clock_control_init(const struct device *dev) { + int r = 0; + +#if defined(CONFIG_CPU_CORTEX_M7) uint32_t old_hclk_freq = 0; uint32_t new_hclk_freq = 0; - int r; - - ARG_UNUSED(dev); /* HW semaphore Clock enable */ #if defined(CONFIG_SOC_STM32H7A3XX) || defined(CONFIG_SOC_STM32H7A3XXQ) || \ @@ -912,23 +916,25 @@ int stm32_clock_control_init(const struct device *dev) optimize_regulator_voltage_scale(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); +#endif /* CONFIG_CPU_CORTEX_M7 */ + + ARG_UNUSED(dev); /* Update CMSIS variable */ SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; return r; } -#else -int stm32_clock_control_init(const struct device *dev) -{ - ARG_UNUSED(dev); - /* Update CMSIS variable */ - SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; +#if defined(STM32_HSE_CSS) +void __weak stm32_hse_css_callback(void) {} - return 0; +/* Called by the HAL in response to an HSE CSS interrupt */ +void HAL_RCC_CSSCallback(void) +{ + stm32_hse_css_callback(); } -#endif /* CONFIG_CPU_CORTEX_M7 */ +#endif /** * @brief RCC device, note that priority is intentionally set to 1 so diff --git a/drivers/clock_control/clock_stm32_ll_wba.c b/drivers/clock_control/clock_stm32_ll_wba.c index 8b9da70017a..5cc3b8651c7 100644 --- a/drivers/clock_control/clock_stm32_ll_wba.c +++ b/drivers/clock_control/clock_stm32_ll_wba.c @@ -260,10 +260,36 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev, return 0; } +static enum clock_control_status stm32_clock_control_get_status(const struct device *dev, + clock_control_subsys_t sub_system) +{ + struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system; + + ARG_UNUSED(dev); + + if (IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX) == true) { + /* Gated clocks */ + if ((sys_read32(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus) & pclken->enr) + == pclken->enr) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } else { + /* Domain clock sources */ + if (enabled_clock(pclken->bus) == 0) { + return CLOCK_CONTROL_STATUS_ON; + } else { + return CLOCK_CONTROL_STATUS_OFF; + } + } +} + static struct clock_control_driver_api stm32_clock_control_api = { .on = stm32_clock_control_on, .off = stm32_clock_control_off, .get_rate = stm32_clock_control_get_subsys_rate, + .get_status = stm32_clock_control_get_status, .configure = stm32_clock_control_configure, }; @@ -458,8 +484,6 @@ static void set_up_fixed_clock_sources(void) /* Wait till LSESYS is ready */ while (!LL_RCC_LSE_IsPropagationReady()) { } - - LL_PWR_DisableBkUpAccess(); } } @@ -551,6 +575,9 @@ int stm32_clock_control_init(const struct device *dev) LL_SetFlashLatency(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); } + /* Set voltage regulator to comply with targeted system frequency */ + set_regu_voltage(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); + SystemCoreClock = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; /* Set bus prescalers prescaler */ diff --git a/drivers/clock_control/clock_stm32f2_f4_f7.c b/drivers/clock_control/clock_stm32f2_f4_f7.c index 6131fcd4c06..a10fede6887 100644 --- a/drivers/clock_control/clock_stm32f2_f4_f7.c +++ b/drivers/clock_control/clock_stm32f2_f4_f7.c @@ -56,6 +56,9 @@ uint32_t get_pllsrc_frequency(void) __unused void config_pll_sysclock(void) { +#if defined(STM32_SRC_PLL_R) && STM32_PLL_R_ENABLED && defined(RCC_PLLCFGR_PLLR) + MODIFY_REG(RCC->PLLCFGR, RCC_PLLCFGR_PLLR, pllr(STM32_PLL_R_DIVISOR)); +#endif LL_RCC_PLL_ConfigDomain_SYS(get_pll_source(), pllm(STM32_PLL_M_DIVISOR), STM32_PLL_N_MULTIPLIER, diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 606ce1fe6d6..28dcf9fbc16 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -222,6 +222,7 @@ endif # UART_MCUMGR config XTENSA_SIM_CONSOLE bool "Use Xtensa simulator console" depends on SIMULATOR_XTENSA + depends on !WINSTREAM_CONSOLE select CONSOLE_HAS_DRIVER default y help @@ -340,6 +341,7 @@ config EFI_CONSOLE config WINSTREAM_CONSOLE bool "Use Winstream console" depends on WINSTREAM + select CONSOLE_HAS_DRIVER help Use winstream as a console. diff --git a/drivers/console/uart_console.c b/drivers/console/uart_console.c index 21df7fd3455..5e5e10963f0 100644 --- a/drivers/console/uart_console.c +++ b/drivers/console/uart_console.c @@ -87,13 +87,11 @@ static int console_out(int c) #endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */ - if (pm_device_runtime_is_enabled(uart_console_dev)) { - if (pm_device_runtime_get(uart_console_dev) < 0) { - /* Enabling the UART instance has failed but this - * function MUST return the byte output. - */ - return c; - } + if (pm_device_runtime_get(uart_console_dev) < 0) { + /* Enabling the UART instance has failed but this + * function MUST return the byte output. + */ + return c; } if ('\n' == c) { @@ -101,10 +99,11 @@ static int console_out(int c) } uart_poll_out(uart_console_dev, c); - if (pm_device_runtime_is_enabled(uart_console_dev)) { - /* As errors cannot be returned, ignore the return value */ - (void)pm_device_runtime_put(uart_console_dev); - } + /* Use async put to avoid useless device suspension/resumption + * when tranmiting chain of chars. + * As errors cannot be returned, ignore the return value + */ + (void)pm_device_runtime_put_async(uart_console_dev, K_MSEC(1)); return c; } @@ -545,14 +544,12 @@ static void uart_console_isr(const struct device *unused, void *user_data) break; } - last_char = byte; - continue; - } - /* Ignore characters if there's no more buffer space */ - if (cur + end < sizeof(cmd->line) - 1) { + } else if (cur + end < sizeof(cmd->line) - 1) { insert_char(&cmd->line[cur++], byte, end); } + + last_char = byte; } } diff --git a/drivers/console/uart_mcumgr.c b/drivers/console/uart_mcumgr.c index 30b0c7be718..2b068e6810c 100644 --- a/drivers/console/uart_mcumgr.c +++ b/drivers/console/uart_mcumgr.c @@ -228,16 +228,9 @@ static void uart_mcumgr_setup(const struct device *uart) #else static void uart_mcumgr_setup(const struct device *uart) { - uint8_t c; - uart_irq_rx_disable(uart); uart_irq_tx_disable(uart); - /* Drain the fifo */ - while (uart_fifo_read(uart, &c, 1)) { - continue; - } - uart_irq_callback_set(uart, uart_mcumgr_isr); uart_irq_rx_enable(uart); diff --git a/drivers/console/winstream_console.c b/drivers/console/winstream_console.c index abc5344593a..8d056a8f6f8 100644 --- a/drivers/console/winstream_console.c +++ b/drivers/console/winstream_console.c @@ -8,10 +8,10 @@ #include #include #include +#include #include #include -#include struct k_spinlock trace_lock; @@ -46,6 +46,29 @@ int arch_printk_char_out(int c) return 0; } +#if defined(CONFIG_STDOUT_CONSOLE) +extern void __stdout_hook_install(int (*hook)(int)); +#else +#define __stdout_hook_install(x) \ + do {/* nothing */ \ + } while ((0)) +#endif + +#if defined(CONFIG_PRINTK) +extern void __printk_hook_install(int (*fn)(int)); +#else +#define __printk_hook_install(x) \ + do {/* nothing */ \ + } while ((0)) +#endif + +static void winstream_console_hook_install(void) +{ + __stdout_hook_install(arch_printk_char_out); + __printk_hook_install(arch_printk_char_out); +} + + static int winstream_console_init(void) { const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); @@ -55,9 +78,10 @@ static int winstream_console_init(void) } const struct mem_win_config *config = dev->config; void *buf = - arch_xtensa_uncached_ptr((__sparse_force void __sparse_cache *)config->mem_base); + sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); winstream = sys_winstream_init(buf, config->size); + winstream_console_hook_install(); return 0; } diff --git a/drivers/console/xtensa_sim_console.c b/drivers/console/xtensa_sim_console.c index 16e48eeee48..316162ddc0c 100644 --- a/drivers/console/xtensa_sim_console.c +++ b/drivers/console/xtensa_sim_console.c @@ -13,7 +13,7 @@ * @param c Character to output * @return The character passed as input. */ -static int console_out(int c) +int arch_printk_char_out(int c) { char buf[16]; @@ -54,8 +54,8 @@ extern void __printk_hook_install(int (*fn)(int)); */ static void xt_sim_console_hook_install(void) { - __stdout_hook_install(console_out); - __printk_hook_install(console_out); + __stdout_hook_install(arch_printk_char_out); + __printk_hook_install(arch_printk_char_out); } /** diff --git a/drivers/counter/Kconfig.gd32 b/drivers/counter/Kconfig.gd32 index eb5d5897af2..fcb8913434e 100644 --- a/drivers/counter/Kconfig.gd32 +++ b/drivers/counter/Kconfig.gd32 @@ -6,7 +6,7 @@ config COUNTER_TIMER_GD32 bool "GD32 timer counter driver" default y - depends on DT_HAS_GD_GD32_TIMER_ENABLED && SOC_FAMILY_GD32_ARM + depends on DT_HAS_GD_GD32_TIMER_ENABLED && !SOC_SERIES_GD32VF103 select USE_GD32_TIMER help Enable counter timer driver for GD32 series devices. diff --git a/drivers/counter/Kconfig.mcux_lpc_rtc b/drivers/counter/Kconfig.mcux_lpc_rtc index bd012db822c..49f063116d5 100644 --- a/drivers/counter/Kconfig.mcux_lpc_rtc +++ b/drivers/counter/Kconfig.mcux_lpc_rtc @@ -1,9 +1,24 @@ -# Copyright (c) 2021, NXP +# Copyright (c) 2021-23, NXP # SPDX-License-Identifier: Apache-2.0 config COUNTER_MCUX_LPC_RTC bool "MCUX LPC RTC driver" default y + depends on DT_HAS_NXP_LPC_RTC_ENABLED || \ + DT_HAS_NXP_LPC_RTC_HIGHRES_ENABLED + help + Enable the LPC rtc driver. + +config COUNTER_MCUX_LPC_RTC_1HZ + bool "MCUX LPC RTC 1Hz counter driver" + default y depends on DT_HAS_NXP_LPC_RTC_ENABLED help - Enable support for LPC rtc driver. + Enable support for LPC 1Hz counter. + +config COUNTER_MCUX_LPC_RTC_HIGHRES + bool "MCUX LPC RTC High Resolution counter driver" + default y + depends on DT_HAS_NXP_LPC_RTC_HIGHRES_ENABLED + help + Enable support for LPC rtc high resolution counter. diff --git a/drivers/counter/counter_ambiq_timer.c b/drivers/counter/counter_ambiq_timer.c index 94549d65685..67df6c5647f 100644 --- a/drivers/counter/counter_ambiq_timer.c +++ b/drivers/counter/counter_ambiq_timer.c @@ -43,7 +43,6 @@ static int counter_ambiq_init(const struct device *dev) tc.ui32PatternLimit = 0; am_hal_timer_config(0, &tc); - am_hal_timer_interrupt_enable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); k_spin_unlock(&lock, key); @@ -98,6 +97,10 @@ static int counter_ambiq_set_alarm(const struct device *dev, uint8_t chan_id, k_spinlock_key_t key = k_spin_lock(&lock); + /* Enable interrupt, due to counter_ambiq_cancel_alarm() disables it*/ + am_hal_timer_interrupt_clear(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + am_hal_timer_interrupt_enable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) { am_hal_timer_compare1_set(0, now + alarm_cfg->ticks); } else { @@ -119,6 +122,8 @@ static int counter_ambiq_cancel_alarm(const struct device *dev, uint8_t chan_id) k_spinlock_key_t key = k_spin_lock(&lock); am_hal_timer_interrupt_disable(AM_HAL_TIMER_MASK(0, AM_HAL_TIMER_COMPARE1)); + /* Reset the compare register */ + am_hal_timer_compare1_set(0, 0); k_spin_unlock(&lock, key); return 0; diff --git a/drivers/counter/counter_ll_stm32_rtc.c b/drivers/counter/counter_ll_stm32_rtc.c index 76114cab386..317bd367391 100644 --- a/drivers/counter/counter_ll_stm32_rtc.c +++ b/drivers/counter/counter_ll_stm32_rtc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -648,6 +649,30 @@ static const struct rtc_stm32_config rtc_config = { .pclken = rtc_clk, }; +#ifdef CONFIG_PM_DEVICE +static int rtc_stm32_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct rtc_stm32_config *cfg = dev->config; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Enable RTC bus clock */ + if (clock_control_on(clk, (clock_control_subsys_t) &cfg->pclken[0]) != 0) { + LOG_ERR("clock op failed\n"); + return -EIO; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif /* CONFIG_PM_DEVICE */ static const struct counter_driver_api rtc_stm32_driver_api = { .start = rtc_stm32_start, @@ -663,7 +688,9 @@ static const struct counter_driver_api rtc_stm32_driver_api = { .get_top_value = rtc_stm32_get_top_value, }; -DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, NULL, +PM_DEVICE_DT_INST_DEFINE(0, rtc_stm32_pm_action); + +DEVICE_DT_INST_DEFINE(0, &rtc_stm32_init, PM_DEVICE_DT_INST_GET(0), &rtc_data, &rtc_config, PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, &rtc_stm32_driver_api); diff --git a/drivers/counter/counter_ll_stm32_timer.c b/drivers/counter/counter_ll_stm32_timer.c index 3c7d561db0f..2c012d31c40 100644 --- a/drivers/counter/counter_ll_stm32_timer.c +++ b/drivers/counter/counter_ll_stm32_timer.c @@ -42,8 +42,7 @@ static void(*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to compare get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const get_timer_compare[TIMER_MAX_CH])(const TIM_TypeDef *) = { @@ -70,8 +69,7 @@ static void(*const disable_it[TIMER_MAX_CH])(TIM_TypeDef *) = { #ifdef CONFIG_ASSERT /** Channel to interrupt enable check function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t(*const check_it_enabled[TIMER_MAX_CH])(const TIM_TypeDef *) = { diff --git a/drivers/counter/counter_mcux_lpc_rtc.c b/drivers/counter/counter_mcux_lpc_rtc.c index 2bb8d920fea..433fef0683c 100644 --- a/drivers/counter/counter_mcux_lpc_rtc.c +++ b/drivers/counter/counter_mcux_lpc_rtc.c @@ -1,11 +1,9 @@ /* - * Copyright 2021-22, NXP + * Copyright 2021-23, NXP * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT nxp_lpc_rtc - #include #include #include @@ -16,17 +14,72 @@ LOG_MODULE_REGISTER(mcux_rtc, CONFIG_COUNTER_LOG_LEVEL); struct mcux_lpc_rtc_data { counter_alarm_callback_t alarm_callback; + counter_top_callback_t top_callback; void *alarm_user_data; + void *top_user_data; + uint32_t value; }; struct mcux_lpc_rtc_config { struct counter_config_info info; RTC_Type *base; + const struct device *rtc_dev; void (*irq_config_func)(const struct device *dev); /* Device defined as wake-up source */ bool wakeup_source; }; +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES +static int mcux_lpc_rtc_highres_start(const struct device *dev); +#endif + +static void mcux_lpc_rtc_isr(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + counter_alarm_callback_t cb; + uint32_t current = RTC_GetSecondsTimerCount(config->base); + + LOG_DBG("Current time is %d ticks", current); + + if ((RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) && + (data->alarm_callback)) { + cb = data->alarm_callback; + data->alarm_callback = NULL; + cb(dev, 0, current, data->alarm_user_data); + } + + if (data->top_callback) { + data->top_callback(dev, data->top_user_data); + } + + /* + * Clear any conditions to ack the IRQ + * + * callback may have already reset the alarm flag if a new + * alarm value was programmed to the TAR + */ + if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) { + RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag); + } + + /* Check if the Wake counter interrupt was set */ + if (RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK) { + RTC_ClearStatusFlags(config->base, kRTC_WakeupFlag); +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES + if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) { + mcux_lpc_rtc_highres_start(dev); + } +#endif + } +} + +#if CONFIG_COUNTER_MCUX_LPC_RTC_1HZ + +#define DT_DRV_COMPAT nxp_lpc_rtc + static int mcux_lpc_rtc_start(const struct device *dev) { const struct counter_config_info *info = dev->config; @@ -145,41 +198,6 @@ static uint32_t mcux_lpc_rtc_get_top_value(const struct device *dev) return info->max_top_value; } -static void mcux_lpc_rtc_isr(const struct device *dev) -{ - const struct counter_config_info *info = dev->config; - const struct mcux_lpc_rtc_config *config = - CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); - struct mcux_lpc_rtc_data *data = dev->data; - counter_alarm_callback_t cb; - uint32_t current = mcux_lpc_rtc_read(dev); - uint32_t enable = (config->base->CTRL & RTC_CTRL_RTC_EN_MASK); - - - LOG_DBG("Current time is %d ticks", current); - - if ((RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) && - (data->alarm_callback)) { - cb = data->alarm_callback; - data->alarm_callback = NULL; - cb(dev, 0, current, data->alarm_user_data); - } - - /* - * Clear any conditions to ack the IRQ - * - * callback may have already reset the alarm flag if a new - * alarm value was programmed to the TAR - */ - RTC_EnableTimer(config->base, false); - if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) { - RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag); - } - if (enable) { - RTC_EnableTimer(config->base, true); - } -} - static int mcux_lpc_rtc_init(const struct device *dev) { const struct counter_config_info *info = dev->config; @@ -212,11 +230,12 @@ static const struct counter_driver_api mcux_rtc_driver_api = { .get_top_value = mcux_lpc_rtc_get_top_value, }; -#define COUNTER_LPC_RTC_DEVICE(id) \ - static void mcux_lpc_rtc_irq_config_##id(const struct device *dev); \ - static const struct mcux_lpc_rtc_config mcux_lpc_rtc_config_##id = { \ - .base = (RTC_Type *)DT_INST_REG_ADDR(id), \ - .irq_config_func = mcux_lpc_rtc_irq_config_##id, \ +#define COUNTER_LPC_RTC_DEVICE(id) \ + static void mcux_lpc_rtc_irq_config_##id(const struct device *dev); \ + static const struct mcux_lpc_rtc_config mcux_lpc_rtc_config_##id = { \ + .base = (RTC_Type *)DT_INST_REG_ADDR(id), \ + .irq_config_func = mcux_lpc_rtc_irq_config_##id, \ + .rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CHILD(id, rtc_highres)), \ .info = { \ .max_top_value = UINT32_MAX, \ .freq = 1, \ @@ -227,7 +246,7 @@ static const struct counter_driver_api mcux_rtc_driver_api = { }; \ static struct mcux_lpc_rtc_data mcux_lpc_rtc_data_##id; \ DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_init, NULL, \ - &mcux_lpc_rtc_data_##id, &mcux_lpc_rtc_config_##id.info, \ + &mcux_lpc_rtc_data_##id, &mcux_lpc_rtc_config_##id.info, \ POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ &mcux_rtc_driver_api); \ static void mcux_lpc_rtc_irq_config_##id(const struct device *dev) \ @@ -242,3 +261,206 @@ static const struct counter_driver_api mcux_rtc_driver_api = { } DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_DEVICE) +#endif + +#if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES + +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_lpc_rtc_highres + +static int mcux_lpc_rtc_highres_start(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + + if (config->rtc_dev) { + /* We have another RTC driver enabled, check if RTC is enabled */ + if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) { + /* RTC is not enabled and we do not turn it on as it will effect + * the RTC counter value thereby affecting the RTC counter drivers + */ + LOG_ERR("RTC Wake counter cannot be started as RTC is not enabled."); + return -EINVAL; + } + } else { + if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) { + RTC_EnableTimer(config->base, true); + } + } + + if (data->value == 0) { + /* Start from the max value */ + RTC_SetWakeupCount(config->base, counter_get_top_value(dev)); + } else { + RTC_SetWakeupCount(config->base, data->value); + } + + return 0; +} + +static int mcux_lpc_rtc_highres_stop(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + config->base->CTRL &= ~RTC_CTRL_RTC1KHZ_EN_MASK; + + if (config->rtc_dev == NULL) { + /* Disable RTC as no other driver is using it */ + RTC_EnableTimer(config->base, false); + } + + return 0; +} + +static uint32_t mcux_lpc_rtc_highres_read(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + uint32_t ticks = RTC_GetWakeupCount(config->base); + + return ticks; +} + +static int mcux_lpc_rtc_highres_set_alarm(const struct device *dev, uint8_t chan_id, + const struct counter_alarm_cfg *alarm_cfg) +{ + return -ENOTSUP; +} + +static int mcux_lpc_rtc_highres_cancel_alarm(const struct device *dev, uint8_t chan_id) +{ + return -ENOTSUP; +} + + +static int mcux_lpc_rtc_highres_get_value(const struct device *dev, uint32_t *ticks) +{ + *ticks = mcux_lpc_rtc_highres_read(dev); + return 0; +} + +static int mcux_lpc_rtc_highres_set_top_value(const struct device *dev, + const struct counter_top_cfg *cfg) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + struct mcux_lpc_rtc_data *data = dev->data; + + if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) { + return -ENOTSUP; + } + + data->value = cfg->ticks; + data->top_callback = cfg->callback; + data->top_user_data = cfg->user_data; + + if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) { + return mcux_lpc_rtc_highres_start(dev); + } + + return 0; +} + +static uint32_t mcux_lpc_rtc_highres_get_pending_int(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + return RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK; +} + +static uint32_t mcux_lpc_rtc_highres_get_top_value(const struct device *dev) +{ + struct mcux_lpc_rtc_data *data = dev->data; + const struct counter_config_info *info = dev->config; + + if (data->value == 0) { + return info->max_top_value; + } else { + return data->value; + } +} + +static int mcux_lpc_rtc_highres_init(const struct device *dev) +{ + const struct counter_config_info *info = dev->config; + const struct mcux_lpc_rtc_config *config = + CONTAINER_OF(info, struct mcux_lpc_rtc_config, info); + + /* Initialize the RTC if this is only driver using it */ + if (config->rtc_dev == NULL) { + RTC_Init(config->base); + + /* Issue a software reset to set the registers to init state */ + RTC_Reset(config->base); + + config->irq_config_func(dev); + } + + if (config->wakeup_source) { + /* Enable the bit to wakeup from Deep Power Down mode */ + RTC_EnableWakeUpTimerInterruptFromDPD(config->base, true); + } + + return 0; +} + +static const struct counter_driver_api mcux_rtc_highres_driver_api = { + .start = mcux_lpc_rtc_highres_start, + .stop = mcux_lpc_rtc_highres_stop, + .get_value = mcux_lpc_rtc_highres_get_value, + .set_alarm = mcux_lpc_rtc_highres_set_alarm, + .cancel_alarm = mcux_lpc_rtc_highres_cancel_alarm, + .set_top_value = mcux_lpc_rtc_highres_set_top_value, + .get_pending_int = mcux_lpc_rtc_highres_get_pending_int, + .get_top_value = mcux_lpc_rtc_highres_get_top_value, +}; + +#define COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(n) \ + do { \ + IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(n)), \ + DT_IRQ(DT_INST_PARENT(n), priority), \ + mcux_lpc_rtc_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_IRQN(DT_INST_PARENT(n))); \ + if (DT_INST_PROP(n, wakeup_source)) { \ + EnableDeepSleepIRQ(DT_IRQN(DT_INST_PARENT(n))); \ + } \ + } while (false) + +#define COUNTER_LPC_RTC_HIGHRES_DEVICE(id) \ + static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev); \ + static const struct mcux_lpc_rtc_config mcux_lpc_rtc_highres_config_##id = { \ + .base = (RTC_Type *)DT_REG_ADDR(DT_INST_PARENT(id)), \ + .rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PARENT(id)), \ + .irq_config_func = mcux_lpc_rtc_highres_irq_config_##id, \ + .info = { \ + .max_top_value = UINT16_MAX, \ + .freq = 1000, \ + .channels = 0, \ + }, \ + .wakeup_source = DT_INST_PROP(id, wakeup_source) \ + }; \ + static struct mcux_lpc_rtc_data mcux_lpc_rtc_highres_data_##id; \ + DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_highres_init, NULL, \ + &mcux_lpc_rtc_highres_data_##id, \ + &mcux_lpc_rtc_highres_config_##id.info, \ + POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY, \ + &mcux_rtc_highres_driver_api); \ + static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev) \ + { \ + COND_CODE_1(IS_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(nxp_lpc_rtc)), \ + (), (COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(id));) \ + } + +DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_HIGHRES_DEVICE) + +#endif diff --git a/drivers/counter/counter_mcux_rtc.c b/drivers/counter/counter_mcux_rtc.c index bd0c0e9512e..39f2b7064f5 100644 --- a/drivers/counter/counter_mcux_rtc.c +++ b/drivers/counter/counter_mcux_rtc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 blik GmbH - * Copyright (c) 2018, NXP + * Copyright (c) 2018,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -236,9 +236,11 @@ static int mcux_rtc_init(const struct device *dev) RTC_GetDefaultConfig(&rtc_config); RTC_Init(config->base, &rtc_config); +#if !(defined(FSL_FEATURE_RTC_HAS_NO_CR_OSCE) && FSL_FEATURE_RTC_HAS_NO_CR_OSCE) /* Enable 32kHz oscillator and wait for 1ms to settle */ - config->base->CR |= 0x100; + RTC_SetClockSource(config->base); k_busy_wait(USEC_PER_MSEC); +#endif /* !FSL_FEATURE_RTC_HAS_NO_CR_OSCE */ config->irq_config_func(dev); diff --git a/drivers/counter/counter_nrfx_rtc.c b/drivers/counter/counter_nrfx_rtc.c index af35564a158..398921f2bd6 100644 --- a/drivers/counter/counter_nrfx_rtc.c +++ b/drivers/counter/counter_nrfx_rtc.c @@ -9,6 +9,7 @@ #include #include #endif +#include #include #ifdef DPPI_PRESENT #include @@ -77,7 +78,7 @@ static int start(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - nrf_rtc_task_trigger(config->rtc, NRF_RTC_TASK_START); + nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_START); return 0; } @@ -86,7 +87,7 @@ static int stop(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - nrf_rtc_task_trigger(config->rtc, NRF_RTC_TASK_STOP); + nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_STOP); return 0; } @@ -95,7 +96,7 @@ static uint32_t read(const struct device *dev) { const struct counter_nrfx_config *config = dev->config; - return nrf_rtc_counter_get(config->rtc); + return nrfy_rtc_counter_get(config->rtc); } static int get_value(const struct device *dev, uint32_t *ticks) @@ -157,7 +158,7 @@ static void set_cc_int_pending(const struct device *dev, uint8_t chan) struct counter_nrfx_data *data = dev->data; atomic_or(&data->ipend_adj, BIT(chan)); - NRFX_IRQ_PENDING_SET(NRFX_IRQ_NUMBER_GET(config->rtc)); + NRFY_IRQ_PENDING_SET(NRFX_IRQ_NUMBER_GET(config->rtc)); } /** @brief Handle case when CC value equals COUNTER+1. @@ -180,12 +181,12 @@ static void handle_next_tick_case(const struct device *dev, uint8_t chan, struct counter_nrfx_data *data = dev->data; val = ticks_add(dev, val, 1, data->top); - nrf_rtc_cc_set(config->rtc, chan, val); + nrfy_rtc_cc_set(config->rtc, chan, val); atomic_or(&data->ipend_adj, CC_ADJ_MASK(chan)); - if (nrf_rtc_counter_get(config->rtc) != now) { + if (nrfy_rtc_counter_get(config->rtc) != now) { set_cc_int_pending(dev, chan); } else { - nrf_rtc_int_enable(config->rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(config->rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); } } @@ -240,8 +241,8 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, "Expected that CC interrupt is disabled."); evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); - top = data->top; - now = nrf_rtc_counter_get(rtc); + top = data->top; + now = nrfy_rtc_counter_get(rtc); /* First take care of a risk of an event coming from CC being set to * next tick. Reconfigure CC to future (now tick is the furthest @@ -249,17 +250,17 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, * (half of 32k tick) and clean potential event. After that time there * is no risk of unwanted event. */ - prev_val = nrf_rtc_cc_get(rtc, chan); - nrf_rtc_event_clear(rtc, evt); - nrf_rtc_cc_set(rtc, chan, now); - nrf_rtc_event_enable(rtc, int_mask); + prev_val = nrfy_rtc_cc_get(rtc, chan); + nrfy_rtc_event_clear(rtc, evt); + nrfy_rtc_cc_set(rtc, chan, now); + nrfy_rtc_event_enable(rtc, int_mask); if (ticks_sub(dev, prev_val, now, top) == 1) { NRFX_DELAY_US(15); - nrf_rtc_event_clear(rtc, evt); + nrfy_rtc_event_clear(rtc, evt); } - now = nrf_rtc_counter_get(rtc); + now = nrfy_rtc_counter_get(rtc); if (absolute) { val = skip_zero_on_custom_top(val, top); @@ -289,8 +290,8 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, */ handle_next_tick_case(dev, chan, now, val); } else { - nrf_rtc_cc_set(rtc, chan, val); - now = nrf_rtc_counter_get(rtc); + nrfy_rtc_cc_set(rtc, chan, val); + now = nrfy_rtc_counter_get(rtc); /* decrement value to detect also case when val == read(dev). * Otherwise, condition would need to include comparing diff @@ -318,7 +319,7 @@ static int set_cc(const struct device *dev, uint8_t chan, uint32_t val, */ handle_next_tick_case(dev, chan, now, val); } else { - nrf_rtc_int_enable(rtc, int_mask); + nrfy_rtc_int_enable(rtc, int_mask); } } @@ -353,9 +354,8 @@ static void disable(const struct device *dev, uint8_t chan) NRF_RTC_Type *rtc = config->rtc; nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); - nrf_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); - nrf_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); - nrf_rtc_event_clear(rtc, evt); + nrfy_rtc_event_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_clear(rtc, evt); config->ch_data[chan].callback = NULL; } @@ -379,7 +379,7 @@ static int ppi_setup(const struct device *dev, uint8_t chan) return 0; } - nrf_rtc_event_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); #ifdef DPPI_PRESENT result = nrfx_dppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { @@ -387,15 +387,15 @@ static int ppi_setup(const struct device *dev, uint8_t chan) return -ENODEV; } - nrf_rtc_subscribe_set(rtc, NRF_RTC_TASK_CLEAR, data->ppi_ch); - nrf_rtc_publish_set(rtc, evt, data->ppi_ch); + nrfy_rtc_subscribe_set(rtc, NRF_RTC_TASK_CLEAR, data->ppi_ch); + nrfy_rtc_publish_set(rtc, evt, data->ppi_ch); (void)nrfx_dppi_channel_enable(data->ppi_ch); #else /* DPPI_PRESENT */ uint32_t evt_addr; uint32_t task_addr; - evt_addr = nrf_rtc_event_address_get(rtc, evt); - task_addr = nrf_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR); + evt_addr = nrfy_rtc_event_address_get(rtc, evt); + task_addr = nrfy_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR); result = nrfx_ppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { @@ -420,13 +420,13 @@ static void ppi_free(const struct device *dev, uint8_t chan) if (!nrfx_config->use_ppi) { return; } - nrf_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan)); #ifdef DPPI_PRESENT nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); (void)nrfx_dppi_channel_disable(ppi_ch); - nrf_rtc_subscribe_clear(rtc, NRF_RTC_TASK_CLEAR); - nrf_rtc_publish_clear(rtc, evt); + nrfy_rtc_subscribe_clear(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_publish_clear(rtc, evt); (void)nrfx_dppi_channel_free(ppi_ch); #else /* DPPI_PRESENT */ (void)nrfx_ppi_channel_disable(ppi_ch); @@ -457,16 +457,16 @@ static int set_fixed_top_value(const struct device *dev, return -EINVAL; } - nrf_rtc_int_disable(rtc, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_disable(rtc, NRF_RTC_INT_OVERFLOW_MASK); data->top_cb = cfg->callback; data->top_user_data = cfg->user_data; if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } if (cfg->callback) { - nrf_rtc_int_enable(rtc, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_enable(rtc, NRF_RTC_INT_OVERFLOW_MASK); } return 0; @@ -494,7 +494,7 @@ static int set_top_value(const struct device *dev, } } - nrf_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); + nrfy_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); if (IS_PPI_WRAP(dev)) { if ((dev_data->top == NRF_RTC_COUNTER_MAX) && @@ -509,19 +509,19 @@ static int set_top_value(const struct device *dev, dev_data->top_cb = cfg->callback; dev_data->top_user_data = cfg->user_data; dev_data->top = cfg->ticks; - nrf_rtc_cc_set(rtc, top_ch, cfg->ticks); + nrfy_rtc_cc_set(rtc, top_ch, cfg->ticks); if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } else if (read(dev) >= cfg->ticks) { err = -ETIME; if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } } if (cfg->callback || sw_wrap_required(dev)) { - nrf_rtc_int_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); + nrfy_rtc_int_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch)); } return err; @@ -546,9 +546,9 @@ static int init_rtc(const struct device *dev, uint32_t prescaler) z_nrf_clock_control_lf_on(CLOCK_CONTROL_NRF_LF_START_NOWAIT); #endif - nrf_rtc_prescaler_set(rtc, prescaler); + nrfy_rtc_prescaler_set(rtc, prescaler); - NRFX_IRQ_ENABLE(NRFX_IRQ_NUMBER_GET(rtc)); + NRFY_IRQ_ENABLE(NRFX_IRQ_NUMBER_GET(rtc)); data->top = NRF_RTC_COUNTER_MAX; err = set_top_value(dev, &top_cfg); @@ -593,14 +593,14 @@ static void top_irq_handle(const struct device *dev) NRF_RTC_EVENT_OVERFLOW : NRF_RTC_CHANNEL_EVENT_ADDR(counter_get_num_of_channels(dev)); - if (nrf_rtc_event_check(rtc, top_evt)) { - nrf_rtc_event_clear(rtc, top_evt); + uint32_t event_mask = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(top_evt)); + if (event_mask & NRFY_EVENT_TO_INT_BITMASK(top_evt)) { /* Perform manual clear if custom top value is used and PPI * clearing is not used. */ if (!IS_FIXED_TOP(dev) && !IS_PPI_WRAP(dev)) { - nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR); } if (cb) { @@ -617,24 +617,24 @@ static void alarm_irq_handle(const struct device *dev, uint32_t chan) NRF_RTC_Type *rtc = config->rtc; nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan); uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(chan); - bool hw_irq_pending = nrf_rtc_event_check(rtc, evt) && - nrf_rtc_int_enable_check(rtc, int_mask); + + bool hw_irq_pending = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(evt)) & + nrfy_rtc_int_enable_check(rtc, NRFY_EVENT_TO_INT_BITMASK(evt)); bool sw_irq_pending = data->ipend_adj & BIT(chan); if (hw_irq_pending || sw_irq_pending) { struct counter_nrfx_ch_data *chdata; counter_alarm_callback_t cb; - nrf_rtc_event_clear(rtc, evt); atomic_and(&data->ipend_adj, ~BIT(chan)); - nrf_rtc_int_disable(rtc, int_mask); + nrfy_rtc_int_disable(rtc, int_mask); chdata = &config->ch_data[chan]; cb = chdata->callback; chdata->callback = NULL; if (cb) { - uint32_t cc = nrf_rtc_cc_get(rtc, chan); + uint32_t cc = nrfy_rtc_cc_get(rtc, chan); if (data->ipend_adj & CC_ADJ_MASK(chan)) { cc = ticks_sub(dev, cc, 1, data->top); diff --git a/drivers/counter/counter_nrfx_timer.c b/drivers/counter/counter_nrfx_timer.c index caf2c5852e4..47537b16d7d 100644 --- a/drivers/counter/counter_nrfx_timer.c +++ b/drivers/counter/counter_nrfx_timer.c @@ -364,8 +364,10 @@ static void alarm_irq_handle(const struct device *dev, uint32_t id) } } -static void irq_handler(const struct device *dev) +static void irq_handler(const void *arg) { + const struct device *dev = arg; + top_irq_handle(dev); for (uint32_t i = 0; i < counter_get_num_of_channels(dev); i++) { @@ -437,7 +439,7 @@ static const struct counter_driver_api counter_nrfx_driver_api = { .channels = CC_TO_ID(DT_INST_PROP(idx, cc_num)), \ }, \ .ch_data = counter##idx##_ch_data, \ - .timer = (NRF_TIMER_Type *)DT_INST_REG_ADDR(idx), \ + .timer = (NRF_TIMER_Type *)_CONCAT(NRF_TIMER, idx), \ LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \ }; \ DEVICE_DT_INST_DEFINE(idx, \ diff --git a/drivers/counter/counter_rpi_pico_timer.c b/drivers/counter/counter_rpi_pico_timer.c index 3e1a1dcbb0b..c2140d58777 100644 --- a/drivers/counter/counter_rpi_pico_timer.c +++ b/drivers/counter/counter_rpi_pico_timer.c @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -32,6 +34,9 @@ struct counter_rpi_pico_timer_config { struct counter_config_info info; timer_hw_t *timer; void (*irq_config)(); + const struct device *clk_dev; + clock_control_subsys_t clk_id; + const struct reset_dt_spec reset; }; static int counter_rpi_pico_timer_start(const struct device *dev) @@ -106,6 +111,11 @@ static int counter_rpi_pico_timer_set_alarm(const struct device *dev, uint8_t id static int counter_rpi_pico_timer_cancel_alarm(const struct device *dev, uint8_t id) { + struct counter_rpi_pico_timer_data *data = dev->data; + struct counter_rpi_pico_timer_ch_data *chdata = &data->ch_data[id]; + + chdata->callback = NULL; + chdata->user_data = NULL; hardware_alarm_cancel(id); return 0; @@ -161,6 +171,17 @@ static void counter_rpi_pico_irq_handle(uint32_t ch, void *arg) static int counter_rpi_pico_timer_init(const struct device *dev) { const struct counter_rpi_pico_timer_config *config = dev->config; + int ret; + + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } config->irq_config(); @@ -209,6 +230,9 @@ static const struct counter_driver_api counter_rpi_pico_driver_api = { .flags = COUNTER_CONFIG_INFO_COUNT_UP, \ .channels = ARRAY_SIZE(ch_data##inst), \ }, \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(inst, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ }; \ DEVICE_DT_INST_DEFINE(inst, counter_rpi_pico_timer_init, NULL, &counter_##inst##_data, \ &counter_##inst##_config, PRE_KERNEL_1, \ diff --git a/drivers/crypto/crypto_npcx_sha.c b/drivers/crypto/crypto_npcx_sha.c index 26403599360..7354ea5877b 100644 --- a/drivers/crypto/crypto_npcx_sha.c +++ b/drivers/crypto/crypto_npcx_sha.c @@ -13,9 +13,9 @@ #include LOG_MODULE_REGISTER(sha_npcx, CONFIG_CRYPTO_LOG_LEVEL); -#define NPCX_HASH_CAPS_SUPPORT (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS) +#define NPCX_HASH_CAPS_SUPPORT (CAP_SEPARATE_IO_BUFS | CAP_SYNC_OPS) #define NPCX_SHA256_HANDLE_SIZE DT_INST_PROP(0, context_buffer_size) -#define NPCX_SHA_MAX_SESSION 1 +#define NPCX_SHA_MAX_SESSION 1 /* The status code returns from Nuvoton Cryptographic Library ROM APIs */ enum ncl_status { @@ -204,13 +204,27 @@ static int npcx_query_caps(const struct device *dev) return NPCX_HASH_CAPS_SUPPORT; } +static int npcx_hash_init(const struct device *dev) +{ + uint32_t handle_size_required; + + handle_size_required = NPCX_NCL_SHA->get_context_size(); + if (handle_size_required != NPCX_SHA256_HANDLE_SIZE) { + LOG_ERR("Pre-alloc buf size doesn't match required buf size (%d)", + handle_size_required); + return -ENOSR; + } + + return 0; +} + static struct crypto_driver_api npcx_crypto_api = { .hash_begin_session = npcx_hash_session_setup, .hash_free_session = npcx_hash_session_free, .query_hw_caps = npcx_query_caps, }; -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, +DEVICE_DT_INST_DEFINE(0, npcx_hash_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_CRYPTO_INIT_PRIORITY, &npcx_crypto_api); BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "only one 'nuvoton,npcx-sha' compatible node can be supported"); diff --git a/drivers/dac/dac_sam.c b/drivers/dac/dac_sam.c index de4680b3ff6..df8b96f66e9 100644 --- a/drivers/dac/dac_sam.c +++ b/drivers/dac/dac_sam.c @@ -107,6 +107,11 @@ static int dac_sam_write_value(const struct device *dev, uint8_t channel, return -EINVAL; } + if (value >= BIT(12)) { + LOG_ERR("value %d out of range", value); + return -EINVAL; + } + k_sem_take(&dev_data->dac_channels[channel].sem, K_FOREVER); /* Trigger conversion */ diff --git a/drivers/dac/dac_sam0.c b/drivers/dac/dac_sam0.c index 2b96b8bc30d..95f561d4a6a 100644 --- a/drivers/dac/dac_sam0.c +++ b/drivers/dac/dac_sam0.c @@ -11,6 +11,8 @@ #include #include #include +#include +LOG_MODULE_REGISTER(dac_sam0, CONFIG_DAC_LOG_LEVEL); /* * Maps between the DTS reference property names and register values. Note that @@ -37,6 +39,11 @@ static int dac_sam0_write_value(const struct device *dev, uint8_t channel, const struct dac_sam0_cfg *const cfg = dev->config; Dac *regs = cfg->regs; + if (value >= BIT(12)) { + LOG_ERR("value %d out of range", value); + return -EINVAL; + } + regs->DATA.reg = (uint16_t)value; return 0; diff --git a/drivers/dai/CMakeLists.txt b/drivers/dai/CMakeLists.txt index 90b5d8b931c..b6bd04939d5 100644 --- a/drivers/dai/CMakeLists.txt +++ b/drivers/dai/CMakeLists.txt @@ -4,3 +4,4 @@ add_subdirectory_ifdef(CONFIG_DAI_INTEL_SSP intel/ssp) add_subdirectory_ifdef(CONFIG_DAI_INTEL_ALH intel/alh) add_subdirectory_ifdef(CONFIG_DAI_INTEL_DMIC intel/dmic) add_subdirectory_ifdef(CONFIG_DAI_INTEL_HDA intel/hda) +add_subdirectory_ifdef(CONFIG_DAI_NXP_SAI nxp/sai) diff --git a/drivers/dai/Kconfig b/drivers/dai/Kconfig index 770b528da6a..da882a99fa0 100644 --- a/drivers/dai/Kconfig +++ b/drivers/dai/Kconfig @@ -29,5 +29,6 @@ source "drivers/dai/intel/ssp/Kconfig.ssp" source "drivers/dai/intel/alh/Kconfig.alh" source "drivers/dai/intel/dmic/Kconfig.dmic" source "drivers/dai/intel/hda/Kconfig.hda" +source "drivers/dai/nxp/sai/Kconfig.sai" endif # DAI diff --git a/drivers/dai/intel/dmic/dmic_nhlt.c b/drivers/dai/intel/dmic/dmic_nhlt.c index 17a8f385a02..3d803da33b9 100644 --- a/drivers/dai/intel/dmic/dmic_nhlt.c +++ b/drivers/dai/intel/dmic/dmic_nhlt.c @@ -139,12 +139,12 @@ static int dai_nhlt_get_clock_div(const struct dai_intel_dmic *dmic, const int p val = dai_dmic_read(dmic, dmic_base[pdm] + FIR_CHANNEL_REGS_SIZE * dmic->dai_config_params.dai_index + FIR_CONFIG); - LOG_ERR("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); + LOG_INF("pdm = %d, FIR_CONFIG = 0x%08X", pdm, val); p_mfir = FIELD_GET(FIR_CONFIG_FIR_DECIMATION, val) + 1; rate_div = p_clkdiv * p_mcic * p_mfir; - LOG_ERR("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", + LOG_INF("dai_index = %d, rate_div = %d, p_clkdiv = %d, p_mcic = %d, p_mfir = %d", dmic->dai_config_params.dai_index, rate_div, p_clkdiv, p_mcic, p_mfir); if (!rate_div) { diff --git a/drivers/dai/intel/ssp/ssp.c b/drivers/dai/intel/ssp/ssp.c index 809cc9833eb..4b8f6e00742 100644 --- a/drivers/dai/intel/ssp/ssp.c +++ b/drivers/dai/intel/ssp/ssp.c @@ -723,7 +723,7 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(index), I2SLCTL_CPA(index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) | @@ -731,7 +731,7 @@ static void dai_ssp_pm_runtime_en_ssp_power(struct dai_intel_ssp *dp, uint32_t i dai_hdamlssp_base(dp) + I2SLCTL_OFFSET); /* Check if powered on. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), 0, + I2SLCTL_CPA(index), I2SLCTL_CPA(index), DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC @@ -759,7 +759,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_ip_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #elif CONFIG_SOC_INTEL_ACE20_LNL sys_write32(sys_read32(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET) & (~I2SLCTL_SPA(index)), @@ -767,7 +767,7 @@ static void dai_ssp_pm_runtime_dis_ssp_power(struct dai_intel_ssp *dp, uint32_t /* Check if powered off. */ ret = dai_ssp_poll_for_register_delay(dai_hdamlssp_base(dp) + I2SLCTL_OFFSET, - I2SLCTL_CPA(index), I2SLCTL_CPA(index), + I2SLCTL_CPA(index), 0, DAI_INTEL_SSP_MAX_SEND_TIME_PER_SAMPLE); #else #error need to define SOC @@ -837,36 +837,73 @@ static void dai_ssp_empty_tx_fifo(struct dai_intel_ssp *dp) } } -/* empty SSP receive FIFO */ -static void dai_ssp_empty_rx_fifo(struct dai_intel_ssp *dp) +static void ssp_empty_rx_fifo_on_start(struct dai_intel_ssp *dp) { - struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; - uint32_t entries; - uint32_t i; + uint32_t i, sssr; - /* - * To make sure all the RX FIFO entries are read out for the flushing, - * we need to wait a minimal SSP port delay after entries are all read, - * and then re-check to see if there is any subsequent entries written - * to the FIFO. This will help to make sure there is no sample mismatched - * issue for the next run with the SSP RX. - */ - while ((sys_read32(dai_base(dp) + SSSR) & SSSR_RNE) && retry--) { - entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); - LOG_DBG("%s before flushing, entries %d", __func__, entries); - for (i = 0; i < entries + 1; i++) { - /* read to try empty fifo */ + sssr = sys_read32(dai_base(dp) + SSSR); + + if (sssr & SSSR_ROR) { + /* The RX FIFO is in overflow condition, empty it */ + for (i = 0; i < DAI_INTEL_SSP_FIFO_DEPTH; i++) sys_read32(dai_base(dp) + SSDR); + + /* Clear the overflow status */ + dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR); + /* Re-read the SSSR register */ + sssr = sys_read32(dai_base(dp) + SSSR); + } + + while ((sssr & SSSR_RNE) && retry--) { + uint32_t entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + + /* Empty the RX FIFO (the DMA is not running at this point) */ + for (i = 0; i < entries + 1; i++) + sys_read32(dai_base(dp) + SSDR); + + sssr = sys_read32(dai_base(dp) + SSSR); + } +} + +static void ssp_empty_rx_fifo_on_stop(struct dai_intel_ssp *dp) +{ + struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); + uint64_t sample_ticks = ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0; + uint32_t retry = DAI_INTEL_SSP_RX_FLUSH_RETRY_MAX; + uint32_t entries[2]; + uint32_t i, sssr; + + sssr = sys_read32(dai_base(dp) + SSSR); + entries[0] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + + while ((sssr & SSSR_RNE) && retry--) { + /* Wait one sample time */ + k_busy_wait(sample_ticks); + + entries[1] = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); + sssr = sys_read32(dai_base(dp) + SSSR); + + if (entries[0] > entries[1]) { + /* + * The DMA is reading the FIFO, check the status in the + * next loop + */ + entries[0] = entries[1]; + } else if (!(sssr & SSSR_RFS)) { + /* + * The DMA request is not asserted, read the FIFO + * directly, otherwise let the next loop iteration to + * check the status + */ + for (i = 0; i < entries[1] + 1; i++) + sys_read32(dai_base(dp) + SSDR); } - /* wait to get valid fifo status and re-check */ - k_busy_wait(ssp->params.fsync_rate ? 1000000 / ssp->params.fsync_rate : 0); - entries = SSCR3_RFL_VAL(sys_read32(dai_base(dp) + SSCR3)); - LOG_DBG("%s after flushing, entries %d", __func__, entries); + sssr = sys_read32(dai_base(dp) + SSSR); } - /* clear interrupt */ + /* Just in case clear the overflow status */ dai_ssp_update_bits(dp, SSSR, SSSR_ROR, SSSR_ROR); } @@ -1524,12 +1561,6 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co ssp->clk_active |= SSP_CLK_BCLK_ES_REQ; if (enable_sse) { - - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - SSCR1_TSRE | SSCR1_RSRE); - /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -1553,11 +1584,6 @@ static int dai_ssp_set_config_tplg(struct dai_intel_ssp *dp, const struct dai_co LOG_INF("%s hw_free stage: releasing BCLK clocks for SSP%d...", __func__, dp->index); if (ssp->clk_active & SSP_CLK_BCLK_ACTIVE) { - /* clear TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - 0); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); LOG_INF("%s SSE clear for SSP%d", __func__, dp->index); } @@ -1759,15 +1785,25 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co const struct dai_intel_ipc4_ssp_config *regs) { struct dai_intel_ssp_pdata *ssp = dai_get_drvdata(dp); - uint32_t ssc0, sstsa, ssrsa; + uint32_t ssc0, sstsa, ssrsa, sscr1; ssc0 = regs->ssc0; - sstsa = regs->sstsa; - ssrsa = regs->ssrsa; + sstsa = SSTSA_GET(regs->sstsa); + ssrsa = SSRSA_GET(regs->ssrsa); + sscr1 = regs->ssc1 & ~(SSCR1_RSRE | SSCR1_TSRE); + + if (regs->sstsa & SSTSA_TXEN || regs->ssrsa & SSRSA_RXEN || + regs->ssc1 & (SSCR1_RSRE | SSCR1_TSRE)) { + LOG_INF("%s: Ignoring %s%s%s%sfrom blob", __func__, + regs->sstsa & SSTSA_TXEN ? "SSTSA:TXEN " : "", + regs->ssrsa & SSRSA_RXEN ? "SSRSA:RXEN " : "", + regs->ssc1 & SSCR1_TSRE ? "SSCR1:TSRE " : "", + regs->ssc1 & SSCR1_RSRE ? "SSCR1:RSRE " : ""); + } sys_write32(ssc0, dai_base(dp) + SSCR0); sys_write32(regs->ssc2 & ~SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */ - sys_write32(regs->ssc1, dai_base(dp) + SSCR1); + sys_write32(sscr1, dai_base(dp) + SSCR1); sys_write32(regs->ssc2 | SSCR2_SFRMEN, dai_base(dp) + SSCR2); /* hardware specific flow */ sys_write32(regs->ssc2, dai_base(dp) + SSCR2); sys_write32(regs->ssc3, dai_base(dp) + SSCR3); @@ -1779,7 +1815,7 @@ static void dai_ssp_set_reg_config(struct dai_intel_ssp *dp, const struct dai_co sys_write32(ssrsa, dai_base(dp) + SSRSA); LOG_INF("%s sscr0 = 0x%08x, sscr1 = 0x%08x, ssto = 0x%08x, sspsp = 0x%0x", __func__, - ssc0, regs->ssc1, regs->sscto, regs->sspsp); + ssc0, sscr1, regs->sscto, regs->sspsp); LOG_INF("%s sscr2 = 0x%08x, sspsp2 = 0x%08x, sscr3 = 0x%08x", __func__, regs->ssc2, regs->sspsp2, regs->ssc3); LOG_INF("%s ssioc = 0x%08x, ssrsa = 0x%08x, sstsa = 0x%08x", __func__, @@ -1828,8 +1864,6 @@ static int dai_ssp_set_config_blob(struct dai_intel_ssp *dp, const struct dai_co } ssp->clk_active |= SSP_CLK_MCLK_ES_REQ; - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, SSCR1_TSRE | SSCR1_RSRE); /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); @@ -1901,15 +1935,14 @@ static void dai_ssp_early_start(struct dai_intel_ssp *dp, int direction) key = k_spin_lock(&dp->lock); + /* RX fifo must be cleared before start */ + if (direction == DAI_DIR_CAPTURE) + ssp_empty_rx_fifo_on_start(dp); + /* request mclk/bclk */ dai_ssp_pre_start(dp); if (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)) { - /* enable TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, - SSCR1_TSRE | SSCR1_RSRE, - SSCR1_TSRE | SSCR1_RSRE); - /* enable port */ dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, SSCR0_SSE); LOG_INF("%s SSE set for SSP%d", __func__, dp->index); @@ -1930,8 +1963,10 @@ static void dai_ssp_start(struct dai_intel_ssp *dp, int direction) /* enable DMA */ if (direction == DAI_DIR_PLAYBACK) { + dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, SSCR1_TSRE); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, SSTSA_TXEN); } else { + dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, SSCR1_RSRE); dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, SSRSA_RXEN); } @@ -1981,7 +2016,8 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) if (direction == DAI_DIR_CAPTURE && ssp->state[DAI_DIR_CAPTURE] != DAI_STATE_PRE_RUNNING) { dai_ssp_update_bits(dp, SSRSA, SSRSA_RXEN, 0); - dai_ssp_empty_rx_fifo(dp); + dai_ssp_update_bits(dp, SSCR1, SSCR1_RSRE, 0); + ssp_empty_rx_fifo_on_stop(dp); ssp->state[DAI_DIR_CAPTURE] = DAI_STATE_PRE_RUNNING; LOG_INF("%s RX stop", __func__); } @@ -1989,6 +2025,7 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* stop Tx if needed */ if (direction == DAI_DIR_PLAYBACK && ssp->state[DAI_DIR_PLAYBACK] != DAI_STATE_PRE_RUNNING) { + dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE, 0); dai_ssp_empty_tx_fifo(dp); dai_ssp_update_bits(dp, SSTSA, SSTSA_TXEN, 0); ssp->state[DAI_DIR_PLAYBACK] = DAI_STATE_PRE_RUNNING; @@ -1997,16 +2034,11 @@ static void dai_ssp_stop(struct dai_intel_ssp *dp, int direction) /* disable SSP port if no users */ if (ssp->state[DAI_DIR_CAPTURE] == DAI_STATE_PRE_RUNNING && - ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING) { - bool clear_rse_bits = COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, - (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), - (true)); - if (clear_rse_bits) { - /* clear TRSE/RSRE before SSE */ - dai_ssp_update_bits(dp, SSCR1, SSCR1_TSRE | SSCR1_RSRE, 0); - dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); - LOG_INF("%s SSE clear SSP%d", __func__, dp->index); - } + ssp->state[DAI_DIR_PLAYBACK] == DAI_STATE_PRE_RUNNING && + COND_CODE_1(CONFIG_INTEL_ADSP_CAVS, + (!(ssp->clk_active & SSP_CLK_BCLK_ES_REQ)), (true))) { + dai_ssp_update_bits(dp, SSCR0, SSCR0_SSE, 0); + LOG_INF("%s SSE clear for SSP%d", __func__, dp->index); } dai_ssp_post_stop(dp); @@ -2159,8 +2191,6 @@ static int dai_ssp_probe(struct dai_intel_ssp *dp) /* Disable dynamic clock gating before touching any register */ dai_ssp_pm_runtime_dis_ssp_clk_gating(dp, dp->index); - dai_ssp_empty_rx_fifo(dp); - return 0; } diff --git a/drivers/dai/intel/ssp/ssp.h b/drivers/dai/intel/ssp/ssp.h index 1d37b9a3335..0d53c0c6159 100644 --- a/drivers/dai/intel/ssp/ssp.h +++ b/drivers/dai/intel/ssp/ssp.h @@ -29,7 +29,7 @@ #define DAI_INTEL_SSP_DEFAULT_IDX 1 /* the SSP port fifo depth */ -#define DAI_INTEL_SSP_FIFO_DEPTH 16 +#define DAI_INTEL_SSP_FIFO_DEPTH 32 /* the watermark for the SSP fifo depth setting */ #define DAI_INTEL_SSP_FIFO_WATERMARK 8 diff --git a/drivers/dai/nxp/sai/CMakeLists.txt b/drivers/dai/nxp/sai/CMakeLists.txt new file mode 100644 index 00000000000..755261307a6 --- /dev/null +++ b/drivers/dai/nxp/sai/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(sai.c) diff --git a/drivers/dai/nxp/sai/Kconfig.sai b/drivers/dai/nxp/sai/Kconfig.sai new file mode 100644 index 00000000000..04c1ff7a430 --- /dev/null +++ b/drivers/dai/nxp/sai/Kconfig.sai @@ -0,0 +1,41 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DAI_NXP_SAI + bool "NXP Synchronous Audio Interface (SAI) driver" + default y + depends on DT_HAS_NXP_DAI_SAI_ENABLED + help + Select this to enable NXP SAI driver. + +if DAI_NXP_SAI + +config SAI_HAS_MCLK_CONFIG_OPTION + bool "Set if SAI has MCLK configuration options" + default n + help + Select this if the SAI IP allows configuration + of the master clock. Master clock configuration + refers to enabling/disabling the master clock, + setting the signal as input or output or dividing + the master clock output. + +config SAI_FIFO_WORD_SIZE + int "Size (in bytes) of a FIFO word" + default 4 + help + Use this to set the size (in bytes) of a SAI + FIFO word. + +config SAI_IMX93_ERRATA_051421 + bool "Set if your SAI IP version is affected by i.MX93's ERRATA 051421" + default n + help + Select this if your SAI ip version is affected by + i.MX93's ERRATA 051421. The errata states that if + the SAI is FSYNC/BCLK master, one of the directions + is SYNC with the other, and the ASYNC direction has + the BYP bit toggled, the SYNC direction's BCLK won't + be generated properly. + +endif # DAI_NXP_SAI diff --git a/drivers/dai/nxp/sai/sai.c b/drivers/dai/nxp/sai/sai.c new file mode 100644 index 00000000000..9146c2c67ae --- /dev/null +++ b/drivers/dai/nxp/sai/sai.c @@ -0,0 +1,911 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "sai.h" + +/* used for binding the driver */ +#define DT_DRV_COMPAT nxp_dai_sai + +#define SAI_TX_RX_HW_DISABLE_TIMEOUT 50 + +/* TODO list: + * + * 1) No busy waiting should be performed in any of the operations. + * In the case of STOP(), the operation should be split into TRIGGER_STOP + * and TRIGGER_POST_STOP. (SOF) + * + * 2) The SAI ISR should stop the SAI whenever a FIFO error interrupt + * is raised. + * + * 3) Transmitter/receiver may remain enabled after sai_tx_rx_disable(). + * Fix this. + */ + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +/* note: i.MX8 boards don't seem to support the MICS field in the MCR + * register. As such, the MCLK source field of sai_master_clock_t is + * useless. I'm assuming the source is selected through xCR2's MSEL. + * + * TODO: for now, this function will set MCR's MSEL to the same value + * as xCR2's MSEL or, rather, to the same MCLK as the one used for + * generating BCLK. Is there a need to support different MCLKs in + * xCR2 and MCR? + */ +static int sai_mclk_config(const struct device *dev, + sai_bclk_source_t bclk_source, + const struct sai_bespoke_config *bespoke) +{ + const struct sai_config *cfg; + struct sai_data *data; + sai_master_clock_t mclk_config; + uint32_t msel, mclk_rate; + int ret; + + cfg = dev->config; + data = dev->data; + + mclk_config.mclkOutputEnable = cfg->mclk_is_output; + + ret = get_msel(bclk_source, &msel); + if (ret < 0) { + LOG_ERR("invalid MCLK source %d for MSEL", bclk_source); + return ret; + } + + /* get MCLK's rate */ + ret = get_mclk_rate(&cfg->clk_data, bclk_source, &mclk_rate); + if (ret < 0) { + LOG_ERR("failed to query MCLK's rate"); + return ret; + } + + LOG_DBG("source MCLK is %u", mclk_rate); + + LOG_DBG("target MCLK is %u", bespoke->mclk_rate); + + /* source MCLK rate */ + mclk_config.mclkSourceClkHz = mclk_rate; + + /* target MCLK rate */ + mclk_config.mclkHz = bespoke->mclk_rate; + + /* commit configuration */ + SAI_SetMasterClockConfig(UINT_TO_I2S(data->regmap), &mclk_config); + + set_msel(data->regmap, msel); + + return 0; +} +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + +void sai_isr(const void *parameter) +{ + const struct device *dev; + struct sai_data *data; + + dev = parameter; + data = dev->data; + + /* check for TX FIFO error */ + if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_TX, data->regmap, kSAI_FIFOErrorFlag)) { + LOG_ERR("FIFO underrun detected"); + /* TODO: this will crash the program and should be addressed as + * mentioned in TODO list's 2). + */ + z_irq_spurious(NULL); + } + + /* check for RX FIFO error */ + if (SAI_TX_RX_STATUS_IS_SET(DAI_DIR_RX, data->regmap, kSAI_FIFOErrorFlag)) { + LOG_ERR("FIFO overrun detected"); + /* TODO: this will crash the program and should be addressed as + * mentioned in TODO list's 2). + */ + z_irq_spurious(NULL); + } +} + +static int sai_config_get(const struct device *dev, + struct dai_config *cfg, + enum dai_dir dir) +{ + struct sai_data *data = dev->data; + + /* dump content of the DAI configuration */ + memcpy(cfg, &data->cfg, sizeof(*cfg)); + + return 0; +} + +static const struct dai_properties + *sai_get_properties(const struct device *dev, enum dai_dir dir, int stream_id) +{ + const struct sai_config *cfg = dev->config; + + switch (dir) { + case DAI_DIR_RX: + return cfg->rx_props; + case DAI_DIR_TX: + return cfg->tx_props; + default: + LOG_ERR("invalid direction: %d", dir); + return NULL; + } + + CODE_UNREACHABLE; +} + +#ifdef CONFIG_SAI_IMX93_ERRATA_051421 +/* notes: + * 1) TX and RX operate in the same mode: master/slave. As such, + * there's no need to check the mode for both directions. + * + * 2) Only one of the directions can operate in SYNC mode at a + * time. + * + * 3) What this piece of code does is it makes the SYNC direction + * use the ASYNC direction's BCLK that comes from its input pad. + * Logically speaking, this would look like: + * + * +--------+ +--------+ + * | TX | | RX | + * | module | | module | + * +--------+ +--------+ + * | ^ | + * | | | + * TX_BCLK | |____________| RX_BCLK + * | | + * V V + * +---------+ +---------+ + * | TX BCLK | | RX BCLK | + * | pad | | pad | + * +---------+ +---------+ + * | | + * | TX_BCLK | RX_BCLK + * V V + * + * Without BCI enabled, the TX module would use an RX_BCLK + * that's divided instead of the one that's obtained from + * bypassing the MCLK (i.e: TX_BCLK would have the value of + * MCLK / ((RX_DIV + 1) * 2)). If BCI is 1, then TX_BCLK will + * be the same as the RX_BCLK that's obtained from bypassing + * the MCLK on RX's side. + * + * 4) The check for BCLK == MCLK is there to see if the ASYNC + * direction will have the BYP bit toggled. + * + * IMPORTANT1: in the above diagram and information, RX is SYNC + * with TX. The same applies if RX is SYNC with TX. Also, this + * applies to i.MX93. For other SoCs, things may be different + * so use this information with caution. + * + * IMPORTANT2: for this to work, you also need to enable the + * pad's input path. For i.MX93, this can be achieved by setting + * the pad's SION bit. + */ +static void sai_config_set_err_051421(I2S_Type *base, + const struct sai_config *cfg, + const struct sai_bespoke_config *bespoke, + sai_transceiver_t *rx_config, + sai_transceiver_t *tx_config) +{ + if (tx_config->masterSlave == kSAI_Master && + bespoke->mclk_rate == bespoke->bclk_rate) { + if (cfg->tx_sync_mode == kSAI_ModeSync) { + base->TCR2 |= I2S_TCR2_BCI(1); + } + + if (cfg->rx_sync_mode == kSAI_ModeSync) { + base->RCR2 |= I2S_RCR2_BCI(1); + } + } +} +#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */ + +static int sai_config_set(const struct device *dev, + const struct dai_config *cfg, + const void *bespoke_data) +{ + const struct sai_bespoke_config *bespoke; + sai_transceiver_t *rx_config, *tx_config; + struct sai_data *data; + const struct sai_config *sai_cfg; + int ret; + + if (cfg->type != DAI_IMX_SAI) { + LOG_ERR("wrong DAI type: %d", cfg->type); + return -EINVAL; + } + + bespoke = bespoke_data; + data = dev->data; + sai_cfg = dev->config; + rx_config = &data->rx_config; + tx_config = &data->tx_config; + + /* since this function configures the transmitter AND the receiver, that + * means both of them need to be stopped. As such, doing the state + * transition here will also result in a state check. + */ + ret = sai_update_state(DAI_DIR_TX, data, DAI_STATE_READY); + if (ret < 0) { + LOG_ERR("failed to update TX state. Reason: %d", ret); + return ret; + } + + ret = sai_update_state(DAI_DIR_RX, data, DAI_STATE_READY); + if (ret < 0) { + LOG_ERR("failed to update RX state. Reason: %d", ret); + return ret; + } + + /* condition: BCLK = FSYNC * TDM_SLOT_WIDTH * TDM_SLOTS */ + if (bespoke->bclk_rate != + (bespoke->fsync_rate * bespoke->tdm_slot_width * bespoke->tdm_slots)) { + LOG_ERR("bad BCLK value: %d", bespoke->bclk_rate); + return -EINVAL; + } + + /* TODO: this should be removed if we're to support sw channels != hw channels */ + if (count_leading_zeros(~bespoke->tx_slots) != bespoke->tdm_slots || + count_leading_zeros(~bespoke->rx_slots) != bespoke->tdm_slots) { + LOG_ERR("number of TX/RX slots doesn't match number of TDM slots"); + return -EINVAL; + } + + /* get default configurations */ + get_bclk_default_config(&tx_config->bitClock); + get_fsync_default_config(&tx_config->frameSync); + get_serial_default_config(&tx_config->serialData); + get_fifo_default_config(&tx_config->fifo); + + /* note1: this may be obvious but enabling multiple SAI + * channels (or data lines) may lead to FIFO starvation/ + * overflow if data is not written/read from the respective + * TDR/RDR registers. + * + * note2: the SAI data line should be enabled based on + * the direction (TX/RX) we're enabling. Enabling the + * data line for the opposite direction will lead to FIFO + * overrun/underrun when working with a SYNC direction. + * + * note3: the TX/RX data line shall be enabled/disabled + * via the sai_trigger_() suite to avoid scenarios in + * which one configures both direction but only starts + * the SYNC direction which would lead to a FIFO underrun. + */ + tx_config->channelMask = 0x0; + + /* TODO: for now, only MCLK1 is supported */ + tx_config->bitClock.bclkSource = kSAI_BclkSourceMclkOption1; + + /* FSYNC is asserted for tdm_slot_width BCLKs */ + tx_config->frameSync.frameSyncWidth = bespoke->tdm_slot_width; + + /* serial data common configuration */ + tx_config->serialData.dataWord0Length = bespoke->tdm_slot_width; + tx_config->serialData.dataWordNLength = bespoke->tdm_slot_width; + tx_config->serialData.dataFirstBitShifted = bespoke->tdm_slot_width; + tx_config->serialData.dataWordNum = bespoke->tdm_slots; + + /* clock provider configuration */ + switch (cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK) { + case DAI_CBP_CFP: + tx_config->masterSlave = kSAI_Slave; + break; + case DAI_CBC_CFC: + tx_config->masterSlave = kSAI_Master; + break; + case DAI_CBC_CFP: + case DAI_CBP_CFC: + LOG_ERR("unsupported provider configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); + return -ENOTSUP; + default: + LOG_ERR("invalid provider configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_PROVIDER_MASK); + return -EINVAL; + } + + LOG_DBG("SAI is in %d mode", tx_config->masterSlave); + + /* protocol configuration */ + switch (cfg->format & DAI_FORMAT_PROTOCOL_MASK) { + case DAI_PROTO_I2S: + /* BCLK is active LOW */ + tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; + /* FSYNC is active LOW */ + tx_config->frameSync.frameSyncPolarity = kSAI_PolarityActiveLow; + break; + case DAI_PROTO_DSP_A: + /* FSYNC is asserted for a single BCLK */ + tx_config->frameSync.frameSyncWidth = 1; + /* BCLK is active LOW */ + tx_config->bitClock.bclkPolarity = kSAI_PolarityActiveLow; + break; + default: + LOG_ERR("unsupported DAI protocol: %d", + cfg->format & DAI_FORMAT_PROTOCOL_MASK); + return -EINVAL; + } + + LOG_DBG("SAI uses protocol: %d", + cfg->format & DAI_FORMAT_PROTOCOL_MASK); + + /* clock inversion configuration */ + switch (cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK) { + case DAI_INVERSION_IB_IF: + SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); + SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); + break; + case DAI_INVERSION_IB_NF: + SAI_INVERT_POLARITY(tx_config->bitClock.bclkPolarity); + break; + case DAI_INVERSION_NB_IF: + SAI_INVERT_POLARITY(tx_config->frameSync.frameSyncPolarity); + break; + case DAI_INVERSION_NB_NF: + /* nothing to do here */ + break; + default: + LOG_ERR("invalid clock inversion configuration: %d", + cfg->format & DAI_FORMAT_CLOCK_INVERSION_MASK); + return -EINVAL; + } + + LOG_DBG("FSYNC polarity: %d", tx_config->frameSync.frameSyncPolarity); + LOG_DBG("BCLK polarity: %d", tx_config->bitClock.bclkPolarity); + + /* duplicate TX configuration */ + memcpy(rx_config, tx_config, sizeof(sai_transceiver_t)); + + tx_config->serialData.dataMaskedWord = ~bespoke->tx_slots; + rx_config->serialData.dataMaskedWord = ~bespoke->rx_slots; + + tx_config->fifo.fifoWatermark = sai_cfg->tx_fifo_watermark - 1; + rx_config->fifo.fifoWatermark = sai_cfg->rx_fifo_watermark - 1; + + LOG_DBG("RX watermark: %d", sai_cfg->rx_fifo_watermark); + LOG_DBG("TX watermark: %d", sai_cfg->tx_fifo_watermark); + + /* set the synchronization mode based on data passed from the DTS */ + tx_config->syncMode = sai_cfg->tx_sync_mode; + rx_config->syncMode = sai_cfg->rx_sync_mode; + + /* commit configuration */ + SAI_RxSetConfig(UINT_TO_I2S(data->regmap), rx_config); + SAI_TxSetConfig(UINT_TO_I2S(data->regmap), tx_config); + + /* a few notes here: + * 1) TX and RX operate in the same mode: master or slave. + * 2) Setting BCLK's rate needs to be performed explicitly + * since SetConfig() doesn't do it for us. + * 3) Setting BCLK's rate has to be performed after the + * SetConfig() call as that resets the SAI registers. + */ + if (tx_config->masterSlave == kSAI_Master) { + SAI_TxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, + bespoke->fsync_rate, bespoke->tdm_slot_width, + bespoke->tdm_slots); + + SAI_RxSetBitClockRate(UINT_TO_I2S(data->regmap), bespoke->mclk_rate, + bespoke->fsync_rate, bespoke->tdm_slot_width, + bespoke->tdm_slots); + } + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION + ret = sai_mclk_config(dev, tx_config->bitClock.bclkSource, bespoke); + if (ret < 0) { + LOG_ERR("failed to set MCLK configuration"); + return ret; + } +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + +#ifdef CONFIG_SAI_IMX93_ERRATA_051421 + sai_config_set_err_051421(UINT_TO_I2S(data->regmap), + sai_cfg, bespoke, + rx_config, tx_config); +#endif /* CONFIG_SAI_IMX93_ERRATA_051421 */ + + /* this is needed so that rates different from FSYNC_RATE + * will not be allowed. + * + * this is because the hardware is configured to match + * the topology rates so attempting to play a file using + * a different rate from the one configured in the hardware + * doesn't work properly. + * + * if != 0, SOF will raise an error if the PCM rate is + * different than the hardware rate (a.k.a this one). + */ + data->cfg.rate = bespoke->fsync_rate; + /* SOF note: we don't support a variable number of channels + * at the moment so leaving the number of channels as 0 is + * unnecessary and leads to issues (e.g: the mixer buffers + * use this value to set the number of channels so having + * a 0 as this value leads to mixer buffers having 0 channels, + * which, in turn, leads to the DAI ending up with 0 channels, + * thus resulting in an error) + */ + data->cfg.channels = bespoke->tdm_slots; + + sai_dump_register_data(data->regmap); + + return 0; +} + +/* SOF note: please be very careful with this function as it does + * busy waiting and may mess up your timing in time critial applications + * (especially with timer domain). If this becomes unusable, the busy + * waiting should be removed altogether and the HW state check should + * be performed in sai_trigger_start() or in sai_config_set(). + * + * TODO: seems like the transmitter still remains active (even if 1ms + * has passed after doing a sai_trigger_stop()!). Most likely this is + * because sai_trigger_stop() immediately stops the data line w/o + * checking the HW state of the transmitter/receiver. As such, to get + * rid of the busy waiting, the STOP operation may have to be split into + * 2 operations: TRIG_STOP and TRIG_POST_STOP. + */ +static bool sai_dir_disable(struct sai_data *data, enum dai_dir dir) +{ + /* VERY IMPORTANT: DO NOT use SAI_TxEnable/SAI_RxEnable + * here as they do not disable the ASYNC direction. + * Since the software logic assures that the ASYNC direction + * is not disabled before the SYNC direction, we can force + * the disablement of the given direction. + */ + sai_tx_rx_force_disable(dir, data->regmap); + + /* please note the difference between the transmitter/receiver's + * hardware states and their software states. The software + * states can be obtained by reading data->tx/rx_enabled, while + * the hardware states can be obtained by reading TCSR/RCSR. The + * hardware state can actually differ from the software state. + * Here, we're interested in reading the hardware state which + * indicates if the transmitter/receiver was actually disabled + * or not. + */ + return WAIT_FOR(!SAI_TX_RX_IS_HW_ENABLED(dir, data->regmap), + SAI_TX_RX_HW_DISABLE_TIMEOUT, k_busy_wait(1)); +} + +static int sai_tx_rx_disable(struct sai_data *data, + const struct sai_config *cfg, enum dai_dir dir) +{ + enum dai_dir sync_dir, async_dir; + bool ret; + + /* sai_disable() should never be called from ISR context + * as it does some busy waiting. + */ + if (k_is_in_isr()) { + LOG_ERR("sai_disable() should never be called from ISR context"); + return -EINVAL; + } + + if (cfg->tx_sync_mode == kSAI_ModeAsync && + cfg->rx_sync_mode == kSAI_ModeAsync) { + ret = sai_dir_disable(data, dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", dir); + return -ETIMEDOUT; + } + } else { + sync_dir = SAI_TX_RX_GET_SYNC_DIR(cfg); + async_dir = SAI_TX_RX_GET_ASYNC_DIR(cfg); + + if (dir == sync_dir) { + ret = sai_dir_disable(data, sync_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + sync_dir); + return -ETIMEDOUT; + } + + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(async_dir, data)) { + ret = sai_dir_disable(data, async_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + async_dir); + return -ETIMEDOUT; + } + } + } else { + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(sync_dir, data)) { + ret = sai_dir_disable(data, async_dir); + if (!ret) { + LOG_ERR("timed out while waiting for dir %d disable", + async_dir); + return -ETIMEDOUT; + } + } + } + } + + return 0; +} + +static int sai_trigger_pause(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + const struct sai_config *cfg; + int ret; + + data = dev->data; + cfg = dev->config; + + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_PAUSED); + if (ret < 0) { + LOG_ERR("failed to transition to PAUSED from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + LOG_DBG("pause on direction %d", dir); + + ret = sai_tx_rx_disable(data, cfg, dir); + if (ret < 0) { + return ret; + } + + /* disable TX/RX data line */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, false); + + return 0; +} + +static int sai_trigger_stop(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + const struct sai_config *cfg; + int ret; + uint32_t old_state; + + data = dev->data; + cfg = dev->config; + old_state = sai_get_state(dir, data); + + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_STOPPING); + if (ret < 0) { + LOG_ERR("failed to transition to STOPPING from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + LOG_DBG("stop on direction %d", dir); + + if (old_state == DAI_STATE_PAUSED) { + /* if SAI was previously paused then all that's + * left to do is disable the DMA requests and + * the data line. + */ + goto out_dmareq_disable; + } + + ret = sai_tx_rx_disable(data, cfg, dir); + if (ret < 0) { + return ret; + } + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, false); + + /* disable TX/RX data line */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x0); + +out_dmareq_disable: + /* disable DMA requests */ + SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, false); + + /* disable error interrupt */ + SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, + kSAI_FIFOErrorInterruptEnable, false); + + return 0; +} + +/* notes: + * 1) The "rx_sync_mode" and "tx_sync_mode" properties force the user to pick from + * SYNC and ASYNC for each direction. As such, there are 4 possible combinations + * that need to be covered here: + * a) TX ASYNC, RX ASYNC + * b) TX SYNC, RX ASYNC + * c) TX ASYNC, RX SYNC + * d) TX SYNC, RX SYNC + * + * Combination d) is not valid and is covered by a BUILD_ASSERT(). As such, there are 3 valid + * combinations that need to be supported. Since the main branch of the IF statement covers + * combination a), there's only combinations b) and c) to be covered here. + * + * 2) We can distinguish between 3 types of directions: + * a) The target direction. This is the direction on which we want to perform the + * software reset. + * b) The SYNC direction. This is, well, the direction that's in SYNC with the other + * direction. + * c) The ASYNC direction. + * + * Of course, the target direction may differ from the SYNC or ASYNC directions, but it + * can't differ from both of them at the same time (i.e: TARGET != SYNC AND TARGET != ASYNC). + * + * If the target direction is the same as the SYNC direction then we can safely perform the + * software reset on the target direction as there's nothing depending on it. We also want + * to do a software reset on the ASYNC direction. We can only do this if the ASYNC direction + * wasn't software enabled (i.e: through an explicit trigger_start() call). + * + * If the target direction is the same as the ASYNC direction then we can only perform a + * software reset on it only if the SYNC direction wasn't software enabled (i.e: through an + * explicit trigger_start() call). + */ +static void sai_tx_rx_sw_reset(struct sai_data *data, + const struct sai_config *cfg, enum dai_dir dir) +{ + enum dai_dir sync_dir, async_dir; + + if (cfg->tx_sync_mode == kSAI_ModeAsync && + cfg->rx_sync_mode == kSAI_ModeAsync) { + /* both directions are ASYNC w.r.t each other. As such, do + * software reset only on the targeted direction. + */ + SAI_TX_RX_SW_RESET(dir, data->regmap); + } else { + sync_dir = SAI_TX_RX_GET_SYNC_DIR(cfg); + async_dir = SAI_TX_RX_GET_ASYNC_DIR(cfg); + + if (dir == sync_dir) { + SAI_TX_RX_SW_RESET(sync_dir, data->regmap); + + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(async_dir, data)) { + SAI_TX_RX_SW_RESET(async_dir, data->regmap); + } + } else { + if (!SAI_TX_RX_DIR_IS_SW_ENABLED(sync_dir, data)) { + SAI_TX_RX_SW_RESET(async_dir, data->regmap); + } + } + } +} + +static int sai_trigger_start(const struct device *dev, + enum dai_dir dir) +{ + struct sai_data *data; + const struct sai_config *cfg; + uint32_t old_state; + int ret; + + data = dev->data; + cfg = dev->config; + old_state = sai_get_state(dir, data); + + /* TX and RX should be triggered independently */ + if (dir != DAI_DIR_RX && dir != DAI_DIR_TX) { + LOG_ERR("invalid direction: %d", dir); + return -EINVAL; + } + + /* attempt to change state */ + ret = sai_update_state(dir, data, DAI_STATE_RUNNING); + if (ret < 0) { + LOG_ERR("failed to transition to RUNNING from %d. Reason: %d", + sai_get_state(dir, data), ret); + return ret; + } + + if (old_state == DAI_STATE_PAUSED) { + /* if the SAI has been paused then there's no + * point in issuing a software reset. As such, + * skip this part and go directly to the TX/RX + * enablement. + */ + goto out_enable_dline; + } + + LOG_DBG("start on direction %d", dir); + + sai_tx_rx_sw_reset(data, cfg, dir); + + /* enable error interrupt */ + SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, data->regmap, + kSAI_FIFOErrorInterruptEnable, true); + + /* TODO: is there a need to write some words to the FIFO to avoid starvation? */ + + /* TODO: for now, only DMA mode is supported */ + SAI_TX_RX_DMA_ENABLE_DISABLE(dir, data->regmap, true); + +out_enable_dline: + /* enable TX/RX data line. This translates to TX_DLINE0/RX_DLINE0 + * being enabled. + * + * TODO: for now we only support 1 data line per direction. + */ + sai_tx_rx_set_dline_mask(dir, data->regmap, 0x1); + + /* this will also enable the async side */ + SAI_TX_RX_ENABLE_DISABLE(dir, data->regmap, true); + + /* update the software state of TX/RX */ + sai_tx_rx_sw_enable_disable(dir, data, true); + + return 0; +} + +static int sai_trigger(const struct device *dev, + enum dai_dir dir, + enum dai_trigger_cmd cmd) +{ + switch (cmd) { + case DAI_TRIGGER_START: + return sai_trigger_start(dev, dir); + case DAI_TRIGGER_PAUSE: + return sai_trigger_pause(dev, dir); + case DAI_TRIGGER_STOP: + return sai_trigger_stop(dev, dir); + case DAI_TRIGGER_PRE_START: + case DAI_TRIGGER_COPY: + /* COPY and PRE_START don't require the SAI + * driver to do anything at the moment so + * mark them as successful via a NULL return + * + * note: although the rest of the unhandled + * trigger commands may be valid, return + * an error code for them as they aren't + * implemented ATM (since they're not + * mandatory for the SAI driver to work). + */ + return 0; + default: + LOG_ERR("invalid trigger command: %d", cmd); + return -EINVAL; + } + + CODE_UNREACHABLE; +} + +static int sai_probe(const struct device *dev) +{ + /* nothing to be done here but sadly mandatory to implement */ + return 0; +} + +static int sai_remove(const struct device *dev) +{ + /* nothing to be done here but sadly mandatory to implement */ + return 0; +} + +static const struct dai_driver_api sai_api = { + .config_set = sai_config_set, + .config_get = sai_config_get, + .trigger = sai_trigger, + .get_properties = sai_get_properties, + .probe = sai_probe, + .remove = sai_remove, +}; + +static int sai_init(const struct device *dev) +{ + const struct sai_config *cfg; + struct sai_data *data; + int i, ret; + + cfg = dev->config; + data = dev->data; + + device_map(&data->regmap, cfg->regmap_phys, cfg->regmap_size, K_MEM_CACHE_NONE); + + /* enable clocks if any */ + for (i = 0; i < cfg->clk_data.clock_num; i++) { + ret = clock_control_on(cfg->clk_data.dev, + UINT_TO_POINTER(cfg->clk_data.clocks[i])); + if (ret < 0) { + return ret; + } + + LOG_DBG("clock %s has been ungated", cfg->clk_data.clock_names[i]); + } + + /* set TX/RX default states */ + data->tx_state = DAI_STATE_NOT_READY; + data->rx_state = DAI_STATE_NOT_READY; + + /* register ISR and enable IRQ */ + cfg->irq_config(); + + return 0; +} + +#define SAI_INIT(inst) \ + \ +BUILD_ASSERT(SAI_FIFO_DEPTH(inst) > 0 && \ + SAI_FIFO_DEPTH(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid FIFO depth"); \ + \ +BUILD_ASSERT(SAI_RX_FIFO_WATERMARK(inst) > 0 && \ + SAI_RX_FIFO_WATERMARK(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid RX FIFO watermark"); \ + \ +BUILD_ASSERT(SAI_TX_FIFO_WATERMARK(inst) > 0 && \ + SAI_TX_FIFO_WATERMARK(inst) <= _SAI_FIFO_DEPTH(inst), \ + "invalid TX FIFO watermark"); \ + \ +BUILD_ASSERT(IS_ENABLED(CONFIG_SAI_HAS_MCLK_CONFIG_OPTION) || \ + !DT_INST_PROP(inst, mclk_is_output), \ + "SAI doesn't support MCLK config but mclk_is_output is specified");\ + \ +BUILD_ASSERT(SAI_TX_SYNC_MODE(inst) != SAI_RX_SYNC_MODE(inst) || \ + SAI_TX_SYNC_MODE(inst) != kSAI_ModeSync, \ + "transmitter and receiver can't be both SYNC with each other"); \ + \ +static const struct dai_properties sai_tx_props_##inst = { \ + .fifo_address = SAI_TX_FIFO_BASE(inst), \ + .fifo_depth = SAI_FIFO_DEPTH(inst) * CONFIG_SAI_FIFO_WORD_SIZE, \ + .dma_hs_id = SAI_TX_DMA_MUX(inst), \ +}; \ + \ +static const struct dai_properties sai_rx_props_##inst = { \ + .fifo_address = SAI_RX_FIFO_BASE(inst), \ + .fifo_depth = SAI_FIFO_DEPTH(inst) * CONFIG_SAI_FIFO_WORD_SIZE, \ + .dma_hs_id = SAI_RX_DMA_MUX(inst), \ +}; \ + \ +void irq_config_##inst(void) \ +{ \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + 0, \ + sai_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst)); \ +} \ + \ +static struct sai_config sai_config_##inst = { \ + .regmap_phys = DT_INST_REG_ADDR(inst), \ + .regmap_size = DT_INST_REG_SIZE(inst), \ + .clk_data = SAI_CLOCK_DATA_DECLARE(inst), \ + .rx_fifo_watermark = SAI_RX_FIFO_WATERMARK(inst), \ + .tx_fifo_watermark = SAI_TX_FIFO_WATERMARK(inst), \ + .mclk_is_output = DT_INST_PROP(inst, mclk_is_output), \ + .tx_props = &sai_tx_props_##inst, \ + .rx_props = &sai_rx_props_##inst, \ + .irq_config = irq_config_##inst, \ + .tx_sync_mode = SAI_TX_SYNC_MODE(inst), \ + .rx_sync_mode = SAI_RX_SYNC_MODE(inst), \ +}; \ + \ +static struct sai_data sai_data_##inst = { \ + .cfg.type = DAI_IMX_SAI, \ + .cfg.dai_index = DT_INST_PROP_OR(inst, dai_index, 0), \ +}; \ + \ +DEVICE_DT_INST_DEFINE(inst, &sai_init, NULL, \ + &sai_data_##inst, &sai_config_##inst, \ + POST_KERNEL, CONFIG_DAI_INIT_PRIORITY, \ + &sai_api); \ + +DT_INST_FOREACH_STATUS_OKAY(SAI_INIT); diff --git a/drivers/dai/nxp/sai/sai.h b/drivers/dai/nxp/sai/sai.h new file mode 100644 index 00000000000..f3f4441a6cb --- /dev/null +++ b/drivers/dai/nxp/sai/sai.h @@ -0,0 +1,543 @@ +/* Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ +#define ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ + +#include +#include +#include + +LOG_MODULE_REGISTER(nxp_dai_sai); + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +#define SAI_MCLK_MCR_MSEL_SHIFT 24 +#define SAI_MCLK_MCR_MSEL_MASK GENMASK(24, 25) +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ +/* workaround the fact that device_map() doesn't exist for SoCs with no MMU */ +#ifndef DEVICE_MMIO_IS_IN_RAM +#define device_map(virt, phys, size, flags) *(virt) = (phys) +#endif /* DEVICE_MMIO_IS_IN_RAM */ + +/* used to convert an uint to I2S_Type * */ +#define UINT_TO_I2S(x) ((I2S_Type *)(uintptr_t)(x)) + +/* macros used for parsing DTS data */ + +/* used instead of IDENTITY because LISTIFY expects the used macro function + * to also take a variable number of arguments. + */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +/* used to generate the list of clock indexes */ +#define _SAI_CLOCK_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_LEN_OR(inst, clocks, 0), IDENTITY_VARGS, (,)) + +/* used to retrieve a clock's ID using its index generated via _SAI_CLOCK_INDEX_ARRAY */ +#define _SAI_GET_CLOCK_ID(clock_idx, inst)\ + DT_INST_CLOCKS_CELL_BY_IDX(inst, clock_idx, name) + +/* used to retrieve a clock's name using its index generated via _SAI_CLOCK_INDEX_ARRAY */ +#define _SAI_GET_CLOCK_NAME(clock_idx, inst)\ + DT_INST_PROP_BY_IDX(inst, clock_names, clock_idx) + +/* used to convert the clocks property into an array of clock IDs */ +#define _SAI_CLOCK_ID_ARRAY(inst)\ + FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_ID, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst)) + +/* used to convert the clock-names property into an array of clock names */ +#define _SAI_CLOCK_NAME_ARRAY(inst)\ + FOR_EACH_FIXED_ARG(_SAI_GET_CLOCK_NAME, (,), inst, _SAI_CLOCK_INDEX_ARRAY(inst)) + +/* used to convert a clocks property into an array of clock IDs. If the property + * is not specified then this macro will return {}. + */ +#define _SAI_GET_CLOCK_ARRAY(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + ({ _SAI_CLOCK_ID_ARRAY(inst) }),\ + ({ })) + +/* used to retrieve a const struct device *dev pointing to the clock controller. + * It is assumed that all SAI clocks come from a single clock provider. + * This macro returns a NULL if the clocks property doesn't exist. + */ +#define _SAI_GET_CLOCK_CONTROLLER(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + (DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst))),\ + (NULL)) + +/* used to convert a clock-names property into an array of clock names. If the + * property is not specified then this macro will return {}. + */ +#define _SAI_GET_CLOCK_NAMES(inst)\ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, nxp_dai_sai), clocks),\ + ({ _SAI_CLOCK_NAME_ARRAY(inst) }),\ + ({ })) + +/* used to declare a struct clock_data */ +#define SAI_CLOCK_DATA_DECLARE(inst) \ +{ \ + .clocks = (uint32_t [])_SAI_GET_CLOCK_ARRAY(inst), \ + .clock_num = DT_INST_PROP_LEN_OR(inst, clocks, 0), \ + .dev = _SAI_GET_CLOCK_CONTROLLER(inst), \ + .clock_names = (const char *[])_SAI_GET_CLOCK_NAMES(inst), \ +} + +/* used to parse the tx-fifo-watermark property. If said property is not + * specified then this macro will return half of the number of words in the + * FIFO. + */ +#define SAI_TX_FIFO_WATERMARK(inst)\ + DT_INST_PROP_OR(inst, tx_fifo_watermark,\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2) + +/* used to parse the rx-fifo-watermark property. If said property is not + * specified then this macro will return half of the number of words in the + * FIFO. + */ +#define SAI_RX_FIFO_WATERMARK(inst)\ + DT_INST_PROP_OR(inst, rx_fifo_watermark,\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) / 2) + +/* used to retrieve TFR0's address based on SAI's physical address */ +#define SAI_TX_FIFO_BASE(inst)\ + FSL_FEATURE_SAI_TX_FIFO_BASEn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)), 0) + +/* used to retrieve RFR0's address based on SAI's physical address */ +#define SAI_RX_FIFO_BASE(inst)\ + FSL_FEATURE_SAI_RX_FIFO_BASEn(UINT_TO_I2S(DT_INST_REG_ADDR(inst)), 0) + +/* internal macro used to retrieve the default TX/RX FIFO's size (in FIFO words) */ +#define _SAI_FIFO_DEPTH(inst)\ + FSL_FEATURE_SAI_FIFO_COUNTn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* used to retrieve the TX/RX FIFO's size (in FIFO words) */ +#define SAI_FIFO_DEPTH(inst)\ + DT_INST_PROP_OR(inst, fifo_depth, _SAI_FIFO_DEPTH(inst)) + +/* used to retrieve the DMA MUX for transmitter */ +#define SAI_TX_DMA_MUX(inst)\ + FSL_FEATURE_SAI_TX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* used to retrieve the DMA MUX for receiver */ +#define SAI_RX_DMA_MUX(inst)\ + FSL_FEATURE_SAI_RX_DMA_MUXn(UINT_TO_I2S(DT_INST_REG_ADDR(inst))) + +/* used to retrieve the synchronization mode of the transmitter. If this + * property is not specified, ASYNC mode will be used. + */ +#define SAI_TX_SYNC_MODE(inst)\ + DT_INST_PROP_OR(inst, tx_sync_mode, kSAI_ModeAsync) + +/* used to retrieve the synchronization mode of the receiver. If this property + * is not specified, ASYNC mode will be used. + */ +#define SAI_RX_SYNC_MODE(inst)\ + DT_INST_PROP_OR(inst, rx_sync_mode, kSAI_ModeAsync) + +/* utility macros */ + +/* invert a clock's polarity. This works because a clock's polarity is expressed + * as a 0 or as a 1. + */ +#define SAI_INVERT_POLARITY(polarity) (polarity) = !(polarity) + +/* used to issue a software reset of the transmitter/receiver */ +#define SAI_TX_RX_SW_RESET(dir, regmap)\ + ((dir) == DAI_DIR_RX ? SAI_RxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware) :\ + SAI_TxSoftwareReset(UINT_TO_I2S(regmap), kSAI_ResetTypeSoftware)) + +/* used to enable/disable the transmitter/receiver. + * When enabling the SYNC component, the ASYNC component will also be enabled. + * Attempting to disable the SYNC component will fail unless the SYNC bit is + * cleared. It is recommended to use sai_tx_rx_force_disable() instead of this + * macro when disabling transmitter/receiver. + */ +#define SAI_TX_RX_ENABLE_DISABLE(dir, regmap, enable)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnable(UINT_TO_I2S(regmap), enable) :\ + SAI_TxEnable(UINT_TO_I2S(regmap), enable)) + +/* used to enable/disable the DMA requests for transmitter/receiver */ +#define SAI_TX_RX_DMA_ENABLE_DISABLE(dir, regmap, enable)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnableDMA(UINT_TO_I2S(regmap),\ + kSAI_FIFORequestDMAEnable, enable) :\ + SAI_TxEnableDMA(UINT_TO_I2S(regmap), kSAI_FIFORequestDMAEnable, enable)) + +/* used to check if the hardware transmitter/receiver is enabled */ +#define SAI_TX_RX_IS_HW_ENABLED(dir, regmap)\ + ((dir) == DAI_DIR_RX ? (UINT_TO_I2S(regmap)->RCSR & I2S_RCSR_RE_MASK) : \ + (UINT_TO_I2S(regmap)->TCSR & I2S_TCSR_TE_MASK)) + +/* used to enable various transmitter/receiver interrupts */ +#define _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? SAI_RxEnableInterrupts(UINT_TO_I2S(regmap), which) : \ + SAI_TxEnableInterrupts(UINT_TO_I2S(regmap), which)) + +/* used to disable various transmitter/receiver interrupts */ +#define _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? SAI_RxDisableInterrupts(UINT_TO_I2S(regmap), which) : \ + SAI_TxDisableInterrupts(UINT_TO_I2S(regmap), which)) + +/* used to enable/disable various transmitter/receiver interrupts */ +#define SAI_TX_RX_ENABLE_DISABLE_IRQ(dir, regmap, which, enable)\ + ((enable == true) ? _SAI_TX_RX_ENABLE_IRQ(dir, regmap, which) :\ + _SAI_TX_RX_DISABLE_IRQ(dir, regmap, which)) + +/* used to check if a status flag is set */ +#define SAI_TX_RX_STATUS_IS_SET(dir, regmap, which)\ + ((dir) == DAI_DIR_RX ? ((UINT_TO_I2S(regmap))->RCSR & (which)) : \ + ((UINT_TO_I2S(regmap))->TCSR & (which))) + +/* used to retrieve the SYNC direction. Use this macro when you know for sure + * you have 1 SYNC direction with 1 ASYNC direction. + */ +#define SAI_TX_RX_GET_SYNC_DIR(cfg)\ + ((cfg)->tx_sync_mode == kSAI_ModeSync ? DAI_DIR_TX : DAI_DIR_RX) + +/* used to retrieve the ASYNC direction. Use this macro when you know for sure + * you have 1 SYNC direction with 1 ASYNC direction. + */ +#define SAI_TX_RX_GET_ASYNC_DIR(cfg)\ + ((cfg)->tx_sync_mode == kSAI_ModeAsync ? DAI_DIR_TX : DAI_DIR_RX) + +/* used to check if transmitter/receiver is SW enabled */ +#define SAI_TX_RX_DIR_IS_SW_ENABLED(dir, data)\ + ((dir) == DAI_DIR_TX ? data->tx_enabled : data->rx_enabled) + +struct sai_clock_data { + uint32_t *clocks; + uint32_t clock_num; + /* assumption: all clocks belong to the same producer */ + const struct device *dev; + const char **clock_names; +}; + +struct sai_data { + mm_reg_t regmap; + sai_transceiver_t rx_config; + sai_transceiver_t tx_config; + bool tx_enabled; + bool rx_enabled; + enum dai_state tx_state; + enum dai_state rx_state; + struct dai_config cfg; +}; + +struct sai_config { + uint32_t regmap_phys; + uint32_t regmap_size; + struct sai_clock_data clk_data; + bool mclk_is_output; + /* if the tx/rx-fifo-watermark properties are not specified, it's going + * to be assumed that the watermark should be set to half of the FIFO + * size. + */ + uint32_t rx_fifo_watermark; + uint32_t tx_fifo_watermark; + const struct dai_properties *tx_props; + const struct dai_properties *rx_props; + uint32_t dai_index; + /* RX synchronization mode - may be SYNC or ASYNC */ + sai_sync_mode_t rx_sync_mode; + /* TX synchronization mode - may be SYNC or ASYNC */ + sai_sync_mode_t tx_sync_mode; + void (*irq_config)(void); +}; + +/* this needs to perfectly match SOF's struct sof_ipc_dai_sai_params */ +struct sai_bespoke_config { + uint32_t reserved0; + + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + /* CLOCK-related data */ + uint32_t mclk_rate; + uint32_t fsync_rate; + uint32_t bclk_rate; + + /* TDM-related data */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; +}; + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION +static int get_msel(sai_bclk_source_t bclk_source, uint32_t *msel) +{ + switch (bclk_source) { + case kSAI_BclkSourceMclkOption1: + *msel = 0; + break; + case kSAI_BclkSourceMclkOption2: + *msel = (0x2 << SAI_MCLK_MCR_MSEL_SHIFT); + break; + case kSAI_BclkSourceMclkOption3: + *msel = (0x3 << SAI_MCLK_MCR_MSEL_SHIFT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void set_msel(uint32_t regmap, int msel) +{ + UINT_TO_I2S(regmap)->MCR &= ~SAI_MCLK_MCR_MSEL_MASK; + UINT_TO_I2S(regmap)->MCR |= msel; +} + +static int clk_lookup_by_name(const struct sai_clock_data *clk_data, char *name) +{ + int i; + + for (i = 0; i < clk_data->clock_num; i++) { + if (!strcmp(name, clk_data->clock_names[i])) { + return i; + } + } + + return -EINVAL; +} + +static int get_mclk_rate(const struct sai_clock_data *clk_data, + sai_bclk_source_t bclk_source, + uint32_t *rate) +{ + int clk_idx; + char *clk_name; + + switch (bclk_source) { + case kSAI_BclkSourceMclkOption1: + clk_name = "mclk1"; + break; + case kSAI_BclkSourceMclkOption2: + clk_name = "mclk2"; + break; + case kSAI_BclkSourceMclkOption3: + clk_name = "mclk3"; + break; + default: + LOG_ERR("invalid bitclock source: %d", bclk_source); + return -EINVAL; + } + + clk_idx = clk_lookup_by_name(clk_data, clk_name); + if (clk_idx < 0) { + LOG_ERR("failed to get clock index for %s", clk_name); + return clk_idx; + } + + return clock_control_get_rate(clk_data->dev, + UINT_TO_POINTER(clk_data->clocks[clk_idx]), + rate); +} +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ + +static inline void get_bclk_default_config(sai_bit_clock_t *cfg) +{ + memset(cfg, 0, sizeof(sai_bit_clock_t)); + + /* by default, BCLK has the following properties: + * + * 1) BCLK is active HIGH. + * 2) BCLK uses MCLK1 source. (only applicable to master mode) + * 3) No source swap. + * 4) No input delay. + */ + cfg->bclkPolarity = kSAI_PolarityActiveHigh; + cfg->bclkSource = kSAI_BclkSourceMclkOption1; +} + +static inline void get_fsync_default_config(sai_frame_sync_t *cfg) +{ + memset(cfg, 0, sizeof(sai_frame_sync_t)); + + /* by default, FSYNC has the following properties: + * + * 1) FSYNC is asserted one bit early with respect to the next + * frame. + * 2) FSYNC is active HIGH. + */ + cfg->frameSyncEarly = true; + cfg->frameSyncPolarity = kSAI_PolarityActiveHigh; +} + +static inline void get_serial_default_config(sai_serial_data_t *cfg) +{ + memset(cfg, 0, sizeof(sai_serial_data_t)); + + /* by default, the serial configuration has the following quirks: + * + * 1) Data pin is not tri-stated. + * 2) MSB is first. + */ + /* note: this is equivalent to checking if the SAI has xCR4's CHMOD bit */ +#if FSL_FEATURE_SAI_HAS_CHANNEL_MODE + cfg->dataMode = kSAI_DataPinStateOutputZero; +#endif /* FSL_FEATURE_SAI_HAS_CHANNEL_MODE */ + cfg->dataOrder = kSAI_DataMSB; +} + +static inline void get_fifo_default_config(sai_fifo_t *cfg) +{ + memset(cfg, 0, sizeof(sai_fifo_t)); +} + +static inline uint32_t sai_get_state(enum dai_dir dir, + struct sai_data *data) +{ + if (dir == DAI_DIR_RX) { + return data->rx_state; + } else { + return data->tx_state; + } +} + +static int sai_update_state(enum dai_dir dir, + struct sai_data *data, + enum dai_state new_state) +{ + enum dai_state old_state = sai_get_state(dir, data); + + LOG_DBG("attempting to transition from %d to %d", old_state, new_state); + + /* check if transition is possible */ + switch (new_state) { + case DAI_STATE_NOT_READY: + /* this shouldn't be possible */ + return -EPERM; + case DAI_STATE_READY: + if (old_state != DAI_STATE_NOT_READY && + old_state != DAI_STATE_READY && + old_state != DAI_STATE_STOPPING) { + return -EPERM; + } + break; + case DAI_STATE_RUNNING: + if (old_state != DAI_STATE_PAUSED && + old_state != DAI_STATE_STOPPING && + old_state != DAI_STATE_READY) { + return -EPERM; + } + break; + case DAI_STATE_PAUSED: + if (old_state != DAI_STATE_RUNNING) { + return -EPERM; + } + break; + case DAI_STATE_STOPPING: + if (old_state != DAI_STATE_READY && + old_state != DAI_STATE_RUNNING && + old_state != DAI_STATE_PAUSED) { + return -EPERM; + } + break; + case DAI_STATE_ERROR: + case DAI_STATE_PRE_RUNNING: + /* these states are not used so transitioning to them + * is considered invalid. + */ + default: + return -EINVAL; + } + + if (dir == DAI_DIR_RX) { + data->rx_state = new_state; + } else { + data->tx_state = new_state; + } + + return 0; +} + +static inline void sai_tx_rx_force_disable(enum dai_dir dir, + uint32_t regmap) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + if (dir == DAI_DIR_RX) { + base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK)); + } else { + base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK)); + } +} + +static inline void sai_tx_rx_sw_enable_disable(enum dai_dir dir, + struct sai_data *data, + bool enable) +{ + if (dir == DAI_DIR_RX) { + data->rx_enabled = enable; + } else { + data->tx_enabled = enable; + } +} + +static inline int count_leading_zeros(uint32_t word) +{ + int num = 0; + + while (word) { + if (!(word & 0x1)) { + num++; + } else { + break; + } + + word = word >> 1; + } + + return num; +} + +static inline void sai_tx_rx_set_dline_mask(enum dai_dir dir, uint32_t regmap, uint32_t mask) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + if (dir == DAI_DIR_RX) { + base->RCR3 &= ~I2S_RCR3_RCE_MASK; + base->RCR3 |= I2S_RCR3_RCE(mask); + } else { + base->TCR3 &= ~I2S_TCR3_TCE_MASK; + base->TCR3 |= I2S_TCR3_TCE(mask); + } +} + +static inline void sai_dump_register_data(uint32_t regmap) +{ + I2S_Type *base = UINT_TO_I2S(regmap); + + LOG_DBG("TCSR: 0x%x", base->TCSR); + LOG_DBG("RCSR: 0x%x", base->RCSR); + + LOG_DBG("TCR1: 0x%x", base->TCR1); + LOG_DBG("RCR1: 0x%x", base->RCR1); + + LOG_DBG("TCR2: 0x%x", base->TCR2); + LOG_DBG("RCR2: 0x%x", base->RCR2); + + LOG_DBG("TCR3: 0x%x", base->TCR3); + LOG_DBG("RCR3: 0x%x", base->RCR3); + + LOG_DBG("TCR4: 0x%x", base->TCR4); + LOG_DBG("RCR4: 0x%x", base->RCR4); + + LOG_DBG("TCR5: 0x%x", base->TCR5); + LOG_DBG("RCR5: 0x%x", base->RCR5); + + LOG_DBG("TMR: 0x%x", base->TMR); + LOG_DBG("RMR: 0x%x", base->RMR); + +#ifdef CONFIG_SAI_HAS_MCLK_CONFIG_OPTION + LOG_DBG("MCR: 0x%x", base->MCR); +#endif /* CONFIG_SAI_HAS_MCLK_CONFIG_OPTION */ +} + +#endif /* ZEPHYR_DRIVERS_DAI_NXP_SAI_H_ */ diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 20bd8659aff..3b166e73892 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_STM32_LTDC display_stm32_ltdc.c) zephyr_library_sources_ifdef(CONFIG_RM68200 display_rm68200.c) zephyr_library_sources_ifdef(CONFIG_RM67162 display_rm67162.c) zephyr_library_sources_ifdef(CONFIG_HX8394 display_hx8394.c) +zephyr_library_sources_ifdef(CONFIG_GC9X01X display_gc9x01x.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index f6a39f0f984..53b1a6f3917 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -40,5 +40,6 @@ source "drivers/display/Kconfig.intel_multibootfb" source "drivers/display/Kconfig.mcux_dcnano_lcdif" source "drivers/display/Kconfig.otm8009a" source "drivers/display/Kconfig.hx8394" +source "drivers/display/Kconfig.gc9x01x" endif # DISPLAY diff --git a/drivers/display/Kconfig.gc9x01x b/drivers/display/Kconfig.gc9x01x new file mode 100644 index 00000000000..aba24c445f1 --- /dev/null +++ b/drivers/display/Kconfig.gc9x01x @@ -0,0 +1,10 @@ +# Copyright 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +config GC9X01X + bool "GC9X01X display driver" + default y + depends on DT_HAS_GALAXYCORE_GC9X01X_ENABLED + select SPI + help + Enable driver for GC9X01X display driver. diff --git a/drivers/display/Kconfig.ili9xxx b/drivers/display/Kconfig.ili9xxx index 0ae849260cf..ccd6778d04a 100644 --- a/drivers/display/Kconfig.ili9xxx +++ b/drivers/display/Kconfig.ili9xxx @@ -14,7 +14,7 @@ config ILI9340 bool "ILI9340 display driver" default y depends on DT_HAS_ILITEK_ILI9340_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9340 display driver. @@ -23,7 +23,7 @@ config ILI9341 bool "ILI9341 display driver" default y depends on DT_HAS_ILITEK_ILI9341_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9341 display driver. @@ -32,7 +32,7 @@ config ILI9342C bool "ILI9342C display driver" default y depends on DT_HAS_ILITEK_ILI9342C_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9342C display driver. @@ -41,7 +41,7 @@ config ILI9488 bool "ILI9488 display driver" default y depends on DT_HAS_ILITEK_ILI9488_ENABLED - select SPI + select MIPI_DBI select ILI9XXX help Enable driver for ILI9488 display driver. diff --git a/drivers/display/Kconfig.sdl b/drivers/display/Kconfig.sdl index a06b143f31e..bfa1f07c48e 100644 --- a/drivers/display/Kconfig.sdl +++ b/drivers/display/Kconfig.sdl @@ -39,4 +39,24 @@ choice SDL_DISPLAY_DEFAULT_PIXEL_FORMAT endchoice +config SDL_DISPLAY_ZOOM_PCT + int "Default zoom percentage" + default 100 + range 10 10000 + help + SDL window zoom percentage to adjust readability on small screens + +config SDL_DISPLAY_USE_HARDWARE_ACCELERATOR + bool "Use hardware accelerator" + default y + help + Enable hardware acceleration for graphics rendering + +config SDL_DISPLAY_MONO_MSB_FIRST + bool "Configure bit order in monochrome formats to MSB first" + default y + help + If selected, set the MSB to represent the first pixel. + This applies when the pixel format is MONO01/MONO10. + endif # SDL_DISPLAY diff --git a/drivers/display/Kconfig.stm32_ltdc b/drivers/display/Kconfig.stm32_ltdc index 1d998c33e8f..11efe766897 100644 --- a/drivers/display/Kconfig.stm32_ltdc +++ b/drivers/display/Kconfig.stm32_ltdc @@ -8,9 +8,12 @@ menuconfig STM32_LTDC default y depends on DT_HAS_ST_STM32_LTDC_ENABLED select USE_STM32_HAL_LTDC + select CACHE_MANAGEMENT if CPU_HAS_DCACHE help Enable driver for STM32 LCT-TFT display controller periheral. +if STM32_LTDC + choice STM32_LTDC_PIXEL_FORMAT prompt "Color pixel format" default STM32_LTDC_RGB565 @@ -37,3 +40,23 @@ config STM32_LTDC_RGB565 (2 bytes per pixel) endchoice + +config STM32_LTDC_FB_NUM + int "Frame buffer number" + default 1 + range 0 2 + help + STM32 LTDC frame buffer number config: + - 0 frame buffer maintained by application, must write with full screen pixels. + - 1 single frame buffer in stm32 ltdc driver. + - 2 double frame buffer in stm32 ltdc driver. + +config STM32_LTDC_DISABLE_FMC_BANK1 + bool "Disable FMC bank1 for STM32F7/H7 series" + depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32F7X + default y + help + Disable FMC bank1 if not used to prevent speculative read accesses. + Refer to AN4861 "4.6 Special recommendations for Cortex-M7 (STM32F7/H7)". + +endif # STM32_LTDC diff --git a/drivers/display/Kconfig.uc81xx b/drivers/display/Kconfig.uc81xx index 31951bd8180..75678d2f663 100644 --- a/drivers/display/Kconfig.uc81xx +++ b/drivers/display/Kconfig.uc81xx @@ -6,7 +6,7 @@ config UC81XX bool "UltraChip UC81xx compatible display controller driver" default y - depends on DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED + depends on DT_HAS_ULTRACHIP_UC8175_ENABLED || DT_HAS_ULTRACHIP_UC8176_ENABLED || DT_HAS_ULTRACHIP_UC8179_ENABLED select SPI help Enable driver for UC81xx compatible controller. diff --git a/drivers/display/display_gc9x01x.c b/drivers/display/display_gc9x01x.c new file mode 100644 index 00000000000..1d432d3f355 --- /dev/null +++ b/drivers/display/display_gc9x01x.c @@ -0,0 +1,698 @@ +/** + * Copyright (c) 2023 Mr Beam Lasers GmbH. + * Copyright (c) 2023 Amrith Venkat Kesavamoorthi + * Copyright (c) 2023 Martin Kiepfer + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT galaxycore_gc9x01x + +#include "display_gc9x01x.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(display_gc9x01x, CONFIG_DISPLAY_LOG_LEVEL); + +/* Command/data GPIO level for commands. */ +#define GC9X01X_GPIO_LEVEL_CMD 0U + +/* Command/data GPIO level for data. */ +#define GC9X01X_GPIO_LEVEL_DATA 1U + +/* Maximum number of default init registers */ +#define GC9X01X_NUM_DEFAULT_INIT_REGS 12U + +/* Display data struct */ +struct gc9x01x_data { + uint8_t bytes_per_pixel; + enum display_pixel_format pixel_format; + enum display_orientation orientation; +}; + +/* Configuration data struct.*/ +struct gc9x01x_config { + struct spi_dt_spec spi; + struct gpio_dt_spec cmd_data; + struct gpio_dt_spec reset; + uint8_t pixel_format; + uint16_t orientation; + uint16_t x_resolution; + uint16_t y_resolution; + bool inversion; + const void *regs; +}; + +/* Initialization command data struct */ +struct gc9x01x_default_init_regs { + uint8_t cmd; + uint8_t len; + uint8_t data[GC9X01X_NUM_DEFAULT_INIT_REGS]; +}; + +/* + * Default initialization commands. There are a lot of undocumented commands + * within the manufacturer sample code, that are essential for proper operation of + * the display controller + */ +static const struct gc9x01x_default_init_regs default_init_regs[] = { + { + .cmd = 0xEBU, + .len = 1U, + .data = {0x14U}, + }, + { + .cmd = 0x84U, + .len = 1U, + .data = {0x40U}, + }, + { + .cmd = 0x85U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x86U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x87U, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x88U, + .len = 1U, + .data = {0x0AU}, + }, + { + .cmd = 0x89U, + .len = 1U, + .data = {0x21U}, + }, + { + .cmd = 0x8AU, + .len = 1U, + .data = {0x00U}, + }, + { + .cmd = 0x8BU, + .len = 1U, + .data = {0x80U}, + }, + { + .cmd = 0x8CU, + .len = 1U, + .data = {0x01U}, + }, + { + .cmd = 0x8DU, + .len = 1U, + .data = {0x01U}, + }, + { + .cmd = 0x8EU, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0x8FU, + .len = 1U, + .data = {0xFFU}, + }, + { + .cmd = 0xB6U, + .len = 2U, + .data = {0x00U, 0x20U}, + }, + { + .cmd = 0x90U, + .len = 4U, + .data = {0x08U, 0x08U, 0x08U, 0x08U}, + }, + { + .cmd = 0xBDU, + .len = 1U, + .data = {0x06U}, + }, + { + .cmd = 0xBCU, + .len = 1U, + .data = {0x00U}, + }, + { + .cmd = 0xFFU, + .len = 3U, + .data = {0x60U, 0x01U, 0x04U}, + }, + { + .cmd = 0xBEU, + .len = 1U, + .data = {0x11U}, + }, + { + .cmd = 0xE1U, + .len = 2U, + .data = {0x10U, 0x0EU}, + }, + { + .cmd = 0xDFU, + .len = 3U, + .data = {0x21U, 0x0CU, 0x02U}, + }, + { + .cmd = 0xEDU, + .len = 2U, + .data = {0x1BU, 0x0BU}, + }, + { + .cmd = 0xAEU, + .len = 1U, + .data = {0x77U}, + }, + { + .cmd = 0xCDU, + .len = 1U, + .data = {0x63U}, + }, + { + .cmd = 0x70U, + .len = 9U, + .data = {0x07U, 0x07U, 0x04U, 0x0EU, 0x0FU, 0x09U, 0x07U, 0x08U, 0x03U}, + }, + { + .cmd = 0x62U, + .len = 12U, + .data = {0x18U, 0x0DU, 0x71U, 0xEDU, 0x70U, 0x70U, 0x18U, 0x0FU, 0x71U, 0xEFU, + 0x70U, 0x70U}, + }, + { + .cmd = 0x63U, + .len = 12U, + .data = {0x18U, 0x11U, 0x71U, 0xF1U, 0x70U, 0x70U, 0x18U, 0x13U, 0x71U, 0xF3U, + 0x70U, 0x70U}, + }, + { + .cmd = 0x64U, + .len = 7U, + .data = {0x28U, 0x29U, 0xF1U, 0x01U, 0xF1U, 0x00U, 0x07U}, + }, + { + .cmd = 0x66U, + .len = 10U, + .data = {0x3CU, 0x00U, 0xCDU, 0x67U, 0x45U, 0x45U, 0x10U, 0x00U, 0x00U, 0x00U}, + }, + { + .cmd = 0x67U, + .len = 10U, + .data = {0x00U, 0x3CU, 0x00U, 0x00U, 0x00U, 0x01U, 0x54U, 0x10U, 0x32U, 0x98U}, + }, + { + .cmd = 0x74U, + .len = 7U, + .data = {0x10U, 0x85U, 0x80U, 0x00U, 0x00U, 0x4EU, 0x00U}, + }, + { + .cmd = 0x98U, + .len = 2U, + .data = {0x3EU, 0x07U}, + }, +}; + +static int gc9x01x_transmit(const struct device *dev, uint8_t cmd, const void *tx_data, + size_t tx_len) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + struct spi_buf tx_buf = {.buf = &cmd, .len = 1U}; + struct spi_buf_set tx_bufs = {.buffers = &tx_buf, .count = 1U}; + + ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_CMD); + if (ret < 0) { + return ret; + } + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + + /* send data (if any) */ + if (tx_data != NULL) { + tx_buf.buf = (void *)tx_data; + tx_buf.len = tx_len; + + ret = gpio_pin_set_dt(&config->cmd_data, GC9X01X_GPIO_LEVEL_DATA); + if (ret < 0) { + return ret; + } + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int gc9x01x_regs_init(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + const struct gc9x01x_regs *regs = config->regs; + int ret; + + /* Enable inter-command mode */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN1, NULL, 0); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INREGEN2, NULL, 0); + if (ret < 0) { + return ret; + } + + /* Apply default init sequence */ + for (int i = 0; (i < ARRAY_SIZE(default_init_regs)) && (ret == 0); i++) { + ret = gc9x01x_transmit(dev, default_init_regs[i].cmd, default_init_regs[i].data, + default_init_regs[i].len); + if (ret < 0) { + return ret; + } + } + + /* Apply generic configuration */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL2, regs->pwrctrl2, sizeof(regs->pwrctrl2)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL3, regs->pwrctrl3, sizeof(regs->pwrctrl3)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PWRCTRL4, regs->pwrctrl4, sizeof(regs->pwrctrl4)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA1, regs->gamma1, sizeof(regs->gamma1)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA2, regs->gamma2, sizeof(regs->gamma2)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA3, regs->gamma3, sizeof(regs->gamma3)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_GAMMA4, regs->gamma4, sizeof(regs->gamma4)); + if (ret < 0) { + return ret; + } + ret = gc9x01x_transmit(dev, GC9X01X_CMD_FRAMERATE, regs->framerate, + sizeof(regs->framerate)); + if (ret < 0) { + return ret; + } + + /* Enable Tearing line */ + ret = gc9x01x_transmit(dev, GC9X01X_CMD_TEON, NULL, 0); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int gc9x01x_exit_sleep(const struct device *dev) +{ + int ret; + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPOUT, NULL, 0); + if (ret < 0) { + return ret; + } + + /* + * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for + * any manufacturing defects. + * This is to allow time for the supply voltages and clock circuits stabilize + */ + k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30); + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int gc9x01x_enter_sleep(const struct device *dev) +{ + int ret; + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_SLPIN, NULL, 0); + if (ret < 0) { + return ret; + } + + /* + * Exit sleepmode and enable display. 30ms on top of the sleepout time to account for + * any manufacturing defects. + */ + k_msleep(GC9X01X_SLEEP_IN_OUT_DURATION_MS + 30); + + return 0; +} +#endif + +static int gc9x01x_hw_reset(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + + if (config->reset.port == NULL) { + return -ENODEV; + } + + gpio_pin_set_dt(&config->reset, 1U); + k_msleep(100); + gpio_pin_set_dt(&config->reset, 0U); + k_msleep(10); + + return 0; +} + +static int gc9x01x_display_blanking_off(const struct device *dev) +{ + LOG_DBG("Turning display blanking off"); + return gc9x01x_transmit(dev, GC9X01X_CMD_DISPON, NULL, 0); +} + +static int gc9x01x_display_blanking_on(const struct device *dev) +{ + LOG_DBG("Turning display blanking on"); + return gc9x01x_transmit(dev, GC9X01X_CMD_DISPOFF, NULL, 0); +} + +static int gc9x01x_set_pixel_format(const struct device *dev, + const enum display_pixel_format pixel_format) +{ + struct gc9x01x_data *data = dev->data; + int ret; + uint8_t tx_data; + uint8_t bytes_per_pixel; + + if (pixel_format == PIXEL_FORMAT_RGB_565) { + bytes_per_pixel = 2U; + tx_data = GC9X01X_PIXFMT_VAL_MCU_16_BIT | GC9X01X_PIXFMT_VAL_RGB_16_BIT; + } else if (pixel_format == PIXEL_FORMAT_RGB_888) { + bytes_per_pixel = 3U; + tx_data = GC9X01X_PIXFMT_VAL_MCU_18_BIT | GC9X01X_PIXFMT_VAL_RGB_18_BIT; + } else { + LOG_ERR("Unsupported pixel format"); + return -ENOTSUP; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_PIXFMT, &tx_data, 1U); + if (ret < 0) { + return ret; + } + + data->pixel_format = pixel_format; + data->bytes_per_pixel = bytes_per_pixel; + + return 0; +} + +static int gc9x01x_set_orientation(const struct device *dev, + const enum display_orientation orientation) +{ + struct gc9x01x_data *data = dev->data; + int ret; + uint8_t tx_data = GC9X01X_MADCTL_VAL_BGR; + + if (orientation == DISPLAY_ORIENTATION_NORMAL) { + /* works 0° - default */ + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_90) { + /* works CW 90° */ + tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MY; + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_180) { + /* works CW 180° */ + tx_data |= GC9X01X_MADCTL_VAL_MY | GC9X01X_MADCTL_VAL_MX | GC9X01X_MADCTL_VAL_MH; + } else if (orientation == DISPLAY_ORIENTATION_ROTATED_270) { + /* works CW 270° */ + tx_data |= GC9X01X_MADCTL_VAL_MV | GC9X01X_MADCTL_VAL_MX; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_MADCTL, &tx_data, 1U); + if (ret < 0) { + return ret; + } + + data->orientation = orientation; + + return 0; +} + +static int gc9x01x_configure(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + + /* Set all the required registers. */ + ret = gc9x01x_regs_init(dev); + if (ret < 0) { + return ret; + } + + /* Pixel format */ + ret = gc9x01x_set_pixel_format(dev, config->pixel_format); + if (ret < 0) { + return ret; + } + + /* Orientation */ + ret = gc9x01x_set_orientation(dev, config->orientation); + if (ret < 0) { + return ret; + } + + /* Display inversion mode. */ + if (config->inversion) { + ret = gc9x01x_transmit(dev, GC9X01X_CMD_INVON, NULL, 0); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int gc9x01x_init(const struct device *dev) +{ + const struct gc9x01x_config *config = dev->config; + int ret; + + if (!spi_is_ready_dt(&config->spi)) { + LOG_ERR("SPI device is not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&config->cmd_data)) { + LOG_ERR("Command/Data GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Could not configure command/data GPIO (%d)", ret); + return ret; + } + + if (config->reset.port != NULL) { + if (!device_is_ready(config->reset.port)) { + LOG_ERR("Reset GPIO device not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + } + + gc9x01x_hw_reset(dev); + + gc9x01x_display_blanking_on(dev); + + ret = gc9x01x_configure(dev); + if (ret < 0) { + LOG_ERR("Could not configure display (%d)", ret); + return ret; + } + + ret = gc9x01x_exit_sleep(dev); + if (ret < 0) { + LOG_ERR("Could not exit sleep mode (%d)", ret); + return ret; + } + + return 0; +} + +static int gc9x01x_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, + const uint16_t w, const uint16_t h) +{ + int ret; + uint16_t spi_data[2]; + + spi_data[0] = sys_cpu_to_be16(x); + spi_data[1] = sys_cpu_to_be16(x + w - 1U); + ret = gc9x01x_transmit(dev, GC9X01X_CMD_COLSET, &spi_data[0], 4U); + if (ret < 0) { + return ret; + } + + spi_data[0] = sys_cpu_to_be16(y); + spi_data[1] = sys_cpu_to_be16(y + h - 1U); + ret = gc9x01x_transmit(dev, GC9X01X_CMD_ROWSET, &spi_data[0], 4U); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int gc9x01x_write(const struct device *dev, const uint16_t x, const uint16_t y, + const struct display_buffer_descriptor *desc, const void *buf) +{ + const struct gc9x01x_config *config = dev->config; + struct gc9x01x_data *data = dev->data; + int ret; + const uint8_t *write_data_start = (const uint8_t *)buf; + struct spi_buf tx_buf; + struct spi_buf_set tx_bufs; + uint16_t write_cnt; + uint16_t nbr_of_writes; + uint16_t write_h; + + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); + __ASSERT((desc->pitch * data->bytes_per_pixel * desc->height) <= desc->buf_size, + "Input buffer to small"); + + LOG_DBG("Writing %dx%d (w,h) @ %dx%d (x,y)", desc->width, desc->height, x, y); + ret = gc9x01x_set_mem_area(dev, x, y, desc->width, desc->height); + if (ret < 0) { + return ret; + } + + if (desc->pitch > desc->width) { + write_h = 1U; + nbr_of_writes = desc->height; + } else { + write_h = desc->height; + nbr_of_writes = 1U; + } + + ret = gc9x01x_transmit(dev, GC9X01X_CMD_MEMWR, write_data_start, + desc->width * data->bytes_per_pixel * write_h); + if (ret < 0) { + return ret; + } + + tx_bufs.buffers = &tx_buf; + tx_bufs.count = 1U; + + write_data_start += desc->pitch * data->bytes_per_pixel; + for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { + tx_buf.buf = (void *)write_data_start; + tx_buf.len = desc->width * data->bytes_per_pixel * write_h; + + ret = spi_write_dt(&config->spi, &tx_bufs); + if (ret < 0) { + return ret; + } + + write_data_start += desc->pitch * data->bytes_per_pixel; + } + + return 0; +} + +static void gc9x01x_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + struct gc9x01x_data *data = dev->data; + const struct gc9x01x_config *config = dev->config; + + memset(capabilities, 0, sizeof(struct display_capabilities)); + + capabilities->supported_pixel_formats = PIXEL_FORMAT_RGB_565 | PIXEL_FORMAT_RGB_888; + capabilities->current_pixel_format = data->pixel_format; + + if (data->orientation == DISPLAY_ORIENTATION_NORMAL || + data->orientation == DISPLAY_ORIENTATION_ROTATED_180) { + capabilities->x_resolution = config->x_resolution; + capabilities->y_resolution = config->y_resolution; + } else { + capabilities->x_resolution = config->y_resolution; + capabilities->y_resolution = config->x_resolution; + } + + capabilities->current_orientation = data->orientation; +} + +#ifdef CONFIG_PM_DEVICE +static int gc9x01x_pm_action(const struct device *dev, enum pm_device_action action) +{ + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + ret = gc9x01x_exit_sleep(dev); + break; + case PM_DEVICE_ACTION_SUSPEND: + ret = gc9x01x_enter_sleep(dev); + break; + default: + ret = -ENOTSUP; + break; + } + + return ret; +} +#endif /* CONFIG_PM_DEVICE */ + +/* Device driver API*/ +static const struct display_driver_api gc9x01x_api = { + .blanking_on = gc9x01x_display_blanking_on, + .blanking_off = gc9x01x_display_blanking_off, + .write = gc9x01x_write, + .get_capabilities = gc9x01x_get_capabilities, + .set_pixel_format = gc9x01x_set_pixel_format, + .set_orientation = gc9x01x_set_orientation, +}; + +#define GC9X01X_INIT(inst) \ + GC9X01X_REGS_INIT(inst); \ + static const struct gc9x01x_config gc9x01x_config_##inst = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8), 0), \ + .cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \ + .pixel_format = DT_INST_PROP(inst, pixel_format), \ + .orientation = DT_INST_ENUM_IDX(inst, orientation), \ + .x_resolution = DT_INST_PROP(inst, width), \ + .y_resolution = DT_INST_PROP(inst, height), \ + .inversion = DT_INST_PROP(inst, display_inversion), \ + .regs = &gc9x01x_regs_##inst, \ + }; \ + static struct gc9x01x_data gc9x01x_data_##inst; \ + PM_DEVICE_DT_INST_DEFINE(inst, gc9x01x_pm_action); \ + DEVICE_DT_INST_DEFINE(inst, &gc9x01x_init, PM_DEVICE_DT_INST_GET(inst), \ + &gc9x01x_data_##inst, &gc9x01x_config_##inst, POST_KERNEL, \ + CONFIG_DISPLAY_INIT_PRIORITY, &gc9x01x_api); + +DT_INST_FOREACH_STATUS_OKAY(GC9X01X_INIT) diff --git a/drivers/display/display_gc9x01x.h b/drivers/display/display_gc9x01x.h new file mode 100644 index 00000000000..ff989dd44cf --- /dev/null +++ b/drivers/display/display_gc9x01x.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023 Mr Beam Lasers GmbH. + * Copyright (c) 2023 Amrith Venkat Kesavamoorthi + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ +#define ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ + +#include + +/* Command registers */ +#define GC9X01X_CMD_SLPIN 0x10U /* Enter Sleep Mode */ +#define GC9X01X_CMD_SLPOUT 0x11U /* Exit Sleep Mode */ +#define GC9X01X_CMD_PTLON 0x12U /* Partial Mode ON */ +#define GC9X01X_CMD_NORON 0x13U /* Normal Display Mode ON */ +#define GC9X01X_CMD_INVOFF 0x20U /* Display Inversion OFF */ +#define GC9X01X_CMD_INVON 0x21U /* Display Inversion ON */ +#define GC9X01X_CMD_DISPOFF 0x28U /* Display OFF */ +#define GC9X01X_CMD_DISPON 0x29U /* Display ON */ +#define GC9X01X_CMD_COLSET 0x2AU /* Column Address Set */ +#define GC9X01X_CMD_ROWSET 0x2BU /* Row Address Set */ +#define GC9X01X_CMD_MEMWR 0x2CU /* Memory Write */ +#define GC9X01X_CMD_PTLAR 0x30U /* Partial Area */ +#define GC9X01X_CMD_VSCRDEF 0x33U /* Vertical Scrolling Definition */ +#define GC9X01X_CMD_TEOFF 0x34U /* Tearing Effect Line OFF */ +#define GC9X01X_CMD_TEON 0x35U /* Tearing Effect Line ON */ +#define GC9X01X_CMD_MADCTL 0x36U /* Memory Access Control */ +#define GC9X01X_CMD_VSCRSADD 0x37U /* Vertical Scrolling Start Address */ +#define GC9X01X_CMD_PIXFMT 0x3AU /* Pixel Format Set */ +#define GC9X01X_CMD_DFUNCTR 0xB6U /* Display Function Control */ +#define GC9X01X_CMD_PWRCTRL1 0xC1U /* Power Control 1 */ +#define GC9X01X_CMD_PWRCTRL2 0xC3U /* Power Control 2 */ +#define GC9X01X_CMD_PWRCTRL3 0xC4U /* Power Control 3 */ +#define GC9X01X_CMD_PWRCTRL4 0xC9U /* Power Control 4 */ +#define GC9X01X_CMD_READID1 0xDAU /* Read ID 1 */ +#define GC9X01X_CMD_READID2 0xDBU /* Read ID 2 */ +#define GC9X01X_CMD_READID3 0xDCU /* Read ID 3 */ +#define GC9X01X_CMD_GAMMA1 0xF0U /* Gamma1 (negative polarity) */ +#define GC9X01X_CMD_GAMMA2 0xF1U /* Gamma2 */ +#define GC9X01X_CMD_GAMMA3 0xF2U /* Gamma3 (positive polarity) */ +#define GC9X01X_CMD_GAMMA4 0xF3U /* Gamma4 */ +#define GC9X01X_CMD_INREGEN1 0xFEU /* Inter Register Enable 1 */ +#define GC9X01X_CMD_INREGEN2 0xEFU /* Inter Register Enable 2 */ +#define GC9X01X_CMD_FRAMERATE 0xE8U /* Frame Rate Control */ + +/* GC9X01X_CMD_MADCTL register fields */ +#define GC9X01X_MADCTL_VAL_MY BIT(7U) +#define GC9X01X_MADCTL_VAL_MX BIT(6U) +#define GC9X01X_MADCTL_VAL_MV BIT(5U) +#define GC9X01X_MADCTL_VAL_ML BIT(4U) +#define GC9X01X_MADCTL_VAL_BGR BIT(3U) +#define GC9X01X_MADCTL_VAL_MH BIT(2U) + +/* GC9X01X_CMD_PIXFMT register fields */ +#define GC9X01X_PIXFMT_VAL_RGB_18_BIT 0x60U +#define GC9X01X_PIXFMT_VAL_RGB_16_BIT 0x50U +#define GC9X01X_PIXFMT_VAL_MCU_18_BIT 0x06U +#define GC9X01X_PIXFMT_VAL_MCU_16_BIT 0x05U + +/* Duration to enter/exit sleep mode (see 6.2.3 and 6.4.2 in datasheet) */ +#define GC9X01X_SLEEP_IN_OUT_DURATION_MS 120 + +/* GC9X01X registers to be intitialized */ +#define GC9X01X_CMD_PWRCTRL1_LEN 1U +#define GC9X01X_CMD_PWRCTRL2_LEN 1U +#define GC9X01X_CMD_PWRCTRL3_LEN 1U +#define GC9X01X_CMD_PWRCTRL4_LEN 1U +#define GC9X01X_CMD_GAMMA1_LEN 6U +#define GC9X01X_CMD_GAMMA2_LEN 6U +#define GC9X01X_CMD_GAMMA3_LEN 6U +#define GC9X01X_CMD_GAMMA4_LEN 6U +#define GC9X01X_CMD_FRAMERATE_LEN 1U + +struct gc9x01x_regs { + uint8_t pwrctrl1[GC9X01X_CMD_PWRCTRL1_LEN]; + uint8_t pwrctrl2[GC9X01X_CMD_PWRCTRL2_LEN]; + uint8_t pwrctrl3[GC9X01X_CMD_PWRCTRL3_LEN]; + uint8_t pwrctrl4[GC9X01X_CMD_PWRCTRL4_LEN]; + uint8_t gamma1[GC9X01X_CMD_GAMMA1_LEN]; + uint8_t gamma2[GC9X01X_CMD_GAMMA2_LEN]; + uint8_t gamma3[GC9X01X_CMD_GAMMA3_LEN]; + uint8_t gamma4[GC9X01X_CMD_GAMMA4_LEN]; + uint8_t framerate[GC9X01X_CMD_FRAMERATE_LEN]; +}; + +#define GC9X01X_REGS_INIT(inst) \ + static const struct gc9x01x_regs gc9x01x_regs_##inst = { \ + .pwrctrl1 = DT_INST_PROP(inst, pwrctrl1), \ + .pwrctrl2 = DT_INST_PROP(inst, pwrctrl2), \ + .pwrctrl3 = DT_INST_PROP(inst, pwrctrl3), \ + .pwrctrl4 = DT_INST_PROP(inst, pwrctrl4), \ + .gamma1 = DT_INST_PROP(inst, gamma1), \ + .gamma2 = DT_INST_PROP(inst, gamma2), \ + .gamma3 = DT_INST_PROP(inst, gamma3), \ + .gamma4 = DT_INST_PROP(inst, gamma4), \ + .framerate = DT_INST_PROP(inst, framerate), \ + }; + +#endif /* ZEPHYR_DRIVERS_DISPLAY_GC9X01X_H_ */ diff --git a/drivers/display/display_hx8394.c b/drivers/display/display_hx8394.c index d5fecfb4fe1..b14846ae343 100644 --- a/drivers/display/display_hx8394.c +++ b/drivers/display/display_hx8394.c @@ -415,21 +415,6 @@ static int hx8394_write(const struct device *dev, const uint16_t x, return 0; } -static int hx8394_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_WRN("Read not implemented"); - return -ENOTSUP; -} - -static void *hx8394_get_framebuffer(const struct device *dev) -{ - LOG_WRN("Direct framebuffer access not implemented"); - return NULL; -} - static int hx8394_blanking_off(const struct device *dev) { const struct hx8394_config *config = dev->config; @@ -452,20 +437,6 @@ static int hx8394_blanking_on(const struct device *dev) } } -static int hx8394_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int hx8394_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_WRN("Set contrast not implemented"); - return -ENOTSUP; -} - static int hx8394_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -526,10 +497,6 @@ static const struct display_driver_api hx8394_api = { .blanking_on = hx8394_blanking_on, .blanking_off = hx8394_blanking_off, .write = hx8394_write, - .read = hx8394_read, - .get_framebuffer = hx8394_get_framebuffer, - .set_brightness = hx8394_set_brightness, - .set_contrast = hx8394_set_contrast, .get_capabilities = hx8394_get_capabilities, .set_pixel_format = hx8394_set_pixel_format, .set_orientation = hx8394_set_orientation, diff --git a/drivers/display/display_ili9xxx.c b/drivers/display/display_ili9xxx.c index 2df7c60ea21..e07e26c274b 100644 --- a/drivers/display/display_ili9xxx.c +++ b/drivers/display/display_ili9xxx.c @@ -26,33 +26,8 @@ int ili9xxx_transmit(const struct device *dev, uint8_t cmd, const void *tx_data, { const struct ili9xxx_config *config = dev->config; - int r; - struct spi_buf tx_buf; - struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1U }; - - /* send command */ - tx_buf.buf = &cmd; - tx_buf.len = 1U; - - gpio_pin_set_dt(&config->cmd_data, ILI9XXX_CMD); - r = spi_write_dt(&config->spi, &tx_bufs); - if (r < 0) { - return r; - } - - /* send data (if any) */ - if (tx_data != NULL) { - tx_buf.buf = (void *)tx_data; - tx_buf.len = tx_len; - - gpio_pin_set_dt(&config->cmd_data, ILI9XXX_DATA); - r = spi_write_dt(&config->spi, &tx_bufs); - if (r < 0) { - return r; - } - } - - return 0; + return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config, + cmd, tx_data, tx_len); } static int ili9xxx_exit_sleep(const struct device *dev) @@ -73,14 +48,9 @@ static void ili9xxx_hw_reset(const struct device *dev) { const struct ili9xxx_config *config = dev->config; - if (config->reset.port == NULL) { + if (mipi_dbi_reset(config->mipi_dev, ILI9XXX_RESET_PULSE_TIME) < 0) { return; - } - - gpio_pin_set_dt(&config->reset, 1); - k_sleep(K_MSEC(ILI9XXX_RESET_PULSE_TIME)); - gpio_pin_set_dt(&config->reset, 0); - + }; k_sleep(K_MSEC(ILI9XXX_RESET_WAIT_TIME)); } @@ -115,11 +85,10 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x, { const struct ili9xxx_config *config = dev->config; struct ili9xxx_data *data = dev->data; + struct display_buffer_descriptor mipi_desc; int r; const uint8_t *write_data_start = (const uint8_t *)buf; - struct spi_buf tx_buf; - struct spi_buf_set tx_bufs; uint16_t write_cnt; uint16_t nbr_of_writes; uint16_t write_h; @@ -139,26 +108,30 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x, if (desc->pitch > desc->width) { write_h = 1U; nbr_of_writes = desc->height; + mipi_desc.height = 1; + mipi_desc.buf_size = desc->pitch * data->bytes_per_pixel; } else { write_h = desc->height; + mipi_desc.height = desc->height; + mipi_desc.buf_size = desc->width * data->bytes_per_pixel * write_h; nbr_of_writes = 1U; } - r = ili9xxx_transmit(dev, ILI9XXX_RAMWR, write_data_start, - desc->width * data->bytes_per_pixel * write_h); + mipi_desc.width = desc->width; + /* Per MIPI API, pitch must always match width */ + mipi_desc.pitch = desc->width; + + r = ili9xxx_transmit(dev, ILI9XXX_RAMWR, NULL, 0); if (r < 0) { return r; } - tx_bufs.buffers = &tx_buf; - tx_bufs.count = 1; - - write_data_start += desc->pitch * data->bytes_per_pixel; - for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) { - tx_buf.buf = (void *)write_data_start; - tx_buf.len = desc->width * data->bytes_per_pixel * write_h; - - r = spi_write_dt(&config->spi, &tx_bufs); + for (write_cnt = 0U; write_cnt < nbr_of_writes; ++write_cnt) { + r = mipi_dbi_write_display(config->mipi_dev, + &config->dbi_config, + write_data_start, + &mipi_desc, + data->pixel_format); if (r < 0) { return r; } @@ -363,35 +336,11 @@ static int ili9xxx_init(const struct device *dev) int r; - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI device is not ready"); + if (!device_is_ready(config->mipi_dev)) { + LOG_ERR("MIPI DBI device is not ready"); return -ENODEV; } - if (!gpio_is_ready_dt(&config->cmd_data)) { - LOG_ERR("Command/Data GPIO device not ready"); - return -ENODEV; - } - - r = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); - if (r < 0) { - LOG_ERR("Could not configure command/data GPIO (%d)", r); - return r; - } - - if (config->reset.port != NULL) { - if (!gpio_is_ready_dt(&config->reset)) { - LOG_ERR("Reset GPIO device not ready"); - return -ENODEV; - } - - r = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); - if (r < 0) { - LOG_ERR("Could not configure reset GPIO (%d)", r); - return r; - } - } - ili9xxx_hw_reset(dev); r = ili9xxx_transmit(dev, ILI9XXX_SWRESET, NULL, 0); @@ -463,13 +412,15 @@ static const struct ili9xxx_quirks ili9488_quirks = { \ static const struct ili9xxx_config ili9xxx_config_##n = { \ .quirks = &ili##t##_quirks, \ - .spi = SPI_DT_SPEC_GET(INST_DT_ILI9XXX(n, t), \ - SPI_OP_MODE_MASTER | SPI_WORD_SET(8), \ - 0), \ - .cmd_data = GPIO_DT_SPEC_GET(INST_DT_ILI9XXX(n, t), \ - cmd_data_gpios), \ - .reset = GPIO_DT_SPEC_GET_OR(INST_DT_ILI9XXX(n, t), \ - reset_gpios, {0}), \ + .mipi_dev = DEVICE_DT_GET(DT_PARENT(INST_DT_ILI9XXX(n, t))), \ + .dbi_config = { \ + .mode = MIPI_DBI_MODE_SPI_4WIRE, \ + .config = MIPI_DBI_SPI_CONFIG_DT( \ + INST_DT_ILI9XXX(n, t), \ + SPI_OP_MODE_MASTER | \ + SPI_WORD_SET(8), \ + 0), \ + }, \ .pixel_format = DT_PROP(INST_DT_ILI9XXX(n, t), pixel_format), \ .rotation = DT_PROP(INST_DT_ILI9XXX(n, t), rotation), \ .x_resolution = ILI##t##_X_RES, \ diff --git a/drivers/display/display_ili9xxx.h b/drivers/display/display_ili9xxx.h index 2cd6da98088..ddf8254224e 100644 --- a/drivers/display/display_ili9xxx.h +++ b/drivers/display/display_ili9xxx.h @@ -9,8 +9,7 @@ #ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9XXX_H_ #define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ILI9XXX_H_ -#include -#include +#include #include /* Commands/registers. */ @@ -65,10 +64,8 @@ struct ili9xxx_quirks { struct ili9xxx_config { const struct ili9xxx_quirks *quirks; - - struct spi_dt_spec spi; - struct gpio_dt_spec cmd_data; - struct gpio_dt_spec reset; + const struct device *mipi_dev; + struct mipi_dbi_config dbi_config; uint8_t pixel_format; uint16_t rotation; uint16_t x_resolution; diff --git a/drivers/display/display_intel_multibootfb.c b/drivers/display/display_intel_multibootfb.c index fc2ef3f32f5..e2b93b60940 100644 --- a/drivers/display/display_intel_multibootfb.c +++ b/drivers/display/display_intel_multibootfb.c @@ -26,33 +26,6 @@ struct framebuf_dev_data { uint32_t pitch; }; -static int framebuf_blanking_on(const struct device *dev) -{ - return -ENOTSUP; -} - -static int framebuf_blanking_off(const struct device *dev) -{ - return -ENOTSUP; -} - -static void *framebuf_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int framebuf_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int framebuf_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static int framebuf_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -133,13 +106,8 @@ static int framebuf_read(const struct device *dev, const uint16_t x, } const struct display_driver_api framebuf_display_api = { - .blanking_on = framebuf_blanking_on, - .blanking_off = framebuf_blanking_off, .write = framebuf_write, .read = framebuf_read, - .get_framebuffer = framebuf_get_framebuffer, - .set_brightness = framebuf_set_brightness, - .set_contrast = framebuf_set_contrast, .get_capabilities = framebuf_get_capabilities, .set_pixel_format = framebuf_set_pixel_format, .set_orientation = framebuf_set_orientation diff --git a/drivers/display/display_max7219.c b/drivers/display/display_max7219.c index 6613e4c5e47..f3ccc52c9d4 100644 --- a/drivers/display/display_max7219.c +++ b/drivers/display/display_max7219.c @@ -139,20 +139,6 @@ static inline void skip_pixel(uint8_t *mask, uint8_t *data, const uint8_t **buf, } } -static int max7219_blanking_on(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - -static int max7219_blanking_off(const struct device *dev) -{ - ARG_UNUSED(dev); - - return -ENOTSUP; -} - static int max7219_write(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, const void *buf) { @@ -213,25 +199,6 @@ static int max7219_write(const struct device *dev, const uint16_t x, const uint1 return 0; } -static int max7219_read(const struct device *dev, const uint16_t x, const uint16_t y, - const struct display_buffer_descriptor *desc, void *buf) -{ - ARG_UNUSED(dev); - ARG_UNUSED(x); - ARG_UNUSED(y); - ARG_UNUSED(desc); - ARG_UNUSED(buf); - - return -ENOTSUP; -} - -static void *max7219_get_framebuffer(const struct device *dev) -{ - ARG_UNUSED(dev); - - return NULL; -} - static int max7219_set_brightness(const struct device *dev, const uint8_t brightness) { int ret; @@ -249,14 +216,6 @@ static int max7219_set_brightness(const struct device *dev, const uint8_t bright return 0; } -static int max7219_set_contrast(const struct device *dev, const uint8_t contrast) -{ - ARG_UNUSED(dev); - ARG_UNUSED(contrast); - - return -ENOTSUP; -} - static int max7219_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -296,13 +255,8 @@ static void max7219_get_capabilities(const struct device *dev, struct display_ca } static const struct display_driver_api max7219_api = { - .blanking_on = max7219_blanking_on, - .blanking_off = max7219_blanking_off, .write = max7219_write, - .read = max7219_read, - .get_framebuffer = max7219_get_framebuffer, .set_brightness = max7219_set_brightness, - .set_contrast = max7219_set_contrast, .get_capabilities = max7219_get_capabilities, .set_pixel_format = max7219_set_pixel_format, .set_orientation = max7219_set_orientation, diff --git a/drivers/display/display_mcux_elcdif.c b/drivers/display/display_mcux_elcdif.c index 830bc3e9a0c..304638011f1 100644 --- a/drivers/display/display_mcux_elcdif.c +++ b/drivers/display/display_mcux_elcdif.c @@ -211,27 +211,6 @@ static int mcux_elcdif_write(const struct device *dev, const uint16_t x, return ret; } -static int mcux_elcdif_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_ERR("Read not implemented"); - return -ENOTSUP; -} - -static void *mcux_elcdif_get_framebuffer(const struct device *dev) -{ - /* - * Direct FB access is not available. If the user wants to set - * the framebuffer directly, they must provide a buffer to - * `display_write` equal in size to the connected display, - * with coordinates [0,0] - */ - LOG_ERR("Direct framebuffer access not available"); - return NULL; -} - static int mcux_elcdif_display_blanking_off(const struct device *dev) { const struct mcux_elcdif_config *config = dev->config; @@ -246,20 +225,6 @@ static int mcux_elcdif_display_blanking_on(const struct device *dev) return gpio_pin_set_dt(&config->backlight_gpio, 0); } -static int mcux_elcdif_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int mcux_elcdif_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int mcux_elcdif_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) @@ -368,10 +333,6 @@ static const struct display_driver_api mcux_elcdif_api = { .blanking_on = mcux_elcdif_display_blanking_on, .blanking_off = mcux_elcdif_display_blanking_off, .write = mcux_elcdif_write, - .read = mcux_elcdif_read, - .get_framebuffer = mcux_elcdif_get_framebuffer, - .set_brightness = mcux_elcdif_set_brightness, - .set_contrast = mcux_elcdif_set_contrast, .get_capabilities = mcux_elcdif_get_capabilities, .set_pixel_format = mcux_elcdif_set_pixel_format, .set_orientation = mcux_elcdif_set_orientation, diff --git a/drivers/display/display_nrf_led_matrix.c b/drivers/display/display_nrf_led_matrix.c index dd36126a7ce..d88bc760e76 100644 --- a/drivers/display/display_nrf_led_matrix.c +++ b/drivers/display/display_nrf_led_matrix.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #ifdef PWM_PRESENT #include @@ -89,6 +90,8 @@ struct display_drv_config { NRF_TIMER_Type *timer; #if USE_PWM NRF_PWM_Type *pwm; +#else + nrfx_gpiote_t gpiote; #endif uint8_t rows[ROW_COUNT]; uint8_t cols[COL_COUNT]; @@ -188,12 +191,6 @@ static int api_set_brightness(const struct device *dev, return 0; } -static int api_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static int api_set_pixel_format(const struct device *dev, const enum display_pixel_format format) { @@ -279,22 +276,12 @@ static int api_write(const struct device *dev, return 0; } -static int api_read(const struct device *dev, - const uint16_t x, const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - const struct display_driver_api driver_api = { .blanking_on = api_blanking_on, .blanking_off = api_blanking_off, .write = api_write, - .read = api_read, .get_framebuffer = api_get_framebuffer, .set_brightness = api_set_brightness, - .set_contrast = api_set_contrast, .get_capabilities = api_get_capabilities, .set_pixel_format = api_set_pixel_format, .set_orientation = api_set_orientation, @@ -340,7 +327,7 @@ static void prepare_pixel_pulse(const struct device *dev, /* First timer channel is used for timing the period of pulses. */ nrf_timer_cc_set(dev_config->timer, 1 + channel_idx, pulse); - NRF_GPIOTE->CONFIG[dev_data->gpiote_ch[channel_idx]] = gpiote_cfg; + dev_config->gpiote.p_reg->CONFIG[dev_data->gpiote_ch[channel_idx]] = gpiote_cfg; #endif /* USE_PWM */ } @@ -370,7 +357,7 @@ static void timer_irq_handler(void *arg) } #else for (int i = 0; i < GROUP_SIZE; ++i) { - NRF_GPIOTE->CONFIG[dev_data->gpiote_ch[i]] = 0; + dev_config->gpiote.p_reg->CONFIG[dev_data->gpiote_ch[i]] = 0; } #endif @@ -466,7 +453,7 @@ static int instance_init(const struct device *dev) return -ENOMEM; } - err = nrfx_gpiote_channel_alloc(gpiote_ch); + err = nrfx_gpiote_channel_alloc(&dev_config->gpiote, gpiote_ch); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate GPIOTE channel."); /* Do not bother with freeing resources allocated @@ -479,7 +466,7 @@ static int instance_init(const struct device *dev) nrf_ppi_channel_endpoint_setup(NRF_PPI, ppi_ch, nrf_timer_event_address_get(dev_config->timer, nrf_timer_compare_event_get(1 + i)), - nrf_gpiote_event_address_get(NRF_GPIOTE, + nrf_gpiote_event_address_get(dev_config->gpiote.p_reg, nrf_gpiote_out_task_get(*gpiote_ch))); nrf_ppi_channel_enable(NRF_PPI, ppi_ch); } @@ -530,6 +517,14 @@ static struct display_drv_data instance_data = { .blanking = true, }; +#if !USE_PWM +#define CHECK_GPIOTE_INST(node_id, prop, idx) \ + BUILD_ASSERT(NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, idx) == \ + NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0), \ + "All column GPIOs must use the same GPIOTE instance"); +DT_FOREACH_PROP_ELEM(MATRIX_NODE, col_gpios, CHECK_GPIOTE_INST) +#endif + #define GET_PIN_INFO(node_id, pha, idx) \ (DT_GPIO_PIN_BY_IDX(node_id, pha, idx) | \ (DT_PROP_BY_PHANDLE_IDX(node_id, pha, idx, port) << 5) | \ @@ -546,6 +541,9 @@ static const struct display_drv_config instance_config = { .timer = (NRF_TIMER_Type *)DT_REG_ADDR(TIMER_NODE), #if USE_PWM .pwm = (NRF_PWM_Type *)DT_REG_ADDR(PWM_NODE), +#else + .gpiote = NRFX_GPIOTE_INSTANCE( + NRF_DT_GPIOTE_INST_BY_IDX(MATRIX_NODE, col_gpios, 0)), #endif .rows = { DT_FOREACH_PROP_ELEM(MATRIX_NODE, row_gpios, GET_PIN_INFO) }, .cols = { DT_FOREACH_PROP_ELEM(MATRIX_NODE, col_gpios, GET_PIN_INFO) }, diff --git a/drivers/display/display_otm8009a.c b/drivers/display/display_otm8009a.c index 2463b431144..5f00ac3a13c 100644 --- a/drivers/display/display_otm8009a.c +++ b/drivers/display/display_otm8009a.c @@ -324,7 +324,7 @@ static int otm8009a_configure(const struct device *dev) /* not documented */ buf[0] = 0x00; - ret = otm8009a_mcs_write(dev, OTM8009A_MCS_NO_DOC2, buf, 3); + ret = otm8009a_mcs_write(dev, OTM8009A_MCS_NO_DOC2, buf, 1); if (ret < 0) { return ret; } @@ -586,27 +586,11 @@ static int otm8009a_write(const struct device *dev, uint16_t x, uint16_t y, return -ENOTSUP; } -static int otm8009a_read(const struct device *dev, uint16_t x, uint16_t y, - const struct display_buffer_descriptor *desc, void *buf) -{ - return -ENOTSUP; -} - -static void *otm8009a_get_framebuffer(const struct device *dev) -{ - return NULL; -} - static int otm8009a_set_brightness(const struct device *dev, uint8_t brightness) { return otm8009a_dcs_write(dev, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &brightness, 1); } -static int otm8009a_set_contrast(const struct device *dev, uint8_t contrast) -{ - return -ENOTSUP; -} - static void otm8009a_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -621,29 +605,12 @@ static void otm8009a_get_capabilities(const struct device *dev, capabilities->current_orientation = data->orientation; } -static int otm8009a_set_pixel_format(const struct device *dev, - enum display_pixel_format pixel_format) -{ - return -ENOTSUP; -} - -static int otm8009a_set_orientation(const struct device *dev, - enum display_orientation orientation) -{ - return -ENOTSUP; -} - static const struct display_driver_api otm8009a_api = { .blanking_on = otm8009a_blanking_on, .blanking_off = otm8009a_blanking_off, .write = otm8009a_write, - .read = otm8009a_read, - .get_framebuffer = otm8009a_get_framebuffer, .set_brightness = otm8009a_set_brightness, - .set_contrast = otm8009a_set_contrast, .get_capabilities = otm8009a_get_capabilities, - .set_pixel_format = otm8009a_set_pixel_format, - .set_orientation = otm8009a_set_orientation, }; static int otm8009a_init(const struct device *dev) diff --git a/drivers/display/display_rm67162.c b/drivers/display/display_rm67162.c index 5516e57789d..e63a4461810 100644 --- a/drivers/display/display_rm67162.c +++ b/drivers/display/display_rm67162.c @@ -434,18 +434,14 @@ static int rm67162_write(const struct device *dev, const uint16_t x, * give to the TE semaphore) before sending the frame */ if (config->te_gpio.port != NULL) { - if (IS_ENABLED(CONFIG_PM)) { - /* Block sleep state until next TE interrupt - * so we can send frame during that interval - */ - pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + /* Block sleep state until next TE interrupt so we can send + * frame during that interval + */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); k_sem_take(&data->te_sem, K_FOREVER); - if (IS_ENABLED(CONFIG_PM)) { - pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, - PM_ALL_SUBSTATES); - } + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, + PM_ALL_SUBSTATES); } src = buf; first_cmd = true; @@ -516,20 +512,6 @@ static int rm67162_blanking_on(const struct device *dev) } } -static int rm67162_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int rm67162_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int rm67162_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -599,8 +581,6 @@ static const struct display_driver_api rm67162_api = { .blanking_off = rm67162_blanking_off, .get_capabilities = rm67162_get_capabilities, .write = rm67162_write, - .set_brightness = rm67162_set_brightness, - .set_contrast = rm67162_set_contrast, .set_pixel_format = rm67162_set_pixel_format, .set_orientation = rm67162_set_orientation, }; diff --git a/drivers/display/display_rm68200.c b/drivers/display/display_rm68200.c index a89e0d0201a..7048790bdf3 100644 --- a/drivers/display/display_rm68200.c +++ b/drivers/display/display_rm68200.c @@ -102,21 +102,6 @@ static int rm68200_write(const struct device *dev, const uint16_t x, return 0; } -static int rm68200_read(const struct device *dev, const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - LOG_ERR("Read not implemented"); - return -ENOTSUP; -} - -static void *rm68200_get_framebuffer(const struct device *dev) -{ - LOG_ERR("Direct framebuffer access not implemented"); - return NULL; -} - static int rm68200_blanking_off(const struct device *dev) { const struct rm68200_config *config = dev->config; @@ -139,20 +124,6 @@ static int rm68200_blanking_on(const struct device *dev) } } -static int rm68200_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - LOG_WRN("Set brightness not implemented"); - return -ENOTSUP; -} - -static int rm68200_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - LOG_ERR("Set contrast not implemented"); - return -ENOTSUP; -} - static int rm68200_set_pixel_format(const struct device *dev, const enum display_pixel_format pixel_format) { @@ -192,10 +163,6 @@ static const struct display_driver_api rm68200_api = { .blanking_on = rm68200_blanking_on, .blanking_off = rm68200_blanking_off, .write = rm68200_write, - .read = rm68200_read, - .get_framebuffer = rm68200_get_framebuffer, - .set_brightness = rm68200_set_brightness, - .set_contrast = rm68200_set_contrast, .get_capabilities = rm68200_get_capabilities, .set_pixel_format = rm68200_set_pixel_format, .set_orientation = rm68200_set_orientation, diff --git a/drivers/display/display_sdl.c b/drivers/display/display_sdl.c index 2a457249ede..f21288d1b0f 100644 --- a/drivers/display/display_sdl.c +++ b/drivers/display/display_sdl.c @@ -10,14 +10,18 @@ #include #include +#include #include #include #include "display_sdl_bottom.h" +#include "cmdline.h" #define LOG_LEVEL CONFIG_DISPLAY_LOG_LEVEL #include LOG_MODULE_REGISTER(display_sdl); +static uint32_t sdl_display_zoom_pct; + struct sdl_display_config { uint16_t height; uint16_t width; @@ -26,18 +30,33 @@ struct sdl_display_config { struct sdl_display_data { void *window; void *renderer; + void *mutex; void *texture; + void *read_texture; bool display_on; enum display_pixel_format current_pixel_format; uint8_t *buf; + uint8_t *read_buf; }; +static inline uint32_t mono_pixel_order(uint32_t order) +{ + if (IS_ENABLED(CONFIG_SDL_DISPLAY_MONO_MSB_FIRST)) { + return BIT(7 - order); + } else { + return BIT(order); + } +} + static int sdl_display_init(const struct device *dev) { const struct sdl_display_config *config = dev->config; struct sdl_display_data *disp_data = dev->data; + bool use_accelerator = true; LOG_DBG("Initializing display driver"); + IF_DISABLED(CONFIG_SDL_DISPLAY_USE_HARDWARE_ACCELERATOR, (use_accelerator = false)); + disp_data->current_pixel_format = #if defined(CONFIG_SDL_DISPLAY_DEFAULT_PIXEL_FORMAT_RGB_888) PIXEL_FORMAT_RGB_888 @@ -54,8 +73,14 @@ static int sdl_display_init(const struct device *dev) #endif /* SDL_DISPLAY_DEFAULT_PIXEL_FORMAT */ ; - int rc = sdl_display_init_bottom(config->height, config->width, &disp_data->window, - &disp_data->renderer, &disp_data->texture); + if (sdl_display_zoom_pct == UINT32_MAX) { + sdl_display_zoom_pct = CONFIG_SDL_DISPLAY_ZOOM_PCT; + } + + int rc = sdl_display_init_bottom(config->height, config->width, sdl_display_zoom_pct, + use_accelerator, &disp_data->window, &disp_data->renderer, + &disp_data->mutex, &disp_data->texture, + &disp_data->read_texture); if (rc != 0) { LOG_ERR("Failed to create SDL display"); @@ -179,7 +204,7 @@ static void sdl_display_write_mono(uint8_t *disp_buf, ((tile_idx * desc->pitch) + w_idx); disp_buf_start = disp_buf; for (h_idx = 0U; h_idx < 8; ++h_idx) { - if ((*byte_ptr & BIT(7-h_idx)) != 0U) { + if ((*byte_ptr & mono_pixel_order(h_idx)) != 0U) { pixel = one_color; } else { pixel = (~one_color) & 0x00FFFFFF; @@ -236,33 +261,166 @@ static int sdl_display_write(const struct device *dev, const uint16_t x, } sdl_display_write_bottom(desc->height, desc->width, x, y, - disp_data->renderer, disp_data->texture, + disp_data->renderer, disp_data->mutex, disp_data->texture, disp_data->buf, disp_data->display_on); return 0; } +static void sdl_display_read_argb8888(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + __ASSERT((desc->pitch * 4U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + memcpy(buf, read_buf, desc->pitch * 4U * desc->height); +} + +static void sdl_display_read_rgb888(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint8_t *buf8; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf8 = ((uint8_t *)buf) + desc->pitch * 3U * h_idx; + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + *buf8 = (*pix_ptr & 0xFF0000) >> 16; + buf8 += 1; + *buf8 = (*pix_ptr & 0xFF00) >> 8; + buf8 += 1; + *buf8 = (*pix_ptr & 0xFF); + buf8 += 1; + } + } +} + +static void sdl_display_read_rgb565(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint16_t pixel; + uint16_t *buf16; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + pixel = (*pix_ptr & 0xF80000) >> 8; + pixel |= (*pix_ptr & 0x00FC00) >> 5; + pixel |= (*pix_ptr & 0x0000F8) >> 3; + *buf16 = sys_be16_to_cpu(pixel); + buf16 += 1; + } + } +} + +static void sdl_display_read_bgr565(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf) +{ + uint32_t w_idx; + uint32_t h_idx; + uint16_t pixel; + uint16_t *buf16; + const uint32_t *pix_ptr; + + __ASSERT((desc->pitch * 2U * desc->height) <= desc->buf_size, "Read buffer is too small"); + + for (h_idx = 0U; h_idx < desc->height; ++h_idx) { + buf16 = (void *)(((uint8_t *)buf) + desc->pitch * 2U * h_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + pix_ptr = (const uint32_t *)read_buf + ((h_idx * desc->pitch) + w_idx); + pixel = (*pix_ptr & 0xF80000) >> 8; + pixel |= (*pix_ptr & 0x00FC00) >> 5; + pixel |= (*pix_ptr & 0x0000F8) >> 3; + *buf16 = pixel; + buf16 += 1; + } + } +} + +static void sdl_display_read_mono(const uint8_t *read_buf, + const struct display_buffer_descriptor *desc, void *buf, + const bool one_is_black) +{ + uint32_t w_idx; + uint32_t h_idx; + uint32_t tile_idx; + uint8_t tile; + const uint32_t *pix_ptr; + uint8_t *buf8; + + __ASSERT((desc->pitch * desc->height) <= (desc->buf_size * 8U), "Read buffer is too small"); + __ASSERT((desc->height % 8U) == 0U, "Read buffer height not aligned per 8 pixels"); + + for (tile_idx = 0U; tile_idx < (desc->height / 8U); ++tile_idx) { + buf8 = (void *)(((uint8_t *)buf) + desc->pitch * tile_idx); + + for (w_idx = 0U; w_idx < desc->width; ++w_idx) { + tile = 0; + + for (h_idx = 0U; h_idx < 8; ++h_idx) { + pix_ptr = (const uint32_t *)read_buf + + ((tile_idx * 8 + h_idx) * desc->pitch + w_idx); + if ((*pix_ptr)) { + tile |= mono_pixel_order(h_idx); + } + } + *buf8 = one_is_black ? ~tile : tile; + buf8 += 1; + } + } +} + static int sdl_display_read(const struct device *dev, const uint16_t x, const uint16_t y, const struct display_buffer_descriptor *desc, void *buf) { struct sdl_display_data *disp_data = dev->data; + int err; LOG_DBG("Reading %dx%d (w,h) bitmap @ %dx%d (x,y)", desc->width, desc->height, x, y); - __ASSERT(desc->width <= desc->pitch, "Pitch is smaller then width"); - __ASSERT((desc->pitch * 3U * desc->height) <= desc->buf_size, - "Input buffer to small"); + __ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width"); - return sdl_display_read_bottom(desc->height, desc->width, x, y, - disp_data->renderer, buf, desc->pitch); -} + memset(disp_data->read_buf, 0, desc->pitch * desc->height * 4); -static void *sdl_display_get_framebuffer(const struct device *dev) -{ - return NULL; + err = sdl_display_read_bottom(desc->height, desc->width, x, y, disp_data->renderer, + disp_data->read_buf, desc->pitch, disp_data->mutex, + disp_data->texture, disp_data->read_texture); + + if (err) { + return err; + } + + if (disp_data->current_pixel_format == PIXEL_FORMAT_ARGB_8888) { + sdl_display_read_argb8888(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_888) { + sdl_display_read_rgb888(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO10) { + sdl_display_read_mono(disp_data->read_buf, desc, buf, true); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_MONO01) { + sdl_display_read_mono(disp_data->read_buf, desc, buf, false); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_RGB_565) { + sdl_display_read_rgb565(disp_data->read_buf, desc, buf); + } else if (disp_data->current_pixel_format == PIXEL_FORMAT_BGR_565) { + sdl_display_read_bgr565(disp_data->read_buf, desc, buf); + } + + return 0; } static int sdl_display_blanking_off(const struct device *dev) @@ -290,18 +448,6 @@ static int sdl_display_blanking_on(const struct device *dev) return 0; } -static int sdl_display_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int sdl_display_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void sdl_display_get_capabilities( const struct device *dev, struct display_capabilities *capabilities) { @@ -319,7 +465,7 @@ static void sdl_display_get_capabilities( PIXEL_FORMAT_BGR_565; capabilities->current_pixel_format = disp_data->current_pixel_format; capabilities->screen_info = SCREEN_INFO_MONO_VTILED | - SCREEN_INFO_MONO_MSB_FIRST; + (IS_ENABLED(CONFIG_SDL_DISPLAY_MONO_MSB_FIRST) ? SCREEN_INFO_MONO_MSB_FIRST : 0); } static int sdl_display_set_pixel_format(const struct device *dev, @@ -344,7 +490,8 @@ static int sdl_display_set_pixel_format(const struct device *dev, static void sdl_display_cleanup(struct sdl_display_data *disp_data) { - sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->texture); + sdl_display_cleanup_bottom(&disp_data->window, &disp_data->renderer, &disp_data->mutex, + &disp_data->texture, &disp_data->read_texture); } static const struct display_driver_api sdl_display_api = { @@ -352,9 +499,6 @@ static const struct display_driver_api sdl_display_api = { .blanking_off = sdl_display_blanking_off, .write = sdl_display_write, .read = sdl_display_read, - .get_framebuffer = sdl_display_get_framebuffer, - .set_brightness = sdl_display_set_brightness, - .set_contrast = sdl_display_set_contrast, .get_capabilities = sdl_display_get_capabilities, .set_pixel_format = sdl_display_set_pixel_format, }; @@ -367,8 +511,11 @@ static const struct display_driver_api sdl_display_api = { \ static uint8_t sdl_buf_##n[4 * DT_INST_PROP(n, height) \ * DT_INST_PROP(n, width)]; \ + static uint8_t sdl_read_buf_##n[4 * DT_INST_PROP(n, height) \ + * DT_INST_PROP(n, width)]; \ static struct sdl_display_data sdl_data_##n = { \ .buf = sdl_buf_##n, \ + .read_buf = sdl_read_buf_##n, \ }; \ \ DEVICE_DT_INST_DEFINE(n, &sdl_display_init, NULL, \ @@ -386,3 +533,22 @@ static const struct display_driver_api sdl_display_api = { NATIVE_TASK(sdl_display_cleanup_##n, ON_EXIT, 1); DT_INST_FOREACH_STATUS_OKAY(DISPLAY_SDL_DEFINE) + +static void display_sdl_native_posix_options(void) +{ + static struct args_struct_t sdl_display_options[] = { + { .option = "display_zoom_pct", + .name = "pct", + .type = 'u', + .dest = (void *)&sdl_display_zoom_pct, + .descript = "Display zoom percentage (100 == 1:1 scale), " + "by default " STRINGIFY(CONFIG_SDL_DISPLAY_ZOOM_PCT) + " = CONFIG_SDL_DISPLAY_ZOOM_PCT" + }, + ARG_TABLE_ENDMARKER + }; + + native_add_command_line_opts(sdl_display_options); +} + +NATIVE_TASK(display_sdl_native_posix_options, PRE_BOOT_1, 1); diff --git a/drivers/display/display_sdl_bottom.c b/drivers/display/display_sdl_bottom.c index a7ad1929f4e..0e995a341c9 100644 --- a/drivers/display/display_sdl_bottom.c +++ b/drivers/display/display_sdl_bottom.c @@ -11,24 +11,38 @@ #include #include "nsi_tracing.h" -int sdl_display_init_bottom(uint16_t height, uint16_t width, - void **window, void **renderer, void **texture) +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, + bool use_accelerator, void **window, void **renderer, void **mutex, + void **texture, void **read_texture) { *window = SDL_CreateWindow("Zephyr Display", SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, width, - height, SDL_WINDOW_SHOWN); + SDL_WINDOWPOS_UNDEFINED, width * zoom_pct / 100, + height * zoom_pct / 100, SDL_WINDOW_SHOWN); if (*window == NULL) { nsi_print_warning("Failed to create SDL window: %s", SDL_GetError()); return -1; } - *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED); + if (use_accelerator) { + *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED); + } else { + *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_SOFTWARE); + } + if (*renderer == NULL) { nsi_print_warning("Failed to create SDL renderer: %s", SDL_GetError()); return -1; } + *mutex = SDL_CreateMutex(); + if (*mutex == NULL) { + nsi_print_warning("Failed to create SDL mutex: %s", SDL_GetError()); + return -1; + } + + SDL_RenderSetLogicalSize(*renderer, width, height); + *texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); if (*texture == NULL) { @@ -36,6 +50,13 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, return -1; } + *read_texture = SDL_CreateTexture(*renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_TARGET, width, height); + if (*read_texture == NULL) { + nsi_print_warning("Failed to create SDL texture for read: %s", SDL_GetError()); + return -1; + } + SDL_SetRenderDrawColor(*renderer, 0, 0, 0, 0xFF); SDL_RenderClear(*renderer); SDL_RenderPresent(*renderer); @@ -45,16 +66,23 @@ int sdl_display_init_bottom(uint16_t height, uint16_t width, void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *texture, + void *renderer, void *mutex, void *texture, uint8_t *buf, bool display_on) { SDL_Rect rect; + int err; rect.x = x; rect.y = y; rect.w = width; rect.h = height; + err = SDL_TryLockMutex(mutex); + if (err) { + nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError()); + return; + } + SDL_UpdateTexture(texture, &rect, buf, 4 * rect.w); if (display_on) { @@ -62,20 +90,40 @@ void sdl_display_write_bottom(const uint16_t height, const uint16_t width, SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } + + SDL_UnlockMutex(mutex); } int sdl_display_read_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *buf, uint16_t pitch) + void *renderer, void *buf, uint16_t pitch, + void *mutex, void *texture, void *read_texture) { SDL_Rect rect; + int err; rect.x = x; rect.y = y; rect.w = width; rect.h = height; - return SDL_RenderReadPixels(renderer, &rect, 0, buf, pitch * 4U); + err = SDL_TryLockMutex(mutex); + if (err) { + nsi_print_warning("Failed to lock SDL mutex: %s", SDL_GetError()); + return -1; + } + + SDL_SetRenderTarget(renderer, read_texture); + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderReadPixels(renderer, &rect, SDL_PIXELFORMAT_ARGB8888, buf, width * 4); + + SDL_SetRenderTarget(renderer, NULL); + + SDL_UnlockMutex(mutex); + + return err; } void sdl_display_blanking_off_bottom(void *renderer, void *texture) @@ -91,13 +139,24 @@ void sdl_display_blanking_on_bottom(void *renderer) SDL_RenderPresent(renderer); } -void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture) +void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture, + void **read_texture) { + if (*read_texture != NULL) { + SDL_DestroyTexture(*read_texture); + *read_texture = NULL; + } + if (*texture != NULL) { SDL_DestroyTexture(*texture); *texture = NULL; } + if (*mutex != NULL) { + SDL_DestroyMutex(*mutex); + *mutex = NULL; + } + if (*renderer != NULL) { SDL_DestroyRenderer(*renderer); *renderer = NULL; diff --git a/drivers/display/display_sdl_bottom.h b/drivers/display/display_sdl_bottom.h index 91ea890c13b..54973777f1b 100644 --- a/drivers/display/display_sdl_bottom.h +++ b/drivers/display/display_sdl_bottom.h @@ -20,18 +20,21 @@ extern "C" { /* Note: None of these functions are public interfaces. But internal to the SDL display driver */ -int sdl_display_init_bottom(uint16_t height, uint16_t width, - void **window, void **renderer, void **texture); +int sdl_display_init_bottom(uint16_t height, uint16_t width, uint16_t zoom_pct, + bool use_accelerator, void **window, void **renderer, void **mutex, + void **texture, void **read_texture); void sdl_display_write_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *texture, + void *renderer, void *mutex, void *texture, uint8_t *buf, bool display_on); int sdl_display_read_bottom(const uint16_t height, const uint16_t width, const uint16_t x, const uint16_t y, - void *renderer, void *buf, uint16_t pitch); + void *renderer, void *buf, uint16_t pitch, + void *mutex, void *texture, void **read_texture); void sdl_display_blanking_off_bottom(void *renderer, void *texture); void sdl_display_blanking_on_bottom(void *renderer); -void sdl_display_cleanup_bottom(void **window, void **renderer, void **texture); +void sdl_display_cleanup_bottom(void **window, void **renderer, void **mutex, void **texture, + void **read_texture); #ifdef __cplusplus } diff --git a/drivers/display/display_st7735r.c b/drivers/display/display_st7735r.c index a20242d9703..88c282d89f8 100644 --- a/drivers/display/display_st7735r.c +++ b/drivers/display/display_st7735r.c @@ -159,15 +159,6 @@ static int st7735r_blanking_off(const struct device *dev) return st7735r_transmit(dev, ST7735R_CMD_DISP_ON, NULL, 0); } -static int st7735r_read(const struct device *dev, - const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - static int st7735r_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) @@ -267,23 +258,6 @@ static int st7735r_write(const struct device *dev, return ret; } -static void *st7735r_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int st7735r_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int st7735r_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void st7735r_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -548,10 +522,6 @@ static const struct display_driver_api st7735r_api = { .blanking_on = st7735r_blanking_on, .blanking_off = st7735r_blanking_off, .write = st7735r_write, - .read = st7735r_read, - .get_framebuffer = st7735r_get_framebuffer, - .set_brightness = st7735r_set_brightness, - .set_contrast = st7735r_set_contrast, .get_capabilities = st7735r_get_capabilities, .set_pixel_format = st7735r_set_pixel_format, .set_orientation = st7735r_set_orientation, diff --git a/drivers/display/display_st7789v.c b/drivers/display/display_st7789v.c index 56440c369c9..0d3a9eb37aa 100644 --- a/drivers/display/display_st7789v.c +++ b/drivers/display/display_st7789v.c @@ -141,15 +141,6 @@ static int st7789v_blanking_off(const struct device *dev) return 0; } -static int st7789v_read(const struct device *dev, - const uint16_t x, - const uint16_t y, - const struct display_buffer_descriptor *desc, - void *buf) -{ - return -ENOTSUP; -} - static void st7789v_set_mem_area(const struct device *dev, const uint16_t x, const uint16_t y, const uint16_t w, const uint16_t h) { @@ -204,23 +195,6 @@ static int st7789v_write(const struct device *dev, return 0; } -static void *st7789v_get_framebuffer(const struct device *dev) -{ - return NULL; -} - -static int st7789v_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} - -static int st7789v_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; -} - static void st7789v_get_capabilities(const struct device *dev, struct display_capabilities *capabilities) { @@ -413,10 +387,6 @@ static const struct display_driver_api st7789v_api = { .blanking_on = st7789v_blanking_on, .blanking_off = st7789v_blanking_off, .write = st7789v_write, - .read = st7789v_read, - .get_framebuffer = st7789v_get_framebuffer, - .set_brightness = st7789v_set_brightness, - .set_contrast = st7789v_set_contrast, .get_capabilities = st7789v_get_capabilities, .set_pixel_format = st7789v_set_pixel_format, .set_orientation = st7789v_set_orientation, diff --git a/drivers/display/display_stm32_ltdc.c b/drivers/display/display_stm32_ltdc.c index 99001c3b37b..4581ea1d012 100644 --- a/drivers/display/display_stm32_ltdc.c +++ b/drivers/display/display_stm32_ltdc.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2022 Byte-Lab d.o.o. * Copyright 2023 NXP + * Copyright (c) 2024 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +19,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); @@ -54,27 +56,15 @@ LOG_MODULE_REGISTER(display_stm32_ltdc, CONFIG_DISPLAY_LOG_LEVEL); #error "Invalid LTDC pixel format chosen" #endif -#if defined(CONFIG_HAS_CMSIS_CORE_M) -#include - -#if __DCACHE_PRESENT == 1 -#define CACHE_INVALIDATE(addr, size) SCB_InvalidateDCache_by_Addr((addr), (size)) -#define CACHE_CLEAN(addr, size) SCB_CleanDCache_by_Addr((addr), (size)) -#else -#define CACHE_INVALIDATE(addr, size) -#define CACHE_CLEAN(addr, size) barrier_dsync_fence_full(); -#endif /* __DCACHE_PRESENT == 1 */ - -#else -#define CACHE_INVALIDATE(addr, size) -#define CACHE_CLEAN(addr, size) -#endif /* CONFIG_HAS_CMSIS_CORE_M */ - struct display_stm32_ltdc_data { LTDC_HandleTypeDef hltdc; enum display_pixel_format current_pixel_format; uint8_t current_pixel_size; uint8_t *frame_buffer; + uint32_t frame_buffer_len; + const uint8_t *pend_buf; + const uint8_t *front_buf; + struct k_sem sem; }; struct display_stm32_ltdc_config { @@ -84,35 +74,27 @@ struct display_stm32_ltdc_config { struct gpio_dt_spec bl_ctrl_gpio; struct stm32_pclken pclken; const struct pinctrl_dev_config *pctrl; + void (*irq_config_func)(const struct device *dev); + const struct device *display_controller; }; -static int stm32_ltdc_blanking_on(const struct device *dev) -{ - return -ENOTSUP; -} - -static int stm32_ltdc_blanking_off(const struct device *dev) -{ - return -ENOTSUP; -} - -static void *stm32_ltdc_get_framebuffer(const struct device *dev) +static void stm32_ltdc_global_isr(const struct device *dev) { struct display_stm32_ltdc_data *data = dev->data; - return (void *) data->frame_buffer; -} + if (__HAL_LTDC_GET_FLAG(&data->hltdc, LTDC_FLAG_LI) && + __HAL_LTDC_GET_IT_SOURCE(&data->hltdc, LTDC_IT_LI)) { + if (data->front_buf != data->pend_buf) { + data->front_buf = data->pend_buf; -static int stm32_ltdc_set_brightness(const struct device *dev, - const uint8_t brightness) -{ - return -ENOTSUP; -} + LTDC_LAYER(&data->hltdc, LTDC_LAYER_1)->CFBAR = (uint32_t)data->front_buf; + __HAL_LTDC_RELOAD_CONFIG(&data->hltdc); -static int stm32_ltdc_set_contrast(const struct device *dev, - const uint8_t contrast) -{ - return -ENOTSUP; + k_sem_give(&data->sem); + } + + __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI); + } } static int stm32_ltdc_set_pixel_format(const struct device *dev, @@ -183,21 +165,60 @@ static int stm32_ltdc_write(const struct device *dev, const uint16_t x, { const struct display_stm32_ltdc_config *config = dev->config; struct display_stm32_ltdc_data *data = dev->data; - uint8_t *dst = data->frame_buffer; + uint8_t *dst = NULL; + const uint8_t *pend_buf = NULL; const uint8_t *src = buf; uint16_t row; - /* dst = pointer to upper left pixel of the rectangle to be updated in frame buffer */ - dst += (x * data->current_pixel_size); - dst += (y * config->width * data->current_pixel_size); + if ((x == 0) && (y == 0) && + (desc->width == config->width) && + (desc->height == config->height) && + (desc->pitch == desc->width)) { + /* Use buf as ltdc frame buffer directly if it length same as ltdc frame buffer. */ + pend_buf = buf; + } else { + if (CONFIG_STM32_LTDC_FB_NUM == 0) { + LOG_ERR("Partial write requires internal frame buffer"); + return -ENOTSUP; + } + + dst = data->frame_buffer; + + if (CONFIG_STM32_LTDC_FB_NUM == 2) { + if (data->front_buf == data->frame_buffer) { + dst = data->frame_buffer + data->frame_buffer_len; + } + + memcpy(dst, data->front_buf, data->frame_buffer_len); + } + + pend_buf = dst; + + /* dst = pointer to upper left pixel of the rectangle + * to be updated in frame buffer. + */ + dst += (x * data->current_pixel_size); + dst += (y * config->width * data->current_pixel_size); + + for (row = 0; row < desc->height; row++) { + (void) memcpy(dst, src, desc->width * data->current_pixel_size); + sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size); + dst += (config->width * data->current_pixel_size); + src += (desc->pitch * data->current_pixel_size); + } - for (row = 0; row < desc->height; row++) { - (void) memcpy(dst, src, desc->width * data->current_pixel_size); - CACHE_CLEAN(dst, desc->width * data->current_pixel_size); - dst += (config->width * data->current_pixel_size); - src += (desc->pitch * data->current_pixel_size); } + if (data->front_buf == pend_buf) { + return 0; + } + + k_sem_reset(&data->sem); + + data->pend_buf = pend_buf; + + k_sem_take(&data->sem, K_FOREVER); + return 0; } @@ -209,7 +230,7 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, const struct display_stm32_ltdc_config *config = dev->config; struct display_stm32_ltdc_data *data = dev->data; uint8_t *dst = buf; - const uint8_t *src = data->frame_buffer; + const uint8_t *src = data->front_buf; uint16_t row; /* src = pointer to upper left pixel of the rectangle to be read from frame buffer */ @@ -218,7 +239,7 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, for (row = 0; row < desc->height; row++) { (void) memcpy(dst, src, desc->width * data->current_pixel_size); - CACHE_CLEAN(dst, desc->width * data->current_pixel_size); + sys_cache_data_flush_range(dst, desc->width * data->current_pixel_size); src += (config->width * data->current_pixel_size); dst += (desc->pitch * data->current_pixel_size); } @@ -226,6 +247,40 @@ static int stm32_ltdc_read(const struct device *dev, const uint16_t x, return 0; } +static int stm32_ltdc_display_blanking_off(const struct device *dev) +{ + const struct display_stm32_ltdc_config *config = dev->config; + const struct device *display_dev = config->display_controller; + + if (display_dev == NULL) { + return 0; + } + + if (!device_is_ready(display_dev)) { + LOG_ERR("Display device %s not ready", display_dev->name); + return -ENODEV; + } + + return display_blanking_off(display_dev); +} + +static int stm32_ltdc_display_blanking_on(const struct device *dev) +{ + const struct display_stm32_ltdc_config *config = dev->config; + const struct device *display_dev = config->display_controller; + + if (display_dev == NULL) { + return 0; + } + + if (!device_is_ready(config->display_controller)) { + LOG_ERR("Display device %s not ready", display_dev->name); + return -ENODEV; + } + + return display_blanking_on(display_dev); +} + static int stm32_ltdc_init(const struct device *dev) { int err; @@ -305,19 +360,41 @@ static int stm32_ltdc_init(const struct device *dev) data->current_pixel_format = DISPLAY_INIT_PIXEL_FORMAT; data->current_pixel_size = STM32_LTDC_INIT_PIXEL_SIZE; + k_sem_init(&data->sem, 0, 1); + + config->irq_config_func(dev); + +#ifdef CONFIG_STM32_LTDC_DISABLE_FMC_BANK1 + /* Clear MBKEN and MTYP[1:0] bits. */ +#ifdef CONFIG_SOC_SERIES_STM32F7X + FMC_Bank1->BTCR[0] &= ~(0x0000000D); +#else /* CONFIG_SOC_SERIES_STM32H7X */ + FMC_Bank1_R->BTCR[0] &= ~(0x0000000D); +#endif +#endif /* CONFIG_STM32_LTDC_DISABLE_FMC_BANK1 */ + /* Initialise the LTDC peripheral */ err = HAL_LTDC_Init(&data->hltdc); if (err != HAL_OK) { return err; } - /* Configure layer 0 (only one layer is used) */ + /* Configure layer 1 (only one layer is used) */ /* LTDC starts fetching pixels and sending them to display after this call */ - err = HAL_LTDC_ConfigLayer(&data->hltdc, &data->hltdc.LayerCfg[0], 0); + err = HAL_LTDC_ConfigLayer(&data->hltdc, &data->hltdc.LayerCfg[0], LTDC_LAYER_1); if (err != HAL_OK) { return err; } + /* Disable layer 2, since it not used */ + __HAL_LTDC_LAYER_DISABLE(&data->hltdc, LTDC_LAYER_2); + + /* Set the line interrupt position */ + LTDC->LIPCR = 0U; + + __HAL_LTDC_CLEAR_FLAG(&data->hltdc, LTDC_FLAG_LI); + __HAL_LTDC_ENABLE_IT(&data->hltdc, LTDC_IT_LI); + return 0; } @@ -379,16 +456,13 @@ static int stm32_ltdc_pm_action(const struct device *dev, #endif /* CONFIG_PM_DEVICE */ static const struct display_driver_api stm32_ltdc_display_api = { - .blanking_on = stm32_ltdc_blanking_on, - .blanking_off = stm32_ltdc_blanking_off, .write = stm32_ltdc_write, .read = stm32_ltdc_read, - .get_framebuffer = stm32_ltdc_get_framebuffer, - .set_brightness = stm32_ltdc_set_brightness, - .set_contrast = stm32_ltdc_set_contrast, .get_capabilities = stm32_ltdc_get_capabilities, .set_pixel_format = stm32_ltdc_set_pixel_format, - .set_orientation = stm32_ltdc_set_orientation + .set_orientation = stm32_ltdc_set_orientation, + .blanking_off = stm32_ltdc_display_blanking_off, + .blanking_on = stm32_ltdc_display_blanking_on, }; #if DT_INST_NODE_HAS_PROP(0, ext_sdram) @@ -414,16 +488,30 @@ static const struct display_driver_api stm32_ltdc_display_api = { #define STM32_LTDC_DEVICE_PINCTRL_GET(n) PINCTRL_DT_INST_DEV_CONFIG_GET(n) #endif +#define STM32_LTDC_FRAME_BUFFER_LEN(inst) \ + (STM32_LTDC_INIT_PIXEL_SIZE * DT_INST_PROP(inst, height) * DT_INST_PROP(inst, width)) \ + #define STM32_LTDC_DEVICE(inst) \ STM32_LTDC_DEVICE_PINCTRL_INIT(inst); \ PM_DEVICE_DT_INST_DEFINE(inst, stm32_ltdc_pm_action); \ + static void stm32_ltdc_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + stm32_ltdc_global_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ /* frame buffer aligned to cache line width for optimal cache flushing */ \ FRAME_BUFFER_SECTION static uint8_t __aligned(32) \ - frame_buffer_##inst[STM32_LTDC_INIT_PIXEL_SIZE * \ - DT_INST_PROP(inst, height) * \ - DT_INST_PROP(inst, width)]; \ + frame_buffer_##inst[CONFIG_STM32_LTDC_FB_NUM * \ + STM32_LTDC_FRAME_BUFFER_LEN(inst)]; \ static struct display_stm32_ltdc_data stm32_ltdc_data_##inst = { \ .frame_buffer = frame_buffer_##inst, \ + .frame_buffer_len = STM32_LTDC_FRAME_BUFFER_LEN(inst), \ + .front_buf = frame_buffer_##inst, \ + .pend_buf = frame_buffer_##inst, \ .hltdc = { \ .Instance = (LTDC_TypeDef *) DT_INST_REG_ADDR(inst), \ .Init = { \ @@ -518,6 +606,9 @@ static const struct display_driver_api stm32_ltdc_display_api = { .bus = DT_INST_CLOCKS_CELL(inst, bus) \ }, \ .pctrl = STM32_LTDC_DEVICE_PINCTRL_GET(inst), \ + .irq_config_func = stm32_ltdc_irq_config_func_##inst, \ + .display_controller = DEVICE_DT_GET_OR_NULL( \ + DT_INST_PHANDLE(inst, display_controller)), \ }; \ DEVICE_DT_INST_DEFINE(inst, \ &stm32_ltdc_init, \ diff --git a/drivers/display/uc81xx.c b/drivers/display/uc81xx.c index 88df6be0289..3aafe933750 100644 --- a/drivers/display/uc81xx.c +++ b/drivers/display/uc81xx.c @@ -66,6 +66,10 @@ struct uc81xx_quirks { bool auto_copy; int (*set_cdi)(const struct device *dev, bool border); + int (*set_tres)(const struct device *dev); + int (*set_ptl)(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc); }; struct uc81xx_config { @@ -224,10 +228,6 @@ static int uc81xx_set_profile(const struct device *dev, UC81XX_PSR_SHL | UC81XX_PSR_SHD | UC81XX_PSR_RST; - const struct uc81xx_tres tres = { - .hres = sys_cpu_to_be16(config->width), - .vres = sys_cpu_to_be16(config->height), - }; if (type >= UC81XX_NUM_PROFILES) { return -EINVAL; @@ -272,9 +272,7 @@ static int uc81xx_set_profile(const struct device *dev, } /* Set panel resolution */ - LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_TRES, - (const void *)&tres, sizeof(tres))) { + if (config->quirks->set_tres(dev)) { return -EIO; } @@ -403,13 +401,6 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 uint16_t x_end_idx = x + desc->width - 1; uint16_t y_end_idx = y + desc->height - 1; - const struct uc81xx_ptl ptl = { - .hrst = sys_cpu_to_be16(x), - .hred = sys_cpu_to_be16(x_end_idx), - .vrst = sys_cpu_to_be16(y), - .vred = sys_cpu_to_be16(y_end_idx), - .flags = UC81XX_PTL_FLAG_PT_SCAN, - }; size_t buf_len; const uint8_t back_buffer = data->blanking_on ? UC81XX_CMD_DTM1 : UC81XX_CMD_DTM2; @@ -448,15 +439,11 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 } } - /* Setup Partial Window and enable Partial Mode */ - LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTIN, NULL, 0)) { return -EIO; } - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -487,8 +474,7 @@ static int uc81xx_write(const struct device *dev, const uint16_t x, const uint16 * needed. */ - if (uc81xx_write_cmd(dev, UC81XX_CMD_PTL, - (const void *)&ptl, sizeof(ptl))) { + if (config->quirks->set_ptl(dev, x, y, x_end_idx, y_end_idx, desc)) { return -EIO; } @@ -654,7 +640,73 @@ static int uc81xx_init(const struct device *dev) return uc81xx_controller_init(dev); } -#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static int uc81xx_set_tres_8(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres8 tres = { + .hres = config->width, + .vres = config->height, + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_8(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl8 ptl = { + .hrst = x, + .hred = x_end_idx, + .vrst = y, + .vred = y_end_idx, + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8179) +static int uc81xx_set_tres_16(const struct device *dev) +{ + const struct uc81xx_config *config = dev->config; + const struct uc81xx_tres16 tres = { + .hres = sys_cpu_to_be16(config->width), + .vres = sys_cpu_to_be16(config->height), + }; + + LOG_HEXDUMP_DBG(&tres, sizeof(tres), "TRES"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_TRES, (const void *)&tres, sizeof(tres)); +} + +static inline int uc81xx_set_ptl_16(const struct device *dev, uint16_t x, uint16_t y, + uint16_t x_end_idx, uint16_t y_end_idx, + const struct display_buffer_descriptor *desc) +{ + const struct uc81xx_ptl16 ptl = { + .hrst = sys_cpu_to_be16(x), + .hred = sys_cpu_to_be16(x_end_idx), + .vrst = sys_cpu_to_be16(y), + .vred = sys_cpu_to_be16(y_end_idx), + .flags = UC81XX_PTL_FLAG_PT_SCAN, + }; + + /* Setup Partial Window and enable Partial Mode */ + LOG_HEXDUMP_DBG(&ptl, sizeof(ptl), "ptl"); + + return uc81xx_write_cmd(dev, UC81XX_CMD_PTL, (const void *)&ptl, sizeof(ptl)); +} +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) || DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static int uc8176_set_cdi(const struct device *dev, bool border) { const struct uc81xx_config *config = dev->config; @@ -675,7 +727,22 @@ static int uc8176_set_cdi(const struct device *dev, bool border) LOG_DBG("CDI: %#hhx", cdi); return uc81xx_write_cmd_uint8(dev, UC81XX_CMD_CDI, cdi); } +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8175) +static const struct uc81xx_quirks uc8175_quirks = { + .max_width = 80, + .max_height = 160, + .auto_copy = false, + + .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_8, + .set_ptl = uc81xx_set_ptl_8, +}; +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(ultrachip_uc8176) static const struct uc81xx_quirks uc8176_quirks = { .max_width = 400, .max_height = 300, @@ -683,6 +750,8 @@ static const struct uc81xx_quirks uc8176_quirks = { .auto_copy = false, .set_cdi = uc8176_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -714,6 +783,8 @@ static const struct uc81xx_quirks uc8179_quirks = { .auto_copy = true, .set_cdi = uc8179_set_cdi, + .set_tres = uc81xx_set_tres_16, + .set_ptl = uc81xx_set_ptl_16, }; #endif @@ -814,6 +885,9 @@ static struct display_driver_api uc81xx_driver_api = { CONFIG_DISPLAY_INIT_PRIORITY, \ &uc81xx_driver_api); +DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8175, UC81XX_DEFINE, + &uc8175_quirks); + DT_FOREACH_STATUS_OKAY_VARGS(ultrachip_uc8176, UC81XX_DEFINE, &uc8176_quirks); diff --git a/drivers/display/uc81xx_regs.h b/drivers/display/uc81xx_regs.h index 322423324ad..aba38ac3e7f 100644 --- a/drivers/display/uc81xx_regs.h +++ b/drivers/display/uc81xx_regs.h @@ -106,14 +106,31 @@ #define UC8179_CDI_DDX1 BIT(1) #define UC8179_CDI_DDX0 BIT(0) -struct uc81xx_tres { +struct uc81xx_tres8 { + uint8_t hres; + uint8_t vres; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_tres8) == 2); + +struct uc81xx_ptl8 { + uint8_t hrst; + uint8_t hred; + uint8_t vrst; + uint8_t vred; + uint8_t flags; +} __packed; + +BUILD_ASSERT(sizeof(struct uc81xx_ptl8) == 5); + +struct uc81xx_tres16 { uint16_t hres; uint16_t vres; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_tres) == 4); +BUILD_ASSERT(sizeof(struct uc81xx_tres16) == 4); -struct uc81xx_ptl { +struct uc81xx_ptl16 { uint16_t hrst; uint16_t hred; uint16_t vrst; @@ -121,11 +138,10 @@ struct uc81xx_ptl { uint8_t flags; } __packed; -BUILD_ASSERT(sizeof(struct uc81xx_ptl) == 9); +BUILD_ASSERT(sizeof(struct uc81xx_ptl16) == 9); #define UC81XX_PTL_FLAG_PT_SCAN BIT(0) - /* Time constants in ms */ #define UC81XX_RESET_DELAY 10U #define UC81XX_PON_DELAY 100U diff --git a/drivers/dma/CMakeLists.txt b/drivers/dma/CMakeLists.txt index e65c3726622..7231848a05a 100644 --- a/drivers/dma/CMakeLists.txt +++ b/drivers/dma/CMakeLists.txt @@ -38,3 +38,5 @@ zephyr_library_sources_ifdef(CONFIG_DMA_ANDES_ATCDMAC300 dma_andes_atcdmac300.c) zephyr_library_sources_ifdef(CONFIG_DMA_SEDI dma_sedi.c) zephyr_library_sources_ifdef(CONFIG_DMA_SMARTBOND dma_smartbond.c) zephyr_library_sources_ifdef(CONFIG_DMA_NXP_SOF_HOST_DMA dma_nxp_sof_host_dma.c) +zephyr_library_sources_ifdef(CONFIG_DMA_EMUL dma_emul.c) +zephyr_library_sources_ifdef(CONFIG_DMA_NXP_EDMA dma_nxp_edma.c) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index e24386558cd..7f584dae57b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -72,4 +72,8 @@ source "drivers/dma/Kconfig.smartbond" source "drivers/dma/Kconfig.nxp_sof_host_dma" +source "drivers/dma/Kconfig.emul" + +source "drivers/dma/Kconfig.nxp_edma" + endif # DMA diff --git a/drivers/dma/Kconfig.emul b/drivers/dma/Kconfig.emul new file mode 100644 index 00000000000..595f577f3d1 --- /dev/null +++ b/drivers/dma/Kconfig.emul @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config DMA_EMUL + bool "Emulated DMA driver [EXPERIMENTAL]" + depends on DT_HAS_ZEPHYR_DMA_EMUL_ENABLED + select EXPERIMENTAL + help + Emulated DMA Driver diff --git a/drivers/dma/Kconfig.nxp_edma b/drivers/dma/Kconfig.nxp_edma new file mode 100644 index 00000000000..3698605451a --- /dev/null +++ b/drivers/dma/Kconfig.nxp_edma @@ -0,0 +1,34 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config DMA_NXP_EDMA + bool "NXP enhanced Direct Memory Access (eDMA) driver" + default y + depends on DT_HAS_NXP_EDMA_ENABLED + help + Enable driver for NXP's eDMA IP. + +if DMA_NXP_EDMA + +config DMA_NXP_EDMA_ALIGN + int "Alignment (in bytes) required for the transfers" + default 8 + help + Use this to set the alignment (in bytes) + used by entities employing this driver to + adjust the addresses and sizes of the memory + regions involved in the transfer process. + This value needs to match one of the possible + values for SSIZE and DSIZE, otherwise the + driver will return an error upon configuration. + +config DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ + bool "Set if CPU should be interrupted when CITER = BITER / 2" + default n + help + Enable this configuration if the CPU should be + interrupted when CITER = BITER / 2. Using this, + the CPU will be interrupted when CITER = BITER and + when CITER = BITER / 2. + +endif # DMA_NXP_EDMA diff --git a/drivers/dma/dma_andes_atcdmac300.c b/drivers/dma/dma_andes_atcdmac300.c index ef90868f943..2f817242fbe 100644 --- a/drivers/dma/dma_andes_atcdmac300.c +++ b/drivers/dma/dma_andes_atcdmac300.c @@ -11,7 +11,6 @@ #include #include #include -#include #define DT_DRV_COMPAT andestech_atcdmac300 @@ -72,18 +71,18 @@ LOG_MODULE_REGISTER(dma_andes_atcdmac300); #define DMA_CH_CTRL_SBINF_MASK BIT(31) #define DMA_CH_CTRL_DBINF_MASK BIT(30) #define DMA_CH_CTRL_PRIORITY_HIGH BIT(29) -#define DMA_CH_CTRL_SBSIZE_MASK BIT(24) +#define DMA_CH_CTRL_SBSIZE_MASK GENMASK(27, 24) #define DMA_CH_CTRL_SBSIZE(n) FIELD_PREP(DMA_CH_CTRL_SBSIZE_MASK, (n)) #define DMA_CH_CTRL_SWIDTH_MASK GENMASK(23, 21) #define DMA_CH_CTRL_SWIDTH(n) FIELD_PREP(DMA_CH_CTRL_SWIDTH_MASK, (n)) #define DMA_CH_CTRL_DWIDTH_MASK GENMASK(20, 18) #define DMA_CH_CTRL_DWIDTH(n) FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (n)) #define DMA_CH_CTRL_SMODE_HANDSHAKE BIT(17) -#define DMA_CH_CTRL_DMODE_HANDSHAKE BIT(17) +#define DMA_CH_CTRL_DMODE_HANDSHAKE BIT(16) #define DMA_CH_CTRL_SRCADDRCTRL_MASK GENMASK(15, 14) -#define DMA_CH_CTRL_SRCADDR_INC FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (0)) -#define DMA_CH_CTRL_SRCADDR_DEC FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (1)) -#define DMA_CH_CTRL_SRCADDR_FIX FIELD_PREP(DMA_CH_CTRL_DWIDTH_MASK, (2)) +#define DMA_CH_CTRL_SRCADDR_INC FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (0)) +#define DMA_CH_CTRL_SRCADDR_DEC FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (1)) +#define DMA_CH_CTRL_SRCADDR_FIX FIELD_PREP(DMA_CH_CTRL_SRCADDRCTRL_MASK, (2)) #define DMA_CH_CTRL_DSTADDRCTRL_MASK GENMASK(13, 12) #define DMA_CH_CTRL_DSTADDR_INC FIELD_PREP(DMA_CH_CTRL_DSTADDRCTRL_MASK, (0)) #define DMA_CH_CTRL_DSTADDR_DEC FIELD_PREP(DMA_CH_CTRL_DSTADDRCTRL_MASK, (1)) diff --git a/drivers/dma/dma_dw_common.c b/drivers/dma/dma_dw_common.c index 0a5040980b2..22de9a7d9ef 100644 --- a/drivers/dma/dma_dw_common.c +++ b/drivers/dma/dma_dw_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "dma_dw_common.h" @@ -546,6 +547,7 @@ int dw_dma_stop(const struct device *dev, uint32_t channel) const struct dw_dma_dev_cfg *const dev_cfg = dev->config; struct dw_dma_dev_data *dev_data = dev->data; struct dw_dma_chan_data *chan_data = &dev_data->chan[channel]; + enum pm_device_state pm_state; int ret = 0; if (channel >= DW_CHAN_COUNT) { @@ -553,7 +555,17 @@ int dw_dma_stop(const struct device *dev, uint32_t channel) goto out; } + /* + * skip if device is not active. if we get an error for state_get, + * do not skip but check actual hardware state and stop if + * needed + */ + ret = pm_device_state_get(dev, &pm_state); + if (!ret && pm_state != PM_DEVICE_STATE_ACTIVE) + goto out; + if (!dw_dma_is_enabled(dev, channel) && chan_data->state != DW_DMA_SUSPENDED) { + ret = 0; goto out; } diff --git a/drivers/dma/dma_emul.c b/drivers/dma/dma_emul.c new file mode 100644 index 00000000000..235593df624 --- /dev/null +++ b/drivers/dma/dma_emul.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT zephyr_dma_emul + +#ifdef CONFIG_DMA_64BIT +#define dma_addr_t uint64_t +#else +#define dma_addr_t uint32_t +#endif + +enum dma_emul_channel_state { + DMA_EMUL_CHANNEL_UNUSED, + DMA_EMUL_CHANNEL_LOADED, + DMA_EMUL_CHANNEL_STARTED, + DMA_EMUL_CHANNEL_STOPPED, +}; + +struct dma_emul_xfer_desc { + struct dma_config config; +}; + +struct dma_emul_work { + const struct device *dev; + uint32_t channel; + struct k_work work; +}; + +struct dma_emul_config { + uint32_t channel_mask; + size_t num_channels; + size_t num_requests; + size_t addr_align; + size_t size_align; + size_t copy_align; + + k_thread_stack_t *work_q_stack; + size_t work_q_stack_size; + int work_q_priority; + + /* points to an array of size num_channels */ + struct dma_emul_xfer_desc *xfer; + /* points to an array of size num_channels * num_requests */ + struct dma_block_config *block; +}; + +struct dma_emul_data { + struct dma_context dma_ctx; + atomic_t *channels_atomic; + struct k_spinlock lock; + struct k_work_q work_q; + struct dma_emul_work work; +}; + +static void dma_emul_work_handler(struct k_work *work); + +LOG_MODULE_REGISTER(dma_emul, CONFIG_DMA_LOG_LEVEL); + +static inline bool dma_emul_xfer_is_error_status(int status) +{ + return status < 0; +} + +static inline const char *const dma_emul_channel_state_to_string(enum dma_emul_channel_state state) +{ + switch (state) { + case DMA_EMUL_CHANNEL_UNUSED: + return "UNUSED"; + case DMA_EMUL_CHANNEL_LOADED: + return "LOADED"; + case DMA_EMUL_CHANNEL_STARTED: + return "STARTED"; + case DMA_EMUL_CHANNEL_STOPPED: + return "STOPPED"; + default: + return "(invalid)"; + }; +} + +/* + * Repurpose the "_reserved" field for keeping track of internal + * channel state. + * + * Note: these must be called with data->lock locked! + */ +static enum dma_emul_channel_state dma_emul_get_channel_state(const struct device *dev, + uint32_t channel) +{ + const struct dma_emul_config *config = dev->config; + + __ASSERT_NO_MSG(channel < config->num_channels); + + return (enum dma_emul_channel_state)config->xfer[channel].config._reserved; +} + +static void dma_emul_set_channel_state(const struct device *dev, uint32_t channel, + enum dma_emul_channel_state state) +{ + const struct dma_emul_config *config = dev->config; + + LOG_DBG("setting channel %u state to %s", channel, dma_emul_channel_state_to_string(state)); + + __ASSERT_NO_MSG(channel < config->num_channels); + __ASSERT_NO_MSG(state >= DMA_EMUL_CHANNEL_UNUSED && state <= DMA_EMUL_CHANNEL_STOPPED); + + config->xfer[channel].config._reserved = state; +} + +static const char *dma_emul_xfer_config_to_string(const struct dma_config *cfg) +{ + static char buffer[1024]; + + snprintf(buffer, sizeof(buffer), + "{" + "\n\tslot: %u" + "\n\tchannel_direction: %u" + "\n\tcomplete_callback_en: %u" + "\n\terror_callback_en: %u" + "\n\tsource_handshake: %u" + "\n\tdest_handshake: %u" + "\n\tchannel_priority: %u" + "\n\tsource_chaining_en: %u" + "\n\tdest_chaining_en: %u" + "\n\tlinked_channel: %u" + "\n\tcyclic: %u" + "\n\t_reserved: %u" + "\n\tsource_data_size: %u" + "\n\tdest_data_size: %u" + "\n\tsource_burst_length: %u" + "\n\tdest_burst_length: %u" + "\n\tblock_count: %u" + "\n\thead_block: %p" + "\n\tuser_data: %p" + "\n\tdma_callback: %p" + "\n}", + cfg->dma_slot, cfg->channel_direction, cfg->complete_callback_en, + cfg->error_callback_en, cfg->source_handshake, cfg->dest_handshake, + cfg->channel_priority, cfg->source_chaining_en, cfg->dest_chaining_en, + cfg->linked_channel, cfg->cyclic, cfg->_reserved, cfg->source_data_size, + cfg->dest_data_size, cfg->source_burst_length, cfg->dest_burst_length, + cfg->block_count, cfg->head_block, cfg->user_data, cfg->dma_callback); + + return buffer; +} + +static const char *dma_emul_block_config_to_string(const struct dma_block_config *cfg) +{ + static char buffer[1024]; + + snprintf(buffer, sizeof(buffer), + "{" + "\n\tsource_address: %p" + "\n\tdest_address: %p" + "\n\tsource_gather_interval: %u" + "\n\tdest_scatter_interval: %u" + "\n\tdest_scatter_count: %u" + "\n\tsource_gather_count: %u" + "\n\tblock_size: %u" + "\n\tnext_block: %p" + "\n\tsource_gather_en: %u" + "\n\tdest_scatter_en: %u" + "\n\tsource_addr_adj: %u" + "\n\tdest_addr_adj: %u" + "\n\tsource_reload_en: %u" + "\n\tdest_reload_en: %u" + "\n\tfifo_mode_control: %u" + "\n\tflow_control_mode: %u" + "\n\t_reserved: %u" + "\n}", + (void *)cfg->source_address, (void *)cfg->dest_address, + cfg->source_gather_interval, cfg->dest_scatter_interval, cfg->dest_scatter_count, + cfg->source_gather_count, cfg->block_size, cfg->next_block, cfg->source_gather_en, + cfg->dest_scatter_en, cfg->source_addr_adj, cfg->dest_addr_adj, + cfg->source_reload_en, cfg->dest_reload_en, cfg->fifo_mode_control, + cfg->flow_control_mode, cfg->_reserved + + ); + + return buffer; +} + +static void dma_emul_work_handler(struct k_work *work) +{ + size_t i; + size_t bytes; + uint32_t channel; + k_spinlock_key_t key; + struct dma_block_config block; + struct dma_config xfer_config; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_emul_work *dma_work = CONTAINER_OF(work, struct dma_emul_work, work); + const struct device *dev = dma_work->dev; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + channel = dma_work->channel; + + do { + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + /* + * copy the dma_config so we don't have to worry about + * it being asynchronously updated. + */ + memcpy(&xfer_config, &xfer->config, sizeof(xfer_config)); + k_spin_unlock(&data->lock, key); + + LOG_DBG("processing xfer %p for channel %u", xfer, channel); + for (i = 0; i < xfer_config.block_count; ++i) { + + LOG_DBG("processing block %zu", i); + + key = k_spin_lock(&data->lock); + /* + * copy the dma_block_config so we don't have to worry about + * it being asynchronously updated. + */ + memcpy(&block, + &config->block[channel * config->num_requests + + xfer_config.dma_slot + i], + sizeof(block)); + k_spin_unlock(&data->lock, key); + + /* transfer data in bursts */ + for (bytes = MIN(block.block_size, xfer_config.dest_burst_length); + bytes > 0; block.block_size -= bytes, block.source_address += bytes, + block.dest_address += bytes, + bytes = MIN(block.block_size, xfer_config.dest_burst_length)) { + + key = k_spin_lock(&data->lock); + state = dma_emul_get_channel_state(dev, channel); + k_spin_unlock(&data->lock, key); + + if (state == DMA_EMUL_CHANNEL_STOPPED) { + LOG_DBG("asynchronously canceled"); + if (xfer_config.error_callback_en) { + xfer_config.dma_callback(dev, xfer_config.user_data, + channel, -ECANCELED); + } else { + LOG_DBG("error_callback_en is not set (async " + "cancel)"); + } + goto out; + } + + __ASSERT_NO_MSG(state == DMA_EMUL_CHANNEL_STARTED); + + /* + * FIXME: create a backend API (memcpy, TCP/UDP socket, etc) + * Simple copy for now + */ + memcpy((void *)(uintptr_t)block.dest_address, + (void *)(uintptr_t)block.source_address, bytes); + } + } + + key = k_spin_lock(&data->lock); + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STOPPED); + k_spin_unlock(&data->lock, key); + + /* FIXME: tests/drivers/dma/chan_blen_transfer/ does not set complete_callback_en */ + if (true) { + xfer_config.dma_callback(dev, xfer_config.user_data, channel, + DMA_STATUS_COMPLETE); + } else { + LOG_DBG("complete_callback_en is not set"); + } + + if (xfer_config.source_chaining_en || xfer_config.dest_chaining_en) { + LOG_DBG("%s(): Linked channel %u -> %u", __func__, channel, + xfer_config.linked_channel); + __ASSERT_NO_MSG(channel != xfer_config.linked_channel); + channel = xfer_config.linked_channel; + } else { + LOG_DBG("%s(): done!", __func__); + break; + } + } while (true); + +out: + return; +} + +static bool dma_emul_config_valid(const struct device *dev, uint32_t channel, + const struct dma_config *xfer_config) +{ + size_t i; + struct dma_block_config *block; + const struct dma_emul_config *config = dev->config; + + if (xfer_config->dma_slot >= config->num_requests) { + LOG_ERR("invalid dma_slot %u", xfer_config->dma_slot); + return false; + } + + if (channel >= config->num_channels) { + LOG_ERR("invalid DMA channel %u", channel); + return false; + } + + if (xfer_config->dest_burst_length != xfer_config->source_burst_length) { + LOG_ERR("burst length does not agree. source: %u dest: %u ", + xfer_config->source_burst_length, xfer_config->dest_burst_length); + return false; + } + + for (i = 0, block = xfer_config->head_block; i < xfer_config->block_count; + ++i, block = block->next_block) { + if (block == NULL) { + LOG_ERR("block %zu / %u is NULL", i + 1, xfer_config->block_count); + return false; + } + + if (i >= config->num_requests) { + LOG_ERR("not enough slots to store block %zu / %u", i + 1, + xfer_config->block_count); + return false; + } + } + + /* + * FIXME: + * + * Need to verify all of the fields in struct dma_config with different DT + * configurations so that the driver model is at least consistent and + * verified by CI. + */ + + return true; +} + +static int dma_emul_configure(const struct device *dev, uint32_t channel, + struct dma_config *xfer_config) +{ + size_t i; + int ret = 0; + size_t block_idx; + k_spinlock_key_t key; + struct dma_block_config *block; + struct dma_block_config *block_it; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + if (!dma_emul_config_valid(dev, channel, xfer_config)) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + + LOG_DBG("%s():\nchannel: %u\nconfig: %s", __func__, channel, + dma_emul_xfer_config_to_string(xfer_config)); + + block_idx = channel * config->num_requests + xfer_config->dma_slot; + + block = &config->block[channel * config->num_requests + xfer_config->dma_slot]; + state = dma_emul_get_channel_state(dev, channel); + switch (state) { + case DMA_EMUL_CHANNEL_UNUSED: + case DMA_EMUL_CHANNEL_STOPPED: + /* copy the configuration into the driver */ + memcpy(&xfer->config, xfer_config, sizeof(xfer->config)); + + /* copy all blocks into slots */ + for (i = 0, block_it = xfer_config->head_block; i < xfer_config->block_count; + ++i, block_it = block_it->next_block, ++block) { + __ASSERT_NO_MSG(block_it != NULL); + + LOG_DBG("block_config %s", dma_emul_block_config_to_string(block_it)); + + memcpy(block, block_it, sizeof(*block)); + } + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_LOADED); + + break; + default: + LOG_ERR("attempt to configure DMA in state %d", state); + ret = -EBUSY; + } + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int dma_emul_reload(const struct device *dev, uint32_t channel, dma_addr_t src, + dma_addr_t dst, size_t size) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_start(const struct device *dev, uint32_t channel) +{ + int ret = 0; + k_spinlock_key_t key; + enum dma_emul_channel_state state; + struct dma_emul_xfer_desc *xfer; + struct dma_config *xfer_config; + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + LOG_DBG("%s(channel: %u)", __func__, channel); + + if (channel >= config->num_channels) { + return -EINVAL; + } + + key = k_spin_lock(&data->lock); + xfer = &config->xfer[channel]; + state = dma_emul_get_channel_state(dev, channel); + switch (state) { + case DMA_EMUL_CHANNEL_STARTED: + /* start after being started already is a no-op */ + break; + case DMA_EMUL_CHANNEL_LOADED: + case DMA_EMUL_CHANNEL_STOPPED: + data->work.channel = channel; + while (true) { + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STARTED); + + xfer_config = &config->xfer[channel].config; + if (xfer_config->source_chaining_en || xfer_config->dest_chaining_en) { + LOG_DBG("%s(): Linked channel %u -> %u", __func__, channel, + xfer_config->linked_channel); + channel = xfer_config->linked_channel; + } else { + break; + } + } + ret = k_work_submit_to_queue(&data->work_q, &data->work.work); + ret = (ret < 0) ? ret : 0; + break; + default: + LOG_ERR("attempt to start dma in invalid state %d", state); + ret = -EIO; + break; + } + k_spin_unlock(&data->lock, key); + + return ret; +} + +static int dma_emul_stop(const struct device *dev, uint32_t channel) +{ + k_spinlock_key_t key; + struct dma_emul_data *data = dev->data; + + key = k_spin_lock(&data->lock); + dma_emul_set_channel_state(dev, channel, DMA_EMUL_CHANNEL_STOPPED); + k_spin_unlock(&data->lock, key); + + return 0; +} + +static int dma_emul_suspend(const struct device *dev, uint32_t channel) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_resume(const struct device *dev, uint32_t channel) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_get_status(const struct device *dev, uint32_t channel, + struct dma_status *status) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static int dma_emul_get_attribute(const struct device *dev, uint32_t type, uint32_t *value) +{ + LOG_DBG("%s()", __func__); + + return -ENOSYS; +} + +static bool dma_emul_chan_filter(const struct device *dev, int channel, void *filter_param) +{ + bool success; + k_spinlock_key_t key; + struct dma_emul_data *data = dev->data; + + key = k_spin_lock(&data->lock); + /* lets assume the struct dma_context handles races properly */ + success = dma_emul_get_channel_state(dev, channel) == DMA_EMUL_CHANNEL_UNUSED; + k_spin_unlock(&data->lock, key); + + return success; +} + +static const struct dma_driver_api dma_emul_driver_api = { + .config = dma_emul_configure, + .reload = dma_emul_reload, + .start = dma_emul_start, + .stop = dma_emul_stop, + .suspend = dma_emul_suspend, + .resume = dma_emul_resume, + .get_status = dma_emul_get_status, + .get_attribute = dma_emul_get_attribute, + .chan_filter = dma_emul_chan_filter, +}; + +#ifdef CONFIG_PM_DEVICE +static int gpio_emul_pm_device_pm_action(const struct device *dev, enum pm_device_action action) +{ + ARG_UNUSED(dev); + ARG_UNUSED(action); + + return 0; +} +#endif + +static int dma_emul_init(const struct device *dev) +{ + struct dma_emul_data *data = dev->data; + const struct dma_emul_config *config = dev->config; + + data->work.dev = dev; + data->dma_ctx.magic = DMA_MAGIC; + data->dma_ctx.dma_channels = config->num_channels; + data->dma_ctx.atomic = data->channels_atomic; + + k_work_queue_init(&data->work_q); + k_work_init(&data->work.work, dma_emul_work_handler); + k_work_queue_start(&data->work_q, config->work_q_stack, config->work_q_stack_size, + config->work_q_priority, NULL); + + return 0; +} + +#define DMA_EMUL_INST_HAS_PROP(_inst, _prop) DT_NODE_HAS_PROP(DT_DRV_INST(_inst), _prop) + +#define DMA_EMUL_INST_CHANNEL_MASK(_inst) \ + DT_INST_PROP_OR(_inst, dma_channel_mask, \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channels) \ + ? ((DT_INST_PROP(_inst, dma_channels) > 0) \ + ? BIT_MASK(DT_INST_PROP_OR(_inst, dma_channels, 0)) \ + : 0) \ + : 0) + +#define DMA_EMUL_INST_NUM_CHANNELS(_inst) \ + DT_INST_PROP_OR(_inst, dma_channels, \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channel_mask) \ + ? POPCOUNT(DT_INST_PROP_OR(_inst, dma_channel_mask, 0)) \ + : 0) + +#define DMA_EMUL_INST_NUM_REQUESTS(_inst) DT_INST_PROP_OR(_inst, dma_requests, 1) + +#define DEFINE_DMA_EMUL(_inst) \ + BUILD_ASSERT(DMA_EMUL_INST_HAS_PROP(_inst, dma_channel_mask) || \ + DMA_EMUL_INST_HAS_PROP(_inst, dma_channels), \ + "at least one of dma_channel_mask or dma_channels must be provided"); \ + \ + BUILD_ASSERT(DMA_EMUL_INST_NUM_CHANNELS(_inst) <= 32, "invalid dma-channels property"); \ + \ + static K_THREAD_STACK_DEFINE(work_q_stack_##_inst, DT_INST_PROP(_inst, stack_size)); \ + \ + static struct dma_emul_xfer_desc \ + dma_emul_xfer_desc_##_inst[DMA_EMUL_INST_NUM_CHANNELS(_inst)]; \ + \ + static struct dma_block_config \ + dma_emul_block_config_##_inst[DMA_EMUL_INST_NUM_CHANNELS(_inst) * \ + DMA_EMUL_INST_NUM_REQUESTS(_inst)]; \ + \ + static const struct dma_emul_config dma_emul_config_##_inst = { \ + .channel_mask = DMA_EMUL_INST_CHANNEL_MASK(_inst), \ + .num_channels = DMA_EMUL_INST_NUM_CHANNELS(_inst), \ + .num_requests = DMA_EMUL_INST_NUM_REQUESTS(_inst), \ + .addr_align = DT_INST_PROP_OR(_inst, dma_buf_addr_alignment, 1), \ + .size_align = DT_INST_PROP_OR(_inst, dma_buf_size_alignment, 1), \ + .copy_align = DT_INST_PROP_OR(_inst, dma_copy_alignment, 1), \ + .work_q_stack = (k_thread_stack_t *)&work_q_stack_##_inst, \ + .work_q_stack_size = K_THREAD_STACK_SIZEOF(work_q_stack_##_inst), \ + .work_q_priority = DT_INST_PROP_OR(_inst, priority, 0), \ + .xfer = dma_emul_xfer_desc_##_inst, \ + .block = dma_emul_block_config_##_inst, \ + }; \ + \ + static ATOMIC_DEFINE(dma_emul_channels_atomic_##_inst, \ + DT_INST_PROP_OR(_inst, dma_channels, 0)); \ + \ + static struct dma_emul_data dma_emul_data_##_inst = { \ + .channels_atomic = dma_emul_channels_atomic_##_inst, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(_inst, dma_emul_pm_device_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(_inst, dma_emul_init, PM_DEVICE_DT_INST_GET(_inst), \ + &dma_emul_data_##_inst, &dma_emul_config_##_inst, POST_KERNEL, \ + CONFIG_DMA_INIT_PRIORITY, &dma_emul_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(DEFINE_DMA_EMUL) diff --git a/drivers/dma/dma_intel_adsp_hda.c b/drivers/dma/dma_intel_adsp_hda.c index 2dd0bea6ed6..fe86b8ca61f 100644 --- a/drivers/dma/dma_intel_adsp_hda.c +++ b/drivers/dma/dma_intel_adsp_hda.c @@ -176,9 +176,7 @@ int intel_adsp_hda_dma_host_reload(const struct device *dev, uint32_t channel, __ASSERT(channel < cfg->dma_channels, "Channel does not exist"); #if CONFIG_DMA_INTEL_ADSP_HDA_TIMING_L1_EXIT -#if CONFIG_SOC_SERIES_INTEL_ACE - ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; -#endif + intel_adsp_force_dmi_l0_state(); switch (cfg->direction) { case HOST_TO_MEMORY: ; /* Only statements can be labeled in C, a declaration is not valid */ @@ -328,6 +326,11 @@ int intel_adsp_hda_dma_stop(const struct device *dev, uint32_t channel) intel_adsp_hda_disable(cfg->base, cfg->regblock_size, channel); + if (!WAIT_FOR(!intel_adsp_hda_is_enabled(cfg->base, cfg->regblock_size, channel), 1000, + k_busy_wait(1))) { + return -EBUSY; + } + return pm_device_runtime_put(dev); } @@ -458,9 +461,7 @@ void intel_adsp_hda_dma_isr(void) } if (clear_l1_exit) { -#if CONFIG_SOC_SERIES_INTEL_ACE - ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); -#endif + intel_adsp_allow_dmi_l1_state(); } #endif } diff --git a/drivers/dma/dma_intel_lpss.c b/drivers/dma/dma_intel_lpss.c index 7d0fec20045..ad004fc1cf8 100644 --- a/drivers/dma/dma_intel_lpss.c +++ b/drivers/dma/dma_intel_lpss.c @@ -24,7 +24,6 @@ LOG_MODULE_REGISTER(dma_intel_lpss, CONFIG_DMA_LOG_LEVEL); struct dma_intel_lpss_cfg { struct dw_dma_dev_cfg dw_cfg; - const struct device *parent; }; int dma_intel_lpss_setup(const struct device *dev) @@ -45,30 +44,13 @@ void dma_intel_lpss_set_base(const struct device *dev, uintptr_t base) dev_cfg->dw_cfg.base = base; } -static int dma_intel_lpss_init(const struct device *dev) -{ - struct dma_intel_lpss_cfg *dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; - uint32_t base; - int ret; - - if (device_is_ready(dev_cfg->parent)) { - base = DEVICE_MMIO_GET(dev_cfg->parent) + DMA_INTEL_LPSS_OFFSET; - dev_cfg->dw_cfg.base = base; - } - - ret = dma_intel_lpss_setup(dev); - - if (ret != 0) { - LOG_ERR("failed to initialize LPSS DMA %s", dev->name); - goto out; - } - ret = 0; -out: - return ret; -} - +#ifdef CONFIG_DMA_64BIT int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, uint64_t src, uint64_t dst, size_t size) +#else +int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, + uint32_t src, uint32_t dst, size_t size) +#endif { struct dw_dma_dev_data *const dev_data = dev->data; struct dma_intel_lpss_cfg *lpss_dev_cfg = (struct dma_intel_lpss_cfg *)dev->config; @@ -76,7 +58,7 @@ int dma_intel_lpss_reload(const struct device *dev, uint32_t channel, struct dw_dma_chan_data *chan_data; uint32_t ctrl_hi = 0; - if (channel >= DW_MAX_CHAN) { + if (channel >= DW_CHAN_COUNT) { return -EINVAL; } @@ -155,12 +137,6 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .stop = dw_dma_stop, }; -#define DMA_LPSS_INIT_VAL_0 49 /* When parent device depends on DMA */ -#define DMA_LPSS_INIT_VAL_1 80 /* When DMA device depends on parent */ - -#define DMA_LPSS_INIT_VAL(n)\ - _CONCAT(DMA_LPSS_INIT_VAL_, DT_INST_NODE_HAS_PROP(n, dma_parent)) - #define DMA_INTEL_LPSS_INIT(n) \ \ static struct dw_drv_plat_data dma_intel_lpss##n = { \ @@ -179,8 +155,6 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { .dw_cfg = { \ .base = 0, \ }, \ - IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dma_parent), \ - (.parent = DEVICE_DT_GET(DT_INST_PHANDLE(n, dma_parent)),))\ }; \ \ static struct dw_dma_dev_data dma_intel_lpss##n##_data = { \ @@ -188,11 +162,11 @@ static const struct dma_driver_api dma_intel_lpss_driver_api = { }; \ \ DEVICE_DT_INST_DEFINE(n, \ - &dma_intel_lpss_init, \ + NULL, \ NULL, \ &dma_intel_lpss##n##_data, \ - &dma_intel_lpss##n##_config, POST_KERNEL, \ - DMA_LPSS_INIT_VAL(n), \ + &dma_intel_lpss##n##_config, PRE_KERNEL_1, \ + CONFIG_DMA_INIT_PRIORITY, \ &dma_intel_lpss_driver_api); \ DT_INST_FOREACH_STATUS_OKAY(DMA_INTEL_LPSS_INIT) diff --git a/drivers/dma/dma_mcux_lpc.c b/drivers/dma/dma_mcux_lpc.c index ef0a164d4af..f8d9ab81e08 100644 --- a/drivers/dma/dma_mcux_lpc.c +++ b/drivers/dma/dma_mcux_lpc.c @@ -41,6 +41,8 @@ struct channel_data { void *user_data; dma_callback_t dma_callback; enum dma_channel_direction dir; + uint8_t src_inc; + uint8_t dst_inc; dma_descriptor_t *curr_descriptor; uint8_t num_of_descriptors; bool descriptors_queued; @@ -83,17 +85,19 @@ static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param, struct channel_data *data = (struct channel_data *)param; uint32_t channel = handle->channel; - if (transferDone) { - ret = DMA_STATUS_COMPLETE; - } - if (intmode == kDMA_IntError) { DMA_AbortTransfer(handle); + } else if (intmode == kDMA_IntA) { + ret = DMA_STATUS_BLOCK; + } else { + ret = DMA_STATUS_COMPLETE; } data->busy = DMA_ChannelIsBusy(data->dma_handle.base, channel); - data->dma_callback(data->dev, data->user_data, channel, ret); + if (data->dma_callback) { + data->dma_callback(data->dev, data->user_data, channel, ret); + } } /* Handles DMA interrupts and dispatches to the individual channel */ @@ -113,16 +117,21 @@ static void dma_mcux_lpc_irq_handler(const struct device *dev) static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, struct dma_block_config *block, uint8_t src_inc, - uint8_t dest_inc) + uint8_t dest_inc, + bool callback_en) { uint32_t xfer_config = 0U; dma_descriptor_t *next_descriptor = NULL; uint32_t width = data->width; uint32_t max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; bool setup_extra_descriptor = false; - uint8_t enable_interrupt; + /* intA is used to indicate transfer of a block */ + uint8_t enable_a_interrupt; + /* intB is used to indicate complete transfer of the list of blocks */ + uint8_t enable_b_interrupt; uint8_t reload; struct dma_block_config local_block; + bool last_block = false; memcpy(&local_block, block, sizeof(struct dma_block_config)); @@ -146,6 +155,7 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, } else { /* Check if this is the last block to transfer */ if (local_block.next_block == NULL) { + last_block = true; /* Last descriptor, check if we should setup a * circular chain */ @@ -187,9 +197,20 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, /* Fire an interrupt after the whole block has been transferred */ if (local_block.block_size > max_xfer_bytes) { - enable_interrupt = 0; + enable_a_interrupt = 0; + enable_b_interrupt = 0; } else { - enable_interrupt = 1; + /* Use intB when this is the end of the block list and transfer */ + if (last_block) { + enable_a_interrupt = 0; + enable_b_interrupt = 1; + } else { + /* Use intA when we need an interrupt per block + * Enable or disable intA based on user configuration + */ + enable_a_interrupt = callback_en; + enable_b_interrupt = 0; + } } /* Reload if we have more descriptors */ @@ -200,7 +221,8 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, } /* Enable interrupt and reload for the descriptor */ - xfer_config = DMA_CHANNEL_XFER(reload, 0UL, enable_interrupt, 0U, + xfer_config = DMA_CHANNEL_XFER(reload, 0UL, enable_a_interrupt, + enable_b_interrupt, width, src_inc, dest_inc, @@ -239,8 +261,10 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, /* Leave curr pointer unchanged so we start queuing new data from * this descriptor */ - /* Enable interrupt and reload for the descriptor */ - xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, 1U, 0U, + /* Enable or disable interrupt based on user request. + * Reload for the descriptor. + */ + xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, callback_en, 0U, width, src_inc, dest_inc, @@ -257,6 +281,17 @@ static int dma_mcux_lpc_queue_descriptors(struct channel_data *data, return 0; } +static void dma_mcux_lpc_clear_channel_data(struct channel_data *data) +{ + data->dma_callback = NULL; + data->dir = 0; + data->src_inc = 0; + data->dst_inc = 0; + data->descriptors_queued = false; + data->num_of_descriptors = 0; + data->curr_descriptor = NULL; + data->width = 0; +} /* Configure a channel */ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, @@ -270,11 +305,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, struct dma_block_config *block_config; uint32_t virtual_channel; uint8_t otrig_index; - uint8_t src_inc, dst_inc; + uint8_t src_inc = 1, dst_inc = 1; bool is_periph = true; uint8_t width; uint32_t max_xfer_bytes; uint8_t reload = 0; + bool complete_callback; if (NULL == dev || NULL == config) { return -EINVAL; @@ -290,6 +326,15 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, */ assert(config->dest_data_size == config->source_data_size); width = config->dest_data_size; + + /* If skip is set on both source and destination + * then skip by the same amount on both sides + */ + if (block_config->source_gather_en && block_config->dest_scatter_en) { + assert(block_config->source_gather_interval == + block_config->dest_scatter_interval); + } + max_xfer_bytes = NXP_LPC_DMA_MAX_XFER * width; /* @@ -329,16 +374,53 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, switch (config->channel_direction) { case MEMORY_TO_MEMORY: is_periph = false; - src_inc = 1; - dst_inc = 1; + if (block_config->source_gather_en) { + src_inc = block_config->source_gather_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((src_inc > 4) || (src_inc == 3)) { + return -EINVAL; + } + } + + if (block_config->dest_scatter_en) { + dst_inc = block_config->dest_scatter_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((dst_inc > 4) || (dst_inc == 3)) { + return -EINVAL; + } + } break; case MEMORY_TO_PERIPHERAL: - src_inc = 1; + /* Set the source increment value */ + if (block_config->source_gather_en) { + src_inc = block_config->source_gather_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((src_inc > 4) || (src_inc == 3)) { + return -EINVAL; + } + } + dst_inc = 0; break; case PERIPHERAL_TO_MEMORY: src_inc = 0; - dst_inc = 1; + + /* Set the destination increment value */ + if (block_config->dest_scatter_en) { + dst_inc = block_config->dest_scatter_interval / width; + /* The current controller only supports incrementing the + * source and destination up to 4 time transfer width + */ + if ((dst_inc > 4) || (dst_inc == 3)) { + return -EINVAL; + } + } break; default: LOG_ERR("not support transfer direction"); @@ -374,7 +456,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, data = DEV_CHANNEL_DATA(dev, virtual_channel); } + dma_mcux_lpc_clear_channel_data(data); + data->dir = config->channel_direction; + /* Save the increment values for the reload function */ + data->src_inc = src_inc; + data->dst_inc = dst_inc; if (data->busy) { DMA_AbortTransfer(p_handle); @@ -384,10 +471,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, k_spinlock_key_t otrigs_key = k_spin_lock(&configuring_otrigs); - data->descriptors_queued = false; - data->num_of_descriptors = 0; data->width = width; - data->curr_descriptor = NULL; + if (config->source_chaining_en || config->dest_chaining_en) { /* Chaining is enabled */ if (!dev_config->otrig_base_address || !dev_config->itrig_base_address) { @@ -462,6 +547,8 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, k_spin_unlock(&configuring_otrigs, otrigs_key); + complete_callback = config->complete_callback_en; + /* Check if we need to queue DMA descriptors */ if ((block_config->block_size > max_xfer_bytes) || (block_config->next_block != NULL)) { @@ -478,9 +565,10 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, dst_inc, max_xfer_bytes); } else { - /* Enable interrupt and reload for the descriptor + /* Enable INTA interrupt if user requested DMA for each block. + * Reload for the descriptor. */ - xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, 1UL, 0UL, + xfer_config = DMA_CHANNEL_XFER(1UL, 0UL, complete_callback, 0UL, width, src_inc, dst_inc, @@ -528,7 +616,13 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, local_block.next_block = block_config->next_block; local_block.source_reload_en = reload; - if (dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc)) { + if (block_config->next_block == NULL) { + /* This is the last block, enable callback. */ + complete_callback = true; + } + + if (dma_mcux_lpc_queue_descriptors(data, &local_block, + src_inc, dst_inc, complete_callback)) { return -ENOMEM; } } @@ -544,7 +638,12 @@ static int dma_mcux_lpc_configure(const struct device *dev, uint32_t channel, assert(block_config->dest_address == ROUND_UP(block_config->dest_address, width)); - if (dma_mcux_lpc_queue_descriptors(data, block_config, src_inc, dst_inc)) { + if (block_config->next_block == NULL) { + /* This is the last block. Enable callback if not enabled. */ + complete_callback = true; + } + if (dma_mcux_lpc_queue_descriptors(data, block_config, + src_inc, dst_inc, complete_callback)) { return -ENOMEM; } @@ -631,26 +730,11 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, struct dma_mcux_lpc_dma_data *dev_data = dev->data; int8_t virtual_channel = dev_data->channel_index[channel]; struct channel_data *data = DEV_CHANNEL_DATA(dev, virtual_channel); - uint8_t src_inc, dst_inc; uint32_t xfer_config = 0U; - switch (data->dir) { - case MEMORY_TO_MEMORY: - src_inc = 1; - dst_inc = 1; - break; - case MEMORY_TO_PERIPHERAL: - src_inc = 1; - dst_inc = 0; - break; - case PERIPHERAL_TO_MEMORY: - src_inc = 0; - dst_inc = 1; - break; - default: - LOG_ERR("not support transfer direction"); - return -EINVAL; - } + /* DMA controller requires that the address be aligned to transfer size */ + assert(src == ROUND_UP(src, data->width)); + assert(dst == ROUND_UP(dst, data->width)); if (!data->descriptors_queued) { dma_handle_t *p_handle; @@ -660,8 +744,8 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, /* Only one buffer, enable interrupt */ xfer_config = DMA_CHANNEL_XFER(0UL, 0UL, 1UL, 0UL, data->width, - src_inc, - dst_inc, + data->src_inc, + data->dst_inc, size); DMA_SubmitChannelTransferParameter(p_handle, xfer_config, @@ -675,7 +759,8 @@ static int dma_mcux_lpc_reload(const struct device *dev, uint32_t channel, local_block.dest_address = dst; local_block.block_size = size; local_block.source_reload_en = 1; - dma_mcux_lpc_queue_descriptors(data, &local_block, src_inc, dst_inc); + dma_mcux_lpc_queue_descriptors(data, &local_block, + data->src_inc, data->dst_inc, true); } return 0; diff --git a/drivers/dma/dma_mcux_smartdma.c b/drivers/dma/dma_mcux_smartdma.c index b1870b3959c..9899797ae53 100644 --- a/drivers/dma/dma_mcux_smartdma.c +++ b/drivers/dma/dma_mcux_smartdma.c @@ -148,12 +148,12 @@ static int dma_mcux_smartdma_start(const struct device *dev, uint32_t channel) { const struct dma_mcux_smartdma_config *config = dev->config; -#ifdef CONFIG_PM /* Block PM transition until DMA completes */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Kick off SMARTDMA */ config->base->CTRL = SMARTDMA_MAGIC | SMARTDMA_BOOT; + return 0; } @@ -162,12 +162,13 @@ static int dma_mcux_smartdma_stop(const struct device *dev, uint32_t channel) { ARG_UNUSED(dev); ARG_UNUSED(channel); + /* Stop DMA */ SMARTDMA_Reset(); -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + return 0; } @@ -195,10 +196,9 @@ static void dma_mcux_smartdma_irq(const struct device *dev) if (data->callback) { data->callback(dev, data->user_data, 0, 0); } -#ifdef CONFIG_PM + /* Release PM lock */ pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /** diff --git a/drivers/dma/dma_nxp_edma.c b/drivers/dma/dma_nxp_edma.c new file mode 100644 index 00000000000..aea1e25a5f0 --- /dev/null +++ b/drivers/dma/dma_nxp_edma.c @@ -0,0 +1,669 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "dma_nxp_edma.h" + +/* TODO list: + * 1) Support for requesting a specific channel. + * 2) Support for checking if DMA transfer is pending when attempting config. (?) + * 3) Support for error interrupt. + * 4) Support for error if buffer overflow/underrun. + * 5) Ideally, HALFMAJOR should be set on a per-channel basis not through a + * config. If not possible, this should be done through a DTS property. Also, + * maybe do the same for INTMAJOR IRQ. + */ + +static void edma_isr(const void *parameter) +{ + const struct edma_config *cfg; + struct edma_data *data; + struct edma_channel *chan; + int ret; + uint32_t update_size; + + chan = (struct edma_channel *)parameter; + cfg = chan->dev->config; + data = chan->dev->data; + + if (!EDMA_ChannelRegRead(data->hal_cfg, chan->id, EDMA_TCD_CH_INT)) { + /* skip, interrupt was probably triggered by another channel */ + return; + } + + /* clear interrupt */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan->id, + EDMA_TCD_CH_INT, EDMA_TCD_CH_INT_MASK, 0); + + if (chan->cyclic_buffer) { + update_size = chan->bsize; + + if (IS_ENABLED(CONFIG_DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ)) { + update_size = chan->bsize / 2; + } else { + update_size = chan->bsize; + } + + /* TODO: add support for error handling here */ + ret = EDMA_CHAN_PRODUCE_CONSUME_A(chan, update_size); + if (ret < 0) { + LOG_ERR("chan %d buffer overflow/underrun", chan->id); + } + } + + /* TODO: are there any sanity checks we have to perform before invoking + * the registered callback? + */ + if (chan->cb) { + chan->cb(chan->dev, chan->arg, chan->id, DMA_STATUS_COMPLETE); + } +} + +static struct edma_channel *lookup_channel(const struct device *dev, + uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + int i; + + data = dev->data; + cfg = dev->config; + + + /* optimization: if dma-channels property is present then + * the channel data associated with the passed channel ID + * can be found at index chan_id in the array of channels. + */ + if (cfg->contiguous_channels) { + /* check for index out of bounds */ + if (chan_id >= data->ctx.dma_channels) { + return NULL; + } + + return &data->channels[chan_id]; + } + + /* channels are passed through the valid-channels property. + * As such, since some channels may be missing we need to + * look through the entire channels array for an ID match. + */ + for (i = 0; i < data->ctx.dma_channels; i++) { + if (data->channels[i].id == chan_id) { + return &data->channels[i]; + } + } + + return NULL; +} + +static int edma_config(const struct device *dev, uint32_t chan_id, + struct dma_config *dma_cfg) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + uint32_t transfer_type; + int ret; + + data = dev->data; + cfg = dev->config; + + if (!dma_cfg->head_block) { + LOG_ERR("head block shouldn't be NULL"); + return -EINVAL; + } + + /* validate source data size (SSIZE) */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, dma_cfg->source_data_size)) { + LOG_ERR("invalid source data size: %d", + dma_cfg->source_data_size); + return -EINVAL; + } + + /* validate destination data size (DSIZE) */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, dma_cfg->dest_data_size)) { + LOG_ERR("invalid destination data size: %d", + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* validate configured alignment */ + if (!EDMA_TransferWidthIsValid(data->hal_cfg, CONFIG_DMA_NXP_EDMA_ALIGN)) { + LOG_ERR("configured alignment %d is invalid", + CONFIG_DMA_NXP_EDMA_ALIGN); + return -EINVAL; + } + + /* Scatter-Gather configurations currently not supported */ + if (dma_cfg->block_count != 1) { + LOG_ERR("number of blocks %d not supported", dma_cfg->block_count); + return -ENOTSUP; + } + + /* source address shouldn't be NULL */ + if (!dma_cfg->head_block->source_address) { + LOG_ERR("source address cannot be NULL"); + return -EINVAL; + } + + /* destination address shouldn't be NULL */ + if (!dma_cfg->head_block->dest_address) { + LOG_ERR("destination address cannot be NULL"); + return -EINVAL; + } + + /* check source address's (SADDR) alignment with respect to the data size (SSIZE) + * + * Failing to meet this condition will lead to the assertion of the SAE + * bit (see CHn_ES register). + * + * TODO: this will also restrict scenarios such as the following: + * SADDR is 8B aligned and SSIZE is 16B. I've tested this + * scenario and seems to raise no hardware errors (I'm assuming + * because this doesn't break the 8B boundary of the 64-bit system + * I tested it on). Is there a need to allow such a scenario? + */ + if (dma_cfg->head_block->source_address % dma_cfg->source_data_size) { + LOG_ERR("source address 0x%x alignment doesn't match data size %d", + dma_cfg->head_block->source_address, + dma_cfg->source_data_size); + return -EINVAL; + } + + /* check destination address's (DADDR) alignment with respect to the data size (DSIZE) + * Failing to meet this condition will lead to the assertion of the DAE + * bit (see CHn_ES register). + */ + if (dma_cfg->head_block->dest_address % dma_cfg->dest_data_size) { + LOG_ERR("destination address 0x%x alignment doesn't match data size %d", + dma_cfg->head_block->dest_address, + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* source burst length should match destination burst length. + * This is because the burst length is the equivalent of NBYTES which + * is used for both the destination and the source. + */ + if (dma_cfg->source_burst_length != + dma_cfg->dest_burst_length) { + LOG_ERR("source burst length %d doesn't match destination burst length %d", + dma_cfg->source_burst_length, + dma_cfg->dest_burst_length); + return -EINVAL; + } + + /* total number of bytes should be a multiple of NBYTES. + * + * This is needed because the EDMA engine performs transfers based + * on CITER (integer value) and NBYTES, thus it has no knowledge of + * the total transfer size. If the total transfer size is not a + * multiple of NBYTES then we'll end up with copying a wrong number + * of bytes (CITER = TOTAL_SIZE / BITER). This, of course, raises + * no error in the hardware but it's still wrong. + */ + if (dma_cfg->head_block->block_size % dma_cfg->source_burst_length) { + LOG_ERR("block size %d should be a multiple of NBYTES %d", + dma_cfg->head_block->block_size, + dma_cfg->source_burst_length); + return -EINVAL; + } + + /* check if NBYTES is a multiple of MAX(SSIZE, DSIZE). + * + * This stems from the fact that NBYTES needs to be a multiple + * of SSIZE AND DSIZE. If NBYTES is a multiple of MAX(SSIZE, DSIZE) + * then it will for sure satisfy the aforementioned condition (since + * SSIZE and DSIZE are powers of 2). + * + * Failing to meet this condition will lead to the assertion of the + * NCE bit (see CHn_ES register). + */ + if (dma_cfg->source_burst_length % + MAX(dma_cfg->source_data_size, dma_cfg->dest_data_size)) { + LOG_ERR("NBYTES %d should be a multiple of MAX(SSIZE(%d), DSIZE(%d))", + dma_cfg->source_burst_length, + dma_cfg->source_data_size, + dma_cfg->dest_data_size); + return -EINVAL; + } + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* save the block size for later usage in edma_reload */ + chan->bsize = dma_cfg->head_block->block_size; + + if (dma_cfg->cyclic) { + chan->cyclic_buffer = true; + + chan->stat.read_position = 0; + chan->stat.write_position = 0; + + /* ASSUMPTION: for CONSUMER-type channels, the buffer from + * which the engine consumes should be full, while in the + * case of PRODUCER-type channels it should be empty. + */ + switch (dma_cfg->channel_direction) { + case MEMORY_TO_PERIPHERAL: + chan->type = CHAN_TYPE_CONSUMER; + chan->stat.free = 0; + chan->stat.pending_length = chan->bsize; + break; + case PERIPHERAL_TO_MEMORY: + chan->type = CHAN_TYPE_PRODUCER; + chan->stat.pending_length = 0; + chan->stat.free = chan->bsize; + break; + default: + LOG_ERR("unsupported transfer dir %d for cyclic mode", + dma_cfg->channel_direction); + return -ENOTSUP; + } + } else { + chan->cyclic_buffer = false; + } + + /* change channel's state to CONFIGURED */ + ret = channel_change_state(chan, CHAN_STATE_CONFIGURED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to CONFIGURED", chan_id); + return ret; + } + + ret = get_transfer_type(dma_cfg->channel_direction, &transfer_type); + if (ret < 0) { + return ret; + } + + chan->cb = dma_cfg->dma_callback; + chan->arg = dma_cfg->user_data; + + /* warning: this sets SOFF and DOFF to SSIZE and DSIZE which are POSITIVE. */ + ret = EDMA_ConfigureTransfer(data->hal_cfg, chan_id, + dma_cfg->head_block->source_address, + dma_cfg->head_block->dest_address, + dma_cfg->source_data_size, + dma_cfg->dest_data_size, + dma_cfg->source_burst_length, + dma_cfg->head_block->block_size, + transfer_type); + if (ret < 0) { + LOG_ERR("failed to configure transfer"); + return to_std_error(ret); + } + + /* TODO: channel MUX should be forced to 0 based on the previous state */ + if (EDMA_HAS_MUX(data->hal_cfg)) { + ret = EDMA_SetChannelMux(data->hal_cfg, chan_id, dma_cfg->dma_slot); + if (ret < 0) { + LOG_ERR("failed to set channel MUX"); + return to_std_error(ret); + } + } + + /* set SLAST and DLAST */ + ret = set_slast_dlast(dma_cfg, transfer_type, data, chan_id); + if (ret < 0) { + return ret; + } + + /* allow interrupting the CPU when a major cycle is completed. + * + * interesting note: only 1 major loop is performed per slave peripheral + * DMA request. For instance, if block_size = 768 and burst_size = 192 + * we're going to get 4 transfers of 192 bytes. Each of these transfers + * translates to a DMA request made by the slave peripheral. + */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CSR, EDMA_TCD_CSR_INTMAJOR_MASK, 0); + + if (IS_ENABLED(CONFIG_DMA_NXP_EDMA_ENABLE_HALFMAJOR_IRQ)) { + /* if enabled through the above configuration, also + * allow the CPU to be interrupted when CITER = BITER / 2. + */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, EDMA_TCD_CSR, + EDMA_TCD_CSR_INTHALF_MASK, 0); + } + + /* enable channel interrupt */ + irq_enable(chan->irq); + + /* dump register status - for debugging purposes */ + edma_dump_channel_registers(data, chan_id); + + return 0; +} + +static int edma_get_status(const struct device *dev, uint32_t chan_id, + struct dma_status *stat) +{ + struct edma_data *data; + struct edma_channel *chan; + uint32_t citer, biter, done; + unsigned int key; + + data = dev->data; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + if (chan->cyclic_buffer) { + key = irq_lock(); + + stat->free = chan->stat.free; + stat->pending_length = chan->stat.pending_length; + + irq_unlock(key); + } else { + /* note: no locking required here. The DMA interrupts + * have no effect over CITER and BITER. + */ + citer = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CITER); + biter = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_BITER); + done = EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR) & + EDMA_TCD_CH_CSR_DONE_MASK; + if (done) { + stat->free = chan->bsize; + stat->pending_length = 0; + } else { + stat->free = (biter - citer) * (chan->bsize / biter); + stat->pending_length = chan->bsize - stat->free; + } + } + + LOG_DBG("free: %d, pending: %d", stat->free, stat->pending_length); + + return 0; +} + +static int edma_suspend(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + edma_dump_channel_registers(data, chan_id); + + /* change channel's state to SUSPENDED */ + ret = channel_change_state(chan, CHAN_STATE_SUSPENDED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to SUSPENDED", chan_id); + return ret; + } + + LOG_DBG("suspending channel %u", chan_id); + + /* disable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CH_CSR, 0, EDMA_TCD_CH_CSR_ERQ_MASK); + + return 0; +} + +static int edma_stop(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + enum channel_state prev_state; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + prev_state = chan->state; + + /* change channel's state to STOPPED */ + ret = channel_change_state(chan, CHAN_STATE_STOPPED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to STOPPED", chan_id); + return ret; + } + + LOG_DBG("stopping channel %u", chan_id); + + if (prev_state == CHAN_STATE_SUSPENDED) { + /* if the channel has been suspended then there's + * no point in disabling the HW requests again. Just + * jump to the channel release operation. + */ + goto out_release_channel; + } + + /* disable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR, 0, + EDMA_TCD_CH_CSR_ERQ_MASK); +out_release_channel: + + /* clear the channel MUX so that it can used by a different peripheral. + * + * note: because the channel is released during dma_stop() that means + * dma_start() can no longer be immediately called. This is because + * one needs to re-configure the channel MUX which can only be done + * through dma_config(). As such, if one intends to reuse the current + * configuration then please call dma_suspend() instead of dma_stop(). + */ + if (EDMA_HAS_MUX(data->hal_cfg)) { + ret = EDMA_SetChannelMux(data->hal_cfg, chan_id, 0); + if (ret < 0) { + LOG_ERR("failed to set channel MUX"); + return to_std_error(ret); + } + } + + edma_dump_channel_registers(data, chan_id); + + return 0; +} + +static int edma_start(const struct device *dev, uint32_t chan_id) +{ + struct edma_data *data; + const struct edma_config *cfg; + struct edma_channel *chan; + int ret; + + data = dev->data; + cfg = dev->config; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* change channel's state to STARTED */ + ret = channel_change_state(chan, CHAN_STATE_STARTED); + if (ret < 0) { + LOG_ERR("failed to change channel %d state to STARTED", chan_id); + return ret; + } + + LOG_DBG("starting channel %u", chan_id); + + /* enable HW requests */ + EDMA_ChannelRegUpdate(data->hal_cfg, chan_id, + EDMA_TCD_CH_CSR, EDMA_TCD_CH_CSR_ERQ_MASK, 0); + + return 0; +} + +static int edma_reload(const struct device *dev, uint32_t chan_id, uint32_t src, + uint32_t dst, size_t size) +{ + struct edma_data *data; + struct edma_channel *chan; + int ret; + unsigned int key; + + data = dev->data; + + /* fetch channel data */ + chan = lookup_channel(dev, chan_id); + if (!chan) { + LOG_ERR("channel ID %u is not valid", chan_id); + return -EINVAL; + } + + /* channel needs to be started to allow reloading */ + if (chan->state != CHAN_STATE_STARTED) { + LOG_ERR("reload is only supported on started channels"); + return -EINVAL; + } + + if (chan->cyclic_buffer) { + key = irq_lock(); + ret = EDMA_CHAN_PRODUCE_CONSUME_B(chan, size); + irq_unlock(key); + if (ret < 0) { + LOG_ERR("chan %d buffer overflow/underrun", chan_id); + return ret; + } + } + + return 0; +} + +static int edma_get_attribute(const struct device *dev, uint32_t type, uint32_t *val) +{ + switch (type) { + case DMA_ATTR_BUFFER_SIZE_ALIGNMENT: + case DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT: + *val = CONFIG_DMA_NXP_EDMA_ALIGN; + break; + case DMA_ATTR_MAX_BLOCK_COUNT: + /* this is restricted to 1 because SG configurations are not supported */ + *val = 1; + break; + default: + LOG_ERR("invalid attribute type: %d", type); + return -EINVAL; + } + + return 0; +} + +static const struct dma_driver_api edma_api = { + .reload = edma_reload, + .config = edma_config, + .start = edma_start, + .stop = edma_stop, + .suspend = edma_suspend, + .resume = edma_start, + .get_status = edma_get_status, + .get_attribute = edma_get_attribute, +}; + +static int edma_init(const struct device *dev) +{ + const struct edma_config *cfg; + struct edma_data *data; + mm_reg_t regmap; + + data = dev->data; + cfg = dev->config; + + /* map instance MMIO */ + device_map(®map, cfg->regmap_phys, cfg->regmap_size, K_MEM_CACHE_NONE); + + /* overwrite physical address set in the HAL configuration. + * We can down-cast the virtual address to a 32-bit address because + * we know we're working with 32-bit addresses only. + */ + data->hal_cfg->regmap = (uint32_t)POINTER_TO_UINT(regmap); + + cfg->irq_config(); + + /* dma_request_channel() uses this variable to keep track of the + * available channels. As such, it needs to be initialized with NULL + * which signifies that all channels are initially available. + */ + data->channel_flags = ATOMIC_INIT(0); + data->ctx.atomic = &data->channel_flags; + + return 0; +} + +/* a few comments about the BUILD_ASSERT statements: + * 1) dma-channels and valid-channels should be mutually exclusive. + * This means that you specify the one or the other. There's no real + * need to have both of them. + * 2) Number of channels should match the number of interrupts for + * said channels (TODO: what about error interrupts?) + * 3) The channel-mux property shouldn't be specified unless + * the eDMA is MUX-capable (signaled via the EDMA_HAS_CHAN_MUX + * configuration). + */ +#define EDMA_INIT(inst) \ + \ +BUILD_ASSERT(!DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels) || \ + !DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), valid_channels), \ + "dma_channels and valid_channels are mutually exclusive"); \ + \ +BUILD_ASSERT(DT_INST_PROP_OR(inst, dma_channels, 0) == \ + DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)) || \ + DT_INST_PROP_LEN_OR(inst, valid_channels, 0) == \ + DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)), \ + "number of interrupts needs to match number of channels"); \ + \ +BUILD_ASSERT(DT_PROP_OR(DT_INST(inst, DT_DRV_COMPAT), hal_cfg_index, 0) < \ + ARRAY_SIZE(s_edmaConfigs), \ + "HAL configuration index out of bounds"); \ + \ +static struct edma_channel channels_##inst[] = EDMA_CHANNEL_ARRAY_GET(inst); \ + \ +static void interrupt_config_function_##inst(void) \ +{ \ + EDMA_CONNECT_INTERRUPTS(inst); \ +} \ + \ +static struct edma_config edma_config_##inst = { \ + .regmap_phys = DT_INST_REG_ADDR(inst), \ + .regmap_size = DT_INST_REG_SIZE(inst), \ + .irq_config = interrupt_config_function_##inst, \ + .contiguous_channels = EDMA_CHANS_ARE_CONTIGUOUS(inst), \ +}; \ + \ +static struct edma_data edma_data_##inst = { \ + .channels = channels_##inst, \ + .ctx.dma_channels = ARRAY_SIZE(channels_##inst), \ + .ctx.magic = DMA_MAGIC, \ + .hal_cfg = &EDMA_HAL_CFG_GET(inst), \ +}; \ + \ +DEVICE_DT_INST_DEFINE(inst, &edma_init, NULL, \ + &edma_data_##inst, &edma_config_##inst, \ + PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ + &edma_api); \ + +DT_INST_FOREACH_STATUS_OKAY(EDMA_INIT); diff --git a/drivers/dma/dma_nxp_edma.h b/drivers/dma/dma_nxp_edma.h new file mode 100644 index 00000000000..234b3fcb70a --- /dev/null +++ b/drivers/dma/dma_nxp_edma.h @@ -0,0 +1,530 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ +#define ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ + +#include +#include +#include +#include + +#include "fsl_edma_soc_rev2.h" + +LOG_MODULE_REGISTER(nxp_edma); + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_edma + +/* workaround the fact that device_map() is not defined for SoCs with no MMU */ +#ifndef DEVICE_MMIO_IS_IN_RAM +#define device_map(virt, phys, size, flags) *(virt) = (phys) +#endif /* DEVICE_MMIO_IS_IN_RAM */ + +/* macros used to parse DTS properties */ + +/* used in conjunction with LISTIFY which expects F to also take a variable + * number of arguments. Since IDENTITY doesn't do that we need to use a version + * of it which also takes a variable number of arguments. + */ +#define IDENTITY_VARGS(V, ...) IDENTITY(V) + +/* used to generate an array of indexes for the channels */ +#define _EDMA_CHANNEL_INDEX_ARRAY(inst)\ + LISTIFY(DT_INST_PROP_LEN_OR(inst, valid_channels, 0), IDENTITY_VARGS, (,)) + +/* used to generate an array of indexes for the channels - this is different + * from _EDMA_CHANNEL_INDEX_ARRAY because the number of channels is passed + * explicitly through dma-channels so no need to deduce it from the length + * of the valid-channels property. + */ +#define _EDMA_CHANNEL_INDEX_ARRAY_EXPLICIT(inst)\ + LISTIFY(DT_INST_PROP_OR(inst, dma_channels, 0), IDENTITY_VARGS, (,)) + +/* used to generate an array of indexes for the interrupt */ +#define _EDMA_INT_INDEX_ARRAY(inst)\ + LISTIFY(DT_NUM_IRQS(DT_INST(inst, DT_DRV_COMPAT)), IDENTITY_VARGS, (,)) + +/* used to register an ISR/arg pair. TODO: should we also use the priority? */ +#define _EDMA_INT_CONNECT(idx, inst) \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \ + 0, edma_isr, \ + &channels_##inst[idx], 0) + +/* used to declare a struct edma_channel by the non-explicit macro suite */ +#define _EDMA_CHANNEL_DECLARE(idx, inst) \ +{ \ + .id = DT_INST_PROP_BY_IDX(inst, valid_channels, idx), \ + .dev = DEVICE_DT_INST_GET(inst), \ + .irq = DT_INST_IRQ_BY_IDX(inst, idx, irq), \ +} + +/* used to declare a struct edma_channel by the explicit macro suite */ +#define _EDMA_CHANNEL_DECLARE_EXPLICIT(idx, inst) \ +{ \ + .id = idx, \ + .dev = DEVICE_DT_INST_GET(inst), \ + .irq = DT_INST_IRQ_BY_IDX(inst, idx, irq), \ +} + +/* used to create an array of channel IDs via the valid-channels property */ +#define _EDMA_CHANNEL_ARRAY(inst) \ + { FOR_EACH_FIXED_ARG(_EDMA_CHANNEL_DECLARE, (,), \ + inst, _EDMA_CHANNEL_INDEX_ARRAY(inst)) } + +/* used to create an array of channel IDs via the dma-channels property */ +#define _EDMA_CHANNEL_ARRAY_EXPLICIT(inst) \ + { FOR_EACH_FIXED_ARG(_EDMA_CHANNEL_DECLARE_EXPLICIT, (,), inst, \ + _EDMA_CHANNEL_INDEX_ARRAY_EXPLICIT(inst)) } + +/* used to construct the channel array based on the specified property: + * dma-channels or valid-channels. + */ +#define EDMA_CHANNEL_ARRAY_GET(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels), \ + (_EDMA_CHANNEL_ARRAY_EXPLICIT(inst)), \ + (_EDMA_CHANNEL_ARRAY(inst))) + +#define EDMA_HAL_CFG_GET(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), hal_cfg_index), \ + (s_edmaConfigs[DT_INST_PROP(inst, hal_cfg_index)]), \ + (s_edmaConfigs[0])) + +/* used to register edma_isr for all specified interrupts */ +#define EDMA_CONNECT_INTERRUPTS(inst) \ + FOR_EACH_FIXED_ARG(_EDMA_INT_CONNECT, (;), \ + inst, _EDMA_INT_INDEX_ARRAY(inst)) + +#define EDMA_CHANS_ARE_CONTIGUOUS(inst)\ + DT_NODE_HAS_PROP(DT_INST(inst, DT_DRV_COMPAT), dma_channels) + +/* utility macros */ + +/* a few words about EDMA_CHAN_PRODUCE_CONSUME_{A/B}: + * - in the context of cyclic buffers we introduce + * the concepts of consumer and producer channels. + * + * - a consumer channel is a channel for which the + * DMA copies data from a buffer, thus leading to + * less data in said buffer (data is consumed with + * each transfer). + * + * - a producer channel is a channel for which the + * DMA copies data into a buffer, thus leading to + * more data in said buffer (data is produced with + * each transfer). + * + * - for consumer channels, each DMA interrupt will + * signal that an amount of data has been consumed + * from the buffer (half of the buffer size if + * HALFMAJOR is enabled, the whole buffer otherwise). + * + * - for producer channels, each DMA interrupt will + * signal that an amount of data has been added + * to the buffer. + * + * - to signal this, the ISR uses EDMA_CHAN_PRODUCE_CONSUME_A + * which will "consume" data from the buffer for + * consumer channels and "produce" data for + * producer channels. + * + * - since the upper layers using this driver need + * to let the EDMA driver know whenever they've produced + * (in the case of consumer channels) or consumed + * data (in the case of producer channels) they can + * do so through the reload() function. + * + * - reload() uses EDMA_CHAN_PRODUCE_CONSUME_B which + * for consumer channels will "produce" data and + * "consume" data for producer channels, thus letting + * the driver know what action the upper layer has + * performed (if the channel is a consumer it's only + * natural that the upper layer will write/produce more + * data to the buffer. The same rationale applies to + * producer channels). + * + * - EDMA_CHAN_PRODUCE_CONSUME_B is just the opposite + * of EDMA_CHAN_PRODUCE_CONSUME_A. If one produces + * data, the other will consume and vice-versa. + * + * - all of this information is valid only in the + * context of cyclic buffers. If this behaviour is + * not enabled, querying the status will simply + * resolve to querying CITER and BITER. + */ +#define EDMA_CHAN_PRODUCE_CONSUME_A(chan, size)\ + ((chan)->type == CHAN_TYPE_CONSUMER ?\ + edma_chan_cyclic_consume(chan, size) :\ + edma_chan_cyclic_produce(chan, size)) + +#define EDMA_CHAN_PRODUCE_CONSUME_B(chan, size)\ + ((chan)->type == CHAN_TYPE_CONSUMER ?\ + edma_chan_cyclic_produce(chan, size) :\ + edma_chan_cyclic_consume(chan, size)) + +enum channel_type { + CHAN_TYPE_CONSUMER = 0, + CHAN_TYPE_PRODUCER, +}; + +enum channel_state { + CHAN_STATE_INIT = 0, + CHAN_STATE_CONFIGURED, + CHAN_STATE_STARTED, + CHAN_STATE_STOPPED, + CHAN_STATE_SUSPENDED, +}; + +struct edma_channel { + /* channel ID, needs to be the same as the hardware channel ID */ + uint32_t id; + /* pointer to device representing the EDMA instance, used by edma_isr */ + const struct device *dev; + /* current state of the channel */ + enum channel_state state; + /* type of the channel (PRODUCER/CONSUMER) - only applicable to cyclic + * buffer configurations. + */ + enum channel_type type; + /* argument passed to the user-defined DMA callback */ + void *arg; + /* user-defined callback, called at the end of a channel's interrupt + * handling. + */ + dma_callback_t cb; + /* INTID associated with the channel */ + int irq; + /* the channel's status */ + struct dma_status stat; + /* cyclic buffer size - currently, this is set to head_block's size */ + uint32_t bsize; + /* set to true if the channel uses a cyclic buffer configuration */ + bool cyclic_buffer; +}; + +struct edma_data { + /* this needs to be the first member */ + struct dma_context ctx; + mm_reg_t regmap; + struct edma_channel *channels; + atomic_t channel_flags; + edma_config_t *hal_cfg; +}; + +struct edma_config { + uint32_t regmap_phys; + uint32_t regmap_size; + void (*irq_config)(void); + /* true if channels are contiguous. The channels may not be contiguous + * if the valid-channels property is used instead of dma-channels. This + * is used to improve the time complexity of the channel lookup + * function. + */ + bool contiguous_channels; +}; + +static inline int channel_change_state(struct edma_channel *chan, + enum channel_state next) +{ + enum channel_state prev = chan->state; + + LOG_DBG("attempting to change state from %d to %d for channel %d", prev, next, chan->id); + + /* validate transition */ + switch (prev) { + case CHAN_STATE_INIT: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + case CHAN_STATE_CONFIGURED: + if (next != CHAN_STATE_STARTED) { + return -EPERM; + } + break; + case CHAN_STATE_STARTED: + if (next != CHAN_STATE_STOPPED && + next != CHAN_STATE_SUSPENDED) { + return -EPERM; + } + break; + case CHAN_STATE_STOPPED: + if (next != CHAN_STATE_CONFIGURED) { + return -EPERM; + } + break; + case CHAN_STATE_SUSPENDED: + if (next != CHAN_STATE_STARTED && + next != CHAN_STATE_STOPPED) { + return -EPERM; + } + break; + default: + LOG_ERR("invalid channel previous state: %d", prev); + return -EINVAL; + } + + /* transition OK, proceed */ + chan->state = next; + + return 0; +} + +static inline int get_transfer_type(enum dma_channel_direction dir, uint32_t *type) +{ + switch (dir) { + case MEMORY_TO_MEMORY: + *type = kEDMA_TransferTypeM2M; + break; + case MEMORY_TO_PERIPHERAL: + *type = kEDMA_TransferTypeM2P; + break; + case PERIPHERAL_TO_MEMORY: + *type = kEDMA_TransferTypeP2M; + break; + default: + LOG_ERR("invalid channel direction: %d", dir); + return -EINVAL; + } + + return 0; +} + +static inline bool data_size_is_valid(uint16_t size) +{ + switch (size) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + break; + default: + return false; + } + + return true; +} + +/* TODO: we may require setting the channel type through DTS + * or through struct dma_config. For now, we'll only support + * MEMORY_TO_PERIPHERAL and PERIPHERAL_TO_MEMORY directions + * and assume that these are bound to a certain channel type. + */ +static inline int edma_set_channel_type(struct edma_channel *chan, + enum dma_channel_direction dir) +{ + switch (dir) { + case MEMORY_TO_PERIPHERAL: + chan->type = CHAN_TYPE_CONSUMER; + break; + case PERIPHERAL_TO_MEMORY: + chan->type = CHAN_TYPE_PRODUCER; + break; + default: + LOG_ERR("unsupported transfer direction: %d", dir); + return -ENOTSUP; + } + + return 0; +} + +/* this function is used in cyclic buffer configurations. What it does + * is it updates the channel's read position based on the number of + * bytes requested. If the number of bytes that's being read is higher + * than the number of bytes available in the buffer (pending_length) + * this will lead to an error. The main point of this check is to + * provide a way for the user to determine if data is consumed at a + * higher rate than it is being produced. + * + * This function is used in edma_isr() for CONSUMER channels to mark + * that data has been consumed (i.e: data has been transferred to the + * destination) (this is done via EDMA_CHAN_PRODUCE_CONSUME_A that's + * called in edma_isr()). For producer channels, this function is used + * in edma_reload() to mark the fact that the user of the EDMA driver + * has consumed data. + */ +static inline int edma_chan_cyclic_consume(struct edma_channel *chan, + uint32_t bytes) +{ + if (bytes > chan->stat.pending_length) { + return -EINVAL; + } + + chan->stat.read_position = + (chan->stat.read_position + bytes) % chan->bsize; + + if (chan->stat.read_position > chan->stat.write_position) { + chan->stat.free = chan->stat.read_position - + chan->stat.write_position; + } else if (chan->stat.read_position == chan->stat.write_position) { + chan->stat.free = chan->bsize; + } else { + chan->stat.free = chan->bsize - + (chan->stat.write_position - chan->stat.read_position); + } + + chan->stat.pending_length = chan->bsize - chan->stat.free; + + return 0; +} + +/* this function is used in cyclic buffer configurations. What it does + * is it updates the channel's write position based on the number of + * bytes requested. If the number of bytes that's being written is higher + * than the number of free bytes in the buffer this will lead to an error. + * The main point of this check is to provide a way for the user to determine + * if data is produced at a higher rate than it is being consumed. + * + * This function is used in edma_isr() for PRODUCER channels to mark + * that data has been produced (i.e: data has been transferred to the + * destination) (this is done via EDMA_CHAN_PRODUCE_CONSUME_A that's + * called in edma_isr()). For consumer channels, this function is used + * in edma_reload() to mark the fact that the user of the EDMA driver + * has produced data. + */ +static inline int edma_chan_cyclic_produce(struct edma_channel *chan, + uint32_t bytes) +{ + if (bytes > chan->stat.free) { + return -EINVAL; + } + + chan->stat.write_position = + (chan->stat.write_position + bytes) % chan->bsize; + + if (chan->stat.write_position > chan->stat.read_position) { + chan->stat.pending_length = chan->stat.write_position - + chan->stat.read_position; + } else if (chan->stat.write_position == chan->stat.read_position) { + chan->stat.pending_length = chan->bsize; + } else { + chan->stat.pending_length = chan->bsize - + (chan->stat.read_position - chan->stat.write_position); + } + + chan->stat.free = chan->bsize - chan->stat.pending_length; + + return 0; +} + +static inline void edma_dump_channel_registers(struct edma_data *data, + uint32_t chan_id) +{ + LOG_DBG("dumping channel data for channel %d", chan_id); + + LOG_DBG("CH_CSR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_CSR)); + LOG_DBG("CH_ES: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_ES)); + LOG_DBG("CH_INT: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_INT)); + LOG_DBG("CH_SBR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_SBR)); + LOG_DBG("CH_PRI: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_PRI)); + + if (EDMA_HAS_MUX(data->hal_cfg)) { + LOG_DBG("CH_MUX: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CH_MUX)); + } + + LOG_DBG("TCD_SADDR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SADDR)); + LOG_DBG("TCD_SOFF: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SOFF)); + LOG_DBG("TCD_ATTR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_ATTR)); + LOG_DBG("TCD_NBYTES: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_NBYTES)); + LOG_DBG("TCD_SLAST_SDA: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_SLAST_SDA)); + LOG_DBG("TCD_DADDR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DADDR)); + LOG_DBG("TCD_DOFF: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DOFF)); + LOG_DBG("TCD_CITER: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CITER)); + LOG_DBG("TCD_DLAST_SGA: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_DLAST_SGA)); + LOG_DBG("TCD_CSR: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_CSR)); + LOG_DBG("TCD_BITER: 0x%x", + EDMA_ChannelRegRead(data->hal_cfg, chan_id, EDMA_TCD_BITER)); +} + +static inline int set_slast_dlast(struct dma_config *dma_cfg, + uint32_t transfer_type, + struct edma_data *data, + uint32_t chan_id) +{ + int32_t slast, dlast; + + if (transfer_type == kEDMA_TransferTypeP2M) { + slast = 0; + } else { + switch (dma_cfg->head_block->source_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + slast = (int32_t)dma_cfg->head_block->block_size; + break; + case DMA_ADDR_ADJ_DECREMENT: + slast = (-1) * (int32_t)dma_cfg->head_block->block_size; + break; + default: + LOG_ERR("unsupported SADDR adjustment: %d", + dma_cfg->head_block->source_addr_adj); + return -EINVAL; + } + } + + if (transfer_type == kEDMA_TransferTypeM2P) { + dlast = 0; + } else { + switch (dma_cfg->head_block->dest_addr_adj) { + case DMA_ADDR_ADJ_INCREMENT: + dlast = (int32_t)dma_cfg->head_block->block_size; + break; + case DMA_ADDR_ADJ_DECREMENT: + dlast = (-1) * (int32_t)dma_cfg->head_block->block_size; + break; + default: + LOG_ERR("unsupported DADDR adjustment: %d", + dma_cfg->head_block->dest_addr_adj); + return -EINVAL; + } + } + + LOG_DBG("attempting to commit SLAST %d", slast); + LOG_DBG("attempting to commit DLAST %d", dlast); + + /* commit configuration */ + EDMA_ChannelRegWrite(data->hal_cfg, chan_id, EDMA_TCD_SLAST_SDA, slast); + EDMA_ChannelRegWrite(data->hal_cfg, chan_id, EDMA_TCD_DLAST_SGA, dlast); + + return 0; +} + +/* the NXP HAL EDMA driver uses some custom return values + * that need to be converted to standard error codes. This function + * performs exactly this translation. + */ +static inline int to_std_error(int edma_err) +{ + switch (edma_err) { + case kStatus_EDMA_InvalidConfiguration: + case kStatus_InvalidArgument: + return -EINVAL; + case kStatus_Busy: + return -EBUSY; + default: + LOG_ERR("unknown EDMA error code: %d", edma_err); + return -EINVAL; + } +} + +#endif /* ZEPHYR_DRIVERS_DMA_DMA_NXP_EDMA_H_ */ diff --git a/drivers/dma/dma_stm32.c b/drivers/dma/dma_stm32.c index 64c3b21f5ae..178d83665b4 100644 --- a/drivers/dma/dma_stm32.c +++ b/drivers/dma/dma_stm32.c @@ -123,7 +123,10 @@ static void dma_stm32_irq_handler(const struct device *dev, uint32_t id) stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_BLOCK); } else if (stm32_dma_is_tc_irq_active(dma, id)) { #ifdef CONFIG_DMAMUX_STM32 - stream->busy = false; + /* Circular buffer never stops receiving as long as peripheral is enabled */ + if (!stream->cyclic) { + stream->busy = false; + } #endif /* Let HAL DMA handle flags on its own */ if (!stream->hal_override) { @@ -312,6 +315,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, stream->hal_override = true; stream->dma_callback = config->dma_callback; stream->user_data = config->user_data; + stream->cyclic = false; return 0; } @@ -361,6 +365,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, stream->user_data = config->user_data; stream->src_size = config->source_data_size; stream->dst_size = config->dest_data_size; + stream->cyclic = config->head_block->source_reload_en; /* Check dest or source memory address, warn if 0 */ if (config->head_block->source_address == 0) { @@ -432,7 +437,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, LOG_DBG("Channel (%d) peripheral inc (%x).", id, DMA_InitStruct.PeriphOrM2MSrcIncMode); - if (config->head_block->source_reload_en) { + if (stream->cyclic) { DMA_InitStruct.Mode = LL_DMA_MODE_CIRCULAR; } else { DMA_InitStruct.Mode = LL_DMA_MODE_NORMAL; @@ -494,7 +499,7 @@ DMA_STM32_EXPORT_API int dma_stm32_configure(const struct device *dev, LL_DMA_EnableIT_TC(dma, dma_stm32_id_to_stream(id)); /* Enable Half-Transfer irq if circular mode is enabled */ - if (config->head_block->source_reload_en) { + if (stream->cyclic) { LL_DMA_EnableIT_HT(dma, dma_stm32_id_to_stream(id)); } @@ -688,20 +693,6 @@ static const struct dma_driver_api dma_funcs = { .get_status = dma_stm32_get_status, }; -#ifdef CONFIG_DMAMUX_STM32 -#define DMA_STM32_OFFSET_INIT(index) \ - .offset = DT_INST_PROP(index, dma_offset), -#else -#define DMA_STM32_OFFSET_INIT(index) -#endif /* CONFIG_DMAMUX_STM32 */ - -#ifdef CONFIG_DMA_STM32_V1 -#define DMA_STM32_MEM2MEM_INIT(index) \ - .support_m2m = DT_INST_PROP(index, st_mem2mem), -#else -#define DMA_STM32_MEM2MEM_INIT(index) -#endif /* CONFIG_DMA_STM32_V1 */ \ - #define DMA_STM32_INIT_DEV(index) \ static struct dma_stm32_stream \ dma_stm32_streams_##index[DMA_STM32_##index##_STREAM_COUNT]; \ @@ -711,10 +702,12 @@ const struct dma_stm32_config dma_stm32_config_##index = { \ .enr = DT_INST_CLOCKS_CELL(index, bits) }, \ .config_irq = dma_stm32_config_irq_##index, \ .base = DT_INST_REG_ADDR(index), \ - DMA_STM32_MEM2MEM_INIT(index) \ + IF_ENABLED(CONFIG_DMA_STM32_V1, \ + (.support_m2m = DT_INST_PROP(index, st_mem2mem),)) \ .max_streams = DMA_STM32_##index##_STREAM_COUNT, \ .streams = dma_stm32_streams_##index, \ - DMA_STM32_OFFSET_INIT(index) \ + IF_ENABLED(CONFIG_DMAMUX_STM32, \ + (.offset = DT_INST_PROP(index, dma_offset),)) \ }; \ \ static struct dma_stm32_data dma_stm32_data_##index = { \ diff --git a/drivers/dma/dma_stm32.h b/drivers/dma/dma_stm32.h index 9e88b7dfc2d..f21cb07e183 100644 --- a/drivers/dma/dma_stm32.h +++ b/drivers/dma/dma_stm32.h @@ -27,6 +27,7 @@ struct dma_stm32_stream { uint32_t dst_size; void *user_data; /* holds the client data */ dma_callback_t dma_callback; + bool cyclic; }; struct dma_stm32_data { diff --git a/drivers/eeprom/eeprom_mchp_xec.c b/drivers/eeprom/eeprom_mchp_xec.c index bd1c83e4c74..171940a008d 100644 --- a/drivers/eeprom/eeprom_mchp_xec.c +++ b/drivers/eeprom/eeprom_mchp_xec.c @@ -241,9 +241,8 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW READ */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_READ) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_READ) { @@ -252,9 +251,7 @@ static int eeprom_xec_read(const struct device *dev, off_t offset, eeprom_xec_data_read_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; @@ -280,9 +277,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, } k_mutex_lock(&data->lock_mtx, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* EEPROM HW WRITE */ for (chunk_idx = 0; chunk_idx < len; chunk_idx += XEC_EEPROM_TRANSFER_SIZE_WRITE) { if ((len-chunk_idx) < XEC_EEPROM_TRANSFER_SIZE_WRITE) { @@ -291,9 +287,8 @@ static int eeprom_xec_write(const struct device *dev, off_t offset, eeprom_xec_data_write_32_bytes(regs, &data_buf[chunk_idx], chunk_size, (offset+chunk_idx)); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif k_mutex_unlock(&data->lock_mtx); return 0; diff --git a/drivers/eeprom/eeprom_simulator.c b/drivers/eeprom/eeprom_simulator.c index 2e8d0ca6650..19efa5b3d9d 100644 --- a/drivers/eeprom/eeprom_simulator.c +++ b/drivers/eeprom/eeprom_simulator.c @@ -7,6 +7,20 @@ #define DT_DRV_COMPAT zephyr_sim_eeprom +#ifdef CONFIG_ARCH_POSIX +#undef _POSIX_C_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include "cmdline.h" +#include "soc.h" +#endif + #include #include @@ -17,15 +31,6 @@ #include #include -#ifdef CONFIG_ARCH_POSIX -#include -#include -#include -#include -#include "cmdline.h" -#include "soc.h" -#endif - #define LOG_LEVEL CONFIG_EEPROM_LOG_LEVEL #include LOG_MODULE_REGISTER(eeprom_simulator); diff --git a/drivers/entropy/CMakeLists.txt b/drivers/entropy/CMakeLists.txt index 99184f3b1e5..11e361517c2 100644 --- a/drivers/entropy/CMakeLists.txt +++ b/drivers/entropy/CMakeLists.txt @@ -17,7 +17,15 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_SAM_RNG entropy_sam.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_SMARTBOND_TRNG entropy_smartbond.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_STM32_RNG entropy_stm32.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_LITEX_RNG entropy_litex.c) -zephyr_library_sources_ifdef(CONFIG_FAKE_ENTROPY_NATIVE_POSIX fake_entropy_native_posix.c) +if(CONFIG_FAKE_ENTROPY_NATIVE_POSIX) + zephyr_library_sources(fake_entropy_native_posix.c) + if(CONFIG_NATIVE_LIBRARY) + target_sources(native_simulator INTERFACE fake_entropy_native_bottom.c) + else() + zephyr_library_sources(fake_entropy_native_bottom.c) + endif() +endif() + zephyr_library_sources_ifdef(CONFIG_USERSPACE entropy_handlers.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_RV32M1_TRNG entropy_rv32m1_trng.c) zephyr_library_sources_ifdef(CONFIG_ENTROPY_GECKO_TRNG entropy_gecko_trng.c) @@ -28,6 +36,6 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_PSA_CRYPTO_RNG entropy_psa_crypt if (CONFIG_BUILD_WITH_TFM) target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/drivers/entropy/entropy_esp32.c b/drivers/entropy/entropy_esp32.c index 359c67dda77..4a15f640ce9 100644 --- a/drivers/entropy/entropy_esp32.c +++ b/drivers/entropy/entropy_esp32.c @@ -44,7 +44,7 @@ static int entropy_esp32_get_entropy(const struct device *dev, uint8_t *buf, uint16_t len) { assert(buf != NULL); - uint8_t *buf_bytes = (uint8_t *)buf; + uint8_t *buf_bytes = buf; while (len > 0) { uint32_t word = entropy_esp32_get_u32(); diff --git a/drivers/entropy/entropy_stm32.c b/drivers/entropy/entropy_stm32.c index 0abedb1940c..9d0e0eb6c48 100644 --- a/drivers/entropy/entropy_stm32.c +++ b/drivers/entropy/entropy_stm32.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,57 @@ static struct entropy_stm32_rng_dev_data entropy_stm32_rng_data = { .rng = (RNG_TypeDef *)DT_INST_REG_ADDR(0), }; +static int entropy_stm32_suspend(void) +{ + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct entropy_stm32_rng_dev_data *dev_data = dev->data; + const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; + RNG_TypeDef *rng = dev_data->rng; + int res; + + LL_RNG_Disable(rng); + +#ifdef CONFIG_SOC_SERIES_STM32WBAX + uint32_t wait_cycles, rng_rate; + + if (LL_PKA_IsEnabled(PKA)) { + return 0; + } + + if (clock_control_get_rate(dev_data->clock, + (clock_control_subsys_t) &dev_cfg->pclken[0], + &rng_rate) < 0) { + return -EIO; + } + + wait_cycles = SystemCoreClock / rng_rate * 2; + + for (int i = wait_cycles; i >= 0; i--) { + } +#endif /* CONFIG_SOC_SERIES_STM32WBAX */ + + res = clock_control_off(dev_data->clock, + (clock_control_subsys_t)&dev_cfg->pclken[0]); + + return res; +} + +static int entropy_stm32_resume(void) +{ + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct entropy_stm32_rng_dev_data *dev_data = dev->data; + const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; + RNG_TypeDef *rng = dev_data->rng; + int res; + + res = clock_control_on(dev_data->clock, + (clock_control_subsys_t)&dev_cfg->pclken[0]); + LL_RNG_Enable(rng); + LL_RNG_EnableIT(rng); + + return res; +} + static void configure_rng(void) { RNG_TypeDef *rng = entropy_stm32_rng_data.rng; @@ -157,6 +209,7 @@ static void configure_rng(void) static void acquire_rng(void) { + entropy_stm32_resume(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) /* Lock the RNG to prevent concurrent access */ z_stm32_hsem_lock(CFG_HW_RNG_SEMID, HSEM_LOCK_WAIT_FOREVER); @@ -167,6 +220,7 @@ static void acquire_rng(void) static void release_rng(void) { + entropy_stm32_suspend(); #if defined(CONFIG_SOC_SERIES_STM32WBX) || defined(CONFIG_STM32H7_DUAL_CORE) z_stm32_hsem_unlock(CFG_HW_RNG_SEMID); #endif /* CONFIG_SOC_SERIES_STM32WBX || CONFIG_STM32H7_DUAL_CORE */ @@ -363,6 +417,9 @@ static int start_pool_filling(bool wait) * rng pool is filled. */ pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } acquire_rng(); irq_enable(IRQN); @@ -492,6 +549,9 @@ static void stm32_rng_isr(const void *arg) irq_disable(IRQN); release_rng(); pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } entropy_stm32_rng_data.filling_pools = false; } @@ -554,7 +614,11 @@ static int entropy_stm32_rng_get_entropy_isr(const struct device *dev, irq_disable(IRQN); irq_unlock(key); - rng_already_acquired = z_stm32_hsem_is_owned(CFG_HW_RNG_SEMID); + /* Do not release if IRQ is enabled. RNG will be released in ISR + * when the pools are full. + */ + rng_already_acquired = z_stm32_hsem_is_owned(CFG_HW_RNG_SEMID) || + irq_enabled; acquire_rng(); cnt = generate_from_isr(buf, len); @@ -638,36 +702,37 @@ static int entropy_stm32_rng_pm_action(const struct device *dev, enum pm_device_action action) { struct entropy_stm32_rng_dev_data *dev_data = dev->data; - const struct entropy_stm32_rng_dev_cfg *dev_cfg = dev->config; - RNG_TypeDef *rng = dev_data->rng; + int res = 0; + /* Remove warning on some platforms */ + ARG_UNUSED(dev_data); + switch (action) { case PM_DEVICE_ACTION_SUSPEND: - LL_RNG_Disable(rng); - -#ifdef CONFIG_SOC_SERIES_STM32WBAX - uint32_t wait_cycles, rng_rate; - - if (clock_control_get_rate(dev_data->clock, - (clock_control_subsys_t) &dev_cfg->pclken[0], - &rng_rate) < 0) { - return -EIO; - } - - wait_cycles = SystemCoreClock / rng_rate * 2; - - for (int i = wait_cycles; i >= 0; i--) { - } -#endif /* CONFIG_SOC_SERIES_STM32WBAX */ - - res = clock_control_off(dev_data->clock, - (clock_control_subsys_t)&dev_cfg->pclken[0]); + res = entropy_stm32_suspend(); break; case PM_DEVICE_ACTION_RESUME: - res = clock_control_on(dev_data->clock, - (clock_control_subsys_t)&dev_cfg->pclken[0]); - LL_RNG_Enable(rng); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { +#if DT_INST_NODE_HAS_PROP(0, health_test_config) + entropy_stm32_resume(); +#if DT_INST_NODE_HAS_PROP(0, health_test_magic) + LL_RNG_SetHealthConfig(rng, DT_INST_PROP(0, health_test_magic)); +#endif /* health_test_magic */ + if (LL_RNG_GetHealthConfig(dev_data->rng) != + DT_INST_PROP_OR(0, health_test_config, 0U)) { + entropy_stm32_rng_init(dev); + } else if (!entropy_stm32_rng_data.filling_pools) { + /* Resume RNG only if it was suspended during filling pool */ + entropy_stm32_suspend(); + } +#endif /* health_test_config */ + } else { + /* Resume RNG only if it was suspended during filling pool */ + if (entropy_stm32_rng_data.filling_pools) { + res = entropy_stm32_resume(); + } + } break; default: return -ENOTSUP; diff --git a/drivers/entropy/fake_entropy_native_bottom.c b/drivers/entropy/fake_entropy_native_bottom.c new file mode 100644 index 00000000000..f456b978d99 --- /dev/null +++ b/drivers/entropy/fake_entropy_native_bottom.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Bottom/Linux side of the pseudo-random entropy generator for + * ARCH_POSIX architecture + */ + +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 + +#include +#include +#include +#include +#include +#include "nsi_tracing.h" + +void entropy_native_seed(unsigned int seed, bool seed_random) +{ + if (seed_random == false) { + srandom(seed); + } else { + unsigned int buf; + int err = getrandom(&buf, sizeof(buf), 0); + + if (err != sizeof(buf)) { + nsi_print_error_and_exit("Could not get random number (%i, %s)\n", + err, strerror(errno)); + } + srandom(buf); + + /* Let's print the seed so users can still reproduce the run if they need to */ + nsi_print_trace("Random generator seeded with 0x%X\n", buf); + } +} diff --git a/drivers/entropy/fake_entropy_native_bottom.h b/drivers/entropy/fake_entropy_native_bottom.h new file mode 100644 index 00000000000..3fedffc0aac --- /dev/null +++ b/drivers/entropy/fake_entropy_native_bottom.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H +#define DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +void entropy_native_seed(unsigned int seed, bool seed_random); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_ENTROPY_FAKE_ENTROPY_NATIVE_BOTTOM_H */ diff --git a/drivers/entropy/fake_entropy_native_posix.c b/drivers/entropy/fake_entropy_native_posix.c index 33658155595..ccdd3aa46e5 100644 --- a/drivers/entropy/fake_entropy_native_posix.c +++ b/drivers/entropy/fake_entropy_native_posix.c @@ -23,8 +23,10 @@ #include "soc.h" #include "cmdline.h" /* native_posix command line options header */ #include "nsi_host_trampolines.h" +#include "fake_entropy_native_bottom.h" static unsigned int seed = 0x5678; +static bool seed_random; static int entropy_native_posix_get_entropy(const struct device *dev, uint8_t *buffer, @@ -67,7 +69,7 @@ static int entropy_native_posix_get_entropy_isr(const struct device *dev, static int entropy_native_posix_init(const struct device *dev) { ARG_UNUSED(dev); - nsi_host_srandom(seed); + entropy_native_seed(seed, seed_random); posix_print_warning("WARNING: " "Using a test - not safe - entropy source\n"); return 0; @@ -87,18 +89,22 @@ DEVICE_DT_INST_DEFINE(0, static void add_fake_entropy_option(void) { static struct args_struct_t entropy_options[] = { - /* - * Fields: - * manual, mandatory, switch, - * option_name, var_name ,type, - * destination, callback, - * description - */ - {false, false, false, - "seed", "r_seed", 'u', - (void *)&seed, NULL, - "A 32-bit integer seed value for the entropy device, such as " - "97229 (decimal), 0x17BCD (hex), or 0275715 (octal)"}, + { + .option = "seed", + .name = "r_seed", + .type = 'u', + .dest = (void *)&seed, + .descript = "A 32-bit integer seed value for the entropy device, such as " + "97229 (decimal), 0x17BCD (hex), or 0275715 (octal)" + }, + { + .is_switch = true, + .option = "seed-random", + .type = 'b', + .dest = (void *)&seed_random, + .descript = "Seed the random generator from /dev/urandom. " + "Note your test may not be reproducible if you set this option" + }, ARG_TABLE_ENDMARKER }; diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index 77455ebda01..5379d00ea21 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -7,6 +7,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c) zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c) +zephyr_library_sources_ifdef(CONFIG_ESPI_TAF_NPCX espi_taf_npcx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c) zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c) zephyr_library_sources_ifdef(CONFIG_ESPI_SAF_XEC espi_saf_mchp_xec.c) diff --git a/drivers/espi/Kconfig.it8xxx2 b/drivers/espi/Kconfig.it8xxx2 index 3b1ac7c436f..e018f869515 100644 --- a/drivers/espi/Kconfig.it8xxx2 +++ b/drivers/espi/Kconfig.it8xxx2 @@ -3,6 +3,8 @@ config ESPI_IT8XXX2 bool "ITE IT8XXX2 embedded controller ESPI driver" + default y + depends on DT_HAS_ITE_IT8XXX2_ESPI_ENABLED depends on SOC_IT8XXX2 help Enable ITE IT8XXX2 ESPI driver. diff --git a/drivers/espi/Kconfig.npcx b/drivers/espi/Kconfig.npcx index d0680565a6d..3f1d511caa1 100644 --- a/drivers/espi/Kconfig.npcx +++ b/drivers/espi/Kconfig.npcx @@ -5,7 +5,9 @@ config ESPI_NPCX bool "Nuvoton NPCX embedded controller (EC) ESPI driver" + default y depends on SOC_FAMILY_NPCX + depends on DT_HAS_NUVOTON_NPCX_ESPI_ENABLED help This option enables the Intel Enhanced Serial Peripheral Interface (eSPI) for NPCX family of processors. @@ -56,6 +58,36 @@ config ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE The size of the ring buffer in byte used by the Port80 ISR to store Postcodes from Host. +config ESPI_TAF_NPCX + bool "Nuvoton NPCX embedded controller (EC) ESPI TAF driver" + depends on SOC_SERIES_NPCX4 + help + This option enables the Intel Enhanced Serial Peripheral Interface + Target Attached Flash (eSPI TAF) for NPCX4 family of processors. + +choice ESPI_TAF_ACCESS_MODE_CHOICE + prompt "eSPI TAF Read Access Mode" + default ESPI_TAF_AUTO_MODE + +config ESPI_TAF_AUTO_MODE + bool "eSPI TAF Automatic Mode" + help + This is the setting to use auto mode for eSPI TAF read. + +config ESPI_TAF_MANUAL_MODE + bool "eSPI TAF Manual Mode" + help + This is the setting to use manual mode for eSPI TAF read. + +endchoice + +config ESPI_TAF_PR_NUM + int "Sets of protection region settings" + default 16 + help + This size is display how many group of slave attached flash protection + region. + # The default value 'y' for the existing options if ESPI_NPCX is selected. if ESPI_NPCX diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c index d6177dee388..6a8a83a13c3 100644 --- a/drivers/espi/espi_npcx.c +++ b/drivers/espi/espi_npcx.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT nuvoton_npcx_espi #include +#include #include #include #include @@ -74,8 +75,8 @@ struct espi_npcx_data { ((hdr & 0xf0000) >> 8)) /* Flash channel maximum payload size */ -#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD 64 -#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD 16 +#define NPCX_ESPI_FLASH_MAX_RX_PAYLOAD DT_INST_PROP(0, rx_plsize) +#define NPCX_ESPI_FLASH_MAX_TX_PAYLOAD DT_INST_PROP(0, tx_plsize) /* eSPI cycle type field for OOB and FLASH channels */ #define ESPI_FLASH_READ_CYCLE_TYPE 0x00 @@ -275,6 +276,19 @@ static void espi_bus_cfg_update_isr(const struct device *dev) NPCX_ESPI_HOST_CH_EN(NPCX_ESPI_CH_VW))) { espi_vw_send_bootload_done(dev); } + +#if (defined(CONFIG_ESPI_FLASH_CHANNEL) && defined(CONFIG_ESPI_SAF)) + /* If CONFIG_ESPI_SAF is set, set to auto or manual mode accroding + * to configuration. + */ + if (IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { +#if defined(CONFIG_ESPI_TAF_AUTO_MODE) + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#else + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#endif + } +#endif } #if defined(CONFIG_ESPI_OOB_CHANNEL) @@ -288,12 +302,82 @@ static void espi_bus_oob_rx_isr(const struct device *dev) #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) +#if defined(CONFIG_ESPI_SAF) +static struct espi_taf_pckt taf_pckt; + +static uint32_t espi_taf_parse(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct npcx_taf_head taf_head; + uint32_t taf_addr; + uint8_t i, roundsize; + + /* Get type, length and tag from RX buffer */ + memcpy(&taf_head, (void *)&inst->FLASHRXBUF[0], sizeof(taf_head)); + taf_pckt.type = taf_head.type; + taf_pckt.len = (((uint16_t)taf_head.tag_hlen & 0xF) << 8) | taf_head.llen; + taf_pckt.tag = taf_head.tag_hlen >> 4; + + if ((taf_pckt.len == 0) && ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_READ)) { + taf_pckt.len = KB(4); + } + + /* Get address from RX buffer */ + taf_addr = inst->FLASHRXBUF[1]; + taf_pckt.addr = sys_cpu_to_be32(taf_addr); + + /* Get written data if eSPI TAF write */ + if ((taf_pckt.type & 0xF) == NPCX_ESPI_TAF_REQ_WRITE) { + roundsize = DIV_ROUND_UP(taf_pckt.len, sizeof(uint32_t)); + for (i = 0; i < roundsize; i++) { + taf_pckt.src[i] = inst->FLASHRXBUF[2 + i]; + } + } + + return (uint32_t)&taf_pckt; +} +#endif /* CONFIG_ESPI_SAF */ + static void espi_bus_flash_rx_isr(const struct device *dev) { + struct espi_reg *const inst = HAL_INSTANCE(dev); struct espi_npcx_data *const data = dev->data; - LOG_DBG("%s", __func__); - k_sem_give(&data->flash_rx_lock); + /* Controller Attached Flash Access */ + if ((inst->ESPICFG & BIT(NPCX_ESPICFG_FLCHANMODE)) == 0) { + k_sem_give(&data->flash_rx_lock); + } else { /* Target Attached Flash Access */ +#if defined(CONFIG_ESPI_SAF) + struct espi_event evt = { + .evt_type = ESPI_BUS_SAF_NOTIFICATION, + .evt_details = ESPI_CHANNEL_FLASH, + .evt_data = espi_taf_parse(dev), + }; + espi_send_callbacks(&data->callbacks, dev, evt); +#else + LOG_WRN("ESPI TAF not supported"); +#endif + } +} + +static void espi_bus_completion_sent_isr(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + /* check that ESPISTS.FLNACS is clear. */ + if (IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS)) { + LOG_ERR("ESPISTS_FLNACS not clear\r\n"); + } + + /* flash operation is done, Make sure the TAFS transmit buffer is empty */ + if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL)) { + LOG_ERR("FLASH_TX_AVAIL not clear\r\n"); + } + + /* In auto mode, release FLASH_NP_FREE here to get next SAF request.*/ + if (IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_SAF_AUTO_READ)) { + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE); + } } #endif @@ -307,6 +391,7 @@ const struct espi_bus_isr espi_bus_isr_tbl[] = { #endif #if defined(CONFIG_ESPI_FLASH_CHANNEL) NPCX_ESPI_BUS_INT_ITEM(FLASHRX, espi_bus_flash_rx_isr), + NPCX_ESPI_BUS_INT_ITEM(FLNACS, espi_bus_completion_sent_isr), #endif }; diff --git a/drivers/espi/espi_taf_npcx.c b/drivers/espi/espi_taf_npcx.c new file mode 100644 index 00000000000..722b26730e8 --- /dev/null +++ b/drivers/espi/espi_taf_npcx.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_espi_taf + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(espi_taf, CONFIG_ESPI_LOG_LEVEL); + +static const struct device *const spi_dev = DEVICE_DT_GET(DT_ALIAS(taf_flash)); + +struct espi_taf_npcx_config { + uintptr_t base; + uintptr_t mapped_addr; + uintptr_t rx_plsz; + enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE erase_sz; + enum NPCX_ESPI_TAF_MAX_READ_REQ max_rd_sz; +}; + +struct espi_taf_npcx_data { + sys_slist_t callbacks; +}; + +#define HAL_INSTANCE(dev) \ + ((struct espi_reg *)((const struct espi_taf_npcx_config *) \ + (dev)->config)->base) + +#define FLBASE_ADDR ( \ + GET_FIELD(inst->FLASHBASE, NPCX_FLASHBASE_FLBASE_ADDR) \ + << GET_FIELD_POS(NPCX_FLASHBASE_FLBASE_ADDR)) + +#define PRTR_BADDR(i) ( \ + GET_FIELD(inst->FLASH_PRTR_BADDR[i], NPCX_FLASH_PRTR_BADDR) \ + << GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR)) + +#define PRTR_HADDR(i) ( \ + GET_FIELD(inst->FLASH_PRTR_HADDR[i], NPCX_FLASH_PRTR_HADDR) \ + << GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR)) | 0xFFF; + +/* Check access region of read request is protected or not */ +static bool espi_taf_check_read_protect(const struct device *dev, uint32_t addr, uint32_t len, + uint8_t tag) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t flash_addr = addr; + uint8_t i; + uint16_t override_rd; + uint32_t base, high; + bool rdpr; + + flash_addr += FLBASE_ADDR; + + for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) { + base = PRTR_BADDR(i); + high = PRTR_HADDR(i); + + rdpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_RPR); + override_rd = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_RPR); + + if (rdpr && !IS_BIT_SET(override_rd, tag) && + (base <= flash_addr + len - 1 && flash_addr <= high)) { + return true; + } + } + + return false; +} + +/* Check access region of write request is protected or not */ +static bool espi_taf_check_write_protect(const struct device *dev, uint32_t addr, + uint32_t len, uint8_t tag) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t flash_addr = addr; + uint8_t i; + uint16_t override_wr; + uint32_t base, high; + bool wrpr; + + flash_addr += FLBASE_ADDR; + + for (i = 0; i < CONFIG_ESPI_TAF_PR_NUM; i++) { + base = PRTR_BADDR(i); + high = PRTR_HADDR(i); + + wrpr = IS_BIT_SET(inst->FLASH_PRTR_BADDR[i], NPCX_FRGN_WPR); + override_wr = GET_FIELD(inst->FLASH_RGN_TAG_OVR[i], NPCX_FLASH_TAG_OVR_WPR); + + if (wrpr && !IS_BIT_SET(override_wr, tag) && + (base <= flash_addr + len - 1 && flash_addr <= high)) { + return true; + } + } + + return false; +} + +static int espi_taf_npcx_configure(const struct device *dev, const struct espi_saf_cfg *cfg) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + +#if defined(CONFIG_ESPI_TAF_AUTO_MODE) + inst->FLASHCTL |= BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#else + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_SAF_AUTO_READ); +#endif + return 0; +} + +static int espi_taf_npcx_set_pr(const struct device *dev, const struct espi_saf_protection *pr) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + const struct espi_saf_pr *preg = pr->pregions; + size_t n = pr->nregions; + uint8_t regnum; + uint16_t bitmask, offset; + uint32_t rw_pr, override_rw; + + if ((dev == NULL) || (pr == NULL)) { + return -EINVAL; + } + + if (pr->nregions >= CONFIG_ESPI_TAF_PR_NUM) { + return -EINVAL; + } + + while (n--) { + regnum = preg->pr_num; + + if (regnum >= CONFIG_ESPI_TAF_PR_NUM) { + return -EINVAL; + } + + rw_pr = preg->master_bm_we << NPCX_FRGN_WPR; + rw_pr = rw_pr | (preg->master_bm_rd << NPCX_FRGN_RPR); + + if (preg->flags) { + bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_BADDR)); + offset = GET_FIELD_POS(NPCX_FLASH_PRTR_BADDR); + inst->FLASH_PRTR_BADDR[regnum] = ((preg->start & bitmask) << offset) + | rw_pr; + bitmask = BIT_MASK(GET_FIELD_SZ(NPCX_FLASH_PRTR_HADDR)); + offset = GET_FIELD_POS(NPCX_FLASH_PRTR_HADDR); + inst->FLASH_PRTR_HADDR[regnum] = (preg->end & bitmask) << offset; + } + + override_rw = (preg->override_r << 16) | preg->override_w; + inst->FLASH_RGN_TAG_OVR[regnum] = override_rw; + preg++; + } + + return 0; +} + +static int espi_taf_npcx_activate(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_AUTO_RD_DIS_CTL); + inst->FLASHCTL &= ~BIT(NPCX_FLASHCTL_BLK_FLASH_NP_FREE); + + return 0; +} + +static bool espi_taf_npcx_channel_ready(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + + if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_FLCHANMODE)) { + return false; + } + return true; +} + +/* This routine set FLASH_C_AVAIL for standard request */ +static void taf_set_flash_c_avail(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t tmp = inst->FLASHCTL; + + /* + * Clear FLASHCTL_FLASH_NP_FREE to avoid host puts a flash + * standard request command at here. + */ + tmp &= NPCX_FLASHCTL_ACCESS_MASK; + + /* Set FLASHCTL_FLASH_TX_AVAIL */ + tmp |= BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL); + inst->FLASHCTL = tmp; +} + +/* This routine release FLASH_NP_FREE for standard request */ +static void taf_release_flash_np_free(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + uint32_t tmp = inst->FLASHCTL; + + /* + * Clear FLASHCTL_FLASH_TX_AVAIL to avoid host puts a + * GET_FLASH_C command at here. + */ + tmp &= NPCX_FLASHCTL_ACCESS_MASK; + + /* Release FLASH_NP_FREE */ + tmp |= BIT(NPCX_FLASHCTL_FLASH_NP_FREE); + inst->FLASHCTL = tmp; +} + +static int taf_npcx_completion_handler(const struct device *dev, uint32_t *buffer) +{ + uint16_t size = DIV_ROUND_UP((uint8_t)(buffer[0]) + 1, sizeof(uint32_t)); + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct npcx_taf_head *head = (struct npcx_taf_head *)buffer; + uint8_t i; + + /* Check the Flash Access TX Queue is empty by polling + * FLASH_TX_AVAIL. + */ + if (WAIT_FOR(IS_BIT_SET(inst->FLASHCTL, NPCX_FLASHCTL_FLASH_TX_AVAIL), + NPCX_FLASH_CHK_TIMEOUT, NULL)) { + LOG_ERR("Check TX Queue Is Empty Timeout"); + return -EBUSY; + } + + /* Check ESPISTS.FLNACS is clear (no slave completion is detected) */ + if (WAIT_FOR(IS_BIT_SET(inst->ESPISTS, NPCX_ESPISTS_FLNACS), + NPCX_FLASH_CHK_TIMEOUT, NULL)) { + LOG_ERR("Check Slave Completion Timeout"); + return -EBUSY; + } + + /* Write packet to FLASHTXBUF */ + for (i = 0; i < size; i++) { + inst->FLASHTXBUF[i] = buffer[i]; + } + + /* Set the FLASHCTL.FLASH_TX_AVAIL bit to 1 to enqueue the packet */ + taf_set_flash_c_avail(dev); + + /* Release FLASH_NP_FREE here to ready get next TAF request */ + if ((head->type != CYC_SCS_CMP_WITH_DATA_FIRST) && + (head->type != CYC_SCS_CMP_WITH_DATA_MIDDLE)) { + taf_release_flash_np_free(dev); + } + + return 0; +} + +static int espi_taf_npcx_flash_read(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config); + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + uint8_t cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY; + uint32_t total_len = pckt->len; + uint32_t len = total_len; + uint32_t addr = pckt->flash_addr; + uint8_t flash_req_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLASHREQSIZE); + uint8_t target_max_size = GET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP); + uint16_t max_read_req = 32 << flash_req_size; + struct npcx_taf_head taf_head; + int rc; + + if (flash_req_size > target_max_size) { + LOG_DBG("Exceeded the maximum supported length"); + if (target_max_size == 0) { + target_max_size = 1; + } + max_read_req = 32 << target_max_size; + } + + if (total_len > max_read_req) { + LOG_ERR("Exceeded the limitation of read length"); + return -EINVAL; + } + + if (espi_taf_check_read_protect(dev, addr, len, taf_data_ptr->tag)) { + LOG_ERR("Access protect region"); + return -EINVAL; + } + + if (total_len <= config->rx_plsz) { + cycle_type = CYC_SCS_CMP_WITH_DATA_ONLY; + len = total_len; + } else { + cycle_type = CYC_SCS_CMP_WITH_DATA_FIRST; + len = config->rx_plsz; + } + + do { + data_ptr = (uint8_t *)taf_data_ptr->data; + + taf_head.pkt_len = len + NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = cycle_type; + taf_head.tag_hlen = (taf_data_ptr->tag << 4) | ((len & 0xF00) >> 8); + taf_head.llen = len & 0xFF; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = flash_read(spi_dev, addr, data_ptr + 4, len); + if (rc) { + LOG_ERR("flash read fail 0x%x", rc); + return -EIO; + } + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + total_len -= len; + addr += len; + + if (total_len <= config->rx_plsz) { + cycle_type = CYC_SCS_CMP_WITH_DATA_LAST; + len = total_len; + } else { + cycle_type = CYC_SCS_CMP_WITH_DATA_MIDDLE; + } + } while (total_len); + + return 0; +} + +static int espi_taf_npcx_flash_write(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)(taf_data_ptr->data); + struct npcx_taf_head taf_head; + int rc; + + if (espi_taf_check_write_protect(dev, pckt->flash_addr, + pckt->len, taf_data_ptr->tag)) { + LOG_ERR("Access protection region"); + return -EINVAL; + } + + rc = flash_write(spi_dev, pckt->flash_addr, data_ptr, pckt->len); + if (rc) { + LOG_ERR("flash write fail 0x%x", rc); + return -EIO; + } + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_SCS_CMP_WITHOUT_DATA; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_flash_erase(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + uint32_t addr = pckt->flash_addr; + uint32_t len = pckt->len; + struct npcx_taf_head taf_head; + int rc; + + if (espi_taf_check_write_protect(dev, addr, len, taf_data_ptr->tag)) { + LOG_ERR("Access protection region"); + return -EINVAL; + } + + rc = flash_erase(spi_dev, addr, len); + if (rc) { + LOG_ERR("flash erase fail"); + return -EIO; + } + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_SCS_CMP_WITHOUT_DATA; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_flash_unsuccess(const struct device *dev, struct espi_saf_packet *pckt) +{ + struct espi_taf_npcx_pckt *taf_data_ptr + = (struct espi_taf_npcx_pckt *)pckt->buf; + uint8_t *data_ptr = (uint8_t *)taf_data_ptr->data; + struct npcx_taf_head taf_head; + int rc; + + taf_head.pkt_len = NPCX_TAF_CMP_HEADER_LEN; + taf_head.type = CYC_UNSCS_CMP_WITHOUT_DATA_ONLY; + taf_head.tag_hlen = (taf_data_ptr->tag << 4); + taf_head.llen = 0x0; + memcpy(data_ptr, &taf_head, sizeof(taf_head)); + + rc = taf_npcx_completion_handler(dev, (uint32_t *)taf_data_ptr->data); + if (rc) { + LOG_ERR("espi taf completion handler fail"); + return rc; + } + + return 0; +} + +static int espi_taf_npcx_init(const struct device *dev) +{ + struct espi_reg *const inst = HAL_INSTANCE(dev); + struct espi_taf_npcx_config *config = ((struct espi_taf_npcx_config *)(dev)->config); + + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLCAPA, + NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF); + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_TRGFLEBLKSIZE, + BIT(config->erase_sz)); + SET_FIELD(inst->FLASHCFG, NPCX_FLASHCFG_FLREQSUP, + config->max_rd_sz); + inst->FLASHBASE = config->mapped_addr; + + return 0; +} + +static const struct espi_saf_driver_api espi_taf_npcx_driver_api = { + .config = espi_taf_npcx_configure, + .set_protection_regions = espi_taf_npcx_set_pr, + .activate = espi_taf_npcx_activate, + .get_channel_status = espi_taf_npcx_channel_ready, + .flash_read = espi_taf_npcx_flash_read, + .flash_write = espi_taf_npcx_flash_write, + .flash_erase = espi_taf_npcx_flash_erase, + .flash_unsuccess = espi_taf_npcx_flash_unsuccess, +}; + +static struct espi_taf_npcx_data npcx_espi_taf_data; + +static const struct espi_taf_npcx_config espi_taf_npcx_config = { + .base = DT_INST_REG_ADDR(0), + .mapped_addr = DT_INST_PROP(0, mapped_addr), + .rx_plsz = DT_PROP(DT_INST_PARENT(0), rx_plsize), + .erase_sz = DT_INST_STRING_TOKEN(0, erase_sz), + .max_rd_sz = DT_INST_STRING_TOKEN(0, max_read_sz), +}; + +DEVICE_DT_INST_DEFINE(0, &espi_taf_npcx_init, NULL, + &npcx_espi_taf_data, &espi_taf_npcx_config, + PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY, + &espi_taf_npcx_driver_api); diff --git a/drivers/ethernet/CMakeLists.txt b/drivers/ethernet/CMakeLists.txt index 8c8795509fd..def0c5bf186 100644 --- a/drivers/ethernet/CMakeLists.txt +++ b/drivers/ethernet/CMakeLists.txt @@ -35,6 +35,8 @@ zephyr_library_sources_ifdef(CONFIG_ETH_SMSC91X eth_smsc91x.c) zephyr_library_sources_ifdef(CONFIG_ETH_IVSHMEM eth_ivshmem.c eth_ivshmem_queue.c) zephyr_library_sources_ifdef(CONFIG_ETH_ADIN2111 eth_adin2111.c) zephyr_library_sources_ifdef(CONFIG_ETH_LAN865X eth_lan865x.c oa_tc6.c) +zephyr_library_sources_ifdef(CONFIG_ETH_NXP_ENET eth_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_ETH_XMC4XXX eth_xmc4xxx.c) if(CONFIG_ETH_NXP_S32_NETC) zephyr_library_sources(eth_nxp_s32_netc.c) diff --git a/drivers/ethernet/Kconfig b/drivers/ethernet/Kconfig index 69b60e09bc2..4bc7b8b9599 100644 --- a/drivers/ethernet/Kconfig +++ b/drivers/ethernet/Kconfig @@ -63,6 +63,8 @@ source "drivers/ethernet/Kconfig.ivshmem" source "drivers/ethernet/Kconfig.adin2111" source "drivers/ethernet/Kconfig.numaker" source "drivers/ethernet/Kconfig.lan865x" +source "drivers/ethernet/Kconfig.nxp_enet" +source "drivers/ethernet/Kconfig.xmc4xxx" source "drivers/ethernet/phy/Kconfig" diff --git a/drivers/ethernet/Kconfig.esp32 b/drivers/ethernet/Kconfig.esp32 index 8adb24cfb77..35c07860f4e 100644 --- a/drivers/ethernet/Kconfig.esp32 +++ b/drivers/ethernet/Kconfig.esp32 @@ -5,7 +5,9 @@ menuconfig ETH_ESP32 bool "ESP32 Ethernet driver" + default y depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_ETH_ENABLED select MDIO help Enable ESP32 Ethernet driver. diff --git a/drivers/ethernet/Kconfig.lan865x b/drivers/ethernet/Kconfig.lan865x index c3bdc2f9b73..42138aa1ed4 100644 --- a/drivers/ethernet/Kconfig.lan865x +++ b/drivers/ethernet/Kconfig.lan865x @@ -6,6 +6,7 @@ menuconfig ETH_LAN865X default y depends on DT_HAS_MICROCHIP_LAN865X_ENABLED select SPI + select NET_L2_ETHERNET_MGMT help The LAN865X is a low power, 10BASE-T1S transceiver compliant with the IEEE® 802.3cg-2019™ Ethernet standard for long reach, 10 @@ -45,6 +46,6 @@ config ETH_LAN865X_TIMEOUT help Given timeout in milliseconds. Maximum amount of time that the driver will wait from the IP stack to get - a memory buffer before the Ethernet frame is dropped. + a memory buffer. endif # ETH_LAN865X diff --git a/drivers/ethernet/Kconfig.nxp_enet b/drivers/ethernet/Kconfig.nxp_enet new file mode 100644 index 00000000000..a6182ade32d --- /dev/null +++ b/drivers/ethernet/Kconfig.nxp_enet @@ -0,0 +1,54 @@ +# NXP ENET Ethernet driver configuration options + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_NXP_ENET + bool "NXP ENET Ethernet driver" + default y + depends on DT_HAS_NXP_ENET_MAC_ENABLED + select NOCACHE_MEMORY if HAS_MCUX_CACHE + select ARM_MPU if CPU_CORTEX_M7 + select MDIO if DT_HAS_NXP_ENET_MDIO_ENABLED + select EXPERIMENTAL + help + Enable NXP ENET Ethernet driver. + +if ETH_NXP_ENET + +config ETH_NXP_ENET_HW_ACCELERATION + bool "Hardware acceleration" + default y + depends on !NET_IPV6 + help + Enable hardware acceleration for the following: + - IPv4, UDP and TCP checksum (both Rx and Tx) + +config ETH_NXP_ENET_USE_DTCM_FOR_DMA_BUFFER + bool "Use DTCM for hardware DMA buffers" + default y + help + Place the hardware DMA buffers into DTCM for better + networking performance. + +config ETH_NXP_ENET_RX_THREAD_STACK_SIZE + int "NXP ENET RX thread stack size" + default 1600 + help + ENET RX thread stack size in bytes. + +config ETH_NXP_ENET_RX_BUFFERS + int "Number of RX buffers for ethernet driver" + default 6 + range 6 16 + help + Set the number of RX buffers provided to the NXP ENET driver. + +config ETH_NXP_ENET_TX_BUFFERS + int "Number of TX buffers for ethernet driver" + default 1 + range 1 16 + help + Set the number of TX buffers provided to the NXP ENET driver. + +endif # ETH_NXP_ENET diff --git a/drivers/ethernet/Kconfig.stm32_hal b/drivers/ethernet/Kconfig.stm32_hal index 4f5f79d1f63..8161ea31f5f 100644 --- a/drivers/ethernet/Kconfig.stm32_hal +++ b/drivers/ethernet/Kconfig.stm32_hal @@ -137,7 +137,7 @@ config ETH_STM32_AUTO_NEGOTIATION_ENABLE config ETH_STM32_HW_CHECKSUM bool "Use TX and RX hardware checksum" - depends on (!SOC_SERIES_STM32H7X && !SOC_SERIES_STM32H5X ) + depends on !SOC_SERIES_STM32H5X help Enable receive and transmit checksum offload to enhance throughput performances. diff --git a/drivers/ethernet/Kconfig.xmc4xxx b/drivers/ethernet/Kconfig.xmc4xxx new file mode 100644 index 00000000000..258d1462b8f --- /dev/null +++ b/drivers/ethernet/Kconfig.xmc4xxx @@ -0,0 +1,56 @@ +# ETH_XMC4XXX Ethernet driver configuration options + +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ETH_XMC4XXX + bool "XMC4XXX Ethernet driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_ETHERNET_ENABLED + help + Enable XMC4XXX Ethernet driver. + +if ETH_XMC4XXX + +config ETH_XMC4XXX_TX_FRAME_POOL_SIZE + int "Number of TX frames in the pool size" + default 4 + help + Number of TX frames which can be buffered in the driver. + +config ETH_XMC4XXX_NUM_TX_DMA_DESCRIPTORS + int "Number of TX DMA descriptors" + default 32 + help + Number of TX DMA descriptors. Each descriptor stores the memory address of a + data fragment and its size. + +config ETH_XMC4XXX_NUM_RX_DMA_DESCRIPTORS + int "Number of RX DMA descriptors" + default 12 + help + Number of RX DMA descriptors. Each descriptor stores the memory address of a + data fragment and its size. The data fragments are pre-allocated from the rx + network buffers (CONFIG_NET_BUF_RX_COUNT). When a frame is received, it is + forwarded to the network stack without copying the data. The buffers + in the descriptors are replaced by new pre-allocated buffers. + +config ETH_XMC4XXX_VLAN_HW_FILTER + bool "Hardware filter VLAN frames" + default y if NET_VLAN_COUNT=1 + depends on NET_VLAN + help + Hardware filter VLAN frames in hardware. Only ethernet frames with + a tag configured using vlan_setup() call will be received. + The filtering can only be done on one vlan tag. If vlan_setup() is + called multiple times, the filtering will be done on the latest + tag. + +config PTP_CLOCK_XMC4XXX + bool "XMC4XXX PTP clock driver support" + default y + depends on PTP_CLOCK + help + Enable XMC4XXX PTP Clock support. + +endif # ETH_XMC4XXX diff --git a/drivers/ethernet/eth_esp32.c b/drivers/ethernet/eth_esp32.c index 0b1744efe6c..6cf6ba44813 100644 --- a/drivers/ethernet/eth_esp32.c +++ b/drivers/ethernet/eth_esp32.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "eth.h" @@ -217,12 +218,25 @@ int eth_esp32_initialize(const struct device *dev) /* Configure phy for Media-Independent Interface (MII) or * Reduced Media-Independent Interface (RMII) mode */ - const char *phy_connection_type = DT_INST_PROP(0, phy_connection_type); + const char *phy_connection_type = DT_INST_PROP_OR(0, + phy_connection_type, + "rmii"); if (strcmp(phy_connection_type, "rmii") == 0) { emac_hal_iomux_init_rmii(); +#if DT_INST_NODE_HAS_PROP(0, ref_clk_output_gpios) + BUILD_ASSERT(DT_INST_GPIO_PIN(0, ref_clk_output_gpios) == 16 || + DT_INST_GPIO_PIN(0, ref_clk_output_gpios) == 17, + "Only GPIO16/17 are allowed as a GPIO REF_CLK source!"); + int ref_clk_gpio = DT_INST_GPIO_PIN(0, ref_clk_output_gpios); + + emac_hal_iomux_rmii_clk_output(ref_clk_gpio); + emac_ll_clock_enable_rmii_output(dev_data->hal.ext_regs); + rtc_clk_apll_enable(true, 0, 0, 6, 2); +#else emac_hal_iomux_rmii_clk_input(); emac_ll_clock_enable_rmii_input(dev_data->hal.ext_regs); +#endif } else if (strcmp(phy_connection_type, "mii") == 0) { emac_hal_iomux_init_mii(); emac_ll_clock_enable_mii(dev_data->hal.ext_regs); diff --git a/drivers/ethernet/eth_ivshmem.c b/drivers/ethernet/eth_ivshmem.c index eb869261cbc..0d2c104359a 100644 --- a/drivers/ethernet/eth_ivshmem.c +++ b/drivers/ethernet/eth_ivshmem.c @@ -297,14 +297,15 @@ int eth_ivshmem_initialize(const struct device *dev) } dev_data->peer_id = (id == 0) ? 1 : 0; - bool tx_buffer_first = id == 0; - uintptr_t output_section_addr; + uintptr_t output_sections[2]; size_t output_section_size = ivshmem_get_output_mem_section( - cfg_data->ivshmem, 0, &output_section_addr); + cfg_data->ivshmem, 0, &output_sections[0]); + ivshmem_get_output_mem_section( + cfg_data->ivshmem, 1, &output_sections[1]); res = eth_ivshmem_queue_init( - &dev_data->ivshmem_queue, output_section_addr, - output_section_size, tx_buffer_first); + &dev_data->ivshmem_queue, output_sections[id], + output_sections[dev_data->peer_id], output_section_size); if (res != 0) { LOG_ERR("Failed to init ivshmem queue"); return res; diff --git a/drivers/ethernet/eth_ivshmem_priv.h b/drivers/ethernet/eth_ivshmem_priv.h index b5769a31f03..f537d3be295 100644 --- a/drivers/ethernet/eth_ivshmem_priv.h +++ b/drivers/ethernet/eth_ivshmem_priv.h @@ -40,8 +40,8 @@ struct eth_ivshmem_queue { }; int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first); + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size); void eth_ivshmem_queue_reset(struct eth_ivshmem_queue *q); int eth_ivshmem_queue_tx_get_buff(struct eth_ivshmem_queue *q, void **data, size_t len); int eth_ivshmem_queue_tx_commit_buff(struct eth_ivshmem_queue *q); diff --git a/drivers/ethernet/eth_ivshmem_queue.c b/drivers/ethernet/eth_ivshmem_queue.c index d5b5b29a735..3301dd72a35 100644 --- a/drivers/ethernet/eth_ivshmem_queue.c +++ b/drivers/ethernet/eth_ivshmem_queue.c @@ -28,8 +28,8 @@ static int tx_clean_used(struct eth_ivshmem_queue *q); static int get_rx_avail_desc_idx(struct eth_ivshmem_queue *q, uint16_t *avail_desc_idx); int eth_ivshmem_queue_init( - struct eth_ivshmem_queue *q, uintptr_t shmem, - size_t shmem_section_size, bool tx_buffer_first) + struct eth_ivshmem_queue *q, uintptr_t tx_shmem, + uintptr_t rx_shmem, size_t shmem_section_size) { memset(q, 0, sizeof(*q)); @@ -44,14 +44,8 @@ int eth_ivshmem_queue_init( q->desc_max_len = vring_desc_len; q->vring_data_max_len = shmem_section_size - vring_header_size; q->vring_header_size = vring_header_size; - - if (tx_buffer_first) { - q->tx.shmem = (void *)shmem; - q->rx.shmem = (void *)(shmem + shmem_section_size); - } else { - q->rx.shmem = (void *)shmem; - q->tx.shmem = (void *)(shmem + shmem_section_size); - } + q->tx.shmem = (void *)tx_shmem; + q->rx.shmem = (void *)rx_shmem; /* Init vrings */ vring_init(&q->tx.vring, vring_desc_len, q->tx.shmem, ETH_IVSHMEM_VRING_ALIGNMENT); diff --git a/drivers/ethernet/eth_lan865x.c b/drivers/ethernet/eth_lan865x.c index 8107b7d3542..5a588914b30 100644 --- a/drivers/ethernet/eth_lan865x.c +++ b/drivers/ethernet/eth_lan865x.c @@ -57,10 +57,12 @@ static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device * return ETHERNET_LINK_10BASE_T | ETHERNET_PROMISC_MODE; } +static int lan865x_gpio_reset(const struct device *dev); static void lan865x_write_macaddress(const struct device *dev); static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type, const struct ethernet_config *config) { + const struct lan865x_config *cfg = dev->config; struct lan865x_data *ctx = dev->data; int ret = -ENOTSUP; @@ -97,6 +99,25 @@ static int lan865x_set_config(const struct device *dev, enum ethernet_config_typ return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); } + if (type == ETHERNET_CONFIG_TYPE_T1S_PARAM) { + ret = lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_OFF); + if (ret) { + return ret; + } + + if (config->t1s_param.type == ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG) { + cfg->plca->enable = config->t1s_param.plca.enable; + cfg->plca->node_id = config->t1s_param.plca.node_id; + cfg->plca->node_count = config->t1s_param.plca.node_count; + cfg->plca->burst_count = config->t1s_param.plca.burst_count; + cfg->plca->burst_timer = config->t1s_param.plca.burst_timer; + cfg->plca->to_timer = config->t1s_param.plca.to_timer; + } + + /* Reset is required to re-program PLCA new configuration */ + lan865x_gpio_reset(dev); + } + return ret; } @@ -121,6 +142,10 @@ static int lan865x_wait_for_reset(const struct device *dev) static int lan865x_gpio_reset(const struct device *dev) { const struct lan865x_config *cfg = dev->config; + struct lan865x_data *ctx = dev->data; + + ctx->reset = false; + ctx->tc6->protected = false; /* Perform (GPIO based) HW reset */ /* assert RESET_N low for 10 µs (5 µs min) */ @@ -337,11 +362,11 @@ static int lan865x_default_config(const struct device *dev, uint8_t silicon_rev) if (ret < 0) return ret; - if (cfg->plca_enable) { - ret = lan865x_config_plca(dev, cfg->plca_node_id, - cfg->plca_node_count, - cfg->plca_burst_count, - cfg->plca_burst_timer); + if (cfg->plca->enable) { + ret = lan865x_config_plca(dev, cfg->plca->node_id, + cfg->plca->node_count, + cfg->plca->burst_count, + cfg->plca->burst_timer); if (ret < 0) { return ret; } @@ -370,19 +395,18 @@ static void lan865x_read_chunks(const struct device *dev) struct net_pkt *pkt; int ret; - k_sem_take(&ctx->tx_rx_sem, K_FOREVER); pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout)); if (!pkt) { LOG_ERR("OA RX: Could not allocate packet!"); - k_sem_give(&ctx->tx_rx_sem); return; } + k_sem_take(&ctx->tx_rx_sem, K_FOREVER); ret = oa_tc6_read_chunks(tc6, pkt); - k_sem_give(&ctx->tx_rx_sem); if (ret < 0) { eth_stats_update_errors_rx(ctx->iface); net_pkt_unref(pkt); + k_sem_give(&ctx->tx_rx_sem); return; } @@ -392,6 +416,7 @@ static void lan865x_read_chunks(const struct device *dev) LOG_ERR("OA RX: Could not process packet (%d)!", ret); net_pkt_unref(pkt); } + k_sem_give(&ctx->tx_rx_sem); } static void lan865x_int_thread(const struct device *dev) @@ -399,6 +424,7 @@ static void lan865x_int_thread(const struct device *dev) struct lan865x_data *ctx = dev->data; struct oa_tc6 *tc6 = ctx->tc6; uint32_t sts, val, ftr; + int ret; while (true) { k_sem_take(&ctx->int_sem, K_FOREVER); @@ -408,7 +434,8 @@ static void lan865x_int_thread(const struct device *dev) oa_tc6_reg_write(tc6, OA_STATUS0, sts); lan865x_default_config(dev, ctx->silicon_rev); oa_tc6_reg_read(tc6, OA_CONFIG0, &val); - oa_tc6_reg_write(tc6, OA_CONFIG0, OA_CONFIG0_SYNC | val); + val |= OA_CONFIG0_SYNC | OA_CONFIG0_RFA_ZARFE; + oa_tc6_reg_write(tc6, OA_CONFIG0, val); lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON); ctx->reset = true; @@ -422,31 +449,19 @@ static void lan865x_int_thread(const struct device *dev) } /* - * The IRQ_N is asserted when RCA becomes > 0, so update its value - * before reading chunks. + * The IRQ_N is asserted when RCA becomes > 0. As described in + * OPEN Alliance 10BASE-T1x standard it is deasserted when first + * data header is received by LAN865x. + * + * Hence, it is mandatory to ALWAYS read at least one data chunk! */ - oa_tc6_update_buf_info(tc6); - - while (tc6->rca > 0) { + do { lan865x_read_chunks(dev); - } - - if (tc6->exst) { - /* - * Just clear any pending interrupts - data RX will be served - * earlier. - * The RESETC is handled separately as it requires LAN865x device - * configuration. - */ - oa_tc6_reg_read(tc6, OA_STATUS0, &sts); - if (sts != 0) { - oa_tc6_reg_write(tc6, OA_STATUS0, sts); - } + } while (tc6->rca > 0); - oa_tc6_reg_read(tc6, OA_STATUS1, &sts); - if (sts != 0) { - oa_tc6_reg_write(tc6, OA_STATUS1, sts); - } + ret = oa_tc6_check_status(tc6); + if (ret == -EIO) { + lan865x_gpio_reset(dev); } } } @@ -508,8 +523,6 @@ static int lan865x_init(const struct device *dev) 0, K_NO_WAIT); k_thread_name_set(ctx->tid_int, "lan865x_interrupt"); - ctx->reset = false; - /* Perform HW reset - 'rst-gpios' required property set in DT */ if (!gpio_is_ready_dt(&cfg->reset)) { LOG_ERR("Reset GPIO device %s is not ready", @@ -534,6 +547,12 @@ static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt) k_sem_take(&ctx->tx_rx_sem, K_FOREVER); ret = oa_tc6_send_chunks(tc6, pkt); + + /* Check if rca > 0 during half-duplex TX transmission */ + if (tc6->rca > 0) { + k_sem_give(&ctx->int_sem); + } + k_sem_give(&ctx->tx_rx_sem); if (ret < 0) { LOG_ERR("TX transmission error, %d", ret); @@ -552,17 +571,21 @@ static const struct ethernet_api lan865x_api_func = { }; #define LAN865X_DEFINE(inst) \ + static struct lan865x_config_plca lan865x_config_plca_##inst = { \ + .node_id = DT_INST_PROP(inst, plca_node_id), \ + .node_count = DT_INST_PROP(inst, plca_node_count), \ + .burst_count = DT_INST_PROP(inst, plca_burst_count), \ + .burst_timer = DT_INST_PROP(inst, plca_burst_timer), \ + .to_timer = DT_INST_PROP(inst, plca_to_timer), \ + .enable = DT_INST_PROP(inst, plca_enable), \ + }; \ + \ static const struct lan865x_config lan865x_config_##inst = { \ .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0), \ .interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ .reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios), \ .timeout = CONFIG_ETH_LAN865X_TIMEOUT, \ - .plca_node_id = DT_INST_PROP(inst, plca_node_id), \ - .plca_node_count = DT_INST_PROP(inst, plca_node_count), \ - .plca_burst_count = DT_INST_PROP(inst, plca_burst_count), \ - .plca_burst_timer = DT_INST_PROP(inst, plca_burst_timer), \ - .plca_to_timer = DT_INST_PROP(inst, plca_to_timer), \ - .plca_enable = DT_INST_PROP(inst, plca_enable), \ + .plca = &lan865x_config_plca_##inst, \ }; \ \ struct oa_tc6 oa_tc6_##inst = { \ @@ -573,8 +596,8 @@ static const struct ethernet_api lan865x_api_func = { static struct lan865x_data lan865x_data_##inst = { \ .mac_address = DT_INST_PROP(inst, local_mac_address), \ .tx_rx_sem = \ - Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, UINT_MAX), \ - .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, UINT_MAX), \ + Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, 1), \ + .int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1), \ .tc6 = &oa_tc6_##inst \ }; \ \ diff --git a/drivers/ethernet/eth_lan865x_priv.h b/drivers/ethernet/eth_lan865x_priv.h index fa4af1a949a..8f1b767595b 100644 --- a/drivers/ethernet/eth_lan865x_priv.h +++ b/drivers/ethernet/eth_lan865x_priv.h @@ -38,6 +38,15 @@ /* Memory Map Sector (MMS) 10 (0xA) */ #define LAN865x_DEVID MMS_REG(0xA, 0x094) +struct lan865x_config_plca { + bool enable : 1; /* 1 - PLCA enable, 0 - CSMA/CD enable */ + uint8_t node_id /* PLCA node id range: 0 to 254 */; + uint8_t node_count; /* PLCA node count range: 1 to 255 */ + uint8_t burst_count; /* PLCA burst count range: 0x0 to 0xFF */ + uint8_t burst_timer; /* PLCA burst timer */ + uint8_t to_timer; /* PLCA TO value */ +}; + struct lan865x_config { struct spi_dt_spec spi; struct gpio_dt_spec interrupt; @@ -45,12 +54,7 @@ struct lan865x_config { int32_t timeout; /* PLCA */ - bool plca_enable : 1; /* 1 - PLCA enable, 0 - CSMA/CD enable */ - uint8_t plca_node_id /* PLCA node id range: 0 to 254 */; - uint8_t plca_node_count; /* PLCA node count range: 1 to 255 */ - uint8_t plca_burst_count; /* PLCA burst count range: 0x0 to 0xFF */ - uint8_t plca_burst_timer; /* PLCA burst timer */ - uint8_t plca_to_timer; /* PLCA TO value */ + struct lan865x_config_plca *plca; /* MAC */ bool tx_cut_through_mode; /* 1 - tx cut through, 0 - Store and forward */ diff --git a/drivers/ethernet/eth_mcux.c b/drivers/ethernet/eth_mcux.c index f9ab95db9aa..81edc564259 100644 --- a/drivers/ethernet/eth_mcux.c +++ b/drivers/ethernet/eth_mcux.c @@ -1163,6 +1163,7 @@ static int eth_init(const struct device *dev) return 0; } +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static void net_if_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined) @@ -1185,15 +1186,18 @@ static void net_if_mcast_cb(struct net_if *iface, ENET_LeaveMulticastGroup(context->base, mac_addr.addr); } } +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ static void eth_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface); struct eth_context *context = dev->data; +#if defined(CONFIG_NET_NATIVE_IPV4) || defined(CONFIG_NET_NATIVE_IPV6) static struct net_if_mcast_monitor mon; net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); +#endif /* CONFIG_NET_NATIVE_IPV4 || CONFIG_NET_NATIVE_IPV6 */ net_if_set_link_addr(iface, context->mac_addr, sizeof(context->mac_addr), diff --git a/drivers/ethernet/eth_native_posix.c b/drivers/ethernet/eth_native_posix.c index 4c0a9b0a7f1..9f1b7b2bcda 100644 --- a/drivers/ethernet/eth_native_posix.c +++ b/drivers/ethernet/eth_native_posix.c @@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include "eth_native_posix_priv.h" +#include "nsi_host_trampolines.h" #include "eth.h" #define NET_BUF_TIMEOUT K_MSEC(100) @@ -193,7 +194,7 @@ static int eth_send(const struct device *dev, struct net_pkt *pkt) LOG_DBG("Send pkt %p len %d", pkt, count); - ret = eth_write_data(ctx->dev_fd, ctx->send, count); + ret = nsi_host_write(ctx->dev_fd, ctx->send, count); if (ret < 0) { LOG_DBG("Cannot send pkt %p (%d)", pkt, ret); } @@ -321,7 +322,7 @@ static int read_data(struct eth_context *ctx, int fd) int status; int count; - count = eth_read_data(fd, ctx->recv, sizeof(ctx->recv)); + count = nsi_host_read(fd, ctx->recv, sizeof(ctx->recv)); if (count <= 0) { return 0; } diff --git a/drivers/ethernet/eth_native_posix_adapt.c b/drivers/ethernet/eth_native_posix_adapt.c index 7e3864910dc..81ae9bdcf8f 100644 --- a/drivers/ethernet/eth_native_posix_adapt.c +++ b/drivers/ethernet/eth_native_posix_adapt.c @@ -116,16 +116,6 @@ int eth_wait_data(int fd) return -EAGAIN; } -ssize_t eth_read_data(int fd, void *buf, size_t buf_len) -{ - return read(fd, buf, buf_len); -} - -ssize_t eth_write_data(int fd, void *buf, size_t buf_len) -{ - return write(fd, buf, buf_len); -} - int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond) { struct timespec tp; diff --git a/drivers/ethernet/eth_native_posix_priv.h b/drivers/ethernet/eth_native_posix_priv.h index 7ce8c19f67a..f1d56f8df17 100644 --- a/drivers/ethernet/eth_native_posix_priv.h +++ b/drivers/ethernet/eth_native_posix_priv.h @@ -14,8 +14,6 @@ int eth_iface_create(const char *dev_name, const char *if_name, bool tun_only); int eth_iface_remove(int fd); int eth_wait_data(int fd); -ssize_t eth_read_data(int fd, void *buf, size_t buf_len); -ssize_t eth_write_data(int fd, void *buf, size_t buf_len); int eth_clock_gettime(uint64_t *second, uint32_t *nanosecond); int eth_promisc_mode(const char *if_name, bool enable); diff --git a/drivers/ethernet/eth_nxp_enet.c b/drivers/ethernet/eth_nxp_enet.c new file mode 100644 index 00000000000..244867dddf6 --- /dev/null +++ b/drivers/ethernet/eth_nxp_enet.c @@ -0,0 +1,986 @@ +/* NXP ENET MAC Driver + * + * Copyright 2023 NXP + * + * Inspiration from eth_mcux.c, which is: + * Copyright (c) 2016-2017 ARM Ltd + * Copyright (c) 2016 Linaro Ltd + * Copyright (c) 2018 Intel Corporation + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_mac + +/* Set up logging module for this driver */ +#define LOG_MODULE_NAME eth_nxp_enet_mac +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +/* + ************ + * Includes * + ************ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_NET_DSA) +#include +#endif + +#include "fsl_enet.h" + +/* + *********** + * Defines * + *********** + */ + +#define RING_ID 0 + +/* + ********************* + * Driver Structures * + ********************* + */ + +struct nxp_enet_mac_config { + ENET_Type *base; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + void (*generate_mac)(uint8_t *mac_addr); + const struct pinctrl_dev_config *pincfg; + enet_buffer_config_t buffer_config; + uint8_t phy_mode; + void (*irq_config_func)(void); + const struct device *phy_dev; + const struct device *mdio; +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + const struct device *ptp_clock; +#endif +}; + +struct nxp_enet_mac_data { + struct net_if *iface; + uint8_t mac_addr[6]; + enet_handle_t enet_handle; + struct k_sem tx_buf_sem; + + K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_NXP_ENET_RX_THREAD_STACK_SIZE); + + struct k_thread rx_thread; + struct k_sem rx_thread_sem; + struct k_mutex tx_frame_buf_mutex; + struct k_mutex rx_frame_buf_mutex; +#ifdef CONFIG_PTP_CLOCK_NXP_ENET + struct k_sem ptp_ts_sem; + struct k_mutex *ptp_mutex; /* created in PTP driver */ +#endif + /* TODO: FIXME. This Ethernet frame sized buffer is used for + * interfacing with MCUX. How it works is that hardware uses + * DMA scatter buffers to receive a frame, and then public + * MCUX call gathers them into this buffer (there's no other + * public interface). All this happens only for this driver + * to scatter this buffer again into Zephyr fragment buffers. + * This is not efficient, but proper resolution of this issue + * depends on introduction of zero-copy networking support + * in Zephyr, and adding needed interface to MCUX (or + * bypassing it and writing a more complex driver working + * directly with hardware). + * + * Note that we do not copy FCS into this buffer thus the + * size is 1514 bytes. + */ + uint8_t *tx_frame_buf; /* Max MTU + ethernet header */ + uint8_t *rx_frame_buf; /* Max MTU + ethernet header */ +}; + +/* + ******************** + * Helper Functions * + ******************** + */ + +static inline struct net_if *get_iface(struct nxp_enet_mac_data *data, uint16_t vlan_tag) +{ + struct net_if *iface = net_eth_get_vlan_iface(data->iface, vlan_tag); + + return iface ? iface : data->iface; +} + +static void net_if_mcast_cb(struct net_if *iface, + const struct net_addr *addr, + bool is_joined) +{ + const struct device *dev = net_if_get_device(iface); + const struct nxp_enet_mac_config *config = dev->config; + struct net_eth_addr mac_addr; + + if (IS_ENABLED(CONFIG_NET_IPV4) && addr->family == AF_INET) { + net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr); + } else if (IS_ENABLED(CONFIG_NET_IPV6) && addr->family == AF_INET6) { + net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr); + } else { + return; + } + + if (is_joined) { + ENET_AddMulticastGroup(config->base, mac_addr.addr); + } else { + ENET_LeaveMulticastGroup(config->base, mac_addr.addr); + } +} + +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) +static bool eth_get_ptp_data(struct net_if *iface, struct net_pkt *pkt) +{ + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + struct ethernet_context *eth_ctx = net_if_l2_data(iface); + bool pkt_is_ptp; + + if (net_eth_is_vlan_enabled(eth_ctx, iface)) { + pkt_is_ptp = ntohs(hdr_vlan->type) == NET_ETH_PTYPE_PTP; + } else { + pkt_is_ptp = ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_PTP; + } + + if (pkt_is_ptp) { + net_pkt_set_priority(pkt, NET_PRIORITY_CA); + } + + return pkt_is_ptp; +} + + +static inline void ts_register_tx_event(const struct device *dev, + enet_frame_info_t *frameinfo) +{ + struct nxp_enet_mac_data *data = dev->data; + struct net_pkt *pkt = frameinfo->context; + + if (pkt && atomic_get(&pkt->atomic_ref) > 0) { + if (eth_get_ptp_data(net_pkt_iface(pkt), pkt) && frameinfo->isTsAvail) { + k_mutex_lock(data->ptp_mutex, K_FOREVER); + + pkt->timestamp.nanosecond = frameinfo->timeStamp.nanosecond; + pkt->timestamp.second = frameinfo->timeStamp.second; + + net_if_add_tx_timestamp(pkt); + k_sem_give(&data->ptp_ts_sem); + + k_mutex_unlock(data->ptp_mutex); + } + net_pkt_unref(pkt); + } +} + +static inline void eth_wait_for_ptp_ts(const struct device *dev, struct net_pkt *pkt) +{ + struct nxp_enet_mac_data *data = dev->data; + + net_pkt_ref(pkt); + k_sem_take(&data->ptp_ts_sem, K_FOREVER); +} +#else +#define eth_get_ptp_data(...) false +#define ts_register_tx_event(...) +#define eth_wait_for_ptp_ts(...) +#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ + +#ifdef CONFIG_PTP_CLOCK +static const struct device *eth_nxp_enet_get_ptp_clock(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + + return config->ptp_clock; +} +#endif /* CONFIG_PTP_CLOCK */ + +/* + ********************************* + * Ethernet driver API Functions * + ********************************* + */ + +static int eth_nxp_enet_tx(const struct device *dev, struct net_pkt *pkt) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + uint16_t total_len = net_pkt_get_len(pkt); + bool frame_is_timestamped; + status_t ret; + + /* Wait for a TX buffer descriptor to be available */ + k_sem_take(&data->tx_buf_sem, K_FOREVER); + + /* Enter critical section for TX frame buffer access */ + k_mutex_lock(&data->tx_frame_buf_mutex, K_FOREVER); + + /* Read network packet from upper layer into frame buffer */ + ret = net_pkt_read(pkt, data->tx_frame_buf, total_len); + if (ret) { + k_sem_give(&data->tx_buf_sem); + goto exit; + } + + frame_is_timestamped = eth_get_ptp_data(net_pkt_iface(pkt), pkt); + + ret = ENET_SendFrame(config->base, &data->enet_handle, data->tx_frame_buf, + total_len, RING_ID, frame_is_timestamped, pkt); + if (ret == kStatus_Success) { + goto exit; + } + + if (frame_is_timestamped) { + eth_wait_for_ptp_ts(dev, pkt); + } else { + LOG_ERR("ENET_SendFrame error: %d", ret); + ENET_ReclaimTxDescriptor(config->base, &data->enet_handle, RING_ID); + } + +exit: + /* Leave critical section for TX frame buffer access */ + k_mutex_unlock(&data->tx_frame_buf_mutex); + + return ret; +} + +static void eth_nxp_enet_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; + static struct net_if_mcast_monitor mon; + + net_if_mcast_mon_register(&mon, iface, net_if_mcast_cb); + + net_if_set_link_addr(iface, data->mac_addr, + sizeof(data->mac_addr), + NET_LINK_ETHERNET); + + /* For VLAN, this value is only used to get the correct L2 driver. + * The iface pointer in context should contain the main interface + * if the VLANs are enabled. + */ + if (data->iface == NULL) { + data->iface = iface; + } + +#if defined(CONFIG_NET_DSA) + dsa_register_master_tx(iface, ð_nxp_enet_tx); +#endif + + ethernet_init(iface); + net_eth_carrier_off(data->iface); + + config->irq_config_func(); +} + +static enum ethernet_hw_caps eth_nxp_enet_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + return ETHERNET_HW_VLAN | ETHERNET_LINK_10BASE_T | +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + ETHERNET_PTP | +#endif +#if defined(CONFIG_NET_DSA) + ETHERNET_DSA_MASTER_PORT | +#endif +#if defined(CONFIG_ETH_NXP_ENET_HW_ACCELERATION) + ETHERNET_HW_TX_CHKSUM_OFFLOAD | + ETHERNET_HW_RX_CHKSUM_OFFLOAD | +#endif + ETHERNET_LINK_100BASE_T; +} + +static int eth_nxp_enet_set_config(const struct device *dev, + enum ethernet_config_type type, + const struct ethernet_config *cfg) +{ + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(data->mac_addr, + cfg->mac_address.addr, + sizeof(data->mac_addr)); + ENET_SetMacAddr(config->base, data->mac_addr); + net_if_set_link_addr(data->iface, data->mac_addr, + sizeof(data->mac_addr), + NET_LINK_ETHERNET); + LOG_DBG("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x", + dev->name, + data->mac_addr[0], data->mac_addr[1], + data->mac_addr[2], data->mac_addr[3], + data->mac_addr[4], data->mac_addr[5]); + return 0; + default: + break; + } + + return -ENOTSUP; +} + +/* + ***************************** + * Ethernet RX Functionality * + ***************************** + */ + +static int eth_nxp_enet_rx(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; + uint32_t frame_length = 0U; + struct net_if *iface; + struct net_pkt *pkt = NULL; + status_t status; + uint32_t ts; + + status = ENET_GetRxFrameSize(&data->enet_handle, + (uint32_t *)&frame_length, RING_ID); + if (status == kStatus_ENET_RxFrameEmpty) { + return 0; + } else if (status == kStatus_ENET_RxFrameError) { + enet_data_error_stats_t error_stats; + + LOG_ERR("ENET_GetRxFrameSize return: %d", (int)status); + + ENET_GetRxErrBeforeReadFrame(&data->enet_handle, + &error_stats, RING_ID); + goto flush; + } + + if (frame_length > NET_ETH_MAX_FRAME_SIZE) { + LOG_ERR("Frame too large (%d)", frame_length); + goto flush; + } + + /* Using root iface. It will be updated in net_recv_data() */ + pkt = net_pkt_rx_alloc_with_buffer(data->iface, frame_length, + AF_UNSPEC, 0, K_NO_WAIT); + if (!pkt) { + goto flush; + } + + k_mutex_lock(&data->rx_frame_buf_mutex, K_FOREVER); + status = ENET_ReadFrame(config->base, &data->enet_handle, + data->rx_frame_buf, frame_length, RING_ID, &ts); + k_mutex_unlock(&data->rx_frame_buf_mutex); + + if (status) { + LOG_ERR("ENET_ReadFrame failed: %d", (int)status); + goto error; + } + + if (net_pkt_write(pkt, data->rx_frame_buf, frame_length)) { + LOG_ERR("Unable to write frame into the packet"); + goto error; + } + + if (IS_ENABLED(CONFIG_NET_VLAN) && ntohs(NET_ETH_HDR(pkt)->type) == NET_ETH_PTYPE_VLAN) { + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt); + + net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); + vlan_tag = net_pkt_vlan_tag(pkt); + +#if CONFIG_NET_TC_RX_COUNT > 1 + enum net_priority prio = net_vlan2priority(net_pkt_vlan_priority(pkt)); + + net_pkt_set_priority(pkt, prio); +#endif /* CONFIG_NET_TC_RX_COUNT > 1 */ + } + +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + k_mutex_lock(data->ptp_mutex, K_FOREVER); + + /* Invalid value by default. */ + pkt->timestamp.nanosecond = UINT32_MAX; + pkt->timestamp.second = UINT64_MAX; + + /* Timestamp the packet using PTP clock */ + if (eth_get_ptp_data(get_iface(data, vlan_tag), pkt)) { + struct net_ptp_time ptp_time; + + ptp_clock_get(config->ptp_clock, &ptp_time); + + /* If latest timestamp reloads after getting from Rx BD, + * then second - 1 to make sure the actual Rx timestamp is accurate + */ + if (ptp_time.nanosecond < ts) { + ptp_time.second--; + } + + pkt->timestamp.nanosecond = ts; + pkt->timestamp.second = ptp_time.second; + } + k_mutex_unlock(data->ptp_mutex); +#endif /* CONFIG_PTP_CLOCK_NXP_ENET */ + + iface = get_iface(data, vlan_tag); +#if defined(CONFIG_NET_DSA) + iface = dsa_net_recv(iface, &pkt); +#endif + if (net_recv_data(iface, pkt) < 0) { + goto error; + } + + return 1; +flush: + /* Flush the current read buffer. This operation can + * only report failure if there is no frame to flush, + * which cannot happen in this context. + */ + status = ENET_ReadFrame(config->base, &data->enet_handle, NULL, + 0, RING_ID, NULL); + __ASSERT_NO_MSG(status == kStatus_Success); +error: + if (pkt) { + net_pkt_unref(pkt); + } + eth_stats_update_errors_rx(get_iface(data, vlan_tag)); + return -EIO; +} + +static void eth_nxp_enet_rx_thread(void *arg1, void *unused1, void *unused2) +{ + const struct device *dev = arg1; + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + + while (1) { + if (k_sem_take(&data->rx_thread_sem, K_FOREVER) == 0) { + while (eth_nxp_enet_rx(dev) == 1) { + ; + } + /* enable the IRQ for RX */ + ENET_EnableInterrupts(config->base, + kENET_RxFrameInterrupt | kENET_RxBufferInterrupt); + } + } +} + +/* + **************************** + * PHY management functions * + **************************** + */ + +static int nxp_enet_phy_reset_and_configure(const struct device *phy) +{ + int ret; + + /* Reset the PHY */ + ret = phy_write(phy, MII_BMCR, MII_BMCR_RESET); + if (ret) { + return ret; + } + + /* 802.3u standard says reset takes up to 0.5s */ + k_busy_wait(500000); + + /* Configure the PHY */ + return phy_configure_link(phy, LINK_HALF_10BASE_T | LINK_FULL_10BASE_T | + LINK_HALF_100BASE_T | LINK_FULL_100BASE_T); +} + +static void nxp_enet_phy_cb(const struct device *phy, + struct phy_link_state *state, + void *eth_dev) +{ + const struct device *dev = eth_dev; + struct nxp_enet_mac_data *data = dev->data; + + if (!data->iface) { + return; + } + + if (!state->is_up) { + net_eth_carrier_off(data->iface); + nxp_enet_phy_reset_and_configure(phy); + } else { + net_eth_carrier_on(data->iface); + } + + LOG_INF("Link is %s", state->is_up ? "up" : "down"); +} + + +static int nxp_enet_phy_init(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + int ret = 0; + + ret = nxp_enet_phy_reset_and_configure(config->phy_dev); + if (ret) { + return ret; + } + + ret = phy_link_callback_set(config->phy_dev, nxp_enet_phy_cb, (void *)dev); + if (ret) { + return ret; + } + + return ret; +} + +/* + **************************** + * Callbacks and interrupts * + **************************** + */ + +void nxp_enet_driver_cb(const struct device *dev, enum nxp_enet_driver dev_type, + enum nxp_enet_callback_reason event, void *data) +{ + if (dev_type == NXP_ENET_MDIO) { + nxp_enet_mdio_callback(dev, event, data); + } else if (dev_type == NXP_ENET_PTP_CLOCK) { + nxp_enet_ptp_clock_callback(dev, event, data); + } +} + +static void eth_callback(ENET_Type *base, enet_handle_t *handle, +#if FSL_FEATURE_ENET_QUEUE > 1 + uint32_t ringId, +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + enet_event_t event, enet_frame_info_t *frameinfo, void *param) +{ + const struct device *dev = param; + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + + switch (event) { + case kENET_RxEvent: + k_sem_give(&data->rx_thread_sem); + break; + case kENET_TxEvent: + ts_register_tx_event(dev, frameinfo); + /* Free the TX buffer. */ + k_sem_give(&data->tx_buf_sem); + break; + case kENET_ErrEvent: + /* Error event: BABR/BABT/EBERR/LC/RL/UN/PLR. */ + break; + case kENET_WakeUpEvent: + /* Wake up from sleep mode event. */ + break; + case kENET_TimeStampEvent: + /* Time stamp event. */ + /* Reset periodic timer to default value. */ + config->base->ATPER = NSEC_PER_SEC; + break; + case kENET_TimeStampAvailEvent: + /* Time stamp available event. */ + break; + } +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +#define ENET_IRQ_HANDLER_ARGS(base, handle) base, handle, 0 +#else +#define ENET_IRQ_HANDLER_ARGS(base, handle) base, handle +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +static void eth_nxp_enet_isr(const struct device *dev) +{ + const struct nxp_enet_mac_config *config = dev->config; + struct nxp_enet_mac_data *data = dev->data; + unsigned int irq_lock_key = irq_lock(); + + uint32_t eir = ENET_GetInterruptStatus(config->base); + + if (eir & (kENET_RxBufferInterrupt | kENET_RxFrameInterrupt)) { + ENET_ReceiveIRQHandler(ENET_IRQ_HANDLER_ARGS(config->base, &data->enet_handle)); + ENET_DisableInterrupts(config->base, + kENET_RxFrameInterrupt | kENET_RxBufferInterrupt); + } + + if (eir & kENET_TxFrameInterrupt) { + ENET_TransmitIRQHandler(ENET_IRQ_HANDLER_ARGS(config->base, &data->enet_handle)); + } + + if (eir & kENET_TxBufferInterrupt) { + ENET_ClearInterruptStatus(config->base, kENET_TxBufferInterrupt); + ENET_DisableInterrupts(config->base, kENET_TxBufferInterrupt); + } + + if (eir & ENET_EIR_MII_MASK) { + nxp_enet_driver_cb(config->mdio, NXP_ENET_MDIO, NXP_ENET_INTERRUPT, NULL); + } + + irq_unlock(irq_lock_key); +} + +/* + ****************** + * Initialization * + ****************** + */ + +static int eth_nxp_enet_init(const struct device *dev) +{ + struct nxp_enet_mac_data *data = dev->data; + const struct nxp_enet_mac_config *config = dev->config; + enet_config_t enet_config; + uint32_t enet_module_clock_rate; + int err; + + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + return err; + } + + /* Initialize kernel objects */ + k_mutex_init(&data->rx_frame_buf_mutex); + k_mutex_init(&data->tx_frame_buf_mutex); + k_sem_init(&data->rx_thread_sem, 0, CONFIG_ETH_NXP_ENET_RX_BUFFERS); + k_sem_init(&data->tx_buf_sem, + CONFIG_ETH_NXP_ENET_TX_BUFFERS, CONFIG_ETH_NXP_ENET_TX_BUFFERS); +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + k_sem_init(&data->ptp_ts_sem, 0, 1); +#endif + + if (config->generate_mac) { + config->generate_mac(data->mac_addr); + } + + /* Start interruption-poll thread */ + k_thread_create(&data->rx_thread, data->rx_thread_stack, + K_KERNEL_STACK_SIZEOF(data->rx_thread_stack), + eth_nxp_enet_rx_thread, (void *) dev, NULL, NULL, + K_PRIO_COOP(2), + 0, K_NO_WAIT); + k_thread_name_set(&data->rx_thread, "eth_nxp_enet_rx"); + + /* Get ENET IP module clock rate */ + err = clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_module_clock_rate); + if (err) { + return err; + } + + /* Use HAL to set up MAC configuration */ + ENET_GetDefaultConfig(&enet_config); + + if (IS_ENABLED(CONFIG_NET_PROMISCUOUS_MODE)) { + enet_config.macSpecialConfig |= kENET_ControlPromiscuousEnable; + } + + if (IS_ENABLED(CONFIG_NET_VLAN)) { + enet_config.macSpecialConfig |= kENET_ControlVLANTagEnable; + } + + if (IS_ENABLED(CONFIG_ETH_NXP_ENET_HW_ACCELERATION)) { + enet_config.txAccelerConfig |= + kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled; + enet_config.rxAccelerConfig |= + kENET_RxAccelIpCheckEnabled | kENET_RxAccelProtoCheckEnabled; + } + + enet_config.interrupt |= kENET_RxFrameInterrupt; + enet_config.interrupt |= kENET_TxFrameInterrupt; + + if (config->phy_mode == NXP_ENET_MII_MODE) { + enet_config.miiMode = kENET_MiiMode; + } else if (config->phy_mode == NXP_ENET_RMII_MODE) { + enet_config.miiMode = kENET_RmiiMode; + } else { + return -EINVAL; + } + + enet_config.callback = eth_callback; + enet_config.userData = (void *)dev; + + ENET_Up(config->base, + &data->enet_handle, + &enet_config, + &config->buffer_config, + data->mac_addr, + enet_module_clock_rate); + + nxp_enet_driver_cb(config->mdio, NXP_ENET_MDIO, NXP_ENET_MODULE_RESET, NULL); + +#if defined(CONFIG_PTP_CLOCK_NXP_ENET) + nxp_enet_driver_cb(config->ptp_clock, NXP_ENET_PTP_CLOCK, + NXP_ENET_MODULE_RESET, &data->ptp_mutex); + ENET_SetTxReclaim(&data->enet_handle, true, 0); +#endif + + ENET_ActiveRead(config->base); + + err = nxp_enet_phy_init(dev); + if (err) { + return err; + } + + LOG_DBG("%s MAC %02x:%02x:%02x:%02x:%02x:%02x", + dev->name, + data->mac_addr[0], data->mac_addr[1], + data->mac_addr[2], data->mac_addr[3], + data->mac_addr[4], data->mac_addr[5]); + + return 0; +} + +#ifdef CONFIG_NET_DSA +#define NXP_ENET_SEND_FUNC dsa_tx +#else +#define NXP_ENET_SEND_FUNC eth_nxp_enet_tx +#endif /* CONFIG_NET_DSA */ + +static const struct ethernet_api api_funcs = { + .iface_api.init = eth_nxp_enet_iface_init, + .get_capabilities = eth_nxp_enet_get_capabilities, + .set_config = eth_nxp_enet_set_config, + .send = NXP_ENET_SEND_FUNC, +#if defined(CONFIG_PTP_CLOCK) + .get_ptp_clock = eth_nxp_enet_get_ptp_clock, +#endif +}; + +#define NXP_ENET_CONNECT_IRQ(node_id, irq_names, idx) \ + do { \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ + DT_IRQ_BY_IDX(node_id, idx, priority), \ + eth_nxp_enet_isr, \ + DEVICE_DT_GET(node_id), \ + 0); \ + irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ + } while (false); + +#define FREESCALE_OUI_B0 0x00 +#define FREESCALE_OUI_B1 0x04 +#define FREESCALE_OUI_B2 0x9f + +#if defined(CONFIG_SOC_SERIES_IMX_RT10XX) +#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->CFG1 ^ OCOTP->CFG2) +#elif defined(CONFIG_SOC_SERIES_IMX_RT11XX) +#define ETH_NXP_ENET_UNIQUE_ID (OCOTP->FUSEN[40].FUSE) +#elif defined(CONFIG_SOC_SERIES_KINETIS_K6X) +#define ETH_NXP_ENET_UNIQUE_ID (SIM->UIDH ^ SIM->UIDMH ^ SIM->UIDML ^ SIM->UIDL) +#else +#error "Unsupported SOC" +#endif + +#define NXP_ENET_GENERATE_MAC_RANDOM(n) \ + static void generate_eth_##n##_mac(uint8_t *mac_addr) \ + { \ + gen_random_mac(mac_addr, \ + FREESCALE_OUI_B0, \ + FREESCALE_OUI_B1, \ + FREESCALE_OUI_B2); \ + } + +#define NXP_ENET_GENERATE_MAC_UNIQUE(n) \ + static void generate_eth_##n##_mac(uint8_t *mac_addr) \ + { \ + uint32_t id = ETH_NXP_ENET_UNIQUE_ID; \ + \ + mac_addr[0] = FREESCALE_OUI_B0; \ + mac_addr[0] |= 0x02; /* force LAA bit */ \ + mac_addr[1] = FREESCALE_OUI_B1; \ + mac_addr[2] = FREESCALE_OUI_B2; \ + mac_addr[3] = id >> 8; \ + mac_addr[4] = id >> 16; \ + mac_addr[5] = id >> 0; \ + mac_addr[5] += n; \ + } + +#define NXP_ENET_GENERATE_MAC(n) \ + COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \ + (NXP_ENET_GENERATE_MAC_RANDOM(n)), \ + (NXP_ENET_GENERATE_MAC_UNIQUE(n))) + +#define NXP_ENET_DECIDE_MAC_ADDR(n) \ + COND_CODE_1(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \ + (NXP_ENET_MAC_ADDR_LOCAL(n)), \ + (NXP_ENET_MAC_ADDR_GENERATED(n))) + +#define NXP_ENET_DECIDE_MAC_GEN_FUNC(n) \ + COND_CODE_1(NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(n)), \ + (NXP_ENET_GEN_MAC_FUNCTION_NO(n)), \ + (NXP_ENET_GEN_MAC_FUNCTION_YES(n))) + +#define NXP_ENET_MAC_ADDR_LOCAL(n) \ + .mac_addr = DT_INST_PROP(n, local_mac_address), + +#define NXP_ENET_MAC_ADDR_GENERATED(n) \ + .mac_addr = {0}, + +#define NXP_ENET_GEN_MAC_FUNCTION_NO(n) \ + .generate_mac = NULL, + +#define NXP_ENET_GEN_MAC_FUNCTION_YES(n) \ + .generate_mac = generate_eth_##n##_mac, + +#define NXP_ENET_DT_PHY_DEV(node_id, phy_phandle, idx) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, phy_phandle, idx)) + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) && \ + CONFIG_ETH_NXP_ENET_USE_DTCM_FOR_DMA_BUFFER +#define _nxp_enet_dma_desc_section __dtcm_bss_section +#define _nxp_enet_dma_buffer_section __dtcm_noinit_section +#define _nxp_enet_driver_buffer_section __dtcm_noinit_section +#elif defined(CONFIG_NOCACHE_MEMORY) +#define _nxp_enet_dma_desc_section __nocache +#define _nxp_enet_dma_buffer_section __nocache +#define _nxp_enet_driver_buffer_section +#else +#define _nxp_enet_dma_desc_section +#define _nxp_enet_dma_buffer_section +#define _nxp_enet_driver_buffer_section +#endif + +/* Use ENET_FRAME_MAX_VLANFRAMELEN for VLAN frame size + * Use ENET_FRAME_MAX_FRAMELEN for Ethernet frame size + */ +#if defined(CONFIG_NET_VLAN) +#if !defined(ENET_FRAME_MAX_VLANFRAMELEN) +#define ENET_FRAME_MAX_VLANFRAMELEN (ENET_FRAME_MAX_FRAMELEN + 4) +#endif +#define ETH_NXP_ENET_BUFFER_SIZE \ + ROUND_UP(ENET_FRAME_MAX_VLANFRAMELEN, ENET_BUFF_ALIGNMENT) +#else +#define ETH_NXP_ENET_BUFFER_SIZE \ + ROUND_UP(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT) +#endif /* CONFIG_NET_VLAN */ + +#define NXP_ENET_PHY_MODE(node_id) \ + DT_ENUM_HAS_VALUE(node_id, phy_connection_type, mii) ? NXP_ENET_MII_MODE : \ + (DT_ENUM_HAS_VALUE(node_id, phy_connection_type, rmii) ? NXP_ENET_RMII_MODE : \ + NXP_ENET_INVALID_MII_MODE) + +#ifdef CONFIG_PTP_CLOCK_NXP_ENET +#define NXP_ENET_PTP_DEV(n) .ptp_clock = DEVICE_DT_GET(DT_INST_PHANDLE(n, nxp_ptp_clock)), +#define NXP_ENET_FRAMEINFO_ARRAY(n) \ + static enet_frame_info_t \ + nxp_enet_##n##_tx_frameinfo_array[CONFIG_ETH_NXP_ENET_TX_BUFFERS]; +#define NXP_ENET_FRAMEINFO(n) \ + .txFrameInfo = nxp_enet_##n##_tx_frameinfo_array, +#else +#define NXP_ENET_PTP_DEV(n) +#define NXP_ENET_FRAMEINFO_ARRAY(n) +#define NXP_ENET_FRAMEINFO(n) \ + .txFrameInfo = NULL +#endif + +#define NXP_ENET_MAC_INIT(n) \ + NXP_ENET_GENERATE_MAC(n) \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + NXP_ENET_FRAMEINFO_ARRAY(n) \ + \ + static void nxp_enet_##n##_irq_config_func(void) \ + { \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, \ + NXP_ENET_CONNECT_IRQ); \ + } \ + \ + volatile static __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_desc_section \ + enet_rx_bd_struct_t \ + nxp_enet_##n##_rx_buffer_desc[CONFIG_ETH_NXP_ENET_RX_BUFFERS]; \ + \ + volatile static __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_desc_section \ + enet_tx_bd_struct_t \ + nxp_enet_##n##_tx_buffer_desc[CONFIG_ETH_NXP_ENET_TX_BUFFERS]; \ + \ + static uint8_t __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_buffer_section \ + nxp_enet_##n##_rx_buffer[CONFIG_ETH_NXP_ENET_RX_BUFFERS] \ + [ETH_NXP_ENET_BUFFER_SIZE]; \ + \ + static uint8_t __aligned(ENET_BUFF_ALIGNMENT) \ + _nxp_enet_dma_buffer_section \ + nxp_enet_##n##_tx_buffer[CONFIG_ETH_NXP_ENET_TX_BUFFERS] \ + [ETH_NXP_ENET_BUFFER_SIZE]; \ + \ + const struct nxp_enet_mac_config nxp_enet_##n##_config = { \ + .base = (ENET_Type *)DT_REG_ADDR(DT_INST_PARENT(n)), \ + .irq_config_func = nxp_enet_##n##_irq_config_func, \ + .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(n))), \ + .clock_subsys = (void *)DT_CLOCKS_CELL_BY_IDX( \ + DT_INST_PARENT(n), 0, name), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .buffer_config = { \ + .rxBdNumber = CONFIG_ETH_NXP_ENET_RX_BUFFERS, \ + .txBdNumber = CONFIG_ETH_NXP_ENET_TX_BUFFERS, \ + .rxBuffSizeAlign = ETH_NXP_ENET_BUFFER_SIZE, \ + .txBuffSizeAlign = ETH_NXP_ENET_BUFFER_SIZE, \ + .rxBdStartAddrAlign = nxp_enet_##n##_rx_buffer_desc, \ + .txBdStartAddrAlign = nxp_enet_##n##_tx_buffer_desc, \ + .rxBufferAlign = nxp_enet_##n##_rx_buffer[0], \ + .txBufferAlign = nxp_enet_##n##_tx_buffer[0], \ + .rxMaintainEnable = true, \ + .txMaintainEnable = true, \ + NXP_ENET_FRAMEINFO(n) \ + }, \ + .phy_mode = NXP_ENET_PHY_MODE(DT_DRV_INST(n)), \ + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle)), \ + .mdio = DEVICE_DT_GET(DT_INST_PHANDLE(n, nxp_mdio)), \ + NXP_ENET_PTP_DEV(n) \ + NXP_ENET_DECIDE_MAC_GEN_FUNC(n) \ + }; \ + \ + static _nxp_enet_driver_buffer_section uint8_t \ + nxp_enet_##n##_tx_frame_buf[NET_ETH_MAX_FRAME_SIZE]; \ + static _nxp_enet_driver_buffer_section uint8_t \ + nxp_enet_##n##_rx_frame_buf[NET_ETH_MAX_FRAME_SIZE]; \ + \ + struct nxp_enet_mac_data nxp_enet_##n##_data = { \ + NXP_ENET_DECIDE_MAC_ADDR(n) \ + .tx_frame_buf = nxp_enet_##n##_tx_frame_buf, \ + .rx_frame_buf = nxp_enet_##n##_rx_frame_buf, \ + }; \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, eth_nxp_enet_init, NULL, \ + &nxp_enet_##n##_data, &nxp_enet_##n##_config, \ + CONFIG_ETH_INIT_PRIORITY, \ + &api_funcs, NET_ETH_MTU); + +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_MAC_INIT) + +/* + * ENET module-level management + */ +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT nxp_enet + +#define NXP_ENET_INIT(n) \ + \ +int nxp_enet_##n##_init(void) \ +{ \ + clock_control_on(DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + (void *)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name)); \ + \ + ENET_Reset((ENET_Type *)DT_INST_REG_ADDR(n)); \ + \ + return 0; \ +} \ + \ + /* Init the module before any of the MAC, MDIO, or PTP clock */ \ + SYS_INIT(nxp_enet_##n##_init, POST_KERNEL, 0); + +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_INIT) diff --git a/drivers/ethernet/eth_nxp_s32_gmac.c b/drivers/ethernet/eth_nxp_s32_gmac.c index 71e3e94c176..67a725d1fc5 100644 --- a/drivers/ethernet/eth_nxp_s32_gmac.c +++ b/drivers/ethernet/eth_nxp_s32_gmac.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(nxp_s32_eth, CONFIG_ETHERNET_LOG_LEVEL); #include #include #include +#include #include #include @@ -42,6 +43,7 @@ struct eth_nxp_s32_config { uint32_t tx_irq; void (*do_config)(void); const struct pinctrl_dev_config *pincfg; + const struct device *phy_dev; const Gmac_CtrlConfigType ctrl_cfg; GMAC_Type *base; @@ -50,6 +52,7 @@ struct eth_nxp_s32_config { struct eth_nxp_s32_data { struct net_if *iface; uint8_t mac_addr[ETH_NXP_S32_MAC_ADDR_LEN]; + uint8_t if_suspended; struct k_mutex tx_mutex; struct k_sem rx_sem; struct k_sem tx_sem; @@ -78,6 +81,72 @@ static inline struct net_if *get_iface(struct eth_nxp_s32_data *ctx, uint16_t vl #endif } +static void convert_phy_to_mac_config(Gmac_Ip_ConfigType *gmac_cfg, enum phy_link_speed phy_speed) +{ + switch (phy_speed) { + case LINK_HALF_10BASE_T: + gmac_cfg->Speed = GMAC_SPEED_10M; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_10BASE_T: + gmac_cfg->Speed = GMAC_SPEED_10M; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + case LINK_HALF_100BASE_T: + gmac_cfg->Speed = GMAC_SPEED_100M; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_100BASE_T: + gmac_cfg->Speed = GMAC_SPEED_100M; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + case LINK_HALF_1000BASE_T: + gmac_cfg->Speed = GMAC_SPEED_1G; + gmac_cfg->Duplex = GMAC_HALF_DUPLEX; + break; + case LINK_FULL_1000BASE_T: + __fallthrough; + default: + gmac_cfg->Speed = GMAC_SPEED_1G; + gmac_cfg->Duplex = GMAC_FULL_DUPLEX; + break; + } +} + +static void phy_link_state_changed(const struct device *pdev, + struct phy_link_state *state, + void *user_data) +{ + const struct device *dev = (struct device *)user_data; + const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; + Gmac_Ip_ConfigType gmac_cfg; + + ARG_UNUSED(pdev); + + if (state->is_up) { + /* Porting phy link config to mac */ + convert_phy_to_mac_config(&gmac_cfg, state->speed); + /* Set MAC configuration */ + Gmac_Ip_SetSpeed(cfg->instance, gmac_cfg.Speed); + + cfg->base->MAC_CONFIGURATION |= GMAC_MAC_CONFIGURATION_DM(gmac_cfg.Duplex); + + /* net iface should be down even if PHY link state is up + * till the upper network layers have suspended the iface. + */ + if (ctx->if_suspended) { + return; + } + + LOG_DBG("Link up"); + net_eth_carrier_on(ctx->iface); + } else { + LOG_DBG("Link down"); + net_eth_carrier_off(ctx->iface); + } +} + #if defined(CONFIG_SOC_SERIES_S32K3XX) static int select_phy_interface(Gmac_Ip_MiiModeType mode) { @@ -167,12 +236,33 @@ static int eth_nxp_s32_init(const struct device *dev) static int eth_nxp_s32_start(const struct device *dev) { const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; + struct phy_link_state state; Gmac_Ip_EnableController(cfg->instance); irq_enable(cfg->rx_irq); irq_enable(cfg->tx_irq); + /* If upper layers enable the net iface then mark it as + * not suspended so that PHY Link changes can have the impact + */ + ctx->if_suspended = false; + + if (cfg->phy_dev) { + phy_get_link_state(cfg->phy_dev, &state); + + /* Enable net_iface only when Ethernet PHY link is up or else + * if net_iface is enabled when link is down and tx happens + * in this state then the used tx buffers will never be recovered back. + */ + if (state.is_up == true) { + net_eth_carrier_on(ctx->iface); + } + } else { + net_eth_carrier_on(ctx->iface); + } + LOG_DBG("GMAC%d started", cfg->instance); return 0; @@ -181,11 +271,19 @@ static int eth_nxp_s32_start(const struct device *dev) static int eth_nxp_s32_stop(const struct device *dev) { const struct eth_nxp_s32_config *cfg = dev->config; + struct eth_nxp_s32_data *ctx = dev->data; Gmac_Ip_StatusType status; int err = 0; - irq_enable(cfg->rx_irq); - irq_enable(cfg->tx_irq); + irq_disable(cfg->rx_irq); + irq_disable(cfg->tx_irq); + + /* If upper layers disable the net iface then mark it as suspended + * in order to save it from the PHY link state changes + */ + ctx->if_suspended = true; + + net_eth_carrier_off(ctx->iface); status = Gmac_Ip_DisableController(cfg->instance); if (status != GMAC_STATUS_SUCCESS) { @@ -250,12 +348,34 @@ static void eth_nxp_s32_iface_init(struct net_if *iface) ethernet_init(iface); net_if_set_link_addr(iface, ctx->mac_addr, sizeof(ctx->mac_addr), NET_LINK_ETHERNET); + LOG_INF("GMAC%d MAC address %02x:%02x:%02x:%02x:%02x:%02x", cfg->instance, ctx->mac_addr[0], ctx->mac_addr[1], ctx->mac_addr[2], ctx->mac_addr[3], ctx->mac_addr[4], ctx->mac_addr[5]); + /* Make sure that the net iface state is not suspended unless + * upper layers explicitly stop the iface + */ + ctx->if_suspended = false; + /* No PHY available, link is always up and MAC speed/duplex settings are fixed */ - net_eth_carrier_on(ctx->iface); + if (cfg->phy_dev == NULL) { + net_if_carrier_on(iface); + return; + } + + /* + * GMAC controls the PHY. If PHY is configured either as fixed + * link or autoneg, the callback is executed at least once + * immediately after setting it. + */ + if (!device_is_ready(cfg->phy_dev)) { + LOG_ERR("PHY device (%p) is not ready, cannot init iface", + cfg->phy_dev); + return; + } + + phy_link_callback_set(cfg->phy_dev, &phy_link_state_changed, (void *)dev); } static int eth_nxp_s32_tx(const struct device *dev, struct net_pkt *pkt) @@ -737,6 +857,11 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ LISTIFY(__DEBRACKET FEATURE_GMAC_NUM_INSTANCES, \ ETH_NXP_S32_HW_INSTANCE_CHECK, (|), n) +#define ETH_NXP_S32_PHY_DEV(n) \ + COND_CODE_1(ETH_NXP_S32_IS_FIXED_LINK(n), NULL, \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, phy_handle), \ + (DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle))), NULL))) + #define ETH_NXP_S32_DEVICE(n) \ ETH_NXP_S32_TX_CALLBACK(n) \ ETH_NXP_S32_RX_CALLBACK(n) \ @@ -757,6 +882,7 @@ BUILD_ASSERT((CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE % FEATURE_GMAC_DATA_BUS_WIDTH_ .ctrl_cfg = ETH_NXP_S32_CTRL_CONFIG(n), \ .do_config = eth_nxp_s32_init_config_##n, \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .phy_dev = ETH_NXP_S32_PHY_DEV(n), \ .rx_irq = DT_INST_IRQ_BY_NAME(n, rx, irq), \ .tx_irq = DT_INST_IRQ_BY_NAME(n, tx, irq), \ .tx_ring_idx = 0U, \ diff --git a/drivers/ethernet/eth_nxp_s32_netc_priv.h b/drivers/ethernet/eth_nxp_s32_netc_priv.h index c4948af3d53..4a3496ee58b 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_priv.h +++ b/drivers/ethernet/eth_nxp_s32_netc_priv.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -78,16 +78,23 @@ mac_addr[5] = (id + n) & 0xff; \ } while (0) -#define NETC_GENERATE_MAC_ADDRESS(node, n) \ +#define NETC_GENERATE_MAC_ADDRESS(n) \ static void nxp_s32_eth##n##_generate_mac(uint8_t mac_addr[6]) \ { \ - COND_CODE_1(DT_PROP(node, zephyr_random_mac_address), \ + COND_CODE_1(DT_INST_PROP(n, zephyr_random_mac_address), \ (_NETC_GENERATE_MAC_ADDRESS_RANDOM), \ - (COND_CODE_0(DT_NODE_HAS_PROP(node, local_mac_address), \ + (COND_CODE_0(DT_INST_NODE_HAS_PROP(n, local_mac_address),\ (_NETC_GENERATE_MAC_ADDRESS_UNIQUE(n)), \ (ARG_UNUSED(mac_addr))))); \ } +#define NETC_SI_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + ((DT_INST_REG_ADDR(n) == IP_NETC__ENETC0_SI##i##_BASE) ? i : 0) + +#define NETC_SI_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET FEATURE_NETC_ETH_NUMBER_OF_CTRLS, \ + NETC_SI_NXP_S32_HW_INSTANCE_CHECK, (|), n) + /* Helper macros to concatenate tokens that require further expansions */ #define _CONCAT3(a, b, c) DT_CAT3(a, b, c) @@ -127,5 +134,6 @@ enum ethernet_hw_caps nxp_s32_eth_get_capabilities(const struct device *dev); void nxp_s32_eth_mcast_cb(struct net_if *iface, const struct net_addr *addr, bool is_joined); int nxp_s32_eth_set_config(const struct device *dev, enum ethernet_config_type type, const struct ethernet_config *config); +extern void Netc_Eth_Ip_MSIX_Rx(uint8_t si_idx); #endif /* ZEPHYR_DRIVERS_ETHERNET_ETH_NXP_S32_NETC_PRIV_H_ */ diff --git a/drivers/ethernet/eth_nxp_s32_netc_psi.c b/drivers/ethernet/eth_nxp_s32_netc_psi.c index 8a3242be911..977825ddd7a 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_psi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_psi.c @@ -1,9 +1,11 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_psi + #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL #include LOG_MODULE_REGISTER(nxp_s32_eth_psi); @@ -26,9 +28,6 @@ LOG_MODULE_REGISTER(nxp_s32_eth_psi); #include "eth.h" #include "eth_nxp_s32_netc_priv.h" -#define PSI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_s32_netc_psi) -#define PHY_NODE DT_PHANDLE(PSI_NODE, phy_handle) -#define INIT_VSIS DT_NODE_HAS_PROP(PSI_NODE, vsis) #define TX_RING_IDX 1 #define RX_RING_IDX 0 @@ -206,19 +205,6 @@ static void nxp_s32_eth_iface_init(struct net_if *iface) } } -static void nxp_s32_eth0_rx_callback(const uint8_t unused, const uint8_t ring) -{ - const struct device *dev = DEVICE_DT_GET(PSI_NODE); - const struct nxp_s32_eth_config *cfg = dev->config; - struct nxp_s32_eth_data *ctx = dev->data; - - ARG_UNUSED(unused); - - if (ring == cfg->rx_ring_idx) { - k_sem_give(&ctx->rx_sem); - } -} - static const struct ethernet_api nxp_s32_eth_api = { .iface_api.init = nxp_s32_eth_iface_init, .get_capabilities = nxp_s32_eth_get_capabilities, @@ -236,24 +222,28 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_psi) == 1, "Only one PSI enabl .NumberOfTxBDR = 1, \ .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT \ | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ + .changeMACAllowed = true, \ + .hashFilterUpdateAllowed = true, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.multicastPromiscuousChangeAllowed = true,)) \ } -#define NETC_VSI_RX_MSG_BUF(node, prop, idx) \ +#define NETC_VSI_RX_MSG_BUF(node, prop, idx, n) \ BUILD_ASSERT((DT_PROP_BY_IDX(node, prop, idx) > NETC_ETH_IP_PSI_INDEX) \ && (DT_PROP_BY_IDX(node, prop, idx) <= FEATURE_NETC_ETH_NUM_OF_VIRTUAL_CTRLS), \ "Invalid VSI index"); \ static Netc_Eth_Ip_VsiToPsiMsgType \ - _CONCAT3(nxp_s32_eth0_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) \ + _CONCAT3(nxp_s32_eth##n##_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) \ __aligned(FEATURE_NETC_ETH_VSI_MSG_ALIGNMENT) -#define NETC_VSI_RX_MSG_BUF_ARRAY(node, prop, idx) \ +#define NETC_VSI_RX_MSG_BUF_ARRAY(node, prop, idx, n) \ [DT_PROP_BY_IDX(node, prop, idx) - 1] = \ - &_CONCAT3(nxp_s32_eth0_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) + &_CONCAT3(nxp_s32_eth##n##_vsi, DT_PROP_BY_IDX(node, prop, idx), _rx_msg_buf) -#define NETC_SWITCH_PORT_CFG(_, __) \ +#define NETC_SWITCH_PORT_CFG(_, n) \ { \ - .ePort = &nxp_s32_eth0_switch_port_egress_cfg, \ - .iPort = &nxp_s32_eth0_switch_port_ingress_cfg, \ + .ePort = &nxp_s32_eth##n##_switch_port_egress_cfg, \ + .iPort = &nxp_s32_eth##n##_switch_port_ingress_cfg, \ .EthSwtPortMacLayerPortEnable = true, \ .EthSwtPortMacLayerSpeed = ETHTRCV_BAUD_RATE_1000MBIT, \ .EthSwtPortMacLayerDuplexMode = NETC_ETHSWT_PORT_FULL_DUPLEX, \ @@ -261,155 +251,185 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_psi) == 1, "Only one PSI enabl .EthSwtPortPruningEnable = true, \ } -static Netc_Eth_Ip_StateType nxp_s32_eth0_state; - -static Netc_Eth_Ip_MACFilterHashTableEntryType -nxp_s32_eth0_mac_filter_hash_table[CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE]; - -NETC_TX_RING(0, 0, NETC_MIN_RING_LEN, NETC_MIN_RING_BUF_SIZE); -NETC_TX_RING(0, TX_RING_IDX, - CONFIG_ETH_NXP_S32_TX_RING_LEN, CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE); -NETC_RX_RING(0, RX_RING_IDX, - CONFIG_ETH_NXP_S32_RX_RING_LEN, CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE); - -static const Netc_Eth_Ip_RxRingConfigType nxp_s32_eth0_rxring_cfg[1] = { - { - .RingDesc = nxp_s32_eth0_rxring0_desc, - .Buffer = nxp_s32_eth0_rxring0_buf, - .ringSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, - .maxRingSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, - .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .TimerThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_TIMER_THRESHOLD, - .PacketsThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_PACKET_THRESHOLD, - .Callback = nxp_s32_eth0_rx_callback, - } -}; - -static const Netc_Eth_Ip_TxRingConfigType nxp_s32_eth0_txring_cfg[2] = { - { - .RingDesc = nxp_s32_eth0_txring0_desc, - .Buffer = nxp_s32_eth0_txring0_buf, - .ringSize = NETC_MIN_RING_LEN, - .maxRingSize = NETC_MIN_RING_LEN, - .bufferLen = NETC_MIN_RING_BUF_SIZE, - .maxBuffLen = NETC_MIN_RING_BUF_SIZE, - }, - { - .RingDesc = nxp_s32_eth0_txring1_desc, - .Buffer = nxp_s32_eth0_txring1_buf, - .ringSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, - .maxRingSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, - .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, - } -}; - -static const Netc_Eth_Ip_GeneralSIConfigType -nxp_s32_eth0_psi_cfg[FEATURE_NETC_ETH_NUMBER_OF_CTRLS] = { - [NETC_ETH_IP_PSI_INDEX] = { - .siId = NETC_ETH_IP_PSI_INDEX, - .enableSi = true, - .NumberOfRxBDR = 1, - .NumberOfTxBDR = 2, - .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT - | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), - }, - COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, NETC_VSI_GENERAL_CFG, (,))), - (EMPTY)) -}; - -COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, NETC_VSI_RX_MSG_BUF, (;))), - (EMPTY)); - -static const Netc_Eth_Ip_EnetcGeneralConfigType nxp_s32_eth0_enetc_general_cfg = { - .numberOfConfiguredSis = FEATURE_NETC_ETH_NUMBER_OF_CTRLS, - .stationInterfaceGeneralConfig = &nxp_s32_eth0_psi_cfg, -#if defined(CONFIG_NET_PROMISCUOUS_MODE) - .maskMACPromiscuousMulticastEnable = (uint16_t)true, - .maskMACPromiscuousUnicastEnable = (uint16_t)true, -#endif - .RxVsiMsgCmdToPsi = { - COND_CODE_1(INIT_VSIS, - (DT_FOREACH_PROP_ELEM_SEP(PSI_NODE, vsis, - NETC_VSI_RX_MSG_BUF_ARRAY, (,))), - (EMPTY)) - }, -}; - -static const Netc_Eth_Ip_StationInterfaceConfigType nxp_s32_eth0_si_cfg = { - .NumberOfRxBDR = 1, - .NumberOfTxBDR = 2, - .txMruMailboxAddr = NULL, - .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(PSI_NODE, rx), - .siMsgMruMailboxAddr = COND_CODE_1(INIT_VSIS, - ((uint32_t *)MRU_MBOX_ADDR(PSI_NODE, vsi_msg)), (NULL)), - .RxInterrupts = (uint32_t)true, - .TxInterrupts = (uint32_t)false, - .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, -}; - -static uint8_t nxp_s32_eth0_switch_vlandr2dei_cfg[NETC_ETHSWT_NUMBER_OF_DR]; -static Netc_EthSwt_Ip_PortIngressType nxp_s32_eth0_switch_port_ingress_cfg; -static Netc_EthSwt_Ip_PortEgressType nxp_s32_eth0_switch_port_egress_cfg = { - .vlanDrToDei = &nxp_s32_eth0_switch_vlandr2dei_cfg, -}; -static Netc_EthSwt_Ip_PortType nxp_s32_eth0_switch_ports_cfg[NETC_ETHSWT_NUMBER_OF_PORTS] = { - LISTIFY(NETC_ETHSWT_NUMBER_OF_PORTS, NETC_SWITCH_PORT_CFG, (,)) -}; - -static const Netc_EthSwt_Ip_ConfigType nxp_s32_eth0_switch_cfg = { - .port = &nxp_s32_eth0_switch_ports_cfg, - .EthSwtArlTableEntryTimeout = NETC_SWITCH_PORT_AGING, - .netcClockFrequency = DT_PROP(PSI_NODE, clock_frequency), - .MacLearningOption = ETHSWT_MACLEARNINGOPTION_HWDISABLED, - .MacForwardingOption = ETHSWT_NO_FDB_LOOKUP_FLOOD_FRAME, - .Timer1588ClkSrc = ETHSWT_REFERENCE_CLOCK_DISABLED, -}; - -PINCTRL_DT_DEFINE(PSI_NODE); - -NETC_GENERATE_MAC_ADDRESS(PSI_NODE, 0) - -static const struct nxp_s32_eth_config nxp_s32_eth0_config = { - .netc_cfg = { - .SiType = NETC_ETH_IP_PHYSICAL_SI, - .siConfig = &nxp_s32_eth0_si_cfg, - .generalConfig = &nxp_s32_eth0_enetc_general_cfg, - .stateStructure = &nxp_s32_eth0_state, - .paCtrlRxRingConfig = &nxp_s32_eth0_rxring_cfg, - .paCtrlTxRingConfig = &nxp_s32_eth0_txring_cfg, - }, - .si_idx = NETC_ETH_IP_PSI_INDEX, - .port_idx = NETC_SWITCH_PORT_IDX, - .tx_ring_idx = TX_RING_IDX, - .rx_ring_idx = RX_RING_IDX, - .msix = { - NETC_MSIX(PSI_NODE, rx, Netc_Eth_Ip_0_MSIX_RxEvent), - COND_CODE_1(INIT_VSIS, - (NETC_MSIX(PSI_NODE, vsi_msg, Netc_Eth_Ip_MSIX_SIMsgEvent)), - (EMPTY)) - }, - .mac_filter_hash_table = &nxp_s32_eth0_mac_filter_hash_table[0], - .generate_mac = nxp_s32_eth0_generate_mac, - .phy_dev = DEVICE_DT_GET(PHY_NODE), - .pincfg = PINCTRL_DT_DEV_CONFIG_GET(PSI_NODE), -}; - -static struct nxp_s32_eth_data nxp_s32_eth0_data = { - .mac_addr = DT_PROP_OR(PSI_NODE, local_mac_address, {0}), -}; - -ETH_NET_DEVICE_DT_DEFINE(PSI_NODE, - nxp_s32_eth_initialize, - NULL, - &nxp_s32_eth0_data, - &nxp_s32_eth0_config, - CONFIG_ETH_INIT_PRIORITY, - &nxp_s32_eth_api, - NET_ETH_MTU); +#define PHY_NODE(n) DT_INST_PHANDLE(n, phy_handle) +#define INIT_VSIS(n) DT_INST_NODE_HAS_PROP(n, vsis) + +#define NETC_PSI_INSTANCE_DEFINE(n) \ +void nxp_s32_eth_psi##n##_rx_event(uint8_t chan, const uint32_t *buf, uint8_t buf_size) \ +{ \ + ARG_UNUSED(chan); \ + ARG_UNUSED(buf); \ + ARG_UNUSED(buf_size); \ + \ + Netc_Eth_Ip_MSIX_Rx(NETC_SI_NXP_S32_HW_INSTANCE(n)); \ +} \ + \ +static void nxp_s32_eth##n##_rx_callback(const uint8_t unused, const uint8_t ring) \ +{ \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ + const struct nxp_s32_eth_config *cfg = dev->config; \ + struct nxp_s32_eth_data *ctx = dev->data; \ + \ + ARG_UNUSED(unused); \ + \ + if (ring == cfg->rx_ring_idx) { \ + k_sem_give(&ctx->rx_sem); \ + } \ +} \ + \ +static Netc_Eth_Ip_StateType nxp_s32_eth##n##_state; \ +static Netc_Eth_Ip_MACFilterHashTableEntryType \ +nxp_s32_eth##n##_mac_filter_hash_table[CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE]; \ + \ +NETC_TX_RING(n, 0, NETC_MIN_RING_LEN, NETC_MIN_RING_BUF_SIZE); \ +NETC_TX_RING(n, TX_RING_IDX, \ + CONFIG_ETH_NXP_S32_TX_RING_LEN, CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE); \ +NETC_RX_RING(n, RX_RING_IDX, \ + CONFIG_ETH_NXP_S32_RX_RING_LEN, CONFIG_ETH_NXP_S32_RX_RING_BUF_SIZE); \ + \ +static const Netc_Eth_Ip_RxRingConfigType nxp_s32_eth##n##_rxring_cfg[1] = { \ + { \ + .RingDesc = nxp_s32_eth##n##_rxring0_desc, \ + .Buffer = nxp_s32_eth##n##_rxring0_buf, \ + .ringSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, \ + .maxRingSize = CONFIG_ETH_NXP_S32_RX_RING_LEN, \ + .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .TimerThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_TIMER_THRESHOLD, \ + .PacketsThreshold = CONFIG_ETH_NXP_S32_RX_IRQ_PACKET_THRESHOLD, \ + .Callback = nxp_s32_eth##n##_rx_callback, \ + } \ +}; \ + \ +static const Netc_Eth_Ip_TxRingConfigType nxp_s32_eth##n##_txring_cfg[2] = { \ + { \ + .RingDesc = nxp_s32_eth##n##_txring0_desc, \ + .Buffer = nxp_s32_eth##n##_txring0_buf, \ + .ringSize = NETC_MIN_RING_LEN, \ + .maxRingSize = NETC_MIN_RING_LEN, \ + .bufferLen = NETC_MIN_RING_BUF_SIZE, \ + .maxBuffLen = NETC_MIN_RING_BUF_SIZE, \ + }, \ + { \ + .RingDesc = nxp_s32_eth##n##_txring1_desc, \ + .Buffer = nxp_s32_eth##n##_txring1_buf, \ + .ringSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, \ + .maxRingSize = CONFIG_ETH_NXP_S32_TX_RING_LEN, \ + .bufferLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + .maxBuffLen = CONFIG_ETH_NXP_S32_TX_RING_BUF_SIZE, \ + } \ +}; \ + \ +static const Netc_Eth_Ip_GeneralSIConfigType \ +nxp_s32_eth##n##_psi_cfg[FEATURE_NETC_ETH_NUMBER_OF_CTRLS] = { \ + [NETC_SI_NXP_S32_HW_INSTANCE(n)] = { \ + .siId = NETC_SI_NXP_S32_HW_INSTANCE(n), \ + .enableSi = true, \ + .NumberOfRxBDR = 1, \ + .NumberOfTxBDR = 2, \ + .SIVlanControl = (NETC_F3_PSICFGR0_SIVC_CVLAN_BIT \ + | NETC_F3_PSICFGR0_SIVC_SVLAN_BIT), \ + .changeMACAllowed = true, \ + .hashFilterUpdateAllowed = true, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.multicastPromiscuousChangeAllowed = true,)) \ + }, \ + COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP(n, vsis, NETC_VSI_GENERAL_CFG, (,))), \ + (EMPTY)) \ +}; \ + \ +COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP_VARGS(n, vsis, NETC_VSI_RX_MSG_BUF, (;), n)), \ + (EMPTY)); \ + \ +static const Netc_Eth_Ip_EnetcGeneralConfigType nxp_s32_eth##n##_enetc_general_cfg = { \ + .numberOfConfiguredSis = FEATURE_NETC_ETH_NUMBER_OF_CTRLS, \ + .stationInterfaceGeneralConfig = &nxp_s32_eth##n##_psi_cfg, \ + IF_ENABLED(CONFIG_NET_PROMISCUOUS_MODE, \ + (.maskMACPromiscuousMulticastEnable = (uint16_t)true, \ + .maskMACPromiscuousUnicastEnable = (uint16_t)true,)) \ + .RxVsiMsgCmdToPsi = { \ + COND_CODE_1(INIT_VSIS(n), \ + (DT_INST_FOREACH_PROP_ELEM_SEP_VARGS(n, vsis, \ + NETC_VSI_RX_MSG_BUF_ARRAY, (,), n)), \ + (EMPTY)) \ + }, \ +}; \ + \ +static const Netc_Eth_Ip_StationInterfaceConfigType nxp_s32_eth##n##_si_cfg = { \ + .NumberOfRxBDR = 1, \ + .NumberOfTxBDR = 2, \ + .txMruMailboxAddr = NULL, \ + .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), rx), \ + .siMsgMruMailboxAddr = COND_CODE_1(INIT_VSIS(n), \ + ((uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), vsi_msg)), (NULL)), \ + .RxInterrupts = (uint32_t)true, \ + .TxInterrupts = (uint32_t)false, \ + .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, \ +}; \ + \ +static uint8_t nxp_s32_eth##n##_switch_vlandr2dei_cfg[NETC_ETHSWT_NUMBER_OF_DR]; \ +static Netc_EthSwt_Ip_PortIngressType nxp_s32_eth##n##_switch_port_ingress_cfg; \ +static Netc_EthSwt_Ip_PortEgressType nxp_s32_eth##n##_switch_port_egress_cfg = { \ + .vlanDrToDei = &nxp_s32_eth##n##_switch_vlandr2dei_cfg, \ +}; \ +static Netc_EthSwt_Ip_PortType nxp_s32_eth##n##_switch_ports_cfg[NETC_ETHSWT_NUMBER_OF_PORTS] = {\ + LISTIFY(NETC_ETHSWT_NUMBER_OF_PORTS, NETC_SWITCH_PORT_CFG, (,), n) \ +}; \ + \ +static const Netc_EthSwt_Ip_ConfigType nxp_s32_eth##n##_switch_cfg = { \ + .port = &nxp_s32_eth##n##_switch_ports_cfg, \ + .EthSwtArlTableEntryTimeout = NETC_SWITCH_PORT_AGING, \ + .netcClockFrequency = DT_INST_PROP(n, clock_frequency), \ + .MacLearningOption = ETHSWT_MACLEARNINGOPTION_HWDISABLED, \ + .MacForwardingOption = ETHSWT_NO_FDB_LOOKUP_FLOOD_FRAME, \ + .Timer1588ClkSrc = ETHSWT_REFERENCE_CLOCK_DISABLED, \ +}; \ + \ +PINCTRL_DT_INST_DEFINE(n); \ + \ +NETC_GENERATE_MAC_ADDRESS(n) \ + \ +static const struct nxp_s32_eth_config nxp_s32_eth##n##_config = { \ + .netc_cfg = { \ + .SiType = NETC_ETH_IP_PHYSICAL_SI, \ + .siConfig = &nxp_s32_eth##n##_si_cfg, \ + .generalConfig = &nxp_s32_eth##n##_enetc_general_cfg, \ + .stateStructure = &nxp_s32_eth##n##_state, \ + .paCtrlRxRingConfig = &nxp_s32_eth##n##_rxring_cfg, \ + .paCtrlTxRingConfig = &nxp_s32_eth##n##_txring_cfg, \ + }, \ + .si_idx = NETC_SI_NXP_S32_HW_INSTANCE(n), \ + .port_idx = NETC_SWITCH_PORT_IDX, \ + .tx_ring_idx = TX_RING_IDX, \ + .rx_ring_idx = RX_RING_IDX, \ + .msix = { \ + NETC_MSIX(DT_DRV_INST(n), rx, nxp_s32_eth_psi##n##_rx_event), \ + COND_CODE_1(INIT_VSIS(n), \ + (NETC_MSIX(DT_DRV_INST(n), vsi_msg, Netc_Eth_Ip_MSIX_SIMsgEvent)),\ + (EMPTY)) \ + }, \ + .mac_filter_hash_table = &nxp_s32_eth##n##_mac_filter_hash_table[0], \ + .generate_mac = nxp_s32_eth##n##_generate_mac, \ + .phy_dev = DEVICE_DT_GET(PHY_NODE(n)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ +}; \ + \ +static struct nxp_s32_eth_data nxp_s32_eth##n##_data = { \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ +}; \ + \ +ETH_NET_DEVICE_DT_INST_DEFINE(n, \ + nxp_s32_eth_initialize, \ + NULL, \ + &nxp_s32_eth##n##_data, \ + &nxp_s32_eth##n##_config, \ + CONFIG_ETH_INIT_PRIORITY, \ + &nxp_s32_eth_api, \ + NET_ETH_MTU); \ + +DT_INST_FOREACH_STATUS_OKAY(NETC_PSI_INSTANCE_DEFINE) static int nxp_s32_eth_switch_init(void) { diff --git a/drivers/ethernet/eth_nxp_s32_netc_vsi.c b/drivers/ethernet/eth_nxp_s32_netc_vsi.c index 1a159529814..0847db8148c 100644 --- a/drivers/ethernet/eth_nxp_s32_netc_vsi.c +++ b/drivers/ethernet/eth_nxp_s32_netc_vsi.c @@ -1,9 +1,11 @@ /* - * Copyright 2022 NXP + * Copyright 2022-2023 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT nxp_s32_netc_vsi + #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL #include LOG_MODULE_REGISTER(nxp_s32_eth_vsi); @@ -26,7 +28,6 @@ LOG_MODULE_REGISTER(nxp_s32_eth_vsi); #include "eth.h" #include "eth_nxp_s32_netc_priv.h" -#define VSI_NODE(n) DT_NODELABEL(enetc_vsi##n) #define TX_RING_IDX 0 #define RX_RING_IDX 0 @@ -83,11 +84,16 @@ static const struct ethernet_api nxp_s32_eth_api = { BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabled supported"); #define NETC_VSI_INSTANCE_DEFINE(n) \ - NETC_GENERATE_MAC_ADDRESS(VSI_NODE(n), n) \ + NETC_GENERATE_MAC_ADDRESS(n) \ + \ + void nxp_s32_eth_vsi##n##_rx_event(uint8_t chan, const uint32_t *buf, uint8_t buf_size) \ + { \ + Netc_Eth_Ip_MSIX_Rx(NETC_SI_NXP_S32_HW_INSTANCE(n)); \ + } \ \ static void nxp_s32_eth##n##_rx_callback(const uint8_t unused, const uint8_t ring) \ { \ - const struct device *dev = DEVICE_DT_GET(VSI_NODE(n)); \ + const struct device *dev = DEVICE_DT_INST_GET(n); \ const struct nxp_s32_eth_config *cfg = dev->config; \ struct nxp_s32_eth_data *ctx = dev->data; \ \ @@ -135,7 +141,7 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl .NumberOfRxBDR = 1, \ .NumberOfTxBDR = 1, \ .txMruMailboxAddr = NULL, \ - .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(VSI_NODE(n), rx), \ + .rxMruMailboxAddr = (uint32_t *)MRU_MBOX_ADDR(DT_DRV_INST(n), rx), \ .RxInterrupts = (uint32_t)true, \ .TxInterrupts = (uint32_t)false, \ .MACFilterTableMaxNumOfEntries = CONFIG_ETH_NXP_S32_MAC_FILTER_TABLE_SIZE, \ @@ -143,7 +149,7 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl }; \ \ static struct nxp_s32_eth_data nxp_s32_eth##n##_data = { \ - .mac_addr = DT_PROP_OR(VSI_NODE(n), local_mac_address, {0}), \ + .mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}), \ }; \ \ static const struct nxp_s32_eth_config nxp_s32_eth##n##_cfg = { \ @@ -154,49 +160,23 @@ BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nxp_s32_netc_vsi) == 1, "Only one VSI enabl .paCtrlRxRingConfig = &nxp_s32_eth##n##_rxring_cfg, \ .paCtrlTxRingConfig = &nxp_s32_eth##n##_txring_cfg, \ }, \ - .si_idx = n, \ + .si_idx = NETC_SI_NXP_S32_HW_INSTANCE(n), \ .tx_ring_idx = TX_RING_IDX, \ .rx_ring_idx = RX_RING_IDX, \ .msix = { \ - NETC_MSIX(VSI_NODE(n), rx, Netc_Eth_Ip_##n##_MSIX_RxEvent), \ + NETC_MSIX(DT_DRV_INST(n), rx, nxp_s32_eth_vsi##n##_rx_event), \ }, \ .mac_filter_hash_table = &nxp_s32_eth##n##_mac_filter_hash_table[0], \ .generate_mac = nxp_s32_eth##n##_generate_mac, \ }; \ \ - ETH_NET_DEVICE_DT_DEFINE(VSI_NODE(n), \ + ETH_NET_DEVICE_DT_INST_DEFINE(n, \ nxp_s32_eth_initialize_common, \ NULL, \ &nxp_s32_eth##n##_data, \ &nxp_s32_eth##n##_cfg, \ CONFIG_ETH_NXP_S32_VSI_INIT_PRIORITY, \ &nxp_s32_eth_api, \ - NET_ETH_MTU) - -#if DT_NODE_HAS_STATUS(VSI_NODE(1), okay) -NETC_VSI_INSTANCE_DEFINE(1); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(2), okay) -NETC_VSI_INSTANCE_DEFINE(2); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(3), okay) -NETC_VSI_INSTANCE_DEFINE(3); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(4), okay) -NETC_VSI_INSTANCE_DEFINE(4); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(5), okay) -NETC_VSI_INSTANCE_DEFINE(5); -#endif - -#if DT_NODE_HAS_STATUS(VSI_NODE(6), okay) -NETC_VSI_INSTANCE_DEFINE(6); -#endif + NET_ETH_MTU); -#if DT_NODE_HAS_STATUS(VSI_NODE(7), okay) -NETC_VSI_INSTANCE_DEFINE(7); -#endif +DT_INST_FOREACH_STATUS_OKAY(NETC_VSI_INSTANCE_DEFINE) diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c index dec6ea6df20..80d43f3616c 100644 --- a/drivers/ethernet/eth_sam_gmac.c +++ b/drivers/ethernet/eth_sam_gmac.c @@ -133,6 +133,8 @@ static inline void dcache_clean(uint32_t addr, uint32_t size) #endif #endif /* !CONFIG_NET_TEST */ +BUILD_ASSERT(DT_INST_ENUM_IDX(0, phy_connection_type) <= 1, "Invalid PHY connection"); + /* RX descriptors list */ static struct gmac_desc rx_desc_que0[MAIN_QUEUE_RX_DESC_COUNT] __nocache __aligned(GMAC_DESC_ALIGNMENT); @@ -1113,7 +1115,20 @@ static int gmac_init(Gmac *gmac, uint32_t gmac_ncfgr_val) /* Setup Network Configuration Register */ gmac->GMAC_NCFGR = gmac_ncfgr_val | mck_divisor; - gmac->GMAC_UR = DT_INST_ENUM_IDX(0, phy_connection_type); + /* Default (RMII) is defined at atmel,gmac-common.yaml file */ + switch (DT_INST_ENUM_IDX(0, phy_connection_type)) { + case 0: /* mii */ + gmac->GMAC_UR = 0x1; + break; + case 1: /* rmii */ + gmac->GMAC_UR = 0x0; + break; + default: + /* Build assert at top of file should catch this case */ + LOG_ERR("The phy connection type is invalid"); + + return -EINVAL; + } #if defined(CONFIG_PTP_CLOCK_SAM_GMAC) /* Initialize PTP Clock Registers */ @@ -2439,7 +2454,7 @@ static int ptp_clock_sam_gmac_adjust(const struct device *dev, int increment) const struct eth_sam_dev_cfg *const cfg = ptp_context->eth_dev->config; Gmac *gmac = cfg->regs; - if ((increment <= -NSEC_PER_SEC) || (increment >= NSEC_PER_SEC)) { + if ((increment <= -(int)NSEC_PER_SEC) || (increment >= (int)NSEC_PER_SEC)) { return -EINVAL; } @@ -2479,6 +2494,6 @@ static int ptp_gmac_init(const struct device *port) DEVICE_DEFINE(gmac_ptp_clock_0, PTP_CLOCK_NAME, ptp_gmac_init, NULL, &ptp_gmac_0_context, NULL, POST_KERNEL, - CONFIG_APPLICATION_INIT_PRIORITY, &ptp_api); + CONFIG_PTP_CLOCK_INIT_PRIORITY, &ptp_api); #endif /* CONFIG_PTP_CLOCK_SAM_GMAC */ diff --git a/drivers/ethernet/eth_stm32_hal.c b/drivers/ethernet/eth_stm32_hal.c index 40760171e9d..b9d4c19186d 100644 --- a/drivers/ethernet/eth_stm32_hal.c +++ b/drivers/ethernet/eth_stm32_hal.c @@ -84,7 +84,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) #define __eth_stm32_desc __dtcm_noinit_section #define __eth_stm32_buf __dtcm_noinit_section -#elif defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) #define __eth_stm32_desc __attribute__((section(".eth_stm32_desc"))) #define __eth_stm32_buf __attribute__((section(".eth_stm32_buf"))) #elif defined(CONFIG_NOCACHE_MEMORY) @@ -1844,13 +1844,13 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) uint32_t addend_val; /* No change needed */ - if (ratio == 1.0f) { + if (ratio == 1.0L) { return 0; } key = irq_lock(); - ratio *= eth_dev_data->clk_ratio_adj; + ratio *= (double)eth_dev_data->clk_ratio_adj; /* Limit possible ratio */ if (ratio * 100 < CONFIG_ETH_STM32_HAL_PTP_CLOCK_ADJ_MIN_PCT || @@ -1863,7 +1863,7 @@ static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio) eth_dev_data->clk_ratio_adj = ratio; /* Update addend register */ - addend_val = UINT32_MAX * eth_dev_data->clk_ratio * ratio; + addend_val = UINT32_MAX * (double)eth_dev_data->clk_ratio * ratio; #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X) heth->Instance->MACTSAR = addend_val; diff --git a/drivers/ethernet/eth_xmc4xxx.c b/drivers/ethernet/eth_xmc4xxx.c new file mode 100644 index 00000000000..ad2cee470f2 --- /dev/null +++ b/drivers/ethernet/eth_xmc4xxx.c @@ -0,0 +1,1162 @@ +/* XMC4XXX Ethernet controller + * + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_ethernet + +#include "eth.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL +#include +LOG_MODULE_REGISTER(eth_xmc4xxx); + +#define NUM_TX_DMA_DESCRIPTORS CONFIG_ETH_XMC4XXX_NUM_TX_DMA_DESCRIPTORS +#define NUM_RX_DMA_DESCRIPTORS CONFIG_ETH_XMC4XXX_NUM_RX_DMA_DESCRIPTORS + +#define ETH_NODE DT_NODELABEL(eth) +#define PHY_NODE DT_PHANDLE_BY_IDX(ETH_NODE, phy, 0) + +#define INFINEON_OUI_B0 0x00 +#define INFINEON_OUI_B1 0x03 +#define INFINEON_OUI_B2 0x19 + +#define MODULO_INC_TX(val) {(val) = (++(val) < NUM_TX_DMA_DESCRIPTORS) ? (val) : 0; } +#define MODULO_INC_RX(val) {(val) = (++(val) < NUM_RX_DMA_DESCRIPTORS) ? (val) : 0; } + +#define IS_OWNED_BY_DMA_TX(desc) (((desc)->status & ETH_MAC_DMA_TDES0_OWN) != 0) +#define IS_OWNED_BY_DMA_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_OWN) != 0) + +#define IS_START_OF_FRAME_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_FS) != 0) +#define IS_END_OF_FRAME_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_LS) != 0) + +#define IS_TIMESTAMP_AVAILABLE_RX(desc) (((desc)->status & ETH_MAC_DMA_RDES0_TSA) != 0) +#define IS_TIMESTAMP_AVAILABLE_TX(desc) (((desc)->status & ETH_MAC_DMA_TDES0_TTSS) != 0) + +#define TOTAL_FRAME_LENGTH(desc) (FIELD_GET(ETH_MAC_DMA_RDES0_FL, (desc)->status) - 4) + +#define ETH_STATUS_ERROR_TRANSMIT_EVENTS \ + (XMC_ETH_MAC_EVENT_BUS_ERROR | XMC_ETH_MAC_EVENT_TRANSMIT_JABBER_TIMEOUT | \ + XMC_ETH_MAC_EVENT_TRANSMIT_UNDERFLOW | XMC_ETH_MAC_EVENT_TRANSMIT_PROCESS_STOPPED) + +#define ETH_STATUS_ERROR_RECEIVE_EVENTS \ + (XMC_ETH_MAC_EVENT_BUS_ERROR | XMC_ETH_MAC_EVENT_RECEIVE_OVERFLOW) + +#define ETH_STATUS_ALL_EVENTS \ + (ETH_STATUS_ERROR_TRANSMIT_EVENTS | ETH_STATUS_ERROR_RECEIVE_EVENTS | \ + XMC_ETH_MAC_EVENT_RECEIVE | XMC_ETH_MAC_EVENT_TRANSMIT | ETH_INTERRUPT_ENABLE_NIE_Msk | \ + ETH_INTERRUPT_ENABLE_AIE_Msk) + +#define ETH_MAC_DISABLE_MMC_INTERRUPT_MSK 0x03ffffffu +#define ETH_MAC_DISABLE_MMC_IPC_RECEIVE_INTERRUPT_MSK 0x3fff3fffu + +#define ETH_STATUS_CLEARABLE_BITS 0x1e7ffu + +#define ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK BIT(14) + +#define ETH_RESET_TIMEOUT_USEC 200000u +#define ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC 100000u + +#define ETH_LINK_SPEED_10M 0 +#define ETH_LINK_SPEED_100M 1 + +#define ETH_LINK_DUPLEX_HALF 0 +#define ETH_LINK_DUPLEX_FULL 1 + +#define ETH_PTP_CLOCK_FREQUENCY 50000000 +#define ETH_PTP_RATE_ADJUST_RATIO_MIN 0.9 +#define ETH_PTP_RATE_ADJUST_RATIO_MAX 1.1 + +struct eth_xmc4xxx_data { + struct net_if *iface; + uint8_t mac_addr[6]; + struct k_sem tx_desc_sem; + bool link_up; +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + struct net_stats_eth stats; +#endif + bool tx_frames_flushed; + uint16_t dma_desc_tx_head; + uint16_t dma_desc_rx_tail; + sys_slist_t tx_frame_list; + struct net_buf *rx_frag_list[NUM_RX_DMA_DESCRIPTORS]; +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + const struct device *ptp_clock; +#endif +}; + +struct eth_xmc4xxx_config { + ETH_GLOBAL_TypeDef *regs; + const struct device *phy_dev; + void (*irq_config_func)(void); + const struct pinctrl_dev_config *pcfg; + const uint8_t phy_connection_type; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl; +}; + +struct eth_xmc4xxx_tx_frame { + sys_snode_t node; + struct net_pkt *pkt; + uint16_t tail_index; + uint16_t head_index; +}; + +K_MEM_SLAB_DEFINE_STATIC(tx_frame_slab, sizeof(struct eth_xmc4xxx_tx_frame), + CONFIG_ETH_XMC4XXX_TX_FRAME_POOL_SIZE, 4); + +static XMC_ETH_MAC_DMA_DESC_t __aligned(4) tx_dma_desc[NUM_TX_DMA_DESCRIPTORS]; +static XMC_ETH_MAC_DMA_DESC_t __aligned(4) rx_dma_desc[NUM_RX_DMA_DESCRIPTORS]; + +static inline struct net_if *get_iface(struct eth_xmc4xxx_data *ctx, uint16_t vlan_tag) +{ +#if defined(CONFIG_NET_VLAN) + struct net_if *iface; + + iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag); + if (!iface) { + return ctx->iface; + } + + return iface; +#else + ARG_UNUSED(vlan_tag); + + return ctx->iface; +#endif +} + +static void eth_xmc4xxx_tx_dma_descriptors_init(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + memset(tx_dma_desc, 0, sizeof(tx_dma_desc)); + + dev_cfg->regs->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t)&tx_dma_desc[0]; + + /* chain the descriptors */ + for (int i = 0; i < NUM_TX_DMA_DESCRIPTORS - 1; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &tx_dma_desc[i]; + + dma_desc->buffer2 = (volatile uint32_t)&tx_dma_desc[i + 1]; + } + + /* TER: transmit end of ring - it is the last descriptor in ring */ + tx_dma_desc[NUM_TX_DMA_DESCRIPTORS - 1].status |= ETH_MAC_DMA_TDES0_TER; + tx_dma_desc[NUM_TX_DMA_DESCRIPTORS - 1].buffer2 = (volatile uint32_t)&tx_dma_desc[0]; +} + +static void eth_xmc4xxx_flush_rx(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct eth_xmc4xxx_data *dev_data = dev->data; + + dev_cfg->regs->OPERATION_MODE &= ~ETH_OPERATION_MODE_SR_Msk; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + rx_dma_desc[i].status = ETH_MAC_DMA_RDES0_OWN; + } + + dev_cfg->regs->OPERATION_MODE |= ETH_OPERATION_MODE_SR_Msk; + dev_data->dma_desc_rx_tail = 0; +} + +static void eth_xmc4xxx_flush_tx(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct eth_xmc4xxx_data *dev_data = dev->data; + sys_snode_t *node; + + LOG_DBG("Flushing tx frames"); + + if (dev_data->tx_frames_flushed) { + return; + } + + dev_cfg->regs->OPERATION_MODE &= ~ETH_OPERATION_MODE_ST_Msk; + + node = sys_slist_get(&dev_data->tx_frame_list); + while (node) { + struct eth_xmc4xxx_tx_frame *tx_frame = SYS_SLIST_CONTAINER(node, tx_frame, node); + + net_pkt_unref(tx_frame->pkt); + k_mem_slab_free(&tx_frame_slab, (void *)tx_frame); + + node = sys_slist_get(&dev_data->tx_frame_list); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.tx++; + dev_data->stats.error_details.tx_aborted_errors++; +#endif + } + + k_sem_reset(&dev_data->tx_desc_sem); + + eth_xmc4xxx_tx_dma_descriptors_init(dev); + dev_cfg->regs->OPERATION_MODE |= ETH_OPERATION_MODE_ST_Msk; + dev_data->dma_desc_tx_head = 0; + dev_data->tx_frames_flushed = true; + + for (int i = 0; i < NUM_TX_DMA_DESCRIPTORS; i++) { + k_sem_give(&dev_data->tx_desc_sem); + } +} + +static inline void eth_xmc4xxx_trigger_dma_tx(ETH_GLOBAL_TypeDef *regs) +{ + regs->STATUS = ETH_STATUS_TPS_Msk; + regs->TRANSMIT_POLL_DEMAND = 0; +} + +static inline void eth_xmc4xxx_trigger_dma_rx(ETH_GLOBAL_TypeDef *regs) +{ + regs->STATUS = ETH_STATUS_RU_Msk; + regs->RECEIVE_POLL_DEMAND = 0U; +} + +static int eth_xmc4xxx_send(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct net_buf *frag; + uint8_t *frag_data; + uint16_t frag_len; + int ret = 0; + XMC_ETH_MAC_DMA_DESC_t *dma_desc = NULL; + struct eth_xmc4xxx_tx_frame *tx_frame; + int num_frags = 0; + bool first_descriptor = false; + + frag = pkt->frags; + while (frag) { + num_frags++; + frag = frag->frags; + } + + if (num_frags > NUM_TX_DMA_DESCRIPTORS) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_dma_failed++; +#endif + LOG_DBG("Number of fragments exceeds total descriptors. Dropping packet"); + return -ENOMEM; + } + + /* All available frames buffered inside the driver. Apply back pressure in the driver. */ + while (tx_frame_slab.info.num_used == CONFIG_ETH_XMC4XXX_TX_FRAME_POOL_SIZE) { + eth_xmc4xxx_trigger_dma_tx(dev_cfg->regs); + k_yield(); + } + + ret = k_mem_slab_alloc(&tx_frame_slab, (void **)&tx_frame, K_NO_WAIT); + __ASSERT_NO_MSG(ret == 0); + + net_pkt_ref(pkt); + + dev_data->tx_frames_flushed = false; + + first_descriptor = true; + tx_frame->pkt = pkt; + tx_frame->tail_index = dev_data->dma_desc_tx_head; + + frag = pkt->frags; + while (frag) { + ret = k_sem_take(&dev_data->tx_desc_sem, K_FOREVER); + /* isr may call k_sem_reset() */ + if (ret < 0 || dev_data->tx_frames_flushed) { + k_mem_slab_free(&tx_frame_slab, (void **)&tx_frame); + net_pkt_unref(pkt); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_aborted_errors++; +#endif + LOG_DBG("Dropping frame. Buffered Tx frames were flushed in ISR."); + return -EIO; + } + + unsigned int key = irq_lock(); + /* Critical section for dma_desc_tx_head and tx_dma_desc. Isr may */ + /* reinitialize the descriptors and set dma_desc_tx_head to 0 */ + + dma_desc = &tx_dma_desc[dev_data->dma_desc_tx_head]; + + frag_data = frag->data; + frag_len = frag->len; + + dma_desc->buffer1 = (volatile uint32_t)frag_data; + dma_desc->length = frag_len; + + /* give ownership of descriptor back to dma and set checksum offload */ + /* TCH we are using a circular list */ + dma_desc->status = ETH_MAC_DMA_TDES0_CIC | ETH_MAC_DMA_TDES0_TCH; + + if (!first_descriptor) { + /* Delay giving ownership of first frag to DMA. Prevents race condition */ + /* where second other frags are not ready */ + dma_desc->status |= ETH_MAC_DMA_TDES0_OWN; + } else { + dma_desc->status |= ETH_MAC_DMA_TDES0_FS; + +#if defined(CONFIG_NET_GPTP) + struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); + + if (ntohs(hdr->type) == NET_ETH_PTYPE_PTP) { + dma_desc->status |= ETH_MAC_DMA_TDES0_TTSE; + } +#endif + } + first_descriptor = false; + + tx_frame->head_index = dev_data->dma_desc_tx_head; + + MODULO_INC_TX(dev_data->dma_desc_tx_head); + + irq_unlock(key); + + frag = frag->frags; + } + + if (dev_data->tx_frames_flushed) { + k_mem_slab_free(&tx_frame_slab, (void **)&tx_frame); + net_pkt_unref(pkt); +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.error_details.tx_aborted_errors++; +#endif + LOG_DBG("Dropping frame. Buffered Tx frames were flushed in ISR."); + return -EIO; + } + + unsigned int key = irq_lock(); + + /* label last dma descriptor as last segment and trigger interrupt on last segment */ + dma_desc->status |= ETH_MAC_DMA_TDES0_IC | ETH_MAC_DMA_TDES0_LS; + + /* Finally give ownership of first frag to DMA. After this point the DMA engine */ + /* may transfer the whole frame from RAM to Ethernet */ + tx_dma_desc[tx_frame->tail_index].status |= ETH_MAC_DMA_TDES0_OWN; + + sys_slist_append(&dev_data->tx_frame_list, &tx_frame->node); + + eth_xmc4xxx_trigger_dma_tx(dev_cfg->regs); + + irq_unlock(key); + + return 0; +} + +static struct net_pkt *eth_xmc4xxx_rx_pkt(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + struct net_pkt *pkt = NULL; + struct net_buf *new_frag; + + bool eof_found = false; + uint16_t tail; + XMC_ETH_MAC_DMA_DESC_t *dma_desc; + int num_frags = 0; + uint16_t frame_end_index; + struct net_buf *frag, *last_frag = NULL; + + tail = dev_data->dma_desc_rx_tail; + dma_desc = &rx_dma_desc[tail]; + + if (IS_OWNED_BY_DMA_RX(dma_desc)) { + return NULL; + } + + if (!IS_START_OF_FRAME_RX(dma_desc)) { + /* handle this error - missing SOF packet? */ + eth_xmc4xxx_flush_rx(dev); + return NULL; + } + + while (!IS_OWNED_BY_DMA_RX(dma_desc)) { + eof_found = IS_END_OF_FRAME_RX(dma_desc); + num_frags++; + if (eof_found) { + break; + } + + MODULO_INC_RX(tail); + + if (tail == dev_data->dma_desc_rx_tail) { + /* wrapped */ + break; + } + + dma_desc = &rx_dma_desc[tail]; + } + + if (!eof_found) { + return NULL; + } + + frame_end_index = tail; + + pkt = net_pkt_rx_alloc(K_NO_WAIT); + if (pkt == NULL) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.rx++; + dev_data->stats.error_details.rx_no_buffer_count++; +#endif + LOG_DBG("Net packet allocation error"); + /* continue because we still need to read out the packet */ + } + + tail = dev_data->dma_desc_rx_tail; + dma_desc = &rx_dma_desc[tail]; + for (;;) { + if (pkt != NULL) { + uint16_t frag_len = CONFIG_NET_BUF_DATA_SIZE; + + frag = dev_data->rx_frag_list[tail]; + if (tail == frame_end_index) { + frag_len = TOTAL_FRAME_LENGTH(dma_desc) - + CONFIG_NET_BUF_DATA_SIZE * (num_frags - 1); + + if (IS_TIMESTAMP_AVAILABLE_RX(dma_desc)) { + struct net_ptp_time timestamp = { + .second = dma_desc->time_stamp_seconds, + .nanosecond = dma_desc->time_stamp_nanoseconds}; + + net_pkt_set_timestamp(pkt, ×tamp); + net_pkt_set_priority(pkt, NET_PRIORITY_CA); + } + } + + new_frag = net_pkt_get_frag(pkt, CONFIG_NET_BUF_DATA_SIZE, K_NO_WAIT); + if (new_frag == NULL) { +#ifdef CONFIG_NET_STATISTICS_ETHERNET + dev_data->stats.errors.rx++; + dev_data->stats.error_details.rx_buf_alloc_failed++; +#endif + LOG_DBG("Frag allocation error. Increase CONFIG_NET_BUF_RX_COUNT."); + net_pkt_unref(pkt); + pkt = NULL; + } else { + net_buf_add(frag, frag_len); + if (!last_frag) { + net_pkt_frag_insert(pkt, frag); + } else { + net_buf_frag_insert(last_frag, frag); + } + + last_frag = frag; + frag = new_frag; + dev_data->rx_frag_list[tail] = frag; + } + } + + dma_desc->buffer1 = (uint32_t)dev_data->rx_frag_list[tail]->data; + dma_desc->length = dev_data->rx_frag_list[tail]->size | + ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK; + dma_desc->status = ETH_MAC_DMA_RDES0_OWN; + + if (tail == frame_end_index) { + break; + } + + MODULO_INC_RX(tail); + dma_desc = &rx_dma_desc[tail]; + } + + + MODULO_INC_RX(tail); + dev_data->dma_desc_rx_tail = tail; + + eth_xmc4xxx_trigger_dma_rx(dev_cfg->regs); + + return pkt; +} + +static void eth_xmc4xxx_handle_rx(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + struct net_pkt *pkt = NULL; + + for (;;) { + uint16_t vlan_tag = NET_VLAN_TAG_UNSPEC; + + pkt = eth_xmc4xxx_rx_pkt(dev); + if (!pkt) { + return; + } +#if defined(CONFIG_NET_VLAN) + struct net_eth_hdr *hdr = NET_ETH_HDR(pkt); + + if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) { + struct net_eth_vlan_hdr *hdr_vlan = (struct net_eth_vlan_hdr *)hdr; + + net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci)); + vlan_tag = net_pkt_vlan_tag(pkt); + +#if CONFIG_NET_TC_RX_COUNT > 1 + enum net_priority prio; + + prio = net_vlan2priority(net_pkt_vlan_priority(pkt)); + net_pkt_set_priority(pkt, prio); +#endif + } +#endif /* CONFIG_NET_VLAN */ + if (net_recv_data(get_iface(dev_data, vlan_tag), pkt) < 0) { + eth_stats_update_errors_rx(get_iface(dev_data, vlan_tag)); + net_pkt_unref(pkt); + } + } +} + +static void eth_xmc4xxx_handle_tx(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + sys_snode_t *node = sys_slist_peek_head(&dev_data->tx_frame_list); + + while (node) { + struct eth_xmc4xxx_tx_frame *tx_frame = SYS_SLIST_CONTAINER(node, tx_frame, node); + bool owned_by_mcu = true; + uint8_t index; + int num_descriptors; + + if (tx_frame->head_index >= tx_frame->tail_index) { + num_descriptors = tx_frame->head_index - tx_frame->tail_index + 1; + } else { + num_descriptors = tx_frame->head_index + NUM_TX_DMA_DESCRIPTORS - + tx_frame->tail_index + 1; + } + + index = tx_frame->tail_index; + for (int i = 0; i < num_descriptors; i++) { + if (IS_OWNED_BY_DMA_TX(&tx_dma_desc[index])) { + owned_by_mcu = false; + break; + } + + MODULO_INC_TX(index); + } + + if (owned_by_mcu) { +#if defined(CONFIG_NET_GPTP) + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &tx_dma_desc[tx_frame->head_index]; + + if (IS_TIMESTAMP_AVAILABLE_TX(dma_desc)) { + struct net_pkt *pkt = tx_frame->pkt; + + if (atomic_get(&pkt->atomic_ref) > 1) { + struct net_ptp_time timestamp = { + .second = dma_desc->time_stamp_seconds, + .nanosecond = dma_desc->time_stamp_nanoseconds}; + + net_pkt_set_timestamp(pkt, ×tamp); + net_if_add_tx_timestamp(pkt); + } + } +#endif + + for (int i = 0; i < num_descriptors; i++) { + k_sem_give(&dev_data->tx_desc_sem); + } + + sys_slist_get(&dev_data->tx_frame_list); + net_pkt_unref(tx_frame->pkt); + k_mem_slab_free(&tx_frame_slab, (void *)tx_frame); + node = sys_slist_peek_head(&dev_data->tx_frame_list); + } else { + node = NULL; + } + } +} + +static void eth_xmc4xxx_isr(const struct device *dev) +{ + uint32_t lock; + uint32_t status; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + lock = irq_lock(); + status = dev_cfg->regs->STATUS; + + if ((status & XMC_ETH_MAC_EVENT_RECEIVE) != 0) { + eth_xmc4xxx_handle_rx(dev); + } + + if ((status & XMC_ETH_MAC_EVENT_TRANSMIT) != 0) { + eth_xmc4xxx_handle_tx(dev); + } + + if ((status & ETH_STATUS_ERROR_TRANSMIT_EVENTS) != 0) { + LOG_ERR("Transmit error event [0x%x]", status); + eth_xmc4xxx_flush_tx(dev); + } + + if ((status & ETH_STATUS_ERROR_RECEIVE_EVENTS) != 0) { + LOG_ERR("Receive error event [0x%x]", status); + eth_xmc4xxx_flush_rx(dev); + } + + dev_cfg->regs->STATUS = status & ETH_STATUS_CLEARABLE_BITS; + + irq_unlock(lock); +} + +static inline void eth_xmc4xxx_enable_tx(ETH_GLOBAL_TypeDef *regs) +{ + regs->OPERATION_MODE |= ETH_OPERATION_MODE_ST_Msk; + regs->MAC_CONFIGURATION |= ETH_MAC_CONFIGURATION_TE_Msk; +} + +static inline void eth_xmc4xxx_enable_rx(ETH_GLOBAL_TypeDef *regs) +{ + regs->OPERATION_MODE |= ETH_OPERATION_MODE_SR_Msk; + regs->MAC_CONFIGURATION |= ETH_MAC_CONFIGURATION_RE_Msk; +} + +static inline void eth_xmc4xxx_set_link(ETH_GLOBAL_TypeDef *regs, struct phy_link_state *state) +{ + uint32_t reg = regs->MAC_CONFIGURATION; + uint32_t val; + + reg &= ~(ETH_MAC_CONFIGURATION_DM_Msk | ETH_MAC_CONFIGURATION_FES_Msk); + + val = PHY_LINK_IS_FULL_DUPLEX(state->speed) ? ETH_LINK_DUPLEX_FULL : + ETH_LINK_DUPLEX_HALF; + reg |= FIELD_PREP(ETH_MAC_CONFIGURATION_DM_Msk, val); + + val = PHY_LINK_IS_SPEED_100M(state->speed) ? ETH_LINK_SPEED_100M : + ETH_LINK_SPEED_10M; + reg |= FIELD_PREP(ETH_MAC_CONFIGURATION_FES_Msk, val); + + regs->MAC_CONFIGURATION = reg; +} + +static void phy_link_state_changed(const struct device *phy_dev, struct phy_link_state *state, + void *user_data) +{ + struct device *dev = user_data; + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + bool is_up = state->is_up; + + if (is_up && !dev_data->link_up) { + LOG_INF("Link up"); + dev_data->link_up = true; + net_eth_carrier_on(dev_data->iface); + eth_xmc4xxx_set_link(dev_cfg->regs, state); + } else if (!is_up && dev_data->link_up) { + LOG_INF("Link down"); + dev_data->link_up = false; + net_eth_carrier_off(dev_data->iface); + } +} + +static void eth_xmc4xxx_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_data->iface = iface; + + net_if_set_link_addr(iface, dev_data->mac_addr, sizeof(dev_data->mac_addr), + NET_LINK_ETHERNET); + + ethernet_init(iface); + + dev_cfg->irq_config_func(); + + /* Do not start the interface until PHY link is up */ + net_if_carrier_off(iface); + + phy_link_callback_set(dev_cfg->phy_dev, &phy_link_state_changed, (void *)dev); + + dev_cfg->regs->INTERRUPT_ENABLE |= ETH_STATUS_ALL_EVENTS; + + eth_xmc4xxx_enable_tx(dev_cfg->regs); + eth_xmc4xxx_enable_rx(dev_cfg->regs); +} + +#if defined(CONFIG_NET_STATISTICS_ETHERNET) +static struct net_stats_eth *eth_xmc4xxx_stats(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + return &dev_data->stats; +} +#endif + +static inline void eth_xmc4xxx_free_rx_bufs(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + if (dev_data->rx_frag_list[i]) { + net_buf_unref(dev_data->rx_frag_list[i]); + dev_data->rx_frag_list[i] = NULL; + } + } +} + +static int eth_xmc4xxx_rx_dma_descriptors_init(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_cfg->regs->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t)&rx_dma_desc[0]; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS - 1; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &rx_dma_desc[i]; + + dma_desc->buffer2 = (volatile uint32_t)&rx_dma_desc[i + 1]; + } + + rx_dma_desc[NUM_RX_DMA_DESCRIPTORS - 1].status |= ETH_MAC_DMA_TDES0_TER; + rx_dma_desc[NUM_RX_DMA_DESCRIPTORS - 1].buffer2 = (volatile uint32_t)&rx_dma_desc[0]; + + for (int i = 0; i < NUM_RX_DMA_DESCRIPTORS; i++) { + XMC_ETH_MAC_DMA_DESC_t *dma_desc = &rx_dma_desc[i]; + struct net_buf *rx_buf = net_pkt_get_reserve_rx_data(CONFIG_NET_BUF_DATA_SIZE, + K_NO_WAIT); + + if (rx_buf == NULL) { + eth_xmc4xxx_free_rx_bufs(dev); + LOG_ERR("Failed to reserve data net buffers"); + return -ENOBUFS; + } + + dev_data->rx_frag_list[i] = rx_buf; + dma_desc->buffer1 = (uint32_t)rx_buf->data; + dma_desc->length = rx_buf->size | ETH_RX_DMA_DESC_SECOND_ADDR_CHAINED_MASK; + dma_desc->status = ETH_MAC_DMA_RDES0_OWN; + } + + return 0; +} + +static inline int eth_xmc4xxx_reset(const struct device *dev) +{ + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + dev_cfg->regs->BUS_MODE |= ETH_BUS_MODE_SWR_Msk; + + /* reset may fail if the clocks are not properly setup */ + if (!WAIT_FOR((dev_cfg->regs->BUS_MODE & ETH_BUS_MODE_SWR_Msk) == 0, + ETH_RESET_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static inline void eth_xmc4xxx_set_mac_address(ETH_GLOBAL_TypeDef *regs, uint8_t *const addr) +{ + regs->MAC_ADDRESS0_HIGH = addr[4] | (addr[5] << 8); + regs->MAC_ADDRESS0_LOW = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24); +} + +static inline void eth_xmc4xxx_mask_unused_interrupts(ETH_GLOBAL_TypeDef *regs) +{ + /* Disable Mac Management Counter (MMC) interrupt events */ + regs->MMC_TRANSMIT_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_INTERRUPT_MSK; + regs->MMC_RECEIVE_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_INTERRUPT_MSK; + + /* IPC - Receive IP checksum checker */ + regs->MMC_IPC_RECEIVE_INTERRUPT_MASK = ETH_MAC_DISABLE_MMC_IPC_RECEIVE_INTERRUPT_MSK; + + /* Disable PMT and timestamp interrupt events */ + regs->INTERRUPT_MASK = ETH_INTERRUPT_MASK_PMTIM_Msk | ETH_INTERRUPT_MASK_TSIM_Msk; +} + +static inline int eth_xmc4xxx_init_timestamp_control_reg(ETH_GLOBAL_TypeDef *regs) +{ +#if defined(CONFIG_NET_GPTP) + regs->TIMESTAMP_CONTROL = ETH_TIMESTAMP_CONTROL_TSENA_Msk | + ETH_TIMESTAMP_CONTROL_TSENALL_Msk; +#endif + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + /* use fine control */ + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSCFUPDT_Msk | + ETH_TIMESTAMP_CONTROL_TSCTRLSSR_Msk; + + /* make ptp run at 50MHz - implies 20ns increment for each increment of the */ + /* sub_second_register */ + regs->SUB_SECOND_INCREMENT = 20; + + /* f_out = f_cpu * K / 2^32, where K = TIMESTAMP_ADDEND. Target F_out = 50MHz */ + /* Therefore, K = ceil(f_out * 2^32 / f_cpu) */ + + uint32_t f_cpu = XMC_SCU_CLOCK_GetSystemClockFrequency(); + uint32_t K = (BIT64(32) * ETH_PTP_CLOCK_FREQUENCY + f_cpu / 2) / f_cpu; + + regs->TIMESTAMP_ADDEND = K; + + /* Addend register update */ + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSADDREG_Msk; + if (!WAIT_FOR((regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSADDREG_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSINIT_Msk; + if (!WAIT_FOR((regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSINIT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } +#endif + return 0; +} + +static int eth_xmc4xxx_init(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl; + int ret; + + sys_slist_init(&dev_data->tx_frame_list); + k_sem_init(&dev_data->tx_desc_sem, NUM_TX_DMA_DESCRIPTORS, + NUM_TX_DMA_DESCRIPTORS); + + if (!device_is_ready(dev_cfg->phy_dev)) { + LOG_ERR("Phy device not ready"); + return -ENODEV; + } + + /* get the port control initialized by MDIO driver */ + port_ctrl.raw = ETH0_CON->CON; + port_ctrl.raw |= dev_cfg->port_ctrl.raw; + + XMC_ETH_MAC_Disable(NULL); + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + XMC_ETH_MAC_SetPortControl(NULL, port_ctrl); + XMC_ETH_MAC_Enable(NULL); + + ret = eth_xmc4xxx_reset(dev); + if (ret != 0) { + LOG_ERR("Error resetting ethernet [%d]", ret); + return ret; + } + + /* Initialize MAC configuration */ + /* enable checksum offload */ + dev_cfg->regs->MAC_CONFIGURATION = ETH_MAC_CONFIGURATION_IPC_Msk; + + /* disable jumbo frames */ + dev_cfg->regs->MAC_CONFIGURATION &= ~ETH_MAC_CONFIGURATION_JE_Msk; + + + /* Initialize Filter registers - disable zero quanta pause*/ + dev_cfg->regs->FLOW_CONTROL = ETH_FLOW_CONTROL_DZPQ_Msk; + + /* rsf - receive store and forward */ + /* tsf - transmit store and forward */ + dev_cfg->regs->OPERATION_MODE = ETH_OPERATION_MODE_RSF_Msk | ETH_OPERATION_MODE_TSF_Msk | + ETH_OPERATION_MODE_OSF_Msk; + + /* Increase enhanced descriptor to 8 WORDS, required when the Advanced */ + /* Time-Stamp feature or Full IPC Offload Engine is enabled */ + dev_cfg->regs->BUS_MODE = ETH_BUS_MODE_ATDS_Msk | ETH_BUS_MODE_AAL_Msk | + ETH_BUS_MODE_FB_Msk | (0x20 << ETH_BUS_MODE_PBL_Pos); + + eth_xmc4xxx_tx_dma_descriptors_init(dev); + ret = eth_xmc4xxx_rx_dma_descriptors_init(dev); + if (ret != 0) { + return ret; + } + + /* Clear interrupts */ + dev_cfg->regs->STATUS = ETH_STATUS_CLEARABLE_BITS; + + eth_xmc4xxx_mask_unused_interrupts(dev_cfg->regs); + +#if !DT_INST_NODE_HAS_PROP(0, local_mac_address) + gen_random_mac(dev_data->mac_addr, INFINEON_OUI_B0, INFINEON_OUI_B1, INFINEON_OUI_B2); +#endif + eth_xmc4xxx_set_mac_address(dev_cfg->regs, dev_data->mac_addr); + + uint32_t reg = dev_cfg->regs->MAC_FRAME_FILTER; + /* enable reception of broadcast frames */ + reg &= ~ETH_MAC_FRAME_FILTER_DBF_Msk; + /* pass all multicast frames */ + reg |= ETH_MAC_FRAME_FILTER_PM_Msk; + dev_cfg->regs->MAC_FRAME_FILTER = reg; + + return eth_xmc4xxx_init_timestamp_control_reg(dev_cfg->regs); +} + +static enum ethernet_hw_caps eth_xmc4xxx_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + enum ethernet_hw_caps caps = ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T | + ETHERNET_HW_TX_CHKSUM_OFFLOAD | ETHERNET_HW_RX_CHKSUM_OFFLOAD; + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + caps |= ETHERNET_PTP; +#endif + +#if defined(CONFIG_NET_VLAN) + caps |= ETHERNET_HW_VLAN; +#endif + + return caps; +} + +static int eth_xmc4xxx_set_config(const struct device *dev, enum ethernet_config_type type, + const struct ethernet_config *config) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + switch (type) { + case ETHERNET_CONFIG_TYPE_MAC_ADDRESS: + memcpy(dev_data->mac_addr, config->mac_address.addr, sizeof(dev_data->mac_addr)); + LOG_INF("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x", dev->name, + dev_data->mac_addr[0], dev_data->mac_addr[1], dev_data->mac_addr[2], + dev_data->mac_addr[3], dev_data->mac_addr[4], dev_data->mac_addr[5]); + + eth_xmc4xxx_set_mac_address(dev_cfg->regs, dev_data->mac_addr); + net_if_set_link_addr(dev_data->iface, dev_data->mac_addr, + sizeof(dev_data->mac_addr), NET_LINK_ETHERNET); + return 0; + default: + break; + } + + return -ENOTSUP; +} + +static void eth_xmc4xxx_irq_config(void) +{ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), eth_xmc4xxx_isr, + DEVICE_DT_INST_GET(0), 0); + irq_enable(DT_INST_IRQN(0)); +} + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) +static const struct device *eth_xmc4xxx_get_ptp_clock(const struct device *dev) +{ + struct eth_xmc4xxx_data *dev_data = dev->data; + + return dev_data->ptp_clock; +} +#endif + + +#if defined(CONFIG_ETH_XMC4XXX_VLAN_HW_FILTER) +int eth_xmc4xxx_vlan_setup(const struct device *dev, struct net_if *iface, uint16_t tag, + bool enable) +{ + ARG_UNUSED(iface); + const struct eth_xmc4xxx_config *dev_cfg = dev->config; + + LOG_INF("Configuring vlan %d", tag); + + if (enable) { + dev_cfg->regs->VLAN_TAG = FIELD_PREP(ETH_VLAN_TAG_VL_Msk, tag) | + ETH_VLAN_TAG_ETV_Msk | + ETH_VLAN_TAG_ESVL_Msk; + dev_cfg->regs->MAC_FRAME_FILTER |= ETH_MAC_FRAME_FILTER_VTFE_Msk; + } else { + dev_cfg->regs->VLAN_TAG = 0; + dev_cfg->regs->MAC_FRAME_FILTER &= ~ETH_MAC_FRAME_FILTER_VTFE_Msk; + } + + return 0; +} +#endif + +static const struct ethernet_api eth_xmc4xxx_api = { + .iface_api.init = eth_xmc4xxx_iface_init, + .send = eth_xmc4xxx_send, + .set_config = eth_xmc4xxx_set_config, + .get_capabilities = eth_xmc4xxx_capabilities, +#if defined(CONFIG_NET_STATISTICS_ETHERNET) + .get_stats = eth_xmc4xxx_stats, +#endif +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + .get_ptp_clock = eth_xmc4xxx_get_ptp_clock, +#endif +#if defined(CONFIG_ETH_XMC4XXX_VLAN_HW_FILTER) + .vlan_setup = eth_xmc4xxx_vlan_setup, +#endif +}; + +PINCTRL_DT_INST_DEFINE(0); + +static struct eth_xmc4xxx_config eth_xmc4xxx_config = { + .regs = (ETH_GLOBAL_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(0)), + .irq_config_func = eth_xmc4xxx_irq_config, + .phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, phy_handle)), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .port_ctrl = { + .rxd0 = DT_INST_ENUM_IDX(0, rxd0_port_ctrl), + .rxd1 = DT_INST_ENUM_IDX(0, rxd1_port_ctrl), + .rxd2 = DT_INST_ENUM_IDX_OR(0, rxd2_port_ctrl, 0), + .rxd3 = DT_INST_ENUM_IDX_OR(0, rxd3_port_ctrl, 0), + .clk_rmii = DT_INST_ENUM_IDX(0, rmii_rx_clk_port_ctrl), + .crs_dv = DT_INST_ENUM_IDX(0, crs_rx_dv_port_ctrl), + .crs = DT_INST_ENUM_IDX_OR(0, crs_port_ctrl, 0), + .rxer = DT_INST_ENUM_IDX(0, rxer_port_ctrl), + .col = DT_INST_ENUM_IDX_OR(0, col_port_ctrl, 0), + .clk_tx = DT_INST_ENUM_IDX_OR(0, tx_clk_port_ctrl, 0), + .mode = DT_INST_ENUM_IDX_OR(0, phy_connection_type, 0), + } +}; + +static struct eth_xmc4xxx_data eth_xmc4xxx_data = { + .mac_addr = DT_INST_PROP_OR(0, local_mac_address, {0}), +}; + +ETH_NET_DEVICE_DT_INST_DEFINE(0, eth_xmc4xxx_init, NULL, ð_xmc4xxx_data, ð_xmc4xxx_config, + CONFIG_ETH_INIT_PRIORITY, ð_xmc4xxx_api, NET_ETH_MTU); + +#if defined(CONFIG_PTP_CLOCK_XMC4XXX) + +struct ptp_context { + const struct device *eth_dev; +}; + +static struct ptp_context ptp_xmc4xxx_context_0; + +static int eth_xmc4xxx_ptp_clock_set(const struct device *dev, struct net_ptp_time *tm) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + + dev_cfg->regs->SYSTEM_TIME_NANOSECONDS_UPDATE = tm->nanosecond; + dev_cfg->regs->SYSTEM_TIME_SECONDS_UPDATE = tm->second; + + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSINIT_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSINIT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_get(const struct device *dev, struct net_ptp_time *tm) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + + uint32_t nanosecond_0 = dev_cfg->regs->SYSTEM_TIME_NANOSECONDS; + uint32_t second_0 = dev_cfg->regs->SYSTEM_TIME_SECONDS; + + uint32_t nanosecond_1 = dev_cfg->regs->SYSTEM_TIME_NANOSECONDS; + uint32_t second_1 = dev_cfg->regs->SYSTEM_TIME_SECONDS; + + /* check that there is no roll over while we read the timestamp. If roll over happens */ + /* just choose the later value */ + if (second_0 == second_1) { + tm->second = second_0; + tm->nanosecond = nanosecond_0; + } else { + tm->second = second_1; + tm->nanosecond = nanosecond_1; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_adjust(const struct device *dev, int increment) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + uint32_t increment_tmp; + + if ((increment <= -(int)NSEC_PER_SEC) || (increment >= (int)NSEC_PER_SEC)) { + return -EINVAL; + } + + if (increment < 0) { + increment_tmp = -increment; + increment_tmp |= ETH_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_Msk; + } else { + increment_tmp = increment; + } + + dev_cfg->regs->SYSTEM_TIME_NANOSECONDS_UPDATE = increment_tmp; + dev_cfg->regs->SYSTEM_TIME_SECONDS_UPDATE = 0; + + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSUPDT_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSUPDT_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static int eth_xmc4xxx_ptp_clock_rate_adjust(const struct device *dev, double ratio) +{ + struct ptp_context *ptp_context = dev->data; + const struct eth_xmc4xxx_config *dev_cfg = ptp_context->eth_dev->config; + uint64_t K = dev_cfg->regs->TIMESTAMP_ADDEND; + + if (ratio < ETH_PTP_RATE_ADJUST_RATIO_MIN || ratio > ETH_PTP_RATE_ADJUST_RATIO_MAX) { + return -EINVAL; + } + + /* f_out = f_cpu * K / 2^32, where K = TIMESTAMP_ADDEND. Target F_out = 50MHz */ + K = K * ratio + 0.5; + if (K > UINT32_MAX) { + return -EINVAL; + } + dev_cfg->regs->TIMESTAMP_ADDEND = K; + + /* Addend register update */ + dev_cfg->regs->TIMESTAMP_CONTROL |= ETH_TIMESTAMP_CONTROL_TSADDREG_Msk; + if (!WAIT_FOR((dev_cfg->regs->TIMESTAMP_CONTROL & ETH_TIMESTAMP_CONTROL_TSADDREG_Msk) == 0, + ETH_TIMESTAMP_CONTROL_REG_TIMEOUT_USEC,)) { + return -ETIMEDOUT; + } + + return 0; +} + +static const struct ptp_clock_driver_api ptp_api_xmc4xxx = { + .set = eth_xmc4xxx_ptp_clock_set, + .get = eth_xmc4xxx_ptp_clock_get, + .adjust = eth_xmc4xxx_ptp_clock_adjust, + .rate_adjust = eth_xmc4xxx_ptp_clock_rate_adjust, +}; + +static int ptp_clock_xmc4xxx_init(const struct device *port) +{ + const struct device *const eth_dev = DEVICE_DT_INST_GET(0); + struct eth_xmc4xxx_data *dev_data = eth_dev->data; + struct ptp_context *ptp_context = port->data; + + dev_data->ptp_clock = port; + ptp_context->eth_dev = eth_dev; + + return 0; +} + +DEVICE_DEFINE(xmc4xxx_ptp_clock_0, PTP_CLOCK_NAME, ptp_clock_xmc4xxx_init, NULL, + &ptp_xmc4xxx_context_0, NULL, POST_KERNEL, CONFIG_PTP_CLOCK_INIT_PRIORITY, + &ptp_api_xmc4xxx); + +#endif /* CONFIG_PTP_CLOCK_XMC4XXX */ diff --git a/drivers/ethernet/oa_tc6.c b/drivers/ethernet/oa_tc6.c index 0fa1f105581..2b1e017f007 100644 --- a/drivers/ethernet/oa_tc6.c +++ b/drivers/ethernet/oa_tc6.c @@ -135,23 +135,30 @@ int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val) return ret; } -int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote) +int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, + uint32_t mask, uint32_t val) { - uint32_t val; + uint32_t tmp; int ret; - ret = oa_tc6_reg_read(tc6, OA_CONFIG0, &val); + ret = oa_tc6_reg_read(tc6, reg, &tmp); if (ret < 0) { return ret; } - if (prote) { - val |= OA_CONFIG0_PROTE; - } else { - val &= ~OA_CONFIG0_PROTE; + tmp &= ~mask; + + if (val) { + tmp |= val; } - ret = oa_tc6_reg_write(tc6, OA_CONFIG0, val); + return oa_tc6_reg_write(tc6, reg, tmp); +} + +int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote) +{ + int ret = oa_tc6_reg_rmw(tc6, OA_CONFIG0, OA_CONFIG0_PROTE, + prote ? OA_CONFIG0_PROTE : 0); if (ret < 0) { return ret; } @@ -168,7 +175,14 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) uint8_t chunks, i; int ret; - chunks = (len / tc6->cps) + 1; + if (len == 0) { + return -ENODATA; + } + + chunks = len / tc6->cps; + if (len % tc6->cps) { + chunks++; + } /* Check if LAN865x has any free internal buffer space */ if (chunks > tc6->txc) { @@ -183,7 +197,7 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) FIELD_PREP(OA_DATA_HDR_SWO, 0); if (i == 1) { - hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); + hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1); } if (i == chunks) { @@ -209,26 +223,48 @@ int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) return 0; } -static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) +int oa_tc6_check_status(struct oa_tc6 *tc6) { - tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr); - tc6->sync = FIELD_GET(OA_DATA_FTR_SYNC, ftr); - tc6->rca = FIELD_GET(OA_DATA_FTR_RCA, ftr); - tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr); + uint32_t sts; + + if (!tc6->sync) { + LOG_ERR("SYNC: Configuration lost, reset IC!"); + return -EIO; + } + + if (tc6->exst) { + /* + * Just clear any pending interrupts. + * The RESETC is handled separately as it requires per + * device configuration. + */ + oa_tc6_reg_read(tc6, OA_STATUS0, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS0, sts); + LOG_WRN("EXST: OA_STATUS0: 0x%x", sts); + } + + oa_tc6_reg_read(tc6, OA_STATUS1, &sts); + if (sts != 0) { + oa_tc6_reg_write(tc6, OA_STATUS1, sts); + LOG_WRN("EXST: OA_STATUS1: 0x%x", sts); + } + } + + return 0; } -int oa_tc6_update_buf_info(struct oa_tc6 *tc6) +static int oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr) { - uint32_t val; - int ret; - - ret = oa_tc6_reg_read(tc6, OA_BUFSTS, &val); - if (ret < 0) { - return ret; + if (oa_tc6_get_parity(ftr)) { + LOG_DBG("OA Status Update: Footer parity error!"); + return -EIO; } - tc6->rca = FIELD_GET(OA_BUFSTS_RCA, val); - tc6->txc = FIELD_GET(OA_BUFSTS_TXC, val); + tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr); + tc6->sync = FIELD_GET(OA_DATA_FTR_SYNC, ftr); + tc6->rca = FIELD_GET(OA_DATA_FTR_RCA, ftr); + tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr); return 0; } @@ -266,9 +302,8 @@ int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_ return ret; } *ftr = sys_be32_to_cpu(*ftr); - oa_tc6_update_status(tc6, *ftr); - return 0; + return oa_tc6_update_status(tc6, *ftr); } int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) @@ -286,8 +321,8 @@ int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr) int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) { struct net_buf *buf_rx = NULL; - uint8_t chunks, sbo, ebo; uint32_t hdr, ftr; + uint8_t sbo, ebo; int ret; /* @@ -299,7 +334,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) tc6->concat_buf = NULL; } - for (chunks = tc6->rca; chunks; chunks--) { + do { buf_rx = net_pkt_get_frag(pkt, tc6->cps, OA_TC6_BUF_ALLOC_TIMEOUT); if (!buf_rx) { LOG_ERR("OA RX: Can't allocate RX buffer fordata!"); @@ -327,7 +362,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) } if (!FIELD_GET(OA_DATA_FTR_DV, ftr)) { - LOG_ERR("OA RX: Data chunk not valid, skip!"); + LOG_DBG("OA RX: Data chunk not valid, skip!"); goto unref_buf; } @@ -383,7 +418,7 @@ int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt) */ break; } - } + } while (tc6->rca > 0); return 0; diff --git a/drivers/ethernet/oa_tc6.h b/drivers/ethernet/oa_tc6.h index 7a9337e7c5d..0918e1382fa 100644 --- a/drivers/ethernet/oa_tc6.h +++ b/drivers/ethernet/oa_tc6.h @@ -21,6 +21,7 @@ #define OA_RESET_SWRESET BIT(0) #define OA_CONFIG0 MMS_REG(0x0, 0x004) #define OA_CONFIG0_SYNC BIT(15) +#define OA_CONFIG0_RFA_ZARFE BIT(12) #define OA_CONFIG0_PROTE BIT(5) #define OA_STATUS0 MMS_REG(0x0, 0x008) #define OA_STATUS0_RESETC BIT(6) @@ -76,6 +77,8 @@ #define OA_TC6_HDR_SIZE 4 #define OA_TC6_FTR_SIZE 4 #define OA_TC6_BUF_ALLOC_TIMEOUT K_MSEC(10) +#define OA_TC6_FTR_RCA_MAX GENMASK(4, 0) +#define OA_TC6_FTR_TXC_MAX GENMASK(4, 0) /** * @brief OA TC6 data. @@ -223,11 +226,27 @@ int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_ int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr); /** - * @brief Read from OA TC6 device and update buffer information + * @brief Read, modify and write control register from OA TC6 device + * + * @param tc6 OA TC6 specific data + * + * @param reg register to modify + * + * @param mask bit mask for modified register + * + * @param value to be stored in the register + * + * @return 0 if successful, <0 otherwise. + */ +int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg, + uint32_t mask, uint32_t val); + +/** + * @brief Check the status of OA TC6 device * * @param tc6 OA TC6 specific data * * @return 0 if successful, <0 otherwise. */ -int oa_tc6_update_buf_info(struct oa_tc6 *tc6); +int oa_tc6_check_status(struct oa_tc6 *tc6); #endif /* OA_TC6_CFG_H__ */ diff --git a/drivers/ethernet/phy/CMakeLists.txt b/drivers/ethernet/phy/CMakeLists.txt index ce4cbe3e715..ff25a9a4fa3 100644 --- a/drivers/ethernet/phy/CMakeLists.txt +++ b/drivers/ethernet/phy/CMakeLists.txt @@ -2,3 +2,5 @@ zephyr_library_sources_ifdef(CONFIG_PHY_GENERIC_MII phy_mii.c) zephyr_library_sources_ifdef(CONFIG_PHY_ADIN2111 phy_adin2111.c) +zephyr_library_sources_ifdef(CONFIG_PHY_TJA1103 phy_tja1103.c) +zephyr_library_sources_ifdef(CONFIG_PHY_MICROCHIP_KSZ8081 phy_microchip_ksz8081.c) diff --git a/drivers/ethernet/phy/Kconfig b/drivers/ethernet/phy/Kconfig index ae1229de1fc..e14a27a398d 100644 --- a/drivers/ethernet/phy/Kconfig +++ b/drivers/ethernet/phy/Kconfig @@ -11,6 +11,7 @@ module-dep = LOG module-str = Log level for Ethernet PHY driver module-help = Sets log level for Ethernet PHY Device Drivers. source "subsys/net/Kconfig.template.log_config.net" +source "drivers/ethernet/phy/Kconfig.tja1103" config PHY_INIT_PRIORITY int "Ethernet PHY driver init priority" @@ -23,8 +24,7 @@ config PHY_INIT_PRIORITY config PHY_GENERIC_MII bool "Generic MII PHY Driver" - default y - depends on DT_HAS_ETHERNET_PHY_ENABLED + default y if DT_HAS_ETHERNET_PHY_ENABLED depends on MDIO help This is a generic MII PHY interface that communicates with the @@ -39,6 +39,15 @@ config PHY_ADIN2111 help Enable ADIN2111 PHY driver. +config PHY_MICROCHIP_KSZ8081 + bool "Microchip KSZ8081 Phy Driver" + default y + depends on DT_HAS_MICROCHIP_KSZ8081_ENABLED + depends on MDIO + depends on GPIO + help + Enable Microchip KSZ8081 Ethernet Phy Driver + config PHY_AUTONEG_TIMEOUT_MS int "Auto-negotiation timeout value in milliseconds" default 4000 diff --git a/drivers/ethernet/phy/Kconfig.tja1103 b/drivers/ethernet/phy/Kconfig.tja1103 new file mode 100644 index 00000000000..e0a00955ce7 --- /dev/null +++ b/drivers/ethernet/phy/Kconfig.tja1103 @@ -0,0 +1,30 @@ +# NXP PHY TJA1103 driver configuration options + +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig PHY_TJA1103 + bool "TJA1103 PHY driver" + default y + depends on DT_HAS_NXP_TJA1103_ENABLED + depends on MDIO + help + Enable TJA1103 PHY driver. + +if PHY_TJA1103 + +config PHY_TJA1103_IRQ_THREAD_STACK_SIZE + int "Stack size for a thread that processes TJA1103 IRQ" + default 2048 + help + Size of the stack used for internal thread which is ran to + process raised INT IRQ. + +config PHY_TJA1103_IRQ_THREAD_PRIO + int "Priority for internal incoming packet handler" + default 2 + help + Priority level for internal thread which is ran for TJA1103 + INT IRQ processing. + +endif # PHY_TJA1103 diff --git a/drivers/ethernet/phy/phy_microchip_ksz8081.c b/drivers/ethernet/phy/phy_microchip_ksz8081.c new file mode 100644 index 00000000000..10d7f78172c --- /dev/null +++ b/drivers/ethernet/phy/phy_microchip_ksz8081.c @@ -0,0 +1,478 @@ +/* + * Copyright 2023 NXP + * + * Inspiration from phy_mii.c, which is: + * Copyright (c) 2021 IP-Logix Inc. + * Copyright 2022 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_ksz8081 + +#include +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE_NAME phy_mc_ksz8081 +#define LOG_LEVEL CONFIG_PHY_LOG_LEVEL +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#define PHY_MC_KSZ8081_OMSO_REG 0x16 +#define PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK BIT(15) +#define PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK BIT(5) + +#define PHY_MC_KSZ8081_CTRL2_REG 0x1F +#define PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL BIT(7) + +#define PHY_MC_KSZ8081_RESET_HOLD_TIME + +enum ksz8081_interface { + KSZ8081_MII, + KSZ8081_RMII, + KSZ8081_RMII_25MHZ, +}; + +struct mc_ksz8081_config { + uint8_t addr; + const struct device *mdio_dev; + enum ksz8081_interface phy_iface; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) + const struct gpio_dt_spec reset_gpio; +#endif +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) + const struct gpio_dt_spec interrupt_gpio; +#endif +}; + +struct mc_ksz8081_data { + const struct device *dev; + struct phy_link_state state; + phy_callback_t cb; + void *cb_data; + struct k_mutex mutex; + struct k_work_delayable phy_monitor_work; +}; + +static int phy_mc_ksz8081_read(const struct device *dev, + uint16_t reg_addr, uint32_t *data) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + + ret = mdio_read(config->mdio_dev, config->addr, reg_addr, (uint16_t *)data); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_write(const struct device *dev, + uint16_t reg_addr, uint32_t data) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + + ret = mdio_write(config->mdio_dev, config->addr, reg_addr, (uint16_t)data); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_autonegotiate(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + int ret; + uint32_t bmcr = 0; + uint32_t bmsr = 0; + uint16_t timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100; + + /* Read control register to write back with autonegotiation bit */ + ret = phy_mc_ksz8081_read(dev, MII_BMCR, &bmcr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic control register", config->addr); + return ret; + } + + /* (re)start autonegotiation */ + LOG_DBG("PHY (%d) is entering autonegotiation sequence", config->addr); + bmcr |= MII_BMCR_AUTONEG_ENABLE | MII_BMCR_AUTONEG_RESTART; + bmcr &= ~MII_BMCR_ISOLATE; + + ret = phy_mc_ksz8081_write(dev, MII_BMCR, bmcr); + if (ret) { + LOG_ERR("Error writing phy (%d) basic control register", config->addr); + return ret; + } + + /* TODO change this to GPIO interrupt driven */ + do { + if (timeout-- == 0) { + LOG_DBG("PHY (%d) autonegotiation timed out", config->addr); + return -ETIMEDOUT; + } + k_msleep(100); + + ret = phy_mc_ksz8081_read(dev, MII_BMSR, &bmsr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic status register", config->addr); + return ret; + } + } while (!(bmsr & MII_BMSR_AUTONEG_COMPLETE)); + + LOG_DBG("PHY (%d) autonegotiation completed", config->addr); + + return 0; +} + +static int phy_mc_ksz8081_get_link(const struct device *dev, + struct phy_link_state *state) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + uint32_t bmsr = 0; + uint32_t anar = 0; + uint32_t anlpar = 0; + struct phy_link_state old_state = data->state; + + /* Lock mutex */ + ret = k_mutex_lock(&data->mutex, K_FOREVER); + if (ret) { + LOG_ERR("PHY mutex lock error"); + return ret; + } + + /* Read link state */ + ret = phy_mc_ksz8081_read(dev, MII_BMSR, &bmsr); + if (ret) { + LOG_ERR("Error reading phy (%d) basic status register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + state->is_up = bmsr & MII_BMSR_LINK_STATUS; + + if (!state->is_up) { + goto result; + } + + /* Read currently configured advertising options */ + ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); + if (ret) { + LOG_ERR("Error reading phy (%d) advertising register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Read link partner capability */ + ret = phy_mc_ksz8081_read(dev, MII_ANLPAR, &anlpar); + if (ret) { + LOG_ERR("Error reading phy (%d) link partner register", config->addr); + k_mutex_unlock(&data->mutex); + return ret; + } + + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + + uint32_t mutual_capabilities = anar & anlpar; + + if (mutual_capabilities & MII_ADVERTISE_100_FULL) { + state->speed = LINK_FULL_100BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_100_HALF) { + state->speed = LINK_HALF_100BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_10_FULL) { + state->speed = LINK_FULL_10BASE_T; + } else if (mutual_capabilities & MII_ADVERTISE_10_HALF) { + state->speed = LINK_HALF_10BASE_T; + } else { + ret = -EIO; + } + +result: + if (memcmp(&old_state, state, sizeof(struct phy_link_state)) != 0) { + LOG_DBG("PHY %d is %s", config->addr, state->is_up ? "up" : "down"); + LOG_DBG("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, + (PHY_LINK_IS_SPEED_100M(state->speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(state->speed) ? "full" : "half"); + } + + return ret; +} + +/* + * Configuration set statically (DT) that should never change + * This function is needed in case the PHY is reset then the next call + * to configure the phy will ensure this configuration will be redone + */ +static int phy_mc_ksz8081_static_cfg(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + uint32_t omso = 0; + uint32_t ctrl2 = 0; + int ret = 0; + + /* Force normal operation in the case of factory mode */ + ret = phy_mc_ksz8081_read(dev, PHY_MC_KSZ8081_OMSO_REG, (uint32_t *)&omso); + if (ret) { + return ret; + } + + omso &= ~PHY_MC_KSZ8081_OMSO_FACTORY_MODE_MASK & + ~PHY_MC_KSZ8081_OMSO_NAND_TREE_MASK; + + ret = phy_mc_ksz8081_write(dev, PHY_MC_KSZ8081_OMSO_REG, (uint32_t)omso); + if (ret) { + return ret; + } + + /* Select correct reference clock mode depending on interface setup */ + ret = phy_mc_ksz8081_read(dev, PHY_MC_KSZ8081_CTRL2_REG, (uint32_t *)&ctrl2); + if (ret) { + return ret; + } + + if (config->phy_iface == KSZ8081_RMII) { + ctrl2 |= PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL; + } else { + ctrl2 &= ~PHY_MC_KSZ8081_CTRL2_REF_CLK_SEL; + } + + ret = phy_mc_ksz8081_write(dev, PHY_MC_KSZ8081_CTRL2_REG, (uint32_t)ctrl2); + if (ret) { + return ret; + } + + return 0; +} + +static int phy_mc_ksz8081_cfg_link(const struct device *dev, + enum phy_link_speed speeds) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + uint32_t anar; + + /* Lock mutex */ + ret = k_mutex_lock(&data->mutex, K_FOREVER); + if (ret) { + LOG_ERR("PHY mutex lock error"); + goto done; + } + + /* We are going to reconfigure the phy, don't need to monitor until done */ + k_work_cancel_delayable(&data->phy_monitor_work); + + /* DT configurations */ + ret = phy_mc_ksz8081_static_cfg(dev); + if (ret) { + goto done; + } + + /* Read ANAR register to write back */ + ret = phy_mc_ksz8081_read(dev, MII_ANAR, &anar); + if (ret) { + LOG_ERR("Error reading phy (%d) advertising register", config->addr); + goto done; + } + + /* Setup advertising register */ + if (speeds & LINK_FULL_100BASE_T) { + anar |= MII_ADVERTISE_100_FULL; + } else { + anar &= ~MII_ADVERTISE_100_FULL; + } + if (speeds & LINK_HALF_100BASE_T) { + anar |= MII_ADVERTISE_100_HALF; + } else { + anar &= ~MII_ADVERTISE_100_HALF; + } + if (speeds & LINK_FULL_10BASE_T) { + anar |= MII_ADVERTISE_10_FULL; + } else { + anar &= ~MII_ADVERTISE_10_FULL; + } + if (speeds & LINK_HALF_10BASE_T) { + anar |= MII_ADVERTISE_10_HALF; + } else { + anar &= ~MII_ADVERTISE_10_HALF; + } + + /* Write capabilities to advertising register */ + ret = phy_mc_ksz8081_write(dev, MII_ANAR, anar); + if (ret) { + LOG_ERR("Error writing phy (%d) advertising register", config->addr); + goto done; + } + + /* (re)do autonegotiation */ + ret = phy_mc_ksz8081_autonegotiate(dev); + if (ret) { + LOG_ERR("Error in autonegotiation"); + goto done; + } + + /* Get link status */ + ret = phy_mc_ksz8081_get_link(dev, &data->state); + + /* Log the results of the configuration */ + LOG_INF("PHY %d is %s", config->addr, data->state.is_up ? "up" : "down"); + LOG_INF("PHY (%d) Link speed %s Mb, %s duplex\n", config->addr, + (PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"), + PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half"); + +done: + /* Unlock mutex */ + k_mutex_unlock(&data->mutex); + + /* Start monitoring */ + k_work_reschedule(&data->phy_monitor_work, + K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); + + return ret; +} + +static int phy_mc_ksz8081_link_cb_set(const struct device *dev, + phy_callback_t cb, void *user_data) +{ + struct mc_ksz8081_data *data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + phy_mc_ksz8081_get_link(dev, &data->state); + + data->cb(dev, &data->state, data->cb_data); + + return 0; +} + +static void phy_mc_ksz8081_monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct mc_ksz8081_data *data = + CONTAINER_OF(dwork, struct mc_ksz8081_data, phy_monitor_work); + const struct device *dev = data->dev; + struct phy_link_state state; + int rc; + + rc = phy_mc_ksz8081_get_link(dev, &state); + + if (rc == 0 && memcmp(&state, &data->state, sizeof(struct phy_link_state)) != 0) { + memcpy(&data->state, &state, sizeof(struct phy_link_state)); + if (data->cb) { + data->cb(dev, &data->state, data->cb_data); + } + } + + /* TODO change this to GPIO interrupt driven */ + k_work_reschedule(&data->phy_monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + +static int phy_mc_ksz8081_init(const struct device *dev) +{ + const struct mc_ksz8081_config *config = dev->config; + struct mc_ksz8081_data *data = dev->data; + int ret; + + data->dev = dev; + + ret = k_mutex_init(&data->mutex); + if (ret) { + return ret; + } + + mdio_bus_enable(config->mdio_dev); + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) + if (!config->interrupt_gpio.port) { + goto skip_int_gpio; + } + + /* Prevent NAND TREE mode */ + ret = gpio_pin_configure_dt(&config->interrupt_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + +skip_int_gpio: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) */ + + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) + if (!config->reset_gpio.port) { + goto skip_reset_gpio; + } + + /* Start reset */ + ret = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_INACTIVE); + if (ret) { + return ret; + } + + /* Wait for 500 ms as specified by datasheet */ + k_busy_wait(USEC_PER_MSEC * 500); + + /* Reset over */ + ret = gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret) { + return ret; + } + +skip_reset_gpio: +#endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) */ + + k_work_init_delayable(&data->phy_monitor_work, + phy_mc_ksz8081_monitor_work_handler); + + return 0; +} + +static const struct ethphy_driver_api mc_ksz8081_phy_api = { + .get_link = phy_mc_ksz8081_get_link, + .cfg_link = phy_mc_ksz8081_cfg_link, + .link_cb_set = phy_mc_ksz8081_link_cb_set, + .read = phy_mc_ksz8081_read, + .write = phy_mc_ksz8081_write, +}; + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_reset_gpio) +#define RESET_GPIO(n) \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, mc_reset_gpio, {0}), +#else +#define RESET_GPIO(n) +#endif /* reset gpio */ + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(mc_interrupt_gpio) +#define INTERRUPT_GPIO(n) \ + .interrupt_gpio = GPIO_DT_SPEC_INST_GET_OR(n, mc_interrupt_gpio, {0}), +#else +#define INTERRUPT_GPIO(n) +#endif /* interrupt gpio */ + +#define MICROCHIP_KSZ8081_INIT(n) \ + static const struct mc_ksz8081_config mc_ksz8081_##n##_config = { \ + .addr = DT_INST_REG_ADDR(n), \ + .mdio_dev = DEVICE_DT_GET(DT_INST_PARENT(n)), \ + .phy_iface = DT_INST_ENUM_IDX(n, mc_interface_type), \ + RESET_GPIO(n) \ + INTERRUPT_GPIO(n) \ + }; \ + \ + static struct mc_ksz8081_data mc_ksz8081_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &phy_mc_ksz8081_init, NULL, \ + &mc_ksz8081_##n##_data, &mc_ksz8081_##n##_config, \ + POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \ + &mc_ksz8081_phy_api); + +DT_INST_FOREACH_STATUS_OKAY(MICROCHIP_KSZ8081_INIT) diff --git a/drivers/ethernet/phy/phy_mii.c b/drivers/ethernet/phy/phy_mii.c index 4ad961089e6..041be3dafaa 100644 --- a/drivers/ethernet/phy/phy_mii.c +++ b/drivers/ethernet/phy/phy_mii.c @@ -39,6 +39,8 @@ struct phy_mii_dev_data { /* Offset to align capabilities bits of 1000BASE-T Control and Status regs */ #define MII_1KSTSR_OFFSET 2 +#define MII_INVALID_PHY_ID UINT32_MAX + static int phy_mii_get_link_state(const struct device *dev, struct phy_link_state *state); @@ -118,13 +120,13 @@ static int get_id(const struct device *dev, uint32_t *phy_id) return -EIO; } - *phy_id = (value & 0xFFFF) << 16; + *phy_id = value << 16; if (reg_read(dev, MII_PHYID2R, &value) < 0) { return -EIO; } - *phy_id |= (value & 0xFFFF); + *phy_id |= value; return 0; } @@ -436,7 +438,7 @@ static int phy_mii_initialize(const struct device *dev) } if (get_id(dev, &phy_id) == 0) { - if (phy_id == 0xFFFFFF) { + if (phy_id == MII_INVALID_PHY_ID) { LOG_ERR("No PHY found at address %d", cfg->phy_addr); diff --git a/drivers/ethernet/phy/phy_tja1103.c b/drivers/ethernet/phy/phy_tja1103.c new file mode 100644 index 00000000000..659fdbf80aa --- /dev/null +++ b/drivers/ethernet/phy/phy_tja1103.c @@ -0,0 +1,461 @@ +/* + * Copyright 2023 NXP + * Copyright 2023 CogniPilot Foundation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_tja1103 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(phy_tja1103, CONFIG_PHY_LOG_LEVEL); + +/* PHYs out of reset check retry delay */ +#define TJA1103_AWAIT_DELAY_POLL_US 15000U +/* Number of retries for PHYs out of reset check */ +#define TJA1103_AWAIT_RETRY_COUNT 200U + +/* TJA1103 PHY identifier */ +#define TJA1103_ID 0x1BB013 + +/* MMD30 - Device status register */ +#define TJA1103_DEVICE_CONTROL (0x0040U) +#define TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN BIT(14) +#define TJA1103_DEVICE_CONTROL_SUPER_CFG_EN BIT(13) +/* Shared - PHY control register */ +#define TJA1103_PHY_CONTROL (0x8100U) +#define TJA1103_PHY_CONTROL_CFG_EN BIT(14) +/* Shared - PHY status register */ +#define TJA1103_PHY_STATUS (0x8102U) +#define TJA1103_PHY_STATUS_LINK_STAT BIT(2) + +/* Shared - PHY functional IRQ masked status register */ +#define TJA1103_PHY_FUNC_IRQ_MSTATUS (0x80A2) +#define TJA1103_PHY_FUNC_IRQ_LINK_EVENT BIT(1) +#define TJA1103_PHY_FUNC_IRQ_LINK_AVAIL BIT(2) +/* Shared -PHY functional IRQ source & enable registers */ +#define TJA1103_PHY_FUNC_IRQ_ACK (0x80A0) +#define TJA1103_PHY_FUNC_IRQ_EN (0x80A1) +#define TJA1103_PHY_FUNC_IRQ_LINK_EVENT_EN BIT(1) +#define TJA1103_PHY_FUNC_IRQ_LINK_AVAIL_EN BIT(2) +/* Always accessible reg for NMIs */ +#define TJA1103_ALWAYS_ACCESSIBLE (0x801F) +#define TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ BIT(4) + +struct phy_tja1103_config { + const struct device *mdio; + struct gpio_dt_spec gpio_interrupt; + uint8_t phy_addr; + uint8_t master_slave; +}; + +struct phy_tja1103_data { + const struct device *dev; + struct phy_link_state state; + struct k_sem sem; + struct k_sem offload_sem; + phy_callback_t cb; + struct gpio_callback phy_tja1103_int_callback; + void *cb_data; + + K_KERNEL_STACK_MEMBER(irq_thread_stack, CONFIG_PHY_TJA1103_IRQ_THREAD_STACK_SIZE); + struct k_thread irq_thread; + + struct k_work_delayable monitor_work; +}; + +static inline int phy_tja1103_c22_read(const struct device *dev, uint16_t reg, uint16_t *val) +{ + const struct phy_tja1103_config *const cfg = dev->config; + + return mdio_read(cfg->mdio, cfg->phy_addr, reg, val); +} + +static inline int phy_tja1103_c22_write(const struct device *dev, uint16_t reg, uint16_t val) +{ + const struct phy_tja1103_config *const cfg = dev->config; + + return mdio_write(cfg->mdio, cfg->phy_addr, reg, val); +} + +static inline int phy_tja1103_c45_write(const struct device *dev, uint16_t devad, uint16_t reg, + uint16_t val) +{ + const struct phy_tja1103_config *cfg = dev->config; + + return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); +} + +static inline int phy_tja1103_c45_read(const struct device *dev, uint16_t devad, uint16_t reg, + uint16_t *val) +{ + const struct phy_tja1103_config *cfg = dev->config; + + return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val); +} + +static int phy_tja1103_reg_read(const struct device *dev, uint16_t reg_addr, uint32_t *data) +{ + const struct phy_tja1103_config *cfg = dev->config; + int ret; + + mdio_bus_enable(cfg->mdio); + + ret = phy_tja1103_c22_read(dev, reg_addr, (uint16_t *)data); + + mdio_bus_disable(cfg->mdio); + + return ret; +} + +static int phy_tja1103_reg_write(const struct device *dev, uint16_t reg_addr, uint32_t data) +{ + const struct phy_tja1103_config *cfg = dev->config; + int ret; + + mdio_bus_enable(cfg->mdio); + + ret = phy_tja1103_c22_write(dev, reg_addr, (uint16_t)data); + + mdio_bus_disable(cfg->mdio); + + return ret; +} + +static int phy_tja1103_id(const struct device *dev, uint32_t *phy_id) +{ + uint16_t val; + + if (phy_tja1103_c22_read(dev, MII_PHYID1R, &val) < 0) { + return -EIO; + } + + *phy_id = (val & UINT16_MAX) << 16; + + if (phy_tja1103_c22_read(dev, MII_PHYID2R, &val) < 0) { + return -EIO; + } + + *phy_id |= (val & UINT16_MAX); + + return 0; +} + +static int update_link_state(const struct device *dev) +{ + struct phy_tja1103_data *const data = dev->data; + bool link_up; + uint16_t val; + + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_STATUS, &val) < 0) { + return -EIO; + } + + link_up = (val & TJA1103_PHY_STATUS_LINK_STAT) != 0; + + /* Let workqueue re-schedule and re-check if the + * link status is unchanged this time + */ + if (data->state.is_up == link_up) { + return -EAGAIN; + } + + data->state.is_up = link_up; + + return 0; +} + +static int phy_tja1103_get_link_state(const struct device *dev, struct phy_link_state *state) +{ + struct phy_tja1103_data *const data = dev->data; + const struct phy_tja1103_config *const cfg = dev->config; + int rc = 0; + + k_sem_take(&data->sem, K_FOREVER); + + /* If Interrupt is configured then the workqueue will not + * update the link state periodically so do it explicitly + */ + if (cfg->gpio_interrupt.port != NULL) { + rc = update_link_state(dev); + } + + memcpy(state, &data->state, sizeof(struct phy_link_state)); + + k_sem_give(&data->sem); + + return rc; +} + +static void invoke_link_cb(const struct device *dev) +{ + struct phy_tja1103_data *const data = dev->data; + struct phy_link_state state; + + if (data->cb == NULL) { + return; + } + + /* Send callback only on link state change */ + if (phy_tja1103_get_link_state(dev, &state) != 0) { + return; + } + + data->cb(dev, &state, data->cb_data); +} + +static void monitor_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct phy_tja1103_data *const data = + CONTAINER_OF(dwork, struct phy_tja1103_data, monitor_work); + const struct device *dev = data->dev; + int rc; + + k_sem_take(&data->sem, K_FOREVER); + + rc = update_link_state(dev); + + k_sem_give(&data->sem); + + /* If link state has changed and a callback is set, invoke callback */ + if (rc == 0) { + invoke_link_cb(dev); + } + + /* Submit delayed work */ + k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD)); +} + +static void phy_tja1103_irq_offload_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + struct phy_tja1103_data *const data = dev->data; + uint16_t irq; + + for (;;) { + /* await trigger from ISR */ + k_sem_take(&data->offload_sem, K_FOREVER); + + if (phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_PHY_FUNC_IRQ_MSTATUS, &irq) < 0) { + return; + } + + /* Handling Link related Functional IRQs */ + if (irq & (TJA1103_PHY_FUNC_IRQ_LINK_EVENT | TJA1103_PHY_FUNC_IRQ_LINK_AVAIL)) { + /* Send callback to MAC on link status changed */ + invoke_link_cb(dev); + + /* Ack the assered link related interrupts */ + phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_PHY_FUNC_IRQ_ACK, irq); + } + } +} + +static void phy_tja1103_handle_irq(const struct device *port, struct gpio_callback *cb, + uint32_t pins) +{ + ARG_UNUSED(pins); + ARG_UNUSED(port); + + struct phy_tja1103_data *const data = + CONTAINER_OF(cb, struct phy_tja1103_data, phy_tja1103_int_callback); + + /* Trigger BH before leaving the ISR */ + k_sem_give(&data->offload_sem); +} + +static void phy_tja1103_cfg_irq_poll(const struct device *dev) +{ + struct phy_tja1103_data *const data = dev->data; + const struct phy_tja1103_config *const cfg = dev->config; + int ret; + + if (cfg->gpio_interrupt.port != NULL) { + if (!gpio_is_ready_dt(&cfg->gpio_interrupt)) { + LOG_ERR("Interrupt GPIO device %s is not ready", + cfg->gpio_interrupt.port->name); + return; + } + + ret = gpio_pin_configure_dt(&cfg->gpio_interrupt, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Failed to configure interrupt GPIO, %d", ret); + return; + } + + gpio_init_callback(&(data->phy_tja1103_int_callback), phy_tja1103_handle_irq, + BIT(cfg->gpio_interrupt.pin)); + + /* Add callback structure to global syslist */ + ret = gpio_add_callback(cfg->gpio_interrupt.port, &data->phy_tja1103_int_callback); + if (ret < 0) { + LOG_ERR("Failed to add INT callback, %d", ret); + return; + } + + ret = phy_tja1103_c45_write( + dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_FUNC_IRQ_EN, + (TJA1103_PHY_FUNC_IRQ_LINK_EVENT_EN | TJA1103_PHY_FUNC_IRQ_LINK_AVAIL_EN)); + if (ret < 0) { + return; + } + + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_interrupt, GPIO_INT_EDGE_FALLING); + if (ret < 0) { + LOG_ERR("Failed to enable INT, %d", ret); + return; + } + + /* PHY initialized, IRQ configured, now initialize the BH handler */ + k_thread_create(&data->irq_thread, data->irq_thread_stack, + CONFIG_PHY_TJA1103_IRQ_THREAD_STACK_SIZE, + phy_tja1103_irq_offload_thread, (void *)dev, NULL, NULL, + CONFIG_PHY_TJA1103_IRQ_THREAD_PRIO, K_ESSENTIAL, K_NO_WAIT); + k_thread_name_set(&data->irq_thread, "phy_tja1103_irq_offload"); + + } else { + k_work_init_delayable(&data->monitor_work, monitor_work_handler); + + monitor_work_handler(&data->monitor_work.work); + } +} + +static int phy_tja1103_cfg_link(const struct device *dev, enum phy_link_speed adv_speeds) +{ + ARG_UNUSED(dev); + + if (adv_speeds & LINK_FULL_100BASE_T) { + return 0; + } + + return -ENOTSUP; +} + +static int phy_tja1103_init(const struct device *dev) +{ + const struct phy_tja1103_config *const cfg = dev->config; + struct phy_tja1103_data *const data = dev->data; + uint32_t phy_id = 0; + uint16_t val; + int ret; + + data->dev = dev; + data->cb = NULL; + data->state.is_up = false; + data->state.speed = LINK_FULL_100BASE_T; + + ret = WAIT_FOR(!phy_tja1103_id(dev, &phy_id) && phy_id == TJA1103_ID, + TJA1103_AWAIT_RETRY_COUNT * TJA1103_AWAIT_DELAY_POLL_US, + k_sleep(K_USEC(TJA1103_AWAIT_DELAY_POLL_US))); + if (ret < 0) { + LOG_ERR("Unable to obtain PHY ID for device 0x%x", cfg->phy_addr); + return -ENODEV; + } + + /* enable config registers */ + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_DEVICE_CONTROL, + TJA1103_DEVICE_CONTROL_GLOBAL_CFG_EN | + TJA1103_DEVICE_CONTROL_SUPER_CFG_EN); + if (ret < 0) { + return ret; + } + + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_PHY_CONTROL, + TJA1103_PHY_CONTROL_CFG_EN); + if (ret < 0) { + return ret; + } + + ret = phy_tja1103_c45_read(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, &val); + if (ret < 0) { + return ret; + } + + /* Change master/slave mode if need */ + if (cfg->master_slave == 1) { + val |= MDIO_PMA_PMD_BT1_CTRL_CFG_MST; + } else if (cfg->master_slave == 2) { + val &= ~MDIO_PMA_PMD_BT1_CTRL_CFG_MST; + } + + ret = phy_tja1103_c45_write(dev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL, val); + if (ret < 0) { + return ret; + } + + /* Check always accesible register for handling NMIs */ + ret = phy_tja1103_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1, TJA1103_ALWAYS_ACCESSIBLE, &val); + if (ret < 0) { + return ret; + } + + /* Ack Fusa Pass Interrupt if Startup Self Test Passed successfully */ + if (val & TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ) { + ret = phy_tja1103_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1, + TJA1103_ALWAYS_ACCESSIBLE, + TJA1103_ALWAYS_ACCESSIBLE_FUSA_PASS_IRQ); + } + + /* Configure interrupt or poll mode for reporting link changes */ + phy_tja1103_cfg_irq_poll(dev); + + return ret; +} + +static int phy_tja1103_link_cb_set(const struct device *dev, phy_callback_t cb, void *user_data) +{ + struct phy_tja1103_data *const data = dev->data; + + data->cb = cb; + data->cb_data = user_data; + + /* Invoke the callback to notify the caller of the current + * link status. + */ + invoke_link_cb(dev); + + return 0; +} + +static const struct ethphy_driver_api phy_tja1103_api = { + .get_link = phy_tja1103_get_link_state, + .cfg_link = phy_tja1103_cfg_link, + .link_cb_set = phy_tja1103_link_cb_set, + .read = phy_tja1103_reg_read, + .write = phy_tja1103_reg_write, +}; + +#define TJA1103_INITIALIZE(n) \ + static const struct phy_tja1103_config phy_tja1103_config_##n = { \ + .phy_addr = DT_INST_REG_ADDR(n), \ + .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \ + .gpio_interrupt = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {0}), \ + .master_slave = DT_INST_ENUM_IDX(n, master_slave), \ + }; \ + static struct phy_tja1103_data phy_tja1103_data_##n = { \ + .sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.sem, 1, 1), \ + .offload_sem = Z_SEM_INITIALIZER(phy_tja1103_data_##n.offload_sem, 0, 1), \ + }; \ + DEVICE_DT_INST_DEFINE(n, &phy_tja1103_init, NULL, &phy_tja1103_data_##n, \ + &phy_tja1103_config_##n, POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \ + &phy_tja1103_api); + +DT_INST_FOREACH_STATUS_OKAY(TJA1103_INITIALIZE) diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 4a02268a2b4..46694eb4792 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -52,12 +52,14 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_FLASH_ANDES_QSPI flash_andes_qspi.c) zephyr_library_sources_ifdef(CONFIG_FLASH_AMBIQ flash_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_CDNS_NAND flash_cadence_nand.c flash_cadence_nand_ll.c) if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) dt_chosen(chosen_flash PROPERTY "zephyr,flash") dt_prop(compat_flash PATH ${chosen_flash} PROPERTY compatible) if(compat_flash MATCHES "nxp,imx-flexspi-nor") zephyr_code_relocate(FILES flash_mcux_flexspi_nor.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) + zephyr_code_relocate(FILES jesd216.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) elseif(compat_flash MATCHES "nxp,imx-flexspi-mx25um51345g") zephyr_code_relocate(FILES flash_mcux_flexspi_mx25um51345g.c LOCATION ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) elseif(compat_flash MATCHES "nxp,imx-flexspi-hyperflash") @@ -68,20 +70,28 @@ endif() if(CONFIG_SOC_FLASH_STM32) if(CONFIG_SOC_SERIES_STM32H7X) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32H7_FLASH_CONTROLLER_ENABLED flash_stm32h7x.c) + elseif(CONFIG_SOC_SERIES_STM32WBAX) + if(CONFIG_BT_STM32WBA) + # BLE is enabled. Use implementation over Flash Manager for coexistence wit RF activities + zephyr_library_sources(flash_stm32wba_fm.c) + else() + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32_FLASH_CONTROLLER_ENABLED flash_stm32.c flash_stm32wbax.c) + endif() else() - zephyr_library_sources(flash_stm32.c) - zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) + if(CONFIG_DT_HAS_ST_STM32_FLASH_CONTROLLER_ENABLED) + zephyr_library_sources(flash_stm32.c) + zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F2_FLASH_CONTROLLER_ENABLED flash_stm32f2x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED flash_stm32f4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED flash_stm32f7x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED flash_stm32l4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L5_FLASH_CONTROLLER_ENABLED flash_stm32l5x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WB_FLASH_CONTROLLER_ENABLED flash_stm32wbx.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WBA_FLASH_CONTROLLER_ENABLED flash_stm32wbax.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F2_FLASH_CONTROLLER_ENABLED flash_stm32f2x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED flash_stm32f4x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED flash_stm32f7x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED flash_stm32l4x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L5_FLASH_CONTROLLER_ENABLED flash_stm32l5x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WB_FLASH_CONTROLLER_ENABLED flash_stm32wbx.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) + endif() endif() endif() diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 698190e7780..81b4cdbe40d 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -151,6 +151,7 @@ source "drivers/flash/Kconfig.gd32" source "drivers/flash/Kconfig.xmc4xxx" source "drivers/flash/Kconfig.ifx_cat1" +source "drivers/flash/Kconfig.cadence_nand" source "drivers/flash/Kconfig.numaker" diff --git a/drivers/flash/Kconfig.cadence_nand b/drivers/flash/Kconfig.cadence_nand new file mode 100644 index 00000000000..52b7a1422b1 --- /dev/null +++ b/drivers/flash/Kconfig.cadence_nand @@ -0,0 +1,53 @@ +# Copyright (c) 2023 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# Macro to find node in device tree +DT_CHOSEN_CDNS_NAND_NODE := nand + +config FLASH_CDNS_NAND + bool "Cadence NAND Flash driver" + default y + depends on DT_HAS_CDNS_NAND_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + help + Enable Cadence NAND support. + +if FLASH_CDNS_NAND + +config CDNS_NAND_INTERRUPT_SUPPORT + bool "Cadence Nand Interrupt Support" + def_bool $(dt_node_has_prop,$(DT_CHOSEN_CDNS_NAND_NODE),interrupts) + help + Enable Cadence Nand Interrupt Support. + +choice + prompt "Set the NAND Operating mode" + default CDNS_NAND_CDMA_MODE + help + Specify the Operating mode used by the driver. + +config CDNS_NAND_CDMA_MODE + bool "Cadence Nand CDMA Operating Mode" + +config CDNS_NAND_PIO_MODE + bool "Cadence Nand PIO Operating Mode" + +config CDNS_NAND_GENERIC_MODE + bool "Cadence Nand Generic Operating Mode" + +endchoice + +config FLASH_CDNS_CDMA_PAGE_COUNT + int "Set the page count for a single transfer in the CDMA Mode" + default 10 + help + Configure the page count for a single transfer in the CDMA Mode + +config FLASH_CDNS_CDMA_BLOCK_COUNT + int "Set the block count for a single transfer in the CDMA Mode" + default 10 + help + Configure the block count for a single transfer in the CDMA Mode + +endif # FLASH_CDNS_NAND diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index 89d411f064b..ec7f5be22b2 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -40,6 +40,7 @@ config FLASH_MCUX_FLEXSPI_NOR depends on DT_HAS_NXP_IMX_FLEXSPI_NOR_ENABLED select FLASH_HAS_PAGE_LAYOUT select FLASH_HAS_DRIVER_ENABLED + select FLASH_JESD216 select MEMC select MEMC_MCUX_FLEXSPI diff --git a/drivers/flash/Kconfig.nor b/drivers/flash/Kconfig.nor index 507e681c120..8263f7f6785 100644 --- a/drivers/flash/Kconfig.nor +++ b/drivers/flash/Kconfig.nor @@ -55,6 +55,16 @@ config SPI_NOR_CS_WAIT_DELAY help This is the wait delay (in us) to allow for CS switching to take effect +config SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY + bool "Sleep while waiting for flash operations to complete" + default y + help + Flash operations can take anywhere from 1ms to 240 seconds to + complete. Enabling this option adds a delay between polls on the + status register for slow operations. Disabling this option can + result in significant flash savings if this driver is the only user + of "k_sleep". This can be the case when building as a bootloader. + config SPI_NOR_FLASH_LAYOUT_PAGE_SIZE int "Page size to use for FLASH_LAYOUT feature" default 65536 diff --git a/drivers/flash/Kconfig.nordic_qspi_nor b/drivers/flash/Kconfig.nordic_qspi_nor index aac9830835a..ff652f60822 100644 --- a/drivers/flash/Kconfig.nordic_qspi_nor +++ b/drivers/flash/Kconfig.nordic_qspi_nor @@ -50,4 +50,13 @@ config NORDIC_QSPI_NOR_XIP QSPI NOR flash chip is executed until the driver has been setup. This will also disable power management for the QSPI NOR flash chip. +config NORDIC_QSPI_NOR_TIMEOUT_MS + int "Timeout for QSPI operations (ms)" + default 500 + help + The QSPI peripheral operation timeout in milliseconds. + Primarily intended for long running operations such as + a flash sector erase. The 500 ms default allows for + most typical NOR flash chips to erase a sector. + endif # NORDIC_QSPI_NOR diff --git a/drivers/flash/Kconfig.sam b/drivers/flash/Kconfig.sam index bb014d65279..64df895bd6a 100644 --- a/drivers/flash/Kconfig.sam +++ b/drivers/flash/Kconfig.sam @@ -7,6 +7,7 @@ config SOC_FLASH_SAM bool "Atmel SAM flash driver" default y depends on DT_HAS_ATMEL_SAM_FLASH_CONTROLLER_ENABLED + select FLASH_PAGE_LAYOUT select FLASH_HAS_PAGE_LAYOUT select FLASH_HAS_DRIVER_ENABLED select MPU_ALLOW_FLASH_WRITE if ARM_MPU diff --git a/drivers/flash/Kconfig.stm32 b/drivers/flash/Kconfig.stm32 index 5344d818322..a452ab8b98d 100644 --- a/drivers/flash/Kconfig.stm32 +++ b/drivers/flash/Kconfig.stm32 @@ -14,6 +14,8 @@ config SOC_FLASH_STM32 select FLASH_PAGE_LAYOUT select FLASH_HAS_PAGE_LAYOUT select MPU_ALLOW_FLASH_WRITE if ARM_MPU + select USE_STM32_HAL_FLASH if BT_STM32WBA + select USE_STM32_HAL_FLASH_EX if BT_STM32WBA help Enable flash driver for STM32 series diff --git a/drivers/flash/flash_cadence_nand.c b/drivers/flash/flash_cadence_nand.c new file mode 100644 index 00000000000..b527a5082ce --- /dev/null +++ b/drivers/flash/flash_cadence_nand.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT cdns_nand + +#include "socfpga_system_manager.h" + +#include +#include +#include + +/* Check if reset property is defined */ +#define CDNS_NAND_RESET_SUPPORT DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + +#if CDNS_NAND_RESET_SUPPORT +#include +#endif + +#include "flash_cadence_nand_ll.h" + +#define DEV_CFG(_dev) ((const struct flash_cadence_nand_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct flash_cadence_nand_data *const)(_dev)->data) + +#define FLASH_WRITE_SIZE DT_PROP(DT_INST(0, DT_DRV_COMPAT), block_size) + +#ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK +#define DFI_CFG_OFFSET 0xFC +/* To check the DFI register setting for NAND in the System Manager */ +#define DFI_SEL_CHK (SOCFPGA_SYSMGR_REG_BASE + DFI_CFG_OFFSET) +#endif + +LOG_MODULE_REGISTER(flash_cdns_nand, CONFIG_FLASH_LOG_LEVEL); + +struct flash_cadence_nand_data { + DEVICE_MMIO_NAMED_RAM(nand_reg); + DEVICE_MMIO_NAMED_RAM(sdma); + /* device info structure */ + struct cadence_nand_params params; + /* Mutex to prevent multiple processes from accessing the same driver api */ + struct k_mutex nand_mutex; +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + /* Semaphore to send a signal from an interrupt handler to a thread */ + struct k_sem interrupt_sem; +#endif +}; + +struct flash_cadence_nand_config { + DEVICE_MMIO_NAMED_ROM(nand_reg); + DEVICE_MMIO_NAMED_ROM(sdma); +#if CDNS_NAND_RESET_SUPPORT + /* Reset controller device configuration for NAND*/ + const struct reset_dt_spec reset; + /* Reset controller device configuration for Combo Phy*/ + const struct reset_dt_spec combo_phy_reset; +#endif +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + void (*irq_config)(void); +#endif +}; + +static const struct flash_parameters flash_cdns_parameters = {.write_block_size = FLASH_WRITE_SIZE, + .erase_value = 0xFF}; + +#if CONFIG_FLASH_PAGE_LAYOUT + +struct flash_pages_layout flash_cdns_pages_layout; + +void flash_cdns_page_layout(const struct device *nand_dev, const struct flash_pages_layout **layout, + size_t *layout_size) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + + flash_cdns_pages_layout.pages_count = nand_param->page_count; + flash_cdns_pages_layout.pages_size = nand_param->page_size; + *layout = &flash_cdns_pages_layout; + *layout_size = 1; +} + +#endif + +static int flash_cdns_nand_erase(const struct device *nand_dev, off_t offset, size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_erase(nand_param, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static int flash_cdns_nand_write(const struct device *nand_dev, off_t offset, const void *data, + size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + if (data == NULL) { + LOG_ERR("Invalid input parameter for NAND Flash Write!"); + return -EINVAL; + } + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_write(nand_param, data, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static int flash_cdns_nand_read(const struct device *nand_dev, off_t offset, void *data, size_t len) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + + if (data == NULL) { + LOG_ERR("Invalid input parameter for NAND Flash Read!"); + return -EINVAL; + } + + k_mutex_lock(&nand_data->nand_mutex, K_FOREVER); + + ret = cdns_nand_read(nand_param, data, offset, len); + + k_mutex_unlock(&nand_data->nand_mutex); + + return ret; +} + +static const struct flash_parameters *flash_cdns_get_parameters(const struct device *nand_dev) +{ + ARG_UNUSED(nand_dev); + + return &flash_cdns_parameters; +} +static const struct flash_driver_api flash_cdns_nand_api = { + .erase = flash_cdns_nand_erase, + .write = flash_cdns_nand_write, + .read = flash_cdns_nand_read, + .get_parameters = flash_cdns_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_cdns_page_layout, +#endif +}; + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + +static void cdns_nand_irq_handler(const struct device *nand_dev) +{ + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + + cdns_nand_irq_handler_ll(nand_param); + k_sem_give(&nand_param->interrupt_sem_t); +} + +#endif + +static int flash_cdns_nand_init(const struct device *nand_dev) +{ + DEVICE_MMIO_NAMED_MAP(nand_dev, nand_reg, K_MEM_CACHE_NONE); + DEVICE_MMIO_NAMED_MAP(nand_dev, sdma, K_MEM_CACHE_NONE); + const struct flash_cadence_nand_config *nand_config = DEV_CFG(nand_dev); + struct flash_cadence_nand_data *const nand_data = DEV_DATA(nand_dev); + struct cadence_nand_params *nand_param = &nand_data->params; + int ret; + +#ifdef CONFIG_BOARD_INTEL_SOCFPGA_AGILEX5_SOCDK + uint32_t status; + + status = sys_read32(DFI_SEL_CHK); + if ((status & 1) != 0) { + LOG_ERR("DFI not configured for NAND Flash controller!!!"); + return -ENODEV; + } +#endif + +#if CDNS_NAND_RESET_SUPPORT + /* Reset Combo phy and NAND only if reset controller driver is supported */ + if ((nand_config->combo_phy_reset.dev != NULL) && (nand_config->reset.dev != NULL)) { + if (!device_is_ready(nand_config->reset.dev)) { + LOG_ERR("Reset controller device not ready"); + return -ENODEV; + } + + ret = reset_line_toggle(nand_config->combo_phy_reset.dev, + nand_config->combo_phy_reset.id); + if (ret != 0) { + LOG_ERR("Combo phy reset failed"); + return ret; + } + + ret = reset_line_toggle(nand_config->reset.dev, nand_config->reset.id); + if (ret != 0) { + LOG_ERR("NAND reset failed"); + return ret; + } + } +#endif + nand_param->nand_base = DEVICE_MMIO_NAMED_GET(nand_dev, nand_reg); + nand_param->sdma_base = DEVICE_MMIO_NAMED_GET(nand_dev, sdma); + ret = k_mutex_init(&nand_data->nand_mutex); + if (ret != 0) { + LOG_ERR("Mutex creation Failed"); + return ret; + } + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + + if (nand_config->irq_config == NULL) { + LOG_ERR("Interrupt function not initialized!!"); + return -EINVAL; + } + nand_config->irq_config(); + ret = k_sem_init(&nand_param->interrupt_sem_t, 0, 1); + if (ret != 0) { + LOG_ERR("Semaphore creation Failed"); + return ret; + } +#endif + nand_param->page_count = + (nand_param->npages_per_block * nand_param->nblocks_per_lun * nand_param->nluns); + /* NAND Memory Controller init */ + ret = cdns_nand_init(nand_param); + if (ret != 0) { + LOG_ERR("NAND initialization Failed"); + return ret; + } + return 0; +} + +#define CDNS_NAND_RESET_SPEC_INIT(inst) \ + .reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ + .combo_phy_reset = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1), + +#define CREATE_FLASH_CADENCE_NAND_DEVICE(inst) \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (static void cdns_nand_irq_config_##inst(void);)) \ + struct flash_cadence_nand_data flash_cadence_nand_data_##inst = { \ + .params = { \ + .datarate_mode = DT_INST_PROP(inst, data_rate_mode), \ + }}; \ + const struct flash_cadence_nand_config flash_cadence_nand_config_##inst = { \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(nand_reg, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME(sdma, DT_DRV_INST(inst)), \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), (CDNS_NAND_RESET_SPEC_INIT(inst))) \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (.irq_config = cdns_nand_irq_config_##inst,))}; \ + DEVICE_DT_INST_DEFINE(inst, flash_cdns_nand_init, NULL, &flash_cadence_nand_data_##inst, \ + &flash_cadence_nand_config_##inst, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_cdns_nand_api); \ + IF_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT, \ + (static void cdns_nand_irq_config_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + cdns_nand_irq_handler, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + })) + +DT_INST_FOREACH_STATUS_OKAY(CREATE_FLASH_CADENCE_NAND_DEVICE) diff --git a/drivers/flash/flash_cadence_nand_ll.c b/drivers/flash/flash_cadence_nand_ll.c new file mode 100644 index 00000000000..a33eb424709 --- /dev/null +++ b/drivers/flash/flash_cadence_nand_ll.c @@ -0,0 +1,1472 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "flash_cadence_nand_ll.h" + +LOG_MODULE_REGISTER(flash_cdns_nand_ll, CONFIG_FLASH_LOG_LEVEL); + +/** + * Wait for the Cadence NAND controller to become idle. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static inline int32_t cdns_nand_wait_idle(uintptr_t base_address) +{ + /* Wait status command response ready */ + if (!WAIT_FOR(CNF_GET_CTRL_BUSY(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) == 0U, + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for wait idle response"); + return -ETIMEDOUT; + } + return 0; +} + +/** + * Set the row address for a NAND flash memory device using the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param local_row_address The row address. + * @param page_set The page set number. + */ +static void row_address_set(struct cadence_nand_params *params, uint32_t *local_row_address, + uint32_t page_set) +{ + uint32_t block_number = 0; + + block_number = ((page_set) / (params->npages_per_block)); + *local_row_address = 0; + *local_row_address |= ROW_VAL_SET((params->page_size_bit) - 1, 0, + ((page_set) % (params->npages_per_block))); + *local_row_address |= + ROW_VAL_SET((params->block_size_bit) - 1, (params->page_size_bit), block_number); + *local_row_address |= ROW_VAL_SET((params->lun_size_bit) - 1, (params->block_size_bit), + (block_number / params->nblocks_per_lun)); +} + +/** + * Retrieve information about the NAND flash device using the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or -ENXIO error value on failure. + */ +static int cdns_nand_device_info(struct cadence_nand_params *params) +{ + struct nf_ctrl_version *nf_ver; + uintptr_t base_address; + uint32_t reg_value = 0; + uint8_t type; + + base_address = params->nand_base; + + /* Read flash device version information */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, VERSION)); + nf_ver = (struct nf_ctrl_version *)®_value; + + LOG_INF("NAND Flash Version Information"); + LOG_INF("HPNFC Magic Number 0x%x", nf_ver->hpnfc_magic_number); + LOG_INF("Fixed number 0x%x", nf_ver->ctrl_fix); + LOG_INF("Controller Revision Number 0x%x", nf_ver->ctrl_rev); + + /* Interface Type */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, DEV_PARAMS0)); + type = CNF_GET_DEV_TYPE(reg_value); + if (type == CNF_DT_UNKNOWN) { + LOG_ERR("%s: device type unknown", __func__); + return -ENXIO; + } + + params->nluns = CNF_GET_NLUNS(reg_value); + LOG_INF("Number of LUMs %hhx", params->nluns); + + /* Pages per block */ + reg_value = sys_read32(CNF_CTRLCFG(base_address, DEV_LAYOUT)); + params->npages_per_block = GET_PAGES_PER_BLOCK(reg_value); + + /* Page size and spare size */ + reg_value = sys_read32(CNF_CTRLPARAM(base_address, DEV_AREA)); + params->page_size = GET_PAGE_SIZE(reg_value); + params->spare_size = GET_SPARE_SIZE(reg_value); + + /* Device blocks per LUN */ + params->nblocks_per_lun = sys_read32(CNF_CTRLPARAM(base_address, DEV_BLOCKS_PLUN)); + + /* Calculate block size and total device size */ + params->block_size = (params->npages_per_block * params->page_size); + params->device_size = ((long long)params->block_size * + (long long)(params->nblocks_per_lun * params->nluns)); + LOG_INF("block size %x total device size %llx", params->block_size, params->device_size); + + /* Calculate bit size of page, block and lun*/ + params->page_size_bit = find_msb_set((params->npages_per_block) - 1); + params->block_size_bit = find_msb_set((params->nblocks_per_lun) - 1); + params->lun_size_bit = find_msb_set((params->nluns) - 1); + return 0; +} + +/** + * Retrieve the status of a specific thread in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param thread The thread identifier. + * @retval The status of the thread. + */ +static uint32_t cdns_nand_get_thrd_status(uintptr_t base_address, uint8_t thread) +{ + uint32_t status; + + sys_write32(THREAD_VAL(thread), (base_address + CMD_STATUS_PTR_ADDR)); + status = sys_read32((base_address + CMD_STAT_CMD_STATUS)); + return status; +} + +/** + * Wait for a specific thread in the Cadence controller to complete. + * + * @param base_address The base address of the Cadence controller. + * @param thread The thread identifier to wait for. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_wait_for_thread(uintptr_t base_address, uint8_t thread) +{ + + if (!WAIT_FOR((sys_read32((base_address) + THR_STATUS) & BIT(thread)) == 0U, + THREAD_IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for thread response"); + return -ETIMEDOUT; + } + + return 0; +} + +/** + * Set features in the Cadence NAND controller using PIO operations. + * + * @param base_address The base address of the Cadence NAND controller. + * @param feat_addr The address of the feature to be set. + * @param feat_val The value of the feature to be set. + * @param thread The thread identifier for the PIO operation. + * @param vol_id The volume identifier for the feature set operation. + * @param use_intr Flag indicating whether to use interrupts during the operation. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_pio_set_features(uintptr_t base_address, uint8_t feat_addr, uint8_t feat_val, + uint8_t thread, uint8_t vol_id) +{ + uint32_t status = 0; + int ret = 0; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + + sys_write32(SET_FEAT_ADDR(feat_addr), (base_address + CDNS_CMD_REG1)); + sys_write32(feat_val, (base_address + CDNS_CMD_REG2)); + status = CMD_0_THREAD_POS_SET(thread); + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(PIO_SET_FEA_MODE); + status |= CMD_0_VOL_ID_SET(vol_id); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Check whether a transfer complete for PIO operation in the Cadence controller has finished. + * + * @param base_address The base address of the Cadence controller. + * @param thread The thread identifier for the PIO operation. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_pio_transfer_complete(uintptr_t base_address, uint8_t thread) +{ + uint32_t status; + + status = WAIT_FOR(((cdns_nand_get_thrd_status(base_address, thread)) != 0), IDLE_TIME_OUT, + k_msleep(1)); + + if (status == 0) { + LOG_ERR("Timed out waiting for thread status response"); + return -ETIMEDOUT; + } + + if ((status & (BIT(F_CSTAT_COMP)))) { + if ((status & (BIT(F_CSTAT_FAIL)))) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } + } else { + LOG_ERR("Cadence status complete failed %s", __func__); + return -EIO; + } + return 0; +} + +/** + * Set the operational mode for the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param opr_mode The operational mode SDR / NVDDR to set. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_set_opr_mode(uintptr_t base_address, uint8_t opr_mode) +{ + uint8_t device_type; + uint32_t timing_mode = 0; + uint32_t status; + int ret; + + if (opr_mode == CNF_OPR_WORK_MODE_SDR) { + + status = ONFI_TIMING_MODE_SDR( + sys_read32(CNF_CTRLPARAM(base_address, ONFI_TIMING_0))); + timing_mode = find_lsb_set(status) - 1; + + /* PHY Register Timing setting*/ + sys_write32(PHY_CTRL_REG_SDR, (base_address + PHY_CTRL_REG_OFFSET)); + sys_write32(PHY_TSEL_REG_SDR, (base_address + PHY_TSEL_REG_OFFSET)); + sys_write32(PHY_DQ_TIMING_REG_SDR, (base_address + PHY_DQ_TIMING_REG_OFFSET)); + sys_write32(PHY_DQS_TIMING_REG_SDR, (base_address + PHY_DQS_TIMING_REG_OFFSET)); + sys_write32(PHY_GATE_LPBK_CTRL_REG_SDR, (base_address + PHY_GATE_LPBK_OFFSET)); + sys_write32(PHY_DLL_MASTER_CTRL_REG_SDR, (base_address + PHY_DLL_MASTER_OFFSET)); + + /* Async mode timing settings */ + sys_write32((CNF_ASYNC_TIMINGS_TRH) | (CNF_ASYNC_TIMINGS_TRP) | + (CNF_ASYNC_TIMINGS_TWH) | (CNF_ASYNC_TIMINGS_TWP), + CNF_MINICTRL(base_address, ASYNC_TOGGLE_TIMINGS)); + + /* Set operation work mode in common settings */ + sys_clear_bits(CNF_MINICTRL(base_address, CMN_SETTINGS), + CNF_OPR_WORK_MODE_SDR_MASK); + + } else { + /* NVDDR MODE */ + status = ONFI_TIMING_MODE_NVDDR( + sys_read32(CNF_CTRLPARAM(base_address, ONFI_TIMING_0))); + timing_mode = find_lsb_set(status) - 1; + /* PHY Register Timing setting*/ + sys_write32(PHY_CTRL_REG_DDR, (base_address + PHY_CTRL_REG_OFFSET)); + sys_write32(PHY_TSEL_REG_DDR, (base_address + PHY_TSEL_REG_OFFSET)); + sys_write32(PHY_DQ_TIMING_REG_DDR, (base_address + PHY_DQ_TIMING_REG_OFFSET)); + sys_write32(PHY_DQS_TIMING_REG_DDR, (base_address + PHY_DQS_TIMING_REG_OFFSET)); + sys_write32(PHY_GATE_LPBK_CTRL_REG_DDR, (base_address + PHY_GATE_LPBK_OFFSET)); + sys_write32(PHY_DLL_MASTER_CTRL_REG_DDR, (base_address + PHY_DLL_MASTER_OFFSET)); + /* Set operation work mode in common settings */ + sys_set_bits(CNF_MINICTRL(base_address, CMN_SETTINGS), + CNF_OPR_WORK_MODE_NVDDR_MASK); + } + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* Check device type */ + device_type = CNF_GET_DEV_TYPE(sys_read32(CNF_CTRLPARAM(base_address, DEV_PARAMS0))); + + if (device_type != ONFI_INTERFACE) { + LOG_ERR("Driver does not support this interface"); + return -ENOTSUP; + } + /* Reset DLL PHY */ + sys_clear_bit(CNF_MINICTRL(base_address, DLL_PHY_CTRL), CNF_DLL_PHY_RST_N); + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + ret = cdns_nand_pio_set_features(base_address, SET_FEAT_TIMING_MODE_ADDRESS, timing_mode, + NF_TDEF_TRD_NUM, VOL_ID); + if (ret != 0) { + return ret; + } + + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + LOG_ERR("cdns pio check failed"); + return ret; + } + + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* set dll_rst_n in dll_phy_ctrl to 1 */ + sys_set_bit(CNF_MINICTRL(base_address, DLL_PHY_CTRL), CNF_DLL_PHY_RST_N); + + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + return 0; +} + +/** + * Configure the transfer settings of the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_transfer_config(uintptr_t base_address) +{ + int ret = 0; + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* Configure data transfer parameters */ + sys_write32(ENABLE, CNF_CTRLCFG(base_address, TRANS_CFG0)); + + /* Disable cache and multiplane. */ + sys_write32(DISABLE, CNF_CTRLCFG(base_address, MULTIPLANE_CFG)); + sys_write32(DISABLE, CNF_CTRLCFG(base_address, CACHE_CFG)); + + /* Clear all interrupts. */ + sys_write32(CLEAR_ALL_INTERRUPT, (base_address + INTR_STATUS)); + return 0; +} + +/** + * Initialize the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_init(struct cadence_nand_params *params) +{ + uint32_t reg_value_read = 0; + uintptr_t base_address = params->nand_base; + uint8_t datarate_mode = params->datarate_mode; + int ret; + + if (!WAIT_FOR(CNF_GET_INIT_COMP(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) != 0U, + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for NAND Controller Init complete status response"); + return -ETIMEDOUT; + } + + if (CNF_GET_INIT_FAIL(sys_read32(CNF_CMDREG(base_address, CTRL_STATUS))) != 0) { + LOG_ERR("NAND Controller Init complete Failed!!!"); + return -ENODEV; + } + + ret = cdns_nand_device_info(params); + if (ret != 0) { + return ret; + } + + /* Hardware Support Features */ + reg_value_read = sys_read32(CNF_CTRLPARAM(base_address, FEATURE)); + /* Enable data integrity parity check if the data integrity parity mechanism is */ + /* supported by the device */ + if (CNF_HW_DI_PR_SUPPORT(reg_value_read) != 0) { + sys_set_bit(CNF_DI(base_address, CONTROL), CNF_DI_PAR_EN); + } + + /* Enable data integrity CRC check if the data integrity CRC mechanism is */ + /* supported by the device */ + if (CNF_HW_DI_CRC_SUPPORT(reg_value_read) != 0) { + sys_set_bit(CNF_DI(base_address, CONTROL), CNF_DI_CRC_EN); + } + /* Status polling mode, device control and status register */ + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + sys_write32(DEV_STAT_DEF_VALUE, CNF_CTRLCFG(base_address, DEV_STAT)); + + /* Set operation work mode */ + ret = cdns_nand_set_opr_mode(base_address, datarate_mode); + if (ret != 0) { + return ret; + } + + /* Set data transfer configuration parameters */ + ret = cdns_nand_transfer_config(base_address); + if (ret != 0) { + return ret; + } + + /* Wait for controller to be in idle state */ + ret = cdns_nand_wait_idle(base_address); + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + + /* DMA Setting */ + sys_write32((F_BURST_SEL_SET(NF_TDEF_BURST_SEL)) | (BIT(F_OTE)), + (base_address + NF_DMA_SETTING)); + + /* Pre fetch */ + sys_write32(((NF_FIFO_TRIGG_LVL_SET(PRE_FETCH_VALUE)) | + (NF_DMA_PACKAGE_SIZE_SET(PRE_FETCH_VALUE))), + (base_address + NF_PRE_FETCH)); + /* Total bits in row addressing*/ + params->total_bit_row = find_msb_set(((params->npages_per_block) - 1)) + + find_msb_set((params->nblocks_per_lun) - 1); + + if (ret != 0) { + LOG_ERR("Failed to establish device access width!"); + return -EINVAL; + } + /* Enable Global Interrupt for NAND*/ +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + sys_set_bit((base_address + INTERRUPT_STATUS_REG), GINTR_ENABLE); +#endif + return 0; +} + +#if CONFIG_CDNS_NAND_CDMA_MODE +/** + * + * This function performs Command descriptor structure prepareation. + * + * @param nf_mem determine which NF memory bank will be selected + * @param flash_ptr start ROW address in NF memory + * @param mem_ptr system memory pointer + * @param ctype Command type (read/write/erase) + * @param cmd_cnt counter for commands + * @param dma_sel select DMA engine (0 - slave DMA, 1 - master DMA) + * @param vol_id specify target volume ID + * + */ +void cdns_nand_cdma_prepare(char nf_mem, uint32_t flash_ptr, char *mem_ptr, uint16_t ctype, + int32_t cmd_cnt, uint8_t dma_sel, uint8_t vol_id, + struct cdns_cdma_command_descriptor *desc) +{ + struct cdns_cdma_command_descriptor *cdma_desc; + + cdma_desc = desc; + /* set fields for one descriptor */ + cdma_desc->flash_pointer = flash_ptr; + cdma_desc->bank_number = nf_mem; + cdma_desc->command_flags |= CDMA_CF_DMA_MASTER_SET(dma_sel) | F_CFLAGS_VOL_ID_SET(vol_id); + cdma_desc->memory_pointer = (uintptr_t)mem_ptr; + cdma_desc->status = 0; + cdma_desc->sync_flag_pointer = 0; + cdma_desc->sync_arguments = 0; + cdma_desc->ctrl_data_ptr = 0x40; + cdma_desc->command_type = ctype; + if (cmd_cnt > 1) { + cdma_desc->next_pointer = (uintptr_t)(desc + 1); + cdma_desc->command_flags |= CFLAGS_MPTRPC_SET | CFLAGS_MPTRPC_SET; + cdma_desc->command_flags |= CFLAGS_CONT_SET; + } else { + cdma_desc->next_pointer = 0; +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + cdma_desc->command_flags |= CDMA_CF_INT_SET; +#endif + } +} + +/** + * Check a command descriptor transfer complete status in the Cadence NAND controller. + * + * @param desc_ptr The pointer to the command descriptor structure. + * @param params The Cadence NAND parameters structure. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_transfer_complete(struct cdns_cdma_command_descriptor *desc_ptr, + struct cadence_nand_params *params) +{ +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + uint32_t status = 0; + + NAND_INT_SEM_TAKE(params); + sys_write32(NF_TDEF_TRD_NUM, (params->nand_base + CMD_STATUS_PTR_ADDR)); + status = sys_read32((params->nand_base + CMD_STAT_CMD_STATUS)); + if ((status & (BIT(F_CSTAT_COMP)))) { + if ((status & (BIT(F_CSTAT_FAIL)))) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } + } else { + LOG_ERR("Cadence status complete failed %s", __func__); + return -EIO; + } +#else + ARG_UNUSED(params); + + if (!WAIT_FOR(((desc_ptr->status & (BIT(F_CSTAT_COMP))) != 0), IDLE_TIME_OUT, + k_msleep(1))) { + LOG_ERR("Timed out waiting for thread status response"); + return -ETIMEDOUT; + } + if ((desc_ptr->status & (BIT(F_CSTAT_FAIL))) != 0) { + LOG_ERR("Cadence status operation failed %s", __func__); + return -EIO; + } +#endif + return 0; +} + +/** + * Send a command descriptor to the Cadence NAND controller for execution. + * + * @param base_address The base address of the Cadence NAND controller. + * @param desc_ptr The pointer to the command descriptor. + * @param thread The thread number for the execution. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_send(uintptr_t base_address, char *desc_ptr, uint8_t thread) +{ + uint64_t desc_address; + uint32_t status; + int ret; + + desc_address = (uint64_t)desc_ptr; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + /* desc_ptr address passing */ + sys_write32(desc_address & U32_MASK_VAL, (base_address + CDNS_CMD_REG2)); + sys_write32((desc_address >> 32) & U32_MASK_VAL, (base_address + CDNS_CMD_REG3)); + /* Thread selection */ + status = CMD_0_THREAD_POS_SET(thread); + /* CDMA Mode selection */ + status |= CMD_0_C_MODE_SET(CT_CDMA_MODE); + /* CMD 0 Reg write*/ + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +static int cdns_cdma_desc_transfer_finish(struct cadence_nand_params *params, uint32_t page_count, + uint32_t max_page_desc, uint32_t ctype, + uint32_t cond_start, char *buffer) +{ + uint32_t page_count_pass = 0; + uint32_t row_address = 0; + uint32_t base_address; + uint32_t page_buffer_size; + struct cdns_cdma_command_descriptor *cdma_desc; + int ret; + + page_buffer_size = (page_count > max_page_desc) ? max_page_desc : page_count; + + cdma_desc = k_malloc(sizeof(struct cdns_cdma_command_descriptor) * page_buffer_size); + + if (cdma_desc == NULL) { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + + base_address = params->nand_base; + + while (page_count > 0) { + row_address_set(params, &row_address, cond_start); + + if (page_count > max_page_desc) { + page_count_pass = max_page_desc; + page_count = page_count - max_page_desc; + cond_start = cond_start + page_count_pass; + } else { + page_count_pass = page_count; + page_count = page_count - page_count_pass; + } + for (int index = 0; index < page_count_pass; index++) { + cdns_nand_cdma_prepare(NF_TDEF_DEV_NUM, row_address, buffer, + (ctype + index), (page_count_pass - index), + DMA_MS_SEL, VOL_ID, (cdma_desc + index)); + } + ret = cdns_nand_send(base_address, (char *)cdma_desc, NF_TDEF_TRD_NUM); + + if (ret != 0) { + k_free(cdma_desc); + return ret; + } + + if (ctype != CNF_CMD_ERASE) { + buffer = buffer + (max_page_desc * params->page_size); + } + + ret = cdns_transfer_complete(cdma_desc, params); + + if (ret != 0) { + k_free(cdma_desc); + return ret; + } + } + + k_free(cdma_desc); + + return 0; +} +/** + * Perform a CDMA write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the write operation. + * @param buffer The buffer containing the data to be written. + * @param page_count The number of pages to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, page_count, CONFIG_FLASH_CDNS_CDMA_PAGE_COUNT, + CNF_CMD_WR, start_page_number, buffer); + + return ret; +} + +/** + * Perform a CDMA read operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read operation. + * @param buffer The buffer to store the read data. + * @param page_count The number of pages to be read. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_read(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, page_count, CONFIG_FLASH_CDNS_CDMA_PAGE_COUNT, + CNF_CMD_RD, start_page_number, buffer); + + return ret; +} + +/** + * Perform a CDMA erase operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_block_number The starting block number for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_cdma_erase(struct cadence_nand_params *params, uint32_t start_block_number, + uint32_t block_count) +{ + int ret; + + ret = cdns_cdma_desc_transfer_finish(params, block_count, + CONFIG_FLASH_CDNS_CDMA_BLOCK_COUNT, CNF_CMD_ERASE, + start_block_number, NULL); + + return ret; +} +#endif + +#if CONFIG_CDNS_NAND_PIO_MODE + +/** + * Perform an erase operation on the Cadence NAND controller using PIO. + * + * @param params The Cadence NAND parameters structure. + * @param thread The thread identifier for the PIO operation. + * @param bank The bank identifier for the erase operation. + * @param start_block The starting block number for the erase operation. + * @param ctype The command type for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_erase(struct cadence_nand_params *params, uint8_t thread, uint8_t bank, + uint32_t start_block, uint16_t ctype, uint32_t block_count) +{ + uint32_t status; + uintptr_t base_address; + uint32_t row_address = 0; + uint32_t index = 0; + int ret; + + base_address = params->nand_base; + for (index = 0; index < block_count; index++) { + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + row_address_set(params, &row_address, (start_block * params->npages_per_block)); + sys_write32(row_address, (base_address + CDNS_CMD_REG1)); + start_block++; + sys_write32((NF_CMD4_BANK_SET(bank)), (base_address + CDNS_CMD_REG4)); + status = CMD_0_THREAD_POS_SET(thread); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= BIT(PIO_CF_INT); +#endif + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(ctype); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, thread); + if (ret != 0) { + return ret; + } + } + + return 0; +} + +/** + * Prepare for a PIO operation in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @param thread The thread ID associated with the operation. + * @param bank The bank ID for the operation. + * @param row_address The row address for the operation. + * @param buf The buffer containing the data for the operation. + * @param ctype The command type for the operation. + * @param dma_sel The DMA selection flag for the operation. + * @param vol_id The volume ID for the operation. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_pio_prepare(uintptr_t base_address, uint8_t thread, uint8_t bank, + uint32_t row_address, char *buf, uint16_t ctype, uint8_t dma_sel, + uint8_t vol_id) +{ + uint64_t buf_addr = (uintptr_t)buf; + uint32_t status; + int ret; + + ret = cdns_wait_for_thread(base_address, thread); + + if (ret != 0) { + return ret; + } + + sys_write32(row_address, (base_address + CDNS_CMD_REG1)); + sys_write32(NF_CMD4_BANK_SET(bank), (base_address + CDNS_CMD_REG4)); + sys_write32(buf_addr & U32_MASK_VAL, (base_address + CDNS_CMD_REG2)); + sys_write32((buf_addr >> 32) & U32_MASK_VAL, (base_address + CDNS_CMD_REG3)); + status = CMD_0_THREAD_POS_SET(thread); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= PIO_CF_INT_SET; +#endif + status |= PIO_CF_DMA_MASTER_SET(dma_sel); + status |= CMD_0_C_MODE_SET(CT_PIO_MODE); + status |= PIO_CMD0_CT_SET(ctype); + status |= CMD_0_VOL_ID_SET(vol_id); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Perform a PIO write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param row_address The row address for the write operation. + * @param buffer The buffer containing the data to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_write(struct cadence_nand_params *params, uint32_t row_address, + char *buffer) +{ + uintptr_t base_address; + int ret; + + base_address = params->nand_base; + + ret = cdns_nand_pio_prepare(base_address, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, row_address, + buffer, CNF_CMD_WR, DMA_MS_SEL, VOL_ID); + + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + return ret; + } + + return 0; +} + +/** + * Perform a PIO read operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param row_address The row address for the read operation. + * @param buffer The buffer to store the read data. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_read(struct cadence_nand_params *params, uint32_t row_address, + char *buffer) +{ + uintptr_t base_address; + int ret; + + base_address = params->nand_base; + + ret = cdns_nand_pio_prepare(base_address, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, row_address, + buffer, CNF_CMD_RD, DMA_MS_SEL, VOL_ID); + + if (ret != 0) { + return ret; + } + + NAND_INT_SEM_TAKE(params); + ret = cdns_pio_transfer_complete(base_address, NF_TDEF_TRD_NUM); + if (ret != 0) { + return ret; + } + + return 0; +} + +/** + * Perform a combined PIO read and write operation for the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read/write operation. + * @param buffer The buffer containing the data to be written or to store the read data. + * @param page_count The number of pages to be read or written. + * @param mode The mode of operation (read, write). + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_pio_read_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count, uint8_t mode) +{ + uint32_t index; + uint32_t pio_row_address = 0; + int ret = 0; + + for (index = 0; index < page_count; index++) { + row_address_set(params, &pio_row_address, start_page_number++); + if (mode == CDNS_READ) { + ret = cdns_nand_pio_read(params, pio_row_address, + buffer + (index * (params->page_size))); + } else { + ret = cdns_nand_pio_write(params, pio_row_address, + buffer + (index * (params->page_size))); + } + } + return ret; +} +#endif + +#if CONFIG_CDNS_NAND_GENERIC_MODE +/** + * Send a generic command to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param mini_ctrl_cmd The command to be sent. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_generic_send_cmd(struct cadence_nand_params *params, uint64_t mini_ctrl_cmd) +{ + + uint32_t mini_ctrl_cmd_l, mini_ctrl_cmd_h, status; + uintptr_t base_address; + int ret = 0; + + base_address = params->nand_base; + mini_ctrl_cmd_l = mini_ctrl_cmd & U32_MASK_VAL; + mini_ctrl_cmd_h = mini_ctrl_cmd >> 32; + ret = cdns_nand_wait_idle(base_address); + + if (ret != 0) { + LOG_ERR("Wait for controller to be in idle state Failed"); + return ret; + } + sys_write32(mini_ctrl_cmd_l, (base_address + CDNS_CMD_REG2)); + sys_write32(mini_ctrl_cmd_h, (base_address + CDNS_CMD_REG3)); + /* Select generic command. */ + status = CMD_0_THREAD_POS_SET(NF_TDEF_TRD_NUM); +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + status |= GEN_CF_INT_SET(GEN_CF_INT_ENABLE); +#endif + status |= CMD_0_C_MODE_SET(CT_GENERIC_MODE); + sys_write32(status, (base_address + CDNS_CMD_REG0)); + return 0; +} + +/** + * Send a generic command data to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param mode The mode of operation (read, write). + * @param data_length The length of the associated data. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_generic_cmd_data(struct cadence_nand_params *params, uint8_t mode, + uint32_t data_length) +{ + uint64_t mini_ctrl_cmd = 0; + int ret = 0; + + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= GCMCD_DATA_SEQ; + mini_ctrl_cmd |= GEN_SECTOR_COUNT_SET; + mini_ctrl_cmd |= GEN_LAST_SECTOR_SIZE_SET((uint64_t)data_length); + mini_ctrl_cmd |= GEN_DIR_SET((uint64_t)mode); + mini_ctrl_cmd |= GEN_SECTOR_SET((uint64_t)data_length); + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + return ret; +} + +/** + * Wait for the completion of an SDMA operation in the Cadence NAND controller. + * + * @param base_address The base address of the Cadence NAND controller. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_wait_sdma(uintptr_t base_address) +{ + + if (!WAIT_FOR(((sys_read32(base_address + INTR_STATUS) & BIT(SDMA_TRIGG)) != 0), + IDLE_TIME_OUT, k_msleep(1))) { + LOG_ERR("Timed out waiting for sdma response"); + return -ETIMEDOUT; + } + sys_set_bit((base_address + INTR_STATUS), SDMA_TRIGG); + return 0; +} + +/** + * Perform buffer copying to SDMA regs in the Cadence NAND controller. + * + * @param sdma_base_address The base address of the SDMA in the Cadence NAND controller. + * @param buffer The source or destination buffer for the copy operation. + * @param data_length The length of the data to be copied. + */ +static void sdma_buffer_copy_in(uint32_t sdma_base_address, uint8_t *buffer, uint32_t data_length) +{ + uint32_t index; + + for (index = 0; index < data_length; index++) { + sys_write8(*(buffer + index), sdma_base_address + index); + } +} + +/** + * Perform buffer copying from SDMA regs in the Cadence NAND controller. + * + * @param sdma_base_address The base address of the SDMA in the Cadence NAND controller. + * @param buffer The source or destination buffer for the copy operation. + * @param data_length The length of the data to be copied. + */ +static void sdma_buffer_copy_out(uint32_t sdma_base_address, uint8_t *buffer, uint32_t data_length) +{ + uint32_t index; + + for (index = 0; index < data_length; index++) { + *(buffer + index) = sys_read8(sdma_base_address + index); + } +} + +/** + * Perform a generic page read operation in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param read_address The address from which to read the page. + * @param data_buffer The buffer to store the read data. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_generic_page_read(struct cadence_nand_params *params, uint64_t read_address, + void *data_buffer) +{ + uint64_t mini_ctrl_cmd = 0; + uintptr_t base_address = params->nand_base; + int ret; + + mini_ctrl_cmd = PAGE_READ_CMD; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + if ((params->nluns > 1) || (params->total_bit_row > 16)) { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE); + } else { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE - 1); + } + mini_ctrl_cmd |= read_address << 32; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_generic_cmd_data(params, CDNS_READ, params->page_size); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_wait_sdma(base_address); + if (ret != 0) { + return ret; + } + sdma_buffer_copy_out(params->sdma_base, data_buffer, params->page_size); + return 0; +} + +/** + * Perform a generic page write operation in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param write_address The address to which the page will be written. + * @param data_buffer The buffer containing the data to be written. + * @retval 0 on success or negative error value on failure. + */ +static int cdns_generic_page_write(struct cadence_nand_params *params, uint64_t write_address, + void *data_buffer) +{ + uint64_t mini_ctrl_cmd = 0; + int ret; + + uintptr_t base_address = params->nand_base; + + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= GEN_ADDR_WRITE_DATA((uint32_t)write_address); + if ((params->nluns > 1) || (params->total_bit_row > BIT16_CHECK)) { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE); + } else { + mini_ctrl_cmd |= PAGE_MAX_BYTES(PAGE_MAX_SIZE - 1); + } + mini_ctrl_cmd |= PAGE_WRITE_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_generic_cmd_data(params, CDNS_WRITE, params->page_size); + if (ret != 0) { + return ret; + } + sdma_buffer_copy_in(params->sdma_base, data_buffer, params->page_size); + NAND_INT_SEM_TAKE(params); + mini_ctrl_cmd = 0; + mini_ctrl_cmd |= PAGE_WRITE_10H_CMD; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= PAGE_CMOD_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + ret = cdns_wait_sdma(base_address); + return ret; +} + +/** + * Perform a generic read or write operation for a range of pages in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_page_number The starting page number for the read or write operation. + * @param buffer The buffer containing the data to be written or to store the read data. + * @param page_count The number of pages to be read or written. + * @param mode The mode of operation (read, write). + * @retval 0 on success or negative error value on failure. + */ +static int cdns_nand_gen_read_write(struct cadence_nand_params *params, uint32_t start_page_number, + char *buffer, uint32_t page_count, uint8_t mode) +{ + uint64_t address = 0; + uint32_t index = 0; + uint32_t gen_row_address = 0; + int ret = 0; + + for (index = 0; index < page_count; index++) { + row_address_set(params, &gen_row_address, start_page_number++); + address = ((uint64_t)gen_row_address); + if (mode == CDNS_READ) { + ret = cdns_generic_page_read(params, address, + buffer + (index * (params->page_size))); + if (ret != 0) { + LOG_ERR("Cadence NAND Generic Page Read Error!!"); + return ret; + } + } else { + ret = cdns_generic_page_write(params, address, + buffer + (index * (params->page_size))); + if (ret != 0) { + LOG_ERR("Cadence NAND Generic Page write Error!!"); + return ret; + } + } + } + return 0; +} + +/** + * Perform a generic erase operation for a range of blocks in the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param start_block The starting block number for the erase operation. + * @param block_count The number of blocks to be erased. + * @retval 0 on success or -ETIMEDOUT error value on failure. + */ +static int cdns_nand_gen_erase(struct cadence_nand_params *params, uint32_t start_block, + uint32_t block_count) +{ + uint64_t mini_ctrl_cmd = 0; + uintptr_t base_address = 0; + uint32_t gen_row_address = 0; + uint32_t index = 0; + int ret = 0; + + for (index = 0; index < block_count; index++) { + row_address_set(params, &gen_row_address, (start_block * params->npages_per_block)); + start_block++; + base_address = params->nand_base; + mini_ctrl_cmd |= GCMD_TWB_VALUE; + mini_ctrl_cmd |= ERASE_ADDR_SIZE; + mini_ctrl_cmd |= ((gen_row_address) & (U32_MASK_VAL)); + mini_ctrl_cmd |= PAGE_ERASE_CMD; + ret = cdns_generic_send_cmd(params, mini_ctrl_cmd); + if (ret != 0) { + return ret; + } + NAND_INT_SEM_TAKE(params); + } + return 0; +} +#endif + +/** + * Read data from the Cadence NAND controller into a buffer. + */ +static inline int cdns_read_data(struct cadence_nand_params *params, uint32_t start_page_number, + const void *buffer, uint32_t page_count) +{ + int ret; + +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_read(params, start_page_number, (char *)buffer, page_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_read_write(params, start_page_number, (char *)buffer, page_count, + CDNS_READ); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_read_write(params, start_page_number, (char *)buffer, page_count, + CDNS_READ); +#endif + return ret; +} + +/** + * Read data from the Cadence NAND controller into a buffer. + * + * @param params The Cadence NAND parameters structure. + * @param buffer The buffer to store the read data. + * @param offset The offset within the NAND to start reading from. + * @param size The size of the data to read. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_read(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t size) +{ + uint32_t start_page_number; + uint32_t end_page_number; + uint32_t page_count; + int ret = 0; + uint16_t r_bytes; + uint16_t bytes_dif; + uint16_t lp_bytes_dif; + uint8_t check_page_first = 0; + uint8_t check_page_last = 0; + uint8_t *first_end_page; + uint8_t *last_end_page; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (size == 0) { + return 0; + } + + if ((offset >= params->device_size) || (size > (params->device_size - offset))) { + LOG_ERR("Wrong offset or size value passed!!"); + return -EINVAL; + } + + start_page_number = offset / (params->page_size); + end_page_number = ((offset + size) - 1) / ((params->page_size)); + + if ((offset % params->page_size) == 0) { + check_page_first = 1; + } + if (((offset + size) % params->page_size) == 0) { + check_page_last = 1; + } + page_count = end_page_number - start_page_number; + page_count++; + if ((check_page_last == 1) && (check_page_first == 1)) { + ret = cdns_read_data(params, start_page_number, (char *)buffer, page_count); + if (ret != 0) { + return ret; + } + + } else if (((check_page_last == 0) && (check_page_first == 1) && (page_count == 1)) || + ((check_page_last == 0) && (check_page_first == 0) && (page_count == 1)) || + ((check_page_last == 1) && (check_page_first == 0) && (page_count == 1))) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, page_count); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + (offset % (params->page_size)), size); + k_free(first_end_page); + } else if (((check_page_last == 0) && (check_page_first == 1) && (page_count == 2)) || + ((check_page_last == 0) && (check_page_first == 0) && (page_count == 2)) || + ((check_page_last == 1) && (check_page_first == 0) && (page_count == 2))) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size * 2)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size * 2)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, page_count); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + (offset % (params->page_size)), size); + k_free(first_end_page); + + } else if ((check_page_last == 0) && (check_page_first == 1) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, end_page_number, first_end_page, 1); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, start_page_number, (char *)buffer, (--page_count)); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + + memcpy((char *)buffer + ((page_count - 1) * params->page_size), first_end_page, + r_bytes); + k_free(first_end_page); + + } else if ((check_page_last == 1) && (check_page_first == 0) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if (first_end_page != NULL) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, 1); + if (ret < 0) { + k_free(first_end_page); + return ret; + } + r_bytes = (offset) % (params->page_size); + bytes_dif = (((start_page_number + 1) * params->page_size) - r_bytes); + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, (++start_page_number), ((char *)buffer + bytes_dif), + (--page_count)); + if (ret != 0) { + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + r_bytes, bytes_dif); + k_free(first_end_page); + } else if ((check_page_last == 0) && (check_page_first == 0) && (page_count > 2)) { + first_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + last_end_page = (char *)k_malloc(sizeof(char) * (params->page_size)); + if ((first_end_page != NULL) && (last_end_page != NULL)) { + memset(first_end_page, 0xFF, sizeof(char) * (params->page_size)); + memset(last_end_page, 0xFF, sizeof(char) * (params->page_size)); + } else { + LOG_ERR("Memory allocation error occurred %s", __func__); + return -ENOSR; + } + ret = cdns_read_data(params, start_page_number, first_end_page, 1); + if (ret != 0) { + k_free(first_end_page); + k_free(last_end_page); + return ret; + } + r_bytes = (offset) % (params->page_size); + bytes_dif = (((start_page_number + 1) * params->page_size) - r_bytes); + lp_bytes_dif = (offset + size) % (params->page_size); + ret = cdns_read_data(params, end_page_number, last_end_page, 1); + if (ret != 0) { + k_free(last_end_page); + k_free(first_end_page); + return ret; + } + r_bytes = (offset + size) % (params->page_size); + ret = cdns_read_data(params, (++start_page_number), ((char *)buffer + bytes_dif), + (page_count - 2)); + if (ret != 0) { + k_free(last_end_page); + k_free(first_end_page); + return ret; + } + memcpy((char *)buffer, first_end_page + r_bytes, bytes_dif); + memcpy(((char *)buffer + bytes_dif + + ((page_count - 2) * (params->npages_per_block))), + last_end_page, lp_bytes_dif); + } + + return 0; +} + +/** + * Write data from a buffer to the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param buffer The buffer containing the data to be written. + * @param offset The offset within the NAND to start writing to. + * @param len The length of the data to write. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_write(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t len) +{ + uint32_t start_page_number; + uint32_t end_page_number; + uint32_t page_count; + int ret = 0; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (len == 0) { + return 0; + } + + if ((offset >= params->device_size) || (len > (params->device_size - offset))) { + LOG_ERR("Wrong offset or len value passed!!"); + return -EINVAL; + } + + if ((offset % params->page_size) != 0) { + LOG_ERR("offset not page aligned!!! Page size = 0x%x", params->page_size); + return -EINVAL; + } + + if ((len % params->page_size) != 0) { + LOG_ERR("length not page aligned!!! Page size = 0x%x", params->page_size); + return -EINVAL; + } + + start_page_number = offset / (params->page_size); + end_page_number = ((offset + len) - 1) / ((params->page_size)); + page_count = end_page_number - start_page_number; + +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_write(params, start_page_number, (char *)buffer, ++page_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_read_write(params, start_page_number, (char *)buffer, ++page_count, + CDNS_WRITE); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_read_write(params, start_page_number, (char *)buffer, ++page_count, + CDNS_WRITE); +#endif + if (ret != 0) { + LOG_ERR("Cadence driver write Failed!!!"); + } + + return ret; +} + +/** + * Perform an erase operation on the Cadence NAND controller. + * + * @param params The Cadence NAND parameters structure. + * @param offset The offset within the NAND to start erasing. + * @param size The size of the data to erase. + * @retval 0 on success or negative error value on failure. + */ +int cdns_nand_erase(struct cadence_nand_params *params, uint32_t offset, uint32_t size) +{ + uint32_t start_block_number; + uint32_t end_block_number; + uint32_t block_count; + int ret; + + if (params == NULL) { + LOG_ERR("Wrong parameter passed!!"); + return -EINVAL; + } + + if (size == 0) { + return 0; + } + + if ((offset >= params->device_size) || (size > (params->device_size - offset))) { + LOG_ERR("Wrong offset or size value passed!!"); + return -EINVAL; + } + if ((offset % (params->block_size)) != 0) { + LOG_ERR("Offset value not aligned with block size!! Erase block size = %x", + params->block_size); + return -EINVAL; + } + if ((size % (params->block_size)) != 0) { + LOG_ERR("Length value not aligned with block size!! Erase block size = %x", + params->block_size); + return -EINVAL; + } + + start_block_number = (offset / ((params->page_size))) / (params->npages_per_block); + end_block_number = + (((offset + size) - 1) / ((params->page_size))) / (params->npages_per_block); + block_count = end_block_number - start_block_number; +#if CONFIG_CDNS_NAND_CDMA_MODE + ret = cdns_nand_cdma_erase(params, start_block_number, ++block_count); +#elif CONFIG_CDNS_NAND_PIO_MODE + ret = cdns_nand_pio_erase(params, NF_TDEF_TRD_NUM, NF_TDEF_DEV_NUM, start_block_number, + CNF_CMD_ERASE, ++block_count); +#elif CONFIG_CDNS_NAND_GENERIC_MODE + ret = cdns_nand_gen_erase(params, start_block_number, ++block_count); +#endif + if (ret != 0) { + LOG_ERR("Cadence driver Erase Failed!!!"); + } + + return ret; +} + +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT +void cdns_nand_irq_handler_ll(struct cadence_nand_params *params) +{ + uint32_t status = 0; + uint8_t thread_num = 0; + + status = sys_read32(params->nand_base + THREAD_INTERRUPT_STATUS); + thread_num = find_lsb_set(status); + + if (GET_INIT_SET_CHECK(status, (thread_num - 1)) != 0) { + /* Clear the interrupt*/ + sys_write32(BIT((thread_num - 1)), params->nand_base + THREAD_INTERRUPT_STATUS); + } +} +#endif diff --git a/drivers/flash/flash_cadence_nand_ll.h b/drivers/flash/flash_cadence_nand_ll.h new file mode 100644 index 00000000000..b52e7c90535 --- /dev/null +++ b/drivers/flash/flash_cadence_nand_ll.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CDNS_NAND_LL_H +#define CDNS_NAND_LL_H + +#include +#include +#include + +#define NAND_INT_SEM_TAKE(param_ptr) \ + COND_CODE_1(IS_ENABLED(CONFIG_CDNS_NAND_INTERRUPT_SUPPORT), \ + (k_sem_take(&(param_ptr->interrupt_sem_t), K_FOREVER)), ()) + +#define CNF_GET_INIT_COMP(x) (FIELD_GET(BIT(9), x)) +#define CNF_GET_INIT_FAIL(x) (FIELD_GET(BIT(10), x)) +#define CNF_GET_CTRL_BUSY(x) (FIELD_GET(BIT(8), x)) +#define GET_PAGE_SIZE(x) (FIELD_GET(GENMASK(15, 0), x)) +#define GET_PAGES_PER_BLOCK(x) (FIELD_GET(GENMASK(15, 0), x)) +#define GET_SPARE_SIZE(x) (FIELD_GET(GENMASK(31, 16), x)) +#define ONFI_TIMING_MODE_SDR(x) (FIELD_GET(GENMASK(15, 0), x)) +#define ONFI_TIMING_MODE_NVDDR(x) (FIELD_GET(GENMASK(31, 15), x)) + +/* Controller parameter registers */ +#define CNF_GET_NLUNS(x) (FIELD_GET(GENMASK(7, 0), x)) +#define CNF_GET_DEV_TYPE(x) (FIELD_GET(GENMASK(31, 30), x)) + +#define CNF_CTRLPARAM_VERSION (0x800) +#define CNF_CTRLPARAM_FEATURE (0x804) +#define CNF_CTRLPARAM_MFR_ID (0x808) +#define CNF_CTRLPARAM_DEV_AREA (0x80C) +#define CNF_CTRLPARAM_DEV_PARAMS0 (0x810) +#define CNF_CTRLPARAM_DEV_PARAMS1 (0x814) +#define CNF_CTRLPARAM_DEV_FEATUERS (0x818) +#define CNF_CTRLPARAM_DEV_BLOCKS_PLUN (0x81C) +#define CNF_CTRLPARAM_ONFI_TIMING_0 (0x824) +#define CNF_CTRLPARAM(_base, _reg) (_base + (CNF_CTRLPARAM_##_reg)) + +#define CNF_CMDREG_CTRL_STATUS (0x118) +#define CNF_CMDREG(_base, _reg) (_base + (CNF_CMDREG_##_reg)) +#define PINSEL(_x) (PINSEL##_x) +#define PIN(_x) PINSEL(_x)##SEL + +/*Hardware Features Support*/ +#define CNF_HW_NF_16_SUPPORT(x) (FIELD_GET(BIT(29), x)) +#define CNF_HW_NVDDR_SS_SUPPORT(x) (FIELD_GET(BIT(27), x)) +#define CNF_HW_ASYNC_SUPPORT(x) (FIELD_GET(BIT(26), x)) +#define CNF_HW_DMA_DATA_WIDTH_SUPPORT(x) (FIELD_GET(BIT(21), x)) +#define CNF_HW_DMA_ADDR_WIDTH_SUPPORT(x) (FIELD_GET(BIT(20), x)) +#define CNF_HW_DI_PR_SUPPORT(x) (FIELD_GET(BIT(14), x)) +#define CNF_HW_ECC_SUPPORT(x) (FIELD_GET(BIT(17), x)) +#define CNF_HW_RMP_SUPPORT(x) (FIELD_GET(BIT(12), x)) +#define CNF_HW_DI_CRC_SUPPORT(x) (FIELD_GET(BIT(8), x)) +#define CNF_HW_WR_PT_SUPPORT(x) (FIELD_GET(BIT(9), x)) + +/* Device types */ +#define CNF_DT_UNKNOWN (0x00) +#define CNF_DT_ONFI (0x01) +#define CNF_DT_JEDEC (0x02) +#define CNF_DT_LEGACY (0x03) + +/* Controller configuration registers */ +#define CNF_CTRLCFG_TRANS_CFG0 (0x400) +#define CNF_CTRLCFG_TRANS_CFG1 (0x404) +#define CNF_CTRLCFG_LONG_POLL (0x408) +#define CNF_CTRLCFG_SHORT_POLL (0x40C) +#define CNF_CTRLCFG_DEV_STAT (0x410) +#define CNF_CTRLCFG_DEV_LAYOUT (0x424) +#define CNF_CTRLCFG_ECC_CFG0 (0x428) +#define CNF_CTRLCFG_ECC_CFG1 (0x42C) +#define CNF_CTRLCFG_MULTIPLANE_CFG (0x434) +#define CNF_CTRLCFG_CACHE_CFG (0x438) +#define CNF_CTRLCFG_DMA_SETTINGS (0x43C) +#define CNF_CTRLCFG_FIFO_TLEVEL (0x454) + +#define CNF_CTRLCFG(_base, _reg) (_base + (CNF_CTRLCFG_##_reg)) + +/* Data integrity registers */ +#define CNF_DI_PAR_EN (0) +#define CNF_DI_CRC_EN (1) +#define CNF_DI_CONTROL (0x700) +#define CNF_DI_INJECT0 (0x704) +#define CNF_DI_INJECT1 (0x708) +#define CNF_DI_ERR_REG_ADDR (0x70C) +#define CNF_DI_INJECT2 (0x710) + +#define CNF_DI(_base, _reg) (_base + (CNF_DI_##_reg)) + +/* Thread idle timeout */ +#define THREAD_IDLE_TIME_OUT 500U + +/* Operation work modes */ +#define CNF_OPR_WORK_MODE_SDR (0) +#define CNF_OPR_WORK_MODE_NVDDR (1) +#define CNF_OPR_WORK_MODE_SDR_MASK (GENMASK(1, 0)) +#define CNF_OPR_WORK_MODE_NVDDR_MASK (BIT(0)) + +#define ONFI_INTERFACE (0x01) +#define NV_DDR_TIMING_READ (16) + +/* Interrupt register field offsets */ +#define INTERRUPT_STATUS_REG (0x0114) +#define THREAD_INTERRUPT_STATUS (0x0138) + +/* Mini controller DLL PHY controller register field offsets */ +#define CNF_DLL_PHY_RST_N (24) +#define CNF_DLL_PHY_EXT_WR_MODE (17) +#define CNF_DLL_PHY_EXT_RD_MODE (16) + +#define CNF_MINICTRL_WP_SETTINGS (0x1000) +#define CNF_MINICTRL_RBN_SETTINGS (0x1004) +#define CNF_MINICTRL_CMN_SETTINGS (0x1008) +#define CNF_MINICTRL_SKIP_BYTES_CFG (0x100C) +#define CNF_MINICTRL_SKIP_BYTES_OFFSET (0x1010) +#define CNF_MINICTRL_TOGGLE_TIMINGS0 (0x1014) +#define CNF_MINICTRL_TOGGLE_TIMINGS1 (0x1018) +#define CNF_MINICTRL_ASYNC_TOGGLE_TIMINGS (0x101C) +#define CNF_MINICTRL_SYNC_TIMINGS (0x1020) +#define CNF_MINICTRL_DLL_PHY_CTRL (0x1034) + +#define CNF_MINICTRL(_base, _reg) (_base + (CNF_MINICTRL_##_reg)) + +/* Async mode register field offsets */ +#define CNF_ASYNC_TIMINGS_TRH FIELD_PREP(GENMASK(28, 24), 2) +#define CNF_ASYNC_TIMINGS_TRP FIELD_PREP(GENMASK(20, 16), 4) +#define CNF_ASYNC_TIMINGS_TWH FIELD_PREP(GENMASK(12, 8), 2) +#define CNF_ASYNC_TIMINGS_TWP FIELD_PREP(GENMASK(4, 0), 4) + +/* Mini controller common settings register field offsets */ +#define CNF_CMN_SETTINGS_WR_WUP (20) +#define CNF_CMN_SETTINGS_RD_WUP (16) +#define CNF_CMN_SETTINGS_DEV16 (8) +#define CNF_CMN_SETTINGS_OPR (0) + +/* Interrupt status register. */ +#define INTR_STATUS (0x0110) +#define GINTR_ENABLE (31) +#define INTERRUPT_DISABLE (0) +#define INTERRUPT_ENABLE (1) + +/* CDMA Command type descriptor*/ +/* CDMA Command type Erase*/ +#define CNF_CMD_ERASE (0x1000) +/* CDMA Program Page type */ +#define CNF_CMD_WR (0x2100) +/* CDMA Read Page type */ +#define CNF_CMD_RD (0x2200) +#define DMA_MS_SEL (1) +#define VOL_ID (0) +#define CDMA_CF_DMA_MASTER (10) +#define CDMA_CF_DMA_MASTER_SET(x) FIELD_PREP(BIT(CDMA_CF_DMA_MASTER), x) +#define F_CFLAGS_VOL_ID (4) +#define F_CFLAGS_VOL_ID_SET(x) FIELD_PREP(GENMASK(7, 4), x) +#define CDMA_CF_INT (8) +#define CDMA_CF_INT_SET BIT(CDMA_CF_INT) +#define COMMON_SET_DEVICE_16BIT (8) +#define CDNS_READ (0) +#define CDNS_WRITE (1) +#define MAX_PAGES_IN_ONE_DSC (8) +#define CFLAGS_MPTRPC (0) +#define CFLAGS_MPTRPC_SET FIELD_PREP(BIT(CFLAGS_MPTRPC), 1) +#define CFLAGS_FPTRPC (1) +#define CFLAGS_FPTRPC_SET FIELD_PREP(BIT(CFLAGS_FPTRPC), 1) +#define CFLAGS_CONT (9) +#define CFLAGS_CONT_SET FIELD_PREP(BIT(CFLAGS_CONT), 1) +#define CLEAR_ALL_INTERRUPT (0xFFFFFFFF) +#define ENABLE (1) +#define DISABLE (0) +#define DEV_STAT_DEF_VALUE (0x40400000) + +/*Command Resister*/ +#define CDNS_CMD_REG0 (0x00) +#define CDNS_CMD_REG1 (0x04) +#define CDNS_CMD_REG2 (0x08) +#define CDNS_CMD_REG3 (0x0C) +#define CMD_STATUS_PTR_ADDR (0x10) +#define CMD_STAT_CMD_STATUS (0x14) +#define CDNS_CMD_REG4 (0x20) + +/* Cdns Nand Operation Modes*/ +#define CT_CDMA_MODE (0) +#define CT_PIO_MODE (1) +#define CT_GENERIC_MODE (3) +#define OPERATING_MODE_CDMA (0) +#define OPERATING_MODE_PIO (1) +#define OPERATING_MODE_GENERIC (2) + +#define THR_STATUS (0x120) +#define CMD_0_THREAD_POS (24) +#define CMD_0_THREAD_POS_SET(x) (FIELD_PREP(GENMASK(26, 24), x)) +#define CMD_0_C_MODE (30) +#define CMD_0_C_MODE_SET(x) (FIELD_PREP(GENMASK(31, 30), x)) +#define CMD_0_VOL_ID_SET(x) (FIELD_PREP(GENMASK(19, 16), x)) +#define PIO_SET_FEA_MODE (0x0100) +#define SET_FEAT_TIMING_MODE_ADDRESS (0x01) + + /* default thread number*/ +#define NF_TDEF_TRD_NUM (0) + +/* NF device number */ +#define NF_TDEF_DEV_NUM (0) +#define F_OTE (16) +#define F_BURST_SEL_SET(x) (FIELD_PREP(GENMASK(7, 0), x)) + +/* DMA maximum burst size (0-127)*/ +#define NF_TDEF_BURST_SEL (127) +#define NF_DMA_SETTING (0x043C) +#define NF_PRE_FETCH (0x0454) +#define PRE_FETCH_VALUE (1024/8) +#define NF_FIFO_TRIGG_LVL_SET(x) (FIELD_PREP(GENMASK(15, 0), x)) +#define NF_DMA_PACKAGE_SIZE_SET(x) (FIELD_PREP(GENMASK(31, 16), x)) +#define NF_FIFO_TRIGG_LVL (0) + +/* BCH correction strength */ +#define NF_TDEF_CORR_STR (0) +#define F_CSTAT_COMP (15) +#define F_CSTAT_FAIL (14) +#define HPNFC_STAT_INPR (0) +#define HPNFC_STAT_FAIL (2) +#define HPNFC_STAT_OK (1) +#define NF_16_ENABLE (1) +#define NF_16_DISABLE (0) + +/*PIO Mode*/ +#define NF_CMD4_BANK_SET(x) (FIELD_PREP(GENMASK(31, 24), x)) +#define PIO_CMD0_CT_POS (0) +#define PIO_CMD0_CT_SET(x) (FIELD_PREP(GENMASK(15, 0), x)) +#define PIO_CF_INT (20) +#define PIO_CF_INT_SET (FIELD_PREP(BIT(PIO_CF_INT), 1)) +#define PIO_CF_DMA_MASTER (21) +#define PIO_CF_DMA_MASTER_SET(x) (FIELD_PREP(BIT(PIO_CF_DMA_MASTER), x)) + +/* Phy registers*/ +#define PHY_DQ_TIMING_REG_OFFSET (0x00002000) +#define PHY_DQS_TIMING_REG_OFFSET (0x00002004) +#define PHY_GATE_LPBK_OFFSET (0x00002008) +#define PHY_DLL_MASTER_OFFSET (0x0000200c) +#define PHY_CTRL_REG_OFFSET (0x00002080) +#define PHY_TSEL_REG_OFFSET (0x00002084) + +#define PHY_CTRL_REG_SDR (0x00004040) +#define PHY_TSEL_REG_SDR (0x00000000) +#define PHY_DQ_TIMING_REG_SDR (0x00000002) +#define PHY_DQS_TIMING_REG_SDR (0x00100004) +#define PHY_GATE_LPBK_CTRL_REG_SDR (0x00D80000) +#define PHY_DLL_MASTER_CTRL_REG_SDR (0x00800000) +#define PHY_DLL_SLAVE_CTRL_REG_SDR (0x00000000) + +#define PHY_CTRL_REG_DDR (0x00000000) +#define PHY_TSEL_REG_DDR (0x00000000) +#define PHY_DQ_TIMING_REG_DDR (0x00000002) +#define PHY_DQS_TIMING_REG_DDR (0x00000004) +#define PHY_GATE_LPBK_CTRL_REG_DDR (0x00380002) +#define PHY_DLL_MASTER_CTRL_REG_DDR (0x001400fe) +#define PHY_DLL_SLAVE_CTRL_REG_DDR (0x00003f3f) + +/*SDMA*/ +#define GCMD_TWB_VALUE BIT64(6) +#define GCMCD_ADDR_SEQ (1) +#define GCMCD_DATA_SEQ (2) +#define ERASE_ADDR_SIZE (FIELD_PREP(GENMASK64(13, 11), 3ULL)) +#define GEN_SECTOR_COUNT (1ULL) +#define GEN_SECTOR_COUNT_SET (FIELD_PREP(GENMASK64(39, 32),\ + GEN_SECTOR_COUNT)) +#define GEN_SECTOR_SIZE (0x100ULL) +#define GEN_LAST_SECTOR_SIZE_SET(x) (FIELD_PREP(GENMASK64(55, 40), x)) +#define SDMA_TRIGG (21ULL) +#define SDMA_SIZE_ADDR (0x0440) +#define SDMA_TRD_NUM_ADDR (0x0444) +#define SDMA_ADDR0_ADDR (0x044c) +#define SDMA_ADDR1_ADDR (0x0450) +#define PAGE_READ_CMD (0x3ULL) +#define PAGE_WRITE_CMD (0x4ULL) +#define PAGE_ERASE_CMD (0x6ULL) +#define PAGE_CMOD_CMD (0x00) +#define PAGE_MAX_SIZE (4) +#define PAGE_MAX_BYTES(x) (FIELD_PREP(GENMASK64(13, 11), x)) +#define GEN_CF_INT (20) +#define GEN_CF_INT_SET(x) (FIELD_PREP(BIT(GEN_CF_INT), x)) +#define GEN_CF_INT_ENABLE (1) +#define GEN_ADDR_POS (16) +#define GEN_DIR_SET(x) (FIELD_PREP(BIT64(11), x)) +#define GEN_SECTOR_SET(x) (FIELD_PREP(GENMASK64(31, 16), x)) +#define PAGE_WRITE_10H_CMD (FIELD_PREP(GENMASK64(23, 16), 0x10ULL)) +#define GEN_ADDR_WRITE_DATA(x) (FIELD_PREP(GENMASK64(63, 32), x)) +#define NUM_ONE (1) +#define U32_MASK_VAL (0xFFFFFFFF) +#define BIT16_CHECK (16) +#define IDLE_TIME_OUT (5000U) +#define ROW_VAL_SET(x, y, z) (FIELD_PREP(GENMASK(x, y), z)) +#define SET_FEAT_ADDR(x) (FIELD_PREP(GENMASK(7, 0), x)) +#define THREAD_VAL(x) (FIELD_PREP(GENMASK(2, 0), x)) +#define INCR_CMD_TYPE(x) (x++) +#define DECR_CNT_ONE(x) (--x) +#define GET_INIT_SET_CHECK(x, y) (FIELD_GET(BIT(y), x)) +struct nf_ctrl_version { + uint32_t ctrl_rev:8; + uint32_t ctrl_fix:8; + uint32_t hpnfc_magic_number:16; +}; + +/* Cadence cdma command descriptor*/ +struct cdns_cdma_command_descriptor { + /* Next descriptor address*/ + uint64_t next_pointer; + /* Flash address is a 32-bit address comprising of ROW ADDR. */ + uint32_t flash_pointer; + uint16_t bank_number; + uint16_t reserved_0; + /*operation the controller needs to perform*/ + uint16_t command_type; + uint16_t reserved_1; + /* Flags for operation of this command. */ + uint16_t command_flags; + uint16_t reserved_2; + /* System/host memory address required for data DMA commands. */ + uint64_t memory_pointer; + /* Status of operation. */ + uint64_t status; + /* Address pointer to sync buffer location. */ + uint64_t sync_flag_pointer; + /* Controls the buffer sync mechanism. */ + uint32_t sync_arguments; + uint32_t reserved_4; + /* Control data pointer. */ + uint64_t ctrl_data_ptr; + +} __aligned(64); + +/* Row Address */ +union row_address { + struct { + uint32_t page_address:7; + uint32_t block_address:10; + uint32_t lun_address:3; + } row_bit_reg; + + uint32_t row_address_raw; +}; + +/* device info structure */ +struct cadence_nand_params { + uintptr_t nand_base; + uintptr_t sdma_base; + uint8_t datarate_mode; + uint8_t nluns; + uint16_t page_size; + uint16_t spare_size; + uint16_t npages_per_block; + uint32_t nblocks_per_lun; + uint32_t block_size; + uint8_t total_bit_row; + uint8_t page_size_bit; + uint8_t block_size_bit; + uint8_t lun_size_bit; + size_t page_count; + unsigned long long device_size; +#ifdef CONFIG_CDNS_NAND_INTERRUPT_SUPPORT + struct k_sem interrupt_sem_t; +#endif +} __aligned(32); + +/* Global function Api */ +int cdns_nand_init(struct cadence_nand_params *params); +int cdns_nand_read(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t size); +int cdns_nand_write(struct cadence_nand_params *params, const void *buffer, uint32_t offset, + uint32_t len); +int cdns_nand_erase(struct cadence_nand_params *params, uint32_t offset, uint32_t size); +#if CONFIG_CDNS_NAND_INTERRUPT_SUPPORT +void cdns_nand_irq_handler_ll(struct cadence_nand_params *params); +#endif + +#endif diff --git a/drivers/flash/flash_gd32_v2.c b/drivers/flash/flash_gd32_v2.c index 20a27b3d17b..645e40fd546 100644 --- a/drivers/flash/flash_gd32_v2.c +++ b/drivers/flash/flash_gd32_v2.c @@ -15,6 +15,7 @@ LOG_MODULE_DECLARE(flash_gd32); #define GD32_NV_FLASH_V2_NODE DT_INST(0, gd_gd32_nv_flash_v2) #define GD32_NV_FLASH_V2_TIMEOUT DT_PROP(GD32_NV_FLASH_V2_NODE, max_erase_time_ms) +#if !defined(CONFIG_SOC_GD32A503) /** * @brief GD32 FMC v2 flash memory has 2 banks. * Bank0 holds the first 512KB, bank1 is used give capacity for reset. @@ -30,6 +31,23 @@ LOG_MODULE_DECLARE(flash_gd32); #define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size) #endif +#elif defined(CONFIG_SOC_GD32A503) +/** + * @brief GD32A503 series flash memory has 2 banks. + * Bank0 holds the first 256KB, bank1 is used give capacity for reset. + * The page size is 1KB for all banks. + */ +#if (PRE_KB(256) >= SOC_NV_FLASH_SIZE) +#define GD32_NV_FLASH_V2_BANK0_SIZE SOC_NV_FLASH_SIZE +#define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size) +#else +#define GD32_NV_FLASH_V2_BANK0_SIZE KB(256) +#define GD32_NV_FLASH_V2_BANK0_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank0_page_size) +#define GD32_NV_FLASH_V2_BANK1_SIZE (SOC_NV_FLASH_SIZE - KB(256)) +#define GD32_NV_FLASH_V2_BANK1_PAGE_SIZE DT_PROP(GD32_NV_FLASH_V2_NODE, bank1_page_size) +#endif +#endif + #define GD32_FMC_V2_BANK0_WRITE_ERR (FMC_STAT0_PGERR | FMC_STAT0_WPERR) #define GD32_FMC_V2_BANK0_ERASE_ERR FMC_STAT0_WPERR @@ -42,7 +60,7 @@ static struct flash_pages_layout gd32_fmc_v2_layout[] = { .pages_size = GD32_NV_FLASH_V2_BANK0_PAGE_SIZE, .pages_count = GD32_NV_FLASH_V2_BANK0_SIZE / GD32_NV_FLASH_V2_BANK0_PAGE_SIZE }, -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE { .pages_size = GD32_NV_FLASH_V2_BANK1_PAGE_SIZE, .pages_count = GD32_NV_FLASH_V2_BANK1_SIZE / GD32_NV_FLASH_V2_BANK1_PAGE_SIZE @@ -77,7 +95,7 @@ static int gd32_fmc_v2_bank0_wait_idle(void) static int gd32_fmc_v2_bank0_write(off_t offset, const void *data, size_t len) { - flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_SIZE + offset); + flash_prg_t *prg_flash = (flash_prg_t *)((uint8_t *)SOC_NV_FLASH_ADDR + offset); flash_prg_t *prg_data = (flash_prg_t *)data; int ret = 0; @@ -158,14 +176,14 @@ static int gd32_fmc_v2_bank0_erase_block(off_t offset, size_t size) return ret; } - size -= GD32_NV_FLASH_V2_BANK0_SIZE; - page_addr += GD32_NV_FLASH_V2_BANK0_SIZE; + size -= GD32_NV_FLASH_V2_BANK0_PAGE_SIZE; + page_addr += GD32_NV_FLASH_V2_BANK0_PAGE_SIZE; } return 0; } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE static inline void gd32_fmc_v2_bank1_unlock(void) { FMC_KEY1 = UNLOCK_KEY0; @@ -179,7 +197,7 @@ static inline void gd32_fmc_v2_bank1_lock(void) static int gd32_fmc_v2_bank1_wait_idle(void) { - const int64_t expired_time = k_uptime_get() + FLASH_GD32_TIMEOUT; + const int64_t expired_time = k_uptime_get() + GD32_NV_FLASH_V2_TIMEOUT; while (FMC_STAT1 & FMC_STAT1_BUSY) { if (k_uptime_get() > expired_time) { @@ -279,7 +297,7 @@ static int gd32_fmc_v2_bank1_erase_block(off_t offset, size_t size) return 0; } -#endif /* FLASH_GD32_BANK1_SIZE */ +#endif /* GD32_NV_FLASH_V2_BANK1_SIZE */ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) { @@ -297,17 +315,17 @@ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) } else { if (offset < GD32_NV_FLASH_V2_BANK0_SIZE) { - if (offset % GD32_NV_FLASH_V2_BANK0_SIZE) { + if (offset % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE) { return false; } if (((offset + len) <= GD32_NV_FLASH_V2_BANK0_SIZE) && - (len % GD32_NV_FLASH_V2_BANK0_SIZE)) { + (len % GD32_NV_FLASH_V2_BANK0_PAGE_SIZE)) { return false; } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE /* Remove bank0 info from offset and len. */ if ((offset < GD32_NV_FLASH_V2_BANK0_SIZE) && ((offset + len) > GD32_NV_FLASH_V2_BANK0_SIZE)) { @@ -316,8 +334,8 @@ bool flash_gd32_valid_range(off_t offset, uint32_t len, bool write) } if (offset >= GD32_NV_FLASH_V2_BANK0_SIZE) { - if ((offset % GD32_NV_FLASH_V2_BANK1_SIZE) || - (len % GD32_NV_FLASH_V2_BANK1_SIZE)) { + if ((offset % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE) || + (len % GD32_NV_FLASH_V2_BANK1_PAGE_SIZE)) { return false; } } @@ -345,7 +363,7 @@ int flash_gd32_write_range(off_t offset, const void *data, size_t len) } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE size_t len1 = len - len0; if (len1 == 0U) { @@ -384,7 +402,7 @@ int flash_gd32_erase_block(off_t offset, size_t size) } } -#ifdef FLASH_GD32_BANK1_SIZE +#ifdef GD32_NV_FLASH_V2_BANK1_SIZE size_t size1 = size - size0; if (size1 == 0U) { diff --git a/drivers/flash/flash_handlers.c b/drivers/flash/flash_handlers.c index ac727b109e7..8c047adbaf4 100644 --- a/drivers/flash/flash_handlers.c +++ b/drivers/flash/flash_handlers.c @@ -94,7 +94,7 @@ static inline int z_vrfy_flash_sfdp_read(const struct device *dev, K_OOPS(K_SYSCALL_MEMORY_WRITE(data, len)); return z_impl_flash_sfdp_read(dev, offset, data, len); } -#include +#include static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, uint8_t *id) @@ -103,7 +103,7 @@ static inline int z_vrfy_flash_read_jedec_id(const struct device *dev, K_OOPS(K_SYSCALL_MEMORY_WRITE(id, 3)); return z_impl_flash_read_jedec_id(dev, id); } -#include +#include #endif /* CONFIG_FLASH_JESD216_API */ diff --git a/drivers/flash/flash_mcux_flexspi_hyperflash.c b/drivers/flash/flash_mcux_flexspi_hyperflash.c index b0a04ee63ed..5c03febc29a 100644 --- a/drivers/flash/flash_mcux_flexspi_hyperflash.c +++ b/drivers/flash/flash_mcux_flexspi_hyperflash.c @@ -433,8 +433,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset key = irq_lock(); } + /* Clock FlexSPI at 84 MHZ (42MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_42M); + data->port, MHZ(84)); while (len) { /* Writing between two page sizes crashes the platform so we @@ -477,8 +478,9 @@ static int flash_flexspi_hyperflash_write(const struct device *dev, off_t offset len -= i; } + /* Clock FlexSPI at 332 MHZ (166 MHz SCLK in DDR mode) */ (void)memc_flexspi_update_clock(&data->controller, &data->config, - data->port, MEMC_FLEXSPI_CLOCK_166M); + data->port, MHZ(332)); #ifdef CONFIG_HAS_MCUX_CACHE DCACHE_InvalidateByRange((uint32_t) dst, size); diff --git a/drivers/flash/flash_mcux_flexspi_nor.c b/drivers/flash/flash_mcux_flexspi_nor.c index 8a9c4f182ad..bfcef6daebd 100644 --- a/drivers/flash/flash_mcux_flexspi_nor.c +++ b/drivers/flash/flash_mcux_flexspi_nor.c @@ -6,11 +6,13 @@ #define DT_DRV_COMPAT nxp_imx_flexspi_nor +#include #include #include #include #include #include "spi_nor.h" +#include "jesd216.h" #include "memc_mcux_flexspi.h" #ifdef CONFIG_HAS_MCUX_CACHE @@ -40,22 +42,21 @@ static uint8_t nor_write_buf[SPI_NOR_PAGE_SIZE]; LOG_MODULE_REGISTER(flash_flexspi_nor, CONFIG_FLASH_LOG_LEVEL); enum { - /* Instructions matching with XIP layout */ - READ_FAST_QUAD_OUTPUT, - READ_FAST_OUTPUT, - READ_NORMAL_OUTPUT, + READ, + PAGE_PROGRAM, READ_STATUS, WRITE_ENABLE, ERASE_SECTOR, ERASE_BLOCK, - PAGE_PROGRAM_INPUT, - PAGE_PROGRAM_QUAD_INPUT, READ_ID, - WRITE_STATUS_REG, - ENTER_QPI, - EXIT_QPI, READ_STATUS_REG, ERASE_CHIP, + READ_JESD216, + /* Used for temporary commands during initialization */ + SCRATCH_CMD, + SCRATCH_CMD2, + /* Must be last entry */ + FLEXSPI_INSTR_END, }; struct flash_flexspi_nor_config { @@ -71,98 +72,70 @@ struct flash_flexspi_nor_data { struct device controller; flexspi_device_config_t config; flexspi_port_t port; + bool legacy_poll; struct flash_pages_layout layout; struct flash_parameters flash_parameters; }; -static const uint32_t flash_flexspi_nor_lut[][4] = { - [READ_ID] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), +/* Initial LUT table */ +static const uint32_t flash_flexspi_nor_base_lut[][MEMC_FLEXSPI_CMD_PER_SEQ] = { + /* 1S-1S-1S flash read command, should be compatible with all SPI nor flashes */ + [READ] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_READ, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), }, - - [READ_STATUS_REG] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), + [READ_JESD216] = { + /* Install read SFDP command */ + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, JESD216_CMD_READ_SFDP, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 24), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 8, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x4), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), }, - - [WRITE_STATUS_REG] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, - kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04), + /* Standard 1S-1S-1S flash write command, can be switched to 1S-1S-4S when QE is set */ + [PAGE_PROGRAM] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, [WRITE_ENABLE] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WREN, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WREN, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, [ERASE_SECTOR] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), }, [ERASE_BLOCK] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), }, [ERASE_CHIP] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_CE, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [READ_FAST_QUAD_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x6B, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x08, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_CE, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }, - [READ_FAST_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), - }, - - [READ_NORMAL_OUTPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_READ, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [READ_STATUS] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, - kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), - }, - - [PAGE_PROGRAM_INPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [PAGE_PROGRAM_QUAD_INPUT] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, - kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), - }, - - [ENTER_QPI] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + [READ_ID] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDID, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01), }, - [EXIT_QPI] = { - FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, - kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + [READ_STATUS_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01), }, }; -static int flash_flexspi_nor_get_vendor_id(struct flash_flexspi_nor_data *data, +/* Helper so we can read flash ID without flash access for XIP */ +static int flash_flexspi_nor_read_id_helper(struct flash_flexspi_nor_data *data, uint8_t *vendor_id) { uint32_t buffer = 0; @@ -175,49 +148,42 @@ static int flash_flexspi_nor_get_vendor_id(struct flash_flexspi_nor_data *data, .SeqNumber = 1, .seqIndex = READ_ID, .data = &buffer, - .dataSize = 1, + .dataSize = 3, }; LOG_DBG("Reading id"); ret = memc_flexspi_transfer(&data->controller, &transfer); - *vendor_id = buffer; + if (ret < 0) { + return ret; + } + + memcpy(vendor_id, &buffer, 3); return ret; } -static int flash_flexspi_nor_read_status(struct flash_flexspi_nor_data *data, - uint32_t *status) +static int flash_flexspi_nor_read_id(const struct device *dev, uint8_t *vendor_id) { - flexspi_transfer_t transfer = { - .deviceAddress = 0, - .port = data->port, - .cmdType = kFLEXSPI_Read, - .SeqNumber = 1, - .seqIndex = READ_STATUS_REG, - .data = status, - .dataSize = 1, - }; - - LOG_DBG("Reading status register"); + struct flash_flexspi_nor_data *data = dev->data; - return memc_flexspi_transfer(&data->controller, &transfer); + return flash_flexspi_nor_read_id_helper(data, vendor_id); } -static int flash_flexspi_nor_write_status(struct flash_flexspi_nor_data *data, +static int flash_flexspi_nor_read_status(struct flash_flexspi_nor_data *data, uint32_t *status) { flexspi_transfer_t transfer = { .deviceAddress = 0, .port = data->port, - .cmdType = kFLEXSPI_Write, + .cmdType = kFLEXSPI_Read, .SeqNumber = 1, - .seqIndex = WRITE_STATUS_REG, + .seqIndex = READ_STATUS_REG, .data = status, .dataSize = 1, }; - LOG_DBG("Writing status register"); + LOG_DBG("Reading status register"); return memc_flexspi_transfer(&data->controller, &transfer); } @@ -300,7 +266,7 @@ static int flash_flexspi_nor_page_program(struct flash_flexspi_nor_data *data, .port = data->port, .cmdType = kFLEXSPI_Write, .SeqNumber = 1, - .seqIndex = PAGE_PROGRAM_QUAD_INPUT, + .seqIndex = PAGE_PROGRAM, .data = (uint32_t *) buffer, .dataSize = len, }; @@ -315,25 +281,24 @@ static int flash_flexspi_nor_wait_bus_busy(struct flash_flexspi_nor_data *data) uint32_t status = 0; int ret; - do { + while (1) { ret = flash_flexspi_nor_read_status(data, &status); LOG_DBG("status: 0x%x", status); if (ret) { LOG_ERR("Could not read status"); return ret; } - } while (status & BIT(0)); - - return 0; -} -static int flash_flexspi_nor_enable_quad_mode(struct flash_flexspi_nor_data *data) -{ - uint32_t status = 0x40; - - flash_flexspi_nor_write_status(data, &status); - flash_flexspi_nor_wait_bus_busy(data); - memc_flexspi_reset(&data->controller); + if (data->legacy_poll) { + if ((status & BIT(0)) == 0) { + break; + } + } else { + if (status & BIT(7)) { + break; + } + } + } return 0; } @@ -494,11 +459,583 @@ static void flash_flexspi_nor_pages_layout(const struct device *dev, } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +/* + * This function enables quad mode, when supported. Otherwise it + * returns an error. + * @param dev: Flexspi device + * @param flexspi_lut: flexspi lut table, useful if instruction writes are needed + * @param qer: DW15 quad enable parameter + * @return 0 if quad mode was entered, or -ENOTSUP if quad mode is not supported + */ +static int flash_flexspi_nor_quad_enable(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ], + uint8_t qer) +{ + int ret; + uint32_t buffer = 0; + uint16_t bit = 0; + uint8_t rd_size, wr_size; + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = data->port, + .SeqNumber = 1, + .data = &buffer, + }; + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + + switch (qer) { + case JESD216_DW15_QER_VAL_NONE: + /* No init needed */ + return 0; + case JESD216_DW15_QER_VAL_S2B1v1: + case JESD216_DW15_QER_VAL_S2B1v4: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 1 of status register 2 */ + bit = BIT(9); + rd_size = 2; + wr_size = 2; + break; + case JESD216_DW15_QER_VAL_S1B6: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 6 of status register 1 */ + bit = BIT(6); + rd_size = 1; + wr_size = 1; + break; + case JESD216_DW15_QER_VAL_S2B7: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x3F, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x3E, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 7 of status register 2 */ + bit = BIT(7); + rd_size = 1; + wr_size = 1; + break; + case JESD216_DW15_QER_VAL_S2B1v5: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR2, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 1 of status register 2 */ + bit = BIT(9); + rd_size = 1; + wr_size = 2; + break; + case JESD216_DW15_QER_VAL_S2B1v6: + /* Install read and write status command */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR2, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_WRSR2, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + + /* Set bit 7 of status register 2 */ + bit = BIT(7); + rd_size = 1; + wr_size = 1; + break; + default: + return -ENOTSUP; + } + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = rd_size; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Read; + /* Read status register */ + ret = memc_flexspi_transfer(&data->controller, &transfer); + if (ret < 0) { + return ret; + } + buffer |= bit; + transfer.dataSize = wr_size; + transfer.seqIndex = SCRATCH_CMD2; + transfer.cmdType = kFLEXSPI_Write; + return memc_flexspi_transfer(&data->controller, &transfer); +} + +/* + * This function enables 4 byte addressing, when supported. Otherwise it + * returns an error. + * @param dev: Flexspi device + * @param flexspi_lut: flexspi lut table, useful if instruction writes are needed + * @param en4b: DW16 enable 4 byte mode parameter + * @return 0 if 4 byte mode was entered, or -ENOTSUP if 4 byte mode was not supported + */ +static int flash_flexspi_nor_4byte_enable(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ], + uint32_t en4b) +{ + int ret; + uint32_t buffer = 0; + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = data->port, + .SeqNumber = 1, + .data = &buffer, + }; + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + if (en4b & BIT(6)) { + /* Flash is always in 4 byte mode. We just need to configure LUT */ + return 0; + } else if (en4b & BIT(5)) { + /* Dedicated vendor instruction set, which we don't support. Exit here */ + return -ENOTSUP; + } else if (en4b & BIT(4)) { + /* Set bit 0 of 16 bit configuration register */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB5, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x1); + flexspi_lut[SCRATCH_CMD2][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB1, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x1); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 2; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Read; + /* Read config register */ + ret = memc_flexspi_transfer(&data->controller, &transfer); + if (ret < 0) { + return ret; + } + buffer |= BIT(0); + /* Set config register */ + transfer.seqIndex = SCRATCH_CMD2; + transfer.cmdType = kFLEXSPI_Read; + return memc_flexspi_transfer(&data->controller, &transfer); + } else if (en4b & BIT(1)) { + /* Issue write enable, then instruction 0xB7 */ + flash_flexspi_nor_write_enable(data); + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB7, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 0; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Command; + return memc_flexspi_transfer(&data->controller, &transfer); + } else if (en4b & BIT(0)) { + /* Issue instruction 0xB7 */ + flexspi_lut[SCRATCH_CMD][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xB7, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + ret = memc_flexspi_set_device_config(&data->controller, + &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + transfer.dataSize = 0; + transfer.seqIndex = SCRATCH_CMD; + transfer.cmdType = kFLEXSPI_Command; + return memc_flexspi_transfer(&data->controller, &transfer); + } + /* Other methods not supported */ + return -ENOTSUP; +} + +/* + * This function configures the FlexSPI to manage the flash device + * based on values in SFDP header + * @param data: Flexspi device data + * @param header: SFDP header for flash + * @param bfp: basic flash parameters for flash + * @param flexspi_lut: LUT table, filled with READ LUT command + * @return 0 on success, or negative value on error + */ +static int flash_flexspi_nor_config_flash(struct flash_flexspi_nor_data *data, + struct jesd216_sfdp_header *header, + struct jesd216_bfp *bfp, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ]) +{ + struct jesd216_instr instr; + struct jesd216_bfp_dw16 dw16; + struct jesd216_bfp_dw15 dw15; + struct jesd216_bfp_dw14 dw14; + uint8_t addr_width; + uint8_t mode_cmd; + int ret; + + addr_width = jesd216_bfp_addrbytes(bfp) == + JESD216_SFDP_BFP_DW1_ADDRBYTES_VAL_4B ? 32 : 24; + + /* Check to see if we can enable 4 byte addressing */ + ret = jesd216_bfp_decode_dw16(&header->phdr[0], bfp, &dw16); + if (ret < 0) { + return ret; + } + + /* Attempt to enable 4 byte addressing */ + ret = flash_flexspi_nor_4byte_enable(data, flexspi_lut, dw16.enter_4ba); + if (ret == 0) { + /* Use 4 byte address width */ + addr_width = 32; + /* Update LUT for ERASE_SECTOR and ERASE_BLOCK to use 32 bit addr */ + flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_BE, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + } + /* Extract the read command. + * Note- enhanced XIP not currently supported, nor is 4-4-4 mode. + */ + if (jesd216_bfp_read_support(&header->phdr[0], bfp, + JESD216_MODE_144, &instr) > 0) { + LOG_DBG("Enable 144 mode"); + /* Configure for 144 QUAD read mode */ + if (instr.mode_clocks == 2) { + mode_cmd = kFLEXSPI_Command_MODE8_SDR; + } else if (instr.mode_clocks == 1) { + mode_cmd = kFLEXSPI_Command_MODE4_SDR; + } else if (instr.mode_clocks == 0) { + /* Just send dummy cycles during mode clock period */ + mode_cmd = kFLEXSPI_Command_DUMMY_SDR; + } else { + return -ENOTSUP; + } + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, instr.instr, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, addr_width); + /* Note- we always set mode bits to 0x0 */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + mode_cmd, kFLEXSPI_4PAD, 0x00, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, instr.wait_states); + flexspi_lut[READ][2] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Read 1S-4S-4S enable method */ + ret = jesd216_bfp_decode_dw15(&header->phdr[0], bfp, &dw15); + if (ret < 0) { + return ret; + } + ret = flash_flexspi_nor_quad_enable(data, flexspi_lut, dw15.qer); + if (ret < 0) { + return ret; + } + /* Now, install 1S-1S-4S page program command */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_1_4, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + + } else if (jesd216_bfp_read_support(&header->phdr[0], bfp, + JESD216_MODE_122, &instr) > 0) { + LOG_DBG("Enable 122 mode"); + if (instr.mode_clocks == 4) { + mode_cmd = kFLEXSPI_Command_MODE8_SDR; + } else if (instr.mode_clocks == 2) { + mode_cmd = kFLEXSPI_Command_MODE4_SDR; + } else if (instr.mode_clocks == 1) { + mode_cmd = kFLEXSPI_Command_MODE2_SDR; + } else if (instr.mode_clocks == 0) { + /* Just send dummy cycles during mode clock period */ + mode_cmd = kFLEXSPI_Command_DUMMY_SDR; + } else { + return -ENOTSUP; + } + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, instr.instr, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_2PAD, addr_width); + /* Note- we always set mode bits to 0x0 */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + mode_cmd, kFLEXSPI_2PAD, 0x0, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_2PAD, instr.wait_states); + flexspi_lut[READ][2] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_READ_SDR, kFLEXSPI_2PAD, 0x02, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Now, install 1S-1S-2S page program command */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_1_2, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, addr_width); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_2PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + } + /* Default to 111 mode if no support exists, leave READ/WRITE untouched */ + + /* Now, read DW14 to determine the polling method we should use while programming */ + ret = jesd216_bfp_decode_dw14(&header->phdr[0], bfp, &dw14); + if (ret < 0) { + return ret; + } + if (dw14.poll_options & BIT(1)) { + /* Read instruction used for polling is 0x70 */ + data->legacy_poll = false; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x70, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + } else { + /* Read instruction used for polling is 0x05 */ + data->legacy_poll = true; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + } + + return 0; +} + +/* Helper so we can avoid flash access while performing SFDP probe */ +static int flash_flexspi_nor_sfdp_read_helper(struct flash_flexspi_nor_data *dev_data, + off_t offset, void *data, size_t len) +{ + flexspi_transfer_t transfer = { + .deviceAddress = offset, + .port = dev_data->port, + .cmdType = kFLEXSPI_Read, + .seqIndex = READ_JESD216, + .SeqNumber = 1, + .data = (uint32_t *)data, + .dataSize = len, + }; + + /* Get SFDP data */ + return memc_flexspi_transfer(&dev_data->controller, &transfer); +} + + +#if defined(CONFIG_FLASH_JESD216_API) + +static int flash_flexspi_nor_sfdp_read(const struct device *dev, + off_t offset, void *data, size_t len) +{ + struct flash_flexspi_nor_data *dev_data = dev->data; + + return flash_flexspi_nor_sfdp_read_helper(dev_data, offset, data, len); +} + +#endif + +/* Checks JEDEC ID of flash. If supported, installs custom LUT table */ +static int flash_flexspi_nor_check_jedec(struct flash_flexspi_nor_data *data, + uint32_t (*flexspi_lut)[MEMC_FLEXSPI_CMD_PER_SEQ]) +{ + int ret; + uint32_t vendor_id; + + ret = flash_flexspi_nor_read_id_helper(data, (uint8_t *)&vendor_id); + if (ret < 0) { + return ret; + } + + /* Switch on manufacturer and vendor ID */ + switch (vendor_id & 0xFFFF) { + case 0x25C2: + /* MX25 flash, use 4 byte read/write */ + flexspi_lut[READ][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_4READ_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 32); + /* Flash needs 10 dummy cycles */ + flexspi_lut[READ][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 10, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04); + /* Only 1S-4S-4S page program supported */ + flexspi_lut[PAGE_PROGRAM][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_PP_1_4_4_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 32); + flexspi_lut[PAGE_PROGRAM][1] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x4, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0); + /* Update ERASE commands for 4 byte mode */ + flexspi_lut[ERASE_SECTOR][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_SE_4B, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 32); + flexspi_lut[ERASE_BLOCK][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xDC, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 32), + /* Read instruction used for polling is 0x05 */ + data->legacy_poll = true; + flexspi_lut[READ_STATUS_REG][0] = FLEXSPI_LUT_SEQ( + kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, SPI_NOR_CMD_RDSR, + kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x01); + /* Device uses bit 6 of status reg 1 for QE */ + return flash_flexspi_nor_quad_enable(data, flexspi_lut, JESD216_DW15_QER_VAL_S1B6); + default: + return -ENOTSUP; + } +} + +/* Probe parameters from flash SFDP header, and use them to configure the FlexSPI */ +static int flash_flexspi_nor_probe(struct flash_flexspi_nor_data *data) +{ + uint32_t flexspi_lut[FLEXSPI_INSTR_END][MEMC_FLEXSPI_CMD_PER_SEQ] = {0}; + /* JESD216B defines up to 23 basic flash parameters */ + uint32_t param_buf[23]; + /* Space to store SFDP header and first parameter header */ + uint8_t sfdp_buf[JESD216_SFDP_SIZE(1)] __aligned(4); + struct jesd216_bfp *bfp = (struct jesd216_bfp *)param_buf; + struct jesd216_sfdp_header *header = (struct jesd216_sfdp_header *)sfdp_buf; + int ret; + unsigned int key = 0U; + + flexspi_device_config_t config = { + .flexspiRootClk = MHZ(50), + .flashSize = FLEXSPI_FLSHCR0_FLSHSZ_MASK, /* Max flash size */ + .ARDSeqNumber = 1, + .ARDSeqIndex = READ, + }; + + if (memc_flexspi_is_running_xip(&data->controller)) { + /* + * ==== ENTER CRITICAL SECTION ==== + * No flash access should be performed in critical section. All + * code and data accessed must reside in ram. + */ + key = irq_lock(); + memc_flexspi_wait_bus_idle(&data->controller); + } + + /* SFDP spec requires that we downclock the FlexSPI to 50MHz or less */ + ret = memc_flexspi_update_clock(&data->controller, &config, + data->port, MHZ(50)); + if (ret < 0) { + goto _exit; + } + + /* Setup initial LUT table and FlexSPI configuration */ + memcpy(flexspi_lut, flash_flexspi_nor_base_lut, sizeof(flash_flexspi_nor_base_lut)); + + ret = memc_flexspi_set_device_config(&data->controller, &config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + goto _exit; + } + + /* First, check if the JEDEC ID of this flash has explicit support + * in this driver + */ + ret = flash_flexspi_nor_check_jedec(data, flexspi_lut); + if (ret == 0) { + /* Flash was supported, SFDP probe not needed */ + goto _program_lut; + } + + ret = flash_flexspi_nor_sfdp_read_helper(data, 0, sfdp_buf, sizeof(sfdp_buf)); + if (ret < 0) { + goto _exit; + } + + LOG_DBG("SFDP header magic: 0x%x", header->magic); + if (jesd216_sfdp_magic(header) != JESD216_SFDP_MAGIC) { + /* Header was read incorrectly */ + LOG_WRN("Invalid header, using legacy SPI mode"); + data->legacy_poll = true; + goto _program_lut; + } + + if (header->phdr[0].len_dw > ARRAY_SIZE(param_buf)) { + /* Not enough space to read parameter table */ + ret = -ENOBUFS; + goto _exit; + } + + /* Read basic flash parameter table */ + ret = flash_flexspi_nor_sfdp_read_helper(data, + jesd216_param_addr(&header->phdr[0]), + param_buf, + sizeof(uint32_t) * header->phdr[0].len_dw); + if (ret < 0) { + goto _exit; + } + + /* Configure flash */ + ret = flash_flexspi_nor_config_flash(data, header, bfp, flexspi_lut); + if (ret < 0) { + goto _exit; + } + +_program_lut: + /* + * Update the FlexSPI with the config structure provided + * from devicetree and the configured LUT + */ + ret = memc_flexspi_set_device_config(&data->controller, &data->config, + (uint32_t *)flexspi_lut, + FLEXSPI_INSTR_END * MEMC_FLEXSPI_CMD_PER_SEQ, + data->port); + if (ret < 0) { + return ret; + } + +_exit: + memc_flexspi_reset(&data->controller); + + if (memc_flexspi_is_running_xip(&data->controller)) { + /* ==== EXIT CRITICAL SECTION ==== */ + irq_unlock(key); + } + + return ret; +} + static int flash_flexspi_nor_init(const struct device *dev) { const struct flash_flexspi_nor_config *config = dev->config; struct flash_flexspi_nor_data *data = dev->data; - uint8_t vendor_id; + uint32_t vendor_id; /* First step- use ROM pointer to controller device to create * a copy of the device structure in RAM we can use while in @@ -511,31 +1048,36 @@ static int flash_flexspi_nor_init(const struct device *dev) return -ENODEV; } - if (memc_flexspi_is_running_xip(&data->controller)) { - /* Wait for bus idle before configuring */ - memc_flexspi_wait_bus_idle(&data->controller); + if (flash_flexspi_nor_probe(data)) { + if (memc_flexspi_is_running_xip(&data->controller)) { + /* We can't continue from here- the LUT stored in + * the FlexSPI will be invalid so we cannot XIP. + * Instead, spin here + */ + while (1) { + /* Spin */ + } + } + LOG_ERR("SFDP probe failed"); + return -EIO; } - if (memc_flexspi_set_device_config(&data->controller, &data->config, - (const uint32_t *)flash_flexspi_nor_lut, - sizeof(flash_flexspi_nor_lut) / MEMC_FLEXSPI_CMD_SIZE, - data->port)) { - LOG_ERR("Could not set device configuration"); - return -EINVAL; + + /* Set the FlexSPI to full clock speed */ + if (memc_flexspi_update_clock(&data->controller, &data->config, + data->port, data->config.flexspiRootClk)) { + LOG_ERR("Could not set flexspi clock speed"); + return -ENOTSUP; } + memc_flexspi_reset(&data->controller); - if (flash_flexspi_nor_get_vendor_id(data, &vendor_id)) { + if (flash_flexspi_nor_read_id(dev, (uint8_t *)&vendor_id)) { LOG_ERR("Could not read vendor id"); return -EIO; } LOG_DBG("Vendor id: 0x%0x", vendor_id); - if (flash_flexspi_nor_enable_quad_mode(data)) { - LOG_ERR("Could not enable quad mode"); - return -EIO; - } - return 0; } @@ -547,6 +1089,10 @@ static const struct flash_driver_api flash_flexspi_nor_api = { #if defined(CONFIG_FLASH_PAGE_LAYOUT) .page_layout = flash_flexspi_nor_pages_layout, #endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = flash_flexspi_nor_sfdp_read, + .read_jedec_id = flash_flexspi_nor_read_id, +#endif }; #define CONCAT3(x, y, z) x ## y ## z @@ -559,7 +1105,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { #define FLASH_FLEXSPI_DEVICE_CONFIG(n) \ { \ - .flexspiRootClk = MHZ(120), \ + .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \ .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \ .CSIntervalUnit = \ CS_INTERVAL_UNIT( \ @@ -572,7 +1118,7 @@ static const struct flash_driver_api flash_flexspi_nor_api = { .enableWordAddress = DT_INST_PROP(n, word_addressable), \ .AWRSeqIndex = 0, \ .AWRSeqNumber = 0, \ - .ARDSeqIndex = READ_FAST_QUAD_OUTPUT, \ + .ARDSeqIndex = READ, \ .ARDSeqNumber = 1, \ .AHBWriteWaitUnit = \ AHB_WRITE_WAIT_UNIT( \ diff --git a/drivers/flash/flash_sam.c b/drivers/flash/flash_sam.c index 118775d29f3..e4a807552fc 100644 --- a/drivers/flash/flash_sam.c +++ b/drivers/flash/flash_sam.c @@ -1,404 +1,530 @@ /* * Copyright (c) 2018 Aurelien Jarno + * Copyright (c) 2023 Bjarki Arge Andreasen * * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT atmel_sam_flash_controller -#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) +/* + * This driver defines a page as the erase_block_size. + * This driver defines a write page as defined by the flash controller + * This driver defines a section as a contiguous array of bytes + * This driver defines an area as the entire flash area + * This driver defines the write block size as the minimum write block size + */ -#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size) -#define FLASH_ERASE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) +#define DT_DRV_COMPAT atmel_sam_flash_controller -#include -#include -#include #include +#include +#include #include -#include #include +#include -#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL #include -LOG_MODULE_REGISTER(flash_sam0); - -/* - * The SAM flash memories use very different granularity for writing, - * erasing and locking. In addition the first sector is composed of two - * 8-KiB small sectors with a minimum 512-byte erase size, while the - * other sectors have a minimum 8-KiB erase size. - * - * For simplicity reasons this flash controller driver only addresses the - * flash by 8-KiB blocks (called "pages" in the Zephyr terminology). - */ +LOG_MODULE_REGISTER(flash_sam, CONFIG_FLASH_LOG_LEVEL); +#define SAM_FLASH_WRITE_PAGE_SIZE (512) -/* - * We only use block mode erases. The datasheet gives a maximum erase time - * of 200ms for a 8KiB block. - */ -#define SAM_FLASH_TIMEOUT_MS 220 -#if defined(IFLASH0_PAGE_SIZE) -#define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE -#endif +typedef void (*sam_flash_irq_init_fn_ptr)(void); -struct flash_sam_dev_cfg { +struct sam_flash_config { Efc *regs; + sam_flash_irq_init_fn_ptr irq_init; + off_t area_address; + off_t area_size; + struct flash_parameters parameters; + struct flash_pages_layout *pages_layouts; + size_t pages_layouts_size; }; -struct flash_sam_dev_data { - struct k_sem sem; +struct sam_flash_erase_data { + off_t section_start; + size_t section_end; + bool succeeded; }; -static const struct flash_parameters flash_sam_parameters = { - .write_block_size = FLASH_WRITE_BLK_SZ, - .erase_value = 0xff, +struct sam_flash_data { + const struct device *dev; + struct k_spinlock lock; + struct sam_flash_erase_data erase_data; + struct k_sem ready_sem; }; -static int flash_sam_write_protection(const struct device *dev, bool enable); - -static inline void flash_sam_sem_take(const struct device *dev) +static bool sam_flash_validate_offset_len(off_t offset, size_t len) { - struct flash_sam_dev_data *data = dev->data; + if (offset < 0) { + return false; + } - k_sem_take(&data->sem, K_FOREVER); + if ((offset + len) < len) { + return false; + } + + return true; } -static inline void flash_sam_sem_give(const struct device *dev) +static bool sam_flash_aligned(size_t value, size_t alignment) { - struct flash_sam_dev_data *data = dev->data; + return (value & (alignment - 1)) == 0; +} - k_sem_give(&data->sem); +static bool sam_flash_offset_is_on_write_page_boundary(off_t offset) +{ + return sam_flash_aligned(offset, SAM_FLASH_WRITE_PAGE_SIZE); } -/* Check that the offset is within the flash */ -static bool flash_sam_valid_range(const struct device *dev, off_t offset, - size_t len) +static inline void sam_flash_mask_ready_interrupt(const struct sam_flash_config *config) { - if (offset > CONFIG_FLASH_SIZE * 1024) { - return false; - } + Efc *regs = config->regs; - if (len && ((offset + len - 1) > (CONFIG_FLASH_SIZE * 1024))) { - return false; - } + regs->EEFC_FMR &= ~EEFC_FMR_FRDY; +} - return true; +static inline void sam_flash_unmask_ready_interrupt(const struct sam_flash_config *config) +{ + Efc *regs = config->regs; + + regs->EEFC_FMR |= EEFC_FMR_FRDY; } -/* Convert an offset in the flash into a page number */ -static off_t flash_sam_get_page(off_t offset) +static void sam_flash_isr(const struct device *dev) { - return offset / IFLASH_PAGE_SIZE; + struct sam_flash_data *data = dev->data; + const struct sam_flash_config *config = dev->config; + + sam_flash_mask_ready_interrupt(config); + k_sem_give(&data->ready_sem); } -/* - * This function checks for errors and waits for the end of the - * previous command. - */ -static int flash_sam_wait_ready(const struct device *dev) +static int sam_flash_section_wait_until_ready(const struct device *dev) { - const struct flash_sam_dev_cfg *config = dev->config; + struct sam_flash_data *data = dev->data; + const struct sam_flash_config *config = dev->config; + Efc *regs = config->regs; + uint32_t eefc_fsr; - Efc * const efc = config->regs; + k_sem_reset(&data->ready_sem); + sam_flash_unmask_ready_interrupt(config); - uint64_t timeout_time = k_uptime_get() + SAM_FLASH_TIMEOUT_MS; - uint32_t fsr; + if (k_sem_take(&data->ready_sem, K_MSEC(500)) < 0) { + LOG_ERR("Command did not execute in time"); + return -EFAULT; + } - do { - fsr = efc->EEFC_FSR; + /* FSR register is cleared on read */ + eefc_fsr = regs->EEFC_FSR; - /* Flash Error Status */ - if (fsr & EEFC_FSR_FLERR) { - return -EIO; - } - /* Flash Lock Error Status */ - if (fsr & EEFC_FSR_FLOCKE) { - return -EACCES; - } - /* Flash Command Error */ - if (fsr & EEFC_FSR_FCMDE) { - return -EINVAL; - } + if (eefc_fsr & EEFC_FSR_FCMDE) { + LOG_ERR("Invalid command requested"); + return -EPERM; + } - /* - * ECC error bits are intentionally not checked as they - * might be set outside of the programming code. - */ + if (eefc_fsr & EEFC_FSR_FLOCKE) { + LOG_ERR("Tried to modify locked region"); + return -EPERM; + } - /* Check for timeout */ - if (k_uptime_get() > timeout_time) { - return -ETIMEDOUT; - } - } while (!(fsr & EEFC_FSR_FRDY)); + if (eefc_fsr & EEFC_FSR_FLERR) { + LOG_ERR("Programming failed"); + return -EPERM; + } return 0; } -/* This function writes a single page, either fully or partially. */ -static int flash_sam_write_page(const struct device *dev, off_t offset, - const void *data, size_t len) +static bool sam_flash_section_is_within_area(const struct device *dev, off_t offset, size_t len) { - const struct flash_sam_dev_cfg *config = dev->config; + const struct sam_flash_config *config = dev->config; - Efc * const efc = config->regs; - const uint32_t *src = data; - uint32_t *dst = (uint32_t *)((uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset); + if ((offset + ((off_t)len)) < offset) { + return false; + } - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + if ((offset >= 0) && ((offset + len) <= config->area_size)) { + return true; + } + + LOG_WRN("Section from 0x%x to 0x%x is not within flash area (0x0 to %x)", + (size_t)offset, (size_t)(offset + len), (size_t)config->area_size); + + return false; +} - /* We need to copy the data using 32-bit accesses */ - for (; len > 0; len -= sizeof(*src)) { - *dst++ = *src++; - /* Assure data are written to the latch buffer consecutively */ - barrier_dsync_fence_full(); +static bool sam_flash_section_is_aligned_with_write_block_size(const struct device *dev, + off_t offset, size_t len) +{ + const struct sam_flash_config *config = dev->config; + + if (sam_flash_aligned(offset, config->parameters.write_block_size) && + sam_flash_aligned(len, config->parameters.write_block_size)) { + return true; } - /* Trigger the flash write */ - efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | - EEFC_FCR_FARG(flash_sam_get_page(offset)) | - EEFC_FCR_FCMD_WP; - barrier_dsync_fence_full(); + LOG_WRN("Section from 0x%x to 0x%x is not aligned with write block size (%u)", + (size_t)offset, (size_t)(offset + len), config->parameters.write_block_size); - /* Wait for the flash write to finish */ - return flash_sam_wait_ready(dev); + return false; } -/* Write data to the flash, page by page */ -static int flash_sam_write(const struct device *dev, off_t offset, - const void *data, size_t len) +static bool sam_flash_section_is_aligned_with_pages(const struct device *dev, off_t offset, + size_t len) { - int rc; - const uint8_t *data8 = data; + const struct sam_flash_config *config = dev->config; + struct flash_pages_info pages_info; + + /* Get the page offset points to */ + if (flash_get_page_info_by_offs(dev, offset, &pages_info) < 0) { + return false; + } - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + /* Validate offset points to start of page */ + if (offset != pages_info.start_offset) { + return false; + } - /* Check that the offset is within the flash */ - if (!flash_sam_valid_range(dev, offset, len)) { - return -EINVAL; + /* Check if end of section is aligned with end of area */ + if ((offset + len) == (config->area_size)) { + return true; } - if (!len) { + /* Get the page pointed to by end of section */ + if (flash_get_page_info_by_offs(dev, offset + len, &pages_info) < 0) { + return false; + } + + /* Validate offset points to start of page */ + if ((offset + len) != pages_info.start_offset) { + return false; + } + + return true; +} + +static int sam_flash_read(const struct device *dev, off_t offset, void *data, size_t len) +{ + struct sam_flash_data *sam_data = dev->data; + const struct sam_flash_config *sam_config = dev->config; + k_spinlock_key_t key; + + if (len == 0) { return 0; } - /* - * Check that the offset and length are multiples of the write - * block size. - */ - if ((offset % FLASH_WRITE_BLK_SZ) != 0) { + if (!sam_flash_validate_offset_len(offset, len)) { return -EINVAL; } - if ((len % FLASH_WRITE_BLK_SZ) != 0) { + + if (!sam_flash_section_is_within_area(dev, offset, len)) { return -EINVAL; } - flash_sam_sem_take(dev); + key = k_spin_lock(&sam_data->lock); + memcpy(data, (uint8_t *)(sam_config->area_address + offset), len); + k_spin_unlock(&sam_data->lock, key); + return 0; +} - rc = flash_sam_write_protection(dev, false); - if (rc >= 0) { - rc = flash_sam_wait_ready(dev); - } +static int sam_flash_write_latch_buffer_to_page(const struct device *dev, off_t offset) +{ + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; + uint32_t page = offset / SAM_FLASH_WRITE_PAGE_SIZE; - if (rc >= 0) { - while (len > 0) { - size_t eop_len, write_len; + regs->EEFC_FCR = EEFC_FCR_FCMD_WP | EEFC_FCR_FARG(page) | EEFC_FCR_FKEY_PASSWD; + sam_flash_section_wait_until_ready(dev); + return 0; +} - /* Maximum size without crossing a page */ - eop_len = -(offset | ~(IFLASH_PAGE_SIZE - 1)); - write_len = MIN(len, eop_len); +static int sam_flash_write_latch_buffer_to_previous_page(const struct device *dev, off_t offset) +{ + return sam_flash_write_latch_buffer_to_page(dev, offset - SAM_FLASH_WRITE_PAGE_SIZE); +} - rc = flash_sam_write_page(dev, offset, data8, write_len); - if (rc < 0) { - break; - } +static void sam_flash_write_dword_to_latch_buffer(off_t offset, uint32_t dword) +{ + *((uint32_t *)offset) = dword; + barrier_dsync_fence_full(); +} - offset += write_len; - data8 += write_len; - len -= write_len; +static int sam_flash_write_dwords_to_flash(const struct device *dev, off_t offset, + const uint32_t *dwords, size_t size) +{ + for (size_t i = 0; i < size; i++) { + sam_flash_write_dword_to_latch_buffer(offset, dwords[i]); + offset += sizeof(uint32_t); + if (sam_flash_offset_is_on_write_page_boundary(offset)) { + sam_flash_write_latch_buffer_to_previous_page(dev, offset); } } - int rc2 = flash_sam_write_protection(dev, true); - - if (!rc) { - rc = rc2; + if (!sam_flash_offset_is_on_write_page_boundary(offset)) { + sam_flash_write_latch_buffer_to_page(dev, offset); } - flash_sam_sem_give(dev); - - return rc; + return 0; } -/* Read data from flash */ -static int flash_sam_read(const struct device *dev, off_t offset, void *data, - size_t len) +static int sam_flash_write(const struct device *dev, off_t offset, const void *data, size_t len) { - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + struct sam_flash_data *sam_data = dev->data; + k_spinlock_key_t key; + + if (len == 0) { + return 0; + } - if (!flash_sam_valid_range(dev, offset, len)) { + if (!sam_flash_validate_offset_len(offset, len)) { return -EINVAL; } - memcpy(data, (uint8_t *)CONFIG_FLASH_BASE_ADDRESS + offset, len); + if (!sam_flash_section_is_aligned_with_write_block_size(dev, offset, len)) { + return -EINVAL; + } + + LOG_DBG("Writing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + len)); + + key = k_spin_lock(&sam_data->lock); + if (sam_flash_write_dwords_to_flash(dev, offset, data, len / sizeof(uint32_t)) < 0) { + k_spin_unlock(&sam_data->lock, key); + return -EAGAIN; + } + k_spin_unlock(&sam_data->lock, key); return 0; } -/* Erase a single 8KiB block */ -static int flash_sam_erase_block(const struct device *dev, off_t offset) +static int sam_flash_unlock_write_page(const struct device *dev, uint16_t page_index) { - const struct flash_sam_dev_cfg *config = dev->config; + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; - Efc * const efc = config->regs; + /* Perform unlock command of write page */ + regs->EEFC_FCR = EEFC_FCR_FCMD_CLB + | EEFC_FCR_FARG(page_index) + | EEFC_FCR_FKEY_PASSWD; - LOG_DBG("offset = 0x%lx", (long)offset); - - efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | - EEFC_FCR_FARG(flash_sam_get_page(offset) | 2) | - EEFC_FCR_FCMD_EPA; - barrier_dsync_fence_full(); - - return flash_sam_wait_ready(dev); + return sam_flash_section_wait_until_ready(dev); } -/* Erase multiple blocks */ -static int flash_sam_erase(const struct device *dev, off_t offset, size_t len) +static int sam_flash_unlock_page(const struct device *dev, const struct flash_pages_info *info) { - int rc = 0; - off_t i; + uint16_t page_index_start; + uint16_t page_index_end; + int ret; + + /* Convert from page offset and size to write page index and count */ + page_index_start = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE; + page_index_end = page_index_start + (info->size / SAM_FLASH_WRITE_PAGE_SIZE); + + for (uint16_t i = page_index_start; i < page_index_end; i++) { + ret = sam_flash_unlock_write_page(dev, i); + if (ret < 0) { + return ret; + } + } - LOG_DBG("offset = 0x%lx, len = %zu", (long)offset, len); + return 0; +} - if (!flash_sam_valid_range(dev, offset, len)) { +static int sam_flash_erase_page(const struct device *dev, const struct flash_pages_info *info) +{ + const struct sam_flash_config *sam_config = dev->config; + Efc *regs = sam_config->regs; + uint32_t page_index; + int ret; + + /* Convert from page offset to write page index */ + page_index = info->start_offset / SAM_FLASH_WRITE_PAGE_SIZE; + + LOG_DBG("Erasing page at 0x%x of size 0x%x", (size_t)info->start_offset, info->size); + + /* Perform erase command of page */ + switch (info->size) { + case 0x800: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x1000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 1) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x2000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 2) + | EEFC_FCR_FKEY_PASSWD; + break; + + case 0x4000: + regs->EEFC_FCR = EEFC_FCR_FCMD_EPA + | EEFC_FCR_FARG(page_index | 3) + | EEFC_FCR_FKEY_PASSWD; + break; + + default: return -EINVAL; } - if (!len) { - return 0; + ret = sam_flash_section_wait_until_ready(dev); + if (ret == 0) { + return ret; } - /* - * Check that the offset and length are multiples of the write - * erase block size. - */ - if ((offset % FLASH_ERASE_BLK_SZ) != 0) { - return -EINVAL; + LOG_ERR("Failed to erase page at 0x%x of size 0x%x", (size_t)info->start_offset, + info->size); + + return ret; +} + +static bool sam_flash_erase_foreach_page(const struct flash_pages_info *info, void *data) +{ + struct sam_flash_data *sam_data = data; + const struct device *dev = sam_data->dev; + struct sam_flash_erase_data *erase_data = &sam_data->erase_data; + + /* Validate we reached first page to erase */ + if (info->start_offset < erase_data->section_start) { + /* Next page */ + return true; } - if ((len % FLASH_ERASE_BLK_SZ) != 0) { - return -EINVAL; + + /* Check if we've reached the end of pages to erase */ + if (info->start_offset >= erase_data->section_end) { + /* Succeeded, stop iterating */ + erase_data->succeeded = true; + return false; } - flash_sam_sem_take(dev); + if (sam_flash_unlock_page(dev, info) < 0) { + /* Failed to unlock page, stop iterating */ + return false; + } - rc = flash_sam_write_protection(dev, false); - if (rc >= 0) { - /* Loop through the pages to erase */ - for (i = offset; i < offset + len; i += FLASH_ERASE_BLK_SZ) { - rc = flash_sam_erase_block(dev, i); - if (rc < 0) { - break; - } - } + if (sam_flash_erase_page(dev, info) < 0) { + /* Failed to erase page, stop iterating */ + return false; } - int rc2 = flash_sam_write_protection(dev, true); + /* Next page */ + return true; +} + +static int sam_flash_erase(const struct device *dev, off_t offset, size_t size) +{ + struct sam_flash_data *sam_data = dev->data; + k_spinlock_key_t key; - if (!rc) { - rc = rc2; + if (size == 0) { + return 0; } - flash_sam_sem_give(dev); + if (!sam_flash_validate_offset_len(offset, size)) { + return -EINVAL; + } - /* - * Invalidate the cache addresses corresponding to the erased blocks, - * so that they really appear as erased. - */ -#ifdef __DCACHE_PRESENT - SCB_InvalidateDCache_by_Addr((void *)(CONFIG_FLASH_BASE_ADDRESS + offset), len); -#endif + if (!sam_flash_section_is_aligned_with_pages(dev, offset, size)) { + return -EINVAL; + } - return rc; -} + LOG_DBG("Erasing sector from 0x%x to 0x%x", (size_t)offset, (size_t)(offset + size)); -/* Enable or disable the write protection */ -static int flash_sam_write_protection(const struct device *dev, bool enable) -{ -#if defined(EFC_6450) - const struct flash_sam_dev_cfg *config = dev->config; - Efc *const efc = config->regs; -#endif - int rc = 0; - - if (enable) { - rc = flash_sam_wait_ready(dev); - if (rc < 0) { - goto done; - } -#if defined(EFC_6450) - efc->EEFC_WPMR = EEFC_WPMR_WPKEY_PASSWD | EEFC_WPMR_WPEN; - } else { - efc->EEFC_WPMR = EEFC_WPMR_WPKEY_PASSWD; -#endif + key = k_spin_lock(&sam_data->lock); + sam_data->erase_data.section_start = offset; + sam_data->erase_data.section_end = offset + size; + sam_data->erase_data.succeeded = false; + flash_page_foreach(dev, sam_flash_erase_foreach_page, sam_data); + if (!sam_data->erase_data.succeeded) { + k_spin_unlock(&sam_data->lock, key); + return -EFAULT; } -done: - return rc; + k_spin_unlock(&sam_data->lock, key); + return 0; } -#if CONFIG_FLASH_PAGE_LAYOUT -/* - * The notion of pages is different in Zephyr and in the SAM documentation. - * Here a page refers to the granularity at which the flash can be erased. - */ -static const struct flash_pages_layout flash_sam_pages_layout = { - .pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ, - .pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size), -}; - -void flash_sam_page_layout(const struct device *dev, - const struct flash_pages_layout **layout, - size_t *layout_size) +static const struct flash_parameters *sam_flash_get_parameters(const struct device *dev) { - *layout = &flash_sam_pages_layout; - *layout_size = 1; + const struct sam_flash_config *config = dev->config; + + return &config->parameters; } -#endif -static const struct flash_parameters * -flash_sam_get_parameters(const struct device *dev) +static void sam_flash_api_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) { - ARG_UNUSED(dev); + const struct sam_flash_config *config = dev->config; - return &flash_sam_parameters; + *layout = config->pages_layouts; + *layout_size = config->pages_layouts_size; } -static int flash_sam_init(const struct device *dev) -{ - struct flash_sam_dev_data *const data = dev->data; +static struct flash_driver_api sam_flash_api = { + .read = sam_flash_read, + .write = sam_flash_write, + .erase = sam_flash_erase, + .get_parameters = sam_flash_get_parameters, + .page_layout = sam_flash_api_pages_layout, +}; - k_sem_init(&data->sem, 1, 1); +static int sam_flash_init(const struct device *dev) +{ + struct sam_flash_data *sam_data = dev->data; + const struct sam_flash_config *sam_config = dev->config; + sam_data->dev = dev; + k_sem_init(&sam_data->ready_sem, 0, 1); + sam_flash_mask_ready_interrupt(sam_config); + sam_config->irq_init(); return 0; } -static const struct flash_driver_api flash_sam_api = { - .erase = flash_sam_erase, - .write = flash_sam_write, - .read = flash_sam_read, - .get_parameters = flash_sam_get_parameters, -#ifdef CONFIG_FLASH_PAGE_LAYOUT - .page_layout = flash_sam_page_layout, -#endif -}; - -static const struct flash_sam_dev_cfg flash_sam_cfg = { - .regs = (Efc *)DT_INST_REG_ADDR(0), -}; +#define SAM_FLASH_DEVICE DT_INST(0, atmel_sam_flash) -static struct flash_sam_dev_data flash_sam_data; +#define SAM_FLASH_PAGES_LAYOUT(node_id, prop, idx) \ + { \ + .pages_count = DT_PHA_BY_IDX(node_id, prop, idx, pages_count), \ + .pages_size = DT_PHA_BY_IDX(node_id, prop, idx, pages_size), \ + } -DEVICE_DT_INST_DEFINE(0, flash_sam_init, NULL, - &flash_sam_data, &flash_sam_cfg, - POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, - &flash_sam_api); +#define SAM_FLASH_PAGES_LAYOUTS \ + DT_FOREACH_PROP_ELEM_SEP(SAM_FLASH_DEVICE, erase_blocks, SAM_FLASH_PAGES_LAYOUT, (,)) + +#define SAM_FLASH_CONTROLLER(inst) \ + struct flash_pages_layout sam_flash_pages_layouts##inst[] = { \ + SAM_FLASH_PAGES_LAYOUTS \ + }; \ + \ + static void sam_flash_irq_init_##inst(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), \ + sam_flash_isr, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQN(inst)); \ + \ + } \ + \ + static const struct sam_flash_config sam_flash_config##inst = { \ + .regs = (Efc *)DT_INST_REG_ADDR(inst), \ + .irq_init = sam_flash_irq_init_##inst, \ + .area_address = DT_REG_ADDR(SAM_FLASH_DEVICE), \ + .area_size = DT_REG_SIZE(SAM_FLASH_DEVICE), \ + .parameters = { \ + .write_block_size = DT_PROP(SAM_FLASH_DEVICE, write_block_size), \ + .erase_value = 0xFF, \ + }, \ + .pages_layouts = sam_flash_pages_layouts##inst, \ + .pages_layouts_size = ARRAY_SIZE(sam_flash_pages_layouts##inst), \ + }; \ + \ + static struct sam_flash_data sam_flash_data##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, sam_flash_init, NULL, &sam_flash_data##inst, \ + &sam_flash_config##inst, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, \ + &sam_flash_api); + +SAM_FLASH_CONTROLLER(0) diff --git a/drivers/flash/flash_simulator_native.c b/drivers/flash/flash_simulator_native.c index b31e42c05e0..44eebeba650 100644 --- a/drivers/flash/flash_simulator_native.c +++ b/drivers/flash/flash_simulator_native.c @@ -9,6 +9,12 @@ * native simulator runner/host context, and not in Zephyr/embedded context. */ +#undef _POSIX_C_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _POSIX_C_SOURCE 200809L + #include #include #include diff --git a/drivers/flash/flash_stm32.c b/drivers/flash/flash_stm32.c index 36e3103c56d..2dcf63f3208 100644 --- a/drivers/flash/flash_stm32.c +++ b/drivers/flash/flash_stm32.c @@ -157,7 +157,7 @@ static void flash_stm32_flush_caches(const struct device *dev, regs->ACR |= FLASH_ACR_DCEN; } #elif defined(CONFIG_SOC_SERIES_STM32F7X) - SCB_InvalidateDCache_by_Addr((uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + SCB_InvalidateDCache_by_Addr((uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), len); #endif } @@ -178,7 +178,7 @@ static int flash_stm32_read(const struct device *dev, off_t offset, LOG_DBG("Read offset: %ld, len: %zu", (long int) offset, len); - memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); return 0; } @@ -562,7 +562,8 @@ static int stm32_flash_init(const struct device *dev) flash_stm32_sem_init(dev); - LOG_DBG("Flash initialized. BS: %zu", + LOG_DBG("Flash @0x%x initialized. BS: %zu", + FLASH_STM32_BASE_ADDRESS, flash_stm32_parameters.write_block_size); /* Check Flash configuration */ diff --git a/drivers/flash/flash_stm32.h b/drivers/flash/flash_stm32.h index e0fba89a550..3583a1379c6 100644 --- a/drivers/flash/flash_stm32.h +++ b/drivers/flash/flash_stm32.h @@ -17,6 +17,9 @@ #include #endif +/* Get the base address of the flash from the DTS node */ +#define FLASH_STM32_BASE_ADDRESS DT_REG_ADDR(DT_INST(0, st_stm32_nv_flash)) + struct flash_stm32_priv { FLASH_TypeDef *regs; #if DT_NODE_HAS_PROP(DT_INST(0, st_stm32_flash_controller), clocks) || \ diff --git a/drivers/flash/flash_stm32_ospi.c b/drivers/flash/flash_stm32_ospi.c index eb84564ddea..2f8d1ec3f96 100644 --- a/drivers/flash/flash_stm32_ospi.c +++ b/drivers/flash/flash_stm32_ospi.c @@ -36,6 +36,9 @@ LOG_MODULE_REGISTER(flash_stm32_ospi, CONFIG_FLASH_LOG_LEVEL); (_CONCAT(HAL_OSPIM_, DT_STRING_TOKEN(STM32_OSPI_NODE, prop))), \ ((default_value))) +/* Get the base address of the flash from the DTS node */ +#define STM32_OSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) + #define STM32_OSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) #define STM32_OSPI_DLYB_BYPASSED DT_PROP(STM32_OSPI_NODE, dlyb_bypass) @@ -1048,10 +1051,20 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, break; } } else { - /* Sector erase */ - LOG_DBG("Sector Erase"); - + /* Sector or Block erase depending on the size */ + LOG_INF("Sector/Block Erase"); + + cmd_erase.AddressMode = + (dev_cfg->data_mode == OSPI_OPI_MODE) + ? HAL_OSPI_ADDRESS_8_LINES + : HAL_OSPI_ADDRESS_1_LINE; + cmd_erase.AddressDtrMode = + (dev_cfg->data_rate == OSPI_DTR_TRANSFER) + ? HAL_OSPI_ADDRESS_DTR_ENABLE + : HAL_OSPI_ADDRESS_DTR_DISABLE; + cmd_erase.AddressSize = stm32_ospi_hal_address_size(dev); cmd_erase.Address = addr; + const struct jesd216_erase_type *erase_types = dev_data->erase_types; const struct jesd216_erase_type *bet = NULL; @@ -1063,12 +1076,12 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, if ((etp->exp != 0) && SPI_NOR_IS_ALIGNED(addr, etp->exp) - && SPI_NOR_IS_ALIGNED(size, etp->exp) + && (size >= BIT(etp->exp)) && ((bet == NULL) || (etp->exp > bet->exp))) { bet = etp; cmd_erase.Instruction = bet->cmd; - } else { + } else if (bet == NULL) { /* Use the default sector erase cmd */ if (dev_cfg->data_mode == OSPI_OPI_MODE) { cmd_erase.Instruction = SPI_NOR_OCMD_SE; @@ -1079,22 +1092,15 @@ static int flash_stm32_ospi_erase(const struct device *dev, off_t addr, ? SPI_NOR_CMD_SE_4B : SPI_NOR_CMD_SE; } - cmd_erase.AddressMode = - (dev_cfg->data_mode == OSPI_OPI_MODE) - ? HAL_OSPI_ADDRESS_8_LINES - : HAL_OSPI_ADDRESS_1_LINE; - cmd_erase.AddressDtrMode = - (dev_cfg->data_rate == OSPI_DTR_TRANSFER) - ? HAL_OSPI_ADDRESS_DTR_ENABLE - : HAL_OSPI_ADDRESS_DTR_DISABLE; - cmd_erase.AddressSize = stm32_ospi_hal_address_size(dev); - cmd_erase.Address = addr; /* Avoid using wrong erase type, * if zero entries are found in erase_types */ bet = NULL; } } + LOG_INF("Sector/Block Erase addr 0x%x, asize 0x%x amode 0x%x instr 0x%x", + cmd_erase.Address, cmd_erase.AddressSize, + cmd_erase.AddressMode, cmd_erase.Instruction); ospi_send_cmd(dev, &cmd_erase); @@ -2232,6 +2238,10 @@ static int flash_stm32_ospi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + LOG_INF("NOR octo-flash at 0x%lx (0x%x bytes)", + (long)(STM32_OSPI_BASE_ADDRESS), + dev_cfg->flash_size); + return 0; } @@ -2297,7 +2307,7 @@ static const struct flash_stm32_ospi_config flash_stm32_ospi_cfg = { .enr = DT_CLOCKS_CELL_BY_NAME(STM32_OSPI_NODE, ospi_mgr, bits)}, #endif .irq_config = flash_stm32_ospi_irq_config_func, - .flash_size = DT_INST_PROP(0, size) / 8U, + .flash_size = DT_INST_REG_ADDR_BY_IDX(0, 1), .max_frequency = DT_INST_PROP(0, ospi_max_frequency), .data_mode = DT_INST_PROP(0, spi_bus_width), /* SPI or OPI */ .data_rate = DT_INST_PROP(0, data_rate), /* DTR or STR */ diff --git a/drivers/flash/flash_stm32_qspi.c b/drivers/flash/flash_stm32_qspi.c index 6a9f8a58557..326c1129a36 100644 --- a/drivers/flash/flash_stm32_qspi.c +++ b/drivers/flash/flash_stm32_qspi.c @@ -29,6 +29,9 @@ #define STM32_QSPI_USE_QUAD_IO 0 #endif +/* Get the base address of the flash from the DTS node */ +#define STM32_QSPI_BASE_ADDRESS DT_INST_REG_ADDR(0) + #define STM32_QSPI_RESET_GPIO DT_INST_NODE_HAS_PROP(0, reset_gpios) #define STM32_QSPI_RESET_CMD DT_INST_NODE_HAS_PROP(0, reset_cmd) @@ -1364,6 +1367,10 @@ static int flash_stm32_qspi_init(const struct device *dev) } #endif /* CONFIG_FLASH_PAGE_LAYOUT */ + LOG_INF("NOR quad-flash at 0x%lx (0x%x bytes)", + (long)(STM32_QSPI_BASE_ADDRESS), + dev_cfg->flash_size); + return 0; } @@ -1420,7 +1427,7 @@ static const struct flash_stm32_qspi_config flash_stm32_qspi_cfg = { .bus = DT_CLOCKS_CELL(STM32_QSPI_NODE, bus) }, .irq_config = flash_stm32_qspi_irq_config_func, - .flash_size = DT_INST_PROP(0, size) / 8U, + .flash_size = DT_INST_REG_ADDR_BY_IDX(0, 1), .max_frequency = DT_INST_PROP(0, qspi_max_frequency), .pcfg = PINCTRL_DT_DEV_CONFIG_GET(STM32_QSPI_NODE), #if STM32_QSPI_RESET_GPIO diff --git a/drivers/flash/flash_stm32f1x.c b/drivers/flash/flash_stm32f1x.c index 0c54d3f69fe..9a2c0bb4a90 100644 --- a/drivers/flash/flash_stm32f1x.c +++ b/drivers/flash/flash_stm32f1x.c @@ -62,7 +62,7 @@ static void erase_page_begin(FLASH_TypeDef *regs, unsigned int page) { /* Set the PER bit and select the page you wish to erase */ regs->CR |= FLASH_CR_PER; - regs->AR = CONFIG_FLASH_BASE_ADDRESS + page * FLASH_PAGE_SIZE; + regs->AR = FLASH_STM32_BASE_ADDRESS + page * FLASH_PAGE_SIZE; barrier_dsync_fence_full(); @@ -99,7 +99,7 @@ static void write_disable(FLASH_TypeDef *regs) static void erase_page_begin(FLASH_TypeDef *regs, unsigned int page) { volatile flash_prg_t *page_base = (flash_prg_t *)( - CONFIG_FLASH_BASE_ADDRESS + page * FLASH_PAGE_SIZE); + FLASH_STM32_BASE_ADDRESS + page * FLASH_PAGE_SIZE); /* Enable programming in erase mode. An erase is triggered by * writing 0 to the first word of a page. */ @@ -123,7 +123,7 @@ static int write_value(const struct device *dev, off_t offset, flash_prg_t val) { volatile flash_prg_t *flash = (flash_prg_t *)( - offset + CONFIG_FLASH_BASE_ADDRESS); + offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); int rc; diff --git a/drivers/flash/flash_stm32f2x.c b/drivers/flash/flash_stm32f2x.c index f3781855f57..a525aa8e90f 100644 --- a/drivers/flash/flash_stm32f2x.c +++ b/drivers/flash/flash_stm32f2x.c @@ -76,7 +76,7 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) /* flush the register write */ tmp = regs->CR; - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; /* Wait until the BSY bit is cleared */ rc = flash_stm32_wait_flash_idle(dev); diff --git a/drivers/flash/flash_stm32f4x.c b/drivers/flash/flash_stm32f4x.c index 4261c26a589..cc718be4593 100644 --- a/drivers/flash/flash_stm32f4x.c +++ b/drivers/flash/flash_stm32f4x.c @@ -20,6 +20,22 @@ LOG_MODULE_REGISTER(flash_stm32f4x, CONFIG_FLASH_LOG_LEVEL); +#if FLASH_STM32_WRITE_BLOCK_SIZE == 8 +typedef uint64_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_DOUBLE_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 4 +typedef uint32_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 2 +typedef uint16_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_HALF_WORD +#elif FLASH_STM32_WRITE_BLOCK_SIZE == 1 +typedef uint8_t flash_prg_t; +#define FLASH_PROGRAM_SIZE FLASH_PSIZE_BYTE +#else +#error Write block size must be a power of 2, from 1 to 8 +#endif + bool flash_stm32_valid_range(const struct device *dev, off_t offset, uint32_t len, bool write) @@ -64,7 +80,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) } } -static int write_byte(const struct device *dev, off_t offset, uint8_t val) +static int write_value(const struct device *dev, off_t offset, flash_prg_t val) { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #if defined(FLASH_OPTCR_DB1M) @@ -95,13 +111,13 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) #endif /* FLASH_OPTCR_DB1M */ regs->CR &= CR_PSIZE_MASK; - regs->CR |= FLASH_PSIZE_BYTE; + regs->CR |= FLASH_PROGRAM_SIZE; regs->CR |= FLASH_CR_PG; /* flush the register write */ tmp = regs->CR; - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((flash_prg_t *)(offset + FLASH_STM32_BASE_ADDRESS)) = val; rc = flash_stm32_wait_flash_idle(dev); regs->CR &= (~FLASH_CR_PG); @@ -152,6 +168,9 @@ static int erase_sector(const struct device *dev, uint32_t sector) } #endif + regs->CR &= CR_PSIZE_MASK; + regs->CR |= FLASH_PROGRAM_SIZE; + regs->CR &= ~FLASH_CR_SNB; regs->CR |= FLASH_CR_SER | (sector << 3); regs->CR |= FLASH_CR_STRT; @@ -199,9 +218,11 @@ int flash_stm32_write_range(const struct device *dev, unsigned int offset, const void *data, unsigned int len) { int i, rc = 0; + flash_prg_t value; - for (i = 0; i < len; i++, offset++) { - rc = write_byte(dev, offset, ((const uint8_t *) data)[i]); + for (i = 0; i < len / sizeof(flash_prg_t); i++) { + value = UNALIGNED_GET((flash_prg_t *)data + i); + rc = write_value(dev, offset + i * sizeof(flash_prg_t), value); if (rc < 0) { return rc; } diff --git a/drivers/flash/flash_stm32f7x.c b/drivers/flash/flash_stm32f7x.c index b65bf25a079..324b66d8197 100644 --- a/drivers/flash/flash_stm32f7x.c +++ b/drivers/flash/flash_stm32f7x.c @@ -60,7 +60,7 @@ static int write_byte(const struct device *dev, off_t offset, uint8_t val) barrier_dsync_fence_full(); /* write the data */ - *((uint8_t *) offset + CONFIG_FLASH_BASE_ADDRESS) = val; + *((uint8_t *) offset + FLASH_STM32_BASE_ADDRESS) = val; /* flush the register write */ barrier_dsync_fence_full(); diff --git a/drivers/flash/flash_stm32g0x.c b/drivers/flash/flash_stm32g0x.c index 41a0e1da3bf..5c232dacc64 100644 --- a/drivers/flash/flash_stm32g0x.c +++ b/drivers/flash/flash_stm32g0x.c @@ -56,7 +56,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); uint32_t tmp; int rc; diff --git a/drivers/flash/flash_stm32g4x.c b/drivers/flash/flash_stm32g4x.c index 8f11e21c20e..631268a70c6 100644 --- a/drivers/flash/flash_stm32g4x.c +++ b/drivers/flash/flash_stm32g4x.c @@ -75,7 +75,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #if defined(FLASH_STM32_DBANK) bool dcache_enabled = false; diff --git a/drivers/flash/flash_stm32h7x.c b/drivers/flash/flash_stm32h7x.c index 61394164c1b..271bb413194 100644 --- a/drivers/flash/flash_stm32h7x.c +++ b/drivers/flash/flash_stm32h7x.c @@ -307,7 +307,7 @@ static int write_ndwords(const struct device *dev, uint8_t n) { volatile uint64_t *flash = (uint64_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); int rc; int i; struct flash_stm32_sector_t sector = get_sector(dev, offset); @@ -451,7 +451,7 @@ static void flash_stm32h7_flush_caches(const struct device *dev, return; /* Cache not enabled */ } - SCB_InvalidateDCache_by_Addr((uint32_t *)(CONFIG_FLASH_BASE_ADDRESS + SCB_InvalidateDCache_by_Addr((uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), len); } #endif /* CONFIG_CPU_CORTEX_M7 */ @@ -574,7 +574,7 @@ static int flash_stm32h7_read(const struct device *dev, off_t offset, barrier_dsync_fence_full(); barrier_isync_fence_full(); - memcpy(data, (uint8_t *) CONFIG_FLASH_BASE_ADDRESS + offset, len); + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); __set_FAULTMASK(0); SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk; diff --git a/drivers/flash/flash_stm32l4x.c b/drivers/flash/flash_stm32l4x.c index ead57fb3df4..d9b0fbbcbee 100644 --- a/drivers/flash/flash_stm32l4x.c +++ b/drivers/flash/flash_stm32l4x.c @@ -23,7 +23,7 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #if !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && \ !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx) && \ - !defined(STM32L4Q5xx) + !defined(STM32L4Q5xx) && !defined(STM32L4P5xx) #define STM32L4X_PAGE_SHIFT 11 #else #define STM32L4X_PAGE_SHIFT 12 @@ -69,7 +69,7 @@ static unsigned int get_page(off_t offset) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); #ifdef CONTROL_DCACHE bool dcache_enabled = false; diff --git a/drivers/flash/flash_stm32l5x.c b/drivers/flash/flash_stm32l5x.c index 8ece9b22492..59b649731e9 100644 --- a/drivers/flash/flash_stm32l5x.c +++ b/drivers/flash/flash_stm32l5x.c @@ -26,8 +26,10 @@ LOG_MODULE_REGISTER(LOG_DOMAIN); #elif defined(CONFIG_SOC_SERIES_STM32L5X) #define STM32_SERIES_MAX_FLASH 512 #elif defined(CONFIG_SOC_SERIES_STM32U5X) -/* at this time stm32u5 mcus have 1MB (stm32u575) or 2MB (stm32u585) */ -#define STM32_SERIES_MAX_FLASH 2048 +/* It is used to handle the 2 banks discontinuity case, the discontinuity is not happen on STM32U5, + * so define it to flash size to avoid the unexptected check. + */ +#define STM32_SERIES_MAX_FLASH (CONFIG_FLASH_SIZE) #endif #define PAGES_PER_BANK ((FLASH_SIZE / FLASH_PAGE_SIZE) / 2) @@ -159,7 +161,7 @@ static int write_nwords(const struct device *dev, off_t offset, const uint32_t * { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); volatile uint32_t *flash = (uint32_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); bool full_zero = true; uint32_t tmp; int rc; @@ -397,7 +399,7 @@ void flash_stm32_page_layout(const struct device *dev, if (stm32_flash_has_2_banks(dev) && (CONFIG_FLASH_SIZE < STM32_SERIES_MAX_FLASH)) { /* - * For stm32l552xx with 256 kB flash or stm32u57x with 1MB flash + * For stm32l552xx with 256 kB flash * which have space between banks 1 and 2. */ @@ -417,8 +419,8 @@ void flash_stm32_page_layout(const struct device *dev, stm32_flash_layout_size = ARRAY_SIZE(stm32_flash_layout); } else { /* - * For stm32l562xx & stm32l552xx with 512 flash or stm32u58x - * with 2MB flash which has no space between banks 1 and 2. + * For stm32l562xx & stm32l552xx with 512 flash or stm32u5x, + * which has no space between banks 1 and 2. */ if (stm32_flash_has_2_banks(dev)) { diff --git a/drivers/flash/flash_stm32wba_fm.c b/drivers/flash/flash_stm32wba_fm.c new file mode 100644 index 00000000000..ff42c2643c5 --- /dev/null +++ b/drivers/flash/flash_stm32wba_fm.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define DT_DRV_COMPAT st_stm32wba_flash_controller + +#include +LOG_MODULE_REGISTER(flash_stm32wba, CONFIG_FLASH_LOG_LEVEL); + +#include "flash_stm32.h" +#include "flash_manager.h" +#include "flash_driver.h" + +/* Let's wait for double the max erase time to be sure that the operation is + * completed. + */ +#define STM32_FLASH_TIMEOUT \ + (2 * DT_PROP(DT_INST(0, st_stm32_nv_flash), max_erase_time)) + +extern struct k_work_q ble_ctlr_work_q; +struct k_work fm_work; + +static const struct flash_parameters flash_stm32_parameters = { + .write_block_size = FLASH_STM32_WRITE_BLOCK_SIZE, + .erase_value = 0xff, +}; + +K_SEM_DEFINE(flash_busy, 0, 1); + +static void flash_callback(FM_FlashOp_Status_t status) +{ + LOG_DBG("%d", status); + + k_sem_give(&flash_busy); +} + +struct FM_CallbackNode cb_ptr = { + .Callback = flash_callback +}; + +void FM_ProcessRequest(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &fm_work); +} + +void FM_BackgroundProcess_Entry(struct k_work *work) +{ + ARG_UNUSED(work); + + FM_BackgroundProcess(); +} + +bool flash_stm32_valid_range(const struct device *dev, off_t offset, + uint32_t len, bool write) +{ + if (write && !flash_stm32_valid_write(offset, len)) { + return false; + } + return flash_stm32_range_exists(dev, offset, len); +} + + +static inline void flash_stm32_sem_take(const struct device *dev) +{ + k_sem_take(&FLASH_STM32_PRIV(dev)->sem, K_FOREVER); +} + +static inline void flash_stm32_sem_give(const struct device *dev) +{ + k_sem_give(&FLASH_STM32_PRIV(dev)->sem); +} + +static int flash_stm32_read(const struct device *dev, off_t offset, + void *data, + size_t len) +{ + if (!flash_stm32_valid_range(dev, offset, len, false)) { + LOG_ERR("Read range invalid. Offset: %p, len: %zu", + (void *) offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + memcpy(data, (uint8_t *) FLASH_STM32_BASE_ADDRESS + offset, len); + + flash_stm32_sem_give(dev); + + return 0; +} + +static int flash_stm32_erase(const struct device *dev, off_t offset, + size_t len) +{ + int rc; + int sect_num = (len / FLASH_PAGE_SIZE) + 1; + + if (!flash_stm32_valid_range(dev, offset, len, true)) { + LOG_ERR("Erase range invalid. Offset: %p, len: %zu", + (void *)offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + LOG_DBG("Erase offset: %p, page: %ld, len: %zu, sect num: %d", + (void *)offset, offset / FLASH_PAGE_SIZE, len, sect_num); + + rc = FM_Erase(offset / FLASH_PAGE_SIZE, sect_num, &cb_ptr); + if (rc == 0) { + k_sem_take(&flash_busy, K_FOREVER); + } else { + LOG_DBG("Erase operation rejected. err = %d", rc); + } + + flash_stm32_sem_give(dev); + + return rc; +} + +static int flash_stm32_write(const struct device *dev, off_t offset, + const void *data, size_t len) +{ + int rc; + + if (!flash_stm32_valid_range(dev, offset, len, true)) { + LOG_ERR("Write range invalid. Offset: %p, len: %zu", + (void *)offset, len); + return -EINVAL; + } + + if (!len) { + return 0; + } + + flash_stm32_sem_take(dev); + + LOG_DBG("Write offset: %p, len: %zu", (void *)offset, len); + + rc = FM_Write((uint32_t *)data, + (uint32_t *)(FLASH_STM32_BASE_ADDRESS + offset), + (int32_t)len/4, &cb_ptr); + if (rc == 0) { + k_sem_take(&flash_busy, K_FOREVER); + } else { + LOG_DBG("Write operation rejected. err = %d", rc); + } + + flash_stm32_sem_give(dev); + + return rc; +} + +static const struct flash_parameters * + flash_stm32_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_stm32_parameters; +} + +static struct flash_stm32_priv flash_data = { + .regs = (FLASH_TypeDef *) DT_INST_REG_ADDR(0), +}; + +void flash_stm32wba_page_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + static struct flash_pages_layout stm32wba_flash_layout = { + .pages_count = 0, + .pages_size = 0, + }; + + ARG_UNUSED(dev); + + if (stm32wba_flash_layout.pages_count == 0) { + stm32wba_flash_layout.pages_count = FLASH_SIZE / FLASH_PAGE_SIZE; + stm32wba_flash_layout.pages_size = FLASH_PAGE_SIZE; + } + + *layout = &stm32wba_flash_layout; + *layout_size = 1; +} + +static const struct flash_driver_api flash_stm32_api = { + .erase = flash_stm32_erase, + .write = flash_stm32_write, + .read = flash_stm32_read, + .get_parameters = flash_stm32_get_parameters, +#ifdef CONFIG_FLASH_PAGE_LAYOUT + .page_layout = flash_stm32wba_page_layout, +#endif +}; + +static int stm32_flash_init(const struct device *dev) +{ + k_sem_init(&FLASH_STM32_PRIV(dev)->sem, 1, 1); + + LOG_DBG("Flash initialized. BS: %zu", + flash_stm32_parameters.write_block_size); + + k_work_init(&fm_work, &FM_BackgroundProcess_Entry); + + /* Enable flash driver system flag */ + FD_SetStatus(FD_FLASHACCESS_RFTS, LL_FLASH_DISABLE); + FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_ENABLE); + FD_SetStatus(FD_FLASHACCESS_SYSTEM, LL_FLASH_ENABLE); + +#if ((CONFIG_FLASH_LOG_LEVEL >= LOG_LEVEL_DBG) && CONFIG_FLASH_PAGE_LAYOUT) + const struct flash_pages_layout *layout; + size_t layout_size; + + flash_stm32wba_page_layout(dev, &layout, &layout_size); + for (size_t i = 0; i < layout_size; i++) { + LOG_DBG("Block %zu: bs: %zu count: %zu", i, + layout[i].pages_size, layout[i].pages_count); + } +#endif + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, stm32_flash_init, NULL, + &flash_data, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &flash_stm32_api); diff --git a/drivers/flash/flash_stm32wbax.c b/drivers/flash/flash_stm32wbax.c index 0796b9a5be4..db158f71a9a 100644 --- a/drivers/flash/flash_stm32wbax.c +++ b/drivers/flash/flash_stm32wbax.c @@ -109,7 +109,7 @@ static int write_qword(const struct device *dev, off_t offset, const uint32_t *b { FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); volatile uint32_t *flash = (uint32_t *)(offset - + CONFIG_FLASH_BASE_ADDRESS); + + FLASH_STM32_BASE_ADDRESS); uint32_t tmp; int rc; diff --git a/drivers/flash/flash_stm32wbx.c b/drivers/flash/flash_stm32wbx.c index e72fddf756f..293d9c5a54e 100644 --- a/drivers/flash/flash_stm32wbx.c +++ b/drivers/flash/flash_stm32wbx.c @@ -60,7 +60,7 @@ static inline void flush_cache(FLASH_TypeDef *regs) static int write_dword(const struct device *dev, off_t offset, uint64_t val) { - volatile uint32_t *flash = (uint32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS); + volatile uint32_t *flash = (uint32_t *)(offset + FLASH_STM32_BASE_ADDRESS); FLASH_TypeDef *regs = FLASH_STM32_REGS(dev); uint32_t tmp; int ret, rc; diff --git a/drivers/flash/nrf_qspi_nor.c b/drivers/flash/nrf_qspi_nor.c index 0e9d4181418..c0e8c397d8e 100644 --- a/drivers/flash/nrf_qspi_nor.c +++ b/drivers/flash/nrf_qspi_nor.c @@ -1386,6 +1386,7 @@ static const struct qspi_nor_config qspi_nor_dev_config = { .sck_delay = DT_INST_PROP(0, sck_delay), .spi_mode = INST_0_SPI_MODE, }, + .nrfx_cfg.timeout = CONFIG_NORDIC_QSPI_NOR_TIMEOUT_MS, .size = INST_0_BYTES, .id = DT_INST_PROP(0, jedec_id), diff --git a/drivers/flash/spi_nor.c b/drivers/flash/spi_nor.c index ea23d11eb95..065795d4924 100644 --- a/drivers/flash/spi_nor.c +++ b/drivers/flash/spi_nor.c @@ -186,6 +186,13 @@ static const struct jesd216_erase_type minimal_erase_types[JESD216_NUM_ERASE_TYP }; #endif /* CONFIG_SPI_NOR_SFDP_MINIMAL */ +/* Register writes should be ready extremely quickly */ +#define WAIT_READY_REGISTER K_NO_WAIT +/* Page writes range from sub-ms to 10ms */ +#define WAIT_READY_WRITE K_TICKS(1) +/* Erases can range from 45ms to 240sec */ +#define WAIT_READY_ERASE K_MSEC(50) + static int spi_nor_write_protection_set(const struct device *dev, bool write_protect); @@ -395,17 +402,27 @@ static int spi_nor_access(const struct device *const dev, * in the code. * * @param dev The device structure + * @param poll_delay Duration between polls of status register * @return 0 on success, negative errno code otherwise */ -static int spi_nor_wait_until_ready(const struct device *dev) +static int spi_nor_wait_until_ready(const struct device *dev, k_timeout_t poll_delay) { int ret; uint8_t reg; - do { - ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg)); - } while (!ret && (reg & SPI_NOR_WIP_BIT)); + ARG_UNUSED(poll_delay); + while (true) { + ret = spi_nor_cmd_read(dev, SPI_NOR_CMD_RDSR, ®, sizeof(reg)); + /* Exit on error or no longer WIP */ + if (ret || !(reg & SPI_NOR_WIP_BIT)) { + break; + } +#ifdef CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY + /* Don't monopolise the CPU while waiting for ready */ + k_sleep(poll_delay); +#endif /* CONFIG_SPI_NOR_SLEEP_WHILE_WAITING_UNTIL_READY */ + } return ret; } @@ -558,7 +575,7 @@ static int spi_nor_wrsr(const struct device *dev, if (ret == 0) { ret = spi_nor_access(dev, SPI_NOR_CMD_WRSR, NOR_ACCESS_WRITE, 0, &sr, sizeof(sr)); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } return ret; @@ -626,7 +643,7 @@ static int mxicy_wrcr(const struct device *dev, ret = spi_nor_access(dev, SPI_NOR_CMD_WRSR, NOR_ACCESS_WRITE, 0, data, sizeof(data)); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } return ret; @@ -659,6 +676,7 @@ static int mxicy_configure(const struct device *dev, const uint8_t *jedec_id) ret = mxicy_rdcr(dev); if (ret < 0) { + release_device(dev); return ret; } current_cr = ret; @@ -771,7 +789,7 @@ static int spi_nor_write(const struct device *dev, off_t addr, src = (const uint8_t *)src + to_write; addr += to_write; - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_WRITE); } } @@ -853,7 +871,7 @@ static int spi_nor_erase(const struct device *dev, off_t addr, size_t size) */ volatile int xcc_ret = #endif - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_ERASE); } int ret2 = spi_nor_write_protection_set(dev, true); @@ -1231,13 +1249,14 @@ static int spi_nor_configure(const struct device *dev) rc = exit_dpd(dev); if (rc < 0) { LOG_ERR("Failed to exit DPD (%d)", rc); + release_device(dev); return -ENODEV; } rc = spi_nor_rdsr(dev); if (rc > 0 && (rc & SPI_NOR_WIP_BIT)) { LOG_WRN("Waiting until flash is ready"); - spi_nor_wait_until_ready(dev); + spi_nor_wait_until_ready(dev, WAIT_READY_REGISTER); } release_device(dev); @@ -1280,12 +1299,12 @@ static int spi_nor_configure(const struct device *dev) rc = spi_nor_wrsr(dev, rc & ~cfg->has_lock); } + release_device(dev); + if (rc != 0) { LOG_ERR("BP clear failed: %d\n", rc); return -ENODEV; } - - release_device(dev); } #ifdef CONFIG_SPI_NOR_SFDP_MINIMAL @@ -1359,6 +1378,16 @@ static int spi_nor_pm_control(const struct device *dev, enum pm_device_action ac case PM_DEVICE_ACTION_TURN_ON: /* Coming out of power off */ rc = spi_nor_configure(dev); +#ifndef CONFIG_SPI_NOR_IDLE_IN_DPD + if (rc == 0) { + /* Move to DPD, the correct device state + * for PM_DEVICE_STATE_SUSPENDED + */ + acquire_device(dev); + rc = enter_dpd(dev); + release_device(dev); + } +#endif /* CONFIG_SPI_NOR_IDLE_IN_DPD */ break; case PM_DEVICE_ACTION_TURN_OFF: break; diff --git a/drivers/fpga/CMakeLists.txt b/drivers/fpga/CMakeLists.txt index 3db822ad0d0..e7a16193c4c 100644 --- a/drivers/fpga/CMakeLists.txt +++ b/drivers/fpga/CMakeLists.txt @@ -6,4 +6,5 @@ zephyr_library_sources_ifdef(CONFIG_FPGA_SHELL fpga_shell.c) zephyr_library_sources_ifdef(CONFIG_EOS_S3_FPGA fpga_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_ICE40_FPGA fpga_ice40.c) +zephyr_library_sources_ifdef(CONFIG_MPFS_FPGA fpga_mpfs.c) zephyr_library_sources_ifdef(CONFIG_ZYNQMP_FPGA fpga_zynqmp.c) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index a9573137be1..6041a164f18 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -28,6 +28,7 @@ config FPGA_SHELL source "drivers/fpga/Kconfig.eos_s3" source "drivers/fpga/Kconfig.ice40" +source "drivers/fpga/Kconfig.mpfs" source "drivers/fpga/Kconfig.zynqmp" endif # FPGA diff --git a/drivers/fpga/Kconfig.mpfs b/drivers/fpga/Kconfig.mpfs new file mode 100644 index 00000000000..197921015ed --- /dev/null +++ b/drivers/fpga/Kconfig.mpfs @@ -0,0 +1,10 @@ +# FPGA Microchip PolarFire SOC driver configuration options + +# Copyright (c) 2023 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MPFS_FPGA + bool "Microchip PolarFire SOC FPGA driver" + depends on SPI + help + Enable support for the Microchip PolarFire SOC FPGA driver. diff --git a/drivers/fpga/fpga_mpfs.c b/drivers/fpga/fpga_mpfs.c new file mode 100644 index 00000000000..d8c777a4501 --- /dev/null +++ b/drivers/fpga/fpga_mpfs.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2024 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mpfs_mailbox +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(fpga_mpfs); + +#define SPI_FLASH_DIRECTORY_OFFSET 0x00000000 +#define SPI_FLASH_GOLDEN_IMAGE_OFFSET 0x00100400 +#define SPI_FLASH_NEW_IMAGE_OFFSET 0x01500400 +#define SPI_FLASH_SECTOR_SIZE 4096 +#define SPI_FLASH_PAGE_SIZE 256 + +#define SERVICES_CR_OFFSET 0x50u +#define SERVICES_SR_OFFSET 0x54u + +#define SCBCTRL_SERVICESCR_REQ (0u) +#define SCBCTRL_SERVICESCR_REQ_MASK BIT(SCBCTRL_SERVICESCR_REQ) + +#define SCBCTRL_SERVICESSR_BUSY (1u) +#define SCBCTRL_SERVICESSR_BUSY_MASK BIT(SCBCTRL_SERVICESSR_BUSY) + +#define SCBCTRL_SERVICESSR_STATUS (16u) +#define SCBCTRL_SERVICESSR_STATUS_MASK_WIDTH (16u) +#define SCBCTRL_SERVICESSR_STATUS_MASK \ + GENMASK(SCBCTRL_SERVICESSR_STATUS + SCBCTRL_SERVICESSR_STATUS_MASK_WIDTH - 1, \ + SCBCTRL_SERVICESSR_STATUS) + +#define MSS_DESIGN_INFO_CMD (0x02) +#define MSS_SYS_BITSTREAM_AUTHENTICATE_CMD 0x23u +#define MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD 0x42u + +struct mpfs_fpga_config { + mm_reg_t base; + mm_reg_t mailbox; +}; + +struct mpfs_fpga_data { + char FPGA_design_ver[30]; +}; + +static inline uint32_t scb_read(mm_reg_t add, mm_reg_t offset) +{ + return sys_read32(add + offset); +} + +static inline void scb_write(mm_reg_t add, mm_reg_t offset, uint32_t val) +{ + return sys_write32(val, add + offset); +} + +/*This function add the index of new image into the spi directory at offset 0x004. + * Note: In the Flash directory first four pages(each page of 256 Bytes) have either + * a valid image address or zeros. The other remaining 12 pages are all filled with 0xFFs. + * + * |------------------------------| 0x000 + * | Golden Image Address: | + * | 0x0100400 | + * |------------------------------| 0x004 + * | Update Image Address | + * | 0x1500400 | + * |------------------------------| 0x008 + * | Empty | + * | 0x000000 | + * |------------------------------| 0x00C + * | Unused for re-programming | + * | | + * |------------------------------| 0x400 + */ +static uint8_t update_spi_flash_directory(const struct device *flash_dev) +{ + size_t len = SPI_FLASH_PAGE_SIZE; + uint8_t buf[SPI_FLASH_PAGE_SIZE]; + uint8_t rc, k; + + memset(buf, 0, len); + + rc = flash_read(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, buf, len); + if (rc != 0) { + LOG_ERR("Flash read failed! %d", rc); + return rc; + } + + /* New image address(0x1500400) entry at offset 0x004 */ + buf[4] = 0x00; + buf[5] = 0x04; + buf[6] = 0x50; + buf[7] = 0x01; + + /* Erase SPI flash directory */ + + rc = flash_erase(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, SPI_FLASH_SECTOR_SIZE); + if (rc != 0) { + LOG_ERR("erase failed! %d", rc); + } + + /* Write the first page with updated address entry */ + rc = flash_write(flash_dev, SPI_FLASH_DIRECTORY_OFFSET, buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + + /* Fill page number second, third and fourth with zeros */ + memset(buf, 0, len); + k = 1; + while (k < 4) { + rc = flash_write(flash_dev, (SPI_FLASH_DIRECTORY_OFFSET + k * 0x100), buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + k++; + } + + return rc; +} + +/* This function Program a new FPGA design image into the SPI Flash at location + * 0x1500400. + * Note: The source location of new image is _bin_start symbol value and the size of + * new image is _bim_size symbol value. + */ +static uint8_t program_new_image(const struct device *flash_dev, uint8_t *image_start, + uint32_t image_size) +{ + size_t len = SPI_FLASH_PAGE_SIZE; + uint8_t buf[SPI_FLASH_PAGE_SIZE]; + uint8_t rc; + uint32_t i, count, k; + uint8_t *temp; + + temp = image_start; + + if (image_size > 0x1400000) { + LOG_ERR("Image is larger than 20Mb"); + return 1; + } + + /* Find the sectors to erase */ + count = (uint32_t)(image_size / SPI_FLASH_SECTOR_SIZE) + 1; + + LOG_INF("Erasing."); + i = 0; + while (i < count) { + rc = flash_erase( + flash_dev, + ((SPI_FLASH_NEW_IMAGE_OFFSET - 0x400) + (i * SPI_FLASH_SECTOR_SIZE)), + SPI_FLASH_SECTOR_SIZE); + if (rc != 0) { + LOG_ERR("erase failed! %d", rc); + } + + if (i % 0x100 == 0) { + LOG_DBG("."); + } + + i++; + } + /* Erase completed and ready to program new image */ + + /* Find the pages to program */ + count = (uint32_t)(image_size / SPI_FLASH_PAGE_SIZE) + 1; + + LOG_INF("Programming."); + i = 0; + while (i < count) { + temp = (image_start + i * SPI_FLASH_PAGE_SIZE); + memset(buf, 0, len); + for (k = 0; k < 256; k++) { + buf[k] = *temp; + temp = temp + 1; + } + + rc = flash_write(flash_dev, (SPI_FLASH_NEW_IMAGE_OFFSET + i * SPI_FLASH_PAGE_SIZE), + buf, len); + if (rc != 0) { + LOG_ERR("Flash write failed! %d", rc); + return rc; + } + + if (i % 0x100 == 0) { + LOG_DBG("."); + } + + i++; + } + + LOG_INF("Programming completed."); + + return rc; +} + +static int8_t verify_image(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + int8_t status = EINVAL; + uint32_t value = 0; + + LOG_INF("Image verification started..."); + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + scb_write(cfg->mailbox, 0, 0x1500400); + + value = (MSS_SYS_BITSTREAM_AUTHENTICATE_CMD << 16) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Read the status returned by System Controller */ + status = ((scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_STATUS_MASK) >> + SCBCTRL_SERVICESSR_STATUS); + LOG_INF("Image verification status : %x ", status); + + return status; +} + +static void activate_image(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + int8_t status = EINVAL; + uint32_t value = 0; + + LOG_INF("Image activation started..."); + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + value = (MSS_SYS_IAP_PROGRAM_BY_SPIIDX_CMD << 16) | BIT(23) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Read the status returned by System Controller */ + status = ((scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_STATUS_MASK) >> + SCBCTRL_SERVICESSR_STATUS); + LOG_INF("Image activation status : %x ", status); +} + +static int mpfs_fpga_reset(const struct device *dev) +{ + int8_t status = EINVAL; + + status = verify_image(dev); + if (status == 0) { + activate_image(dev); + } + return 0; +} + +static int mpfs_fpga_load(const struct device *dev, uint32_t *image_ptr, uint32_t img_size) +{ + const struct device *flash_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(bitstream_flash)); + + if (flash_dev == NULL) { + LOG_ERR("Device not found"); + return -ENOENT; + } + + if (!device_is_ready(flash_dev)) { + LOG_ERR("%s: device not ready.", flash_dev->name); + return 1; + } + + if (img_size == 0) { + LOG_ERR("Image size is zero."); + return -EINVAL; + } + + if (image_ptr == NULL) { + LOG_ERR("Failed to read FPGA image"); + return -EINVAL; + } + + update_spi_flash_directory(flash_dev); + program_new_image(flash_dev, (uint8_t *)image_ptr, img_size); + return 0; +} + +static const char *mpfs_fpga_get_info(const struct device *dev) +{ + struct mpfs_fpga_data *data = dev->data; + const struct mpfs_fpga_config *cfg = dev->config; + uint32_t value = 0; + uint16_t design_version = 0; + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + /* Form the SS command: bit 0 to 6 is the opcode, bit 7 to 15 is the Mailbox + * offset For some services this field has another meaning. + * (e.g. for IAP bit-stream auth. it means spi_idx) + */ + + value = (MSS_DESIGN_INFO_CMD << 16) | 0x1; + scb_write(cfg->base, SERVICES_CR_OFFSET, value); + + /* REQ bit will remain set till the system controller starts + * processing command. Since DRI is slow interface, we are waiting + * here to make sure System controller has started processing + * command + */ + while (scb_read(cfg->base, SERVICES_CR_OFFSET) & SCBCTRL_SERVICESCR_REQ_MASK) { + ; + } + + /* Once system controller starts processing command The busy bit will + * go 1. Make sure that service is complete i.e. BUSY bit is gone 0 + */ + while (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + ; + } + + design_version = scb_read(cfg->mailbox, 32); + sprintf(data->FPGA_design_ver, (uint8_t *)"Design Version : 0x%x", design_version); + + return data->FPGA_design_ver; +} + +static enum FPGA_status mpfs_fpga_get_status(const struct device *dev) +{ + const struct mpfs_fpga_config *cfg = dev->config; + + if (scb_read(cfg->base, SERVICES_SR_OFFSET) & SCBCTRL_SERVICESSR_BUSY_MASK) { + return FPGA_STATUS_INACTIVE; + } else { + return FPGA_STATUS_ACTIVE; + } +} + +static int mpfs_fpga_init(const struct device *dev) +{ + return 0; +} + +static struct mpfs_fpga_data fpga_data; + +static struct mpfs_fpga_config fpga_config = { + .base = DT_INST_REG_ADDR_BY_IDX(0, 0), + .mailbox = DT_INST_REG_ADDR_BY_IDX(0, 2), +}; + +static const struct fpga_driver_api mpfs_fpga_api = { + .reset = mpfs_fpga_reset, + .load = mpfs_fpga_load, + .get_info = mpfs_fpga_get_info, + .get_status = mpfs_fpga_get_status, +}; + +DEVICE_DT_INST_DEFINE(0, &mpfs_fpga_init, NULL, &fpga_data, &fpga_config, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &mpfs_fpga_api); diff --git a/drivers/fpga/fpga_zynqmp.c b/drivers/fpga/fpga_zynqmp.c index 8da54462fae..8181edf5c75 100644 --- a/drivers/fpga/fpga_zynqmp.c +++ b/drivers/fpga/fpga_zynqmp.c @@ -293,7 +293,7 @@ static int zynqmp_fpga_load(const struct device *dev, uint32_t *image_ptr, } for (int i = 0; i < (img_size / 4); i++) { - *(BITSTREAM + i) = __bswap_32(*(addr + i)); + *(BITSTREAM + i) = BSWAP_32(*(addr + i)); } init_pcap(dev); diff --git a/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c b/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c index 4c9ba6702aa..79537d2f509 100644 --- a/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c +++ b/drivers/fuel_gauge/sbs_gauge/sbs_gauge.c @@ -311,12 +311,12 @@ static const struct fuel_gauge_driver_api sbs_gauge_driver_api = { /* Conditionally defined battery config based on battery cutoff support */ #define SBS_GAUGE_CONFIG_DEFINE(index) \ - COND_CODE_1(DT_INST_PROP_OR(index, battery_cutoff_support, false), \ + COND_CODE_1(DT_INST_PROP(index, battery_cutoff_support), \ (_SBS_GAUGE_CONFIG_DEFINE(index)), (;)) /* Conditionally get the battery config variable name or NULL based on battery cutoff support */ #define SBS_GAUGE_GET_BATTERY_CONFIG_NAME(index) \ - COND_CODE_1(DT_INST_PROP_OR(index, battery_cutoff_support, false), \ + COND_CODE_1(DT_INST_PROP(index, battery_cutoff_support), \ (&_SBS_GAUGE_BATT_CUTOFF_CFG_VAR_NAME(index)), (NULL)) #define SBS_GAUGE_INIT(index) \ diff --git a/drivers/gnss/CMakeLists.txt b/drivers/gnss/CMakeLists.txt index 6c24df4903e..cfa5c6ed210 100644 --- a/drivers/gnss/CMakeLists.txt +++ b/drivers/gnss/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_GNSS_DUMP gnss_dump.c) zephyr_library_sources_ifdef(CONFIG_GNSS_PARSE gnss_parse.c) zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183 gnss_nmea0183.c) zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183_MATCH gnss_nmea0183_match.c) +zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA_GENERIC gnss_nmea_generic.c) zephyr_library_sources_ifdef(CONFIG_GNSS_QUECTEL_LCX6G gnss_quectel_lcx6g.c) diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig index 5bdc0f530d8..2ff552940a3 100644 --- a/drivers/gnss/Kconfig +++ b/drivers/gnss/Kconfig @@ -64,6 +64,7 @@ module = GNSS module-str = gnss source "subsys/logging/Kconfig.template.log_config" +rsource "Kconfig.generic" rsource "Kconfig.quectel_lcx6g" endif diff --git a/drivers/gnss/Kconfig.generic b/drivers/gnss/Kconfig.generic new file mode 100644 index 00000000000..47fbd4a7c6c --- /dev/null +++ b/drivers/gnss/Kconfig.generic @@ -0,0 +1,26 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config GNSS_NMEA_GENERIC + bool "Generic GNSS NMEA device" + default y + depends on GNSS + depends on DT_HAS_GNSS_NMEA_GENERIC_ENABLED + select MODEM_MODULES + select MODEM_BACKEND_UART + select MODEM_CHAT + select GNSS_PARSE + select GNSS_NMEA0183 + select GNSS_NMEA0183_MATCH + help + Generic NMEA based GNSS device. + +config GNSS_NMEA_GENERIC_SATELLITES_COUNT + int "Maximum satellite count" + depends on GNSS_SATELLITES + default 24 + help + Maximum number of satellite that the driver that can be decoded from + the GNSS device. This does not affect the number of devices that the + device is actually tracking, just how many of those can be reported + in the satellites callback. diff --git a/drivers/gnss/Kconfig.quectel_lcx6g b/drivers/gnss/Kconfig.quectel_lcx6g index 6736015aed7..3036f76d05b 100644 --- a/drivers/gnss/Kconfig.quectel_lcx6g +++ b/drivers/gnss/Kconfig.quectel_lcx6g @@ -15,3 +15,23 @@ config GNSS_QUECTEL_LCX6G select GNSS_NMEA0183_MATCH help Enable quectel LCX6G series GNSS modem driver. + +if GNSS_QUECTEL_LCX6G + +config GNSS_QUECTEL_LCX6G_UART_RX_BUF_SIZE + int "Size of UART backend receive buffer" + default 256 + +config GNSS_QUECTEL_LCX6G_UART_TX_BUF_SIZE + int "Size of UART backend transmit buffer" + default 64 + +if GNSS_SATELLITES + +config GNSS_QUECTEL_LCX6G_SAT_ARRAY_SIZE + int "Size of GNSS satellites array" + default 24 + +endif # GNSS_SATELLITES + +endif # GNSS_QUECTEL_LCX6G diff --git a/drivers/gnss/gnss_dump.c b/drivers/gnss/gnss_dump.c index 1946d65ea2e..f87b64a4946 100644 --- a/drivers/gnss/gnss_dump.c +++ b/drivers/gnss/gnss_dump.c @@ -5,6 +5,7 @@ */ #include "gnss_dump.h" +#include #include #include @@ -94,20 +95,22 @@ int gnss_dump_info(char *str, uint16_t strsize, const struct gnss_info *info) int gnss_dump_nav_data(char *str, uint16_t strsize, const struct navigation_data *nav_data) { int ret; - int32_t altitude_int; - int32_t altitude_fraction; - const char *fmt = "navigation_data: {latitude: %lli.%lli, longitude : %lli.%lli, " - "bearing %u.%u, speed %u.%u, altitude: %i.%i}"; - - altitude_int = nav_data->altitude / 1000; - altitude_fraction = nav_data->altitude % 1000; - altitude_fraction = (altitude_fraction < 0) ? -altitude_fraction : altitude_fraction; - - ret = snprintk(str, strsize, fmt, nav_data->latitude / 1000000000, - nav_data->latitude % 1000000000, nav_data->longitude / 1000000000, - nav_data->longitude % 1000000000, nav_data->bearing / 1000, - nav_data->bearing % 1000, nav_data->speed / 1000, nav_data->speed % 1000, - altitude_int, altitude_fraction); + const char *fmt = "navigation_data: {latitude: %s%lli.%09lli, longitude : %s%lli.%09lli, " + "bearing %u.%03u, speed %u.%03u, altitude: %s%i.%03i}"; + char *lat_sign = nav_data->latitude < 0 ? "-" : ""; + char *lon_sign = nav_data->longitude < 0 ? "-" : ""; + char *alt_sign = nav_data->altitude < 0 ? "-" : ""; + + ret = snprintk(str, strsize, fmt, + lat_sign, + llabs(nav_data->latitude) / 1000000000, + llabs(nav_data->latitude) % 1000000000, + lon_sign, + llabs(nav_data->longitude) / 1000000000, + llabs(nav_data->longitude) % 1000000000, + nav_data->bearing / 1000, nav_data->bearing % 1000, + nav_data->speed / 1000, nav_data->speed % 1000, + alt_sign, abs(nav_data->altitude) / 1000, abs(nav_data->altitude) % 1000); return (strsize < ret) ? -ENOMEM : 0; } diff --git a/drivers/gnss/gnss_nmea0183_match.c b/drivers/gnss/gnss_nmea0183_match.c index 3fe3b159fdb..cd82c552ee4 100644 --- a/drivers/gnss/gnss_nmea0183_match.c +++ b/drivers/gnss/gnss_nmea0183_match.c @@ -4,22 +4,28 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include +#include "gnss_parse.h" #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" -#include "gnss_publish.h" -static bool gnss_nmea0183_match_timed_out(struct gnss_nmea0183_match_data *data) +static int gnss_nmea0183_match_parse_utc(char **argv, uint16_t argc, uint32_t *utc) { - int64_t delta; + int64_t i64; - delta = k_uptime_delta(&data->timestamp); - data->timestamp = k_uptime_get(); - return ((uint16_t)delta) > data->timeout_ms; + if ((gnss_parse_dec_to_milli(argv[1], &i64) < 0) || + (i64 < 0) || + (i64 > UINT32_MAX)) { + return -EINVAL; + } + + *utc = (uint32_t)i64; + return 0; } #if CONFIG_GNSS_SATELLITES @@ -30,10 +36,15 @@ static void gnss_nmea0183_match_reset_gsv(struct gnss_nmea0183_match_data *data) } #endif -static void gnss_nmea0183_match_reset(struct gnss_nmea0183_match_data *data) +static void gnss_nmea0183_match_publish(struct gnss_nmea0183_match_data *data) { - data->gga_received = false; - data->rmc_received = false; + if ((data->gga_utc == 0) || (data->rmc_utc == 0)) { + return; + } + + if (data->gga_utc == data->rmc_utc) { + gnss_publish_data(data->gnss, &data->data); + } } void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint16_t argc, @@ -41,19 +52,15 @@ void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint { struct gnss_nmea0183_match_data *data = user_data; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_gga((const char **)argv, argc, &data->data) < 0) { return; } - data->gga_received = true; - - if (data->gga_received && data->rmc_received) { - gnss_publish_data(data->gnss, &data->data); + if (gnss_nmea0183_match_parse_utc(argv, argc, &data->gga_utc) < 0) { + return; } + + gnss_nmea0183_match_publish(data); } void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint16_t argc, @@ -61,19 +68,15 @@ void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint { struct gnss_nmea0183_match_data *data = user_data; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_rmc((const char **)argv, argc, &data->data) < 0) { return; } - data->rmc_received = true; - - if (data->gga_received && data->rmc_received) { - gnss_publish_data(data->gnss, &data->data); + if (gnss_nmea0183_match_parse_utc(argv, argc, &data->rmc_utc) < 0) { + return; } + + gnss_nmea0183_match_publish(data); } #if CONFIG_GNSS_SATELLITES @@ -84,10 +87,6 @@ void gnss_nmea0183_match_gsv_callback(struct modem_chat *chat, char **argv, uint struct gnss_nmea0183_gsv_header header; int ret; - if (gnss_nmea0183_match_timed_out(data)) { - gnss_nmea0183_match_reset(data); - } - if (gnss_nmea0183_parse_gsv_header((const char **)argv, argc, &header) < 0) { return; } @@ -124,7 +123,7 @@ int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data, const struct gnss_nmea0183_match_config *config) { __ASSERT(data != NULL, "data argument must be provided"); - __ASSERT(config != NULL, "data argument must be provided"); + __ASSERT(config != NULL, "config argument must be provided"); memset(data, 0, sizeof(struct gnss_nmea0183_match_data)); data->gnss = config->gnss; @@ -132,6 +131,5 @@ int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data, data->satellites = config->satellites; data->satellites_size = config->satellites_size; #endif - data->timeout_ms = config->timeout_ms; return 0; } diff --git a/drivers/gnss/gnss_nmea0183_match.h b/drivers/gnss/gnss_nmea0183_match.h index 65104e1dc8a..28ed395320b 100644 --- a/drivers/gnss/gnss_nmea0183_match.h +++ b/drivers/gnss/gnss_nmea0183_match.h @@ -49,11 +49,9 @@ struct gnss_nmea0183_match_data { uint16_t satellites_size; uint16_t satellites_length; #endif - int64_t timestamp; - uint16_t timeout_ms; - uint8_t gga_received : 1; - uint8_t rmc_received : 1; - uint8_t gsv_message_number : 6; + uint32_t gga_utc; + uint32_t rmc_utc; + uint8_t gsv_message_number; }; /** GNSS NMEA0183 match configuration structure */ @@ -66,8 +64,6 @@ struct gnss_nmea0183_match_config { /** Number of elements in buffer for parsed satellites */ uint16_t satellites_size; #endif - /** The maximum time from the first to the last NMEA0183 message of a fix */ - uint16_t timeout_ms; }; /** diff --git a/drivers/gnss/gnss_nmea_generic.c b/drivers/gnss/gnss_nmea_generic.c new file mode 100644 index 00000000000..2f23f4d7353 --- /dev/null +++ b/drivers/gnss/gnss_nmea_generic.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2023 Trackunit Corporation + * Copyright (c) 2023 Bjarki Arge Andreasen + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gnss_nmea0183.h" +#include "gnss_nmea0183_match.h" +#include "gnss_parse.h" + +#include +LOG_MODULE_REGISTER(gnss_nmea_generic, CONFIG_GNSS_LOG_LEVEL); + +#define DT_DRV_COMPAT gnss_nmea_generic + +#define UART_RECV_BUF_SZ 128 +#define CHAT_RECV_BUF_SZ 256 +#define CHAT_ARGV_SZ 32 + +struct gnss_nmea_generic_config { + const struct device *uart; +}; + +struct gnss_nmea_generic_data { + struct gnss_nmea0183_match_data match_data; +#if CONFIG_GNSS_SATELLITES + struct gnss_satellite satellites[CONFIG_GNSS_NMEA_GENERIC_SATELLITES_COUNT]; +#endif + + /* UART backend */ + struct modem_pipe *uart_pipe; + struct modem_backend_uart uart_backend; + uint8_t uart_backend_receive_buf[UART_RECV_BUF_SZ]; + + /* Modem chat */ + struct modem_chat chat; + uint8_t chat_receive_buf[CHAT_RECV_BUF_SZ]; + uint8_t *chat_argv[CHAT_ARGV_SZ]; + + struct k_spinlock lock; +}; + +MODEM_CHAT_MATCHES_DEFINE(unsol_matches, + MODEM_CHAT_MATCH_WILDCARD("$??GGA,", ",*", gnss_nmea0183_match_gga_callback), + MODEM_CHAT_MATCH_WILDCARD("$??RMC,", ",*", gnss_nmea0183_match_rmc_callback), +#if CONFIG_GNSS_SATELLITES + MODEM_CHAT_MATCH_WILDCARD("$??GSV,", ",*", gnss_nmea0183_match_gsv_callback), +#endif +); + +static int gnss_nmea_generic_resume(const struct device *dev) +{ + struct gnss_nmea_generic_data *data = dev->data; + int ret; + + ret = modem_pipe_open(data->uart_pipe); + if (ret < 0) { + return ret; + } + + ret = modem_chat_attach(&data->chat, data->uart_pipe); + if (ret < 0) { + modem_pipe_close(data->uart_pipe); + return ret; + } + + return ret; +} + +static struct gnss_driver_api gnss_api = { +}; + +static int gnss_nmea_generic_init_nmea0183_match(const struct device *dev) +{ + struct gnss_nmea_generic_data *data = dev->data; + + const struct gnss_nmea0183_match_config match_config = { + .gnss = dev, +#if CONFIG_GNSS_SATELLITES + .satellites = data->satellites, + .satellites_size = ARRAY_SIZE(data->satellites), +#endif + }; + + return gnss_nmea0183_match_init(&data->match_data, &match_config); +} + +static void gnss_nmea_generic_init_pipe(const struct device *dev) +{ + const struct gnss_nmea_generic_config *cfg = dev->config; + struct gnss_nmea_generic_data *data = dev->data; + + const struct modem_backend_uart_config uart_backend_config = { + .uart = cfg->uart, + .receive_buf = data->uart_backend_receive_buf, + .receive_buf_size = sizeof(data->uart_backend_receive_buf), + }; + + data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config); +} + +static uint8_t gnss_nmea_generic_char_delimiter[] = {'\r', '\n'}; + +static int gnss_nmea_generic_init_chat(const struct device *dev) +{ + struct gnss_nmea_generic_data *data = dev->data; + + const struct modem_chat_config chat_config = { + .user_data = data, + .receive_buf = data->chat_receive_buf, + .receive_buf_size = sizeof(data->chat_receive_buf), + .delimiter = gnss_nmea_generic_char_delimiter, + .delimiter_size = ARRAY_SIZE(gnss_nmea_generic_char_delimiter), + .filter = NULL, + .filter_size = 0, + .argv = data->chat_argv, + .argv_size = ARRAY_SIZE(data->chat_argv), + .unsol_matches = unsol_matches, + .unsol_matches_size = ARRAY_SIZE(unsol_matches), + }; + + return modem_chat_init(&data->chat, &chat_config); +} + +static int gnss_nmea_generic_init(const struct device *dev) +{ + int ret; + + ret = gnss_nmea_generic_init_nmea0183_match(dev); + if (ret < 0) { + return ret; + } + + gnss_nmea_generic_init_pipe(dev); + + ret = gnss_nmea_generic_init_chat(dev); + if (ret < 0) { + return ret; + } + + ret = gnss_nmea_generic_resume(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +#define GNSS_NMEA_GENERIC(inst) \ + static struct gnss_nmea_generic_config gnss_nmea_generic_cfg_##inst = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + }; \ + \ + static struct gnss_nmea_generic_data gnss_nmea_generic_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_init, NULL, \ + &gnss_nmea_generic_data_##inst, \ + &gnss_nmea_generic_cfg_##inst, \ + POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api); + +DT_INST_FOREACH_STATUS_OKAY(GNSS_NMEA_GENERIC) diff --git a/drivers/gnss/gnss_publish.c b/drivers/gnss/gnss_publish.c index 98e3a2e5e19..7ddfa5e09fe 100644 --- a/drivers/gnss/gnss_publish.c +++ b/drivers/gnss/gnss_publish.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "gnss_publish.h" +#include #include #include diff --git a/drivers/gnss/gnss_quectel_lcx6g.c b/drivers/gnss/gnss_quectel_lcx6g.c index 0ca7f5203ac..09fa8fd8e4a 100644 --- a/drivers/gnss/gnss_quectel_lcx6g.c +++ b/drivers/gnss/gnss_quectel_lcx6g.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -14,7 +15,6 @@ #include #include -#include "gnss_publish.h" #include "gnss_nmea0183.h" #include "gnss_nmea0183_match.h" #include "gnss_parse.h" @@ -22,20 +22,18 @@ #include LOG_MODULE_REGISTER(quectel_lcx6g, CONFIG_GNSS_LOG_LEVEL); -#define QUECTEL_LCX6G_STARTUP_DELAY (K_MSEC(300U)) -#define QUECTEL_LCX6G_STATE_CHANGE_DELAY_MSEC (300LL) -#define QUECTEL_LCX6G_PAIR_TIMEOUT (K_SECONDS(11)) -#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S (10U) +#define QUECTEL_LCX6G_PM_TIMEOUT_MS 500U +#define QUECTEL_LCX6G_SCRIPT_TIMEOUT_S 10U -#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY (4) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS (1) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL (0) -#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE (5) +#define QUECTEL_LCX6G_PAIR_NAV_MODE_STATIONARY 4 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_FITNESS 1 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_NORMAL 0 +#define QUECTEL_LCX6G_PAIR_NAV_MODE_DRONE 5 -#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED (0) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED (4) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK (1) -#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED (2) +#define QUECTEL_LCX6G_PAIR_PPS_MODE_DISABLED 0 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED 4 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_AFTER_LOCK 1 +#define QUECTEL_LCX6G_PAIR_PPS_MODE_ENABLED_WHILE_LOCKED 2 struct quectel_lcx6g_config { const struct device *uart; @@ -46,14 +44,14 @@ struct quectel_lcx6g_config { struct quectel_lcx6g_data { struct gnss_nmea0183_match_data match_data; #if CONFIG_GNSS_SATELLITES - struct gnss_satellite satellites[24]; + struct gnss_satellite satellites[CONFIG_GNSS_QUECTEL_LCX6G_SAT_ARRAY_SIZE]; #endif /* UART backend */ struct modem_pipe *uart_pipe; struct modem_backend_uart uart_backend; - uint8_t uart_backend_receive_buf[128]; - uint8_t uart_backend_transmit_buf[64]; + uint8_t uart_backend_receive_buf[CONFIG_GNSS_QUECTEL_LCX6G_UART_RX_BUF_SIZE]; + uint8_t uart_backend_transmit_buf[CONFIG_GNSS_QUECTEL_LCX6G_UART_TX_BUF_SIZE]; /* Modem chat */ struct modem_chat chat; @@ -77,6 +75,7 @@ struct quectel_lcx6g_data { }; struct k_spinlock lock; + k_timeout_t pm_timeout; }; #define MODEM_CHAT_SCRIPT_NO_ABORT_DEFINE(_sym, _script_chats, _callback, _timeout) \ @@ -173,35 +172,60 @@ static int quectel_lcx6g_configure_pps(const struct device *dev) return modem_chat_run_script(&data->chat, &data->dynamic_script); } +static void quectel_lcx6g_pm_changed(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + uint32_t pm_ready_at_ms; + + pm_ready_at_ms = k_uptime_get() + QUECTEL_LCX6G_PM_TIMEOUT_MS; + data->pm_timeout = K_TIMEOUT_ABS_MS(pm_ready_at_ms); +} + +static void quectel_lcx6g_await_pm_ready(const struct device *dev) +{ + struct quectel_lcx6g_data *data = dev->data; + + LOG_INF("Waiting until PM ready"); + k_sleep(data->pm_timeout); +} + static int quectel_lcx6g_resume(const struct device *dev) { struct quectel_lcx6g_data *data = dev->data; int ret; + LOG_INF("Resuming"); + + quectel_lcx6g_await_pm_ready(dev); + ret = modem_pipe_open(data->uart_pipe); if (ret < 0) { + LOG_ERR("Failed to open pipe"); return ret; } ret = modem_chat_attach(&data->chat, data->uart_pipe); if (ret < 0) { + LOG_ERR("Failed to attach chat"); modem_pipe_close(data->uart_pipe); return ret; } ret = modem_chat_run_script(&data->chat, &resume_script); if (ret < 0) { + LOG_ERR("Failed to initialize GNSS"); modem_pipe_close(data->uart_pipe); return ret; } - k_msleep(1000); - ret = quectel_lcx6g_configure_pps(dev); if (ret < 0) { + LOG_ERR("Failed to configure PPS"); modem_pipe_close(data->uart_pipe); + return ret; } + LOG_INF("Resumed"); return ret; } @@ -211,18 +235,32 @@ static int quectel_lcx6g_suspend(const struct device *dev) struct quectel_lcx6g_data *data = dev->data; int ret; - ret = modem_chat_run_script_run(&data->chat, &suspend_script); + LOG_INF("Suspending"); + + quectel_lcx6g_await_pm_ready(dev); + + ret = modem_chat_run_script(&data->chat, &suspend_script); if (ret < 0) { - modem_pipe_close(data->uart_pipe); + LOG_ERR("Failed to suspend GNSS"); + } else { + LOG_INF("Suspended"); } + modem_pipe_close(data->uart_pipe); return ret; } +static void quectel_lcx6g_turn_on(const struct device *dev) +{ + LOG_INF("Powered on"); +} + static int quectel_lcx6g_turn_off(const struct device *dev) { struct quectel_lcx6g_data *data = dev->data; + LOG_INF("Powered off"); + return modem_pipe_close(data->uart_pipe); } @@ -244,6 +282,7 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti break; case PM_DEVICE_ACTION_TURN_ON: + quectel_lcx6g_turn_on(dev); ret = 0; break; @@ -255,6 +294,8 @@ static int quectel_lcx6g_pm_action(const struct device *dev, enum pm_device_acti break; } + quectel_lcx6g_pm_changed(dev); + k_spin_unlock(&data->lock, key); return ret; } @@ -649,7 +690,6 @@ static int quectel_lcx6g_init_nmea0183_match(const struct device *dev) .satellites = data->satellites, .satellites_size = ARRAY_SIZE(data->satellites), #endif - .timeout_ms = 50, }; return gnss_nmea0183_match_init(&data->match_data, &config); @@ -687,7 +727,6 @@ static int quectel_lcx6g_init_chat(const struct device *dev) .argv_size = ARRAY_SIZE(data->chat_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; return modem_chat_init(&data->chat, &chat_config); @@ -721,7 +760,6 @@ static int quectel_lcx6g_init(const struct device *dev) { int ret; - LOG_INF("Initializing Quectel LCX6G"); ret = quectel_lcx6g_init_nmea0183_match(dev); if (ret < 0) { return ret; @@ -736,18 +774,19 @@ static int quectel_lcx6g_init(const struct device *dev) quectel_lcx6g_init_dynamic_script(dev); -#ifdef CONFIG_PM_DEVICE_RUNTIME - pm_device_init_suspended(dev); -#else - LOG_INF("Resuming Quectel LCX6G"); - ret = quectel_lcx6g_resume(dev); - if (ret < 0) { - LOG_ERR("Failed to resume Quectel LCX6G"); - return ret; + quectel_lcx6g_pm_changed(dev); + + if (pm_device_is_powered(dev)) { + ret = quectel_lcx6g_resume(dev); + if (ret < 0) { + return ret; + } + quectel_lcx6g_pm_changed(dev); + } else { + pm_device_init_off(dev); } -#endif - LOG_INF("Quectel LCX6G initialized"); - return 0; + + return pm_device_runtime_enable(dev); } #define LCX6G_INST_NAME(inst, name) \ diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index b1cd06978bb..3e4ae12dc4a 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_MCP230XX gpio_mcp230xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX gpio_mcux.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_IGPIO gpio_mcux_igpio.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_RGPIO gpio_mcux_rgpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_LPC gpio_mcux_lpc.c) zephyr_library_sources_ifdef(CONFIG_GPIO_MMIO32 gpio_mmio32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XEC gpio_mchp_xec.c) @@ -56,7 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SNPS_CREG gpio_creg_gpio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_STMPE1600 gpio_stmpe1600.c) zephyr_library_sources_ifdef(CONFIG_GPIO_XEC_V2 gpio_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCA953X gpio_pca953x.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_PCF8574 gpio_pcf8574.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_PCF857X gpio_pcf857x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_FXL6408 gpio_fxl6408.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ANDES_ATCGPIO100 gpio_andes_atcgpio100.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NEORV32 gpio_neorv32.c) @@ -87,8 +88,9 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ALTERA_PIO gpio_altera_pio.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_RA gpio_ra.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RENESAS_RA gpio_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_AMBIQ gpio_ambiq.c) if (CONFIG_GPIO_EMUL_SDL) zephyr_library_sources(gpio_emul_sdl.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c49e2aa1167..ff9d02704d8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -105,6 +105,8 @@ source "drivers/gpio/Kconfig.mcux" source "drivers/gpio/Kconfig.mcux_igpio" +source "drivers/gpio/Kconfig.mcux_rgpio" + source "drivers/gpio/Kconfig.mcux_lpc" source "drivers/gpio/Kconfig.mmio32" @@ -179,7 +181,7 @@ source "drivers/gpio/Kconfig.stmpe1600" source "drivers/gpio/Kconfig.pca953x" -source "drivers/gpio/Kconfig.pcf8574" +source "drivers/gpio/Kconfig.pcf857x" source "drivers/gpio/Kconfig.fxl6408" @@ -232,8 +234,10 @@ source "drivers/gpio/Kconfig.altera" source "drivers/gpio/Kconfig.bcm2711" -source "drivers/gpio/Kconfig.ra" +source "drivers/gpio/Kconfig.renesas_ra" source "drivers/gpio/Kconfig.rzt2m" +source "drivers/gpio/Kconfig.ambiq" + endif # GPIO diff --git a/drivers/gpio/Kconfig.ambiq b/drivers/gpio/Kconfig.ambiq new file mode 100644 index 00000000000..924028e6f27 --- /dev/null +++ b/drivers/gpio/Kconfig.ambiq @@ -0,0 +1,14 @@ +# Ambiq SDK GPIO +# +# Copyright (c) 2023 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +config GPIO_AMBIQ + bool "AMBIQ GPIO driver" + default y + depends on DT_HAS_AMBIQ_GPIO_ENABLED + select AMBIQ_HAL + help + Enable driver for Ambiq gpio. diff --git a/drivers/gpio/Kconfig.mcux_rgpio b/drivers/gpio/Kconfig.mcux_rgpio new file mode 100644 index 00000000000..6446137542a --- /dev/null +++ b/drivers/gpio/Kconfig.mcux_rgpio @@ -0,0 +1,12 @@ +# MCUX RGPIO configuration options + +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_MCUX_RGPIO + bool "MCUX RGPIO driver" + default y + depends on DT_HAS_NXP_IMX_RGPIO_ENABLED + select PINCTRL + help + Enable the MCUX RGPIO driver. diff --git a/drivers/gpio/Kconfig.nrfx b/drivers/gpio/Kconfig.nrfx index 356c43cb5fa..760a45204fd 100644 --- a/drivers/gpio/Kconfig.nrfx +++ b/drivers/gpio/Kconfig.nrfx @@ -5,7 +5,12 @@ menuconfig GPIO_NRFX bool "nRF GPIO driver" default y depends on DT_HAS_NORDIC_NRF_GPIO_ENABLED - select NRFX_GPIOTE + select NRFX_GPIOTE0 if HAS_HW_NRF_GPIOTE0 + select NRFX_GPIOTE1 if HAS_HW_NRF_GPIOTE1 + select NRFX_GPIOTE20 if HAS_HW_NRF_GPIOTE20 + select NRFX_GPIOTE30 if HAS_HW_NRF_GPIOTE30 + select NRFX_GPIOTE130 if HAS_HW_NRF_GPIOTE130 + select NRFX_GPIOTE131 if HAS_HW_NRF_GPIOTE131 help Enable GPIO driver for nRF line of MCUs. diff --git a/drivers/gpio/Kconfig.pcf8574 b/drivers/gpio/Kconfig.pcf8574 deleted file mode 100644 index 0c35008aa64..00000000000 --- a/drivers/gpio/Kconfig.pcf8574 +++ /dev/null @@ -1,19 +0,0 @@ -# PCF8574 GPIO configuration options - -# Copyright (c) 2022 Ithinx -# SPDX-License-Identifier: Apache-2.0 - -menuconfig GPIO_PCF8574 - bool "PCF8574 I2C GPIO chip" - default y - depends on DT_HAS_NXP_PCF8574_ENABLED - select I2C - help - Enable driver for PCF8574 I2C GPIO chip. - -config GPIO_PCF8574_INIT_PRIORITY - int "Init priority" - default 70 - depends on GPIO_PCF8574 - help - Device driver initialization priority. diff --git a/drivers/gpio/Kconfig.pcf857x b/drivers/gpio/Kconfig.pcf857x new file mode 100644 index 00000000000..2617d8a76a1 --- /dev/null +++ b/drivers/gpio/Kconfig.pcf857x @@ -0,0 +1,21 @@ +# PCF857x GPIO configuration options + +# Copyright (c) 2022 Ithinx +# Copyright (c) 2023 Mr Beam Lasers GmbH +# Copyright (c) 2023 Amrith Venkat Kesavamoorthi +# SPDX-License-Identifier: Apache-2.0 + +menuconfig GPIO_PCF857X + bool "PCF857X I2C GPIO chip" + default y + depends on DT_HAS_NXP_PCF857X_ENABLED + select I2C + help + Enable driver for PCF857X I2C GPIO chip. + +config GPIO_PCF857X_INIT_PRIORITY + int "Init priority" + default 70 + depends on GPIO_PCF857X + help + Device driver initialization priority. diff --git a/drivers/gpio/Kconfig.ra b/drivers/gpio/Kconfig.ra deleted file mode 100644 index 391a32f293d..00000000000 --- a/drivers/gpio/Kconfig.ra +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2023 TOKITA Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -config GPIO_RA - bool "Renesas RA Series GPIO driver" - default y - select GPIO_GET_CONFIG - depends on DT_HAS_RENESAS_RA_GPIO_ENABLED - help - Enable Renesas RA series GPIO driver. diff --git a/drivers/gpio/Kconfig.renesas_ra b/drivers/gpio/Kconfig.renesas_ra new file mode 100644 index 00000000000..bd6f536ee80 --- /dev/null +++ b/drivers/gpio/Kconfig.renesas_ra @@ -0,0 +1,10 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_RENESAS_RA + bool "Renesas RA Series GPIO driver" + default y + select GPIO_GET_CONFIG + depends on DT_HAS_RENESAS_RA_GPIO_ENABLED + help + Enable Renesas RA series GPIO driver. diff --git a/drivers/gpio/gpio_ambiq.c b/drivers/gpio/gpio_ambiq.c new file mode 100644 index 00000000000..b036094e683 --- /dev/null +++ b/drivers/gpio/gpio_ambiq.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2023 Antmicro + * Copyright (c) 2023 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_gpio_bank + +#include +#include +#include +#include +#include +#include + +#include + +typedef void (*ambiq_gpio_cfg_func_t)(void); + +struct ambiq_gpio_config { + struct gpio_driver_config common; + uint32_t base; + uint32_t offset; + uint32_t irq_num; + ambiq_gpio_cfg_func_t cfg_func; + uint8_t ngpios; +}; + +struct ambiq_gpio_data { + struct gpio_driver_data common; + sys_slist_t cb; + struct k_spinlock lock; +}; + +static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + pin += (dev_cfg->offset >> 2); + + am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default; + + if (flags & GPIO_INPUT) { + pincfg = am_hal_gpio_pincfg_input; + if (flags & GPIO_PULL_UP) { + pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLUP_50K; + } else if (flags & GPIO_PULL_DOWN) { + pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLDOWN_50K; + } + } + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_SINGLE_ENDED) { + if (flags & GPIO_LINE_OPEN_DRAIN) { + pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN; + } + } else { + pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL; + } + } + if (flags & GPIO_DISCONNECTED) { + pincfg = am_hal_gpio_pincfg_disabled; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH; + am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_SET); + + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW; + am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_CLEAR); + } + + am_hal_gpio_pinconfig(pin, pincfg); + + return 0; +} + +#ifdef CONFIG_GPIO_GET_CONFIG +static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *out_flags) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + am_hal_gpio_pincfg_t pincfg; + + pin += (dev_cfg->offset >> 2); + + am_hal_gpio_pinconfig_get(pin, &pincfg); + + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_DISABLE && + pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_NONE) { + *out_flags = GPIO_DISCONNECTED; + } + if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { + *out_flags = GPIO_INPUT; + if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLUP_50K) { + *out_flags |= GPIO_PULL_UP; + } else if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLDOWN_50K) { + *out_flags |= GPIO_PULL_DOWN; + } + } + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) { + *out_flags = GPIO_OUTPUT | GPIO_PUSH_PULL; + if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + *out_flags = GPIO_OUTPUT | GPIO_OPEN_DRAIN; + if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) { + *out_flags |= GPIO_OUTPUT_HIGH; + } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) { + *out_flags |= GPIO_OUTPUT_LOW; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_GPIO_GET_DIRECTION +static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pins_t map, + gpio_port_pins_t *inputs, gpio_port_pins_t *outputs) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + am_hal_gpio_pincfg_t pincfg; + gpio_port_pins_t ip = 0; + gpio_port_pins_t op = 0; + uint32_t pin_offset = dev_cfg->offset >> 2; + + if (inputs != NULL) { + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((map >> i) & 1) { + am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg); + if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) { + ip |= BIT(i); + } + } + } + *inputs = ip; + } + if (outputs != NULL) { + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((map >> i) & 1) { + am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg); + if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL || + pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) { + op |= BIT(i); + } + } + } + *outputs = op; + } + + return 0; +} +#endif + +static int ambiq_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + *value = (*AM_HAL_GPIO_RDn(dev_cfg->offset >> 2)); + + return 0; +} + +static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((mask >> i) & 1) { + am_hal_gpio_state_write(i + pin_offset, ((value >> i) & 1)); + } + } + + return 0; +} + +static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_SET); + } + } + + return 0; +} + +static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_CLEAR); + } + } + + return 0; +} + +static int ambiq_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + uint32_t pin_offset = dev_cfg->offset >> 2; + + for (int i = 0; i < dev_cfg->ngpios; i++) { + if ((pins >> i) & 1) { + am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_TOGGLE); + } + } + + return 0; +} + +static void ambiq_gpio_isr(const struct device *dev) +{ + struct ambiq_gpio_data *const data = dev->data; + const struct ambiq_gpio_config *const dev_cfg = dev->config; + + uint32_t int_status; + + am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + + gpio_fire_callbacks(&data->cb, dev, int_status); +} + +static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct ambiq_gpio_config *const dev_cfg = dev->config; + struct ambiq_gpio_data *const data = dev->data; + + am_hal_gpio_pincfg_t pincfg; + int gpio_pin = pin + (dev_cfg->offset >> 2); + uint32_t int_status; + int ret; + + ret = am_hal_gpio_pinconfig_get(gpio_pin, &pincfg); + + if (mode == GPIO_INT_MODE_DISABLED) { + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_NONE; + ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0, + AM_HAL_GPIO_INT_CTRL_INDV_DISABLE, + (void *)&gpio_pin); + k_spin_unlock(&data->lock, key); + + } else { + if (mode == GPIO_INT_MODE_LEVEL) { + return -ENOTSUP; + } + switch (trig) { + case GPIO_INT_TRIG_LOW: + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO; + break; + case GPIO_INT_TRIG_HIGH: + pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI; + break; + case GPIO_INT_TRIG_BOTH: + /* + * GPIO_INT_TRIG_BOTH is not supported on Ambiq Apollo4 Plus Platform + * ERR008: GPIO: Dual-edge interrupts are not vectoring + */ + return -ENOTSUP; + } + ret = am_hal_gpio_pinconfig(gpio_pin, pincfg); + + irq_enable(dev_cfg->irq_num); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status); + ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status); + ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0, + AM_HAL_GPIO_INT_CTRL_INDV_ENABLE, + (void *)&gpio_pin); + k_spin_unlock(&data->lock, key); + } + return ret; +} + +static int ambiq_gpio_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct ambiq_gpio_data *const data = dev->data; + + return gpio_manage_callback(&data->cb, callback, set); +} + +static int ambiq_gpio_init(const struct device *port) +{ + const struct ambiq_gpio_config *const dev_cfg = port->config; + + NVIC_ClearPendingIRQ(dev_cfg->irq_num); + + dev_cfg->cfg_func(); + + return 0; +} + +static const struct gpio_driver_api ambiq_gpio_drv_api = { + .pin_configure = ambiq_gpio_pin_configure, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = ambiq_gpio_get_config, +#endif + .port_get_raw = ambiq_gpio_port_get_raw, + .port_set_masked_raw = ambiq_gpio_port_set_masked_raw, + .port_set_bits_raw = ambiq_gpio_port_set_bits_raw, + .port_clear_bits_raw = ambiq_gpio_port_clear_bits_raw, + .port_toggle_bits = ambiq_gpio_port_toggle_bits, + .pin_interrupt_configure = ambiq_gpio_pin_interrupt_configure, + .manage_callback = ambiq_gpio_manage_callback, +#ifdef CONFIG_GPIO_GET_DIRECTION + .port_get_direction = ambiq_gpio_port_get_direction, +#endif +}; + +#define AMBIQ_GPIO_DEFINE(n) \ + static struct ambiq_gpio_data ambiq_gpio_data_##n; \ + static void ambiq_gpio_cfg_func_##n(void); \ + \ + static const struct ambiq_gpio_config ambiq_gpio_config_##n = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .base = DT_REG_ADDR(DT_INST_PARENT(n)), \ + .offset = DT_INST_REG_ADDR(n), \ + .ngpios = DT_INST_PROP(n, ngpios), \ + .irq_num = DT_INST_IRQN(n), \ + .cfg_func = ambiq_gpio_cfg_func_##n}; \ + static void ambiq_gpio_cfg_func_##n(void) \ + { \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), ambiq_gpio_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + return; \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &ambiq_gpio_init, NULL, &ambiq_gpio_data_##n, \ + &ambiq_gpio_config_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &ambiq_gpio_drv_api); + +DT_INST_FOREACH_STATUS_OKAY(AMBIQ_GPIO_DEFINE) diff --git a/drivers/gpio/gpio_andes_atcgpio100.c b/drivers/gpio/gpio_andes_atcgpio100.c index 4b5d18fc0a7..f7c8bdfc4da 100644 --- a/drivers/gpio/gpio_andes_atcgpio100.c +++ b/drivers/gpio/gpio_andes_atcgpio100.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio_b91.c b/drivers/gpio/gpio_b91.c index bc73f9db9f5..4c4c14dc909 100644 --- a/drivers/gpio/gpio_b91.c +++ b/drivers/gpio/gpio_b91.c @@ -10,6 +10,7 @@ #include #include #include +#include /* Driver dts compatibility: telink,b91_gpio */ diff --git a/drivers/gpio/gpio_bd8lb600fs.c b/drivers/gpio/gpio_bd8lb600fs.c index 30ae851d90b..ad49e4a7768 100644 --- a/drivers/gpio/gpio_bd8lb600fs.c +++ b/drivers/gpio/gpio_bd8lb600fs.c @@ -30,40 +30,61 @@ struct bd8lb600fs_config { struct spi_dt_spec bus; const struct gpio_dt_spec gpio_reset; + int gpios_count; }; struct bd8lb600fs_drv_data { /* gpio_driver_data needs to be first */ struct gpio_driver_data data; - uint8_t state; /* each bit is one output channel, bit 0 = channel 1, ... */ - uint8_t configured; /* each bit defines if the output channel is configured, see state */ + uint32_t state; /* each bit is one output channel, bit 0 = channel 1, ... */ + uint32_t configured; /* each bit defines if the output channel is configured, see state */ struct k_mutex lock; + int instance_count_actual; + int gpios_count_actual; }; -static int write_state(const struct bd8lb600fs_config *config, uint8_t state) +static int write_state(const struct device *dev, uint32_t state) { - LOG_DBG("writing state 0x%02X to BD8LB600FS", state); + const struct bd8lb600fs_config *config = dev->config; + struct bd8lb600fs_drv_data *drv_data = dev->data; + + LOG_DBG("%s: writing state 0x%08X to BD8LB600FS", dev->name, state); uint16_t state_converted = 0; - uint8_t buffer_tx[2]; - const struct spi_buf tx_buf[] = {{ + uint8_t buffer_tx[8]; + const struct spi_buf tx_buf = { .buf = buffer_tx, - .len = ARRAY_SIZE(buffer_tx), - }}; + .len = drv_data->instance_count_actual * sizeof(state_converted), + }; const struct spi_buf_set tx = { - .buffers = tx_buf, - .count = ARRAY_SIZE(tx_buf), + .buffers = &tx_buf, + .count = 1, }; - for (size_t i = 0; i < 8; ++i) { - if ((state & BIT(i)) == 0) { - state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2); - } else { - state_converted |= OUTPUT_ON << (i * 2); + memset(buffer_tx, 0x00, sizeof(buffer_tx)); + + for (size_t j = 0; j < drv_data->instance_count_actual; ++j) { + int instance_position = (drv_data->instance_count_actual - j - 1) * 2; + + state_converted = 0; + + for (size_t i = 0; i < 8; ++i) { + if ((state & BIT(i + j*8)) == 0) { + state_converted |= OUTPUT_OFF_WITH_OPEN_LOAD_DETECTION << (i * 2); + } else { + state_converted |= OUTPUT_ON << (i * 2); + } } + + LOG_DBG("%s: configuration for instance %zu: %04X (position %i)", + dev->name, + j, + state_converted, + instance_position); + sys_put_be16(state_converted, buffer_tx + instance_position); } - sys_put_be16(state_converted, buffer_tx); + LOG_HEXDUMP_DBG(buffer_tx, ARRAY_SIZE(buffer_tx), "configuration written out"); int result = spi_write_dt(&config->bus, &tx); @@ -77,7 +98,6 @@ static int write_state(const struct bd8lb600fs_config *config, uint8_t state) static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -85,8 +105,8 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp return -EWOULDBLOCK; } - if (pin > 7) { - LOG_ERR("invalid pin nummber %i", pin); + if (pin >= drv_data->gpios_count_actual) { + LOG_ERR("invalid pin number %i", pin); return -EINVAL; } @@ -130,7 +150,7 @@ static int bd8lb600fs_pin_configure(const struct device *dev, gpio_pin_t pin, gp WRITE_BIT(drv_data->configured, pin, 1); - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -145,7 +165,6 @@ static int bd8lb600fs_port_get_raw(const struct device *dev, uint32_t *value) static int bd8lb600fs_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -156,7 +175,7 @@ static int bd8lb600fs_port_set_masked_raw(const struct device *dev, uint32_t mas k_mutex_lock(&drv_data->lock, K_FOREVER); drv_data->state = (drv_data->state & ~mask) | (mask & value); - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -175,7 +194,6 @@ static int bd8lb600fs_port_clear_bits_raw(const struct device *dev, uint32_t mas static int bd8lb600fs_port_toggle_bits(const struct device *dev, uint32_t mask) { - const struct bd8lb600fs_config *config = dev->config; struct bd8lb600fs_drv_data *drv_data = dev->data; /* cannot execute a bus operation in an ISR context */ @@ -186,7 +204,7 @@ static int bd8lb600fs_port_toggle_bits(const struct device *dev, uint32_t mask) k_mutex_lock(&drv_data->lock, K_FOREVER); drv_data->state ^= mask; - int result = write_state(config, drv_data->state); + int result = write_state(dev, drv_data->state); k_mutex_unlock(&drv_data->lock); @@ -212,6 +230,11 @@ static int bd8lb600fs_init(const struct device *dev) return -ENODEV; } + if (!gpio_is_ready_dt(&config->gpio_reset)) { + LOG_ERR("%s: reset GPIO is not ready", dev->name); + return -ENODEV; + } + int result = k_mutex_init(&drv_data->lock); if (result != 0) { @@ -219,6 +242,22 @@ static int bd8lb600fs_init(const struct device *dev) return result; } + drv_data->instance_count_actual = config->gpios_count / 8; + + if (config->gpios_count % 8 != 0) { + LOG_ERR("%s: number of GPIOs %i is not a multiple of 8", + dev->name, config->gpios_count); + return -EINVAL; + } + + if (drv_data->instance_count_actual > 4) { + LOG_ERR("%s: only a maximum of 4 devices are supported for the daisy chaining", + dev->name); + return -EINVAL; + } + + drv_data->gpios_count_actual = drv_data->instance_count_actual * 8; + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); if (result != 0) { @@ -242,6 +281,7 @@ static int bd8lb600fs_init(const struct device *dev) .bus = SPI_DT_SPEC_INST_GET( \ inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ .gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), reset_gpios, 0), \ + .gpios_count = DT_INST_PROP(inst, ngpios), \ }; \ \ static struct bd8lb600fs_drv_data bd8lb600fs_##inst##_drvdata = { \ diff --git a/drivers/gpio/gpio_efinix_sapphire.c b/drivers/gpio/gpio_efinix_sapphire.c index 9456406a63c..50123731a5f 100644 --- a/drivers/gpio/gpio_efinix_sapphire.c +++ b/drivers/gpio/gpio_efinix_sapphire.c @@ -34,14 +34,14 @@ LOG_MODULE_REGISTER(gpio_efinix_sapphire); #define BSP_GPIO_INTERRUPT_HIGH_ENABLE 0x28 #define BSP_GPIO_INTERRUPT_LOW_ENABLE 0x2c -/* efinix sapphire specefic gpio config struct */ +/* efinix sapphire specific gpio config struct */ struct gpio_efinix_sapphire_cfg { uint32_t base_addr; int n_gpios; struct gpio_driver_config common; }; -/* efinix sapphire specefic gpio data struct */ +/* efinix sapphire specific gpio data struct */ struct gpio_efinix_sapphire_data { struct gpio_driver_data common; const struct device *dev; @@ -79,7 +79,7 @@ static inline void cfg_output_bit(const struct gpio_efinix_sapphire_cfg *config, } } -/* To use the controller bare minimun as IO, Peripheral has to configure, */ +/* To use the controller bare minimum as IO, Peripheral has to configure, */ /* the Output enable register, b0 : Input, b1 : Output */ static int gpio_efinix_sapphire_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) diff --git a/drivers/gpio/gpio_ite_it8xxx2.c b/drivers/gpio/gpio_ite_it8xxx2.c index 754a3b773f1..1171c5b3391 100644 --- a/drivers/gpio/gpio_ite_it8xxx2.c +++ b/drivers/gpio/gpio_ite_it8xxx2.c @@ -149,7 +149,7 @@ static const struct { [IT8XXX2_IRQ_WU63] = {BIT(3), 6, BIT(3)}, [IT8XXX2_IRQ_WU64] = {BIT(4), 6, BIT(4)}, [IT8XXX2_IRQ_WU65] = {BIT(5), 6, BIT(5)}, - [IT8XXX2_IRQ_WU65] = {BIT(6), 6, BIT(6)}, + [IT8XXX2_IRQ_WU66] = {BIT(6), 6, BIT(6)}, [IT8XXX2_IRQ_WU67] = {BIT(7), 6, BIT(7)}, [IT8XXX2_IRQ_WU70] = {BIT(0), 7, BIT(0)}, [IT8XXX2_IRQ_WU71] = {BIT(1), 7, BIT(1)}, diff --git a/drivers/gpio/gpio_ite_it8xxx2_v2.c b/drivers/gpio/gpio_ite_it8xxx2_v2.c index 23fd2178179..16f505587f9 100644 --- a/drivers/gpio/gpio_ite_it8xxx2_v2.c +++ b/drivers/gpio/gpio_ite_it8xxx2_v2.c @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT ite_it8xxx2_gpio_v2 +#include #include #include #include @@ -18,9 +19,12 @@ #include #include #include +#include +#include #include #include #include + LOG_MODULE_REGISTER(gpio_it8xxx2, LOG_LEVEL_ERR); /* @@ -50,6 +54,8 @@ struct gpio_ite_cfg { uint8_t has_volt_sel[8]; /* Number of pins per group of GPIO */ uint8_t num_pins; + /* gpioksi, gpioksoh and gpioksol extended setting */ + bool kbs_ctrl; }; /* Structure gpio_ite_data is about callback function */ @@ -57,6 +63,11 @@ struct gpio_ite_data { struct gpio_driver_data common; sys_slist_t callbacks; uint8_t volt_default_set; + struct k_spinlock lock; + uint8_t level_isr_high; + uint8_t level_isr_low; + const struct device *instance; + struct k_work interrupt_worker; }; /** @@ -73,6 +84,7 @@ static int gpio_ite_configure(const struct device *dev, volatile uint8_t *reg_gpcr = (uint8_t *)gpio_config->reg_gpcr + pin; struct gpio_ite_data *data = dev->data; uint8_t mask = BIT(pin); + int rc = 0; /* Don't support "open source" mode */ if (((flags & GPIO_SINGLE_ENDED) != 0) && @@ -80,24 +92,27 @@ static int gpio_ite_configure(const struct device *dev, return -ENOTSUP; } + k_spinlock_key_t key = k_spin_lock(&data->lock); if (flags == GPIO_DISCONNECTED) { - *reg_gpcr = GPCR_PORT_PIN_MODE_TRISTATE; + ECREG(reg_gpcr) = GPCR_PORT_PIN_MODE_TRISTATE; /* * Since not all GPIOs can be to configured as tri-state, * prompt error if pin doesn't support the flag. */ - if (*reg_gpcr != GPCR_PORT_PIN_MODE_TRISTATE) { + if (ECREG(reg_gpcr) != GPCR_PORT_PIN_MODE_TRISTATE) { /* Go back to default setting (input) */ - *reg_gpcr = GPCR_PORT_PIN_MODE_INPUT; + ECREG(reg_gpcr) = GPCR_PORT_PIN_MODE_INPUT; LOG_ERR("Cannot config the node-gpio@%x, pin=%d as tri-state", (uint32_t)reg_gpdr, pin); - return -ENOTSUP; + rc = -ENOTSUP; + goto unlock_and_return; } /* * The following configuration isn't necessary because the pin * was configured as disconnected. */ - return 0; + rc = 0; + goto unlock_and_return; } /* @@ -105,9 +120,9 @@ static int gpio_ite_configure(const struct device *dev, * when changing the line to an output. */ if (flags & GPIO_OPEN_DRAIN) { - *reg_gpotr |= mask; + ECREG(reg_gpotr) |= mask; } else { - *reg_gpotr &= ~mask; + ECREG(reg_gpotr) &= ~mask; } /* 1.8V or 3.3V */ @@ -117,10 +132,10 @@ static int gpio_ite_configure(const struct device *dev, if (volt == IT8XXX2_GPIO_VOLTAGE_1P8) { __ASSERT(!(flags & GPIO_PULL_UP), "Don't enable internal pullup if 1.8V voltage is used"); - *reg_p18scr |= mask; + ECREG(reg_p18scr) |= mask; data->volt_default_set &= ~mask; } else if (volt == IT8XXX2_GPIO_VOLTAGE_3P3) { - *reg_p18scr &= ~mask; + ECREG(reg_p18scr) &= ~mask; /* * A variable is needed to store the difference between * 3.3V and default so that the flag can be distinguished @@ -128,45 +143,80 @@ static int gpio_ite_configure(const struct device *dev, */ data->volt_default_set &= ~mask; } else if (volt == IT8XXX2_GPIO_VOLTAGE_DEFAULT) { - *reg_p18scr &= ~mask; + ECREG(reg_p18scr) &= ~mask; data->volt_default_set |= mask; } else { - return -EINVAL; + rc = -EINVAL; + goto unlock_and_return; } } /* If output, set level before changing type to an output. */ if (flags & GPIO_OUTPUT) { if (flags & GPIO_OUTPUT_INIT_HIGH) { - *reg_gpdr |= mask; + ECREG(reg_gpdr) |= mask; } else if (flags & GPIO_OUTPUT_INIT_LOW) { - *reg_gpdr &= ~mask; + ECREG(reg_gpdr) &= ~mask; } } /* Set input or output. */ - if (flags & GPIO_OUTPUT) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_OUTPUT) & - ~GPCR_PORT_PIN_MODE_INPUT; + if (gpio_config->kbs_ctrl) { + /* Handle keyboard scan controller */ + uint8_t ksxgctrlr = ECREG(reg_gpcr); + + ksxgctrlr |= KSIX_KSOX_KBS_GPIO_MODE; + if (flags & GPIO_OUTPUT) { + ksxgctrlr |= KSIX_KSOX_GPIO_OUTPUT; + } else { + ksxgctrlr &= ~KSIX_KSOX_GPIO_OUTPUT; + } + ECREG(reg_gpcr) = ksxgctrlr; } else { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & + /* Handle regular GPIO controller */ + if (flags & GPIO_OUTPUT) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_OUTPUT) & + ~GPCR_PORT_PIN_MODE_INPUT; + } else { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_INPUT) & ~GPCR_PORT_PIN_MODE_OUTPUT; + } } /* Handle pullup / pulldown */ - if (flags & GPIO_PULL_UP) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLUP) & - ~GPCR_PORT_PIN_MODE_PULLDOWN; - } else if (flags & GPIO_PULL_DOWN) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLDOWN) & - ~GPCR_PORT_PIN_MODE_PULLUP; + if (gpio_config->kbs_ctrl) { + /* Handle keyboard scan controller */ + uint8_t ksxgctrlr = ECREG(reg_gpcr); + + if (flags & GPIO_PULL_UP) { + ksxgctrlr = (ksxgctrlr | KSIX_KSOX_GPIO_PULLUP) & + ~KSIX_KSOX_GPIO_PULLDOWN; + } else if (flags & GPIO_PULL_DOWN) { + ksxgctrlr = (ksxgctrlr | KSIX_KSOX_GPIO_PULLDOWN) & + ~KSIX_KSOX_GPIO_PULLUP; + } else { + /* No pull up/down */ + ksxgctrlr &= ~(KSIX_KSOX_GPIO_PULLUP | KSIX_KSOX_GPIO_PULLDOWN); + } + ECREG(reg_gpcr) = ksxgctrlr; } else { - /* No pull up/down */ - *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_PULLUP | - GPCR_PORT_PIN_MODE_PULLDOWN); + /* Handle regular GPIO controller */ + if (flags & GPIO_PULL_UP) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLUP) & + ~GPCR_PORT_PIN_MODE_PULLDOWN; + } else if (flags & GPIO_PULL_DOWN) { + ECREG(reg_gpcr) = (ECREG(reg_gpcr) | GPCR_PORT_PIN_MODE_PULLDOWN) & + ~GPCR_PORT_PIN_MODE_PULLUP; + } else { + /* No pull up/down */ + ECREG(reg_gpcr) &= ~(GPCR_PORT_PIN_MODE_PULLUP | + GPCR_PORT_PIN_MODE_PULLDOWN); + } } - return 0; +unlock_and_return: + k_spin_unlock(&data->lock, key); + return rc; } #ifdef CONFIG_GPIO_GET_CONFIG @@ -183,8 +233,9 @@ static int gpio_ite_get_config(const struct device *dev, uint8_t mask = BIT(pin); gpio_flags_t flags = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* push-pull or open-drain */ - if (*reg_gpotr & mask) { + if (ECREG(reg_gpotr) & mask) { flags |= GPIO_OPEN_DRAIN; } @@ -193,7 +244,7 @@ static int gpio_ite_get_config(const struct device *dev, if (data->volt_default_set & mask) { flags |= IT8XXX2_GPIO_VOLTAGE_DEFAULT; } else { - if (*reg_p18scr & mask) { + if (ECREG(reg_p18scr) & mask) { flags |= IT8XXX2_GPIO_VOLTAGE_1P8; } else { flags |= IT8XXX2_GPIO_VOLTAGE_3P3; @@ -202,31 +253,32 @@ static int gpio_ite_get_config(const struct device *dev, } /* set input or output. */ - if (*reg_gpcr & GPCR_PORT_PIN_MODE_OUTPUT) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_OUTPUT) { flags |= GPIO_OUTPUT; /* set level */ - if (*reg_gpdr & mask) { + if (ECREG(reg_gpdr) & mask) { flags |= GPIO_OUTPUT_HIGH; } else { flags |= GPIO_OUTPUT_LOW; } } - if (*reg_gpcr & GPCR_PORT_PIN_MODE_INPUT) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_INPUT) { flags |= GPIO_INPUT; /* pullup / pulldown */ - if (*reg_gpcr & GPCR_PORT_PIN_MODE_PULLUP) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_PULLUP) { flags |= GPIO_PULL_UP; } - if (*reg_gpcr & GPCR_PORT_PIN_MODE_PULLDOWN) { + if (ECREG(reg_gpcr) & GPCR_PORT_PIN_MODE_PULLDOWN) { flags |= GPIO_PULL_DOWN; } } *out_flags = flags; + k_spin_unlock(&data->lock, key); return 0; } @@ -239,7 +291,7 @@ static int gpio_ite_port_get_raw(const struct device *dev, volatile uint8_t *reg_gpdmr = (uint8_t *)gpio_config->reg_gpdmr; /* Get raw bits of GPIO mirror register */ - *value = *reg_gpdmr; + *value = ECREG(reg_gpdmr); return 0; } @@ -250,9 +302,13 @@ static int gpio_ite_port_set_masked_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; - uint8_t out = *reg_gpdr; + uint8_t masked_value = value & mask; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + uint8_t out = ECREG(reg_gpdr); - *reg_gpdr = ((out & ~mask) | (value & mask)); + ECREG(reg_gpdr) = ((out & ~mask) | masked_value); + k_spin_unlock(&data->lock, key); return 0; } @@ -262,9 +318,12 @@ static int gpio_ite_port_set_bits_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Set raw bits of GPIO data register */ - *reg_gpdr |= pins; + ECREG(reg_gpdr) |= pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -274,9 +333,12 @@ static int gpio_ite_port_clear_bits_raw(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Clear raw bits of GPIO data register */ - *reg_gpdr &= ~pins; + ECREG(reg_gpdr) &= ~pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -286,9 +348,12 @@ static int gpio_ite_port_toggle_bits(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; volatile uint8_t *reg_gpdr = (uint8_t *)gpio_config->reg_gpdr; + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); /* Toggle raw bits of GPIO data register */ - *reg_gpdr ^= pins; + ECREG(reg_gpdr) ^= pins; + k_spin_unlock(&data->lock, key); return 0; } @@ -299,7 +364,11 @@ static int gpio_ite_manage_callback(const struct device *dev, { struct gpio_ite_data *data = dev->data; - return gpio_manage_callback(&data->callbacks, callback, set); + k_spinlock_key_t key = k_spin_lock(&data->lock); + int rc = gpio_manage_callback(&data->callbacks, callback, set); + + k_spin_unlock(&data->lock, key); + return rc; } static void gpio_ite_isr(const void *arg) @@ -318,13 +387,41 @@ static void gpio_ite_isr(const void *arg) volatile uint8_t *reg_wuesr = reg_base + 1; uint8_t wuc_mask = gpio_config->wuc_mask[pin]; + /* Should be safe even without spinlock. */ /* Clear the WUC status register. */ - *reg_wuesr = wuc_mask; + ECREG(reg_wuesr) = wuc_mask; + /* The callbacks are user code, and therefore should + * not hold the lock. + */ gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); break; } } + /* Reschedule worker */ + k_work_submit(&data->interrupt_worker); +} + +static void gpio_ite_interrupt_worker(struct k_work *work) +{ + struct gpio_ite_data * const data = CONTAINER_OF( + work, struct gpio_ite_data, interrupt_worker); + gpio_port_value_t value; + gpio_port_value_t triggered_int; + + gpio_ite_port_get_raw(data->instance, &value); + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + triggered_int = (value & data->level_isr_high) | (~value & data->level_isr_low); + k_spin_unlock(&data->lock, key); + + if (triggered_int != 0) { + gpio_fire_callbacks(&data->callbacks, data->instance, + triggered_int); + /* Reschedule worker */ + k_work_submit(&data->interrupt_worker); + } } static int gpio_ite_pin_interrupt_configure(const struct device *dev, @@ -334,6 +431,7 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, { const struct gpio_ite_cfg *gpio_config = dev->config; uint8_t gpio_irq = gpio_config->gpio_irq[pin]; + struct gpio_ite_data *data = dev->data; #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT if (mode == GPIO_INT_MODE_DISABLED || mode == GPIO_INT_MODE_DISABLE_ONLY) { @@ -351,11 +449,6 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ } - if (mode == GPIO_INT_MODE_LEVEL) { - LOG_ERR("Level trigger mode not supported"); - return -ENOTSUP; - } - /* Disable irq before configuring it */ irq_disable(gpio_irq); @@ -366,28 +459,45 @@ static int gpio_ite_pin_interrupt_configure(const struct device *dev, volatile uint8_t *reg_wubemr = reg_base + 3; uint8_t wuc_mask = gpio_config->wuc_mask[pin]; + k_spinlock_key_t key = k_spin_lock(&data->lock); + /* Set both edges interrupt. */ if ((trig & GPIO_INT_TRIG_BOTH) == GPIO_INT_TRIG_BOTH) { - *reg_wubemr |= wuc_mask; + ECREG(reg_wubemr) |= wuc_mask; } else { - *reg_wubemr &= ~wuc_mask; + ECREG(reg_wubemr) &= ~wuc_mask; } if (trig & GPIO_INT_TRIG_LOW) { - *reg_wuemr |= wuc_mask; + ECREG(reg_wuemr) |= wuc_mask; + } else { + ECREG(reg_wuemr) &= ~wuc_mask; + } + + if (mode == GPIO_INT_MODE_LEVEL) { + if (trig & GPIO_INT_TRIG_LOW) { + data->level_isr_low |= BIT(pin); + data->level_isr_high &= ~BIT(pin); + } else { + data->level_isr_low &= ~BIT(pin); + data->level_isr_high |= BIT(pin); + } } else { - *reg_wuemr &= ~wuc_mask; + data->level_isr_low &= ~BIT(pin); + data->level_isr_high &= ~BIT(pin); } /* * Always write 1 to clear the WUC status register after * modifying edge mode selection register (WUBEMR and WUEMR). */ - *reg_wuesr = wuc_mask; + ECREG(reg_wuesr) = wuc_mask; + k_spin_unlock(&data->lock, key); } /* Enable GPIO interrupt */ irq_connect_dynamic(gpio_irq, 0, gpio_ite_isr, dev, 0); irq_enable(gpio_irq); + k_work_submit(&data->interrupt_worker); return 0; } @@ -408,6 +518,14 @@ static const struct gpio_driver_api gpio_ite_driver_api = { static int gpio_ite_init(const struct device *dev) { + struct gpio_ite_data *data = dev->data; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + data->instance = dev; + k_work_init(&data->interrupt_worker, + gpio_ite_interrupt_worker); + k_spin_unlock(&data->lock, key); + return 0; } @@ -428,6 +546,7 @@ static const struct gpio_ite_cfg gpio_ite_cfg_##inst = { \ .gpio_irq = IT8XXX2_DT_GPIO_IRQ_LIST(inst), \ .has_volt_sel = DT_INST_PROP_OR(inst, has_volt_sel, {0}), \ .num_pins = DT_INST_PROP(inst, ngpios), \ + .kbs_ctrl = DT_INST_PROP_OR(inst, keyboard_controller, 0), \ }; \ DEVICE_DT_INST_DEFINE(inst, \ gpio_ite_init, \ @@ -440,18 +559,18 @@ DEVICE_DT_INST_DEFINE(inst, \ DT_INST_FOREACH_STATUS_OKAY(GPIO_ITE_DEV_CFG_DATA) +#ifdef CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN static int gpio_it8xxx2_init_set(void) { - if (IS_ENABLED(CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN)) { - const struct device *const gpiok = DEVICE_DT_GET(DT_NODELABEL(gpiok)); - const struct device *const gpiol = DEVICE_DT_GET(DT_NODELABEL(gpiol)); + const struct device *const gpiok = DEVICE_DT_GET(DT_NODELABEL(gpiok)); + const struct device *const gpiol = DEVICE_DT_GET(DT_NODELABEL(gpiol)); - for (int i = 0; i < 8; i++) { - gpio_pin_configure(gpiok, i, GPIO_INPUT | GPIO_PULL_DOWN); - gpio_pin_configure(gpiol, i, GPIO_INPUT | GPIO_PULL_DOWN); - } + for (int i = 0; i < 8; i++) { + gpio_pin_configure(gpiok, i, GPIO_INPUT | GPIO_PULL_DOWN); + gpio_pin_configure(gpiol, i, GPIO_INPUT | GPIO_PULL_DOWN); } return 0; } SYS_INIT(gpio_it8xxx2_init_set, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY); +#endif /* CONFIG_SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN */ diff --git a/drivers/gpio/gpio_mchp_mss.c b/drivers/gpio/gpio_mchp_mss.c index b5b3a7033d5..7db42b77913 100644 --- a/drivers/gpio/gpio_mchp_mss.c +++ b/drivers/gpio/gpio_mchp_mss.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio_mcp23xxx.c b/drivers/gpio/gpio_mcp23xxx.c index c9bf2f6aa69..c9cb32866b7 100644 --- a/drivers/gpio/gpio_mcp23xxx.c +++ b/drivers/gpio/gpio_mcp23xxx.c @@ -412,8 +412,13 @@ static void mcp23xxx_work_handler(struct k_work *work) } if (!intf) { - /* Probable cause: REG_GPIO was read from somewhere else before the interrupt - * handler had a chance to run + /* Probable causes: + * - REG_GPIO was read from somewhere else before the interrupt handler had a chance + * to run + * - Even though the datasheet says differently, reading INTCAP while a level + * interrupt is active briefly (~2ns) causes the interrupt line to go high and + * low again. This causes a second ISR to be scheduled, which then won't + * find any active interrupts if the callback has disabled the level interrupt. */ LOG_ERR("Spurious interrupt"); goto fail; diff --git a/drivers/gpio/gpio_mcux_lpc.c b/drivers/gpio/gpio_mcux_lpc.c index 297e83930f2..673ad496a14 100644 --- a/drivers/gpio/gpio_mcux_lpc.c +++ b/drivers/gpio/gpio_mcux_lpc.c @@ -44,7 +44,6 @@ struct gpio_mcux_lpc_config { IOCON_Type *pinmux_base; #endif uint32_t port_no; - clock_ip_name_t clock_ip_name; }; struct gpio_mcux_lpc_data { @@ -381,7 +380,6 @@ static int gpio_mcux_lpc_manage_cb(const struct device *port, static int gpio_mcux_lpc_init(const struct device *dev) { const struct gpio_mcux_lpc_config *config = dev->config; - GPIO_PortInit(config->gpio_base, config->port_no); return 0; @@ -398,7 +396,7 @@ static const struct gpio_driver_api gpio_mcux_lpc_driver_api = { .manage_callback = gpio_mcux_lpc_manage_cb, }; -static const clock_ip_name_t gpio_clock_names[] = GPIO_CLOCKS; + #ifdef IOPCTL #define PINMUX_BASE IOPCTL @@ -429,8 +427,7 @@ static const clock_ip_name_t gpio_clock_names[] = GPIO_CLOCKS; .gpio_base = GPIO, \ .pinmux_base = PINMUX_BASE, \ .int_source = DT_INST_ENUM_IDX(n, int_source), \ - .port_no = DT_INST_PROP(n, port), \ - .clock_ip_name = gpio_clock_names[DT_INST_PROP(n, port)], \ + .port_no = DT_INST_PROP(n, port) \ }; \ \ static struct gpio_mcux_lpc_data gpio_mcux_lpc_data_##n; \ diff --git a/drivers/gpio/gpio_mcux_rgpio.c b/drivers/gpio/gpio_mcux_rgpio.c new file mode 100644 index 00000000000..16ad02c6ae8 --- /dev/null +++ b/drivers/gpio/gpio_mcux_rgpio.c @@ -0,0 +1,308 @@ +/* + * Copyright 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_imx_rgpio + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct gpio_pin_gaps { + uint8_t start; + uint8_t len; +}; + +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct mcux_rgpio_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct mcux_rgpio_data *)(_dev)->data) + +struct mcux_rgpio_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + + DEVICE_MMIO_NAMED_ROM(reg_base); + + const struct pinctrl_soc_pinmux *pin_muxes; + const struct gpio_pin_gaps *pin_gaps; + uint8_t mux_count; + uint8_t gap_count; +}; + +struct mcux_rgpio_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data general; + + DEVICE_MMIO_NAMED_RAM(reg_base); + + /* port ISR callback routine address */ + sys_slist_t callbacks; +}; + +static int mcux_rgpio_configure(const struct device *dev, + gpio_pin_t pin, gpio_flags_t flags) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + const struct mcux_rgpio_config *config = dev->config; + + struct pinctrl_soc_pin pin_cfg; + int cfg_idx = pin, i; + + /* Some SOCs have non-contiguous gpio pin layouts, account for this */ + for (i = 0; i < config->gap_count; i++) { + if (pin >= config->pin_gaps[i].start) { + if (pin < (config->pin_gaps[i].start + + config->pin_gaps[i].len)) { + /* Pin is not connected to a mux */ + return -ENOTSUP; + } + cfg_idx -= config->pin_gaps[i].len; + } + } + + /* Init pin configuration struct, and use pinctrl api to apply settings */ + if (cfg_idx >= config->mux_count) { + /* Pin is not connected to a mux */ + return -ENOTSUP; + } + + /* Set appropriate bits in pin configuration register */ + volatile uint32_t *gpio_cfg_reg = (volatile uint32_t *) + ((size_t)config->pin_muxes[cfg_idx].config_register); + uint32_t reg = *gpio_cfg_reg; + + /* TODO: Default flags, work for i.MX 9352 */ + if ((flags & GPIO_SINGLE_ENDED) != 0) { + /* Set ODE bit */ + reg |= (0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT); + } else { + reg &= ~(0x1 << MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT); + } + if (((flags & GPIO_PULL_UP) != 0) || ((flags & GPIO_PULL_DOWN) != 0)) { + /* i.MX93 has no pull enable bit */ + if (((flags & GPIO_PULL_UP) != 0)) { + reg |= (0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT); + reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT); + } else { + reg |= (0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT); + reg &= ~(0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT); + } + } else { + /* Set pin to highz */ + reg &= ~((0x1 << MCUX_IMX_BIAS_PULL_DOWN_SHIFT) | + (0x1 << MCUX_IMX_BIAS_PULL_UP_SHIFT)); + } + + memcpy(&pin_cfg.pinmux, &config->pin_muxes[cfg_idx], sizeof(pin_cfg)); + /* cfg register will be set by pinctrl_configure_pins */ + pin_cfg.pin_ctrl_flags = reg; + pinctrl_configure_pins(&pin_cfg, 1, PINCTRL_REG_NONE); + + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; + } + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + RGPIO_WritePinOutput(base, pin, 1); + } + + if (flags & GPIO_OUTPUT_INIT_LOW) { + RGPIO_WritePinOutput(base, pin, 0); + } + + WRITE_BIT(base->PDDR, pin, flags & GPIO_OUTPUT); + + return 0; +} + +static int mcux_rgpio_port_get_raw(const struct device *dev, uint32_t *value) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + *value = base->PDIR; + + return 0; +} + +static int mcux_rgpio_port_set_masked_raw(const struct device *dev, + uint32_t mask, + uint32_t value) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + base->PDOR = (base->PDOR & ~mask) | (mask & value); + + return 0; +} + +static int mcux_rgpio_port_set_bits_raw(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortSet(base, mask); + + return 0; +} + +static int mcux_rgpio_port_clear_bits_raw(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortClear(base, mask); + + return 0; +} + +static int mcux_rgpio_port_toggle_bits(const struct device *dev, + uint32_t mask) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + + RGPIO_PortToggle(base, mask); + + return 0; +} + +static int mcux_rgpio_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + unsigned int key; + uint8_t irqs, irqc; + + irqs = 0; /* only irq0 is used for irq */ + + if (mode == GPIO_INT_MODE_DISABLED) { + irqc = kRGPIO_InterruptOrDMADisabled; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_LOW)) { + irqc = kRGPIO_InterruptFallingEdge; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_HIGH)) { + irqc = kRGPIO_InterruptRisingEdge; + } else if ((mode == GPIO_INT_MODE_EDGE) && + (trig == GPIO_INT_TRIG_BOTH)) { + irqc = kRGPIO_InterruptEitherEdge; + } else if ((mode == GPIO_INT_MODE_LEVEL) && + (trig == GPIO_INT_TRIG_LOW)) { + irqc = kRGPIO_InterruptLogicZero; + } else if ((mode == GPIO_INT_MODE_LEVEL) && + (trig == GPIO_INT_TRIG_HIGH)) { + irqc = kRGPIO_InterruptLogicOne; + } else { + return -EINVAL; /* should never end up here */ + } + + key = irq_lock(); + RGPIO_SetPinInterruptConfig(base, pin, irqs, irqc); + irq_unlock(key); + + return 0; +} + +static int mcux_rgpio_manage_callback(const struct device *dev, + struct gpio_callback *callback, + bool set) +{ + struct mcux_rgpio_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static void mcux_rgpio_port_isr(const struct device *dev) +{ + RGPIO_Type *base = (RGPIO_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + struct mcux_rgpio_data *data = dev->data; + uint32_t int_flags; + + int_flags = base->ISFR[0]; /* Notice: only irq0 is used for now */ + base->ISFR[0] = int_flags; + + gpio_fire_callbacks(&data->callbacks, dev, int_flags); +} + +static const struct gpio_driver_api mcux_rgpio_driver_api = { + .pin_configure = mcux_rgpio_configure, + .port_get_raw = mcux_rgpio_port_get_raw, + .port_set_masked_raw = mcux_rgpio_port_set_masked_raw, + .port_set_bits_raw = mcux_rgpio_port_set_bits_raw, + .port_clear_bits_raw = mcux_rgpio_port_clear_bits_raw, + .port_toggle_bits = mcux_rgpio_port_toggle_bits, + .pin_interrupt_configure = mcux_rgpio_pin_interrupt_configure, + .manage_callback = mcux_rgpio_manage_callback, +}; + +/* These macros will declare an array of pinctrl_soc_pinmux types */ +#define PINMUX_INIT(node, prop, idx) MCUX_IMX_PINMUX(DT_PROP_BY_IDX(node, prop, idx)), +#define MCUX_RGPIO_PIN_DECLARE(n) \ + const struct pinctrl_soc_pinmux mcux_rgpio_pinmux_##n[] = { \ + DT_FOREACH_PROP_ELEM(DT_DRV_INST(n), pinmux, PINMUX_INIT) \ + }; \ + const uint8_t mcux_rgpio_pin_gaps_##n[] = \ + DT_INST_PROP_OR(n, gpio_reserved_ranges, {}); +#define MCUX_RGPIO_PIN_INIT(n) \ + .pin_muxes = mcux_rgpio_pinmux_##n, \ + .pin_gaps = (const struct gpio_pin_gaps *)mcux_rgpio_pin_gaps_##n, \ + .mux_count = DT_PROP_LEN(DT_DRV_INST(n), pinmux), \ + .gap_count = (ARRAY_SIZE(mcux_rgpio_pin_gaps_##n) / 2) + +#define MCUX_RGPIO_IRQ_INIT(n, i) \ + do { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \ + DT_INST_IRQ_BY_IDX(n, i, priority), \ + mcux_rgpio_port_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQ_BY_IDX(n, i, irq)); \ + } while (false) + +#define MCUX_RGPIO_INIT(n) \ + MCUX_RGPIO_PIN_DECLARE(n) \ + static int mcux_rgpio_##n##_init(const struct device *dev); \ + \ + static const struct mcux_rgpio_config mcux_rgpio_##n##_config = {\ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\ + }, \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ + MCUX_RGPIO_PIN_INIT(n) \ + }; \ + \ + static struct mcux_rgpio_data mcux_rgpio_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + mcux_rgpio_##n##_init, \ + NULL, \ + &mcux_rgpio_##n##_data, \ + &mcux_rgpio_##n##_config, \ + POST_KERNEL, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &mcux_rgpio_driver_api); \ + \ + static int mcux_rgpio_##n##_init(const struct device *dev) \ + { \ + DEVICE_MMIO_NAMED_MAP(dev, reg_base, \ + K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \ + (MCUX_RGPIO_IRQ_INIT(n, 0);)) \ + \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 1), \ + (MCUX_RGPIO_IRQ_INIT(n, 1);)) \ + \ + return 0; \ + } + +DT_INST_FOREACH_STATUS_OKAY(MCUX_RGPIO_INIT) diff --git a/drivers/gpio/gpio_nrfx.c b/drivers/gpio/gpio_nrfx.c index 0aa282dda37..d89c964cc90 100644 --- a/drivers/gpio/gpio_nrfx.c +++ b/drivers/gpio/gpio_nrfx.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #define DT_DRV_COMPAT nordic_nrf_gpio #include @@ -25,6 +26,7 @@ struct gpio_nrfx_cfg { NRF_GPIO_Type *port; uint32_t edge_sense; uint8_t port_num; + nrfx_gpiote_t gpiote; }; static inline struct gpio_nrfx_data *get_port_data(const struct device *port) @@ -37,131 +39,139 @@ static inline const struct gpio_nrfx_cfg *get_port_cfg(const struct device *port return port->config; } -static int get_drive(gpio_flags_t flags, nrf_gpio_pin_drive_t *drive) +static bool has_gpiote(const struct gpio_nrfx_cfg *cfg) +{ + return cfg->gpiote.p_reg != NULL; +} + +static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) +{ + if (flags & GPIO_PULL_UP) { + return NRF_GPIO_PIN_PULLUP; + } else if (flags & GPIO_PULL_DOWN) { + return NRF_GPIO_PIN_PULLDOWN; + } + + return NRF_GPIO_PIN_NOPULL; +} + +static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, + gpio_flags_t flags) { + nrfx_err_t err = NRFX_SUCCESS; + uint8_t ch; + bool free_ch = false; + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); + nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); + nrf_gpio_pin_pull_t pull = get_pull(flags); + nrf_gpio_pin_drive_t drive; + switch (flags & (NRF_GPIO_DRIVE_MSK | GPIO_OPEN_DRAIN)) { case NRF_GPIO_DRIVE_S0S1: - *drive = NRF_GPIO_PIN_S0S1; + drive = NRF_GPIO_PIN_S0S1; break; case NRF_GPIO_DRIVE_S0H1: - *drive = NRF_GPIO_PIN_S0H1; + drive = NRF_GPIO_PIN_S0H1; break; case NRF_GPIO_DRIVE_H0S1: - *drive = NRF_GPIO_PIN_H0S1; + drive = NRF_GPIO_PIN_H0S1; break; case NRF_GPIO_DRIVE_H0H1: - *drive = NRF_GPIO_PIN_H0H1; + drive = NRF_GPIO_PIN_H0H1; break; case NRF_GPIO_DRIVE_S0 | GPIO_OPEN_DRAIN: - *drive = NRF_GPIO_PIN_S0D1; + drive = NRF_GPIO_PIN_S0D1; break; case NRF_GPIO_DRIVE_H0 | GPIO_OPEN_DRAIN: - *drive = NRF_GPIO_PIN_H0D1; + drive = NRF_GPIO_PIN_H0D1; break; case NRF_GPIO_DRIVE_S1 | GPIO_OPEN_SOURCE: - *drive = NRF_GPIO_PIN_D0S1; + drive = NRF_GPIO_PIN_D0S1; break; case NRF_GPIO_DRIVE_H1 | GPIO_OPEN_SOURCE: - *drive = NRF_GPIO_PIN_D0H1; + drive = NRF_GPIO_PIN_D0H1; break; default: return -EINVAL; } - return 0; -} - -static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags) -{ - if (flags & GPIO_PULL_UP) { - return NRF_GPIO_PIN_PULLUP; - } else if (flags & GPIO_PULL_DOWN) { - return NRF_GPIO_PIN_PULLDOWN; + if (flags & GPIO_OUTPUT_INIT_HIGH) { + nrf_gpio_port_out_set(cfg->port, BIT(pin)); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + nrf_gpio_port_out_clear(cfg->port, BIT(pin)); } - return NRF_GPIO_PIN_NOPULL; -} + if (!has_gpiote(cfg)) { + nrf_gpio_pin_dir_t dir = (flags & GPIO_OUTPUT) + ? NRF_GPIO_PIN_DIR_OUTPUT + : NRF_GPIO_PIN_DIR_INPUT; + nrf_gpio_pin_input_t input = (flags & GPIO_INPUT) + ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT; -static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin, - gpio_flags_t flags) -{ - nrfx_err_t err = NRFX_SUCCESS; - uint8_t ch; - bool free_ch = false; - const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); - nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); + nrf_gpio_reconfigure(abs_pin, &dir, &input, &pull, &drive, NULL); + return 0; + } /* Get the GPIOTE channel associated with this pin, if any. It needs * to be freed when the pin is reconfigured or disconnected. */ if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { - err = nrfx_gpiote_channel_get(abs_pin, &ch); + err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch); free_ch = (err == NRFX_SUCCESS); } if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { /* Ignore the error code. The pin may not have been used. */ - (void)nrfx_gpiote_pin_uninit(abs_pin); - - if (free_ch) { - err = nrfx_gpiote_channel_free(ch); - __ASSERT_NO_MSG(err == NRFX_SUCCESS); + (void)nrfx_gpiote_pin_uninit(&cfg->gpiote, abs_pin); + } else { + /* Remove previously configured trigger when pin is reconfigured. */ + if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_NONE, + }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; + + err = nrfx_gpiote_input_configure(&cfg->gpiote, + abs_pin, &input_pin_config); + if (err != NRFX_SUCCESS) { + return -EINVAL; + } } - return 0; - } - - if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT)) { - nrfx_gpiote_trigger_config_t trigger_config = { - .trigger = NRFX_GPIOTE_TRIGGER_NONE - }; + if (flags & GPIO_OUTPUT) { + nrfx_gpiote_output_config_t output_config = { + .drive = drive, + .input_connect = (flags & GPIO_INPUT) + ? NRF_GPIO_PIN_INPUT_CONNECT + : NRF_GPIO_PIN_INPUT_DISCONNECT, + .pull = pull, + }; + + err = nrfx_gpiote_output_configure(&cfg->gpiote, + abs_pin, &output_config, NULL); + } else { + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_pull_config = &pull, + }; + + err = nrfx_gpiote_input_configure(&cfg->gpiote, + abs_pin, &input_pin_config); + } - /* Remove previously configured trigger when pin is reconfigured. */ - err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL); if (err != NRFX_SUCCESS) { return -EINVAL; } - - if (free_ch) { - err = nrfx_gpiote_channel_free(ch); - __ASSERT_NO_MSG(err == NRFX_SUCCESS); - } } - if (flags & GPIO_OUTPUT) { - nrf_gpio_pin_drive_t drive; - int rv = get_drive(flags, &drive); - - if (rv != 0) { - return rv; - } - - nrfx_gpiote_output_config_t output_config = { - .drive = drive, - .input_connect = (flags & GPIO_INPUT) ? - NRF_GPIO_PIN_INPUT_CONNECT : - NRF_GPIO_PIN_INPUT_DISCONNECT, - .pull = get_pull(flags) - }; - - - if (flags & GPIO_OUTPUT_INIT_HIGH) { - nrf_gpio_port_out_set(cfg->port, BIT(pin)); - } else if (flags & GPIO_OUTPUT_INIT_LOW) { - nrf_gpio_port_out_clear(cfg->port, BIT(pin)); - } - - err = nrfx_gpiote_output_configure(abs_pin, &output_config, NULL); - return (err != NRFX_SUCCESS) ? -EINVAL : 0; + if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) { + err = nrfx_gpiote_channel_free(&cfg->gpiote, ch); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); } - nrfx_gpiote_input_config_t input_config = { - .pull = get_pull(flags) - }; - - err = nrfx_gpiote_input_configure(abs_pin, &input_config, NULL, NULL); - - return (err != NRFX_SUCCESS) ? -EINVAL : 0; + return 0; } static int gpio_nrfx_port_get_raw(const struct device *port, @@ -242,12 +252,17 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, enum gpio_int_mode mode, enum gpio_int_trig trig) { - uint32_t abs_pin = NRF_GPIO_PIN_MAP(get_port_cfg(port)->port_num, pin); + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); + uint32_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin); nrfx_err_t err; uint8_t ch; + if (!has_gpiote(cfg)) { + return -ENOTSUP; + } + if (mode == GPIO_INT_MODE_DISABLED) { - nrfx_gpiote_trigger_disable(abs_pin); + nrfx_gpiote_trigger_disable(&cfg->gpiote, abs_pin); return 0; } @@ -255,16 +270,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, nrfx_gpiote_trigger_config_t trigger_config = { .trigger = get_trigger(mode, trig), }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; /* If edge mode is to be used and pin is not configured to use sense for * edge use IN event. */ - if (!(BIT(pin) & get_port_cfg(port)->edge_sense) && + if (!(BIT(pin) & cfg->edge_sense) && (mode == GPIO_INT_MODE_EDGE) && (nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) { - err = nrfx_gpiote_channel_get(abs_pin, &ch); + err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch); if (err == NRFX_ERROR_INVALID_PARAM) { - err = nrfx_gpiote_channel_alloc(&ch); + err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch); if (err != NRFX_SUCCESS) { return -ENOMEM; } @@ -273,12 +291,12 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port, trigger_config.p_in_channel = &ch; } - err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL); + err = nrfx_gpiote_input_configure(&cfg->gpiote, abs_pin, &input_pin_config); if (err != NRFX_SUCCESS) { return -EINVAL; } - nrfx_gpiote_trigger_enable(abs_pin, true); + nrfx_gpiote_trigger_enable(&cfg->gpiote, abs_pin, true); return 0; } @@ -367,26 +385,31 @@ static void nrfx_gpio_handler(nrfx_gpiote_pin_t abs_pin, } #endif /* CONFIG_GPIO_NRFX_INTERRUPT */ -#define GPIOTE_NODE DT_INST(0, nordic_nrf_gpiote) +#define GPIOTE_IRQ_HANDLER_CONNECT(node_id) \ + IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), nrfx_isr, \ + NRFX_CONCAT(nrfx_gpiote_, DT_PROP(node_id, instance), _irq_handler), 0); static int gpio_nrfx_init(const struct device *port) { + const struct gpio_nrfx_cfg *cfg = get_port_cfg(port); nrfx_err_t err; - if (nrfx_gpiote_is_init()) { + if (!has_gpiote(cfg)) { + return 0; + } + + if (nrfx_gpiote_init_check(&cfg->gpiote)) { return 0; } - err = nrfx_gpiote_init(0/*not used*/); + err = nrfx_gpiote_init(&cfg->gpiote, 0 /*not used*/); if (err != NRFX_SUCCESS) { return -EIO; } #ifdef CONFIG_GPIO_NRFX_INTERRUPT - nrfx_gpiote_global_callback_set(nrfx_gpio_handler, NULL); - - IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority), - nrfx_isr, nrfx_gpiote_irq_handler, 0); + nrfx_gpiote_global_callback_set(&cfg->gpiote, nrfx_gpio_handler, NULL); + DT_FOREACH_STATUS_OKAY(nordic_nrf_gpiote, GPIOTE_IRQ_HANDLER_CONNECT); #endif /* CONFIG_GPIO_NRFX_INTERRUPT */ return 0; @@ -408,12 +431,27 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { #endif }; +#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance) +#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance) + +#define GPIOTE_INSTANCE(id) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(id, gpiote_instance), \ + (NRFX_GPIOTE_INSTANCE(GPIOTE_INST(id))), \ + ({ .p_reg = NULL })) + /* Device instantiation is done with node labels because 'port_num' is * the peripheral number by SoC numbering. We therefore cannot use * DT_INST APIs here without wider changes. */ +#define GPIOTE_CHECK(id) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(id, gpiote_instance), \ + (BUILD_ASSERT(DT_NODE_HAS_STATUS(GPIOTE_PHANDLE(id), okay), \ + "Please enable GPIOTE instance for used GPIO port!")), \ + ()) + #define GPIO_NRF_DEVICE(id) \ + GPIOTE_CHECK(id); \ static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \ .common = { \ .port_pin_mask = \ @@ -421,7 +459,8 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = { }, \ .port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \ .port_num = DT_INST_PROP(id, port), \ - .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0) \ + .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \ + .gpiote = GPIOTE_INSTANCE(id), \ }; \ \ static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \ diff --git a/drivers/gpio/gpio_pca953x.c b/drivers/gpio/gpio_pca953x.c index 7b5db11826e..81898e83382 100644 --- a/drivers/gpio/gpio_pca953x.c +++ b/drivers/gpio/gpio_pca953x.c @@ -27,6 +27,8 @@ LOG_MODULE_REGISTER(pca953x, CONFIG_GPIO_LOG_LEVEL); #define PCA953X_INPUT_PORT 0x00 #define PCA953X_OUTPUT_PORT 0x01 #define PCA953X_CONFIGURATION 0x03 +#define REG_INPUT_LATCH_PORT0 0x42 +#define REG_INT_MASK_PORT0 0x45 /* Number of pins supported by the device */ #define NUM_PINS 8 @@ -67,6 +69,8 @@ struct pca953x_config { struct i2c_dt_spec i2c; const struct gpio_dt_spec gpio_int; bool interrupt_enabled; + int interrupt_mask; + int input_latch; }; /** @@ -439,6 +443,20 @@ static int gpio_pca953x_init(const struct device *dev) rc = gpio_add_callback(cfg->gpio_int.port, &drv_data->gpio_cb); + + if (rc) { + goto out; + } + + /* This may not present on all variants of device */ + if (cfg->input_latch > -1) { + rc = i2c_reg_write_byte_dt(&cfg->i2c, REG_INPUT_LATCH_PORT0, + cfg->input_latch); + } + if (cfg->interrupt_mask > -1) { + rc = i2c_reg_write_byte_dt(&cfg->i2c, REG_INT_MASK_PORT0, + cfg->interrupt_mask); + } } out: if (rc) { @@ -468,6 +486,8 @@ static const struct gpio_driver_api api_table = { }, \ .interrupt_enabled = DT_INST_NODE_HAS_PROP(n, nint_gpios), \ .gpio_int = GPIO_DT_SPEC_INST_GET_OR(n, nint_gpios, {0}), \ + .interrupt_mask = DT_INST_PROP_OR(n, interrupt_mask, -1), \ + .input_latch = DT_INST_PROP_OR(n, input_latch, -1), \ }; \ \ static struct pca953x_drv_data pca953x_drvdata_##n = { \ diff --git a/drivers/gpio/gpio_pcf8574.c b/drivers/gpio/gpio_pcf8574.c deleted file mode 100644 index 80a0d8b7d06..00000000000 --- a/drivers/gpio/gpio_pcf8574.c +++ /dev/null @@ -1,397 +0,0 @@ -/** - * Copyright (c) 2022 Ithinx GmbH - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT nxp_pcf8574 - -#include - -#include -#include -#include -#include -LOG_MODULE_REGISTER(pcf8574, CONFIG_GPIO_LOG_LEVEL); - -struct pcf8574_pins_cfg { - uint8_t configured_as_outputs; /* 0 for input, 1 for output */ - uint8_t outputs_state; -}; - -/** Runtime driver data of the pcf8574*/ -struct pcf8574_drv_data { - /* gpio_driver_data needs to be first */ - struct gpio_driver_data common; - struct pcf8574_pins_cfg pins_cfg; - sys_slist_t callbacks; - struct k_sem lock; - struct k_work work; - const struct device *dev; - struct gpio_callback int_gpio_cb; - uint8_t input_port_last; -}; - -/** Configuration data*/ -struct pcf8574_drv_cfg { - /* gpio_driver_config needs to be first */ - struct gpio_driver_config common; - struct i2c_dt_spec i2c; - struct gpio_dt_spec gpio_int; -}; - -/** - * @brief Reads the value of the pins from pcf8574 respectively from a connected device. - * - * @param dev Pointer to the device structure of the driver instance. - * @param value Pointer to the input value. It contains the received Byte. - * - * @retval 0 If successful. - * @retval Negative value for error code. - */ -static int pcf8574_process_input(const struct device *dev, gpio_port_value_t *value) -{ - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; - int rc = 0; - uint8_t rx_buf; - - rc = i2c_read_dt(&drv_cfg->i2c, &rx_buf, sizeof(rx_buf)); - if (rc != 0) { - LOG_ERR("%s: failed to read from device: %d", dev->name, rc); - return -EIO; - } - - if (value) { - *value = rx_buf; - } - - drv_data->input_port_last = rx_buf; - - return rc; -} - -/** Register the read-task as work*/ -static void pcf8574_work_handler(struct k_work *work) -{ - struct pcf8574_drv_data *drv_data = CONTAINER_OF(work, struct pcf8574_drv_data, work); - - k_sem_take(&drv_data->lock, K_FOREVER); - - uint32_t changed_pins; - uint8_t input_port_last_temp = drv_data->input_port_last; - int rc = pcf8574_process_input(drv_data->dev, &changed_pins); - - if (rc) { - LOG_ERR("Failed to read interrupt sources: %d", rc); - } - k_sem_give(&drv_data->lock); - if (input_port_last_temp != (uint8_t)changed_pins && !rc) { - - /** Find changed bits*/ - changed_pins ^= input_port_last_temp; - gpio_fire_callbacks(&drv_data->callbacks, drv_data->dev, changed_pins); - } -} - -/** Callback for interrupt through some level changes on pcf8574 pins*/ -static void pcf8574_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, - uint32_t pins) -{ - ARG_UNUSED(dev); - ARG_UNUSED(pins); - - struct pcf8574_drv_data *drv_data = - CONTAINER_OF(gpio_cb, struct pcf8574_drv_data, int_gpio_cb); - - k_work_submit(&drv_data->work); -} - -/** - * @brief This function reads a value from the connected device - * - * @param dev Pointer to the device structure of a port. - * @param value Pointer to a variable where pin values will be stored. - * - * @retval 0 If successful. - * @retval Negative value for error code. - */ -static int pcf8574_port_get_raw(const struct device *dev, gpio_port_value_t *value) -{ - struct pcf8574_drv_data *drv_data = dev->data; - int rc; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - if ((~drv_data->pins_cfg.configured_as_outputs & (uint8_t)*value) != (uint8_t)*value) { - LOG_ERR("Pin(s) is/are configured as output which should be input."); - return -EOPNOTSUPP; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - /** - * Reading of the input port also clears the generated interrupt, - * thus the configured callbacks must be fired also here if needed. - */ - rc = pcf8574_process_input(dev, value); - - k_sem_give(&drv_data->lock); - - return rc; -} - -/** - * @brief This function realizes the write connection to the i2c device. - * - * @param dev A pointer to the device structure - * @param mask A mask of bits to set some bits to LOW or HIGH - * @param value The value which is written via i2c to the pfc8574's output pins - * @param toggle A way to toggle some bits with xor - * - * @retval 0 If successful. - * @retval Negative value for error code. - */ -static int pcf8574_port_set_raw(const struct device *dev, uint8_t mask, uint8_t value, - uint8_t toggle) -{ - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; - int rc = 0; - uint8_t tx_buf; - - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - if ((drv_data->pins_cfg.configured_as_outputs & value) != value) { - LOG_ERR("Pin(s) is/are configured as input which should be output."); - return -EOPNOTSUPP; - } - - tx_buf = (drv_data->pins_cfg.outputs_state & ~mask); - tx_buf |= (value & mask); - tx_buf ^= toggle; - - rc = i2c_write_dt(&drv_cfg->i2c, &tx_buf, sizeof(tx_buf)); - - if (rc != 0) { - LOG_ERR("%s: failed to write output port: %d", dev->name, rc); - return -EIO; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - drv_data->pins_cfg.outputs_state = tx_buf; - k_sem_give(&drv_data->lock); - - return 0; -} - -/** - * @brief This function fills a dummy because the pfc8574 has no pins to configure. - * You can use it to set some pins permanent to HIGH or LOW until reset. It uses the port_set_raw - * function to set the pins of pcf8574 directly. - * - * @param dev Pointer to the device structure for the driver instance. - * @param pin The bit in the io register which is set to high - * @param flags Flags like the GPIO direction or the state - * - * @retval 0 If successful. - * @retval Negative value for error. - */ -static int pcf8574_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) -{ - struct pcf8574_drv_data *drv_data = dev->data; - int ret = 0; - uint8_t temp_pins = drv_data->pins_cfg.outputs_state; - uint8_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; - - if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_DISCONNECTED | GPIO_SINGLE_ENDED)) { - return -ENOTSUP; - } - if (flags & GPIO_INPUT) { - temp_outputs &= ~BIT(pin); - temp_pins &= ~(1 << pin); - } else if (flags & GPIO_OUTPUT) { - drv_data->pins_cfg.configured_as_outputs |= BIT(pin); - temp_outputs = drv_data->pins_cfg.configured_as_outputs; - } - if (flags & GPIO_OUTPUT_INIT_HIGH) { - temp_pins |= (1 << pin); - } - if (flags & GPIO_OUTPUT_INIT_LOW) { - temp_pins &= ~(1 << pin); - } - - ret = pcf8574_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); - - if (ret == 0) { - k_sem_take(&drv_data->lock, K_FOREVER); - drv_data->pins_cfg.outputs_state = temp_pins; - drv_data->pins_cfg.configured_as_outputs = temp_outputs; - k_sem_give(&drv_data->lock); - } - - return ret; -} - -/** - * @brief Sets a value to the pins of pcf8574 - * - * @param dev Pointer to the device structure for the driver instance. - * @param mask The bit mask which bits should be set - * @param value The value which should be set - * - * @retval 0 If successful. - * @retval Negative value for error. - */ -static int pcf8574_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, - gpio_port_value_t value) -{ - return pcf8574_port_set_raw(dev, (uint8_t)mask, (uint8_t)value, 0); -} - -/** - * @brief Sets some output pins of the pcf8574 - * - * @param dev Pointer to the device structure for the driver instance. - * @param pins The pin(s) which will be set in a range from 0 to 7 - * - * @retval 0 If successful. - * @retval Negative value for error. - */ -static int pcf8574_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) -{ - return pcf8574_port_set_raw(dev, (uint8_t)pins, (uint8_t)pins, 0); -} - -/** - * @brief clear some bits - * - * @param dev Pointer to the device structure for the driver instance. - * @param pins Pins which will be cleared - * - * @retval 0 If successful. - * @retval Negative value for error. - */ -static int pcf8574_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) -{ - return pcf8574_port_set_raw(dev, (uint8_t)pins, 0, 0); -} - -/** - * @brief Toggle some bits - * - * @param dev Pointer to the device structure for the driver instance. - * @param pins Pins which will be toggled - * - * @retval 0 If successful. - * @retval Negative value for error. - */ -static int pcf8574_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) -{ - return pcf8574_port_set_raw(dev, 0, 0, (uint8_t)pins); -} - -/* Each pin gives an interrupt at pcf8574. In this function the configuration is checked. */ -static int pcf8574_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, - enum gpio_int_mode mode, enum gpio_int_trig trig) -{ - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - - if (!drv_cfg->gpio_int.port) { - return -ENOTSUP; - } - - /* This device supports only edge-triggered interrupts. */ - if (mode == GPIO_INT_MODE_LEVEL) { - return -ENOTSUP; - } - - return 0; -} - -/** Register the callback in the callback list */ -static int pcf8574_manage_callback(const struct device *dev, struct gpio_callback *callback, - bool set) -{ - struct pcf8574_drv_data *drv_data = dev->data; - - return gpio_manage_callback(&drv_data->callbacks, callback, set); -} - -/** Initialize the pcf8574 */ -static int pcf8574_init(const struct device *dev) -{ - const struct pcf8574_drv_cfg *drv_cfg = dev->config; - struct pcf8574_drv_data *drv_data = dev->data; - int rc; - - if (!device_is_ready(drv_cfg->i2c.bus)) { - LOG_ERR("%s is not ready", drv_cfg->i2c.bus->name); - return -ENODEV; - } - - /* If the INT line is available, configure the callback for it. */ - if (drv_cfg->gpio_int.port) { - if (!gpio_is_ready_dt(&drv_cfg->gpio_int)) { - LOG_ERR("Port is not ready"); - return -ENODEV; - } - - rc = gpio_pin_configure_dt(&drv_cfg->gpio_int, GPIO_INPUT); - if (rc != 0) { - LOG_ERR("%s: failed to configure INT line: %d", dev->name, rc); - return -EIO; - } - - rc = gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); - if (rc != 0) { - LOG_ERR("%s: failed to configure INT interrupt: %d", dev->name, rc); - return -EIO; - } - - gpio_init_callback(&drv_data->int_gpio_cb, pcf8574_int_gpio_handler, - BIT(drv_cfg->gpio_int.pin)); - rc = gpio_add_callback(drv_cfg->gpio_int.port, &drv_data->int_gpio_cb); - if (rc != 0) { - LOG_ERR("%s: failed to add INT callback: %d", dev->name, rc); - return -EIO; - } - } - - return 0; -} - -/** Realizes the functions of gpio.h for pcf8574*/ -static const struct gpio_driver_api pcf8574_drv_api = { - .pin_configure = pcf8574_pin_configure, - .port_get_raw = pcf8574_port_get_raw, - .port_set_masked_raw = pcf8574_port_set_masked_raw, - .port_set_bits_raw = pcf8574_port_set_bits_raw, - .port_clear_bits_raw = pcf8574_port_clear_bits_raw, - .port_toggle_bits = pcf8574_port_toggle_bits, - .pin_interrupt_configure = pcf8574_pin_interrupt_configure, - .manage_callback = pcf8574_manage_callback, -}; - -#define GPIO_PCF8574_INST(idx) \ - static const struct pcf8574_drv_cfg pcf8574_cfg##idx = { \ - .common = \ - { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ - }, \ - .gpio_int = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}), \ - .i2c = I2C_DT_SPEC_INST_GET(idx), \ - }; \ - static struct pcf8574_drv_data pcf8574_data##idx = { \ - .lock = Z_SEM_INITIALIZER(pcf8574_data##idx.lock, 1, 1), \ - .work = Z_WORK_INITIALIZER(pcf8574_work_handler), \ - .dev = DEVICE_DT_INST_GET(idx), \ - }; \ - DEVICE_DT_INST_DEFINE(idx, pcf8574_init, NULL, &pcf8574_data##idx, &pcf8574_cfg##idx, \ - POST_KERNEL, CONFIG_GPIO_PCF8574_INIT_PRIORITY, &pcf8574_drv_api); - -DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF8574_INST); diff --git a/drivers/gpio/gpio_pcf857x.c b/drivers/gpio/gpio_pcf857x.c new file mode 100644 index 00000000000..c30e1a5d36d --- /dev/null +++ b/drivers/gpio/gpio_pcf857x.c @@ -0,0 +1,408 @@ +/** + * Copyright (c) + * 2022 Ithinx GmbH + * 2023 Amrith Venkat Kesavamoorthi + * 2023 Mr Beam Lasers GmbH. + * + * SPDX-License-Identifier: Apache-2.0 + * + * @see https://www.nxp.com/docs/en/data-sheet/PCF8575.pdf + * @see https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf + */ + +#define DT_DRV_COMPAT nxp_pcf857x + +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(pcf857x, CONFIG_GPIO_LOG_LEVEL); + +struct pcf857x_pins_cfg { + uint16_t configured_as_outputs; /* 0 for input, 1 for output */ + uint16_t outputs_state; +}; + +/** Runtime driver data of the pcf857x*/ +struct pcf857x_drv_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + struct pcf857x_pins_cfg pins_cfg; + sys_slist_t callbacks; + struct k_sem lock; + struct k_work work; + const struct device *dev; + struct gpio_callback int_gpio_cb; + uint16_t input_port_last; + int num_bytes; +}; + +/** Configuration data*/ +struct pcf857x_drv_cfg { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + struct i2c_dt_spec i2c; + struct gpio_dt_spec gpio_int; +}; + +/** + * @brief Reads the value of the pins from pcf857x respectively from a connected device. + * + * @param dev Pointer to the device structure of the driver instance. + * @param value Pointer to the input value. It contains the received Bytes(receives 2 Bytes for P0 + * and P1). + * + * @retval 0 If successful. + * @retval Negative value for error code. + */ +static int pcf857x_process_input(const struct device *dev, gpio_port_value_t *value) +{ + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; + int rc = 0; + uint8_t rx_buf[2] = {0}; + + rc = i2c_read_dt(&drv_cfg->i2c, rx_buf, drv_data->num_bytes); + if (rc != 0) { + LOG_ERR("%s: failed to read from device: %d", dev->name, rc); + return -EIO; + } + + if (value) { + *value = sys_get_le16(rx_buf); /*format P17-P10..P07-P00 (bit15-bit8..bit7-bit0)*/ + } + + drv_data->input_port_last = sys_get_le16(rx_buf); + + return rc; +} + +/** Register the read-task as work*/ +static void pcf857x_work_handler(struct k_work *work) +{ + struct pcf857x_drv_data *drv_data = CONTAINER_OF(work, struct pcf857x_drv_data, work); + + k_sem_take(&drv_data->lock, K_FOREVER); + + uint32_t changed_pins; + uint16_t input_port_last_temp = drv_data->input_port_last; + int rc = pcf857x_process_input(drv_data->dev, &changed_pins); + + if (rc) { + LOG_ERR("Failed to read interrupt sources: %d", rc); + } + k_sem_give(&drv_data->lock); + if (input_port_last_temp != (uint16_t)changed_pins && !rc) { + + /** Find changed bits*/ + changed_pins ^= input_port_last_temp; + gpio_fire_callbacks(&drv_data->callbacks, drv_data->dev, changed_pins); + } +} + +/** Callback for interrupt through some level changes on pcf857x pins*/ +static void pcf857x_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb, + uint32_t pins) +{ + ARG_UNUSED(dev); + ARG_UNUSED(pins); + + struct pcf857x_drv_data *drv_data = + CONTAINER_OF(gpio_cb, struct pcf857x_drv_data, int_gpio_cb); + + k_work_submit(&drv_data->work); +} + +/** + * @brief This function reads a value from the connected device + * + * @param dev Pointer to the device structure of a port. + * @param value Pointer to a variable where pin values will be stored. + * + * @retval 0 If successful. + * @retval Negative value for error code. + */ +static int pcf857x_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + struct pcf857x_drv_data *drv_data = dev->data; + int rc; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if ((~drv_data->pins_cfg.configured_as_outputs & (uint16_t)*value) != (uint16_t)*value) { + LOG_ERR("Pin(s) is/are configured as output which should be input."); + return -EOPNOTSUPP; + } + + k_sem_take(&drv_data->lock, K_FOREVER); + + /** + * Reading of the input port also clears the generated interrupt, + * thus the configured callbacks must be fired also here if needed. + */ + rc = pcf857x_process_input(dev, value); + + k_sem_give(&drv_data->lock); + + return rc; +} + +/** + * @brief This function realizes the write connection to the i2c device. + * + * @param dev A pointer to the device structure + * @param mask A mask of bits to set some bits to LOW or HIGH + * @param value The value which is written via i2c to the pcf857x's output pins + * @param toggle A way to toggle some bits with xor + * + * @retval 0 If successful. + * @retval Negative value for error code. + */ +static int pcf857x_port_set_raw(const struct device *dev, uint16_t mask, uint16_t value, + uint16_t toggle) +{ + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; + int rc = 0; + uint16_t tx_buf; + uint8_t tx_buf_p[2]; + + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + if ((drv_data->pins_cfg.configured_as_outputs & value) != value) { + LOG_ERR("Pin(s) is/are configured as input which should be output."); + return -EOPNOTSUPP; + } + + tx_buf = (drv_data->pins_cfg.outputs_state & ~mask); + tx_buf |= (value & mask); + tx_buf ^= toggle; + sys_put_le16(tx_buf, tx_buf_p); + + rc = i2c_write_dt(&drv_cfg->i2c, tx_buf_p, drv_data->num_bytes); + if (rc != 0) { + LOG_ERR("%s: failed to write output port: %d", dev->name, rc); + return -EIO; + } + k_sem_take(&drv_data->lock, K_FOREVER); + drv_data->pins_cfg.outputs_state = tx_buf; + k_sem_give(&drv_data->lock); + + return 0; +} + +/** + * @brief This function fills a dummy because the pcf857x has no pins to configure. + * You can use it to set some pins permanent to HIGH or LOW until reset. It uses the port_set_raw + * function to set the pins of pcf857x directly. + * + * @param dev Pointer to the device structure for the driver instance. + * @param pin The bit in the io register which is set to high + * @param flags Flags like the GPIO direction or the state + * + * @retval 0 If successful. + * @retval Negative value for error. + */ +static int pcf857x_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + struct pcf857x_drv_data *drv_data = dev->data; + int ret = 0; + uint16_t temp_pins = drv_data->pins_cfg.outputs_state; + uint16_t temp_outputs = drv_data->pins_cfg.configured_as_outputs; + + if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_DISCONNECTED | GPIO_SINGLE_ENDED)) { + return -ENOTSUP; + } + if (flags & GPIO_INPUT) { + temp_outputs &= ~BIT(pin); + temp_pins &= ~(1 << pin); + } else if (flags & GPIO_OUTPUT) { + drv_data->pins_cfg.configured_as_outputs |= BIT(pin); + temp_outputs = drv_data->pins_cfg.configured_as_outputs; + } + if (flags & GPIO_OUTPUT_INIT_HIGH) { + temp_pins |= (1 << pin); + } + if (flags & GPIO_OUTPUT_INIT_LOW) { + temp_pins &= ~(1 << pin); + } + + ret = pcf857x_port_set_raw(dev, drv_data->pins_cfg.configured_as_outputs, temp_pins, 0); + + if (ret == 0) { + k_sem_take(&drv_data->lock, K_FOREVER); + drv_data->pins_cfg.outputs_state = temp_pins; + drv_data->pins_cfg.configured_as_outputs = temp_outputs; + k_sem_give(&drv_data->lock); + } + + return ret; +} + +/** + * @brief Sets a value to the pins of pcf857x + * + * @param dev Pointer to the device structure for the driver instance. + * @param mask The bit mask which bits should be set + * @param value The value which should be set + * + * @retval 0 If successful. + * @retval Negative value for error. + */ +static int pcf857x_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + return pcf857x_port_set_raw(dev, (uint16_t)mask, (uint16_t)value, 0); +} + +/** + * @brief Sets some output pins of the pcf857x + * + * @param dev Pointer to the device structure for the driver instance. + * @param pins The pin(s) which will be set in a range from P17-P10..P07-P00 + * + * @retval 0 If successful. + * @retval Negative value for error. + */ +static int pcf857x_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + return pcf857x_port_set_raw(dev, (uint16_t)pins, (uint16_t)pins, 0); +} + +/** + * @brief clear some bits + * + * @param dev Pointer to the device structure for the driver instance. + * @param pins Pins which will be cleared + * + * @retval 0 If successful. + * @retval Negative value for error. + */ +static int pcf857x_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + return pcf857x_port_set_raw(dev, (uint16_t)pins, 0, 0); +} + +/** + * @brief Toggle some bits + * + * @param dev Pointer to the device structure for the driver instance. + * @param pins Pins which will be toggled + * + * @retval 0 If successful. + * @retval Negative value for error. + */ +static int pcf857x_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + return pcf857x_port_set_raw(dev, 0, 0, (uint16_t)pins); +} + +/* Each pin gives an interrupt at pcf857x. In this function the configuration is checked. */ +static int pcf857x_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + + if (!drv_cfg->gpio_int.port) { + return -ENOTSUP; + } + + /* This device supports only edge-triggered interrupts. */ + if (mode == GPIO_INT_MODE_LEVEL) { + return -ENOTSUP; + } + + return 0; +} + +/** Register the callback in the callback list */ +static int pcf857x_manage_callback(const struct device *dev, struct gpio_callback *callback, + bool set) +{ + struct pcf857x_drv_data *drv_data = dev->data; + + return gpio_manage_callback(&drv_data->callbacks, callback, set); +} + +/** Initialize the pcf857x */ +static int pcf857x_init(const struct device *dev) +{ + const struct pcf857x_drv_cfg *drv_cfg = dev->config; + struct pcf857x_drv_data *drv_data = dev->data; + int rc; + + if (!device_is_ready(drv_cfg->i2c.bus)) { + LOG_ERR("%s is not ready", drv_cfg->i2c.bus->name); + return -ENODEV; + } + + /* If the INT line is available, configure the callback for it. */ + if (drv_cfg->gpio_int.port) { + if (!gpio_is_ready_dt(&drv_cfg->gpio_int)) { + LOG_ERR("Port is not ready"); + return -ENODEV; + } + + rc = gpio_pin_configure_dt(&drv_cfg->gpio_int, GPIO_INPUT); + if (rc != 0) { + LOG_ERR("%s: failed to configure INT line: %d", dev->name, rc); + return -EIO; + } + + rc = gpio_pin_interrupt_configure_dt(&drv_cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE); + if (rc != 0) { + LOG_ERR("%s: failed to configure INT interrupt: %d", dev->name, rc); + return -EIO; + } + + gpio_init_callback(&drv_data->int_gpio_cb, pcf857x_int_gpio_handler, + BIT(drv_cfg->gpio_int.pin)); + rc = gpio_add_callback(drv_cfg->gpio_int.port, &drv_data->int_gpio_cb); + if (rc != 0) { + LOG_ERR("%s: failed to add INT callback: %d", dev->name, rc); + return -EIO; + } + } + + return 0; +} + +/** Realizes the functions of gpio.h for pcf857x*/ +static const struct gpio_driver_api pcf857x_drv_api = { + .pin_configure = pcf857x_pin_configure, + .port_get_raw = pcf857x_port_get_raw, + .port_set_masked_raw = pcf857x_port_set_masked_raw, + .port_set_bits_raw = pcf857x_port_set_bits_raw, + .port_clear_bits_raw = pcf857x_port_clear_bits_raw, + .port_toggle_bits = pcf857x_port_toggle_bits, + .pin_interrupt_configure = pcf857x_pin_interrupt_configure, + .manage_callback = pcf857x_manage_callback, +}; + +#define GPIO_PCF857X_INST(idx) \ + static const struct pcf857x_drv_cfg pcf857x_cfg##idx = { \ + .common = \ + { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx), \ + }, \ + .gpio_int = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}), \ + .i2c = I2C_DT_SPEC_INST_GET(idx), \ + }; \ + static struct pcf857x_drv_data pcf857x_data##idx = { \ + .lock = Z_SEM_INITIALIZER(pcf857x_data##idx.lock, 1, 1), \ + .work = Z_WORK_INITIALIZER(pcf857x_work_handler), \ + .dev = DEVICE_DT_INST_GET(idx), \ + .num_bytes = DT_INST_ENUM_IDX(idx, ngpios) + 1, \ + }; \ + DEVICE_DT_INST_DEFINE(idx, pcf857x_init, NULL, &pcf857x_data##idx, &pcf857x_cfg##idx, \ + POST_KERNEL, CONFIG_GPIO_PCF857X_INIT_PRIORITY, &pcf857x_drv_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_PCF857X_INST); diff --git a/drivers/gpio/gpio_rcar.c b/drivers/gpio/gpio_rcar.c index 820db5fc76c..f60112427bc 100644 --- a/drivers/gpio/gpio_rcar.c +++ b/drivers/gpio/gpio_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 IoT.bzh + * Copyright (c) 2020-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,7 @@ struct gpio_rcar_data { #define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ #define OUTDTSEL 0x40 /* Output Data Select Register */ #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ +#define INEN 0x50 /* General Input Enable Register */ static inline uint32_t gpio_rcar_read(const struct device *dev, uint32_t offs) { @@ -106,6 +107,11 @@ static void gpio_rcar_config_general_input_output_mode( /* Configure positive logic in POSNEG */ gpio_rcar_modify_bit(dev, POSNEG, gpio, false); + /* Select "Input Enable/Disable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, gpio, !output); +#endif + /* Select "General Input/Output Mode" in IOINTSEL */ gpio_rcar_modify_bit(dev, IOINTSEL, gpio, false); @@ -223,6 +229,11 @@ static int gpio_rcar_pin_interrupt_configure(const struct device *dev, gpio_rcar_modify_bit(dev, BOTHEDGE, pin, true); } + /* Select "Input Enable" in INEN for Gen4 SoCs */ +#ifdef CONFIG_SOC_SERIES_RCAR_GEN4 + gpio_rcar_modify_bit(dev, INEN, pin, true); +#endif + gpio_rcar_modify_bit(dev, IOINTSEL, pin, true); if (mode == GPIO_INT_MODE_EDGE) { diff --git a/drivers/gpio/gpio_ra.c b/drivers/gpio/gpio_renesas_ra.c similarity index 100% rename from drivers/gpio/gpio_ra.c rename to drivers/gpio/gpio_renesas_ra.c diff --git a/drivers/gpio/gpio_sifive.c b/drivers/gpio/gpio_sifive.c index 77703f25707..7e56b9dba3e 100644 --- a/drivers/gpio/gpio_sifive.c +++ b/drivers/gpio/gpio_sifive.c @@ -18,7 +18,7 @@ #include #include #include - +#include #include typedef void (*sifive_cfg_func_t)(void); @@ -145,10 +145,6 @@ static int gpio_sifive_config(const struct device *dev, { volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev); - if (pin >= SIFIVE_PINMUX_PINS) { - return -EINVAL; - } - /* We cannot support open-source open-drain configuration */ if ((flags & GPIO_SINGLE_ENDED) != 0) { return -ENOTSUP; diff --git a/drivers/gpio/gpio_stm32.c b/drivers/gpio/gpio_stm32.c index 877dbb4882c..e2cdb1d5325 100644 --- a/drivers/gpio/gpio_stm32.c +++ b/drivers/gpio/gpio_stm32.c @@ -524,9 +524,11 @@ static int gpio_stm32_config(const struct device *dev, } /* Enable device clock before configuration (requires bank writes) */ - err = pm_device_runtime_get(dev); - if (err < 0) { - return err; + if (((flags & GPIO_OUTPUT) != 0) || ((flags & GPIO_INPUT) != 0)) { + err = pm_device_runtime_get(dev); + if (err < 0) { + return err; + } } if ((flags & GPIO_OUTPUT) != 0) { @@ -719,7 +721,9 @@ static int gpio_stm32_init(const struct device *dev) return ret; } - pm_device_init_suspended(dev); + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_init_suspended(dev); + } (void)pm_device_runtime_enable(dev); return 0; diff --git a/drivers/gpio/gpio_tle9104.c b/drivers/gpio/gpio_tle9104.c index 072828dec88..47a899e1615 100644 --- a/drivers/gpio/gpio_tle9104.c +++ b/drivers/gpio/gpio_tle9104.c @@ -75,6 +75,8 @@ struct tle9104_data { /* each bit defines if the output channel is configured, see state */ uint8_t configured; struct k_mutex lock; + /* communication watchdog is getting ignored */ + bool cwd_ignore; }; static void tle9104_set_cfg_cwdtime(uint8_t *destination, uint8_t value) @@ -116,6 +118,7 @@ static int tle9104_transceive_frame(const struct device *dev, bool write, enum tle9104_register *read_reg, uint8_t *read_data) { const struct tle9104_config *config = dev->config; + struct tle9104_data *data = dev->data; uint16_t write_frame; uint16_t read_frame; int result; @@ -160,8 +163,10 @@ static int tle9104_transceive_frame(const struct device *dev, bool write, return -EIO; } - if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) { - LOG_WRN("communication fault reported by TLE9104"); + if (!data->cwd_ignore) { + if ((TLE9104_SPIFRAME_FAULTCOMMUNICATION_BIT & read_frame) != 0) { + LOG_WRN("%s: communication fault reported by TLE9104", dev->name); + } } *read_reg = FIELD_GET(GENMASK(TLE9104_FRAME_FAULTGLOBAL_POS - 1, TLE9104_FRAME_ADDRESS_POS), @@ -249,7 +254,7 @@ static int tle9104_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_ } if (pin >= TLE9104_GPIO_COUNT) { - LOG_ERR("invalid pin nummber %i", pin); + LOG_ERR("invalid pin number %i", pin); return -EINVAL; } @@ -385,6 +390,8 @@ static int tle9104_init(const struct device *dev) LOG_DBG("initialize TLE9104 instance %s", dev->name); + data->cwd_ignore = true; + result = k_mutex_init(&data->lock); if (result != 0) { LOG_ERR("unable to initialize mutex"); @@ -408,8 +415,8 @@ static int tle9104_init(const struct device *dev) register_cfg |= TLE9104_CFG_OUT1DD_BIT << i; - if (!device_is_ready(current->port)) { - LOG_ERR("control GPIO %s is not ready", current->port->name); + if (!gpio_is_ready_dt(current)) { + LOG_ERR("%s: control GPIO is not ready", dev->name); return -ENODEV; } @@ -421,8 +428,8 @@ static int tle9104_init(const struct device *dev) } if (config->gpio_enable.port != NULL) { - if (!device_is_ready(config->gpio_enable.port)) { - LOG_ERR("enable GPIO %s is not ready", config->gpio_enable.port->name); + if (!gpio_is_ready_dt(&config->gpio_enable)) { + LOG_ERR("%s: enable GPIO is not ready", dev->name); return -ENODEV; } @@ -433,16 +440,23 @@ static int tle9104_init(const struct device *dev) } } - result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); - if (result != 0) { - LOG_ERR("failed to initialize GPIO for reset"); - return result; - } + if (config->gpio_reset.port != NULL) { + if (!gpio_is_ready_dt(&config->gpio_reset)) { + LOG_ERR("%s: reset GPIO is not yet ready", dev->name); + return -ENODEV; + } - k_busy_wait(TLE9104_RESET_DURATION_TIME_US); - gpio_pin_set_dt(&config->gpio_reset, 0); - k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US + - TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US); + result = gpio_pin_configure_dt(&config->gpio_reset, GPIO_OUTPUT_ACTIVE); + if (result != 0) { + LOG_ERR("failed to initialize GPIO for reset"); + return result; + } + + k_busy_wait(TLE9104_RESET_DURATION_TIME_US); + gpio_pin_set_dt(&config->gpio_reset, 0); + k_busy_wait(TLE9104_RESET_DURATION_WAIT_TIME_US + + TLE9104_RESET_DURATION_WAIT_TIME_SAFETY_MARGIN_US); + } /* * The first read value should be the ICVID, this acts also as the setup of the @@ -498,6 +512,8 @@ static int tle9104_init(const struct device *dev) return result; } + data->cwd_ignore = false; + return 0; } @@ -516,7 +532,7 @@ BUILD_ASSERT(CONFIG_GPIO_TLE9104_INIT_PRIORITY > CONFIG_SPI_INIT_PRIORITY, .bus = SPI_DT_SPEC_INST_GET( \ inst, SPI_OP_MODE_MASTER | SPI_MODE_CPHA | SPI_WORD_SET(8), 0), \ .gpio_enable = TLE9104_INIT_GPIO_FIELDS(inst, en_gpios), \ - .gpio_reset = GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), resn_gpios, 0), \ + .gpio_reset = TLE9104_INIT_GPIO_FIELDS(inst, resn_gpios), \ .gpio_control = { \ TLE9104_INIT_GPIO_FIELDS(inst, in1_gpios), \ TLE9104_INIT_GPIO_FIELDS(inst, in2_gpios), \ diff --git a/drivers/hwinfo/CMakeLists.txt b/drivers/hwinfo/CMakeLists.txt index 437fbf969cf..ab3b587dc75 100644 --- a/drivers/hwinfo/CMakeLists.txt +++ b/drivers/hwinfo/CMakeLists.txt @@ -25,5 +25,6 @@ zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM_RSTC hwinfo_sam_rstc.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM hwinfo_sam.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM0 hwinfo_sam0.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_SAM4L hwinfo_sam4l.c) +zephyr_library_sources_ifdef(CONFIG_HWINFO_SMARTBOND hwinfo_smartbond.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_STM32 hwinfo_stm32.c) zephyr_library_sources_ifdef(CONFIG_HWINFO_ANDES hwinfo_andes.c) diff --git a/drivers/hwinfo/Kconfig b/drivers/hwinfo/Kconfig index 7c4cc7f0805..84afbefd84f 100644 --- a/drivers/hwinfo/Kconfig +++ b/drivers/hwinfo/Kconfig @@ -149,6 +149,13 @@ config HWINFO_SAM0 help Enable Atmel SAM0 hwinfo driver. +config HWINFO_SMARTBOND + bool "Smartbond device reset cause" + default y + depends on SOC_FAMILY_SMARTBOND + help + Enable Smartbond reset cause hwinfo driver. + config HWINFO_ESP32 bool "ESP32 device ID" default y @@ -181,7 +188,7 @@ config HWINFO_GECKO config HWINFO_ANDES bool "Andes system ID" default y - depends on SOC_SERIES_RISCV_ANDES_V5 + depends on SOC_FAMILY_ANDES_V5 help Enable Andes hwinfo driver diff --git a/drivers/hwinfo/hwinfo_esp32.c b/drivers/hwinfo/hwinfo_esp32.c index df4d6732112..131c3fac0c5 100644 --- a/drivers/hwinfo/hwinfo_esp32.c +++ b/drivers/hwinfo/hwinfo_esp32.c @@ -15,7 +15,7 @@ ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length) { -#if !defined(CONFIG_SOC_SERIES_ESP32) && !defined(CONFIG_SOC_SERIES_ESP32_NET) +#if !defined(CONFIG_SOC_SERIES_ESP32) uint32_t rdata1 = sys_read32(EFUSE_RD_MAC_SPI_SYS_0_REG); uint32_t rdata2 = sys_read32(EFUSE_RD_MAC_SPI_SYS_1_REG); #else diff --git a/drivers/hwinfo/hwinfo_nrf.c b/drivers/hwinfo/hwinfo_nrf.c index 2a79f1d0c0d..4375cf05b2f 100644 --- a/drivers/hwinfo/hwinfo_nrf.c +++ b/drivers/hwinfo/hwinfo_nrf.c @@ -58,22 +58,56 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) if (reason & NRFX_RESET_REASON_DIF_MASK) { flags |= RESET_DEBUG; } + if (reason & NRFX_RESET_REASON_SREQ_MASK) { + flags |= RESET_SOFTWARE; + } -#if !NRF_POWER_HAS_RESETREAS +#if NRFX_RESET_REASON_HAS_CTRLAP if (reason & NRFX_RESET_REASON_CTRLAP_MASK) { flags |= RESET_DEBUG; } - if (reason & NRFX_RESET_REASON_DOG0_MASK) { - flags |= RESET_WATCHDOG; +#endif +#if NRFX_RESET_REASON_HAS_LPCOMP + if (reason & NRFX_RESET_REASON_LPCOMP_MASK) { + flags |= RESET_LOW_POWER_WAKE; + } +#endif +#if NRFX_RESET_REASON_HAS_NFC + if (reason & NRFX_RESET_REASON_NFC_MASK) { + flags |= RESET_LOW_POWER_WAKE; + } +#endif +#if NRFX_RESET_REASON_HAS_VBUS + if (reason & NRFX_RESET_REASON_VBUS_MASK) { + flags |= RESET_POR; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPSOFT + if (reason & NRFX_RESET_REASON_CTRLAPSOFT_MASK) { + flags |= RESET_DEBUG; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPHARD + if (reason & NRFX_RESET_REASON_CTRLAPHARD_MASK) { + flags |= RESET_DEBUG; + } +#endif +#if NRFX_RESET_REASON_HAS_CTRLAPPIN + if (reason & NRFX_RESET_REASON_CTRLAPPIN_MASK) { + flags |= RESET_DEBUG; } +#endif +#if !NRF_POWER_HAS_RESETREAS if (reason & NRFX_RESET_REASON_DOG1_MASK) { flags |= RESET_WATCHDOG; } - if (reason & NRFX_RESETREAS_SREQ_MASK) { - flags |= RESET_SOFTWARE; +#endif +#if NRFX_RESET_REASON_HAS_GRTC + if (reason & NRFX_RESET_REASON_GRTC_MASK) { + flags |= RESET_CLOCK; } - -#if NRF_RESET_HAS_NETWORK +#endif +#if NRFX_RESET_REASON_HAS_NETWORK if (reason & NRFX_RESET_REASON_LSREQ_MASK) { flags |= RESET_SOFTWARE; } @@ -87,10 +121,14 @@ int z_impl_hwinfo_get_reset_cause(uint32_t *cause) flags |= RESET_DEBUG; } #endif - -#else - if (reason & NRFX_RESET_REASON_SREQ_MASK) { - flags |= RESET_SOFTWARE; +#if defined(NRFX_RESET_REASON_TAMPC_MASK) + if (reason & NRFX_RESET_REASON_TAMPC_MASK) { + flags |= RESET_SECURITY; + } +#endif +#if defined(NRFX_RESET_REASON_SECTAMPER_MASK) + if (reason & NRFX_RESET_REASON_SECTAMPER_MASK) { + flags |= RESET_SECURITY; } #endif diff --git a/drivers/hwinfo/hwinfo_smartbond.c b/drivers/hwinfo/hwinfo_smartbond.c new file mode 100644 index 00000000000..f19c7770d60 --- /dev/null +++ b/drivers/hwinfo/hwinfo_smartbond.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Jerzy Kasenberg. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int z_impl_hwinfo_get_reset_cause(uint32_t *cause) +{ + int ret = 0; + uint32_t reason = CRG_TOP->RESET_STAT_REG; + uint32_t flags = 0; + + /* + * When POR is detected other bits are not valid. + */ + if (reason & CRG_TOP_RESET_STAT_REG_PORESET_STAT_Msk) { + flags = RESET_POR; + } else { + if (reason & CRG_TOP_RESET_STAT_REG_HWRESET_STAT_Msk) { + flags |= RESET_PIN; + } + if (reason & CRG_TOP_RESET_STAT_REG_SWRESET_STAT_Msk) { + flags |= RESET_SOFTWARE; + } + if (reason & CRG_TOP_RESET_STAT_REG_WDOGRESET_STAT_Msk) { + flags |= RESET_WATCHDOG; + } + if (reason & CRG_TOP_RESET_STAT_REG_CMAC_WDOGRESET_STAT_Msk) { + flags |= RESET_WATCHDOG; + } + if (reason & CRG_TOP_RESET_STAT_REG_SWD_HWRESET_STAT_Msk) { + flags |= RESET_DEBUG; + } + } + + *cause = flags; + + return ret; +} + +int z_impl_hwinfo_clear_reset_cause(void) +{ + int ret = 0; + + CRG_TOP->RESET_STAT_REG = 0; + + return ret; +} + +int z_impl_hwinfo_get_supported_reset_cause(uint32_t *supported) +{ + *supported = (RESET_PIN + | RESET_SOFTWARE + | RESET_POR + | RESET_WATCHDOG + | RESET_DEBUG); + + return 0; +} diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index f7f363ed8d4..fe96c112202 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -6,10 +6,7 @@ zephyr_library() zephyr_library_sources(i2c_common.c) -if(CONFIG_I2C_RTIO) -zephyr_library_sources(i2c_rtio.c) -zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs_rtio.c) -else() +zephyr_library_sources_ifdef(CONFIG_I2C_RTIO i2c_rtio.c) zephyr_library_sources_ifdef(CONFIG_I2C_SHELL i2c_shell.c) zephyr_library_sources_ifdef(CONFIG_I2C_BITBANG i2c_bitbang.c) zephyr_library_sources_ifdef(CONFIG_I2C_TELINK_B91 i2c_b91.c) @@ -29,7 +26,11 @@ zephyr_library_sources_ifdef(CONFIG_I2C_EMUL i2c_emul.c) zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWI i2c_nrfx_twi.c) zephyr_library_sources_ifdef(CONFIG_I2C_NRFX_TWIM i2c_nrfx_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c) -zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs.c) +if(CONFIG_RTIO) + zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs_rtio.c) +else() + zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIHS i2c_sam_twihs.c) +endif() zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWIM i2c_sam4l_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_SBCON i2c_sbcon.c) zephyr_library_sources_ifdef(CONFIG_I2C_SIFIVE i2c_sifive.c) @@ -55,6 +56,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_MCHP_MSS i2c_mchp_mss.c) zephyr_library_sources_ifdef(CONFIG_I2C_SEDI i2c_sedi.c) zephyr_library_sources_ifdef(CONFIG_I2C_AMBIQ i2c_ambiq.c) zephyr_library_sources_ifdef(CONFIG_GPIO_I2C_SWITCH gpio_i2c_switch.c) +zephyr_library_sources_ifdef(CONFIG_I2C_NUMAKER i2c_numaker.c) zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V1 i2c_ll_stm32_v1.c @@ -64,7 +66,6 @@ zephyr_library_sources_ifdef(CONFIG_I2C_STM32_V2 i2c_ll_stm32_v2.c i2c_ll_stm32.c ) -endif() zephyr_library_sources_ifdef(CONFIG_I2C_TEST i2c_test.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 233879167c6..86e9cd87934 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -92,6 +92,8 @@ source "drivers/i2c/Kconfig.xilinx_axi" source "drivers/i2c/Kconfig.mchp_mss" source "drivers/i2c/Kconfig.sedi" source "drivers/i2c/Kconfig.ambiq" +source "drivers/i2c/Kconfig.numaker" +source "drivers/i2c/Kconfig.mcux" config I2C_INIT_PRIORITY int "Init priority" diff --git a/drivers/i2c/Kconfig.dw b/drivers/i2c/Kconfig.dw index c84215f4571..796cfb643d1 100644 --- a/drivers/i2c/Kconfig.dw +++ b/drivers/i2c/Kconfig.dw @@ -18,6 +18,6 @@ config I2C_DW_LPSS_DMA select DMA select DMA_INTEL_LPSS help - This option enables I2C DMA feature to be used for asynchrounous - data transfers. All Tx operaton are done using dma channel 0 and + This option enables I2C DMA feature to be used for asynchronous + data transfers. All Tx operations are done using dma channel 0 and all Rx operations are done using dma channel 1. diff --git a/drivers/i2c/Kconfig.mcux b/drivers/i2c/Kconfig.mcux new file mode 100644 index 00000000000..7c519abac3b --- /dev/null +++ b/drivers/i2c/Kconfig.mcux @@ -0,0 +1,14 @@ +# I2C configuration options + +# Copyright (c) 2024, NXP +# SPDX-License-Identifier: Apache-2.0 + +config I2C_NXP_TRANSFER_TIMEOUT + int "Transfer timeout [ms]" + default 0 + help + Timeout in milliseconds used for each I2C transfer. + 0 means that the driver should use the K_FOREVER value, + i.e. it should wait as long as necessary. + In conjunction with this, FSL_FEATURE_I2C_TIMEOUT_RECOVERY + must be enabled to allow the driver to fully recover. diff --git a/drivers/i2c/Kconfig.numaker b/drivers/i2c/Kconfig.numaker new file mode 100644 index 00000000000..622592cd020 --- /dev/null +++ b/drivers/i2c/Kconfig.numaker @@ -0,0 +1,14 @@ +# NUMAKER I2C driver configuration options + +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config I2C_NUMAKER + bool "Nuvoton NuMaker I2C driver" + default y + select HAS_NUMAKER_I2C + depends on DT_HAS_NUVOTON_NUMAKER_I2C_ENABLED + help + This option enables I2C driver for Nuvoton NuMaker family of + processors. + Say y if you wish to enable NuMaker I2C. diff --git a/drivers/i2c/gpio_i2c_switch.c b/drivers/i2c/gpio_i2c_switch.c index 07183d82e62..d5a125a531b 100644 --- a/drivers/i2c/gpio_i2c_switch.c +++ b/drivers/i2c/gpio_i2c_switch.c @@ -64,7 +64,7 @@ static int gpio_i2c_switch_transfer(const struct device *dev, struct i2c_msg *ms return res; } -const struct i2c_driver_api gpio_i2c_switch_api_funcs = { +static const struct i2c_driver_api gpio_i2c_switch_api_funcs = { .configure = gpio_i2c_switch_configure, .transfer = gpio_i2c_switch_transfer, }; diff --git a/drivers/i2c/i2c_ambiq.c b/drivers/i2c/i2c_ambiq.c index 432bfbe4f00..e8b62fb2c45 100644 --- a/drivers/i2c/i2c_ambiq.c +++ b/drivers/i2c/i2c_ambiq.c @@ -139,7 +139,7 @@ static int i2c_ambiq_init(const struct device *dev) ret = config->pwr_func(); - ret = i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | I2C_SPEED_SET(bitrate_cfg)); + ret = i2c_ambiq_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); @@ -152,7 +152,7 @@ static int i2c_ambiq_init(const struct device *dev) return ret; } -static struct i2c_driver_api i2c_ambiq_driver_api = { +static const struct i2c_driver_api i2c_ambiq_driver_api = { .configure = i2c_ambiq_configure, .transfer = i2c_ambiq_transfer, }; diff --git a/drivers/i2c/i2c_andes_atciic100.h b/drivers/i2c/i2c_andes_atciic100.h index 1aa0ff6f397..9312427ee8e 100644 --- a/drivers/i2c/i2c_andes_atciic100.h +++ b/drivers/i2c/i2c_andes_atciic100.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index ca4485606b7..b198aa15c1b 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -74,9 +74,10 @@ void cb_i2c_idma_transfer(const struct device *dma, void *user_data, uint32_t channel, int status) { const struct device *dev = (const struct device *)user_data; + const struct i2c_dw_rom_config * const rom = dev->config; struct i2c_dw_dev_config *const dw = dev->data; - dma_stop(dw->dma_dev, channel); + dma_stop(rom->dma_dev, channel); i2c_dw_enable_idma(dev, false); if (status) { @@ -104,11 +105,12 @@ inline void *i2c_dw_dr_phy_addr(const struct device *dev) int32_t i2c_dw_idma_rx_transfer(const struct device *dev) { struct i2c_dw_dev_config *const dw = dev->data; + const struct i2c_dw_rom_config * const rom = dev->config; struct dma_config dma_cfg = { 0 }; struct dma_block_config dma_block_cfg = { 0 }; - if (!device_is_ready(dw->dma_dev)) { + if (!device_is_ready(rom->dma_dev)) { LOG_DBG("DMA device is not ready"); return -ENODEV; } @@ -131,12 +133,12 @@ int32_t i2c_dw_idma_rx_transfer(const struct device *dev) dma_block_cfg.source_address = (uint64_t)i2c_dw_dr_phy_addr(dev); dw->xfr_status = false; - if (dma_config(dw->dma_dev, DMA_INTEL_LPSS_RX_CHAN, &dma_cfg)) { + if (dma_config(rom->dma_dev, DMA_INTEL_LPSS_RX_CHAN, &dma_cfg)) { LOG_DBG("Error transfer"); return -EIO; } - if (dma_start(dw->dma_dev, DMA_INTEL_LPSS_RX_CHAN)) { + if (dma_start(rom->dma_dev, DMA_INTEL_LPSS_RX_CHAN)) { LOG_DBG("Error transfer"); return -EIO; } @@ -150,12 +152,13 @@ int32_t i2c_dw_idma_rx_transfer(const struct device *dev) int32_t i2c_dw_idma_tx_transfer(const struct device *dev, uint64_t data) { + const struct i2c_dw_rom_config * const rom = dev->config; struct i2c_dw_dev_config *const dw = dev->data; struct dma_config dma_cfg = { 0 }; struct dma_block_config dma_block_cfg = { 0 }; - if (!device_is_ready(dw->dma_dev)) { + if (!device_is_ready(rom->dma_dev)) { LOG_DBG("DMA device is not ready"); return -ENODEV; } @@ -178,13 +181,13 @@ int32_t i2c_dw_idma_tx_transfer(const struct device *dev, dma_block_cfg.dest_address = (uint64_t)i2c_dw_dr_phy_addr(dev); dw->xfr_status = false; - if (dma_config(dw->dma_dev, DMA_INTEL_LPSS_TX_CHAN, &dma_cfg)) { + if (dma_config(rom->dma_dev, DMA_INTEL_LPSS_TX_CHAN, &dma_cfg)) { LOG_DBG("Error transfer"); return -EIO; } - if (dma_start(dw->dma_dev, DMA_INTEL_LPSS_TX_CHAN)) { - LOG_DBG("Error trnasfer"); + if (dma_start(rom->dma_dev, DMA_INTEL_LPSS_TX_CHAN)) { + LOG_DBG("Error transfer"); return -EIO; } i2c_dw_enable_idma(dev, true); @@ -198,10 +201,10 @@ static inline void i2c_dw_data_ask(const struct device *dev) { struct i2c_dw_dev_config * const dw = dev->data; uint32_t data; - uint8_t tx_empty; - int8_t rx_empty; - uint8_t cnt; - uint8_t rx_buffer_depth, tx_buffer_depth; + int tx_empty; + int rx_empty; + int cnt; + int rx_buffer_depth, tx_buffer_depth; union ic_comp_param_1_register ic_comp_param_1; uint32_t reg_base = get_regs(dev); @@ -390,8 +393,9 @@ static void i2c_dw_isr(const struct device *port) uint32_t stat = sys_read32(reg_base + IDMA_REG_INTR_STS); if (stat & IDMA_TX_RX_CHAN_MASK) { + const struct i2c_dw_rom_config * const rom = port->config; /* Handle the DMA interrupt */ - dma_intel_lpss_isr(dw->dma_dev); + dma_intel_lpss_isr(rom->dma_dev); } #endif @@ -905,7 +909,7 @@ static int i2c_dw_set_slave_mode(const struct device *dev, uint8_t addr) write_tx_tl(0, reg_base); write_rx_tl(0, reg_base); - LOG_DBG("I2C: Host registed as Slave Device"); + LOG_DBG("I2C: Host registered as Slave Device"); return 0; } @@ -1049,11 +1053,11 @@ static int i2c_dw_initialize(const struct device *dev) pcie_set_cmd(rom->pcie->bdf, PCIE_CONF_CMDSTAT_MASTER, true); #ifdef CONFIG_I2C_DW_LPSS_DMA - size_t nhdls = 0; - const device_handle_t *hdls; + uintptr_t base; - hdls = device_supported_handles_get(dev, &nhdls); - dw->dma_dev = device_from_handle(*hdls); + base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; + dma_intel_lpss_set_base(rom->dma_dev, base); + dma_intel_lpss_setup(rom->dma_dev); /* Assign physical & virtual address to dma instance */ dw->phy_addr = mbar.phys_addr; @@ -1184,6 +1188,12 @@ static int i2c_dw_initialize(const struct device *dev) #define I2C_CONFIG_REG_INIT(n) \ _CONCAT(I2C_CONFIG_REG_INIT_PCIE, DT_INST_ON_BUS(n, pcie))(n) +#define I2C_CONFIG_DMA_INIT(n) \ + COND_CODE_1(CONFIG_I2C_DW_LPSS_DMA, \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \ + (.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_IDX(n, 0)),), \ + ())), ()) + #define I2C_DEVICE_INIT_DW(n) \ PINCTRL_DW_DEFINE(n); \ I2C_PCIE_DEFINE(n); \ @@ -1195,6 +1205,7 @@ static int i2c_dw_initialize(const struct device *dev) RESET_DW_CONFIG(n) \ PINCTRL_DW_CONFIG(n) \ I2C_DW_INIT_PCIE(n) \ + I2C_CONFIG_DMA_INIT(n) \ }; \ static struct i2c_dw_dev_config i2c_##n##_runtime; \ I2C_DEVICE_DT_INST_DEFINE(n, i2c_dw_initialize, NULL, \ diff --git a/drivers/i2c/i2c_dw.h b/drivers/i2c/i2c_dw.h index 34427504708..c25246bbafe 100644 --- a/drivers/i2c/i2c_dw.h +++ b/drivers/i2c/i2c_dw.h @@ -104,6 +104,10 @@ struct i2c_dw_rom_config { #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) struct pcie_dev *pcie; #endif /* I2C_DW_PCIE_ENABLED */ + +#ifdef CONFIG_I2C_DW_LPSS_DMA + const struct device *dma_dev; +#endif }; struct i2c_dw_dev_config { @@ -124,7 +128,6 @@ struct i2c_dw_dev_config { uint8_t xfr_flags; bool support_hs_mode; #ifdef CONFIG_I2C_DW_LPSS_DMA - const struct device *dma_dev; uintptr_t phy_addr; uintptr_t base_addr; /* For dma transfer */ diff --git a/drivers/i2c/i2c_emul.c b/drivers/i2c/i2c_emul.c index 4324f6792c6..62e0b0d7621 100644 --- a/drivers/i2c/i2c_emul.c +++ b/drivers/i2c/i2c_emul.c @@ -90,12 +90,14 @@ static int i2c_emul_transfer(const struct device *dev, struct i2c_msg *msgs, uin __ASSERT_NO_MSG(emul->api); __ASSERT_NO_MSG(emul->api->transfer); - ret = api->transfer(emul->target, msgs, num_msgs, addr); - if (ret) { - return ret; + if (emul->mock_api != NULL && emul->mock_api->transfer != NULL) { + ret = emul->mock_api->transfer(emul->target, msgs, num_msgs, addr); + if (ret != -ENOSYS) { + return ret; + } } - return 0; + return api->transfer(emul->target, msgs, num_msgs, addr); } /** @@ -125,14 +127,14 @@ int i2c_emul_register(const struct device *dev, struct i2c_emul *emul) sys_slist_append(&data->emuls, &emul->node); - LOG_INF("Register emulator '%s' at I2C addr %02x\n", name, emul->addr); + LOG_INF("Register emulator '%s' at I2C addr %02x", name, emul->addr); return 0; } /* Device instantiation */ -static struct i2c_driver_api i2c_emul_api = { +static const struct i2c_driver_api i2c_emul_api = { .configure = i2c_emul_configure, .get_config = i2c_emul_get_config, .transfer = i2c_emul_transfer, diff --git a/drivers/i2c/i2c_gd32.c b/drivers/i2c/i2c_gd32.c index ab4347f2352..4959bed65b1 100644 --- a/drivers/i2c/i2c_gd32.c +++ b/drivers/i2c/i2c_gd32.c @@ -644,7 +644,7 @@ static int i2c_gd32_configure(const struct device *dev, return err; } -static struct i2c_driver_api i2c_gd32_driver_api = { +static const struct i2c_driver_api i2c_gd32_driver_api = { .configure = i2c_gd32_configure, .transfer = i2c_gd32_transfer, }; diff --git a/drivers/i2c/i2c_gpio.c b/drivers/i2c/i2c_gpio.c index 17d1eac0d8a..4cb5606507a 100644 --- a/drivers/i2c/i2c_gpio.c +++ b/drivers/i2c/i2c_gpio.c @@ -123,7 +123,7 @@ static int i2c_gpio_recover_bus(const struct device *dev) return rc; } -static struct i2c_driver_api api = { +static const struct i2c_driver_api api = { .configure = i2c_gpio_configure, .transfer = i2c_gpio_transfer, .recover_bus = i2c_gpio_recover_bus, diff --git a/drivers/i2c/i2c_ifx_xmc4.c b/drivers/i2c/i2c_ifx_xmc4.c index 43714cce618..82994eae077 100644 --- a/drivers/i2c/i2c_ifx_xmc4.c +++ b/drivers/i2c/i2c_ifx_xmc4.c @@ -194,7 +194,7 @@ static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, XMC_I2C_CH_ClearStatusFlag(config->i2c, 0xFFFFFFFF); if ((msg_index == 0) || (msg[msg_index].flags & I2C_MSG_RESTART)) { - /* Send START conditon */ + /* Send START condition */ cmd_type = ((msg[msg_index].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? XMC_I2C_CH_CMD_READ : XMC_I2C_CH_CMD_WRITE; @@ -272,7 +272,7 @@ static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, } } - /* Send STOP conditon */ + /* Send STOP condition */ if (msg[msg_index].flags & I2C_MSG_STOP) { XMC_I2C_CH_MasterStop(config->i2c); } diff --git a/drivers/i2c/i2c_ite_enhance.c b/drivers/i2c/i2c_ite_enhance.c index 1d26ade56c1..ae799596270 100644 --- a/drivers/i2c/i2c_ite_enhance.c +++ b/drivers/i2c/i2c_ite_enhance.c @@ -71,6 +71,7 @@ struct i2c_enhance_config { /* I2C alternate configuration */ const struct pinctrl_dev_config *pcfg; uint8_t prescale_scl_low; + uint8_t data_hold_time; uint32_t clock_gate_offset; bool target_enable; bool target_pio_mode; @@ -293,8 +294,9 @@ static void i2c_enhanced_port_set_frequency(const struct device *dev, int freq_hz) { const struct i2c_enhance_config *config = dev->config; - uint32_t clk_div, psr, pll_clock; + uint32_t clk_div, psr, pll_clock, psr_h, psr_l; uint8_t *base = config->base; + uint8_t prescale_scl = config->prescale_scl_low; pll_clock = chip_get_pll_freq(); /* @@ -317,11 +319,28 @@ static void i2c_enhanced_port_set_frequency(const struct device *dev, } /* Adjust SCL low period prescale */ - psr += config->prescale_scl_low; + psr_l = psr + prescale_scl; + if (psr_l > 0xFD) { + psr_l = 0xFD; + LOG_WRN("(psr + prescale_scl) can not be greater than 0xfd."); + } - /* Set I2C Speed */ - IT8XXX2_I2C_PSR(base) = psr & 0xFF; - IT8XXX2_I2C_HSPR(base) = psr & 0xFF; + /* + * Adjust SCL high period prescale + * The property setting prescale_scl must be less than psr and + * the minimum value of psr_h is 2. + */ + if (psr > (prescale_scl + 2)) { + psr_h = psr - prescale_scl; + } else { + psr_h = 2; + LOG_WRN("prescale_scl_low should be less than (psr - 2)."); + } + + /* Set I2C Speed for SCL low period. */ + IT8XXX2_I2C_PSR(base) = psr_l & 0xFF; + /* Set I2C Speed for SCL high period. */ + IT8XXX2_I2C_HSPR(base) = psr_h & 0xFF; } } @@ -1011,7 +1030,7 @@ static void target_i2c_isr_dma(const struct device *dev, &rdata, &len); if (len > CONFIG_I2C_TARGET_IT8XXX2_MAX_BUF_SIZE) { - LOG_ERR("The bufffer size exceeds " + LOG_ERR("The buffer size exceeds " "I2C_TARGET_IT8XXX2_MAX_BUF_SIZE: len=%d", len); } else { @@ -1145,6 +1164,7 @@ static int i2c_enhance_init(const struct device *dev) struct i2c_enhance_data *data = dev->data; const struct i2c_enhance_config *config = dev->config; uint8_t *base = config->base; + uint8_t data_hold_time = config->data_hold_time; uint32_t bitrate_cfg; int error, status; @@ -1196,6 +1216,10 @@ static int i2c_enhance_init(const struct device *dev) (IT8XXX2_SMB_SMB45CHS &= ~GENMASK(6, 4)); } + /* Set I2C data hold time. */ + IT8XXX2_I2C_DHTR(base) = (IT8XXX2_I2C_DHTR(base) & ~GENMASK(2, 0)) | + (data_hold_time - 3); + /* Set clock frequency for I2C ports */ if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || @@ -1453,6 +1477,7 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_I2C_TARGET_BUFFER_MODE), .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ .prescale_scl_low = DT_INST_PROP_OR(inst, prescale_scl_low, 0), \ + .data_hold_time = DT_INST_PROP_OR(inst, data_hold_time, 0), \ .clock_gate_offset = DT_INST_PROP(inst, clock_gate_offset), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ .target_enable = DT_INST_PROP(inst, target_enable), \ diff --git a/drivers/i2c/i2c_ite_it8xxx2.c b/drivers/i2c/i2c_ite_it8xxx2.c index b931a932030..734a38e5b25 100644 --- a/drivers/i2c/i2c_ite_it8xxx2.c +++ b/drivers/i2c/i2c_ite_it8xxx2.c @@ -210,6 +210,15 @@ static void i2c_standard_port_timing_regs_400khz(uint8_t port) /* Port clock frequency depends on setting of timing registers. */ IT8XXX2_SMB_SCLKTS(port) = 0; /* Suggested setting of timing registers of 400kHz. */ +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + IT8XXX2_SMB_4P7USL = 0x16; + IT8XXX2_SMB_4P0USL = 0x11; + IT8XXX2_SMB_300NS = 0x8; + IT8XXX2_SMB_250NS = 0x8; + IT8XXX2_SMB_45P3USL = 0xff; + IT8XXX2_SMB_45P3USH = 0x3; + IT8XXX2_SMB_4P7A4P0H = 0; +#else IT8XXX2_SMB_4P7USL = 0x3; IT8XXX2_SMB_4P0USL = 0; IT8XXX2_SMB_300NS = 0x1; @@ -217,6 +226,7 @@ static void i2c_standard_port_timing_regs_400khz(uint8_t port) IT8XXX2_SMB_45P3USL = 0x6a; IT8XXX2_SMB_45P3USH = 0x1; IT8XXX2_SMB_4P7A4P0H = 0; +#endif } /* Set clock frequency for i2c port A, B , or C */ @@ -1259,6 +1269,14 @@ BUILD_ASSERT((DT_PROP(DT_NODELABEL(i2c2), fifo_enable) == false), "Channel C cannot use FIFO mode."); #endif +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +#define I2C_IT8XXX2_CHECK_SUPPORTED_CLOCK(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \ + I2C_BITRATE_FAST), "Only supports 400 KHz"); + +DT_INST_FOREACH_STATUS_OKAY(I2C_IT8XXX2_CHECK_SUPPORTED_CLOCK) +#endif + #define I2C_ITE_IT8XXX2_INIT(inst) \ PINCTRL_DT_INST_DEFINE(inst); \ BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == \ diff --git a/drivers/i2c/i2c_litex.c b/drivers/i2c/i2c_litex.c index 8f429ba5e59..58636209bf6 100644 --- a/drivers/i2c/i2c_litex.c +++ b/drivers/i2c/i2c_litex.c @@ -10,6 +10,8 @@ #include #include "i2c_bitbang.h" +#include + #define SCL_BIT_POS 0 #define SDA_DIR_BIT_POS 1 #define SDA_BIT_W_POS 2 @@ -108,8 +110,8 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, } static const struct i2c_driver_api i2c_litex_driver_api = { - .configure = i2c_litex_configure, - .transfer = i2c_litex_transfer, + .configure = i2c_litex_configure, + .transfer = i2c_litex_transfer, }; /* Device Instantiation */ diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c index 2fcb1f8e931..29f5a5ae08f 100644 --- a/drivers/i2c/i2c_ll_stm32.c +++ b/drivers/i2c/i2c_ll_stm32.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -62,20 +63,19 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) { const struct i2c_stm32_config *cfg = dev->config; struct i2c_stm32_data *data = dev->data; + const struct device *clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); I2C_TypeDef *i2c = cfg->i2c; uint32_t i2c_clock = 0U; int ret; if (IS_ENABLED(STM32_I2C_DOMAIN_CLOCK_SUPPORT) && (cfg->pclk_len > 1)) { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t)&cfg->pclken[1], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[1], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[1])"); return -EIO; } } else { - if (clock_control_get_rate(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), - (clock_control_subsys_t) &cfg->pclken[0], + if (clock_control_get_rate(clk, (clock_control_subsys_t)&cfg->pclken[0], &i2c_clock) < 0) { LOG_ERR("Failed call clock_control_get_rate(pclken[0])"); return -EIO; @@ -95,9 +95,13 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config) #endif LL_I2C_Disable(i2c); - LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C); + i2c_stm32_set_smbus_mode(dev, data->mode); ret = stm32_i2c_configure_timing(dev, i2c_clock); + if (data->smbalert_active) { + LL_I2C_Enable(i2c); + } + #ifdef CONFIG_PM_DEVICE_RUNTIME ret = clock_control_off(clk, (clock_control_subsys_t)&cfg->pclken[0]); if (ret < 0) { @@ -170,10 +174,11 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, /* Prevent driver from being suspended by PM until I2C transaction is complete */ #ifdef CONFIG_PM_DEVICE_RUNTIME (void)pm_device_runtime_get(dev); -#else - pm_device_busy_set(dev); #endif + /* Prevent the clocks to be stopped during the i2c transaction */ + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + current = msg; while (num_msgs > 0) { @@ -191,10 +196,10 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg, num_msgs--; } + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + #ifdef CONFIG_PM_DEVICE_RUNTIME (void)pm_device_runtime_put(dev); -#else - pm_device_busy_clear(dev); #endif k_sem_give(&data->bus_mutex); @@ -366,6 +371,7 @@ static int i2c_stm32_init(const struct device *dev) #endif data->is_configured = false; + data->mode = I2CSTM32MODE_I2C; /* * initialize mutex used when multiple transfers @@ -442,6 +448,70 @@ static int i2c_stm32_pm_action(const struct device *dev, enum pm_device_action a #endif +#ifdef CONFIG_SMBUS_STM32_SMBALERT +void i2c_stm32_smbalert_set_callback(const struct device *dev, i2c_stm32_smbalert_cb_func_t func, + const struct device *cb_dev) +{ + struct i2c_stm32_data *data = dev->data; + + data->smbalert_cb_func = func; + data->smbalert_cb_dev = cb_dev; +} +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +void i2c_stm32_set_smbus_mode(const struct device *dev, enum i2c_stm32_mode mode) +{ + const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; + I2C_TypeDef *i2c = cfg->i2c; + + data->mode = mode; + + switch (mode) { + case I2CSTM32MODE_I2C: + LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C); + return; +#ifdef CONFIG_SMBUS_STM32 + case I2CSTM32MODE_SMBUSHOST: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_HOST); + return; + case I2CSTM32MODE_SMBUSDEVICE: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_DEVICE); + return; + case I2CSTM32MODE_SMBUSDEVICEARP: + LL_I2C_SetMode(i2c, LL_I2C_MODE_SMBUS_DEVICE_ARP); + return; +#endif + default: + LOG_ERR("%s: invalid mode %i", dev->name, mode); + return; + } +} + +#ifdef CONFIG_SMBUS_STM32 +void i2c_stm32_smbalert_enable(const struct device *dev) +{ + struct i2c_stm32_data *data = dev->data; + const struct i2c_stm32_config *cfg = dev->config; + + data->smbalert_active = true; + LL_I2C_EnableSMBusAlert(cfg->i2c); + LL_I2C_EnableIT_ERR(cfg->i2c); + LL_I2C_Enable(cfg->i2c); +} + +void i2c_stm32_smbalert_disable(const struct device *dev) +{ + struct i2c_stm32_data *data = dev->data; + const struct i2c_stm32_config *cfg = dev->config; + + data->smbalert_active = false; + LL_I2C_DisableSMBusAlert(cfg->i2c); + LL_I2C_DisableIT_ERR(cfg->i2c); + LL_I2C_Disable(cfg->i2c); +} +#endif /* CONFIG_SMBUS_STM32 */ + /* Macros for I2C instance declaration */ #ifdef CONFIG_I2C_STM32_INTERRUPT @@ -489,30 +559,12 @@ static void i2c_stm32_irq_config_func_##index(const struct device *dev) \ #endif /* CONFIG_I2C_STM32_INTERRUPT */ -#if CONFIG_I2C_STM32_BUS_RECOVERY -#define I2C_STM32_SCL_INIT(n) .scl = GPIO_DT_SPEC_INST_GET_OR(n, scl_gpios, {0}), -#define I2C_STM32_SDA_INIT(n) .sda = GPIO_DT_SPEC_INST_GET_OR(n, sda_gpios, {0}), -#else -#define I2C_STM32_SCL_INIT(n) -#define I2C_STM32_SDA_INIT(n) -#endif /* CONFIG_I2C_STM32_BUS_RECOVERY */ - -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2) -#define DEFINE_TIMINGS(index) \ - static const uint32_t i2c_timings_##index[] = \ - DT_INST_PROP_OR(index, timings, {}); -#define USE_TIMINGS(index) \ - .timings = (const struct i2c_config_timing *) i2c_timings_##index, \ - .n_timings = ARRAY_SIZE(i2c_timings_##index), -#else /* V2 */ -#define DEFINE_TIMINGS(index) -#define USE_TIMINGS(index) -#endif /* V2 */ - #define STM32_I2C_INIT(index) \ STM32_I2C_IRQ_HANDLER_DECL(index); \ \ -DEFINE_TIMINGS(index) \ +IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2), \ + (static const uint32_t i2c_timings_##index[] = \ + DT_INST_PROP_OR(index, timings, {});)) \ \ PINCTRL_DT_INST_DEFINE(index); \ \ @@ -526,9 +578,12 @@ static const struct i2c_stm32_config i2c_stm32_cfg_##index = { \ STM32_I2C_IRQ_HANDLER_FUNCTION(index) \ .bitrate = DT_INST_PROP(index, clock_frequency), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ - I2C_STM32_SCL_INIT(index) \ - I2C_STM32_SDA_INIT(index) \ - USE_TIMINGS(index) \ + IF_ENABLED(CONFIG_I2C_STM32_BUS_RECOVERY, \ + (.scl = GPIO_DT_SPEC_INST_GET_OR(index, scl_gpios, {0}),\ + .sda = GPIO_DT_SPEC_INST_GET_OR(index, sda_gpios, {0}),))\ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_i2c_v2), \ + (.timings = (const struct i2c_config_timing *) i2c_timings_##index,\ + .n_timings = ARRAY_SIZE(i2c_timings_##index),)) \ }; \ \ static struct i2c_stm32_data i2c_stm32_dev_data_##index; \ diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h index c77b687038d..0a9dc1be350 100644 --- a/drivers/i2c/i2c_ll_stm32.h +++ b/drivers/i2c/i2c_ll_stm32.h @@ -9,6 +9,8 @@ #ifndef ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_ #define ZEPHYR_DRIVERS_I2C_I2C_LL_STM32_H_ +#include + #ifdef CONFIG_I2C_STM32_BUS_RECOVERY #include #endif /* CONFIG_I2C_STM32_BUS_RECOVERY */ @@ -79,6 +81,12 @@ struct i2c_stm32_data { bool slave_attached; #endif bool is_configured; + bool smbalert_active; + enum i2c_stm32_mode mode; +#ifdef CONFIG_SMBUS_STM32_SMBALERT + i2c_stm32_smbalert_cb_func_t smbalert_cb_func; + const struct device *smbalert_cb_dev; +#endif }; int32_t stm32_i2c_transaction(const struct device *dev, diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c index d0a0131858f..ff63ee39913 100644 --- a/drivers/i2c/i2c_ll_stm32_v1.c +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -48,13 +48,17 @@ static void stm32_i2c_generate_start_condition(I2C_TypeDef *i2c) static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; LL_I2C_DisableIT_TX(i2c); LL_I2C_DisableIT_RX(i2c); LL_I2C_DisableIT_EVT(i2c); LL_I2C_DisableIT_BUF(i2c); - LL_I2C_DisableIT_ERR(i2c); + + if (!data->smbalert_active) { + LL_I2C_DisableIT_ERR(i2c); + } } static void stm32_i2c_enable_transfer_interrupts(const struct device *dev) @@ -118,6 +122,7 @@ static void stm32_i2c_reset(const struct device *dev) static void stm32_i2c_master_finish(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; #ifdef CONFIG_I2C_STM32_INTERRUPT @@ -125,16 +130,17 @@ static void stm32_i2c_master_finish(const struct device *dev) #endif #if defined(CONFIG_I2C_TARGET) - struct i2c_stm32_data *data = dev->data; data->master_active = false; - if (!data->slave_attached) { + if (!data->slave_attached && !data->smbalert_active) { LL_I2C_Disable(i2c); } else { stm32_i2c_enable_transfer_interrupts(dev); LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK); } #else - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #endif } @@ -538,7 +544,9 @@ int i2c_stm32_target_unregister(const struct device *dev, struct i2c_target_conf LL_I2C_ClearFlag_STOP(i2c); LL_I2C_ClearFlag_ADDR(i2c); - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } data->slave_attached = false; @@ -608,6 +616,16 @@ void stm32_i2c_error_isr(void *arg) data->current.is_err = 1U; goto end; } + +#if defined(CONFIG_SMBUS_STM32_SMBALERT) + if (LL_I2C_IsActiveSMBusFlag_ALERT(i2c)) { + LL_I2C_ClearSMBusFlag_ALERT(i2c); + if (data->smbalert_cb_func != NULL) { + data->smbalert_cb_func(data->smbalert_cb_dev); + } + goto end; + } +#endif return; end: stm32_i2c_master_mode_end(dev); @@ -881,7 +899,7 @@ static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg, } } /* ADDR must be cleared before NACK generation. Either in 2 byte reception - * byte 1 will be NACK'ed and slave wont sent the last byte + * byte 1 will be NACK'ed and slave won't sent the last byte */ LL_I2C_ClearFlag_ADDR(i2c); if (len == 1U) { diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c index c75d68e4f19..a685ebebeb7 100644 --- a/drivers/i2c/i2c_ll_stm32_v2.c +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -74,6 +74,7 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg, static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) { const struct i2c_stm32_config *cfg = dev->config; + struct i2c_stm32_data *data = dev->data; I2C_TypeDef *i2c = cfg->i2c; LL_I2C_DisableIT_TX(i2c); @@ -81,7 +82,10 @@ static void stm32_i2c_disable_transfer_interrupts(const struct device *dev) LL_I2C_DisableIT_STOP(i2c); LL_I2C_DisableIT_NACK(i2c); LL_I2C_DisableIT_TC(i2c); - LL_I2C_DisableIT_ERR(i2c); + + if (!data->smbalert_active) { + LL_I2C_DisableIT_ERR(i2c); + } } static void stm32_i2c_enable_transfer_interrupts(const struct device *dev) @@ -109,11 +113,13 @@ static void stm32_i2c_master_mode_end(const struct device *dev) #if defined(CONFIG_I2C_TARGET) data->master_active = false; - if (!data->slave_attached) { + if (!data->slave_attached && !data->smbalert_active) { LL_I2C_Disable(i2c); } #else - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #endif k_sem_give(&data->device_sync_sem); } @@ -142,9 +148,19 @@ static void stm32_i2c_slave_event(const struct device *dev) __ASSERT_NO_MSG(0); return; } + } else { + /* On STM32 the LL_I2C_GetAddressMatchCode & (ISR register) returns + * only 7bits of address match so 10 bit dual addressing is broken. + * Revert to assuming single address match. + */ + if (data->slave_cfg != NULL) { + slave_cfg = data->slave_cfg; + } else { + __ASSERT_NO_MSG(0); + return; + } } - slave_cfg = data->slave_cfg; slave_cb = slave_cfg->callbacks; if (LL_I2C_IsActiveFlag_TXIS(i2c)) { @@ -320,7 +336,9 @@ int i2c_stm32_target_unregister(const struct device *dev, LL_I2C_ClearFlag_STOP(i2c); LL_I2C_ClearFlag_ADDR(i2c); - LL_I2C_Disable(i2c); + if (!data->smbalert_active) { + LL_I2C_Disable(i2c); + } #if defined(CONFIG_PM_DEVICE_RUNTIME) if (pm_device_wakeup_is_capable(dev)) { @@ -427,6 +445,16 @@ static int stm32_i2c_error(const struct device *dev) goto end; } +#if defined(CONFIG_SMBUS_STM32_SMBALERT) + if (LL_I2C_IsActiveSMBusFlag_ALERT(i2c)) { + LL_I2C_ClearSMBusFlag_ALERT(i2c); + if (data->smbalert_cb_func != NULL) { + data->smbalert_cb_func(data->smbalert_cb_dev); + } + goto end; + } +#endif + return 0; end: stm32_i2c_master_mode_end(dev); diff --git a/drivers/i2c/i2c_mchp_mss.c b/drivers/i2c/i2c_mchp_mss.c index 887579cf9a1..49b0da2a719 100644 --- a/drivers/i2c/i2c_mchp_mss.c +++ b/drivers/i2c/i2c_mchp_mss.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/i2c_mcux_flexcomm.c b/drivers/i2c/i2c_mcux_flexcomm.c index 2eee6adebda..151992ecc9d 100644 --- a/drivers/i2c/i2c_mcux_flexcomm.c +++ b/drivers/i2c/i2c_mcux_flexcomm.c @@ -19,6 +19,10 @@ LOG_MODULE_REGISTER(mcux_flexcomm); #include "i2c-priv.h" +#define I2C_TRANSFER_TIMEOUT_MSEC \ + COND_CODE_0(CONFIG_I2C_NXP_TRANSFER_TIMEOUT, (K_FOREVER), \ + (K_MSEC(CONFIG_I2C_NXP_TRANSFER_TIMEOUT))) + struct mcux_flexcomm_config { I2C_Type *base; const struct device *clock_dev; @@ -168,7 +172,7 @@ static int mcux_flexcomm_transfer(const struct device *dev, } /* Wait for the transfer to complete */ - k_sem_take(&data->device_sync_sem, K_FOREVER); + k_sem_take(&data->device_sync_sem, I2C_TRANSFER_TIMEOUT_MSEC); /* Return an error if the transfer didn't complete * successfully. e.g., nak, timeout, lost arbitration diff --git a/drivers/i2c/i2c_mcux_lpi2c.c b/drivers/i2c/i2c_mcux_lpi2c.c index cc6d7954b58..16660359312 100644 --- a/drivers/i2c/i2c_mcux_lpi2c.c +++ b/drivers/i2c/i2c_mcux_lpi2c.c @@ -32,8 +32,13 @@ LOG_MODULE_REGISTER(mcux_lpi2c); */ #define SCAN_DELAY_US(baudrate) (12 * USEC_PER_SEC / baudrate) +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct mcux_lpi2c_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct mcux_lpi2c_data *)(_dev)->data) + struct mcux_lpi2c_config { - LPI2C_Type *base; + DEVICE_MMIO_NAMED_ROM(reg_base); const struct device *clock_dev; clock_control_subsys_t clock_subsys; void (*irq_config_func)(const struct device *dev); @@ -47,6 +52,7 @@ struct mcux_lpi2c_config { }; struct mcux_lpi2c_data { + DEVICE_MMIO_NAMED_RAM(reg_base); lpi2c_master_handle_t handle; struct k_sem lock; struct k_sem device_sync_sem; @@ -66,7 +72,7 @@ static int mcux_lpi2c_configure(const struct device *dev, { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); uint32_t clock_freq; uint32_t baudrate; int ret; @@ -138,11 +144,11 @@ static uint32_t mcux_lpi2c_convert_flags(int msg_flags) } static int mcux_lpi2c_transfer(const struct device *dev, struct i2c_msg *msgs, - uint8_t num_msgs, uint16_t addr) + uint8_t num_msgs, uint16_t addr) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpi2c_master_transfer_t transfer; status_t status; int ret = 0; @@ -304,8 +310,8 @@ static int mcux_lpi2c_recover_bus(const struct device *dev) #ifdef CONFIG_I2C_TARGET static void mcux_lpi2c_slave_irq_handler(const struct device *dev) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; int ret; uint32_t flags; @@ -319,11 +325,11 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) * every byte. For these reason, we handle the LPI2C IRQ * directly. */ - flags = LPI2C_SlaveGetStatusFlags(config->base); + flags = LPI2C_SlaveGetStatusFlags(base); if (flags & kLPI2C_SlaveAddressValidFlag) { /* Read Slave address to clear flag */ - LPI2C_SlaveGetReceivedAddress(config->base); + LPI2C_SlaveGetReceivedAddress(base); data->first_tx = true; /* Reset to sending ACK, in case we NAK'ed before */ data->send_ack = true; @@ -331,7 +337,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) if (flags & kLPI2C_SlaveRxReadyFlag) { /* RX data is available, read it and issue callback */ - i2c_data = (uint8_t)config->base->SRDR; + i2c_data = (uint8_t)base->SRDR; if (data->first_tx) { data->first_tx = false; if (target_cb->write_requested) { @@ -365,7 +371,7 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) data->read_active = false; } else { /* Send I2C data */ - config->base->STDR = i2c_data; + base->STDR = i2c_data; } } } else if (data->read_active) { @@ -377,33 +383,34 @@ static void mcux_lpi2c_slave_irq_handler(const struct device *dev) data->read_active = false; } else { /* Send I2C data */ - config->base->STDR = i2c_data; + base->STDR = i2c_data; } } } } if (flags & kLPI2C_SlaveStopDetectFlag) { - LPI2C_SlaveClearStatusFlags(config->base, flags); + LPI2C_SlaveClearStatusFlags(base, flags); if (target_cb->stop) { target_cb->stop(data->target_cfg); } } if (flags & kLPI2C_SlaveTransmitAckFlag) { - LPI2C_SlaveTransmitAck(config->base, data->send_ack); + LPI2C_SlaveTransmitAck(base, data->send_ack); } } static int mcux_lpi2c_target_register(const struct device *dev, - struct i2c_target_config *target_config) + struct i2c_target_config *target_config) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpi2c_slave_config_t slave_config; uint32_t clock_freq; - LPI2C_MasterDeinit(config->base); + LPI2C_MasterDeinit(base); /* Get the clock frequency */ if (clock_control_get_rate(config->clock_dev, config->clock_subsys, @@ -430,11 +437,11 @@ static int mcux_lpi2c_target_register(const struct device *dev, * this behavior may cause issues with some I2C controllers. */ slave_config.sclStall.enableAck = true; - LPI2C_SlaveInit(config->base, &slave_config, clock_freq); + LPI2C_SlaveInit(base, &slave_config, clock_freq); /* Clear all flags. */ - LPI2C_SlaveClearStatusFlags(config->base, (uint32_t)kLPI2C_SlaveClearFlags); + LPI2C_SlaveClearStatusFlags(base, (uint32_t)kLPI2C_SlaveClearFlags); /* Enable interrupt */ - LPI2C_SlaveEnableInterrupts(config->base, + LPI2C_SlaveEnableInterrupts(base, (kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag | @@ -446,8 +453,8 @@ static int mcux_lpi2c_target_register(const struct device *dev, static int mcux_lpi2c_target_unregister(const struct device *dev, struct i2c_target_config *target_config) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); if (!data->target_attached) { return -EINVAL; @@ -456,7 +463,7 @@ static int mcux_lpi2c_target_unregister(const struct device *dev, data->target_cfg = NULL; data->target_attached = false; - LPI2C_SlaveDeinit(config->base); + LPI2C_SlaveDeinit(base); return 0; } @@ -464,9 +471,8 @@ static int mcux_lpi2c_target_unregister(const struct device *dev, static void mcux_lpi2c_isr(const struct device *dev) { - const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); #ifdef CONFIG_I2C_TARGET if (data->target_attached) { @@ -481,11 +487,15 @@ static int mcux_lpi2c_init(const struct device *dev) { const struct mcux_lpi2c_config *config = dev->config; struct mcux_lpi2c_data *data = dev->data; - LPI2C_Type *base = config->base; + LPI2C_Type *base; uint32_t clock_freq, bitrate_cfg; lpi2c_master_config_t master_config; int error; + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + + base = (LPI2C_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + k_sem_init(&data->lock, 1, 1); k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); @@ -549,7 +559,7 @@ static const struct i2c_driver_api mcux_lpi2c_driver_api = { static void mcux_lpi2c_config_func_##n(const struct device *dev); \ \ static const struct mcux_lpi2c_config mcux_lpi2c_config_##n = { \ - .base = (LPI2C_Type *)DT_INST_REG_ADDR(n), \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),\ @@ -566,17 +576,17 @@ static const struct i2c_driver_api mcux_lpi2c_driver_api = { static struct mcux_lpi2c_data mcux_lpi2c_data_##n; \ \ I2C_DEVICE_DT_INST_DEFINE(n, mcux_lpi2c_init, NULL, \ - &mcux_lpi2c_data_##n, \ - &mcux_lpi2c_config_##n, POST_KERNEL, \ - CONFIG_I2C_INIT_PRIORITY, \ - &mcux_lpi2c_driver_api); \ + &mcux_lpi2c_data_##n, \ + &mcux_lpi2c_config_##n, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &mcux_lpi2c_driver_api); \ \ static void mcux_lpi2c_config_func_##n(const struct device *dev) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - mcux_lpi2c_isr, \ - DEVICE_DT_INST_GET(n), 0); \ + DT_INST_IRQ(n, priority), \ + mcux_lpi2c_isr, \ + DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } diff --git a/drivers/i2c/i2c_nios2.c b/drivers/i2c/i2c_nios2.c index 2540a0a87ac..1300b2d95b6 100644 --- a/drivers/i2c/i2c_nios2.c +++ b/drivers/i2c/i2c_nios2.c @@ -152,7 +152,7 @@ static void i2c_nios2_isr(const struct device *dev) static int i2c_nios2_init(const struct device *dev); -static struct i2c_driver_api i2c_nios2_driver_api = { +static const struct i2c_driver_api i2c_nios2_driver_api = { .configure = i2c_nios2_configure, .transfer = i2c_nios2_transfer, }; diff --git a/drivers/i2c/i2c_npcx_controller.c b/drivers/i2c/i2c_npcx_controller.c index 9cd4a02970b..1349a535b93 100644 --- a/drivers/i2c/i2c_npcx_controller.c +++ b/drivers/i2c/i2c_npcx_controller.c @@ -770,8 +770,15 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status) inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE); inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE); + /* + * Re-enable interrupts because they are turned off after the SMBus module + * is reset above. + */ + inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN); /* End of transaction */ data->oper_state = NPCX_I2C_IDLE; + + LOG_DBG("target: Bus error on port%02x!", data->port); return; } @@ -801,7 +808,7 @@ static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status) /* Clear NMATCH Bit */ inst->SMBST = BIT(NPCX_SMBST_NMATCH); - /* Distinguish tje direction of i2c target mode by reading XMIT bit */ + /* Distinguish the direction of i2c target mode by reading XMIT bit */ if (IS_BIT_SET(inst->SMBST, NPCX_SMBST_XMIT)) { /* Start transmitting data in i2c target mode */ data->oper_state = NPCX_I2C_WRITE_FIFO; diff --git a/drivers/i2c/i2c_npcx_controller.h b/drivers/i2c/i2c_npcx_controller.h index 08338244043..6155f1a1499 100644 --- a/drivers/i2c/i2c_npcx_controller.h +++ b/drivers/i2c/i2c_npcx_controller.h @@ -70,7 +70,7 @@ int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr, uint8_t port); /** - * @brief Toggle the SCL to generate maxmium 9 clocks until the target release + * @brief Toggle the SCL to generate maximum 9 clocks until the target release * the SDA line and send a STOP condition. * * @param i2c_dev Pointer to the device structure for i2c controller instance. diff --git a/drivers/i2c/i2c_numaker.c b/drivers/i2c/i2c_numaker.c new file mode 100644 index 00000000000..0c856015660 --- /dev/null +++ b/drivers/i2c/i2c_numaker.c @@ -0,0 +1,784 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_i2c + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(i2c_numaker, CONFIG_I2C_LOG_LEVEL); + +#include "i2c-priv.h" +#include +#include + +/* i2c Master Mode Status */ +#define M_START 0x08 /* Start */ +#define M_REPEAT_START 0x10 /* Master Repeat Start */ +#define M_TRAN_ADDR_ACK 0x18 /* Master Transmit Address ACK */ +#define M_TRAN_ADDR_NACK 0x20 /* Master Transmit Address NACK */ +#define M_TRAN_DATA_ACK 0x28 /* Master Transmit Data ACK */ +#define M_TRAN_DATA_NACK 0x30 /* Master Transmit Data NACK */ +#define M_ARB_LOST 0x38 /* Master Arbitration Los */ +#define M_RECE_ADDR_ACK 0x40 /* Master Receive Address ACK */ +#define M_RECE_ADDR_NACK 0x48 /* Master Receive Address NACK */ +#define M_RECE_DATA_ACK 0x50 /* Master Receive Data ACK */ +#define M_RECE_DATA_NACK 0x58 /* Master Receive Data NACK */ +#define BUS_ERROR 0x00 /* Bus error */ + +/* i2c Slave Mode Status */ +#define S_REPEAT_START_STOP 0xA0 /* Slave Transmit Repeat Start or Stop */ +#define S_TRAN_ADDR_ACK 0xA8 /* Slave Transmit Address ACK */ +#define S_TRAN_DATA_ACK 0xB8 /* Slave Transmit Data ACK */ +#define S_TRAN_DATA_NACK 0xC0 /* Slave Transmit Data NACK */ +#define S_TRAN_LAST_DATA_ACK 0xC8 /* Slave Transmit Last Data ACK */ +#define S_RECE_ADDR_ACK 0x60 /* Slave Receive Address ACK */ +#define S_RECE_ARB_LOST 0x68 /* Slave Receive Arbitration Lost */ +#define S_RECE_DATA_ACK 0x80 /* Slave Receive Data ACK */ +#define S_RECE_DATA_NACK 0x88 /* Slave Receive Data NACK */ + +/* i2c GC Mode Status */ +#define GC_ADDR_ACK 0x70 /* GC mode Address ACK */ +#define GC_ARB_LOST 0x78 /* GC mode Arbitration Lost */ +#define GC_DATA_ACK 0x90 /* GC mode Data ACK */ +#define GC_DATA_NACK 0x98 /* GC mode Data NACK */ + +/* i2c Other Status */ +#define ADDR_TRAN_ARB_LOST 0xB0 /* Address Transmit Arbitration Lost */ +#define BUS_RELEASED 0xF8 /* Bus Released */ + +struct i2c_numaker_config { + I2C_T *i2c_base; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clkctrl_dev; + uint32_t irq_n; + void (*irq_config_func)(const struct device *dev); + const struct pinctrl_dev_config *pincfg; + uint32_t bitrate; +}; + +struct i2c_numaker_data { + struct k_sem lock; + uint32_t dev_config; + /* Master transfer context */ + struct { + struct k_sem xfer_sync; + uint16_t addr; + struct i2c_msg *msgs_beg; + struct i2c_msg *msgs_pos; + struct i2c_msg *msgs_end; + uint8_t *buf_beg; + uint8_t *buf_pos; + uint8_t *buf_end; + } master_xfer; +#ifdef CONFIG_I2C_TARGET + /* Slave transfer context */ + struct { + struct i2c_target_config *slave_config; + bool slave_addressed; + } slave_xfer; +#endif +}; + +/* ACK/NACK last data byte, dependent on whether or not message merge is allowed */ +static void m_numaker_i2c_master_xfer_msg_read_last_byte(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + /* Shouldn't invoke with message pointer OOB */ + __ASSERT_NO_MSG(data->master_xfer.msgs_pos < data->master_xfer.msgs_end); + /* Should invoke with exactly one data byte remaining for read */ + __ASSERT_NO_MSG((data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ); + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 1); + + /* Flags of previous message */ + bool do_stop_prev = data->master_xfer.msgs_pos->flags & I2C_MSG_STOP; + + /* Advance to next messages temporarily */ + data->master_xfer.msgs_pos++; + + /* Has next message? */ + if (data->master_xfer.msgs_pos < data->master_xfer.msgs_end) { + /* Flags of next message */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read_next = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_restart_next = data->master_xfer.msgs_pos->flags & I2C_MSG_RESTART; + + /* + * Different R/W bit so message merge is disallowed. + * Force I2C Repeat Start on I2C Stop/Repeat Start missing + */ + if (!is_read_next) { + if (!do_stop_prev && !do_restart_next) { + do_restart_next = true; + } + } + + if (do_stop_prev || do_restart_next) { + /* NACK last data byte (required for Master Receiver) */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } else { + /* ACK last data byte, so to merge adjacent messages into one transaction */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } + } else { + /* NACK last data byte (required for Master Receiver) */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + + /* Roll back message pointer */ + data->master_xfer.msgs_pos--; +} + +/* End the transfer, involving I2C Stop and signal to thread */ +static void m_numaker_i2c_master_xfer_end(const struct device *dev, bool do_stop) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + if (do_stop) { + /* Do I2C Stop */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + } + + /* Signal master transfer end */ + k_sem_give(&data->master_xfer.xfer_sync); +} + +static void m_numaker_i2c_master_xfer_msg_end(const struct device *dev); +/* Read next data byte, involving ACK/NACK last data byte and message merge */ +static void m_numaker_i2c_master_xfer_msg_read_next_byte(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + switch (data->master_xfer.buf_end - data->master_xfer.buf_pos) { + case 0: + /* Last data byte ACKed, we'll do message merge */ + m_numaker_i2c_master_xfer_msg_end(dev); + break; + case 1: + /* Read last data byte for this message */ + m_numaker_i2c_master_xfer_msg_read_last_byte(dev); + break; + default: + /* ACK non-last data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } +} + +/* End one message transfer, involving message merge and transfer end */ +static void m_numaker_i2c_master_xfer_msg_end(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + /* Shouldn't invoke with message pointer OOB */ + __ASSERT_NO_MSG(data->master_xfer.msgs_pos < data->master_xfer.msgs_end); + /* Should have transferred up */ + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 0); + + /* Flags of previous message */ + bool is_read_prev = (data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_stop_prev = data->master_xfer.msgs_pos->flags & I2C_MSG_STOP; + + /* Advance to next messages */ + data->master_xfer.msgs_pos++; + + /* Has next message? */ + if (data->master_xfer.msgs_pos < data->master_xfer.msgs_end) { + /* Flags of next message */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read_next = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + bool do_restart_next = data->master_xfer.msgs_pos->flags & I2C_MSG_RESTART; + + /* + * Different R/W bit so message merge is disallowed. + * Force I2C Repeat Start on I2C Stop/Repeat Start missing + */ + if (!is_read_prev != !is_read_next) { /* Logical XOR idiom */ + if (!do_stop_prev && !do_restart_next) { + LOG_WRN("Cannot merge adjacent messages, force I2C Repeat Start"); + do_restart_next = true; + } + } + + if (do_stop_prev) { + /* Do I2C Stop and then Start */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | + I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + } else if (do_restart_next) { + /* Do I2C Repeat Start */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | I2C_CTL0_SI_Msk); + } else { + /* Merge into the same transaction */ + + /* Prepare buffer for current message */ + data->master_xfer.buf_beg = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_pos = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_end = data->master_xfer.msgs_pos->buf + + data->master_xfer.msgs_pos->len; + + if (is_read_prev) { + m_numaker_i2c_master_xfer_msg_read_next_byte(dev); + } else { + /* + * Interrupt flag not cleared, expect to re-enter ISR with + * context unchanged, except buffer changed for message change. + */ + } + } + } else { + if (!do_stop_prev) { + LOG_WRN("Last message not marked I2C Stop"); + } + + m_numaker_i2c_master_xfer_end(dev, do_stop_prev); + } +} + +static int i2c_numaker_configure(const struct device *dev, uint32_t dev_config) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + uint32_t bitrate; + + /* Check address size */ + if (dev_config & I2C_ADDR_10_BITS) { + LOG_ERR("10-bits address not supported"); + return -ENOTSUP; + } + + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + bitrate = KHZ(100); + break; + case I2C_SPEED_FAST: + bitrate = KHZ(400); + break; + case I2C_SPEED_FAST_PLUS: + bitrate = MHZ(1); + break; + default: + LOG_ERR("Speed code %d not supported", I2C_SPEED_GET(dev_config)); + return -ENOTSUP; + } + + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + +#ifdef CONFIG_I2C_TARGET + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Reconfigure with slave being busy"); + err = -EBUSY; + goto done; + } +#endif + + I2C_Open(i2c_base, bitrate); + /* INTEN bit and FSM control bits (STA, STO, SI, AA) are packed in one register CTL0. */ + i2c_base->CTL0 |= (I2C_CTL0_INTEN_Msk | I2C_CTL0_I2CEN_Msk); + data->dev_config = dev_config; + +done: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +static int i2c_numaker_get_config(const struct device *dev, uint32_t *dev_config) +{ + struct i2c_numaker_data *data = dev->data; + + if (!dev_config) { + return -EINVAL; + } + + k_sem_take(&data->lock, K_FOREVER); + *dev_config = data->dev_config; + k_sem_give(&data->lock); + + return 0; +} + +/* + * Master active transfer: + * 1. Do I2C Start to start the transfer (thread) + * 2. I2C FSM (ISR) + * 3. Force I2C Stop to end the transfer (thread) + * Slave passive transfer: + * 1. Prepare callback (thread) + * 2. Do data transfer via above callback (ISR) + */ +static int i2c_numaker_transfer(const struct device *dev, struct i2c_msg *msgs, + uint8_t num_msgs, uint16_t addr) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Master transfer with slave being busy"); + err = -EBUSY; + goto cleanup; + } + + if (num_msgs == 0) { + goto cleanup; + } + + /* Prepare to start transfer */ + data->master_xfer.addr = addr; + data->master_xfer.msgs_beg = msgs; + data->master_xfer.msgs_pos = msgs; + data->master_xfer.msgs_end = msgs + num_msgs; + + /* Do I2C Start to start the transfer */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STA_Msk | I2C_CTL0_SI_Msk); + + irq_enable(config->irq_n); + k_sem_take(&data->master_xfer.xfer_sync, K_FOREVER); + irq_disable(config->irq_n); + + /* Check transfer result */ + if (data->master_xfer.msgs_pos != data->master_xfer.msgs_end) { + bool is_read; + bool is_10bit; + + is_read = (data->master_xfer.msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + is_10bit = data->master_xfer.msgs_pos->flags & I2C_MSG_ADDR_10_BITS; + LOG_ERR("Failed message:"); + LOG_ERR("MSG IDX: %d", data->master_xfer.msgs_pos - data->master_xfer.msgs_beg); + LOG_ERR("ADDR (%d-bit): 0x%04X", is_10bit ? 10 : 7, addr); + LOG_ERR("DIR: %s", is_read ? "R" : "W"); + LOG_ERR("Expected %d bytes transferred, but actual %d", + data->master_xfer.msgs_pos->len, + data->master_xfer.buf_pos - data->master_xfer.buf_beg); + err = -EIO; + goto i2c_stop; + } + +i2c_stop: + + /* Do I2C Stop to release bus ownership */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + +#ifdef CONFIG_I2C_TARGET + /* Enable slave mode if one slave is registered */ + if (data->slave_xfer.slave_config) { + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } +#endif + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +#ifdef CONFIG_I2C_TARGET +static int i2c_numaker_slave_register(const struct device *dev, + struct i2c_target_config *slave_config) +{ + if (!slave_config || !slave_config->callbacks) { + return -EINVAL; + } + + if (slave_config->flags & I2C_ADDR_10_BITS) { + LOG_ERR("10-bits address not supported"); + return -ENOTSUP; + } + + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_config) { + err = -EBUSY; + goto cleanup; + } + + data->slave_xfer.slave_config = slave_config; + /* Slave address */ + I2C_SetSlaveAddr(i2c_base, + 0, + slave_config->address, + I2C_GCMODE_DISABLE); + + /* Slave address state */ + data->slave_xfer.slave_addressed = false; + + /* Enable slave mode */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} + +static int i2c_numaker_slave_unregister(const struct device *dev, + struct i2c_target_config *slave_config) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + int err = 0; + + if (!slave_config) { + return -EINVAL; + } + + k_sem_take(&data->lock, K_FOREVER); + irq_disable(config->irq_n); + + if (data->slave_xfer.slave_config != slave_config) { + err = -EINVAL; + goto cleanup; + } + + if (data->slave_xfer.slave_addressed) { + LOG_ERR("Unregister slave driver with slave being busy"); + err = -EBUSY; + goto cleanup; + } + + /* Slave address: Zero */ + I2C_SetSlaveAddr(i2c_base, + 0, + 0, + I2C_GCMODE_DISABLE); + + /* Slave address state */ + data->slave_xfer.slave_addressed = false; + + /* Disable slave mode */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + data->slave_xfer.slave_config = NULL; + +cleanup: + + irq_enable(config->irq_n); + k_sem_give(&data->lock); + + return err; +} +#endif + +static int i2c_numaker_recover_bus(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; + + k_sem_take(&data->lock, K_FOREVER); + /* Do I2C Stop to release bus ownership */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_STO_Msk | I2C_CTL0_SI_Msk); + k_sem_give(&data->lock); + + return 0; +} + +static void i2c_numaker_isr(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + I2C_T *i2c_base = config->i2c_base; +#ifdef CONFIG_I2C_TARGET + struct i2c_target_config *slave_config = data->slave_xfer.slave_config; + const struct i2c_target_callbacks *slave_callbacks = + slave_config ? slave_config->callbacks : NULL; + uint8_t data_byte; +#endif + uint32_t status; + + if (I2C_GET_TIMEOUT_FLAG(i2c_base)) { + I2C_ClearTimeoutFlag(i2c_base); + return; + } + + status = I2C_GET_STATUS(i2c_base); + + switch (status) { + case M_START: /* Start */ + case M_REPEAT_START: /* Master Repeat Start */ + /* Prepare buffer for current message */ + data->master_xfer.buf_beg = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_pos = data->master_xfer.msgs_pos->buf; + data->master_xfer.buf_end = data->master_xfer.msgs_pos->buf + + data->master_xfer.msgs_pos->len; + + /* Write I2C address */ + struct i2c_msg *msgs_pos = data->master_xfer.msgs_pos; + bool is_read = (msgs_pos->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ; + uint16_t addr = data->master_xfer.addr; + int addr_rw = is_read ? ((addr << 1) | 1) : (addr << 1); + + I2C_SET_DATA(i2c_base, (uint8_t) (addr_rw & 0xFF)); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + break; + case M_TRAN_ADDR_ACK: /* Master Transmit Address ACK */ + case M_TRAN_DATA_ACK: /* Master Transmit Data ACK */ + __ASSERT_NO_MSG(data->master_xfer.buf_pos); + if (data->master_xfer.buf_pos < data->master_xfer.buf_end) { + I2C_SET_DATA(i2c_base, *data->master_xfer.buf_pos++); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* End this message */ + m_numaker_i2c_master_xfer_msg_end(dev); + } + break; + case M_TRAN_ADDR_NACK: /* Master Transmit Address NACK */ + case M_TRAN_DATA_NACK: /* Master Transmit Data NACK */ + case M_RECE_ADDR_NACK: /* Master Receive Address NACK */ + case M_ARB_LOST: /* Master Arbitration Lost */ + m_numaker_i2c_master_xfer_end(dev, true); + break; + case M_RECE_ADDR_ACK: /* Master Receive Address ACK */ + case M_RECE_DATA_ACK: /* Master Receive Data ACK */ + __ASSERT_NO_MSG(data->master_xfer.buf_pos); + + if (status == M_RECE_ADDR_ACK) { + __ASSERT_NO_MSG(data->master_xfer.buf_pos < data->master_xfer.buf_end); + } else if (status == M_RECE_DATA_ACK) { + __ASSERT_NO_MSG((data->master_xfer.buf_end - + data->master_xfer.buf_pos) >= 1); + *data->master_xfer.buf_pos++ = I2C_GET_DATA(i2c_base); + } + + m_numaker_i2c_master_xfer_msg_read_next_byte(dev); + break; + case M_RECE_DATA_NACK: /* Master Receive Data NACK */ + __ASSERT_NO_MSG((data->master_xfer.buf_end - data->master_xfer.buf_pos) == 1); + *data->master_xfer.buf_pos++ = I2C_GET_DATA(i2c_base); + /* End this message */ + m_numaker_i2c_master_xfer_msg_end(dev); + break; + case BUS_ERROR: /* Bus error */ + m_numaker_i2c_master_xfer_end(dev, true); + break; +#ifdef CONFIG_I2C_TARGET + /* NOTE: Don't disable interrupt here because slave mode relies on */ + /* for passive transfer in ISR. */ + + /* Slave Transmit */ + case S_TRAN_ADDR_ACK: /* Slave Transmit Address ACK */ + case ADDR_TRAN_ARB_LOST: /* Slave Transmit Arbitration Lost */ + data->slave_xfer.slave_addressed = true; + if (slave_callbacks->read_requested(slave_config, &data_byte) == 0) { + /* Non-last data byte */ + I2C_SET_DATA(i2c_base, data_byte); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Go S_TRAN_LAST_DATA_ACK on error */ + I2C_SET_DATA(i2c_base, 0xFF); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_TRAN_DATA_ACK: /* Slave Transmit Data ACK */ + if (slave_callbacks->read_processed(slave_config, &data_byte) == 0) { + /* Non-last data byte */ + I2C_SET_DATA(i2c_base, data_byte); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Go S_TRAN_LAST_DATA_ACK on error */ + I2C_SET_DATA(i2c_base, 0xFF); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_TRAN_DATA_NACK: /* Slave Transmit Data NACK */ + case S_TRAN_LAST_DATA_ACK: /* Slave Transmit Last Data ACK */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; + /* Slave Receive */ + case S_RECE_DATA_ACK: /* Slave Receive Data ACK */ + data_byte = I2C_GET_DATA(i2c_base); + if (slave_callbacks->write_received(slave_config, data_byte) == 0) { + /* Write OK, ACK next data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Write FAILED, NACK next data byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_RECE_DATA_NACK: /* Slave Receive Data NACK */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; + case S_RECE_ADDR_ACK: /* Slave Receive Address ACK */ + case S_RECE_ARB_LOST: /* Slave Receive Arbitration Lost */ + data->slave_xfer.slave_addressed = true; + if (slave_callbacks->write_requested(slave_config) == 0) { + /* Write ready, ACK next byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + } else { + /* Write not ready, NACK next byte */ + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk); + } + break; + case S_REPEAT_START_STOP: /* Slave Transmit/Receive Repeat Start or Stop */ + /* Go slave end */ + data->slave_xfer.slave_addressed = false; + slave_callbacks->stop(slave_config); + I2C_SET_CONTROL_REG(i2c_base, I2C_CTL0_SI_Msk | I2C_CTL0_AA_Msk); + break; +#endif /* CONFIG_I2C_TARGET */ + + case BUS_RELEASED: /* Bus Released */ + /* Ignore the interrupt raised by BUS_RELEASED. */ + break; + default: + __ASSERT(false, "Uncaught I2C FSM state"); + m_numaker_i2c_master_xfer_end(dev, true); + } +} + +static int i2c_numaker_init(const struct device *dev) +{ + const struct i2c_numaker_config *config = dev->config; + struct i2c_numaker_data *data = dev->data; + int err = 0; + struct numaker_scc_subsys scc_subsys; + + /* Validate this module's reset object */ + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("reset controller not ready"); + return -ENODEV; + } + + /* Clean mutable context */ + memset(data, 0x00, sizeof(*data)); + + k_sem_init(&data->lock, 1, 1); + k_sem_init(&data->master_xfer.xfer_sync, 0, 1); + + SYS_UnlockReg(); + + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + scc_subsys.pcc.clk_src = config->clk_src; + scc_subsys.pcc.clk_div = config->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + err = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t) &scc_subsys); + if (err != 0) { + goto cleanup; + } + /* Equivalent to CLK_SetModuleClock() */ + err = clock_control_configure(config->clkctrl_dev, + (clock_control_subsys_t) &scc_subsys, + NULL); + if (err != 0) { + goto cleanup; + } + + /* Configure pinmux (NuMaker's SYS MFP) */ + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err != 0) { + goto cleanup; + } + + /* Reset I2C to default state, same as BSP's SYS_ResetModule(id_rst) */ + reset_line_toggle_dt(&config->reset); + + err = i2c_numaker_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate)); + if (err != 0) { + goto cleanup; + } + + config->irq_config_func(dev); + +cleanup: + + SYS_LockReg(); + return err; +} + +static const struct i2c_driver_api i2c_numaker_driver_api = { + .configure = i2c_numaker_configure, + .get_config = i2c_numaker_get_config, + .transfer = i2c_numaker_transfer, +#ifdef CONFIG_I2C_TARGET + .target_register = i2c_numaker_slave_register, + .target_unregister = i2c_numaker_slave_unregister, +#endif + .recover_bus = i2c_numaker_recover_bus, +}; + +#define I2C_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static void i2c_numaker_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + i2c_numaker_isr, \ + DEVICE_DT_INST_GET(inst), \ + 0); \ + \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct i2c_numaker_config i2c_numaker_config_##inst = { \ + .i2c_base = (I2C_T *) DT_INST_REG_ADDR(inst), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))),\ + .irq_n = DT_INST_IRQN(inst), \ + .irq_config_func = i2c_numaker_irq_config_func_##inst, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .bitrate = DT_INST_PROP(inst, clock_frequency), \ + }; \ + \ + static struct i2c_numaker_data i2c_numaker_data_##inst; \ + \ + I2C_DEVICE_DT_INST_DEFINE(inst, \ + i2c_numaker_init, \ + NULL, \ + &i2c_numaker_data_##inst, \ + &i2c_numaker_config_##inst, \ + POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_numaker_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(I2C_NUMAKER_INIT); diff --git a/drivers/i2c/i2c_rtio.c b/drivers/i2c/i2c_rtio.c index 7e74329612d..6c02837065d 100644 --- a/drivers/i2c/i2c_rtio.c +++ b/drivers/i2c/i2c_rtio.c @@ -26,7 +26,7 @@ struct rtio_sqe *i2c_rtio_copy(struct rtio *r, sqe = rtio_sqe_acquire(r); if (sqe == NULL) { - rtio_spsc_drop_all(r->sq); + rtio_sqe_drop_all(r); return NULL; } diff --git a/drivers/i2c/i2c_rv32m1_lpi2c.c b/drivers/i2c/i2c_rv32m1_lpi2c.c index ca0f6e6ef2e..ef64f1ac3d3 100644 --- a/drivers/i2c/i2c_rv32m1_lpi2c.c +++ b/drivers/i2c/i2c_rv32m1_lpi2c.c @@ -15,6 +15,7 @@ #include #include #include +#include #include LOG_MODULE_REGISTER(rv32m1_lpi2c); diff --git a/drivers/i2c/i2c_sbcon.c b/drivers/i2c/i2c_sbcon.c index 8ef32d7bb89..e3ddd62b262 100644 --- a/drivers/i2c/i2c_sbcon.c +++ b/drivers/i2c/i2c_sbcon.c @@ -93,7 +93,7 @@ static int i2c_sbcon_transfer(const struct device *dev, struct i2c_msg *msgs, slave_address); } -static struct i2c_driver_api api = { +static const struct i2c_driver_api api = { .configure = i2c_sbcon_configure, .transfer = i2c_sbcon_transfer, }; diff --git a/drivers/i2c/i2c_sedi.c b/drivers/i2c/i2c_sedi.c index ab14a7be9dd..4802e0ba071 100644 --- a/drivers/i2c/i2c_sedi.c +++ b/drivers/i2c/i2c_sedi.c @@ -112,8 +112,10 @@ static int i2c_sedi_api_full_io(const struct device *dev, struct i2c_msg *msgs, return ret; } -static const struct i2c_driver_api i2c_sedi_apis = {.configure = i2c_sedi_api_configure, - .transfer = i2c_sedi_api_full_io}; +static const struct i2c_driver_api i2c_sedi_apis = { + .configure = i2c_sedi_api_configure, + .transfer = i2c_sedi_api_full_io +}; #ifdef CONFIG_PM_DEVICE diff --git a/drivers/i2c/i2c_sifive.c b/drivers/i2c/i2c_sifive.c index 671139bd266..ca2e4ae8b68 100644 --- a/drivers/i2c/i2c_sifive.c +++ b/drivers/i2c/i2c_sifive.c @@ -317,7 +317,7 @@ static int i2c_sifive_init(const struct device *dev) } -static struct i2c_driver_api i2c_sifive_api = { +static const struct i2c_driver_api i2c_sifive_api = { .configure = i2c_sifive_configure, .transfer = i2c_sifive_transfer, }; diff --git a/drivers/i2c/i2c_tca954x.c b/drivers/i2c/i2c_tca954x.c index da19336af73..9a61d2bad17 100644 --- a/drivers/i2c/i2c_tca954x.c +++ b/drivers/i2c/i2c_tca954x.c @@ -151,7 +151,7 @@ static int tca954x_channel_init(const struct device *dev) return 0; } -const struct i2c_driver_api tca954x_api_funcs = { +static const struct i2c_driver_api tca954x_api_funcs = { .configure = tca954x_configure, .transfer = tca954x_transfer, }; diff --git a/drivers/i2s/Kconfig.stm32 b/drivers/i2s/Kconfig.stm32 index 8ef499ce7c9..3a4078d9f7a 100644 --- a/drivers/i2s/Kconfig.stm32 +++ b/drivers/i2s/Kconfig.stm32 @@ -7,10 +7,11 @@ menuconfig I2S_STM32 bool "STM32 MCU I2S controller driver" default y depends on DT_HAS_ST_STM32_I2S_ENABLED + select CACHE_MANAGEMENT if CPU_HAS_DCACHE select DMA help Enable I2S support on the STM32 family of processors. - (Tested on the STM32F4 series) + (Tested on the STM32F4 & STM32H7 series) if I2S_STM32 diff --git a/drivers/i2s/i2s_ll_stm32.c b/drivers/i2s/i2s_ll_stm32.c index 7ff2d2c3b6e..bf06d5f4df7 100644 --- a/drivers/i2s/i2s_ll_stm32.c +++ b/drivers/i2s/i2s_ll_stm32.c @@ -16,26 +16,13 @@ #include #include #include +#include #include "i2s_ll_stm32.h" #include #include LOG_MODULE_REGISTER(i2s_ll_stm32); -/* FIXME change to - * #if __DCACHE_PRESENT == 1 - * when cache support is added - */ -#if 0 -#define DCACHE_INVALIDATE(addr, size) \ - SCB_InvalidateDCache_by_Addr((uint32_t *)addr, size) -#define DCACHE_CLEAN(addr, size) \ - SCB_CleanDCache_by_Addr((uint32_t *)addr, size) -#else -#define DCACHE_INVALIDATE(addr, size) {; } -#define DCACHE_CLEAN(addr, size) {; } -#endif - #define MODULO_INC(val, max) { val = (++val < max) ? val : 0; } static unsigned int div_round_closest(uint32_t dividend, uint32_t divisor) @@ -187,6 +174,9 @@ static int i2s_stm32_configure(const struct device *dev, enum i2s_dir dir, int ret; if (dir == I2S_DIR_RX) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + return -ENOSYS; +#endif stream = &dev_data->rx; } else if (dir == I2S_DIR_TX) { stream = &dev_data->tx; @@ -549,7 +539,11 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg, ret = reload_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->mem_block, stream->cfg.block_size); if (ret < 0) { @@ -558,7 +552,7 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg, } /* Assure cache coherency after DMA write operation */ - DCACHE_INVALIDATE(mblk_tmp, stream->cfg.block_size); + sys_cache_data_invd_range(mblk_tmp, stream->cfg.block_size); /* All block data received */ ret = queue_put(&stream->mem_block_queue, mblk_tmp, @@ -629,12 +623,16 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, k_sem_give(&stream->sem); /* Assure cache coherency before DMA read operation */ - DCACHE_CLEAN(stream->mem_block, mem_block_size); + sys_cache_data_flush_range(stream->mem_block, mem_block_size); ret = reload_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, stream->mem_block, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->cfg.block_size); if (ret < 0) { LOG_DBG("Failed to start TX DMA transfer: %d", ret); @@ -649,6 +647,7 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg, static uint32_t i2s_stm32_irq_count; static uint32_t i2s_stm32_irq_ovr_count; +static uint32_t i2s_stm32_irq_udr_count; static void i2s_stm32_isr(const struct device *dev) { @@ -665,6 +664,12 @@ static void i2s_stm32_isr(const struct device *dev) LL_I2S_ClearFlag_OVR(cfg->i2s); } + /* NOTE: UDR error must be explicitly cleared on STM32H7 */ + if (LL_I2S_IsActiveFlag_UDR(cfg->i2s)) { + i2s_stm32_irq_udr_count++; + LL_I2S_ClearFlag_UDR(cfg->i2s); + } + i2s_stm32_irq_count++; } @@ -736,7 +741,11 @@ static int rx_stream_start(struct stream *stream, const struct device *dev) ret = start_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetRxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->src_addr_increment, stream->mem_block, stream->dst_addr_increment, stream->fifo_threshold, stream->cfg.block_size); @@ -747,8 +756,17 @@ static int rx_stream_start(struct stream *stream, const struct device *dev) LL_I2S_EnableDMAReq_RX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_EnableIT_OVR(cfg->i2s); + LL_I2S_EnableIT_UDR(cfg->i2s); + LL_I2S_EnableIT_FRE(cfg->i2s); + LL_I2S_Enable(cfg->i2s); + LL_SPI_StartMasterTransfer(cfg->i2s); +#else LL_I2S_EnableIT_ERR(cfg->i2s); LL_I2S_Enable(cfg->i2s); +#endif + return 0; } @@ -767,7 +785,7 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) k_sem_give(&stream->sem); /* Assure cache coherency before DMA read operation */ - DCACHE_CLEAN(stream->mem_block, mem_block_size); + sys_cache_data_flush_range(stream->mem_block, mem_block_size); if (stream->master) { LL_I2S_SetTransferMode(cfg->i2s, LL_I2S_MODE_MASTER_TX); @@ -781,7 +799,11 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) ret = start_dma(stream->dev_dma, stream->dma_channel, &stream->dma_cfg, stream->mem_block, stream->src_addr_increment, +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + (void *)LL_SPI_DMA_GetTxRegAddr(cfg->i2s), +#else (void *)LL_SPI_DMA_GetRegAddr(cfg->i2s), +#endif stream->dst_addr_increment, stream->fifo_threshold, stream->cfg.block_size); if (ret < 0) { @@ -791,8 +813,17 @@ static int tx_stream_start(struct stream *stream, const struct device *dev) LL_I2S_EnableDMAReq_TX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_EnableIT_OVR(cfg->i2s); + LL_I2S_EnableIT_UDR(cfg->i2s); + LL_I2S_EnableIT_FRE(cfg->i2s); + + LL_I2S_Enable(cfg->i2s); + LL_SPI_StartMasterTransfer(cfg->i2s); +#else LL_I2S_EnableIT_ERR(cfg->i2s); LL_I2S_Enable(cfg->i2s); +#endif return 0; } @@ -802,7 +833,13 @@ static void rx_stream_disable(struct stream *stream, const struct device *dev) const struct i2s_stm32_cfg *cfg = dev->config; LL_I2S_DisableDMAReq_RX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_DisableIT_OVR(cfg->i2s); + LL_I2S_DisableIT_UDR(cfg->i2s); + LL_I2S_DisableIT_FRE(cfg->i2s); +#else LL_I2S_DisableIT_ERR(cfg->i2s); +#endif dma_stop(stream->dev_dma, stream->dma_channel); if (stream->mem_block != NULL) { @@ -820,7 +857,13 @@ static void tx_stream_disable(struct stream *stream, const struct device *dev) const struct i2s_stm32_cfg *cfg = dev->config; LL_I2S_DisableDMAReq_TX(cfg->i2s); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_i2s) + LL_I2S_DisableIT_OVR(cfg->i2s); + LL_I2S_DisableIT_UDR(cfg->i2s); + LL_I2S_DisableIT_FRE(cfg->i2s); +#else LL_I2S_DisableIT_ERR(cfg->i2s); +#endif dma_stop(stream->dev_dma, stream->dma_channel); if (stream->mem_block != NULL) { diff --git a/drivers/i2s/i2s_mcux_flexcomm.c b/drivers/i2s/i2s_mcux_flexcomm.c index 4155bd24b62..6e966edd4a1 100644 --- a/drivers/i2s/i2s_mcux_flexcomm.c +++ b/drivers/i2s/i2s_mcux_flexcomm.c @@ -75,16 +75,24 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, I2S_TxGetDefaultConfig(fsl_cfg); } - /* Support single channel pair */ - if (i2s_cfg->channels == 0 || i2s_cfg->channels > 2) { - LOG_ERR("unsupported number of channels"); - return -EINVAL; + fsl_cfg->dataLength = i2s_cfg->word_size; + if ((i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) == + I2S_FMT_DATA_FORMAT_I2S) { + /* Classic I2S. We always use 2 channels */ + fsl_cfg->frameLength = 2 * i2s_cfg->word_size; + } else { + fsl_cfg->frameLength = i2s_cfg->channels * i2s_cfg->word_size; } - fsl_cfg->oneChannel = (i2s_cfg->channels == 1); + if (fsl_cfg->dataLength < 4 || fsl_cfg->dataLength > 32) { + LOG_ERR("Unsupported data length"); + return -EINVAL; + } - fsl_cfg->dataLength = i2s_cfg->word_size; - fsl_cfg->frameLength = i2s_cfg->channels * i2s_cfg->word_size; + if (fsl_cfg->frameLength < 4 || fsl_cfg->frameLength > 2048) { + LOG_ERR("Unsupported frame length"); + return -EINVAL; + } /* Set master/slave configuration */ switch (i2s_cfg->options & (I2S_OPT_BIT_CLK_SLAVE | @@ -105,11 +113,6 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, break; } - /* - * Set format. Zephyr choose arbitrary subset of possible - * formats, the mapping below is not tested for anything - * but classic mode and is not guaranteed to be correct. - */ switch (i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) { case I2S_FMT_DATA_FORMAT_I2S: fsl_cfg->mode = kI2S_ModeI2sClassic; @@ -126,10 +129,6 @@ static int i2s_mcux_flexcomm_cfg_convert(uint32_t base_frequency, fsl_cfg->mode = kI2S_ModeDspWs50; fsl_cfg->wsPol = true; break; - case I2S_FMT_DATA_FORMAT_RIGHT_JUSTIFIED: - fsl_cfg->mode = kI2S_ModeDspWs50; - fsl_cfg->wsPol = true; - break; default: LOG_ERR("Unsupported I2S data format"); return -EINVAL; @@ -191,13 +190,10 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, { const struct i2s_mcux_config *cfg = dev->config; struct i2s_mcux_data *dev_data = dev->data; - I2S_Type *base = cfg->base; struct stream *stream; uint32_t base_frequency; i2s_config_t fsl_cfg; int result; - uint8_t bits_per_word = 0; - uint8_t bytes_per_word = 0; if (dir == I2S_DIR_RX) { stream = &dev_data->rx; @@ -261,27 +257,52 @@ static int i2s_mcux_configure(const struct device *dev, enum i2s_dir dir, I2S_TxInit(cfg->base, &fsl_cfg); } - /* Data length in bits */ - bits_per_word = (uint8_t)(((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> - I2S_CFG1_DATALEN_SHIFT) + 1U); - - /* Convert to bytes */ - bytes_per_word = (bits_per_word + 7U) / 8U; - - /* if one channel is disabled, bytes_per_word should be 4U, user should - * pay attention that when data length is shorter than 16, - * the data format: left data put in 0-15 bit and right data should put in 16-31 - */ - if (((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) == 0U)) { - bytes_per_word = 4U; - } - /* since DMA do not support 24bit transfer width, use 32bit instead */ - if (bytes_per_word == 3U) { - bytes_per_word = 4U; + if ((i2s_cfg->channels > 2) && + (i2s_cfg->format & I2S_FMT_DATA_FORMAT_MASK) != + I2S_FMT_DATA_FORMAT_I2S) { + /* + * More than 2 channels are enabled, so we need to enable + * secondary channel pairs. + */ +#if (defined(FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL) && \ + FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL) + for (uint32_t slot = 1; slot < i2s_cfg->channels / 2; slot++) { + /* Position must be set so that data does not overlap + * with previous channel pair. Each channel pair + * will occupy slots of "word_size" bits. + */ + I2S_EnableSecondaryChannel(cfg->base, slot - 1, false, + i2s_cfg->word_size * 2 * slot); + } +#else + /* No support */ + return -ENOTSUP; +#endif } - stream->dma_cfg.dest_data_size = bytes_per_word; - stream->dma_cfg.source_data_size = bytes_per_word; + /* + * I2S API definition specifies that a "16 bit word will occupy 2 bytes, + * a 24 or 32 bit word will occupy 4 bytes". Therefore, we will assume + * that "odd" word sizes will be aligned to 16 or 32 bit boundaries. + * + * FIFO depth is controlled by the number of bits per word (DATALEN). + * Per the RM: + * If the data length is 4-16, the FIFO should be filled + * with two 16 bit values (one for left, one for right channel) + * + * If the data length is 17-24, the FIFO should be filled with 2 24 bit + * values (one for left, one for right channel). We can just transfer + * 4 bytes, since the I2S API specifies 24 bit values would be aligned + * to a 32 bit boundary. + * + * If the data length is 25-32, the FIFO should be filled + * with one 32 bit value. First value is left channel, second is right. + * + * All this is to say that we can always use 4 byte transfer widths + * with the DMA engine, regardless of the data length. + */ + stream->dma_cfg.dest_data_size = 4U; + stream->dma_cfg.source_data_size = 4U; /* Save configuration for get_config */ memcpy(&stream->cfg, i2s_cfg, sizeof(struct i2s_config)); @@ -930,6 +951,7 @@ static int i2s_mcux_init(const struct device *dev) .dma_cfg = { \ .channel_direction = PERIPHERAL_TO_MEMORY, \ .dma_callback = i2s_mcux_dma_rx_callback, \ + .complete_callback_en = true, \ .block_count = NUM_RX_DMA_BLOCKS, \ } \ } diff --git a/drivers/i2s/i2s_nrfx.c b/drivers/i2s/i2s_nrfx.c index e1b3684c4f7..b4a6f55443f 100644 --- a/drivers/i2s/i2s_nrfx.c +++ b/drivers/i2s/i2s_nrfx.c @@ -20,6 +20,11 @@ struct stream_cfg { nrfx_i2s_config_t nrfx_cfg; }; +struct i2s_buf { + void *mem_block; + size_t size; +}; + struct i2s_nrfx_drv_data { struct onoff_manager *clk_mgr; struct onoff_client clk_cli; @@ -189,9 +194,14 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg, static bool get_next_tx_buffer(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *buffers) { + struct i2s_buf buf; int ret = k_msgq_get(&drv_data->tx_queue, - &buffers->p_tx_buffer, + &buf, K_NO_WAIT); + if (ret == 0) { + buffers->p_tx_buffer = buf.mem_block; + buffers->buffer_size = buf.size / sizeof(uint32_t); + } return (ret == 0); } @@ -226,16 +236,23 @@ static void free_rx_buffer(struct i2s_nrfx_drv_data *drv_data, void *buffer) static bool supply_next_buffers(struct i2s_nrfx_drv_data *drv_data, nrfx_i2s_buffers_t *next) { - drv_data->last_tx_buffer = next->p_tx_buffer; - if (drv_data->active_dir != I2S_DIR_TX) { /* -> RX active */ if (!get_next_rx_buffer(drv_data, next)) { drv_data->state = I2S_STATE_ERROR; nrfx_i2s_stop(drv_data->p_i2s); return false; } + /* Set buffer size if there is no TX buffer (which effectively + * controls how many bytes will be received). + */ + if (drv_data->active_dir == I2S_DIR_RX) { + next->buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } } + drv_data->last_tx_buffer = next->p_tx_buffer; + LOG_DBG("Next buffers: %p/%p", next->p_tx_buffer, next->p_rx_buffer); nrfx_i2s_next_buffers_set(drv_data->p_i2s, next); return true; @@ -294,8 +311,12 @@ static void data_handler(const struct device *dev, if (drv_data->discard_rx) { free_rx_buffer(drv_data, released->p_rx_buffer); } else { + struct i2s_buf buf = { + .mem_block = released->p_rx_buffer, + .size = released->buffer_size * sizeof(uint32_t) + }; int ret = k_msgq_put(&drv_data->rx_queue, - &released->p_rx_buffer, + &buf, K_NO_WAIT); if (ret < 0) { LOG_ERR("No room in RX queue"); @@ -345,6 +366,7 @@ static void data_handler(const struct device *dev, * before this buffer would be started again). */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = 1; } else if (get_next_tx_buffer(drv_data, &next)) { /* Next TX buffer successfully retrieved from * the queue, nothing more to do here. @@ -361,6 +383,7 @@ static void data_handler(const struct device *dev, * will be stopped earlier. */ next.p_tx_buffer = drv_data->last_tx_buffer; + next.buffer_size = 1; } else { /* Next TX buffer cannot be supplied now. * Defer it to when the user writes more data. @@ -377,21 +400,21 @@ static void data_handler(const struct device *dev, static void purge_queue(const struct device *dev, enum i2s_dir dir) { struct i2s_nrfx_drv_data *drv_data = dev->data; - void *mem_block; + struct i2s_buf buf; if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH) { while (k_msgq_get(&drv_data->tx_queue, - &mem_block, + &buf, K_NO_WAIT) == 0) { - free_tx_buffer(drv_data, mem_block); + free_tx_buffer(drv_data, buf.mem_block); } } if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH) { while (k_msgq_get(&drv_data->rx_queue, - &mem_block, + &buf, K_NO_WAIT) == 0) { - free_rx_buffer(drv_data, mem_block); + free_rx_buffer(drv_data, buf.mem_block); } } } @@ -501,7 +524,8 @@ static int i2s_nrfx_configure(const struct device *dev, enum i2s_dir dir, * the MCK output is used), find a suitable clock configuration for it. */ if (nrfx_cfg.mode == NRF_I2S_MODE_MASTER || - nrfx_cfg.mck_pin != NRF_I2S_PIN_NOT_CONNECTED) { + (nrf_i2s_mck_pin_get(drv_cfg->i2s.p_reg) & I2S_PSEL_MCK_CONNECT_Msk) + == I2S_PSEL_MCK_CONNECT_Connected << I2S_PSEL_MCK_CONNECT_Pos) { find_suitable_clock(drv_cfg, &nrfx_cfg, i2s_cfg); /* Unless the PCLK32M source is used with the HFINT oscillator * (which is always available without any additional actions), @@ -554,6 +578,7 @@ static int i2s_nrfx_read(const struct device *dev, void **mem_block, size_t *size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf; int ret; if (!drv_data->rx_configured) { @@ -562,7 +587,7 @@ static int i2s_nrfx_read(const struct device *dev, } ret = k_msgq_get(&drv_data->rx_queue, - mem_block, + &buf, (drv_data->state == I2S_STATE_ERROR) ? K_NO_WAIT : SYS_TIMEOUT_MS(drv_data->rx.cfg.timeout)); @@ -570,10 +595,11 @@ static int i2s_nrfx_read(const struct device *dev, return -EIO; } - LOG_DBG("Released RX %p", *mem_block); + LOG_DBG("Released RX %p", buf.mem_block); if (ret == 0) { - *size = drv_data->rx.cfg.block_size; + *mem_block = buf.mem_block; + *size = buf.size; } return ret; @@ -583,6 +609,7 @@ static int i2s_nrfx_write(const struct device *dev, void *mem_block, size_t size) { struct i2s_nrfx_drv_data *drv_data = dev->data; + struct i2s_buf buf = { .mem_block = mem_block, .size = size }; int ret; if (!drv_data->tx_configured) { @@ -596,14 +623,14 @@ static int i2s_nrfx_write(const struct device *dev, return -EIO; } - if (size != drv_data->tx.cfg.block_size) { - LOG_ERR("This device can only write blocks of %u bytes", + if (size > drv_data->tx.cfg.block_size || size < sizeof(uint32_t)) { + LOG_ERR("This device can only write blocks up to %u bytes", drv_data->tx.cfg.block_size); return -EIO; } ret = k_msgq_put(&drv_data->tx_queue, - &mem_block, + &buf, SYS_TIMEOUT_MS(drv_data->tx.cfg.timeout)); if (ret < 0) { return ret; @@ -656,15 +683,20 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data) /* Failed to allocate next RX buffer */ ret = -ENOMEM; } else { - uint32_t block_size = (drv_data->active_dir == I2S_DIR_TX) - ? drv_data->tx.cfg.block_size - : drv_data->rx.cfg.block_size; nrfx_err_t err; + /* It is necessary to set buffer size here only for I2S_DIR_RX, + * because only then the get_next_tx_buffer() call in the if + * condition above gets short-circuited. + */ + if (drv_data->active_dir == I2S_DIR_RX) { + initial_buffers.buffer_size = + drv_data->rx.cfg.block_size / sizeof(uint32_t); + } + drv_data->last_tx_buffer = initial_buffers.p_tx_buffer; - err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, - block_size / sizeof(uint32_t), 0); + err = nrfx_i2s_start(drv_data->p_i2s, &initial_buffers, 0); if (err == NRFX_SUCCESS) { return 0; } @@ -898,8 +930,8 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { #define I2S_CLK_SRC(idx) DT_STRING_TOKEN(I2S(idx), clock_source) #define I2S_NRFX_DEVICE(idx) \ - static void *tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ - static void *rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ + static struct i2s_buf tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \ + static struct i2s_buf rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \ static void data_handler##idx(nrfx_i2s_buffers_t const *p_released, \ uint32_t status) \ { \ @@ -935,10 +967,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = { return err; \ } \ k_msgq_init(&i2s_nrfx_data##idx.tx_queue, \ - (char *)tx_msgs##idx, sizeof(void *), \ + (char *)tx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(tx_msgs##idx)); \ k_msgq_init(&i2s_nrfx_data##idx.rx_queue, \ - (char *)rx_msgs##idx, sizeof(void *), \ + (char *)rx_msgs##idx, sizeof(struct i2s_buf), \ ARRAY_SIZE(rx_msgs##idx)); \ init_clock_manager(dev); \ return 0; \ diff --git a/drivers/i3c/i3c_cdns.c b/drivers/i3c/i3c_cdns.c index cad71e5cae6..ef361523e4e 100644 --- a/drivers/i3c/i3c_cdns.c +++ b/drivers/i3c/i3c_cdns.c @@ -14,154 +14,154 @@ #include #include -#define DEV_ID 0x0 +#define DEV_ID 0x0 #define DEV_ID_I3C_MASTER 0x5034 -#define CONF_STATUS0 0x4 +#define CONF_STATUS0 0x4 #define CONF_STATUS0_CMDR_DEPTH(x) (4 << (((x)&GENMASK(31, 29)) >> 29)) -#define CONF_STATUS0_ECC_CHK BIT(28) -#define CONF_STATUS0_INTEG_CHK BIT(27) +#define CONF_STATUS0_ECC_CHK BIT(28) +#define CONF_STATUS0_INTEG_CHK BIT(27) #define CONF_STATUS0_CSR_DAP_CHK BIT(26) #define CONF_STATUS0_TRANS_TOUT_CHK BIT(25) #define CONF_STATUS0_PROT_FAULTS_CHK BIT(24) -#define CONF_STATUS0_GPO_NUM(x) (((x)&GENMASK(23, 16)) >> 16) -#define CONF_STATUS0_GPI_NUM(x) (((x)&GENMASK(15, 8)) >> 8) +#define CONF_STATUS0_GPO_NUM(x) (((x)&GENMASK(23, 16)) >> 16) +#define CONF_STATUS0_GPI_NUM(x) (((x)&GENMASK(15, 8)) >> 8) #define CONF_STATUS0_IBIR_DEPTH(x) (4 << (((x)&GENMASK(7, 6)) >> 7)) #define CONF_STATUS0_SUPPORTS_DDR BIT(5) -#define CONF_STATUS0_SEC_MASTER BIT(4) +#define CONF_STATUS0_SEC_MASTER BIT(4) #define CONF_STATUS0_DEVS_NUM(x) ((x)&GENMASK(3, 0)) -#define CONF_STATUS1 0x8 -#define CONF_STATUS1_IBI_HW_RES(x) ((((x)&GENMASK(31, 28)) >> 28) + 1) -#define CONF_STATUS1_CMD_DEPTH(x) (4 << (((x)&GENMASK(27, 26)) >> 26)) +#define CONF_STATUS1 0x8 +#define CONF_STATUS1_IBI_HW_RES(x) ((((x)&GENMASK(31, 28)) >> 28) + 1) +#define CONF_STATUS1_CMD_DEPTH(x) (4 << (((x)&GENMASK(27, 26)) >> 26)) #define CONF_STATUS1_SLVDDR_RX_DEPTH(x) (8 << (((x)&GENMASK(25, 21)) >> 21)) #define CONF_STATUS1_SLVDDR_TX_DEPTH(x) (8 << (((x)&GENMASK(20, 16)) >> 16)) -#define CONF_STATUS1_IBI_DEPTH(x) (2 << (((x)&GENMASK(12, 10)) >> 10)) -#define CONF_STATUS1_RX_DEPTH(x) (8 << (((x)&GENMASK(9, 5)) >> 5)) -#define CONF_STATUS1_TX_DEPTH(x) (8 << ((x)&GENMASK(4, 0))) - -#define REV_ID 0xc -#define REV_ID_VID(id) (((id)&GENMASK(31, 20)) >> 20) -#define REV_ID_PID(id) (((id)&GENMASK(19, 8)) >> 8) -#define REV_ID_REV(id) ((id)&GENMASK(7, 0)) +#define CONF_STATUS1_IBI_DEPTH(x) (2 << (((x)&GENMASK(12, 10)) >> 10)) +#define CONF_STATUS1_RX_DEPTH(x) (8 << (((x)&GENMASK(9, 5)) >> 5)) +#define CONF_STATUS1_TX_DEPTH(x) (8 << ((x)&GENMASK(4, 0))) + +#define REV_ID 0xc +#define REV_ID_VID(id) (((id)&GENMASK(31, 20)) >> 20) +#define REV_ID_PID(id) (((id)&GENMASK(19, 8)) >> 8) +#define REV_ID_REV(id) ((id)&GENMASK(7, 0)) #define REV_ID_VERSION(m, n) ((m << 5) | (n)) #define REV_ID_REV_MAJOR(id) (((id)&GENMASK(7, 5)) >> 5) #define REV_ID_REV_MINOR(id) ((id)&GENMASK(4, 0)) -#define CTRL 0x10 -#define CTRL_DEV_EN BIT(31) -#define CTRL_HALT_EN BIT(30) -#define CTRL_MCS BIT(29) -#define CTRL_MCS_EN BIT(28) -#define CTRL_I3C_11_SUPP BIT(26) -#define CTRL_THD_DELAY(x) (((x) << 24) & GENMASK(25, 24)) -#define CTRL_HJ_DISEC BIT(8) -#define CTRL_MST_ACK BIT(7) -#define CTRL_HJ_ACK BIT(6) -#define CTRL_HJ_INIT BIT(5) -#define CTRL_MST_INIT BIT(4) -#define CTRL_AHDR_OPT BIT(3) -#define CTRL_PURE_BUS_MODE 0 +#define CTRL 0x10 +#define CTRL_DEV_EN BIT(31) +#define CTRL_HALT_EN BIT(30) +#define CTRL_MCS BIT(29) +#define CTRL_MCS_EN BIT(28) +#define CTRL_I3C_11_SUPP BIT(26) +#define CTRL_THD_DELAY(x) (((x) << 24) & GENMASK(25, 24)) +#define CTRL_HJ_DISEC BIT(8) +#define CTRL_MST_ACK BIT(7) +#define CTRL_HJ_ACK BIT(6) +#define CTRL_HJ_INIT BIT(5) +#define CTRL_MST_INIT BIT(4) +#define CTRL_AHDR_OPT BIT(3) +#define CTRL_PURE_BUS_MODE 0 #define CTRL_MIXED_FAST_BUS_MODE 2 #define CTRL_MIXED_SLOW_BUS_MODE 3 -#define CTRL_BUS_MODE_MASK GENMASK(1, 0) -#define THD_DELAY_MAX 3 +#define CTRL_BUS_MODE_MASK GENMASK(1, 0) +#define THD_DELAY_MAX 3 -#define PRESCL_CTRL0 0x14 +#define PRESCL_CTRL0 0x14 #define PRESCL_CTRL0_I2C(x) ((x) << 16) #define PRESCL_CTRL0_I3C(x) (x) #define PRESCL_CTRL0_MAX GENMASK(9, 0) -#define PRESCL_CTRL1 0x18 +#define PRESCL_CTRL1 0x18 #define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8) -#define PRESCL_CTRL1_PP_LOW(x) ((x) << 8) +#define PRESCL_CTRL1_PP_LOW(x) ((x) << 8) #define PRESCL_CTRL1_OD_LOW_MASK GENMASK(7, 0) -#define PRESCL_CTRL1_OD_LOW(x) (x) - -#define MST_IER 0x20 -#define MST_IDR 0x24 -#define MST_IMR 0x28 -#define MST_ICR 0x2c -#define MST_ISR 0x30 -#define MST_INT_HALTED BIT(18) -#define MST_INT_MR_DONE BIT(17) +#define PRESCL_CTRL1_OD_LOW(x) (x) + +#define MST_IER 0x20 +#define MST_IDR 0x24 +#define MST_IMR 0x28 +#define MST_ICR 0x2c +#define MST_ISR 0x30 +#define MST_INT_HALTED BIT(18) +#define MST_INT_MR_DONE BIT(17) #define MST_INT_IMM_COMP BIT(16) -#define MST_INT_TX_THR BIT(15) -#define MST_INT_TX_OVF BIT(14) +#define MST_INT_TX_THR BIT(15) +#define MST_INT_TX_OVF BIT(14) #define MST_INT_IBID_THR BIT(12) #define MST_INT_IBID_UNF BIT(11) #define MST_INT_IBIR_THR BIT(10) #define MST_INT_IBIR_UNF BIT(9) #define MST_INT_IBIR_OVF BIT(8) -#define MST_INT_RX_THR BIT(7) -#define MST_INT_RX_UNF BIT(6) +#define MST_INT_RX_THR BIT(7) +#define MST_INT_RX_UNF BIT(6) #define MST_INT_CMDD_EMP BIT(5) #define MST_INT_CMDD_THR BIT(4) #define MST_INT_CMDD_OVF BIT(3) #define MST_INT_CMDR_THR BIT(2) #define MST_INT_CMDR_UNF BIT(1) #define MST_INT_CMDR_OVF BIT(0) -#define MST_INT_MASK GENMASK(18, 0) +#define MST_INT_MASK GENMASK(18, 0) -#define MST_STATUS0 0x34 -#define MST_STATUS0_IDLE BIT(18) -#define MST_STATUS0_HALTED BIT(17) +#define MST_STATUS0 0x34 +#define MST_STATUS0_IDLE BIT(18) +#define MST_STATUS0_HALTED BIT(17) #define MST_STATUS0_MASTER_MODE BIT(16) -#define MST_STATUS0_TX_FULL BIT(13) -#define MST_STATUS0_IBID_FULL BIT(12) -#define MST_STATUS0_IBIR_FULL BIT(11) -#define MST_STATUS0_RX_FULL BIT(10) -#define MST_STATUS0_CMDD_FULL BIT(9) -#define MST_STATUS0_CMDR_FULL BIT(8) -#define MST_STATUS0_TX_EMP BIT(5) -#define MST_STATUS0_IBID_EMP BIT(4) -#define MST_STATUS0_IBIR_EMP BIT(3) -#define MST_STATUS0_RX_EMP BIT(2) -#define MST_STATUS0_CMDD_EMP BIT(1) -#define MST_STATUS0_CMDR_EMP BIT(0) - -#define CMDR 0x38 -#define CMDR_NO_ERROR 0 +#define MST_STATUS0_TX_FULL BIT(13) +#define MST_STATUS0_IBID_FULL BIT(12) +#define MST_STATUS0_IBIR_FULL BIT(11) +#define MST_STATUS0_RX_FULL BIT(10) +#define MST_STATUS0_CMDD_FULL BIT(9) +#define MST_STATUS0_CMDR_FULL BIT(8) +#define MST_STATUS0_TX_EMP BIT(5) +#define MST_STATUS0_IBID_EMP BIT(4) +#define MST_STATUS0_IBIR_EMP BIT(3) +#define MST_STATUS0_RX_EMP BIT(2) +#define MST_STATUS0_CMDD_EMP BIT(1) +#define MST_STATUS0_CMDR_EMP BIT(0) + +#define CMDR 0x38 +#define CMDR_NO_ERROR 0 #define CMDR_DDR_PREAMBLE_ERROR 1 -#define CMDR_DDR_PARITY_ERROR 2 -#define CMDR_DDR_RX_FIFO_OVF 3 -#define CMDR_DDR_TX_FIFO_UNF 4 -#define CMDR_M0_ERROR 5 -#define CMDR_M1_ERROR 6 -#define CMDR_M2_ERROR 7 -#define CMDR_MST_ABORT 8 -#define CMDR_NACK_RESP 9 -#define CMDR_INVALID_DA 10 -#define CMDR_DDR_DROPPED 11 -#define CMDR_ERROR(x) (((x)&GENMASK(27, 24)) >> 24) -#define CMDR_XFER_BYTES(x) (((x)&GENMASK(19, 8)) >> 8) -#define CMDR_CMDID_HJACK_DISEC 0xfe +#define CMDR_DDR_PARITY_ERROR 2 +#define CMDR_DDR_RX_FIFO_OVF 3 +#define CMDR_DDR_TX_FIFO_UNF 4 +#define CMDR_M0_ERROR 5 +#define CMDR_M1_ERROR 6 +#define CMDR_M2_ERROR 7 +#define CMDR_MST_ABORT 8 +#define CMDR_NACK_RESP 9 +#define CMDR_INVALID_DA 10 +#define CMDR_DDR_DROPPED 11 +#define CMDR_ERROR(x) (((x)&GENMASK(27, 24)) >> 24) +#define CMDR_XFER_BYTES(x) (((x)&GENMASK(19, 8)) >> 8) +#define CMDR_CMDID_HJACK_DISEC 0xfe #define CMDR_CMDID_HJACK_ENTDAA 0xff -#define CMDR_CMDID(x) ((x)&GENMASK(7, 0)) +#define CMDR_CMDID(x) ((x)&GENMASK(7, 0)) -#define IBIR 0x3c -#define IBIR_ACKED BIT(12) -#define IBIR_SLVID(x) (((x)&GENMASK(11, 8)) >> 8) -#define IBIR_SLVID_INV 0xF -#define IBIR_ERROR BIT(7) +#define IBIR 0x3c +#define IBIR_ACKED BIT(12) +#define IBIR_SLVID(x) (((x)&GENMASK(11, 8)) >> 8) +#define IBIR_SLVID_INV 0xF +#define IBIR_ERROR BIT(7) #define IBIR_XFER_BYTES(x) (((x)&GENMASK(6, 2)) >> 2) -#define IBIR_TYPE_IBI 0 -#define IBIR_TYPE_HJ 1 -#define IBIR_TYPE_MR 2 -#define IBIR_TYPE(x) ((x)&GENMASK(1, 0)) - -#define SLV_IER 0x40 -#define SLV_IDR 0x44 -#define SLV_IMR 0x48 -#define SLV_ICR 0x4c -#define SLV_ISR 0x50 -#define SLV_INT_DEFSLVS BIT(21) -#define SLV_INT_TM BIT(20) -#define SLV_INT_ERROR BIT(19) +#define IBIR_TYPE_IBI 0 +#define IBIR_TYPE_HJ 1 +#define IBIR_TYPE_MR 2 +#define IBIR_TYPE(x) ((x)&GENMASK(1, 0)) + +#define SLV_IER 0x40 +#define SLV_IDR 0x44 +#define SLV_IMR 0x48 +#define SLV_ICR 0x4c +#define SLV_ISR 0x50 +#define SLV_INT_DEFSLVS BIT(21) +#define SLV_INT_TM BIT(20) +#define SLV_INT_ERROR BIT(19) #define SLV_INT_EVENT_UP BIT(18) -#define SLV_INT_HJ_DONE BIT(17) -#define SLV_INT_MR_DONE BIT(16) -#define SLV_INT_DA_UPD BIT(15) +#define SLV_INT_HJ_DONE BIT(17) +#define SLV_INT_MR_DONE BIT(16) +#define SLV_INT_DA_UPD BIT(15) #define SLV_INT_SDR_FAIL BIT(14) #define SLV_INT_DDR_FAIL BIT(13) #define SLV_INT_M_RD_ABORT BIT(12) @@ -177,73 +177,73 @@ #define SLV_INT_DDR_WR_COMP BIT(2) #define SLV_INT_SDR_RD_COMP BIT(1) #define SLV_INT_SDR_WR_COMP BIT(0) -#define SLV_INT_MASK GENMASK(20, 0) +#define SLV_INT_MASK GENMASK(20, 0) -#define SLV_STATUS0 0x54 -#define SLV_STATUS0_REG_ADDR(s) (((s)&GENMASK(23, 16)) >> 16) +#define SLV_STATUS0 0x54 +#define SLV_STATUS0_REG_ADDR(s) (((s)&GENMASK(23, 16)) >> 16) #define SLV_STATUS0_XFRD_BYTES(s) ((s)&GENMASK(15, 0)) -#define SLV_STATUS1 0x58 -#define SLV_STATUS1_AS(s) (((s)&GENMASK(21, 20)) >> 20) -#define SLV_STATUS1_VEN_TM BIT(19) -#define SLV_STATUS1_HJ_DIS BIT(18) -#define SLV_STATUS1_MR_DIS BIT(17) -#define SLV_STATUS1_PROT_ERR BIT(16) -#define SLV_STATUS1_DA(s) (((s)&GENMASK(15, 9)) >> 9) -#define SLV_STATUS1_HAS_DA BIT(8) -#define SLV_STATUS1_DDR_RX_FULL BIT(7) -#define SLV_STATUS1_DDR_TX_FULL BIT(6) +#define SLV_STATUS1 0x58 +#define SLV_STATUS1_AS(s) (((s)&GENMASK(21, 20)) >> 20) +#define SLV_STATUS1_VEN_TM BIT(19) +#define SLV_STATUS1_HJ_DIS BIT(18) +#define SLV_STATUS1_MR_DIS BIT(17) +#define SLV_STATUS1_PROT_ERR BIT(16) +#define SLV_STATUS1_DA(s) (((s)&GENMASK(15, 9)) >> 9) +#define SLV_STATUS1_HAS_DA BIT(8) +#define SLV_STATUS1_DDR_RX_FULL BIT(7) +#define SLV_STATUS1_DDR_TX_FULL BIT(6) #define SLV_STATUS1_DDR_RX_EMPTY BIT(5) #define SLV_STATUS1_DDR_TX_EMPTY BIT(4) -#define SLV_STATUS1_SDR_RX_FULL BIT(3) -#define SLV_STATUS1_SDR_TX_FULL BIT(2) +#define SLV_STATUS1_SDR_RX_FULL BIT(3) +#define SLV_STATUS1_SDR_TX_FULL BIT(2) #define SLV_STATUS1_SDR_RX_EMPTY BIT(1) #define SLV_STATUS1_SDR_TX_EMPTY BIT(0) -#define CMD0_FIFO 0x60 -#define CMD0_FIFO_IS_DDR BIT(31) -#define CMD0_FIFO_IS_CCC BIT(30) -#define CMD0_FIFO_BCH BIT(29) +#define CMD0_FIFO 0x60 +#define CMD0_FIFO_IS_DDR BIT(31) +#define CMD0_FIFO_IS_CCC BIT(30) +#define CMD0_FIFO_BCH BIT(29) #define XMIT_BURST_STATIC_SUBADDR 0 -#define XMIT_SINGLE_INC_SUBADDR 1 +#define XMIT_SINGLE_INC_SUBADDR 1 #define XMIT_SINGLE_STATIC_SUBADDR 2 #define XMIT_BURST_WITHOUT_SUBADDR 3 #define CMD0_FIFO_PRIV_XMIT_MODE(m) ((m) << 27) -#define CMD0_FIFO_SBCA BIT(26) -#define CMD0_FIFO_RSBC BIT(25) -#define CMD0_FIFO_IS_10B BIT(24) -#define CMD0_FIFO_PL_LEN(l) ((l) << 12) -#define CMD0_FIFO_PL_LEN_MAX 4095 -#define CMD0_FIFO_DEV_ADDR(a) ((a) << 1) -#define CMD0_FIFO_RNW BIT(0) - -#define CMD1_FIFO 0x64 +#define CMD0_FIFO_SBCA BIT(26) +#define CMD0_FIFO_RSBC BIT(25) +#define CMD0_FIFO_IS_10B BIT(24) +#define CMD0_FIFO_PL_LEN(l) ((l) << 12) +#define CMD0_FIFO_PL_LEN_MAX 4095 +#define CMD0_FIFO_DEV_ADDR(a) ((a) << 1) +#define CMD0_FIFO_RNW BIT(0) + +#define CMD1_FIFO 0x64 #define CMD1_FIFO_CMDID(id) ((id) << 24) #define CMD1_FIFO_CSRADDR(a) (a) #define CMD1_FIFO_CCC(id) (id) #define TX_FIFO 0x68 -#define IMD_CMD0 0x70 +#define IMD_CMD0 0x70 #define IMD_CMD0_PL_LEN(l) ((l) << 12) #define IMD_CMD0_DEV_ADDR(a) ((a) << 1) -#define IMD_CMD0_RNW BIT(0) +#define IMD_CMD0_RNW BIT(0) -#define IMD_CMD1 0x74 +#define IMD_CMD1 0x74 #define IMD_CMD1_CCC(id) (id) -#define IMD_DATA 0x78 -#define RX_FIFO 0x80 -#define IBI_DATA_FIFO 0x84 +#define IMD_DATA 0x78 +#define RX_FIFO 0x80 +#define IBI_DATA_FIFO 0x84 #define SLV_DDR_TX_FIFO 0x88 #define SLV_DDR_RX_FIFO 0x8c #define CMD_IBI_THR_CTRL 0x90 -#define IBIR_THR(t) ((t) << 24) -#define CMDR_THR(t) ((t) << 16) -#define CMDR_THR_MASK (GENMASK(20, 16)) -#define IBI_THR(t) ((t) << 8) -#define CMD_THR(t) (t) +#define IBIR_THR(t) ((t) << 24) +#define CMDR_THR(t) ((t) << 16) +#define CMDR_THR_MASK (GENMASK(20, 16)) +#define IBI_THR(t) ((t) << 8) +#define CMD_THR(t) (t) #define TX_RX_THR_CTRL 0x94 #define RX_THR(t) ((t) << 16) @@ -255,91 +255,91 @@ #define SLV_DDR_RX_THR(t) ((t) << 16) #define SLV_DDR_TX_THR(t) (t) -#define FLUSH_CTRL 0x9c -#define FLUSH_IBI_RESP BIT(23) -#define FLUSH_CMD_RESP BIT(22) +#define FLUSH_CTRL 0x9c +#define FLUSH_IBI_RESP BIT(23) +#define FLUSH_CMD_RESP BIT(22) #define FLUSH_SLV_DDR_RX_FIFO BIT(22) #define FLUSH_SLV_DDR_TX_FIFO BIT(21) -#define FLUSH_IMM_FIFO BIT(20) -#define FLUSH_IBI_FIFO BIT(19) -#define FLUSH_RX_FIFO BIT(18) -#define FLUSH_TX_FIFO BIT(17) -#define FLUSH_CMD_FIFO BIT(16) +#define FLUSH_IMM_FIFO BIT(20) +#define FLUSH_IBI_FIFO BIT(19) +#define FLUSH_RX_FIFO BIT(18) +#define FLUSH_TX_FIFO BIT(17) +#define FLUSH_CMD_FIFO BIT(16) -#define TTO_PRESCL_CTRL0 0xb0 +#define TTO_PRESCL_CTRL0 0xb0 #define TTO_PRESCL_CTRL0_PRESCL_I2C(x) ((x) << 16) #define TTO_PRESCL_CTRL0_PRESCL_I3C(x) (x) -#define TTO_PRESCL_CTRL1 0xb4 +#define TTO_PRESCL_CTRL1 0xb4 #define TTO_PRESCL_CTRL1_DIVB(x) ((x) << 16) #define TTO_PRESCL_CTRL1_DIVA(x) (x) #define TTO_PRESCL_CTRL1_PP_LOW(x) ((x) << 8) #define TTO_PRESCL_CTRL1_OD_LOW(x) (x) -#define DEVS_CTRL 0xb8 -#define DEVS_CTRL_DEV_CLR_SHIFT 16 -#define DEVS_CTRL_DEV_CLR_ALL GENMASK(31, 16) -#define DEVS_CTRL_DEV_CLR(dev) BIT(16 + (dev)) +#define DEVS_CTRL 0xb8 +#define DEVS_CTRL_DEV_CLR_SHIFT 16 +#define DEVS_CTRL_DEV_CLR_ALL GENMASK(31, 16) +#define DEVS_CTRL_DEV_CLR(dev) BIT(16 + (dev)) #define DEVS_CTRL_DEV_ACTIVE(dev) BIT(dev) #define DEVS_CTRL_DEVS_ACTIVE_MASK GENMASK(15, 0) -#define MAX_DEVS 16 +#define MAX_DEVS 16 -#define DEV_ID_RR0(d) (0xc0 + ((d)*0x10)) -#define DEV_ID_RR0_LVR_EXT_ADDR BIT(11) -#define DEV_ID_RR0_HDR_CAP BIT(10) -#define DEV_ID_RR0_IS_I3C BIT(9) +#define DEV_ID_RR0(d) (0xc0 + ((d)*0x10)) +#define DEV_ID_RR0_LVR_EXT_ADDR BIT(11) +#define DEV_ID_RR0_HDR_CAP BIT(10) +#define DEV_ID_RR0_IS_I3C BIT(9) #define DEV_ID_RR0_DEV_ADDR_MASK (GENMASK(6, 0) | GENMASK(15, 13)) #define DEV_ID_RR0_SET_DEV_ADDR(a) (((a)&GENMASK(6, 0)) | (((a)&GENMASK(9, 7)) << 6)) #define DEV_ID_RR0_GET_DEV_ADDR(x) ((((x) >> 1) & GENMASK(6, 0)) | (((x) >> 6) & GENMASK(9, 7))) -#define DEV_ID_RR1(d) (0xc4 + ((d)*0x10)) +#define DEV_ID_RR1(d) (0xc4 + ((d)*0x10)) #define DEV_ID_RR1_PID_MSB(pid) (pid) -#define DEV_ID_RR2(d) (0xc8 + ((d)*0x10)) +#define DEV_ID_RR2(d) (0xc8 + ((d)*0x10)) #define DEV_ID_RR2_PID_LSB(pid) ((pid) << 16) -#define DEV_ID_RR2_BCR(bcr) ((bcr) << 8) -#define DEV_ID_RR2_DCR(dcr) (dcr) -#define DEV_ID_RR2_LVR(lvr) (lvr) +#define DEV_ID_RR2_BCR(bcr) ((bcr) << 8) +#define DEV_ID_RR2_DCR(dcr) (dcr) +#define DEV_ID_RR2_LVR(lvr) (lvr) -#define SIR_MAP(x) (0x180 + ((x)*4)) -#define SIR_MAP_DEV_REG(d) SIR_MAP((d) / 2) +#define SIR_MAP(x) (0x180 + ((x)*4)) +#define SIR_MAP_DEV_REG(d) SIR_MAP((d) / 2) #define SIR_MAP_DEV_SHIFT(d, fs) ((fs) + (((d) % 2) ? 16 : 0)) #define SIR_MAP_DEV_CONF_MASK(d) (GENMASK(15, 0) << (((d) % 2) ? 16 : 0)) -#define SIR_MAP_DEV_CONF(d, c) ((c) << (((d) % 2) ? 16 : 0)) -#define DEV_ROLE_SLAVE 0 -#define DEV_ROLE_MASTER 1 -#define SIR_MAP_DEV_ROLE(role) ((role) << 14) -#define SIR_MAP_DEV_SLOW BIT(13) -#define SIR_MAP_DEV_PL(l) ((l) << 8) -#define SIR_MAP_PL_MAX GENMASK(4, 0) -#define SIR_MAP_DEV_DA(a) ((a) << 1) -#define SIR_MAP_DEV_ACK BIT(0) - -#define GPIR_WORD(x) (0x200 + ((x)*4)) +#define SIR_MAP_DEV_CONF(d, c) ((c) << (((d) % 2) ? 16 : 0)) +#define DEV_ROLE_SLAVE 0 +#define DEV_ROLE_MASTER 1 +#define SIR_MAP_DEV_ROLE(role) ((role) << 14) +#define SIR_MAP_DEV_SLOW BIT(13) +#define SIR_MAP_DEV_PL(l) ((l) << 8) +#define SIR_MAP_PL_MAX GENMASK(4, 0) +#define SIR_MAP_DEV_DA(a) ((a) << 1) +#define SIR_MAP_DEV_ACK BIT(0) + +#define GPIR_WORD(x) (0x200 + ((x)*4)) #define GPI_REG(val, id) (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) -#define GPOR_WORD(x) (0x220 + ((x)*4)) +#define GPOR_WORD(x) (0x220 + ((x)*4)) #define GPO_REG(val, id) (((val) >> (((id) % 4) * 8)) & GENMASK(7, 0)) -#define ASF_INT_STATUS 0x300 +#define ASF_INT_STATUS 0x300 #define ASF_INT_RAW_STATUS 0x304 -#define ASF_INT_MASK 0x308 -#define ASF_INT_TEST 0x30c +#define ASF_INT_MASK 0x308 +#define ASF_INT_TEST 0x30c #define ASF_INT_FATAL_SELECT 0x310 #define ASF_INTEGRITY_ERR BIT(6) #define ASF_PROTOCOL_ERR BIT(5) #define ASF_TRANS_TIMEOUT_ERR BIT(4) -#define ASF_CSR_ERR BIT(3) -#define ASF_DAP_ERR BIT(2) +#define ASF_CSR_ERR BIT(3) +#define ASF_DAP_ERR BIT(2) #define ASF_SRAM_UNCORR_ERR BIT(1) #define ASF_SRAM_CORR_ERR BIT(0) -#define ASF_SRAM_CORR_FAULT_STATUS 0x320 -#define ASF_SRAM_UNCORR_FAULT_STATUS 0x324 +#define ASF_SRAM_CORR_FAULT_STATUS 0x320 +#define ASF_SRAM_UNCORR_FAULT_STATUS 0x324 #define ASF_SRAM_CORR_FAULT_INSTANCE(x) ((x) >> 24) -#define ASF_SRAM_CORR_FAULT_ADDR(x) ((x)&GENMASK(23, 0)) +#define ASF_SRAM_CORR_FAULT_ADDR(x) ((x)&GENMASK(23, 0)) -#define ASF_SRAM_FAULT_STATS 0x328 +#define ASF_SRAM_FAULT_STATS 0x328 #define ASF_SRAM_FAULT_UNCORR_STATS(x) ((x) >> 16) #define ASF_SRAM_FAULT_CORR_STATS(x) ((x)&GENMASK(15, 0)) @@ -354,14 +354,14 @@ #define ASF_TRANS_TOUT_FAULT_SCL_HIGH BIT(1) #define ASF_TRANS_TOUT_FAULT_FSCL_HIGH BIT(0) -#define ASF_PROTO_FAULT_MASK 0x340 -#define ASF_PROTO_FAULT_STATUS 0x344 +#define ASF_PROTO_FAULT_MASK 0x340 +#define ASF_PROTO_FAULT_STATUS 0x344 #define ASF_PROTO_FAULT_SLVSDR_RD_ABORT BIT(31) -#define ASF_PROTO_FAULT_SLVDDR_FAIL BIT(30) -#define ASF_PROTO_FAULT_S(x) BIT(16 + (x)) +#define ASF_PROTO_FAULT_SLVDDR_FAIL BIT(30) +#define ASF_PROTO_FAULT_S(x) BIT(16 + (x)) #define ASF_PROTO_FAULT_MSTSDR_RD_ABORT BIT(15) -#define ASF_PROTO_FAULT_MSTDDR_FAIL BIT(14) -#define ASF_PROTO_FAULT_M(x) BIT(x) +#define ASF_PROTO_FAULT_MSTDDR_FAIL BIT(14) +#define ASF_PROTO_FAULT_M(x) BIT(x) /******************************************************************************* * Local Constants Definition @@ -371,13 +371,15 @@ #define I3C_CONTROLLER_ADDR 0x08 /* Maximum i3c devices that the IP can be built with */ -#define I3C_MAX_DEVS 11 -#define I3C_MAX_MSGS 10 -#define I3C_SIR_DEFAULT_DA 0x7F -#define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 -#define I3C_MAX_IDLE_WAIT_RETRIES 5000 -#define I3C_PRESCL_REG_SCALE (4) -#define I2C_PRESCL_REG_SCALE (5) +#define I3C_MAX_DEVS 11 +#define I3C_MAX_MSGS 10 +#define I3C_SIR_DEFAULT_DA 0x7F +#define I3C_MAX_IDLE_CANCEL_WAIT_RETRIES 50 +#define I3C_PRESCL_REG_SCALE (4) +#define I2C_PRESCL_REG_SCALE (5) +#define I3C_WAIT_FOR_IDLE_STATE_US 100 +#define I3C_IDLE_TIMEOUT_CYC \ + (I3C_WAIT_FOR_IDLE_STATE_US * (sys_clock_hw_cycles_per_sec() / USEC_PER_SEC)) /* Target T_LOW period in open-drain mode. */ #define I3C_BUS_TLOW_OD_MIN_NS 200 @@ -431,6 +433,7 @@ struct cdns_i3c_cmd { uint32_t cmd0; uint32_t cmd1; uint32_t len; + uint32_t *num_xfer; void *buf; uint32_t error; }; @@ -613,6 +616,25 @@ static int cdns_i3c_read_rx_fifo(const struct cdns_i3c_config *config, void *buf return 0; } +static inline int cdns_i3c_wait_for_idle(const struct device *dev) +{ + const struct cdns_i3c_config *config = dev->config; + uint32_t start_time = k_cycle_get_32(); + + /** + * Spin waiting for device to go idle. It is unlikely that this will + * actually take any time unless if the last transaction came immediately + * after an error condition. + */ + while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE)) { + if (k_cycle_get_32() - start_time > I3C_IDLE_TIMEOUT_CYC) { + return -EAGAIN; + } + } + + return 0; +} + static void cdns_i3c_set_prescalers(const struct device *dev) { struct cdns_i3c_data *data = dev->data; @@ -995,19 +1017,9 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1022,6 +1034,8 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay dcmd->buf = payload->ccc.data; dcmd->len = payload->ccc.data_len; dcmd->cmd0 |= CMD0_FIFO_PL_LEN(payload->ccc.data_len); + /* write the address of num_xfer which is to be updated upon message completion */ + dcmd->num_xfer = &(payload->ccc.num_xfer); } else if (payload->targets.num_targets > 0) { dcmd->buf = payload->targets.payloads[0].data; dcmd->len = payload->targets.payloads[0].data_len; @@ -1030,6 +1044,8 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay if (payload->targets.payloads[0].rnw) { dcmd->cmd0 |= CMD0_FIFO_RNW; } + /* write the address of num_xfer which is to be updated upon message completion */ + dcmd->num_xfer = &(payload->targets.payloads[0].num_xfer); idx++; } num_cmds++; @@ -1055,6 +1071,11 @@ static int cdns_i3c_do_ccc(const struct device *dev, struct i3c_ccc_payload *pay cmd->buf = tgt_payload->data; cmd->len = tgt_payload->data_len; + /* + * write the address of num_xfer which is to be updated upon message + * completion + */ + cmd->num_xfer = &(tgt_payload->num_xfer); idx++; } @@ -1263,6 +1284,10 @@ static void cdns_i3c_complete_transfer(const struct device *dev) uint32_t rx = 0; int ret = 0; struct cdns_i3c_cmd *cmd; + bool was_full; + + /* Used only to determine in the case of a controller abort */ + was_full = cdns_i3c_rx_fifo_full(config); /* Disable further interrupts */ sys_write32(MST_INT_CMDD_EMP, config->base + MST_IDR); @@ -1288,6 +1313,9 @@ static void cdns_i3c_complete_transfer(const struct device *dev) /* Read any rx data into buffer */ if (cmd->cmd0 & CMD0_FIFO_RNW) { rx = MIN(CMDR_XFER_BYTES(cmdr), cmd->len); + if (cmd->num_xfer != NULL) { + *cmd->num_xfer = rx; + } ret = cdns_i3c_read_rx_fifo(config, cmd->buf, rx); } @@ -1300,12 +1328,33 @@ static void cdns_i3c_complete_transfer(const struct device *dev) case CMDR_NO_ERROR: break; + case CMDR_MST_ABORT: + /* + * A controller abort is forced if the RX FIFO fills up + * There is also the case where the fifo can be full as + * the len of the packet is the same length of the fifo + * Check that the requested len is greater than the total + * transferred to confirm that is not case. Otherwise the + * abort was caused by the buffer length being meet and + * the target did not give an End of Data (EoD) in the T + * bit. Do not treat that condition as an error because + * some targets will just auto-increment the read address + * way beyond the buffer not giving an EoD. + */ + if ((was_full) && (data->xfer.cmds[i].len > *data->xfer.cmds[i].num_xfer)) { + ret = -ENOSPC; + } else { + LOG_DBG("%s: Controller Abort due to buffer length excedded with " + "no EoD from target", + dev->name); + } + break; + case CMDR_DDR_PREAMBLE_ERROR: case CMDR_DDR_PARITY_ERROR: case CMDR_M0_ERROR: case CMDR_M1_ERROR: case CMDR_M2_ERROR: - case CMDR_MST_ABORT: case CMDR_NACK_RESP: case CMDR_DDR_DROPPED: ret = -EIO; @@ -1383,19 +1432,9 @@ static int cdns_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1421,6 +1460,9 @@ static int cdns_i3c_i2c_transfer(const struct device *dev, struct i3c_i2c_device if ((msgs[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) { cmd->cmd0 |= CMD0_FIFO_RNW; } + + /* i2c transfers are a don't care for num_xfer */ + cmd->num_xfer = NULL; } data->xfer.ret = -ETIMEDOUT; @@ -1676,19 +1718,9 @@ static int cdns_i3c_transfer(const struct device *dev, struct i3c_device_desc *t k_mutex_lock(&data->bus_lock, K_FOREVER); - /** - * Spin waiting for device to go idle. It is unlikely that this will - * actually take any time unless if the last transaction came immediately - * after an error condition. - */ - uint32_t retry_count = I3C_MAX_IDLE_WAIT_RETRIES; - - while (!(sys_read32(config->base + MST_STATUS0) & MST_STATUS0_IDLE) && (retry_count > 0)) { - retry_count--; - } - if (retry_count == 0) { - LOG_ERR("%s: Unable to start transfer, device not idle", dev->name); - ret = -EAGAIN; + /* wait for idle */ + ret = cdns_i3c_wait_for_idle(dev); + if (ret != 0) { goto error; } @@ -1732,6 +1764,9 @@ static int cdns_i3c_transfer(const struct device *dev, struct i3c_device_desc *t } else { send_broadcast = true; } + + /* write the address of num_xfer which is to be updated upon message completion */ + cmd->num_xfer = &(msgs[i].num_xfer); } data->xfer.ret = -ETIMEDOUT; @@ -2300,18 +2335,18 @@ static enum i3c_bus_mode i3c_bus_mode(const struct i3c_dev_list *dev_list) enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; for (int i = 0; i < dev_list->num_i2c; i++) { - switch (I3C_DCR_I2C_DEV_IDX(dev_list->i2c[i].lvr)) { - case I3C_DCR_I2C_DEV_IDX_0: + switch (I3C_LVR_I2C_DEV_IDX(dev_list->i2c[i].lvr)) { + case I3C_LVR_I2C_DEV_IDX_0: if (mode < I3C_BUS_MODE_MIXED_FAST) { mode = I3C_BUS_MODE_MIXED_FAST; } break; - case I3C_DCR_I2C_DEV_IDX_1: + case I3C_LVR_I2C_DEV_IDX_1: if (mode < I3C_BUS_MODE_MIXED_LIMITED) { mode = I3C_BUS_MODE_MIXED_LIMITED; } break; - case I3C_DCR_I2C_DEV_IDX_2: + case I3C_LVR_I2C_DEV_IDX_2: if (mode < I3C_BUS_MODE_MIXED_SLOW) { mode = I3C_BUS_MODE_MIXED_SLOW; } diff --git a/drivers/i3c/i3c_mcux.c b/drivers/i3c/i3c_mcux.c index d996639dab0..4d630ee1519 100644 --- a/drivers/i3c/i3c_mcux.c +++ b/drivers/i3c/i3c_mcux.c @@ -1131,6 +1131,9 @@ static int mcux_i3c_transfer(const struct device *dev, goto out_xfer_i3c_stop_unlock; } + /* write back the total number of bytes transferred */ + msgs[i].num_xfer = ret; + if (emit_stop) { /* After a STOP, send broadcast header before next msg */ send_broadcast = true; @@ -1371,6 +1374,9 @@ static int mcux_i3c_do_ccc(const struct device *dev, goto out_ccc_stop; } + + /* write back the total number of bytes transferred */ + payload->ccc.num_xfer = ret; } /* Wait for controller to say the operation is done */ @@ -1402,6 +1408,9 @@ static int mcux_i3c_do_ccc(const struct device *dev, goto out_ccc_stop; } + + /* write back the total number of bytes transferred */ + tgt_payload->num_xfer = ret; } } @@ -2079,9 +2088,9 @@ static const struct i3c_driver_api mcux_i3c_driver_api = { #define I3C_MCUX_DEVICE(id) \ PINCTRL_DT_INST_DEFINE(id); \ static void mcux_i3c_config_func_##id(const struct device *dev); \ - static struct i3c_device_desc mcux_i3c_device_array_##id[] = \ + static struct i3c_device_desc mcux_i3c_device_array_##id[] = \ I3C_DEVICE_ARRAY_DT_INST(id); \ - static struct i3c_i2c_device_desc mcux_i3c_i2c_device_array_##id[] = \ + static struct i3c_i2c_device_desc mcux_i3c_i2c_device_array_##id[] = \ I3C_I2C_DEVICE_ARRAY_DT_INST(id); \ static const struct mcux_i3c_config mcux_i3c_config_##id = { \ .base = (I3C_Type *) DT_INST_REG_ADDR(id), \ @@ -2095,7 +2104,7 @@ static const struct i3c_driver_api mcux_i3c_driver_api = { .common.dev_list.num_i2c = ARRAY_SIZE(mcux_i3c_i2c_device_array_##id), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ .disable_open_drain_high_pp = \ - DT_INST_PROP_OR(id, disable_open_drain_high_pp, false), \ + DT_INST_PROP(id, disable_open_drain_high_pp), \ }; \ static struct mcux_i3c_data mcux_i3c_data_##id = { \ .clocks.i3c_od_scl_hz = DT_INST_PROP_OR(id, i3c_od_scl_hz, 0), \ diff --git a/drivers/ieee802154/ieee802154_b91.c b/drivers/ieee802154/ieee802154_b91.c index 0557c533944..e44c99888dd 100644 --- a/drivers/ieee802154/ieee802154_b91.c +++ b/drivers/ieee802154/ieee802154_b91.c @@ -26,6 +26,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #endif +#include + #include "ieee802154_b91.h" @@ -617,7 +619,7 @@ static int b91_attr_get(const struct device *dev, enum ieee802154_attr attr, } /* IEEE802154 driver APIs structure */ -static struct ieee802154_radio_api b91_radio_api = { +static const struct ieee802154_radio_api b91_radio_api = { .iface_api.init = b91_iface_init, .get_capabilities = b91_get_capabilities, .cca = b91_cca, diff --git a/drivers/ieee802154/ieee802154_cc1200.c b/drivers/ieee802154/ieee802154_cc1200.c index e5f8ea36670..7bc3aa3ed12 100644 --- a/drivers/ieee802154/ieee802154_cc1200.c +++ b/drivers/ieee802154/ieee802154_cc1200.c @@ -813,7 +813,7 @@ static const struct cc1200_config cc1200_config = { static struct cc1200_context cc1200_context_data; -static struct ieee802154_radio_api cc1200_radio_api = { +static const struct ieee802154_radio_api cc1200_radio_api = { .iface_api.init = cc1200_iface_init, .get_capabilities = cc1200_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c index 5d5a53ed08e..263b98d2823 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx.c @@ -570,7 +570,7 @@ static void ieee802154_cc13xx_cc26xx_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_radio_api = { +static const struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_radio_api = { .iface_api.init = ieee802154_cc13xx_cc26xx_iface_init, .get_capabilities = ieee802154_cc13xx_cc26xx_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c index ea626908d16..dbaa02ff9eb 100644 --- a/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c +++ b/drivers/ieee802154/ieee802154_cc13xx_cc26xx_subg.c @@ -909,7 +909,7 @@ static void ieee802154_cc13xx_cc26xx_subg_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api +static const struct ieee802154_radio_api ieee802154_cc13xx_cc26xx_subg_radio_api = { .iface_api.init = ieee802154_cc13xx_cc26xx_subg_iface_init, diff --git a/drivers/ieee802154/ieee802154_cc2520.c b/drivers/ieee802154/ieee802154_cc2520.c index cf7c1091661..1f86d20d02f 100644 --- a/drivers/ieee802154/ieee802154_cc2520.c +++ b/drivers/ieee802154/ieee802154_cc2520.c @@ -1057,7 +1057,7 @@ static const struct cc2520_config cc2520_config = { static struct cc2520_context cc2520_context_data; -static struct ieee802154_radio_api cc2520_radio_api = { +static const struct ieee802154_radio_api cc2520_radio_api = { .iface_api.init = cc2520_iface_init, .get_capabilities = cc2520_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_dw1000.c b/drivers/ieee802154/ieee802154_dw1000.c index d20df488966..13d5e047544 100644 --- a/drivers/ieee802154/ieee802154_dw1000.c +++ b/drivers/ieee802154/ieee802154_dw1000.c @@ -1659,7 +1659,7 @@ static void dwt_iface_api_init(struct net_if *iface) LOG_INF("Iface initialized"); } -static struct ieee802154_radio_api dwt_radio_api = { +static const struct ieee802154_radio_api dwt_radio_api = { .iface_api.init = dwt_iface_api_init, .get_capabilities = dwt_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_kw41z.c b/drivers/ieee802154/ieee802154_kw41z.c index aee802ad6ff..40064c6df7b 100644 --- a/drivers/ieee802154/ieee802154_kw41z.c +++ b/drivers/ieee802154/ieee802154_kw41z.c @@ -1091,7 +1091,7 @@ static int kw41z_attr_get(const struct device *dev, enum ieee802154_attr attr, &drv_attr.phy_supported_channels, value); } -static struct ieee802154_radio_api kw41z_radio_api = { +static const struct ieee802154_radio_api kw41z_radio_api = { .iface_api.init = kw41z_iface_init, .get_capabilities = kw41z_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_mcr20a.c b/drivers/ieee802154/ieee802154_mcr20a.c index 6a1e5a99727..2e6ed142861 100644 --- a/drivers/ieee802154/ieee802154_mcr20a.c +++ b/drivers/ieee802154/ieee802154_mcr20a.c @@ -1452,7 +1452,7 @@ static const struct mcr20a_config mcr20a_config = { static struct mcr20a_context mcr20a_context_data; -static struct ieee802154_radio_api mcr20a_radio_api = { +static const struct ieee802154_radio_api mcr20a_radio_api = { .iface_api.init = mcr20a_iface_init, .get_capabilities = mcr20a_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index 553d71188e9..0643d6051b6 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -1213,7 +1213,7 @@ static const struct nrf5_802154_config nrf5_radio_cfg = { .irq_config_func = nrf5_irq_config, }; -static struct ieee802154_radio_api nrf5_radio_api = { +static const struct ieee802154_radio_api nrf5_radio_api = { .iface_api.init = nrf5_iface_init, .get_capabilities = nrf5_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_rf2xx.c b/drivers/ieee802154/ieee802154_rf2xx.c index ac7f13580d0..4d7c188ce67 100644 --- a/drivers/ieee802154/ieee802154_rf2xx.c +++ b/drivers/ieee802154/ieee802154_rf2xx.c @@ -1084,7 +1084,7 @@ static void rf2xx_iface_init(struct net_if *iface) ieee802154_init(iface); } -static struct ieee802154_radio_api rf2xx_radio_api = { +static const struct ieee802154_radio_api rf2xx_radio_api = { .iface_api.init = rf2xx_iface_init, .get_capabilities = rf2xx_get_capabilities, diff --git a/drivers/ieee802154/ieee802154_uart_pipe.c b/drivers/ieee802154/ieee802154_uart_pipe.c index cdb420d9747..72bcf5b8ebf 100644 --- a/drivers/ieee802154/ieee802154_uart_pipe.c +++ b/drivers/ieee802154/ieee802154_uart_pipe.c @@ -392,7 +392,7 @@ static void upipe_iface_init(struct net_if *iface) static struct upipe_context upipe_context_data; -static struct ieee802154_radio_api upipe_radio_api = { +static const struct ieee802154_radio_api upipe_radio_api = { .iface_api.init = upipe_iface_init, .get_capabilities = upipe_get_capabilities, diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index d63dc2ae797..9aeb9198b31 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -4,8 +4,11 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) # zephyr-keep-sorted-start +zephyr_library_sources_ifdef(CONFIG_INPUT_ANALOG_AXIS input_analog_axis.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ANALOG_AXIS_SETTINGS input_analog_axis_settings.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CAP1203 input_cap1203.c) zephyr_library_sources_ifdef(CONFIG_INPUT_CST816S input_cst816s.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_ESP32_TOUCH_SENSOR input_esp32_touch_sensor.c) zephyr_library_sources_ifdef(CONFIG_INPUT_FT5336 input_ft5336.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KBD_MATRIX input_gpio_kbd_matrix.c) zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c) @@ -26,3 +29,16 @@ if (CONFIG_INPUT_SDL_TOUCH) target_sources(native_simulator INTERFACE input_sdl_touch_bottom.c) endif() endif() + +if(CONFIG_NATIVE_LINUX_EVDEV) + if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL Linux) + zephyr_library_sources(linux_evdev.c) + if (CONFIG_NATIVE_APPLICATION) + zephyr_library_sources(linux_evdev_bottom.c) + else() + target_sources(native_simulator INTERFACE linux_evdev_bottom.c) + endif() + else() + message(FATAL_ERROR "CONFIG_NATIVE_LINUX_EVDEV only available on Linux") + endif() +endif() diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index afab00d4259..41c93241f2a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -6,8 +6,11 @@ if INPUT menu "Input drivers" # zephyr-keep-sorted-start +source "drivers/input/Kconfig.analog_axis" source "drivers/input/Kconfig.cap1203" source "drivers/input/Kconfig.cst816s" +source "drivers/input/Kconfig.esp32" +source "drivers/input/Kconfig.evdev" source "drivers/input/Kconfig.ft5336" source "drivers/input/Kconfig.gpio_kbd_matrix" source "drivers/input/Kconfig.gpio_keys" diff --git a/drivers/input/Kconfig.analog_axis b/drivers/input/Kconfig.analog_axis new file mode 100644 index 00000000000..472b611acea --- /dev/null +++ b/drivers/input/Kconfig.analog_axis @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_ANALOG_AXIS + bool "ADC based analog axis input driver" + default y + depends on DT_HAS_ANALOG_AXIS_ENABLED + depends on ADC + depends on MULTITHREADING + help + ADC based analog axis input driver + +if INPUT_ANALOG_AXIS + +config INPUT_ANALOG_AXIS_THREAD_STACK_SIZE + int "Stack size for the analog axis thread" + default 762 + help + Size of the stack used for the analog axis thread. + +config INPUT_ANALOG_AXIS_THREAD_PRIORITY + int "Priority for the analog axis thread" + default 0 + help + Priority level of the analog axis thread. + +config INPUT_ANALOG_AXIS_SETTINGS + bool "Analog axis settings support" + default y + depends on SETTINGS + help + Settings support for the analog axis driver, exposes a + analog_axis_calibration_save() function to save the calibration into + settings and load them automatically on startup. + +config INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES + int "Maximum number of axes supported in the settings." + default 8 + help + Maximum number of axes that can have calibration value saved in + settings. + +endif diff --git a/drivers/input/Kconfig.esp32 b/drivers/input/Kconfig.esp32 new file mode 100644 index 00000000000..17460c94c64 --- /dev/null +++ b/drivers/input/Kconfig.esp32 @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_ESP32_TOUCH_SENSOR + bool "Espressif Touch Sensor input driver" + default n + depends on DT_HAS_ESPRESSIF_ESP32_TOUCH_ENABLED + help + Enable support for Espressif Touch Sensor input driver. diff --git a/drivers/input/Kconfig.evdev b/drivers/input/Kconfig.evdev new file mode 100644 index 00000000000..568797800f3 --- /dev/null +++ b/drivers/input/Kconfig.evdev @@ -0,0 +1,29 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config NATIVE_LINUX_EVDEV + bool "Native Linux evdev based input device" + default y + depends on DT_HAS_ZEPHYR_NATIVE_LINUX_EVDEV_ENABLED + depends on ARCH_POSIX + depends on MULTITHREADING + help + Enable reading input from a Linux evdev device, requires specifying + an evdev device path in the --evdev command line argument. + +if NATIVE_LINUX_EVDEV + +config NATIVE_LINUX_EVDEV_THREAD_PRIORITY + int "Priority for the Linux evdev thread" + default 0 + help + Priority level of the internal thread handling Linux input events. + +config NATIVE_LINUX_THREAD_SLEEP_MS + int "Sleep period for the Linux evdev thread" + default 10 + help + How long to sleep between checking for new events in the Linux input + events thread. + +endif diff --git a/drivers/input/Kconfig.it8xxx2 b/drivers/input/Kconfig.it8xxx2 index 6e729b27c3a..0c59b342534 100644 --- a/drivers/input/Kconfig.it8xxx2 +++ b/drivers/input/Kconfig.it8xxx2 @@ -6,6 +6,5 @@ config INPUT_ITE_IT8XXX2_KBD default y depends on DT_HAS_ITE_IT8XXX2_KBD_ENABLED select INPUT_KBD_MATRIX - select MULTITHREADING help This option enables the ITE keyboard scan driver. diff --git a/drivers/input/Kconfig.kbd_matrix b/drivers/input/Kconfig.kbd_matrix index 5d1328a227f..4532b270f9c 100644 --- a/drivers/input/Kconfig.kbd_matrix +++ b/drivers/input/Kconfig.kbd_matrix @@ -3,6 +3,7 @@ config INPUT_KBD_MATRIX bool + depends on MULTITHREADING help Enable library used for keyboard matrix drivers. @@ -14,4 +15,46 @@ config INPUT_KBD_MATRIX_THREAD_STACK_SIZE help Size of the stack used for the keyboard matrix thread. + +config INPUT_KBD_MATRIX_THREAD_PRIORITY + int "Priority for the keyboard matrix thread" + default 0 + help + Priority level of the keyboard matrix thread. + +config INPUT_KBD_MATRIX_16_BIT_ROW + bool "16 bit row size support" + help + Use a 16 bit type for the internal structure, allow using a matrix + with up to 16 rows if the driver supports it. + +config INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC + bool "Allow runtime changes to the actual key mask" + help + If enabled, the actual-key-mask devicetree property data is stored in + RAM, and a input_kbd_matrix_actual_key_mask_set() function is + available to change the content at runtime. + +config INPUT_SHELL_KBD_MATRIX_STATE + bool "Input kbd_matrix_state shell command" + depends on INPUT_SHELL + help + Enable an input kbd_matrix_state shell command to log the state of a + keyboard matrix device. + +config INPUT_SHELL_KBD_MATRIX_STATE_MAX_COLS + int "Maximum column count for the kbd_matrix_state command" + default 32 + depends on INPUT_SHELL_KBD_MATRIX_STATE + help + Maximum column count for a device processed by the input + kbd_matrix_state shell command. + +config INPUT_KBD_DRIVE_COLUMN_HOOK + bool + help + Call an application specific hook after the driver specific + drive_column implementation. The application must implement the + input_kbd_matrix_drive_column_hook function. + endif # INPUT_KBD_MATRIX diff --git a/drivers/input/Kconfig.npcx b/drivers/input/Kconfig.npcx index ef380b0ca4b..07c2e301944 100644 --- a/drivers/input/Kconfig.npcx +++ b/drivers/input/Kconfig.npcx @@ -8,7 +8,6 @@ config INPUT_NPCX_KBD default y depends on DT_HAS_NUVOTON_NPCX_KBD_ENABLED select INPUT_KBD_MATRIX - select MULTITHREADING help This option enables the keyboard scan driver for NPCX family of processors. diff --git a/drivers/input/input_analog_axis.c b/drivers/input/input_analog_axis.c new file mode 100644 index 00000000000..ace693ddf58 --- /dev/null +++ b/drivers/input/input_analog_axis.c @@ -0,0 +1,271 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT analog_axis + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(analog_axis, CONFIG_INPUT_LOG_LEVEL); + +struct analog_axis_channel_config { + struct adc_dt_spec adc; + int16_t out_min; + int16_t out_max; + uint16_t axis; + bool invert; +}; + +struct analog_axis_channel_data { + int last_out; +}; + +struct analog_axis_config { + uint32_t poll_period_ms; + const struct analog_axis_channel_config *channel_cfg; + struct analog_axis_channel_data *channel_data; + struct analog_axis_calibration *calibration; + const uint8_t num_channels; +}; + +struct analog_axis_data { + struct k_mutex cal_lock; + analog_axis_raw_data_t raw_data_cb; + struct k_timer timer; + struct k_thread thread; + + K_KERNEL_STACK_MEMBER(thread_stack, + CONFIG_INPUT_ANALOG_AXIS_THREAD_STACK_SIZE); +}; + +int analog_axis_num_axes(const struct device *dev) +{ + const struct analog_axis_config *cfg = dev->config; + + return cfg->num_channels; +} + +int analog_axis_calibration_get(const struct device *dev, + int channel, + struct analog_axis_calibration *out_cal) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + struct analog_axis_calibration *cal = &cfg->calibration[channel]; + + if (channel >= cfg->num_channels) { + return -EINVAL; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + memcpy(out_cal, cal, sizeof(struct analog_axis_calibration)); + k_mutex_unlock(&data->cal_lock); + + return 0; +} + +void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_t cb) +{ + struct analog_axis_data *data = dev->data; + + k_mutex_lock(&data->cal_lock, K_FOREVER); + data->raw_data_cb = cb; + k_mutex_unlock(&data->cal_lock); +} + +int analog_axis_calibration_set(const struct device *dev, + int channel, + struct analog_axis_calibration *new_cal) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + struct analog_axis_calibration *cal = &cfg->calibration[channel]; + + if (channel >= cfg->num_channels) { + return -EINVAL; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + memcpy(cal, new_cal, sizeof(struct analog_axis_calibration)); + k_mutex_unlock(&data->cal_lock); + + return 0; +} + +static void analog_axis_loop(const struct device *dev) +{ + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + int16_t bufs[cfg->num_channels]; + int32_t out; + struct adc_sequence sequence = { + .buffer = bufs, + .buffer_size = sizeof(bufs), + }; + const struct analog_axis_channel_config *axis_cfg_0 = &cfg->channel_cfg[0]; + int err; + int i; + + adc_sequence_init_dt(&axis_cfg_0->adc, &sequence); + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + + sequence.channels |= BIT(axis_cfg->adc.channel_id); + } + + err = adc_read(axis_cfg_0->adc.dev, &sequence); + if (err < 0) { + LOG_ERR("Could not read (%d)", err); + return; + } + + k_mutex_lock(&data->cal_lock, K_FOREVER); + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + struct analog_axis_channel_data *axis_data = &cfg->channel_data[i]; + struct analog_axis_calibration *cal = &cfg->calibration[i]; + int16_t in_range = cal->in_max - cal->in_min; + int16_t out_range = axis_cfg->out_max - axis_cfg->out_min; + int32_t raw_val = bufs[i]; + + if (axis_cfg->invert) { + raw_val *= -1; + } + + if (data->raw_data_cb != NULL) { + data->raw_data_cb(dev, i, raw_val); + } + + LOG_DBG("%s: ch %d: raw_val: %d", dev->name, i, raw_val); + + out = CLAMP((raw_val - cal->in_min) * out_range / in_range + axis_cfg->out_min, + axis_cfg->out_min, axis_cfg->out_max); + + if (cal->out_deadzone > 0) { + int16_t center = DIV_ROUND_CLOSEST( + axis_cfg->out_max + axis_cfg->out_min, 2); + if (abs(out - center) < cal->out_deadzone) { + out = center; + } + } + + if (axis_data->last_out != out) { + input_report_abs(dev, axis_cfg->axis, out, true, K_FOREVER); + } + axis_data->last_out = out; + } + + k_mutex_unlock(&data->cal_lock); +} + +static void analog_axis_thread(void *arg1, void *arg2, void *arg3) +{ + const struct device *dev = arg1; + const struct analog_axis_config *cfg = dev->config; + struct analog_axis_data *data = dev->data; + int err; + int i; + + for (i = 0; i < cfg->num_channels; i++) { + const struct analog_axis_channel_config *axis_cfg = &cfg->channel_cfg[i]; + + if (!adc_is_ready_dt(&axis_cfg->adc)) { + LOG_ERR("ADC controller device not ready"); + return; + } + + err = adc_channel_setup_dt(&axis_cfg->adc); + if (err < 0) { + LOG_ERR("Could not setup channel #%d (%d)", i, err); + return; + } + } + + k_timer_init(&data->timer, NULL, NULL); + k_timer_start(&data->timer, + K_MSEC(cfg->poll_period_ms), K_MSEC(cfg->poll_period_ms)); + + while (true) { + analog_axis_loop(dev); + k_timer_status_sync(&data->timer); + } +} + +static int analog_axis_init(const struct device *dev) +{ + struct analog_axis_data *data = dev->data; + k_tid_t tid; + + k_mutex_init(&data->cal_lock); + + tid = k_thread_create(&data->thread, data->thread_stack, + K_KERNEL_STACK_SIZEOF(data->thread_stack), + analog_axis_thread, (void *)dev, NULL, NULL, + CONFIG_INPUT_ANALOG_AXIS_THREAD_PRIORITY, + 0, K_NO_WAIT); + if (!tid) { + LOG_ERR("thread creation failed"); + return -ENODEV; + } + + k_thread_name_set(&data->thread, dev->name); + + return 0; +} + +#define ANALOG_AXIS_CHANNEL_CFG_DEF(node_id) \ + { \ + .adc = ADC_DT_SPEC_GET(node_id), \ + .out_min = (int16_t)DT_PROP(node_id, out_min), \ + .out_max = (int16_t)DT_PROP(node_id, out_max), \ + .axis = DT_PROP(node_id, zephyr_axis), \ + .invert = DT_PROP(node_id, invert), \ + } + +#define ANALOG_AXIS_CHANNEL_CAL_DEF(node_id) \ + { \ + .in_min = (int16_t)DT_PROP(node_id, in_min), \ + .in_max = (int16_t)DT_PROP(node_id, in_max), \ + .out_deadzone = DT_PROP(node_id, out_deadzone), \ + } + +#define ANALOG_AXIS_INIT(inst) \ + static const struct analog_axis_channel_config analog_axis_channel_cfg_##inst[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, ANALOG_AXIS_CHANNEL_CFG_DEF, (,)) \ + }; \ + \ + static struct analog_axis_channel_data \ + analog_axis_channel_data_##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)]; \ + \ + static struct analog_axis_calibration \ + analog_axis_calibration##inst[ARRAY_SIZE(analog_axis_channel_cfg_##inst)] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP( \ + inst, ANALOG_AXIS_CHANNEL_CAL_DEF, (,)) \ + }; \ + \ + static const struct analog_axis_config analog_axis_cfg_##inst = { \ + .poll_period_ms = DT_INST_PROP(inst, poll_period_ms), \ + .channel_cfg = analog_axis_channel_cfg_##inst, \ + .channel_data = analog_axis_channel_data_##inst, \ + .calibration = analog_axis_calibration##inst, \ + .num_channels = ARRAY_SIZE(analog_axis_channel_cfg_##inst), \ + }; \ + \ + static struct analog_axis_data analog_axis_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, analog_axis_init, NULL, \ + &analog_axis_data_##inst, &analog_axis_cfg_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(ANALOG_AXIS_INIT) diff --git a/drivers/input/input_analog_axis_settings.c b/drivers/input/input_analog_axis_settings.c new file mode 100644 index 00000000000..3d29af8b96f --- /dev/null +++ b/drivers/input/input_analog_axis_settings.c @@ -0,0 +1,111 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(analog_axis_settings, CONFIG_INPUT_LOG_LEVEL); + +#define ANALOG_AXIS_SETTINGS_PATH_MAX 32 + +#define MAX_AXES CONFIG_INPUT_ANALOG_AXIS_SETTINGS_MAX_AXES + +static void analog_axis_calibration_log(const struct device *dev) +{ + struct analog_axis_calibration cal; + int i; + + for (i = 0; i < analog_axis_num_axes(dev); i++) { + analog_axis_calibration_get(dev, i, &cal); + + LOG_INF("%s: ch: %d min: %d max: %d deadzone: %d", + dev->name, i, cal.in_min, cal.in_max, cal.out_deadzone); + } +} + +static int analog_axis_calibration_load(const char *key, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + const struct device *dev; + struct analog_axis_calibration cal[MAX_AXES]; + int axes; + char dev_name[ANALOG_AXIS_SETTINGS_PATH_MAX]; + const char *next; + int nlen; + ssize_t len; + + nlen = settings_name_next(key, &next); + if (nlen + 1 > sizeof(dev_name)) { + LOG_ERR("Setting name too long: %d", nlen); + return -EINVAL; + } + + memcpy(dev_name, key, nlen); + dev_name[nlen] = '\0'; + + dev = device_get_binding(dev_name); + if (dev == NULL) { + LOG_ERR("Cannot restore: device %s not available", dev_name); + return -ENODEV; + } + + len = read_cb(cb_arg, cal, sizeof(cal)); + if (len < 0) { + LOG_ERR("Data restore error: %d", len); + } + + axes = analog_axis_num_axes(dev); + if (len != sizeof(struct analog_axis_calibration) * axes) { + LOG_ERR("Invalid settings data length: %d, expected %d", + len, sizeof(struct analog_axis_calibration) * axes); + return -EIO; + } + + for (int i = 0; i < axes; i++) { + analog_axis_calibration_set(dev, i, &cal[i]); + } + + analog_axis_calibration_log(dev); + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(analog_axis, "aa-cal", NULL, + analog_axis_calibration_load, NULL, NULL); + +int analog_axis_calibration_save(const struct device *dev) +{ + struct analog_axis_calibration cal[MAX_AXES]; + int axes; + char path[ANALOG_AXIS_SETTINGS_PATH_MAX]; + int ret; + + analog_axis_calibration_log(dev); + + ret = snprintk(path, sizeof(path), "aa-cal/%s", dev->name); + if (ret < 0) { + return -EINVAL; + } + + axes = analog_axis_num_axes(dev); + for (int i = 0; i < axes; i++) { + analog_axis_calibration_get(dev, i, &cal[i]); + } + + ret = settings_save_one(path, &cal[0], + sizeof(struct analog_axis_calibration) * axes); + if (ret < 0) { + LOG_ERR("Settings save errord: %d", ret); + return ret; + } + + return 0; +} diff --git a/drivers/input/input_cst816s.c b/drivers/input/input_cst816s.c index 9409deb045a..6c17af3aca9 100644 --- a/drivers/input/input_cst816s.c +++ b/drivers/input/input_cst816s.c @@ -14,7 +14,8 @@ LOG_MODULE_REGISTER(cst816s, CONFIG_INPUT_LOG_LEVEL); -#define CST816S_CHIP_ID 0xB4 +#define CST816S_CHIP_ID1 0xB4 +#define CST816S_CHIP_ID2 0xB5 #define CST816S_REG_DATA 0x00 #define CST816S_REG_GESTURE_ID 0x01 @@ -202,7 +203,7 @@ static int cst816s_chip_init(const struct device *dev) return ret; } - if (chip_id != CST816S_CHIP_ID) { + if ((chip_id != CST816S_CHIP_ID1) && (chip_id != CST816S_CHIP_ID2)) { LOG_ERR("CST816S wrong chip id: returned 0x%x", chip_id); return -ENODEV; } diff --git a/drivers/input/input_esp32_touch_sensor.c b/drivers/input/input_esp32_touch_sensor.c new file mode 100644 index 00000000000..9f6858da1c7 --- /dev/null +++ b/drivers/input/input_esp32_touch_sensor.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_touch + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(espressif_esp32_touch, CONFIG_INPUT_LOG_LEVEL); + +BUILD_ASSERT(!IS_ENABLED(CONFIG_COUNTER_RTC_ESP32), + "Conflict detected: COUNTER_RTC_ESP32 enabled"); + +#define ESP32_SCAN_DONE_MAX_COUNT 5 + +#if defined(CONFIG_SOC_SERIES_ESP32) +#define ESP32_RTC_INTR_MSK RTC_CNTL_TOUCH_INT_ST_M +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + +#define ESP32_RTC_INTR_MSK (RTC_CNTL_TOUCH_DONE_INT_ST_M | \ + RTC_CNTL_TOUCH_ACTIVE_INT_ST_M | \ + RTC_CNTL_TOUCH_INACTIVE_INT_ST_M | \ + RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | \ + RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M) + +#define ESP32_TOUCH_PAD_INTR_MASK (TOUCH_PAD_INTR_MASK_ACTIVE | \ + TOUCH_PAD_INTR_MASK_INACTIVE | \ + TOUCH_PAD_INTR_MASK_TIMEOUT | \ + TOUCH_PAD_INTR_MASK_SCAN_DONE) + +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + +struct esp32_touch_sensor_channel_config { + int32_t channel_num; + int32_t channel_sens; + uint32_t zephyr_code; +}; + +struct esp32_touch_sensor_config { + uint32_t debounce_interval_ms; + int num_channels; + int href_microvolt_enum_idx; + int lref_microvolt_enum_idx; + int href_atten_microvolt_enum_idx; + int filter_mode; + int filter_debounce_cnt; + int filter_noise_thr; + int filter_jitter_step; + int filter_smooth_level; + const struct esp32_touch_sensor_channel_config *channel_cfg; + struct esp32_touch_sensor_channel_data *channel_data; +}; + +struct esp32_touch_sensor_channel_data { + const struct device *dev; + struct k_work_delayable work; + uint32_t status; +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + uint32_t last_status; +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ +}; + +struct esp32_touch_sensor_data { + uint32_t rtc_intr_msk; +}; + +static void esp32_touch_sensor_interrupt_cb(void *arg) +{ + const struct device *dev = arg; + struct esp32_touch_sensor_data *dev_data = dev->data; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + const struct esp32_touch_sensor_channel_config *channel_cfg; + const int num_channels = dev_cfg->num_channels; + uint32_t pad_status; + +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_intr_clear(); + +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + static uint8_t scan_done_counter; + + touch_pad_intr_mask_t intr_mask = touch_hal_read_intr_status_mask(); + + if (intr_mask & TOUCH_PAD_INTR_MASK_SCAN_DONE) { + if (++scan_done_counter == ESP32_SCAN_DONE_MAX_COUNT) { + touch_hal_intr_disable(TOUCH_PAD_INTR_MASK_SCAN_DONE); + for (int i = 0; i < num_channels; i++) { + channel_cfg = &dev_cfg->channel_cfg[i]; + + /* Set interrupt threshold */ + uint32_t benchmark_value; + + touch_hal_read_benchmark(channel_cfg->channel_num, + &benchmark_value); + touch_hal_set_threshold(channel_cfg->channel_num, + channel_cfg->channel_sens * benchmark_value / 100); + } + } + return; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + touch_hal_read_trigger_status_mask(&pad_status); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_clear_trigger_status_mask(); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + for (int i = 0; i < num_channels; i++) { + uint32_t channel_status; + + channel_cfg = &dev_cfg->channel_cfg[i]; + channel_status = (pad_status >> channel_cfg->channel_num) & 0x01; + +#if defined(CONFIG_SOC_SERIES_ESP32) + if (channel_status != 0) { +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + uint32_t channel_num = (uint32_t)touch_hal_get_current_meas_channel(); + + if (channel_cfg->channel_num == channel_num) { +#endif /* CONFIG_SOC_SERIES_ESP32 */ + struct esp32_touch_sensor_channel_data + *channel_data = &dev_cfg->channel_data[i]; + + channel_data->status = channel_status; + (void)k_work_reschedule(&channel_data->work, + K_MSEC(dev_cfg->debounce_interval_ms)); + } + } +} + +static void esp32_rtc_isr(void *arg) +{ + uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); + + if (arg != NULL) { + const struct device *dev = arg; + struct esp32_touch_sensor_data *dev_data = dev->data; + + if (dev_data->rtc_intr_msk & status) { + esp32_touch_sensor_interrupt_cb(arg); + } + } + + REG_WRITE(RTC_CNTL_INT_CLR_REG, status); +} + +static esp_err_t esp32_rtc_isr_install(intr_handler_t intr_handler, const void *handler_arg) +{ + esp_err_t err; + + REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); + REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); + err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, intr_handler, (void *)handler_arg, NULL); + + return err; +} + +/** + * Handle debounced touch sensor touch state. + */ +static void esp32_touch_sensor_change_deferred(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct esp32_touch_sensor_channel_data *channel_data = + CONTAINER_OF(dwork, struct esp32_touch_sensor_channel_data, work); + const struct device *dev = channel_data->dev; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + int key_index = channel_data - &dev_cfg->channel_data[0]; + const struct esp32_touch_sensor_channel_config + *channel_cfg = &dev_cfg->channel_cfg[key_index]; + +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + if (channel_data->last_status != channel_data->status) { +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + input_report_key(dev, channel_cfg->zephyr_code, + channel_data->status, true, K_FOREVER); +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + channel_data->last_status = channel_data->status; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ +} + +static int esp32_touch_sensor_init(const struct device *dev) +{ + struct esp32_touch_sensor_data *dev_data = dev->data; + const struct esp32_touch_sensor_config *dev_cfg = dev->config; + const int num_channels = dev_cfg->num_channels; + + touch_hal_init(); + +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_volt_t volt = { + .refh = dev_cfg->href_microvolt_enum_idx, + .refh = dev_cfg->href_microvolt_enum_idx, + .atten = dev_cfg->href_atten_microvolt_enum_idx + }; + + touch_hal_set_voltage(&volt); + touch_hal_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + for (int i = 0; i < num_channels; i++) { + struct esp32_touch_sensor_channel_data *channel_data = &dev_cfg->channel_data[i]; + const struct esp32_touch_sensor_channel_config *channel_cfg = + &dev_cfg->channel_cfg[i]; + + if (!(channel_cfg->channel_num > 0 && + channel_cfg->channel_num < SOC_TOUCH_SENSOR_NUM)) { + LOG_ERR("Touch %d configuration failed: " + "Touch channel error", i); + return -EINVAL; + } + +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + if (channel_cfg->channel_num == SOC_TOUCH_DENOISE_CHANNEL) { + LOG_ERR("Touch %d configuration failed: " + "TOUCH0 is internal denoise channel", i); + return -EINVAL; + } +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + + gpio_num_t gpio_num = touch_sensor_channel_io_map[channel_cfg->channel_num]; + + rtc_gpio_init(gpio_num); + rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED); + rtc_gpio_pulldown_dis(gpio_num); + rtc_gpio_pullup_dis(gpio_num); + + touch_hal_config(channel_cfg->channel_num); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_set_threshold(channel_cfg->channel_num, 0); + touch_hal_set_group_mask(BIT(channel_cfg->channel_num), + BIT(channel_cfg->channel_num)); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + touch_hal_set_channel_mask(BIT(channel_cfg->channel_num)); + + channel_data->status = 0; +#if defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + channel_data->last_status = 0; +#endif /* defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) */ + channel_data->dev = dev; + + k_work_init_delayable(&channel_data->work, esp32_touch_sensor_change_deferred); + } + +#if defined(CONFIG_SOC_SERIES_ESP32) + for (int i = 0; i < num_channels; i++) { + const struct esp32_touch_sensor_channel_config *channel_cfg = + &dev_cfg->channel_cfg[i]; + uint32_t ref_time; + + ref_time = k_uptime_get_32(); + while (!touch_hal_meas_is_done()) { + if (k_uptime_get_32() - ref_time > 500) { + return -ETIMEDOUT; + } + k_busy_wait(1000); + } + uint16_t touch_value = touch_hal_read_raw_data(channel_cfg->channel_num); + + touch_hal_set_threshold(channel_cfg->channel_num, + touch_value * (100 - channel_cfg->channel_num) / 100); + } + +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + touch_filter_config_t filter_info = { + .mode = dev_cfg->filter_mode, + .debounce_cnt = dev_cfg->filter_debounce_cnt, + .noise_thr = dev_cfg->filter_noise_thr, + .jitter_step = dev_cfg->filter_jitter_step, + .smh_lvl = dev_cfg->filter_smooth_level, + }; + touch_hal_filter_set_config(&filter_info); + touch_hal_filter_enable(); + + touch_hal_timeout_enable(); + touch_hal_timeout_set_threshold(SOC_TOUCH_PAD_THRESHOLD_MAX); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + dev_data->rtc_intr_msk = ESP32_RTC_INTR_MSK; + esp32_rtc_isr_install(&esp32_rtc_isr, dev); +#if defined(CONFIG_SOC_SERIES_ESP32) + touch_hal_intr_enable(); +#elif defined(CONFIG_SOC_SERIES_ESP32S2) || defined(CONFIG_SOC_SERIES_ESP32S3) + touch_hal_intr_enable(ESP32_TOUCH_PAD_INTR_MASK); + touch_hal_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +#endif /* defined(CONFIG_SOC_SERIES_ESP32) */ + + touch_hal_start_fsm(); + + return 0; +} + +#define ESP32_TOUCH_SENSOR_CHANNEL_CFG_INIT(node_id) \ + { \ + .channel_num = DT_PROP(node_id, channel_num), \ + .channel_sens = DT_PROP(node_id, channel_sens), \ + .zephyr_code = DT_PROP(node_id, zephyr_code), \ + } + +#define ESP32_TOUCH_SENSOR_INIT(inst) \ + static const struct esp32_touch_sensor_channel_config \ + esp32_touch_sensor_channel_config_##inst[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, \ + ESP32_TOUCH_SENSOR_CHANNEL_CFG_INIT, (,)) \ + }; \ + \ + static struct esp32_touch_sensor_channel_data esp32_touch_sensor_channel_data_##inst \ + [ARRAY_SIZE(esp32_touch_sensor_channel_config_##inst)]; \ + \ + static const struct esp32_touch_sensor_config esp32_touch_sensor_config_##inst = { \ + .debounce_interval_ms = DT_INST_PROP(inst, debounce_interval_ms), \ + .num_channels = ARRAY_SIZE(esp32_touch_sensor_channel_config_##inst), \ + .href_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, href_microvolt), \ + .lref_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, lref_microvolt), \ + .href_atten_microvolt_enum_idx = DT_INST_ENUM_IDX(inst, href_atten_microvolt), \ + .filter_mode = DT_INST_PROP(inst, filter_mode), \ + .filter_debounce_cnt = DT_INST_PROP(inst, filter_debounce_cnt), \ + .filter_noise_thr = DT_INST_PROP(inst, filter_noise_thr), \ + .filter_jitter_step = DT_INST_PROP(inst, filter_jitter_step), \ + .filter_smooth_level = DT_INST_PROP(inst, filter_smooth_level), \ + .channel_cfg = esp32_touch_sensor_channel_config_##inst, \ + .channel_data = esp32_touch_sensor_channel_data_##inst, \ + }; \ + \ + static struct esp32_touch_sensor_data esp32_touch_sensor_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, \ + &esp32_touch_sensor_init, \ + NULL, \ + &esp32_touch_sensor_data_##inst, \ + &esp32_touch_sensor_config_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(ESP32_TOUCH_SENSOR_INIT) diff --git a/drivers/input/input_ft5336.c b/drivers/input/input_ft5336.c index 1dd705d80f6..fea0aa26c11 100644 --- a/drivers/input/input_ft5336.c +++ b/drivers/input/input_ft5336.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); @@ -18,6 +20,7 @@ LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); /* FT5336 used registers */ #define REG_TD_STATUS 0x02U #define REG_P1_XH 0x03U +#define REG_G_PMODE 0xA5U /* REG_TD_STATUS: Touch points. */ #define TOUCH_POINTS_POS 0U @@ -35,6 +38,9 @@ LOG_MODULE_REGISTER(ft5336, CONFIG_INPUT_LOG_LEVEL); /* REG_Pn_XH: Position */ #define POSITION_H_MSK 0x0FU +/* REG_G_PMODE: Power Consume Mode */ +#define PMOD_HIBERNATE 0x03U + /** FT5336 configuration (DT). */ struct ft5336_config { /** I2C bus. */ @@ -173,7 +179,6 @@ static int ft5336_init(const struct device *dev) } #ifdef CONFIG_INPUT_FT5336_INTERRUPT - if (!gpio_is_ready_dt(&config->int_gpio)) { LOG_ERR("Interrupt GPIO controller device not ready"); return -ENODEV; @@ -204,19 +209,80 @@ static int ft5336_init(const struct device *dev) k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_FT5336_PERIOD), K_MSEC(CONFIG_INPUT_FT5336_PERIOD)); #endif + + r = pm_device_runtime_enable(dev); + if (r < 0 && r != -ENOTSUP) { + LOG_ERR("Failed to enable runtime power management"); + return r; + } + return 0; } -#define FT5336_INIT(index) \ - static const struct ft5336_config ft5336_config_##index = { \ - .bus = I2C_DT_SPEC_INST_GET(index), \ - .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \ - IF_ENABLED(CONFIG_INPUT_FT5336_INTERRUPT, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \ - }; \ - static struct ft5336_data ft5336_data_##index; \ - DEVICE_DT_INST_DEFINE(index, ft5336_init, NULL, \ - &ft5336_data_##index, &ft5336_config_##index, \ - POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); +#ifdef CONFIG_PM_DEVICE +static int ft5336_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct ft5336_config *config = dev->config; +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + struct ft5336_data *data = dev->data; +#endif + int ret; + + if (config->reset_gpio.port == NULL) { + return -ENOTSUP; + } + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + ret = i2c_reg_write_byte_dt(&config->bus, + REG_G_PMODE, PMOD_HIBERNATE); + if (ret < 0) { + return ret; + } + +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + k_timer_stop(&data->timer); +#endif + break; + case PM_DEVICE_ACTION_RESUME: + ret = gpio_pin_set_dt(&config->reset_gpio, 1); + if (ret < 0) { + return ret; + } + + k_sleep(K_MSEC(5)); + + ret = gpio_pin_set_dt(&config->reset_gpio, 0); + if (ret < 0) { + return ret; + } + +#ifndef CONFIG_INPUT_FT5336_INTERRUPT + k_timer_start(&data->timer, + K_MSEC(CONFIG_INPUT_FT5336_PERIOD), + K_MSEC(CONFIG_INPUT_FT5336_PERIOD)); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +#define FT5336_INIT(index) \ + PM_DEVICE_DT_INST_DEFINE(n, ft5336_pm_action); \ + static const struct ft5336_config ft5336_config_##index = { \ + .bus = I2C_DT_SPEC_INST_GET(index), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(index, reset_gpios, {0}), \ + IF_ENABLED(CONFIG_INPUT_FT5336_INTERRUPT, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET(index, int_gpios),)) \ + }; \ + static struct ft5336_data ft5336_data_##index; \ + DEVICE_DT_INST_DEFINE(index, ft5336_init, PM_DEVICE_DT_INST_GET(n), \ + &ft5336_data_##index, &ft5336_config_##index, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(FT5336_INIT) diff --git a/drivers/input/input_gpio_kbd_matrix.c b/drivers/input/input_gpio_kbd_matrix.c index 9d532bfd0af..4c82e132f07 100644 --- a/drivers/input/input_gpio_kbd_matrix.c +++ b/drivers/input/input_gpio_kbd_matrix.c @@ -22,13 +22,21 @@ struct gpio_kbd_matrix_config { struct input_kbd_matrix_common_config common; const struct gpio_dt_spec *row_gpio; const struct gpio_dt_spec *col_gpio; + struct gpio_callback *gpio_cb; - gpio_callback_handler_t handler; + gpio_callback_handler_t gpio_cb_handler; + + struct k_work_delayable *idle_poll_dwork; + k_work_handler_t idle_poll_handler; + + bool col_drive_inactive; }; struct gpio_kbd_matrix_data { struct input_kbd_matrix_common_data common; uint32_t last_col_state; + bool direct_read; + bool direct_write; }; INPUT_KBD_STRUCT_CHECK(struct gpio_kbd_matrix_config, @@ -39,7 +47,7 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; struct gpio_kbd_matrix_data *data = dev->data; - int state; + uint32_t state; if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) { state = 0; @@ -49,11 +57,26 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) state = BIT(col); } + if (data->direct_write) { + const struct gpio_dt_spec *gpio0 = &cfg->col_gpio[0]; + gpio_port_pins_t gpio_mask; + gpio_port_value_t gpio_val; + + gpio_mask = BIT_MASK(common->col_size) << gpio0->pin; + gpio_val = state << gpio0->pin; + + gpio_port_set_masked(gpio0->port, gpio_mask, gpio_val); + + return; + } + for (int i = 0; i < common->col_size; i++) { const struct gpio_dt_spec *gpio = &cfg->col_gpio[i]; if ((data->last_col_state ^ state) & BIT(i)) { - if (state & BIT(i)) { + if (cfg->col_drive_inactive) { + gpio_pin_set_dt(gpio, state & BIT(i)); + } else if (state & BIT(i)) { gpio_pin_configure_dt(gpio, GPIO_OUTPUT_ACTIVE); } else { gpio_pin_configure_dt(gpio, GPIO_INPUT); @@ -64,11 +87,21 @@ static void gpio_kbd_matrix_drive_column(const struct device *dev, int col) data->last_col_state = state; } -static int gpio_kbd_matrix_read_row(const struct device *dev) +static kbd_row_t gpio_kbd_matrix_read_row(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; - int val = 0; + struct gpio_kbd_matrix_data *data = dev->data; + kbd_row_t val = 0; + + if (data->direct_read) { + const struct gpio_dt_spec *gpio0 = &cfg->row_gpio[0]; + gpio_port_value_t gpio_val; + + gpio_port_get(gpio0->port, &gpio_val); + + return (gpio_val >> gpio0->pin) & BIT_MASK(common->row_size); + } for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; @@ -81,15 +114,41 @@ static int gpio_kbd_matrix_read_row(const struct device *dev) return val; } +static __maybe_unused void gpio_kbd_matrix_idle_poll_handler(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + const struct input_kbd_matrix_common_config *common = &cfg->common; + + if (gpio_kbd_matrix_read_row(dev) == 0) { + k_work_reschedule(cfg->idle_poll_dwork, + K_USEC(common->poll_period_us)); + return; + } + + input_kbd_matrix_poll_start(dev); +} + static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabled) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; - unsigned int flags = enabled ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; int ret; + if (cfg->idle_poll_dwork != NULL) { + if (enabled) { + k_work_reschedule(cfg->idle_poll_dwork, + K_USEC(common->poll_period_us)); + } + return; + } + + if (cfg->gpio_cb == NULL) { + return; + } + for (int i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; + gpio_flags_t flags = enabled ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; ret = gpio_pin_interrupt_configure_dt(gpio, flags); if (ret != 0) { @@ -99,10 +158,38 @@ static void gpio_kbd_matrix_set_detect_mode(const struct device *dev, bool enabl } } +static bool gpio_kbd_matrix_is_gpio_coherent( + const struct gpio_dt_spec *gpio, int gpio_count) +{ + const struct gpio_dt_spec *gpio0 = &gpio[0]; + + for (int i = 1; i < gpio_count; i++) { + if (gpio[i].port != gpio0->port || + gpio[i].dt_flags != gpio0->dt_flags || + gpio[i].pin != gpio0->pin + i) { + return false; + } + } + + return true; +} + +static bool gpio_kbd_continuous_scan_mode(const struct device *dev) +{ + const struct gpio_kbd_matrix_config *cfg = dev->config; + + if (cfg->gpio_cb == NULL && cfg->idle_poll_dwork == NULL) { + return true; + } + + return false; +} + static int gpio_kbd_matrix_init(const struct device *dev) { const struct gpio_kbd_matrix_config *cfg = dev->config; const struct input_kbd_matrix_common_config *common = &cfg->common; + struct gpio_kbd_matrix_data *data = dev->data; int ret; int i; @@ -114,7 +201,11 @@ static int gpio_kbd_matrix_init(const struct device *dev) return -ENODEV; } - ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + if (cfg->col_drive_inactive) { + ret = gpio_pin_configure_dt(gpio, GPIO_OUTPUT_INACTIVE); + } else { + ret = gpio_pin_configure_dt(gpio, GPIO_INPUT); + } if (ret != 0) { LOG_ERR("Pin %d configuration failed: %d", i, ret); return ret; @@ -123,7 +214,7 @@ static int gpio_kbd_matrix_init(const struct device *dev) for (i = 0; i < common->row_size; i++) { const struct gpio_dt_spec *gpio = &cfg->row_gpio[i]; - struct gpio_callback *gpio_cb = &cfg->gpio_cb[i]; + struct gpio_callback *gpio_cb; if (!gpio_is_ready_dt(gpio)) { LOG_ERR("%s is not ready", gpio->port->name); @@ -136,7 +227,13 @@ static int gpio_kbd_matrix_init(const struct device *dev) return ret; } - gpio_init_callback(gpio_cb, cfg->handler, BIT(gpio->pin)); + if (cfg->gpio_cb == NULL) { + continue; + } + gpio_cb = &cfg->gpio_cb[i]; + + gpio_init_callback(gpio_cb, cfg->gpio_cb_handler, + BIT(gpio->pin)); ret = gpio_add_callback_dt(gpio, gpio_cb); if (ret < 0) { @@ -145,9 +242,32 @@ static int gpio_kbd_matrix_init(const struct device *dev) } } - gpio_kbd_matrix_set_detect_mode(dev, true); + if (cfg->idle_poll_dwork != NULL) { + k_work_init_delayable(cfg->idle_poll_dwork, + cfg->idle_poll_handler); + } + + data->direct_read = gpio_kbd_matrix_is_gpio_coherent( + cfg->row_gpio, common->row_size); + + if (cfg->col_drive_inactive) { + data->direct_write = gpio_kbd_matrix_is_gpio_coherent( + cfg->col_gpio, common->col_size); + } + + LOG_DBG("direct_read: %d direct_write: %d", + data->direct_read, data->direct_write); + + ret = input_kbd_matrix_common_init(dev); + if (ret != 0) { + return ret; + } + + if (gpio_kbd_continuous_scan_mode(dev)) { + input_kbd_matrix_poll_start(dev); + } - return input_kbd_matrix_common_init(dev); + return 0; } static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { @@ -162,12 +282,6 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { INPUT_KBD_MATRIX_DT_INST_DEFINE_ROW_COL( \ n, DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)); \ \ - static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \ - struct gpio_callback *cb, uint32_t pins) \ - { \ - input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \ - } \ - \ static const struct gpio_dt_spec gpio_kbd_matrix_row_gpio_##n[DT_INST_PROP_LEN( \ n, row_gpios)] = { \ DT_INST_FOREACH_PROP_ELEM_SEP(n, row_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ @@ -176,7 +290,26 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { n, col_gpios)] = { \ DT_INST_FOREACH_PROP_ELEM_SEP(n, col_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)) \ }; \ + \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, interrupt), ( \ static struct gpio_callback gpio_kbd_matrix_gpio_cb_##n[DT_INST_PROP_LEN(n, row_gpios)];\ + static void gpio_kbd_matrix_cb_##n(const struct device *gpio_dev, \ + struct gpio_callback *cb, uint32_t pins) \ + { \ + input_kbd_matrix_poll_start(DEVICE_DT_INST_GET(n)); \ + } \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, poll), ( \ + static struct k_work_delayable gpio_kbd_matrix_idle_poll_dwork_##n; \ + static void gpio_kbd_matrix_idle_poll_handler_##n(struct k_work *work) \ + { \ + gpio_kbd_matrix_idle_poll_handler(DEVICE_DT_INST_GET(n)); \ + } \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, scan), ( \ + BUILD_ASSERT(DT_INST_PROP(n, poll_timeout_ms) == 0, \ + "poll-timeout-ms must be set to 0 for scan mode to work correctly"); \ + )) \ \ static const struct gpio_kbd_matrix_config gpio_kbd_matrix_cfg_##n = { \ .common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT_ROW_COL( \ @@ -184,8 +317,15 @@ static const struct input_kbd_matrix_api gpio_kbd_matrix_api = { DT_INST_PROP_LEN(n, row_gpios), DT_INST_PROP_LEN(n, col_gpios)), \ .row_gpio = gpio_kbd_matrix_row_gpio_##n, \ .col_gpio = gpio_kbd_matrix_col_gpio_##n, \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, interrupt), ( \ .gpio_cb = gpio_kbd_matrix_gpio_cb_##n, \ - .handler = gpio_kbd_matrix_cb_##n, \ + .gpio_cb_handler = gpio_kbd_matrix_cb_##n, \ + )) \ + IF_ENABLED(DT_INST_ENUM_HAS_VALUE(n, idle_mode, poll), ( \ + .idle_poll_dwork = &gpio_kbd_matrix_idle_poll_dwork_##n, \ + .idle_poll_handler = gpio_kbd_matrix_idle_poll_handler_##n, \ + )) \ + .col_drive_inactive = DT_INST_PROP(n, col_drive_inactive), \ }; \ \ static struct gpio_kbd_matrix_data gpio_kbd_matrix_data_##n; \ diff --git a/drivers/input/input_gpio_keys.c b/drivers/input/input_gpio_keys.c index bf157d59471..cd277c19fdc 100644 --- a/drivers/input/input_gpio_keys.c +++ b/drivers/input/input_gpio_keys.c @@ -11,12 +11,14 @@ #include #include #include +#include +#include +#include LOG_MODULE_REGISTER(gpio_keys, CONFIG_INPUT_LOG_LEVEL); struct gpio_keys_callback { struct gpio_callback gpio_cb; - uint32_t zephyr_code; int8_t pin_state; }; @@ -26,35 +28,43 @@ struct gpio_keys_pin_config { /** Zephyr code from devicetree */ uint32_t zephyr_code; }; + +struct gpio_keys_pin_data { + const struct device *dev; + struct gpio_keys_callback cb_data; + struct k_work_delayable work; + int8_t pin_state; +}; + struct gpio_keys_config { /** Debounce interval in milliseconds from devicetree */ uint32_t debounce_interval_ms; const int num_keys; const struct gpio_keys_pin_config *pin_cfg; + struct gpio_keys_pin_data *pin_data; + k_work_handler_t handler; + bool polling_mode; }; -struct gpio_keys_pin_data { - const struct device *dev; - struct gpio_keys_callback cb_data; - struct k_work_delayable work; - int8_t pin_state; +struct gpio_keys_data { +#ifdef CONFIG_PM_DEVICE + atomic_t suspended; +#endif }; /** * Handle debounced gpio pin state. */ -static void gpio_keys_change_deferred(struct k_work *work) +static void gpio_keys_poll_pin(const struct device *dev, int key_index) { - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); - const struct device *dev = pin_data->dev; - int key_index = pin_data - (struct gpio_keys_pin_data *)dev->data; const struct gpio_keys_config *cfg = dev->config; const struct gpio_keys_pin_config *pin_cfg = &cfg->pin_cfg[key_index]; + struct gpio_keys_pin_data *pin_data = &cfg->pin_data[key_index]; + int new_pressed; - const int new_pressed = gpio_pin_get(pin_cfg->spec.port, pin_cfg->spec.pin); + new_pressed = gpio_pin_get(pin_cfg->spec.port, pin_cfg->spec.pin); - LOG_DBG("gpio_change_deferred %s pin_state=%d, new_pressed=%d, key_index=%d", dev->name, + LOG_DBG("%s: pin_state=%d, new_pressed=%d, key_index=%d", dev->name, pin_data->cb_data.pin_state, new_pressed, key_index); /* If gpio changed, report the event */ @@ -66,61 +76,84 @@ static void gpio_keys_change_deferred(struct k_work *work) } } -static void gpio_keys_change_call_deferred(struct gpio_keys_pin_data *data, uint32_t msec) +static __maybe_unused void gpio_keys_poll_pins(struct k_work *work) { - int __maybe_unused rv = k_work_reschedule(&data->work, K_MSEC(msec)); + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); + const struct device *dev = pin_data->dev; + const struct gpio_keys_config *cfg = dev->config; + +#ifdef CONFIG_PM_DEVICE + struct gpio_keys_data *data = dev->data; + + if (atomic_get(&data->suspended) == 1) { + return; + } +#endif + + for (int i = 0; i < cfg->num_keys; i++) { + gpio_keys_poll_pin(dev, i); + } - __ASSERT(rv >= 0, "Set wake mask work queue error"); + k_work_reschedule(dwork, K_MSEC(cfg->debounce_interval_ms)); +} + +static __maybe_unused void gpio_keys_change_deferred(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct gpio_keys_pin_data *pin_data = CONTAINER_OF(dwork, struct gpio_keys_pin_data, work); + const struct device *dev = pin_data->dev; + const struct gpio_keys_config *cfg = dev->config; + int key_index = pin_data - (struct gpio_keys_pin_data *)cfg->pin_data; + + gpio_keys_poll_pin(dev, key_index); } static void gpio_keys_interrupt(const struct device *dev, struct gpio_callback *cbdata, uint32_t pins) { - ARG_UNUSED(dev); /* This is a pointer to GPIO device, use dev pointer in - * cbdata for pointer to gpio_debounce device node - */ struct gpio_keys_callback *keys_cb = CONTAINER_OF( cbdata, struct gpio_keys_callback, gpio_cb); struct gpio_keys_pin_data *pin_data = CONTAINER_OF( keys_cb, struct gpio_keys_pin_data, cb_data); const struct gpio_keys_config *cfg = pin_data->dev->config; - for (int i = 0; i < cfg->num_keys; i++) { - if (pins & BIT(cfg->pin_cfg[i].spec.pin)) { - gpio_keys_change_call_deferred(pin_data, cfg->debounce_interval_ms); - } - } + ARG_UNUSED(dev); /* GPIO device pointer. */ + ARG_UNUSED(pins); + + k_work_reschedule(&pin_data->work, K_MSEC(cfg->debounce_interval_ms)); } static int gpio_keys_interrupt_configure(const struct gpio_dt_spec *gpio_spec, struct gpio_keys_callback *cb, uint32_t zephyr_code) { - int retval; - gpio_flags_t flags; + int ret; gpio_init_callback(&cb->gpio_cb, gpio_keys_interrupt, BIT(gpio_spec->pin)); - retval = gpio_add_callback(gpio_spec->port, &cb->gpio_cb); - if (retval < 0) { + ret = gpio_add_callback(gpio_spec->port, &cb->gpio_cb); + if (ret < 0) { LOG_ERR("Could not set gpio callback"); - return retval; + return ret; } - cb->zephyr_code = zephyr_code; cb->pin_state = -1; - flags = GPIO_INT_EDGE_BOTH & ~GPIO_INT_MODE_DISABLED; - LOG_DBG("%s [0x%p, %d]", __func__, gpio_spec->port, gpio_spec->pin); + LOG_DBG("port=%s, pin=%d", gpio_spec->port->name, gpio_spec->pin); - retval = z_impl_gpio_pin_interrupt_configure(gpio_spec->port, gpio_spec->pin, flags); + ret = gpio_pin_interrupt_configure_dt(gpio_spec, GPIO_INT_EDGE_BOTH); + if (ret < 0) { + LOG_ERR("interrupt configuration failed: %d", ret); + return ret; + } - return retval; + return 0; } static int gpio_keys_init(const struct device *dev) { - struct gpio_keys_pin_data *pin_data = dev->data; const struct gpio_keys_config *cfg = dev->config; + struct gpio_keys_pin_data *pin_data = cfg->pin_data; int ret; for (int i = 0; i < cfg->num_keys; i++) { @@ -138,7 +171,11 @@ static int gpio_keys_init(const struct device *dev) } pin_data[i].dev = dev; - k_work_init_delayable(&pin_data[i].work, gpio_keys_change_deferred); + k_work_init_delayable(&pin_data[i].work, cfg->handler); + + if (cfg->polling_mode) { + continue; + } ret = gpio_keys_interrupt_configure(&cfg->pin_cfg[i].spec, &pin_data[i].cb_data, @@ -149,8 +186,74 @@ static int gpio_keys_init(const struct device *dev) } } + if (cfg->polling_mode) { + /* use pin 0 work to poll all the pins periodically */ + k_work_reschedule(&pin_data[0].work, K_MSEC(cfg->debounce_interval_ms)); + } + + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management"); + return ret; + } + + return 0; +} + +#ifdef CONFIG_PM_DEVICE +static int gpio_keys_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct gpio_keys_config *cfg = dev->config; + struct gpio_keys_data *data = dev->data; + struct gpio_keys_pin_data *pin_data = cfg->pin_data; + gpio_flags_t gpio_flags; + gpio_flags_t int_flags; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + gpio_flags = GPIO_DISCONNECTED; + int_flags = GPIO_INT_DISABLE; + atomic_set(&data->suspended, 1); + break; + case PM_DEVICE_ACTION_RESUME: + gpio_flags = GPIO_INPUT; + int_flags = GPIO_INT_EDGE_BOTH; + atomic_set(&data->suspended, 0); + break; + default: + return -ENOTSUP; + } + + for (int i = 0; i < cfg->num_keys; i++) { + const struct gpio_dt_spec *gpio = &cfg->pin_cfg[i].spec; + + ret = gpio_pin_configure_dt(gpio, gpio_flags); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + + if (cfg->polling_mode) { + continue; + } + + ret = gpio_pin_interrupt_configure_dt(gpio, int_flags); + if (ret < 0) { + LOG_ERR("interrupt configuration failed: %d", ret); + return ret; + } + } + + if (action == PM_DEVICE_ACTION_RESUME && cfg->polling_mode) { + k_work_reschedule(&pin_data[0].work, + K_MSEC(cfg->debounce_interval_ms)); + } + return 0; } +#endif #define GPIO_KEYS_CFG_CHECK(node_id) \ BUILD_ASSERT(DT_NODE_HAS_PROP(node_id, zephyr_code), \ @@ -164,17 +267,29 @@ static int gpio_keys_init(const struct device *dev) #define GPIO_KEYS_INIT(i) \ DT_INST_FOREACH_CHILD_STATUS_OKAY(i, GPIO_KEYS_CFG_CHECK); \ + \ static const struct gpio_keys_pin_config gpio_keys_pin_config_##i[] = { \ DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(i, GPIO_KEYS_CFG_DEF, (,))}; \ + \ + static struct gpio_keys_pin_data \ + gpio_keys_pin_data_##i[ARRAY_SIZE(gpio_keys_pin_config_##i)]; \ + \ static const struct gpio_keys_config gpio_keys_config_##i = { \ .debounce_interval_ms = DT_INST_PROP(i, debounce_interval_ms), \ .num_keys = ARRAY_SIZE(gpio_keys_pin_config_##i), \ .pin_cfg = gpio_keys_pin_config_##i, \ + .pin_data = gpio_keys_pin_data_##i, \ + .handler = COND_CODE_1(DT_INST_PROP(i, polling_mode), \ + (gpio_keys_poll_pins), (gpio_keys_change_deferred)), \ + .polling_mode = DT_INST_PROP(i, polling_mode), \ }; \ - static struct gpio_keys_pin_data \ - gpio_keys_pin_data_##i[ARRAY_SIZE(gpio_keys_pin_config_##i)]; \ - DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, NULL, gpio_keys_pin_data_##i, \ - &gpio_keys_config_##i, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ - NULL); + \ + static struct gpio_keys_data gpio_keys_data_##i; \ + \ + PM_DEVICE_DT_INST_DEFINE(i, gpio_keys_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(i, &gpio_keys_init, PM_DEVICE_DT_INST_GET(i), \ + &gpio_keys_data_##i, &gpio_keys_config_##i, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(GPIO_KEYS_INIT) diff --git a/drivers/input/input_gpio_qdec.c b/drivers/input/input_gpio_qdec.c index 2b1a3578b34..4a9b524f461 100644 --- a/drivers/input/input_gpio_qdec.c +++ b/drivers/input/input_gpio_qdec.c @@ -13,6 +13,10 @@ #include #include #include +#include +#include +#include +#include #include LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); @@ -20,8 +24,12 @@ LOG_MODULE_REGISTER(input_gpio_qdec, CONFIG_INPUT_LOG_LEVEL); #define GPIO_QDEC_GPIO_NUM 2 struct gpio_qdec_config { - struct gpio_dt_spec gpio[GPIO_QDEC_GPIO_NUM]; + struct gpio_dt_spec ab_gpio[GPIO_QDEC_GPIO_NUM]; + const struct gpio_dt_spec *led_gpio; + uint8_t led_gpio_count; + uint32_t led_pre_us; uint32_t sample_time_us; + uint32_t idle_poll_time_us; uint32_t idle_timeout_ms; uint16_t axis; uint8_t steps_per_period; @@ -35,6 +43,10 @@ struct gpio_qdec_data { struct k_work event_work; struct k_work_delayable idle_work; struct gpio_callback gpio_cb; + atomic_t polling; +#ifdef CONFIG_PM_DEVICE + atomic_t suspended; +#endif }; /* Positive transitions */ @@ -49,18 +61,95 @@ struct gpio_qdec_data { #define QDEC_HH_LH 0x31 #define QDEC_HL_HH 0x23 +static void gpio_qdec_irq_setup(const struct device *dev, bool enable) +{ + const struct gpio_qdec_config *cfg = dev->config; + gpio_flags_t flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; + int ret; + + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; + + ret = gpio_pin_interrupt_configure_dt(gpio, flags); + if (ret != 0) { + LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); + return; + } + } +} + +static bool gpio_qdec_idle_polling_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + + if (cfg->idle_poll_time_us > 0) { + return true; + } + + return false; +} + +static void gpio_qdec_poll_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + + if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_qdec_irq_setup(dev, false); + } + + k_timer_start(&data->sample_timer, K_NO_WAIT, + K_USEC(cfg->sample_time_us)); + + atomic_set(&data->polling, 1); + + LOG_DBG("polling start"); +} + +static void gpio_qdec_idle_mode(const struct device *dev) +{ + const struct gpio_qdec_config *cfg = dev->config; + struct gpio_qdec_data *data = dev->data; + + if (gpio_qdec_idle_polling_mode(dev)) { + k_timer_start(&data->sample_timer, K_NO_WAIT, + K_USEC(cfg->idle_poll_time_us)); + } else { + k_timer_stop(&data->sample_timer); + gpio_qdec_irq_setup(dev, true); + } + + atomic_set(&data->polling, 0); + + LOG_DBG("polling stop"); +} + static uint8_t gpio_qdec_get_step(const struct device *dev) { const struct gpio_qdec_config *cfg = dev->config; uint8_t step = 0x00; - if (gpio_pin_get_dt(&cfg->gpio[0])) { + if (gpio_qdec_idle_polling_mode(dev)) { + for (int i = 0; i < cfg->led_gpio_count; i++) { + gpio_pin_set_dt(&cfg->led_gpio[i], 1); + } + + k_busy_wait(cfg->led_pre_us); + } + + if (gpio_pin_get_dt(&cfg->ab_gpio[0])) { step |= 0x01; } - if (gpio_pin_get_dt(&cfg->gpio[1])) { + if (gpio_pin_get_dt(&cfg->ab_gpio[1])) { step |= 0x02; } + if (gpio_qdec_idle_polling_mode(dev)) { + for (int i = 0; i < cfg->led_gpio_count; i++) { + gpio_pin_set_dt(&cfg->led_gpio[i], 0); + } + } + return step; } @@ -73,12 +162,23 @@ static void gpio_qdec_sample_timer_timeout(struct k_timer *timer) unsigned int key; uint8_t step; +#ifdef CONFIG_PM_DEVICE + if (atomic_get(&data->suspended) == 1) { + return; + } +#endif + step = gpio_qdec_get_step(dev); if (data->prev_step == step) { return; } + if (gpio_qdec_idle_polling_mode(dev) && + atomic_get(&data->polling) == 0) { + gpio_qdec_poll_mode(dev); + } + switch ((data->prev_step << 4U) | step) { case QDEC_LL_LH: case QDEC_LH_HH: @@ -128,23 +228,6 @@ static void gpio_qdec_event_worker(struct k_work *work) } } -static void gpio_qdec_irq_setup(const struct device *dev, bool enable) -{ - const struct gpio_qdec_config *cfg = dev->config; - unsigned int flags = enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE; - int ret; - - for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { - const struct gpio_dt_spec *gpio = &cfg->gpio[i]; - - ret = gpio_pin_interrupt_configure_dt(gpio, flags); - if (ret != 0) { - LOG_ERR("Pin %d interrupt configuration failed: %d", i, ret); - return; - } - } -} - static void gpio_qdec_idle_worker(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); @@ -152,11 +235,7 @@ static void gpio_qdec_idle_worker(struct k_work *work) dwork, struct gpio_qdec_data, idle_work); const struct device *dev = data->dev; - k_timer_stop(&data->sample_timer); - - gpio_qdec_irq_setup(dev, true); - - LOG_DBG("polling stop"); + gpio_qdec_idle_mode(dev); } static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb, @@ -165,14 +244,8 @@ static void gpio_qdec_cb(const struct device *gpio_dev, struct gpio_callback *cb struct gpio_qdec_data *data = CONTAINER_OF( cb, struct gpio_qdec_data, gpio_cb); const struct device *dev = data->dev; - const struct gpio_qdec_config *cfg = dev->config; - - gpio_qdec_irq_setup(dev, false); - - k_timer_start(&data->sample_timer, K_NO_WAIT, - K_USEC(cfg->sample_time_us)); - LOG_DBG("polling start"); + gpio_qdec_poll_mode(dev); } static int gpio_qdec_init(const struct device *dev) @@ -190,9 +263,9 @@ static int gpio_qdec_init(const struct device *dev) k_timer_user_data_set(&data->sample_timer, (void *)dev); gpio_init_callback(&data->gpio_cb, gpio_qdec_cb, - BIT(cfg->gpio[0].pin) | BIT(cfg->gpio[1].pin)); + BIT(cfg->ab_gpio[0].pin) | BIT(cfg->ab_gpio[1].pin)); for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { - const struct gpio_dt_spec *gpio = &cfg->gpio[i]; + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; if (!gpio_is_ready_dt(gpio)) { LOG_ERR("%s is not ready", gpio->port->name); @@ -205,6 +278,10 @@ static int gpio_qdec_init(const struct device *dev) return ret; } + if (gpio_qdec_idle_polling_mode(dev)) { + continue; + } + ret = gpio_add_callback_dt(gpio, &data->gpio_cb); if (ret < 0) { LOG_ERR("Could not set gpio callback"); @@ -212,23 +289,136 @@ static int gpio_qdec_init(const struct device *dev) } } + for (int i = 0; i < cfg->led_gpio_count; i++) { + const struct gpio_dt_spec *gpio = &cfg->led_gpio[i]; + gpio_flags_t mode; + + if (!gpio_is_ready_dt(gpio)) { + LOG_ERR("%s is not ready", gpio->port->name); + return -ENODEV; + } + + mode = gpio_qdec_idle_polling_mode(dev) ? + GPIO_OUTPUT_INACTIVE : GPIO_OUTPUT_ACTIVE; + + ret = gpio_pin_configure_dt(gpio, mode); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return ret; + } + } + data->prev_step = gpio_qdec_get_step(dev); - gpio_qdec_irq_setup(dev, true); + gpio_qdec_idle_mode(dev); + + ret = pm_device_runtime_enable(dev); + if (ret < 0) { + LOG_ERR("Failed to enable runtime power management"); + return ret; + } LOG_DBG("Device %s initialized", dev->name); return 0; } +#ifdef CONFIG_PM_DEVICE +static void gpio_qdec_pin_suspend(const struct device *dev, bool suspend) +{ + const struct gpio_qdec_config *cfg = dev->config; + gpio_flags_t mode = suspend ? GPIO_DISCONNECTED : GPIO_INPUT; + int ret; + + for (int i = 0; i < GPIO_QDEC_GPIO_NUM; i++) { + const struct gpio_dt_spec *gpio = &cfg->ab_gpio[i]; + + ret = gpio_pin_configure_dt(gpio, mode); + if (ret != 0) { + LOG_ERR("Pin %d configuration failed: %d", i, ret); + return; + } + } + + for (int i = 0; i < cfg->led_gpio_count; i++) { + if (suspend) { + gpio_pin_set_dt(&cfg->led_gpio[i], 0); + } else if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_pin_set_dt(&cfg->led_gpio[i], 1); + } + } +} + +static int gpio_qdec_pm_action(const struct device *dev, + enum pm_device_action action) +{ + struct gpio_qdec_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + struct k_work_sync sync; + + atomic_set(&data->suspended, 1); + + k_work_cancel_delayable_sync(&data->idle_work, &sync); + + if (!gpio_qdec_idle_polling_mode(dev)) { + gpio_qdec_irq_setup(dev, false); + } + + k_timer_stop(&data->sample_timer); + + gpio_qdec_pin_suspend(dev, true); + + break; + case PM_DEVICE_ACTION_RESUME: + atomic_set(&data->suspended, 0); + + gpio_qdec_pin_suspend(dev, false); + + data->prev_step = gpio_qdec_get_step(dev); + data->acc = 0; + + gpio_qdec_idle_mode(dev); + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + #define QDEC_GPIO_INIT(n) \ BUILD_ASSERT(DT_INST_PROP_LEN(n, gpios) == GPIO_QDEC_GPIO_NUM, \ "input_gpio_qdec: gpios must have exactly two entries"); \ \ + BUILD_ASSERT(!(DT_INST_NODE_HAS_PROP(n, led_gpios) && \ + DT_INST_NODE_HAS_PROP(n, idle_poll_time_us)) || \ + DT_INST_NODE_HAS_PROP(n, led_pre_us), \ + "led-pre-us must be specified when setting led-gpios and " \ + "idle-poll-time-us"); \ + \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), ( \ + static const struct gpio_dt_spec gpio_qdec_led_gpio_##n[] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(n, led_gpios, \ + GPIO_DT_SPEC_GET_BY_IDX, (,)) \ + }; \ + )) \ + \ static const struct gpio_qdec_config gpio_qdec_cfg_##n = { \ - .gpio = {GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0), \ - GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1)}, \ + .ab_gpio = { \ + GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 0), \ + GPIO_DT_SPEC_INST_GET_BY_IDX(n, gpios, 1), \ + }, \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(n, led_gpios), ( \ + .led_gpio = gpio_qdec_led_gpio_##n, \ + .led_gpio_count = ARRAY_SIZE(gpio_qdec_led_gpio_##n), \ + .led_pre_us = DT_INST_PROP_OR(n, led_pre_us, 0), \ + )) \ .sample_time_us = DT_INST_PROP(n, sample_time_us), \ + .idle_poll_time_us = DT_INST_PROP_OR(n, idle_poll_time_us, 0), \ .idle_timeout_ms = DT_INST_PROP(n, idle_timeout_ms), \ .steps_per_period = DT_INST_PROP(n, steps_per_period), \ .axis = DT_INST_PROP(n, zephyr_axis), \ @@ -236,7 +426,9 @@ static int gpio_qdec_init(const struct device *dev) \ static struct gpio_qdec_data gpio_qdec_data_##n; \ \ - DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, NULL, \ + PM_DEVICE_DT_INST_DEFINE(n, gpio_qdec_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_qdec_init, PM_DEVICE_DT_INST_GET(n), \ &gpio_qdec_data_##n, \ &gpio_qdec_cfg_##n, \ POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ diff --git a/drivers/input/input_gt911.c b/drivers/input/input_gt911.c index c7f2d5c90b3..01699c06377 100644 --- a/drivers/input/input_gt911.c +++ b/drivers/input/input_gt911.c @@ -17,9 +17,9 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); /* GT911 used registers */ -#define DEVICE_ID __bswap_16(0x8140U) -#define REG_STATUS __bswap_16(0x814EU) -#define REG_FIRST_POINT __bswap_16(0x814FU) +#define DEVICE_ID BSWAP_16(0x8140U) +#define REG_STATUS BSWAP_16(0x814EU) +#define REG_FIRST_POINT BSWAP_16(0x814FU) /* REG_TD_STATUS: Touch points. */ #define TOUCH_POINTS_MSK 0x0FU @@ -28,7 +28,7 @@ LOG_MODULE_REGISTER(gt911, CONFIG_INPUT_LOG_LEVEL); #define TOUCH_STATUS_MSK (1 << 7U) /* The GT911's config */ -#define GT911_CONFIG_REG __bswap_16(0x8047U) +#define GT911_CONFIG_REG BSWAP_16(0x8047U) #define REG_CONFIG_VERSION GT911_CONFIG_REG #define REG_CONFIG_SIZE (186U) #define GT911_PRODUCT_ID (0x00313139U) diff --git a/drivers/input/input_ite_it8xxx2_kbd.c b/drivers/input/input_ite_it8xxx2_kbd.c index 8d688d42db1..5e62e6ee32e 100644 --- a/drivers/input/input_ite_it8xxx2_kbd.c +++ b/drivers/input/input_ite_it8xxx2_kbd.c @@ -79,7 +79,7 @@ static void it8xxx2_kbd_drive_column(const struct device *dev, int col) } } -static int it8xxx2_kbd_read_row(const struct device *dev) +static kbd_row_t it8xxx2_kbd_read_row(const struct device *dev) { const struct it8xxx2_kbd_config *const config = dev->config; struct kscan_it8xxx2_regs *const inst = config->base; diff --git a/drivers/input/input_kbd_matrix.c b/drivers/input/input_kbd_matrix.c index 6005a76b3b3..095a9bb0cfd 100644 --- a/drivers/input/input_kbd_matrix.c +++ b/drivers/input/input_kbd_matrix.c @@ -16,8 +16,6 @@ LOG_MODULE_REGISTER(input_kbd_matrix, CONFIG_INPUT_LOG_LEVEL); -#define INPUT_KBD_MATRIX_ROW_MASK UINT8_MAX - void input_kbd_matrix_poll_start(const struct device *dev) { struct input_kbd_matrix_common_data *data = dev->data; @@ -28,7 +26,7 @@ void input_kbd_matrix_poll_start(const struct device *dev) static bool input_kbd_matrix_ghosting(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; - const uint8_t *state = cfg->matrix_new_state; + const kbd_row_t *state = cfg->matrix_new_state; /* * Matrix keyboard designs are suceptible to ghosting. @@ -59,7 +57,7 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) * using z&(z-1) which is non-zero only if z has more * than one bit set. */ - uint8_t common_row_bits = state[c] & state[c_next]; + kbd_row_t common_row_bits = state[c] & state[c_next]; if (common_row_bits & (common_row_bits - 1)) { return true; @@ -70,25 +68,42 @@ static bool input_kbd_matrix_ghosting(const struct device *dev) return false; } +static void input_kbd_matrix_drive_column(const struct device *dev, int col) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + const struct input_kbd_matrix_api *api = cfg->api; + + api->drive_column(dev, col); + +#ifdef CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK + input_kbd_matrix_drive_column_hook(dev, col); +#endif +} + static bool input_kbd_matrix_scan(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; const struct input_kbd_matrix_api *api = cfg->api; - int row; - uint8_t key_event = 0U; + kbd_row_t row; + kbd_row_t key_event = 0U; for (int col = 0; col < cfg->col_size; col++) { - api->drive_column(dev, col); + input_kbd_matrix_drive_column(dev, col); /* Allow the matrix to stabilize before reading it */ k_busy_wait(cfg->settle_time_us); - row = api->read_row(dev) & INPUT_KBD_MATRIX_ROW_MASK; + row = api->read_row(dev); + + if (cfg->actual_key_mask != NULL) { + row &= cfg->actual_key_mask[col]; + } + cfg->matrix_new_state[col] = row; key_event |= row; } - api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); + input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE); return key_event != 0U; } @@ -97,10 +112,10 @@ static void input_kbd_matrix_update_state(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; struct input_kbd_matrix_common_data *data = dev->data; - uint8_t *matrix_new_state = cfg->matrix_new_state; + kbd_row_t *matrix_new_state = cfg->matrix_new_state; uint32_t cycles_now; - uint8_t row_changed; - uint8_t deb_col; + kbd_row_t row_changed; + kbd_row_t deb_col; cycles_now = k_cycle_get_32(); @@ -143,8 +158,8 @@ static void input_kbd_matrix_update_state(const struct device *dev) /* Debouncing for each row key occurs here */ for (int r = 0; r < cfg->row_size; r++) { - uint8_t mask = BIT(r); - uint8_t row_bit = matrix_new_state[c] & mask; + kbd_row_t mask = BIT(r); + kbd_row_t row_bit = matrix_new_state[c] & mask; /* Continue if we already debounce a key */ if (!(deb_col & mask)) { @@ -153,18 +168,18 @@ static void input_kbd_matrix_update_state(const struct device *dev) uint8_t cyc_idx = c * cfg->row_size + r; uint8_t scan_cyc_idx = cfg->scan_cycle_idx[cyc_idx]; - uint8_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; + uint32_t scan_clk_cycle = data->scan_clk_cycle[scan_cyc_idx]; /* Convert the clock cycle differences to usec */ - uint32_t debt = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); + uint32_t deb_t_us = k_cyc_to_us_floor32(cycles_now - scan_clk_cycle); /* Does the key requires more time to be debounced? */ - if (debt < (row_bit ? cfg->debounce_down_ms : cfg->debounce_up_ms)) { + if (deb_t_us < (row_bit ? cfg->debounce_down_us : cfg->debounce_up_us)) { /* Need more time to debounce */ continue; } - cfg->matrix_unstable_state[c] &= ~row_bit; + cfg->matrix_unstable_state[c] &= ~mask; /* Check if there was a change in the stable state */ if ((cfg->matrix_stable_state[c] & mask) == row_bit) { @@ -197,7 +212,7 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) key_pressed = input_kbd_matrix_scan(dev); for (int c = 0; c < cfg->col_size; c++) { - LOG_DBG("c=%2d u=%02x p=%02x n=%02x", + LOG_DBG("c=%2d u=" PRIkbdrow " p=" PRIkbdrow " n=" PRIkbdrow, c, cfg->matrix_unstable_state[c], cfg->matrix_previous_state[c], @@ -214,6 +229,17 @@ static bool input_kbd_matrix_check_key_events(const struct device *dev) return key_pressed; } +static k_timepoint_t input_kbd_matrix_poll_timeout(const struct device *dev) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + + if (cfg->poll_timeout_ms == 0) { + return sys_timepoint_calc(K_FOREVER); + } + + return sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); +} + static void input_kbd_matrix_poll(const struct device *dev) { const struct input_kbd_matrix_common_config *cfg = dev->config; @@ -222,13 +248,13 @@ static void input_kbd_matrix_poll(const struct device *dev) uint32_t cycles_diff; uint32_t wait_period_us; - poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + poll_time_end = input_kbd_matrix_poll_timeout(dev); while (true) { uint32_t start_period_cycles = k_cycle_get_32(); if (input_kbd_matrix_check_key_events(dev)) { - poll_time_end = sys_timepoint_calc(K_MSEC(cfg->poll_timeout_ms)); + poll_time_end = input_kbd_matrix_poll_timeout(dev); } else if (sys_timepoint_expired(poll_time_end)) { break; } @@ -262,9 +288,16 @@ static void input_kbd_matrix_polling_thread(void *arg1, void *unused2, void *unu ARG_UNUSED(unused3); while (true) { - api->drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); + input_kbd_matrix_drive_column(dev, INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL); api->set_detect_mode(dev, true); + /* Check the rows again after enabling the interrupt to catch + * any potential press since the last read. + */ + if (api->read_row(dev) != 0) { + input_kbd_matrix_poll_start(dev); + } + k_sem_take(&data->poll_lock, K_FOREVER); LOG_DBG("scan start"); @@ -282,11 +315,32 @@ int input_kbd_matrix_common_init(const struct device *dev) k_sem_init(&data->poll_lock, 0, 1); k_thread_create(&data->thread, data->thread_stack, - CONFIG_INPUT_KBD_MATRIX_THREAD_STACK_SIZE, + K_KERNEL_STACK_SIZEOF(data->thread_stack), input_kbd_matrix_polling_thread, (void *)dev, NULL, NULL, - K_PRIO_COOP(4), 0, K_NO_WAIT); + CONFIG_INPUT_KBD_MATRIX_THREAD_PRIORITY, 0, K_NO_WAIT); k_thread_name_set(&data->thread, dev->name); return 0; } + +#if CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC +int input_kbd_matrix_actual_key_mask_set(const struct device *dev, + uint8_t row, uint8_t col, bool enabled) +{ + const struct input_kbd_matrix_common_config *cfg = dev->config; + + if (row >= cfg->row_size || col >= cfg->col_size) { + return -EINVAL; + } + + if (cfg->actual_key_mask == NULL) { + LOG_WRN("actual-key-mask not defined for %s", dev->name); + return -EINVAL; + } + + WRITE_BIT(cfg->actual_key_mask[col], row, enabled); + + return 0; +} +#endif diff --git a/drivers/input/input_npcx_kbd.c b/drivers/input/input_npcx_kbd.c index 64cde93bda9..7b2469d1d5f 100644 --- a/drivers/input/input_npcx_kbd.c +++ b/drivers/input/input_npcx_kbd.c @@ -57,8 +57,13 @@ static void npcx_kbd_ksi_isr(const struct device *dev, struct npcx_wui *wui) static void npcx_kbd_set_detect_mode(const struct device *dev, bool enabled) { const struct npcx_kbd_config *const config = dev->config; + const struct input_kbd_matrix_common_config *common = &config->common; if (enabled) { + for (int i = 0; i < common->row_size; i++) { + npcx_miwu_irq_get_and_clear_pending(&config->wui_maps[i]); + } + irq_enable(config->irq); } else { irq_disable(config->irq); @@ -97,12 +102,12 @@ static void npcx_kbd_drive_column(const struct device *dev, int col) inst->KBSOUT1 = ((mask >> 16) & 0x03); } -static int npcx_kbd_read_row(const struct device *dev) +static kbd_row_t npcx_kbd_read_row(const struct device *dev) { const struct npcx_kbd_config *config = dev->config; const struct input_kbd_matrix_common_config *common = &config->common; struct kbs_reg *const inst = config->base; - int val; + kbd_row_t val; val = inst->KBSIN; @@ -127,7 +132,7 @@ static void npcx_kbd_init_ksi_wui_callback(const struct device *dev, npcx_miwu_manage_callback(callback, 1); /* Configure MIWU setting and enable its interrupt */ - npcx_miwu_interrupt_configure(wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_BOTH); + npcx_miwu_interrupt_configure(wui, NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_LOW); npcx_miwu_irq_enable(wui); } diff --git a/drivers/input/linux_evdev.c b/drivers/input/linux_evdev.c new file mode 100644 index 00000000000..55d412d567c --- /dev/null +++ b/drivers/input/linux_evdev.c @@ -0,0 +1,115 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_native_linux_evdev + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux_evdev_bottom.h" + +LOG_MODULE_REGISTER(linux_evdev, CONFIG_INPUT_LOG_LEVEL); + +static int linux_evdev_fd = -1; +static const char *linux_evdev_path; +static struct k_thread linux_evdev_thread; +static K_KERNEL_STACK_DEFINE(linux_evdev_thread_stack, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); + +static void linux_evdev_options(void) +{ + static struct args_struct_t linux_evdev_options[] = { + { + .is_mandatory = true, + .option = "evdev", + .name = "path", + .type = 's', + .dest = (void *)&linux_evdev_path, + .descript = "Path of the evdev device to use", + }, + ARG_TABLE_ENDMARKER, + }; + + native_add_command_line_opts(linux_evdev_options); +} + +static void linux_evdev_check_arg(void) +{ + if (linux_evdev_path == NULL) { + posix_print_error_and_exit( + "Error: evdev device missing.\n" + "Please specify an evdev device with the --evdev " + "argument when using CONFIG_NATIVE_LINUX_EVDEV=y\n"); + } +} + +static void linux_evdev_cleanup(void) +{ + if (linux_evdev_fd >= 0) { + nsi_host_close(linux_evdev_fd); + } +} + +NATIVE_TASK(linux_evdev_options, PRE_BOOT_1, 10); +NATIVE_TASK(linux_evdev_check_arg, PRE_BOOT_2, 10); +NATIVE_TASK(linux_evdev_cleanup, ON_EXIT, 10); + +static void linux_evdev_thread_fn(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + uint16_t type; + uint16_t code; + int32_t value; + int ret; + + while (true) { + ret = linux_evdev_read(linux_evdev_fd, &type, &code, &value); + if (ret == NATIVE_LINUX_EVDEV_NO_DATA) { + /* Let other threads run. */ + k_sleep(K_MSEC(CONFIG_NATIVE_LINUX_THREAD_SLEEP_MS)); + continue; + } else if (ret < 0) { + return; + } + + LOG_DBG("evdev event: type=%d code=%d val=%d", type, code, value); + + if (type == 0) { /* EV_SYN */ + input_report(dev, 0, 0, 0, true, K_FOREVER); + } else if (type == INPUT_EV_KEY && value == 2) { + /* nothing, ignore key repeats */ + } else { + input_report(dev, type, code, value, false, K_FOREVER); + } + } +} + +static int linux_evdev_init(const struct device *dev) +{ + linux_evdev_fd = linux_evdev_open(linux_evdev_path); + + k_thread_create(&linux_evdev_thread, linux_evdev_thread_stack, + K_KERNEL_STACK_SIZEOF(linux_evdev_thread_stack), + linux_evdev_thread_fn, (void *)dev, NULL, NULL, + CONFIG_NATIVE_LINUX_EVDEV_THREAD_PRIORITY, 0, K_NO_WAIT); + + k_thread_name_set(&linux_evdev_thread, dev->name); + + return 0; +} + +BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, + "Only one zephyr,native-linux-evdev compatible node is supported"); + +DEVICE_DT_INST_DEFINE(0, linux_evdev_init, NULL, + NULL, NULL, + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); diff --git a/drivers/input/linux_evdev_bottom.c b/drivers/input/linux_evdev_bottom.c new file mode 100644 index 00000000000..be65ace084a --- /dev/null +++ b/drivers/input/linux_evdev_bottom.c @@ -0,0 +1,53 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "linux_evdev_bottom.h" + +int linux_evdev_read(int fd, uint16_t *type, uint16_t *code, int32_t *value) +{ + struct input_event ev; + int ret; + + ret = read(fd, &ev, sizeof(ev)); + if (ret < 0) { + if (errno == EAGAIN || errno == EINTR) { + return NATIVE_LINUX_EVDEV_NO_DATA; + } + nsi_print_warning("Read error: %s", strerror(errno)); + return -EIO; + } else if (ret < sizeof(ev)) { + nsi_print_warning("Unexpected read size: %d, expecting %d", + ret, sizeof(ev)); + return -EIO; + } + + *type = ev.type; + *code = ev.code; + *value = ev.value; + + return 0; +} + +int linux_evdev_open(const char *path) +{ + int fd; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + nsi_print_error_and_exit( + "Failed to open the evdev device %s: %s\n", + path, strerror(errno)); + } + + return fd; +} diff --git a/drivers/input/linux_evdev_bottom.h b/drivers/input/linux_evdev_bottom.h new file mode 100644 index 00000000000..153fa4ef6c2 --- /dev/null +++ b/drivers/input/linux_evdev_bottom.h @@ -0,0 +1,17 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ +#define ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ + +#include + +#define NATIVE_LINUX_EVDEV_NO_DATA INT32_MIN + +int linux_evdev_read(int fd, uint16_t *type, uint16_t *code, int32_t *value); +int linux_evdev_open(const char *path); + +#endif /* ZEPHYR_DRIVERS_INPUT_LINUX_EVDEV_BOTTOM_H_ */ diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 5598d038940..0df052e6045 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -32,14 +32,23 @@ zephyr_library_sources_ifdef(CONFIG_SWERV_PIC intc_swerv_pic.c) zephyr_library_sources_ifdef(CONFIG_VEXRISCV_LITEX_IRQ intc_vexriscv_litex.c) zephyr_library_sources_ifdef(CONFIG_VIM intc_vim.c) zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.c) +zephyr_library_sources_ifdef(CONFIG_NUCLEI_ECLIC intc_nuclei_eclic.S) zephyr_library_sources_ifdef(CONFIG_NXP_S32_EIRQ intc_eirq_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) -zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_ra_icu.c) +zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c) +zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) endif() +if(CONFIG_PLIC_SHELL) + message(WARNING " + WARNING: `CONFIG_PLIC_SHELL` is enabled. + This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t))" + ) +endif() + zephyr_library_include_directories(${ZEPHYR_BASE}/arch/common/include) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 2a79a998c02..a956afdf1f6 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -102,6 +102,8 @@ source "drivers/interrupt_controller/Kconfig.nxp_pint" source "drivers/interrupt_controller/Kconfig.vim" -source "drivers/interrupt_controller/Kconfig.ra" +source "drivers/interrupt_controller/Kconfig.renesas_ra" + +source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" endmenu diff --git a/drivers/interrupt_controller/Kconfig.clic b/drivers/interrupt_controller/Kconfig.clic index caa9a93a284..a047a832331 100644 --- a/drivers/interrupt_controller/Kconfig.clic +++ b/drivers/interrupt_controller/Kconfig.clic @@ -5,5 +5,14 @@ config NUCLEI_ECLIC bool "Enhanced Core Local Interrupt Controller (ECLIC)" default y depends on DT_HAS_NUCLEI_ECLIC_ENABLED + select MULTI_LEVEL_INTERRUPTS + select RISCV_SOC_HAS_CUSTOM_IRQ_HANDLING if !RISCV_VECTORED_MODE help Interrupt controller for Nuclei SoC core. + +config LEGACY_CLIC + bool "Use the legacy clic specification" + depends on RISCV_HAS_CLIC + help + Enables legacy clic, where smclicshv extension is not supported and + hardware vectoring is set via mode bits of mtvec. diff --git a/drivers/interrupt_controller/Kconfig.multilevel b/drivers/interrupt_controller/Kconfig.multilevel index 501cf0f4a46..0aae541021e 100644 --- a/drivers/interrupt_controller/Kconfig.multilevel +++ b/drivers/interrupt_controller/Kconfig.multilevel @@ -18,6 +18,7 @@ config MULTI_LEVEL_INTERRUPTS by the hardware. (The term "aggregator" here means "interrupt controller".) +if MULTI_LEVEL_INTERRUPTS config 1ST_LEVEL_INTERRUPT_BITS int "Total number of first level interrupt bits" range 1 32 @@ -29,7 +30,6 @@ config 1ST_LEVEL_INTERRUPT_BITS config MAX_IRQ_PER_AGGREGATOR int "Max IRQs per interrupt aggregator" default 0 - depends on MULTI_LEVEL_INTERRUPTS help The maximum number of interrupt inputs to any aggregator in the @@ -37,7 +37,6 @@ config MAX_IRQ_PER_AGGREGATOR config 2ND_LEVEL_INTERRUPTS bool "Second-level interrupt support" - depends on MULTI_LEVEL_INTERRUPTS help Second level interrupts are used to increase the number of addressable interrupts in a system. @@ -142,3 +141,5 @@ aggregator = 6 rsource "Kconfig.multilevel.aggregator_template" aggregator = 7 rsource "Kconfig.multilevel.aggregator_template" + +endif diff --git a/drivers/interrupt_controller/Kconfig.nxp_irqsteer b/drivers/interrupt_controller/Kconfig.nxp_irqsteer new file mode 100644 index 00000000000..b2dbc9b2afa --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.nxp_irqsteer @@ -0,0 +1,14 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config NXP_IRQSTEER + bool "IRQ_STEER interrupt controller for NXP chips" + default y + depends on DT_HAS_NXP_IRQSTEER_INTC_ENABLED + depends on MULTI_LEVEL_INTERRUPTS + depends on XTENSA + help + The IRQSTEER INTC provides support for MUX-ing + multiple interrupts from peripheral to one or + more CPU interrupt lines. This is used for CPUs + such as XTENSA DSPs. diff --git a/drivers/interrupt_controller/Kconfig.plic b/drivers/interrupt_controller/Kconfig.plic index c1e16c7c1c5..d4f91a3fbd2 100644 --- a/drivers/interrupt_controller/Kconfig.plic +++ b/drivers/interrupt_controller/Kconfig.plic @@ -10,3 +10,14 @@ config PLIC help Platform Level Interrupt Controller provides support for external interrupt lines defined by the RISC-V SoC. + +if PLIC + +config PLIC_SHELL + bool "PLIC shell commands" + depends on SHELL + help + Enable additional shell commands useful for debugging. + Caution: This can use quite a bit of RAM (PLICs * IRQs * sizeof(uint16_t)). + +endif # PLIC diff --git a/drivers/interrupt_controller/Kconfig.ra b/drivers/interrupt_controller/Kconfig.renesas_ra similarity index 100% rename from drivers/interrupt_controller/Kconfig.ra rename to drivers/interrupt_controller/Kconfig.renesas_ra diff --git a/drivers/interrupt_controller/intc_dw_ace.c b/drivers/interrupt_controller/intc_dw_ace.c index a876756a34f..9bda4bddcfa 100644 --- a/drivers/interrupt_controller/intc_dw_ace.c +++ b/drivers/interrupt_controller/intc_dw_ace.c @@ -92,7 +92,7 @@ void dw_ace_irq_enable(const struct device *dev, uint32_t irq) ACE_INTC[i].irq_intmask_l &= ~BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); } } @@ -108,7 +108,7 @@ void dw_ace_irq_disable(const struct device *dev, uint32_t irq) ACE_INTC[i].irq_intmask_l |= BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } } @@ -119,7 +119,7 @@ int dw_ace_irq_is_enabled(const struct device *dev, unsigned int irq) if (is_dw_irq(irq)) { return ACE_INTC[0].irq_inten_l & BIT(ACE_IRQ_FROM_ZEPHYR(irq)); } else if ((irq & ~XTENSA_IRQ_NUM_MASK) == 0U) { - return z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + return xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); } return false; @@ -161,7 +161,7 @@ static int dw_ace_init(const struct device *dev) ARG_UNUSED(dev); IRQ_CONNECT(ACE_INTC_IRQ, 0, dwint_isr, 0, 0); - z_xtensa_irq_enable(ACE_INTC_IRQ); + xtensa_irq_enable(ACE_INTC_IRQ); return 0; } diff --git a/drivers/interrupt_controller/intc_ioapic.c b/drivers/interrupt_controller/intc_ioapic.c index 22e9ecaf374..0748ddccf76 100644 --- a/drivers/interrupt_controller/intc_ioapic.c +++ b/drivers/interrupt_controller/intc_ioapic.c @@ -125,24 +125,17 @@ static const struct device *const vtd = DEVICE_DT_GET_OR_NULL(DT_INST(0, intel_vt_d)); static uint16_t ioapic_id; - static bool get_vtd(void) { - union acpi_dmar_id *dmar_id; - int inst_cnt; - - if (vtd != NULL) { - return true; - } - - /* Assume only one PCH in system (say client platform). */ - if (!acpi_drhd_get(ACPI_DMAR_SCOPE_TYPE_IOAPIC, NULL, &dmar_id, &inst_cnt, 1u)) { + if (!device_is_ready(vtd)) { return false; } - ioapic_id = dmar_id->raw; + if (ioapic_id != 0) { + return true; + } - return vtd == NULL ? false : true; + return acpi_dmar_ioapic_get(&ioapic_id) == 0; } #endif /* CONFIG_INTEL_VTD_ICTL && !INTEL_VTD_ICTL_XAPIC_PASSTHROUGH */ diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.S b/drivers/interrupt_controller/intc_nuclei_eclic.S new file mode 100644 index 00000000000..b077d281751 --- /dev/null +++ b/drivers/interrupt_controller/intc_nuclei_eclic.S @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Baumer Electric AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Assembler-hooks specific to Nuclei's Extended Core Interrupt Controller + */ + +#include + + +GTEXT(__soc_handle_irq) +/* + * In an ECLIC, pending interrupts don't have to be cleared by hand. + * In vectored mode, interrupts are cleared automatically. + * In non-vectored mode, interrupts are cleared when writing the mnxti register (done in + * __soc_handle_all_irqs). + * Thus this function can directly return. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + ret + +#if !defined(CONFIG_RISCV_VECTORED_MODE) + +GTEXT(__soc_handle_all_irqs) + +#ifdef CONFIG_TRACING +/* imports */ +GTEXT(sys_trace_isr_enter) +GTEXT(sys_trace_isr_exit) +#endif + +/* + * This function services and clears all pending interrupts for an ECLIC in non-vectored mode. + */ +SECTION_FUNC(exception.other, __soc_handle_all_irqs) + mv t2, ra + + /* Read and clear mnxti to get highest current interrupt and enable interrupts. Will return + * original interrupt if no others appear. */ + csrrci a0, 0x345, MSTATUS_IEN + beqz a0, irq_done /* Check if original interrupt vanished. */ + +irq_loop: + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_enter +#endif + + /* Call corresponding registered function in _sw_isr_table. a0 is offset in words, table is + * 2-word wide -> shift by one */ + la t0, _sw_isr_table + slli a0, a0, (1) + add t0, t0, a0 + + /* Load argument in a0 register */ + lw a0, 0(t0) + + /* Load ISR function address in register t1 */ + lw t1, RV_REGSIZE(t0) + + /* Call ISR function */ + jalr ra, t1, 0 + + /* Read and clear mnxti to get highest current interrupt and enable interrupts. */ + csrrci a0, 0x345, MSTATUS_IEN + +#ifdef CONFIG_TRACING_ISR + call sys_trace_isr_exit +#endif + + bnez a0, irq_loop + +irq_done: + mv ra, t2 + ret +#endif diff --git a/drivers/interrupt_controller/intc_nuclei_eclic.c b/drivers/interrupt_controller/intc_nuclei_eclic.c index 7c112c1a63f..94f4d067ccb 100644 --- a/drivers/interrupt_controller/intc_nuclei_eclic.c +++ b/drivers/interrupt_controller/intc_nuclei_eclic.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -88,10 +87,8 @@ struct CLICCTRL { /** ECLIC Mode mask for MTVT CSR Register */ #define ECLIC_MODE_MTVEC_Msk 3U -/** CLIC INTATTR: TRIG Position */ -#define CLIC_INTATTR_TRIG_Pos 1U /** CLIC INTATTR: TRIG Mask */ -#define CLIC_INTATTR_TRIG_Msk (0x3UL << CLIC_INTATTR_TRIG_Pos) +#define CLIC_INTATTR_TRIG_Msk 0x3U #define ECLIC_CFG (*((volatile union CLICCFG *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 0)))) #define ECLIC_INFO (*((volatile union CLICINFO *)(DT_REG_ADDR_BY_IDX(DT_NODELABEL(eclic), 1)))) @@ -158,8 +155,27 @@ void riscv_clic_irq_priority_set(uint32_t irq, uint32_t pri, uint32_t flags) ECLIC_CTRL[irq].INTCTRL = intctrl; - ECLIC_CTRL[irq].INTATTR.b.shv = 0; - ECLIC_CTRL[irq].INTATTR.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk); + union CLICINTATTR intattr = {.w = 0}; +#if defined(CONFIG_RISCV_VECTORED_MODE) && !defined(CONFIG_LEGACY_CLIC) + /* + * Set Selective Hardware Vectoring. + * Legacy SiFive does not implement smclicshv extension and vectoring is + * enabled in the mode bits of mtvec. + */ + intattr.b.shv = 1; +#else + intattr.b.shv = 0; +#endif + intattr.b.trg = (uint8_t)(flags & CLIC_INTATTR_TRIG_Msk); + ECLIC_CTRL[irq].INTATTR = intattr; +} + +/** + * @brief Set pending bit of an interrupt + */ +void riscv_clic_irq_set_pending(uint32_t irq) +{ + ECLIC_CTRL[irq].INTIP.b.IP = 1; } static int nuclei_eclic_init(const struct device *dev) diff --git a/drivers/interrupt_controller/intc_nxp_irqsteer.c b/drivers/interrupt_controller/intc_nxp_irqsteer.c new file mode 100644 index 00000000000..cd06b23854a --- /dev/null +++ b/drivers/interrupt_controller/intc_nxp_irqsteer.c @@ -0,0 +1,480 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Driver for NXP's IRQ_STEER IP. + * + * Below you may find some useful information that will help you better understand how the + * driver works. The ">" sign is used to mark ideas that are considered important and should + * be taken note of. + * + * 1) What is the IRQ_STEER IP? + * - in Zephyr terminology, the IRQ_STEER can be considered an interrupt aggregator. As such, + * its main goal is to multiplex multiple interrupt lines into a single/multiple ones. + * + * 2) How does the IRQ_STEER IP work? + * - below you may find a diagram meant to give you an intuition regarding the IP's structure + * and how it works (all of the information below is applicable to i.MX8MP but it can be + * extended to any NXP SoC using the IRQ_STEER IP): + * + * SYSTEM_INTID[0:159] + * | + * MASK[0:4]------ | + * | | + * +------+ + * | | + * |32 AND| + * | | + * +------+ + * | + * SET[0:4]------ | + * | | + * +------+ + * | | + * |32 OR | + * | | + * +------+ + * |__________ STATUS[0:4] + * | + * +------+ + * |GROUP | + * | BY | + * | 64 | + * +------+ + * | | | + * _____________| | |________________ + * | | | + * MASTER_IN[0] MASTER_IN[1] MASTER_IN[2] + * | | | + * | | | + * |_____________ | _______________| + * | | | + * +------+ + * | | + * | AND | ---------- MINTDIS[0:2] + * | | + * +------+ + * | | | + * _____________| | |________________ + * | | | + * MASTER_OUT[0] MASTER_OUT[1] MASTER_OUT[2] + * + * - initially, all SYSTEM_INTID are grouped by 32 => 5 groups. + * + * > each of these groups is controlled by a MASK, SET and STATUS index as follows: + * + * MASK/SET/STATUS[0] => SYSTEM_INTID[159:128] + * MASK/SET/STATUS[1] => SYSTEM_INTID[127:96] + * MASK/SET/STATUS[2] => SYSTEM_INTID[95:64] + * MASK/SET/STATUS[3] => SYSTEM_INTID[63:32] + * MASK/SET/STATUS[4] => SYSTEM_INTID[31:0] + * + * > after that, all SYSTEM_INTID are grouped by 64 as follows: + * + * SYSTEM_INTID[159:96] => MASTER_IN[2] + * SYSTEM_INTID[95:32] => MASTER_IN[1] + * SYSTEM_INTID[31:0] => MASTER_IN[0] + * + * note: MASTER_IN[0] is only responsible for 32 interrupts + * + * > the value of MASTER_IN[x] is obtained by OR'ing the input interrupt lines. + * + * > the value of MASTER_OUT[x] is obtained by AND'ing MASTER_IN[x] with !MINTDIS[x]. + * + * - whenever a SYSTEM_INTID is asserted, its corresponding MASTER_OUT signal will also + * be asserted, thus signaling the target processor. + * + * > please note the difference between an IRQ_STEER channel and an IRQ_STEER master output. + * An IRQ_STEER channel refers to an IRQ_STEER instance (e.g: the DSP uses IRQ_STEER channel + * 0 a.k.a instance 0). An IRQ_STEER channel has multiple master outputs. For example, in + * the case of i.MX8MP each IRQ_STEER channel has 3 master outputs since an IRQ_STEER channel + * routes 160 interrupts (32 for first master output, 64 for second master output, and 64 for + * the third master output). + * + * 3) Using Zephyr's multi-level interrupt support + * - since Zephyr supports organizing interrupts on multiple levels, we can use this to + * separate the interrupts in 2 levels: + * 1) LEVEL 1 INTERRUPTS + * - these are the interrupts that go directly to the processor (for example, + * on i.MX8MP the MU can directly assert the DSP's interrupt line 7) + * + * 2) LEVEL 2 INTERRUPTS + * - these interrupts go through IRQ_STEER and are signaled by a single + * processor interrupt line. + * - e.g: for i.MX8MP, INTID 34 (SDMA3) goes through IRQ_STEER and is signaled + * to the DSP by INTID 20 which is a direct interrupt (or LEVEL 1 interrupt). + * + * - the following diagram (1) shows the interrupt organization on i.MX8MP: + * +------------+ + * | | + * SYSTEM_INTID[31:0] ------ IRQ_STEER_MASTER_0 ---- | 19 | + * | | + * SYSTEM_INTID[95:32] ----- IRQ_STEER_MASTER_1 ---- | 20 DSP | + * | | + * SYSTEM_INTID[159:96] ---- IRQ_STEER_MASTER_2 ---- | 21 | + * | | + * +------------+ + * + * - as such, asserting a system interrupt will lead to asserting its corresponding DSP + * interrupt line (for example, if system interrupt 34 is asserted, that would lead to + * interrupt 20 being asserted) + * + * - in the above diagram, SYSTEM_INTID[x] are LEVEL 2 interrupts, while 19, 20, and 21 are + * LEVEL 1 interrupts. + * + * - INTID 19 is the parent of SYSTEM_INTID[31:0] and so on. + * + * > before going into how the INTIDs are encoded, we need to distinguish between 3 types of + * INTIDs: + * 1) System INTIDs + * - these are the values that can be found in NXP's TRMs for different + * SoCs (usually they have the same IDs as the GIC SPIs) + * - for example, INTID 34 is a system INTID for SDMA3 (i.MX8MP). + * + * 2) Zephyr INTIDs + * - these are the Zephyr-specific encodings of the system INTIDs. + * - these are used to encode multi-level interrupts (for more information + * please see [1]) + * > if you need to register an interrupt dynamically, you need to use this + * encoding when specifying the interrupt. + * + * 3) DTS INTIDs + * - these are the encodings of the system INTIDs used in the DTS. + * - all of these INTIDs are relative to IRQ_STEER's MASTER_OUTs. + * + * > encoding an INTID: + * 1) SYSTEM INTID => ZEPHYR INTID + * - the following steps need to be performed: + * + * a) Find out which IRQ_STEER MASTER + * is in charge of aggregating this interrupt. + * * for instance, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is + * aggregated by MASTER 1 as depicted in diagram (1). + * + * b) After finding the MASTER aggregator, you need + * to find the corresponding parent interrupt. + * * for example, SYSTEM_INTID 34 (SDMA3 on i.MX8MP) is + * aggregated by MASTER 1, which has the parent INTID 20 + * as depicted in diagram (1) => PARENT_INTID(34) = 20. + * + * c) Find the INTID relative to the MASTER aggregator. This is done + * by subtracting the number of interrupts each of the previous + * master aggregators is in charge of. If the master aggregator is + * MASTER 0 then RELATIVE_INTID=SYSTEM_INTID. + * * for example, SYSTEM_ID 34 is aggregated by MASTER 1. + * As such, we need to subtract 32 from 34 (because the + * previous master - MASTER 0 - is in charge of aggregating + * 32 interrupts) => RELATIVE_INTID(34) = 2. + * + * * generally speaking, RELATIVE_INTID can be computed using + * the following formula (assuming SYSTEM_INTID belongs to + * MASTER y): + * RELATIVE_INTID(x) = x - + * \sum{i=0}^{y - 1} GET_MASTER_INT_NUM(i) + * where: + * 1) GET_MASTER_INT_NUM(x) computes the number of + * interrupts master x aggregates + * 2) x is the system interrupt + * + * * to make sure your computation is correct use the + * following restriction: + * 0 <= RELATIVE_INTID(x) < GET_MASTER_INT_NUM(y) + * + * d) To the obtained RELATIVE_INTID you need to add the value of 1, + * left shift the result by the number of bits used to encode the + * level 1 interrupts (see [1] for details) and OR the parent ID. + * * for example, RELATIVE_INTID(34) = 2 (i.MX8MP), + * PARENT_INTID(34) = 20 => ZEPHYR_INTID = ((2 + 1) << 8) | 20 + * + * * generally speaking, ZEPHYR_INTID can be computed using + * the following formula: + * ZEPHYR_INTID(x) = ((RELATIVE_INTID(x) + 1) << + * NUM_LVL1_BITS) | PARENT_INTID(x) + * where: + * 1) RELATIVE_INTID(x) computes the relative INTID + * of system interrupt x (step c). + * + * 2) NUM_LVL1_BITS is the number of bits used to + * encode level 1 interrupts. + * + * 3) PARENT_INTID(x) computes the parent INTID of a + * system interrupt x (step b) + * + * - all of these steps are performed by to_zephyr_irq(). + * > for interrupts aggregated by MASTER 0 you may skip step c) as + * RELATIVE_INTID(x) = x. + * + * 2) SYSTEM INTID => DTS INTID + * - for this you just have to compute RELATIVE_INTID as described above in + * step c). + * - for example, if an IP uses INTID 34 you'd write its interrupts property + * as follows (i.MX8MP): + * interrupts = <&master1 2>; + * + * 4) Notes and comments + * > PLEASE DON'T MISTAKE THE ZEPHYR MULTI-LEVEL INTERRUPT ORGANIZATION WITH THE XTENSA ONE. + * THEY ARE DIFFERENT THINGS. + * + * [1]: https://docs.zephyrproject.org/latest/kernel/services/interrupts.html#multi-level-interrupt-handling + */ + +#include +#include +#include +#include + +#include "sw_isr_common.h" + +/* used for driver binding */ +#define DT_DRV_COMPAT nxp_irqsteer_intc + +/* macros used for DTS parsing */ +#define _IRQSTEER_REGISTER_DISPATCHER(node_id) \ + IRQ_CONNECT(DT_IRQN(node_id), \ + DT_IRQ(node_id, priority), \ + irqsteer_isr_dispatcher, \ + &dispatchers[DT_REG_ADDR(node_id)], \ + 0) + +#define _IRQSTEER_DECLARE_DISPATCHER(node_id) \ +{ \ + .dev = DEVICE_DT_GET(DT_PARENT(node_id)), \ + .master_index = DT_REG_ADDR(node_id), \ + .irq = DT_IRQN(node_id), \ +} + +#define IRQSTEER_DECLARE_DISPATCHERS(parent_id)\ + DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_DECLARE_DISPATCHER, (,)) + +#define IRQSTEER_REGISTER_DISPATCHERS(parent_id)\ + DT_FOREACH_CHILD_STATUS_OKAY_SEP(parent_id, _IRQSTEER_REGISTER_DISPATCHER, (;)) + +/* utility macros */ +#define UINT_TO_IRQSTEER(x) ((IRQSTEER_Type *)(x)) + +struct irqsteer_config { + uint32_t regmap_phys; + uint32_t regmap_size; + struct irqsteer_dispatcher *dispatchers; +}; + +struct irqsteer_dispatcher { + const struct device *dev; + /* which set of interrupts is the dispatcher in charge of? */ + uint32_t master_index; + /* which interrupt line is the dispatcher tied to? */ + uint32_t irq; +}; + +static struct irqsteer_dispatcher dispatchers[] = { + IRQSTEER_DECLARE_DISPATCHERS(DT_NODELABEL(irqsteer)) +}; + +/* used to convert system INTID to zephyr INTID */ +static int to_zephyr_irq(uint32_t regmap, uint32_t irq, + struct irqsteer_dispatcher *dispatcher) +{ + int i, idx; + + idx = irq; + + for (i = dispatcher->master_index - 1; i >= 0; i--) { + idx -= IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return irq_to_level_2(idx) | dispatcher->irq; +} + +/* used to convert master-relative INTID to system INTID */ +static int to_system_irq(uint32_t regmap, int irq, int master_index) +{ + int i; + + for (i = master_index - 1; i >= 0; i--) { + irq += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return irq; +} + +/* used to convert zephyr INTID to system INTID */ +static int from_zephyr_irq(uint32_t regmap, uint32_t irq, uint32_t master_index) +{ + int i, idx; + + idx = irq; + + for (i = 0; i < master_index; i++) { + idx += IRQSTEER_GetMasterIrqCount(UINT_TO_IRQSTEER(regmap), i); + } + + return idx; +} + +void z_soc_irq_enable_disable(uint32_t irq, bool enable) +{ + uint32_t parent_irq; + int i, system_irq, level2_irq; + const struct irqsteer_config *cfg; + + if (irq_get_level(irq) == 1) { + /* LEVEL 1 interrupts are DSP direct */ + if (enable) { + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + } else { + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + } + return; + } + + parent_irq = irq_parent_level_2(irq); + level2_irq = irq_from_level_2(irq); + + /* find dispatcher responsible for this interrupt */ + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + if (dispatchers[i].irq != parent_irq) { + continue; + } + + cfg = dispatchers[i].dev->config; + + system_irq = from_zephyr_irq(cfg->regmap_phys, level2_irq, + dispatchers[i].master_index); + + if (enable) { + IRQSTEER_EnableInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + system_irq); + } else { + IRQSTEER_DisableInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + system_irq); + } + + return; + } +} + +void z_soc_irq_enable(uint32_t irq) +{ + z_soc_irq_enable_disable(irq, true); +} + +void z_soc_irq_disable(uint32_t irq) +{ + z_soc_irq_enable_disable(irq, false); +} + +int z_soc_irq_is_enabled(unsigned int irq) +{ + uint32_t parent_irq; + int i, system_irq, level2_irq; + const struct irqsteer_config *cfg; + + if (irq_get_level(irq) == 1) { + /* LEVEL 1 interrupts are DSP direct */ + return xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + } + + parent_irq = irq_parent_level_2(irq); + level2_irq = irq_from_level_2(irq); + + /* find dispatcher responsible for this interrupt */ + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + if (dispatchers[i].irq != parent_irq) { + continue; + } + + cfg = dispatchers[i].dev->config; + + system_irq = from_zephyr_irq(cfg->regmap_phys, level2_irq, + dispatchers[i].master_index); + + return IRQSTEER_InterruptIsEnabled(UINT_TO_IRQSTEER(cfg->regmap_phys), system_irq); + } + + return false; +} + + +static void irqsteer_isr_dispatcher(const void *data) +{ + struct irqsteer_dispatcher *dispatcher; + const struct irqsteer_config *cfg; + uint32_t table_idx; + int system_irq, zephyr_irq, i; + uint64_t status; + + dispatcher = (struct irqsteer_dispatcher *)data; + cfg = dispatcher->dev->config; + + /* fetch master interrupts status */ + status = IRQSTEER_GetMasterInterruptsStatus(UINT_TO_IRQSTEER(cfg->regmap_phys), + dispatcher->master_index); + + for (i = 0; status; i++) { + /* if bit 0 is set then that means relative INTID i is asserted */ + if (status & 1) { + /* convert master-relative INTID to a system INTID */ + system_irq = to_system_irq(cfg->regmap_phys, i, + dispatcher->master_index); + + /* convert system INTID to a Zephyr INTID */ + zephyr_irq = to_zephyr_irq(cfg->regmap_phys, system_irq, dispatcher); + + /* compute index in the SW ISR table */ + table_idx = z_get_sw_isr_table_idx(zephyr_irq); + + /* call child's ISR */ + _sw_isr_table[table_idx].isr(_sw_isr_table[table_idx].arg); + } + + status >>= 1; + } +} + +static void irqsteer_enable_dispatchers(const struct device *dev) +{ + int i; + struct irqsteer_dispatcher *dispatcher; + const struct irqsteer_config *cfg; + + cfg = dev->config; + + for (i = 0; i < ARRAY_SIZE(dispatchers); i++) { + dispatcher = &dispatchers[i]; + + IRQSTEER_EnableMasterInterrupt(UINT_TO_IRQSTEER(cfg->regmap_phys), + dispatcher->irq); + + xtensa_irq_enable(XTENSA_IRQ_NUMBER(dispatcher->irq)); + } +} + +static int irqsteer_init(const struct device *dev) +{ + IRQSTEER_REGISTER_DISPATCHERS(DT_NODELABEL(irqsteer)); + + /* enable all dispatchers */ + irqsteer_enable_dispatchers(dev); + + return 0; +} + + +/* TODO: do we need to add support for MMU-based SoCs? */ +static struct irqsteer_config irqsteer_config = { + .regmap_phys = DT_REG_ADDR(DT_NODELABEL(irqsteer)), + .regmap_size = DT_REG_SIZE(DT_NODELABEL(irqsteer)), + .dispatchers = dispatchers, +}; + +/* assumption: only 1 IRQ_STEER instance */ +DEVICE_DT_INST_DEFINE(0, + &irqsteer_init, + NULL, + NULL, &irqsteer_config, + PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, + NULL); diff --git a/drivers/interrupt_controller/intc_plic.c b/drivers/interrupt_controller/intc_plic.c index 51ce1769396..f5f762e4aba 100644 --- a/drivers/interrupt_controller/intc_plic.c +++ b/drivers/interrupt_controller/intc_plic.c @@ -13,12 +13,14 @@ * for RISC-V processors */ +#include + #include "sw_isr_common.h" #include #include #include -#include +#include #include #include @@ -29,17 +31,30 @@ * These registers' offset are defined in the RISCV PLIC specs, see: * https://github.com/riscv/riscv-plic-spec */ -#define PLIC_REG_PRIO_OFFSET 0x0 -#define PLIC_REG_IRQ_EN_OFFSET 0x2000 -#define PLIC_REG_REGS_OFFSET 0x200000 -#define PLIC_REG_REGS_THRES_PRIORITY_OFFSET 0 -#define PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET sizeof(uint32_t) +#define CONTEXT_BASE 0x200000 +#define CONTEXT_SIZE 0x1000 +#define CONTEXT_THRESHOLD 0x00 +#define CONTEXT_CLAIM 0x04 +#define CONTEXT_ENABLE_BASE 0x2000 +#define CONTEXT_ENABLE_SIZE 0x80 /* * Trigger type is mentioned, but not defined in the RISCV PLIC specs. * However, it is defined and supported by at least the Andes & Telink datasheet, and supported * in Linux's SiFive PLIC driver */ +#define PLIC_TRIG_LEVEL ((uint32_t)0) +#define PLIC_TRIG_EDGE ((uint32_t)1) +#define PLIC_DRV_HAS_COMPAT(compat) \ + DT_NODE_HAS_COMPAT(DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT), compat) + +#if PLIC_DRV_HAS_COMPAT(andestech_nceplic100) +#define PLIC_SUPPORTS_TRIG_TYPE 1 +#define PLIC_REG_TRIG_TYPE_WIDTH 1 #define PLIC_REG_TRIG_TYPE_OFFSET 0x1080 +#else +/* Trigger-type not supported */ +#define PLIC_REG_TRIG_TYPE_WIDTH 0 +#endif /* PLIC registers are 32-bit memory-mapped */ #define PLIC_REG_SIZE 32 @@ -62,6 +77,15 @@ struct plic_config { riscv_plic_irq_config_func_t irq_config_func; }; +struct plic_stats { + uint16_t *const irq_count; + const int irq_count_len; +}; + +struct plic_data { + struct plic_stats stats; +}; + static uint32_t save_irq; static const struct device *save_dev; @@ -82,18 +106,60 @@ static inline uint32_t get_plic_enabled_size(const struct device *dev) return local_irq_to_reg_index(config->num_irqs) + 1; } +static inline uint32_t get_first_context(uint32_t hartid) +{ + return hartid == 0 ? 0 : (hartid * 2) - 1; +} + +static inline mem_addr_t get_context_en_addr(const struct device *dev, uint32_t cpu_num) +{ + const struct plic_config *config = dev->config; + uint32_t hartid; + /* + * We want to return the irq_en address for the context of given hart. + * If hartid is 0, we return the devices irq_en property, job done. If it is + * greater than zero, we assume that there are two context's associated with + * each hart: M mode enable, followed by S mode enable. We return the M mode + * enable address. + */ +#if CONFIG_SMP + hartid = _kernel.cpus[cpu_num].arch.hartid; +#else + hartid = arch_proc_id(); +#endif + return config->irq_en + get_first_context(hartid) * CONTEXT_ENABLE_SIZE; +} + static inline mem_addr_t get_claim_complete_addr(const struct device *dev) { const struct plic_config *config = dev->config; - return config->reg + PLIC_REG_REGS_CLAIM_COMPLETE_OFFSET; + /* + * We want to return the claim complete addr for the hart's context. + * We are making a few assumptions here: + * 1. for hart 0, return the first context claim complete. + * 2. for any other hart, we assume they have two privileged mode contexts + * which are contiguous, where the m mode context is first. + * We return the m mode context. + */ + + return config->reg + get_first_context(arch_proc_id()) * CONTEXT_SIZE + + CONTEXT_CLAIM; } -static inline mem_addr_t get_threshold_priority_addr(const struct device *dev) + +static inline mem_addr_t get_threshold_priority_addr(const struct device *dev, uint32_t cpu_num) { const struct plic_config *config = dev->config; + uint32_t hartid; + +#if CONFIG_SMP + hartid = _kernel.cpus[cpu_num].arch.hartid; +#else + hartid = arch_proc_id(); +#endif - return config->reg + PLIC_REG_REGS_THRES_PRIORITY_OFFSET; + return config->reg + (get_first_context(hartid) * CONTEXT_SIZE); } /** @@ -105,14 +171,15 @@ static inline mem_addr_t get_threshold_priority_addr(const struct device *dev) */ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) { - const struct device *dev = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), - (z_get_sw_isr_device_from_irq(irq)), (NULL)); - - return dev == NULL ? DEVICE_DT_INST_GET(0) : dev; +#ifdef CONFIG_DYNAMIC_INTERRUPTS + return z_get_sw_isr_device_from_irq(irq); +#else + return DEVICE_DT_INST_GET(0); +#endif } /** - * @brief return edge irq value or zero + * @brief Return the value of the trigger type register for the IRQ * * In the event edge irq is enable this will return the trigger * value of the irq. In the event edge irq is not supported this @@ -121,21 +188,46 @@ static inline const struct device *get_plic_dev_from_irq(uint32_t irq) * @param dev PLIC-instance device * @param local_irq PLIC-instance IRQ number to add to the trigger * - * @return irq value when enabled 0 otherwise + * @return Trigger type register value if PLIC supports trigger type, PLIC_TRIG_LEVEL otherwise */ -static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) +static uint32_t __maybe_unused riscv_plic_irq_trig_val(const struct device *dev, uint32_t local_irq) { + if (!IS_ENABLED(PLIC_SUPPORTS_TRIG_TYPE)) { + return PLIC_TRIG_LEVEL; + } + const struct plic_config *config = dev->config; mem_addr_t trig_addr = config->trig + local_irq_to_reg_offset(local_irq); + uint32_t offset = local_irq * PLIC_REG_TRIG_TYPE_WIDTH; + + return sys_read32(trig_addr) & GENMASK(offset + PLIC_REG_TRIG_TYPE_WIDTH - 1, offset); +} + +static void plic_irq_enable_set_state(uint32_t irq, bool enable) +{ + const struct device *dev = get_plic_dev_from_irq(irq); + const uint32_t local_irq = irq_from_level_2(irq); + + for (uint32_t cpu_num = 0; cpu_num < arch_num_cpus(); cpu_num++) { + mem_addr_t en_addr = + get_context_en_addr(dev, cpu_num) + local_irq_to_reg_offset(local_irq); + + uint32_t en_value; + uint32_t key; - return sys_read32(trig_addr) & BIT(local_irq); + key = irq_lock(); + en_value = sys_read32(en_addr); + WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, enable); + sys_write32(en_value, en_addr); + irq_unlock(key); + } } /** * @brief Enable a riscv PLIC-specific interrupt line * * This routine enables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_enable is called by SOC_FAMILY_RISCV_PRIVILEGED + * riscv_plic_irq_enable is called by RISCV_PRIVILEGED * arch_irq_enable function to enable external interrupts for * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. * @@ -143,25 +235,14 @@ static int riscv_plic_is_edge_irq(const struct device *dev, uint32_t local_irq) */ void riscv_plic_irq_enable(uint32_t irq) { - const struct device *dev = get_plic_dev_from_irq(irq); - const struct plic_config *config = dev->config; - const uint32_t local_irq = irq_from_level_2(irq); - mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); - uint32_t en_value; - uint32_t key; - - key = irq_lock(); - en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, true); - sys_write32(en_value, en_addr); - irq_unlock(key); + plic_irq_enable_set_state(irq, true); } /** * @brief Disable a riscv PLIC-specific interrupt line * * This routine disables a RISCV PLIC-specific interrupt line. - * riscv_plic_irq_disable is called by SOC_FAMILY_RISCV_PRIVILEGED + * riscv_plic_irq_disable is called by RISCV_PRIVILEGED * arch_irq_disable function to disable external interrupts, for * IRQS level == 2, whenever CONFIG_RISCV_HAS_PLIC variable is set. * @@ -169,18 +250,7 @@ void riscv_plic_irq_enable(uint32_t irq) */ void riscv_plic_irq_disable(uint32_t irq) { - const struct device *dev = get_plic_dev_from_irq(irq); - const struct plic_config *config = dev->config; - const uint32_t local_irq = irq_from_level_2(irq); - mem_addr_t en_addr = config->irq_en + local_irq_to_reg_offset(local_irq); - uint32_t en_value; - uint32_t key; - - key = irq_lock(); - en_value = sys_read32(en_addr); - WRITE_BIT(en_value, local_irq & PLIC_REG_MASK, false); - sys_write32(en_value, en_addr); - irq_unlock(key); + plic_irq_enable_set_state(irq, false); } /** @@ -253,11 +323,21 @@ static void plic_irq_handler(const struct device *dev) const struct plic_config *config = dev->config; mem_addr_t claim_complete_addr = get_claim_complete_addr(dev); struct _isr_table_entry *ite; - int edge_irq; + uint32_t __maybe_unused trig_val; /* Get the IRQ number generating the interrupt */ const uint32_t local_irq = sys_read32(claim_complete_addr); +#ifdef CONFIG_PLIC_SHELL + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + /* Cap the count at __UINT16_MAX__ */ + if (stat.irq_count[local_irq] != __UINT16_MAX__) { + stat.irq_count[local_irq]++; + } +#endif /* CONFIG_PLIC_SHELL */ + /* * Save IRQ in save_irq. To be used, if need be, by * subsequent handlers registered in the _sw_isr_table table, @@ -271,18 +351,20 @@ static void plic_irq_handler(const struct device *dev) * If the IRQ is out of range, call z_irq_spurious. * A call to z_irq_spurious will not return. */ - if (local_irq == 0U || local_irq >= config->num_irqs) + if (local_irq == 0U || local_irq >= config->num_irqs) { z_irq_spurious(NULL); + } - edge_irq = riscv_plic_is_edge_irq(dev, local_irq); - +#if IS_ENABLED(PLIC_DRV_HAS_COMPAT(andestech_nceplic100)) + trig_val = riscv_plic_irq_trig_val(dev, local_irq); /* - * For edge triggered interrupts, write to the claim_complete register - * to indicate to the PLIC controller that the IRQ has been handled - * for edge triggered interrupts. + * Edge-triggered interrupts on Andes NCEPLIC100 have to be acknowledged first before + * getting handled so that we don't miss on the next edge-triggered interrupt. */ - if (edge_irq) + if (trig_val == PLIC_TRIG_EDGE) { sys_write32(local_irq, claim_complete_addr); + } +#endif const uint32_t parent_irq = COND_CODE_1(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS), (z_get_sw_isr_irq_from_device(dev)), (0U)); @@ -300,8 +382,14 @@ static void plic_irq_handler(const struct device *dev) * PLIC controller that the IRQ has been handled * for level triggered interrupts. */ - if (!edge_irq) +#if IS_ENABLED(PLIC_DRV_HAS_COMPAT(andestech_nceplic100)) + /* For NCEPLIC100, handle only if level-triggered */ + if (trig_val == PLIC_TRIG_LEVEL) { sys_write32(local_irq, claim_complete_addr); + } +#else + sys_write32(local_irq, claim_complete_addr); +#endif } /** @@ -314,13 +402,21 @@ static void plic_irq_handler(const struct device *dev) static int plic_init(const struct device *dev) { const struct plic_config *config = dev->config; - mem_addr_t en_addr = config->irq_en; + mem_addr_t en_addr, thres_prio_addr; mem_addr_t prio_addr = config->prio; - mem_addr_t thres_prio_addr = get_threshold_priority_addr(dev); - /* Ensure that all interrupts are disabled initially */ - for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { - sys_write32(0U, en_addr + (i * sizeof(uint32_t))); + /* Iterate through each of the contexts, HART + PRIV */ + for (uint32_t cpu_num = 0; cpu_num < arch_num_cpus(); cpu_num++) { + en_addr = get_context_en_addr(dev, cpu_num); + thres_prio_addr = get_threshold_priority_addr(dev, cpu_num); + + /* Ensure that all interrupts are disabled initially */ + for (uint32_t i = 0; i < get_plic_enabled_size(dev); i++) { + sys_write32(0U, en_addr + (i * sizeof(uint32_t))); + } + + /* Set threshold priority to 0 */ + sys_write32(0U, thres_prio_addr); } /* Set priority of each interrupt line to 0 initially */ @@ -328,15 +424,134 @@ static int plic_init(const struct device *dev) sys_write32(0U, prio_addr + (i * sizeof(uint32_t))); } - /* Set threshold priority to 0 */ - sys_write32(0U, thres_prio_addr); - /* Configure IRQ for PLIC driver */ config->irq_config_func(); return 0; } +#ifdef CONFIG_PLIC_SHELL +static inline int parse_device(const struct shell *sh, size_t argc, char *argv[], + const struct device **plic) +{ + ARG_UNUSED(argc); + + *plic = device_get_binding(argv[1]); + if (*plic == NULL) { + shell_error(sh, "PLIC device (%s) not found!\n", argv[1]); + return -ENODEV; + } + + return 0; +} + +static int cmd_get_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + uint16_t min_hit = 0; + + if (ret != 0) { + return ret; + } + + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + if (argc > 2) { + min_hit = (uint16_t)atoi(argv[2]); + shell_print(sh, "IRQ line with > %d hits:", min_hit); + } + + shell_print(sh, " IRQ\t Hits"); + shell_print(sh, "=================="); + for (int i = 0; i < stat.irq_count_len; i++) { + if (stat.irq_count[i] > min_hit) { + shell_print(sh, "%6d\t%10d", i, stat.irq_count[i]); + } + } + shell_print(sh, ""); + + return 0; +} + +static int cmd_clear_stats(const struct shell *sh, size_t argc, char *argv[]) +{ + const struct device *dev; + int ret = parse_device(sh, argc, argv, &dev); + + if (ret != 0) { + return ret; + } + + const struct plic_data *data = dev->data; + struct plic_stats stat = data->stats; + + memset(stat.irq_count, 0, stat.irq_count_len * sizeof(uint16_t)); + + shell_print(sh, "Cleared stats of %s.\n", dev->name); + + return 0; +} + +/* Device name autocompletion support */ +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_stats_cmds, + SHELL_CMD_ARG(get, &dsub_device_name, + "Read PLIC's stats.\n" + "Usage: plic stats get [minimum hits]", + cmd_get_stats, 2, 1), + SHELL_CMD_ARG(clear, &dsub_device_name, + "Reset PLIC's stats.\n" + "Usage: plic stats clear ", + cmd_clear_stats, 2, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_STATIC_SUBCMD_SET_CREATE(plic_cmds, + SHELL_CMD_ARG(stats, &plic_stats_cmds, "PLIC stats", NULL, 3, 0), + SHELL_SUBCMD_SET_END +); + +static int cmd_plic(const struct shell *sh, size_t argc, char **argv) +{ + shell_error(sh, "%s:unknown parameter: %s", argv[0], argv[1]); + return -EINVAL; +} + +SHELL_CMD_ARG_REGISTER(plic, &plic_cmds, "PLIC shell commands", + cmd_plic, 2, 0); + +#define PLIC_MIN_IRQ_NUM(n) MIN(DT_INST_PROP(n, riscv_ndev), CONFIG_MAX_IRQ_PER_AGGREGATOR) +#define PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n) \ + static uint16_t local_irq_count_##n[PLIC_MIN_IRQ_NUM(n)]; + +#define PLIC_INTC_DATA_INIT(n) \ + PLIC_INTC_IRQ_COUNT_BUF_DEFINE(n); \ + static struct plic_data plic_data_##n = { \ + .stats = { \ + .irq_count = local_irq_count_##n, \ + .irq_count_len = PLIC_MIN_IRQ_NUM(n), \ + }, \ + }; + +#define PLIC_INTC_DATA(n) &plic_data_##n +#else +#define PLIC_INTC_DATA_INIT(...) +#define PLIC_INTC_DATA(n) (NULL) +#endif + #define PLIC_INTC_IRQ_FUNC_DECLARE(n) static void plic_irq_config_func_##n(void) #define PLIC_INTC_IRQ_FUNC_DEFINE(n) \ @@ -349,10 +564,11 @@ static int plic_init(const struct device *dev) #define PLIC_INTC_CONFIG_INIT(n) \ PLIC_INTC_IRQ_FUNC_DECLARE(n); \ static const struct plic_config plic_config_##n = { \ - .prio = PLIC_BASE_ADDR(n) + PLIC_REG_PRIO_OFFSET, \ - .irq_en = PLIC_BASE_ADDR(n) + PLIC_REG_IRQ_EN_OFFSET, \ - .reg = PLIC_BASE_ADDR(n) + PLIC_REG_REGS_OFFSET, \ - .trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET, \ + .prio = PLIC_BASE_ADDR(n), \ + .irq_en = PLIC_BASE_ADDR(n) + CONTEXT_ENABLE_BASE, \ + .reg = PLIC_BASE_ADDR(n) + CONTEXT_BASE, \ + IF_ENABLED(PLIC_SUPPORTS_TRIG_TYPE, \ + (.trig = PLIC_BASE_ADDR(n) + PLIC_REG_TRIG_TYPE_OFFSET,)) \ .max_prio = DT_INST_PROP(n, riscv_max_priority), \ .num_irqs = DT_INST_PROP(n, riscv_ndev), \ .irq_config_func = plic_irq_config_func_##n, \ @@ -361,8 +577,9 @@ static int plic_init(const struct device *dev) #define PLIC_INTC_DEVICE_INIT(n) \ PLIC_INTC_CONFIG_INIT(n) \ + PLIC_INTC_DATA_INIT(n) \ DEVICE_DT_INST_DEFINE(n, &plic_init, NULL, \ - NULL, &plic_config_##n, \ + PLIC_INTC_DATA(n), &plic_config_##n, \ PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, \ NULL); diff --git a/drivers/interrupt_controller/intc_ra_icu.c b/drivers/interrupt_controller/intc_ra_icu.c deleted file mode 100644 index 167673f187f..00000000000 --- a/drivers/interrupt_controller/intc_ra_icu.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023 TOKITTA Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT renesas_ra_interrupt_controller_unit - -#include -#include -#include -#include -#include -#include - -#define IELSRn_REG(n) (DT_INST_REG_ADDR(0) + IELSRn_OFFSET + (n * 4)) -#define IRQCRi_REG(i) (DT_INST_REG_ADDR(0) + IRQCRi_OFFSET + (i)) - -#define IRQCRi_IRQMD_POS 0 -#define IRQCRi_IRQMD_MASK BIT_MASK(2) -#define IELSRn_IR_POS 16 -#define IELSRn_IR_MASK BIT_MASK(1) - -enum { - IRQCRi_OFFSET = 0x0, - IELSRn_OFFSET = 0x300, -}; - -int ra_icu_query_exists_irq(uint32_t event) -{ - for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) { - uint32_t els = sys_read32(IELSRn_REG(i)) & UINT8_MAX; - - if (event == els) { - return i; - } - } - - return -EINVAL; -} - -int ra_icu_query_available_irq(uint32_t event) -{ - int irq = -EINVAL; - - if (ra_icu_query_exists_irq(event) > 0) { - return -EINVAL; - } - - for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) { - if (_sw_isr_table[i].isr == z_irq_spurious) { - irq = i; - break; - } - } - - return irq; -} - -void ra_icu_clear_int_flag(unsigned int irqn) -{ - uint32_t cfg = sys_read32(IELSRn_REG(irqn)); - - sys_write32(cfg & ~BIT(IELSRn_IR_POS), IELSRn_REG(irqn)); -} - -void ra_icu_query_irq_config(unsigned int irq, uint32_t *intcfg, ra_isr_handler *cb, - const void **cbarg) -{ - *intcfg = sys_read32(IELSRn_REG(irq)); - *cb = _sw_isr_table[irq].isr; - *cbarg = (void *)_sw_isr_table[irq].arg; -} - -static void ra_icu_irq_configure(unsigned int irqn, uint32_t intcfg) -{ - uint8_t reg = sys_read8(IRQCRi_REG(irqn)) & ~(IRQCRi_IRQMD_MASK); - - sys_write8(reg | (intcfg & IRQCRi_IRQMD_MASK), IRQCRi_REG(irqn)); -} - -int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, - void (*routine)(const void *parameter), const void *parameter, - uint32_t flags) -{ - uint32_t event = ((flags & RA_ICU_FLAG_EVENT_MASK) >> RA_ICU_FLAG_EVENT_OFFSET); - uint32_t intcfg = ((flags & RA_ICU_FLAG_INTCFG_MASK) >> RA_ICU_FLAG_INTCFG_OFFSET); - int irqn = irq; - - if (irq == RA_ICU_IRQ_UNSPECIFIED) { - irqn = ra_icu_query_available_irq(event); - if (irqn < 0) { - return irqn; - } - } - - irq_disable(irqn); - sys_write32(event, IELSRn_REG(irqn)); - z_isr_install(irqn, routine, parameter); - z_arm_irq_priority_set(irqn, priority, flags); - ra_icu_irq_configure(event, intcfg); - irq_enable(irqn); - - return irqn; -} - -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, - NULL); diff --git a/drivers/interrupt_controller/intc_renesas_ra_icu.c b/drivers/interrupt_controller/intc_renesas_ra_icu.c new file mode 100644 index 00000000000..57b9ac731ab --- /dev/null +++ b/drivers/interrupt_controller/intc_renesas_ra_icu.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 TOKITTA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_ra_interrupt_controller_unit + +#include +#include +#include +#include +#include +#include + +#define IELSRn_REG(n) (DT_INST_REG_ADDR(0) + IELSRn_OFFSET + (n * 4)) +#define IRQCRi_REG(i) (DT_INST_REG_ADDR(0) + IRQCRi_OFFSET + (i)) + +#define IRQCRi_IRQMD_POS 0 +#define IRQCRi_IRQMD_MASK BIT_MASK(2) +#define IELSRn_IR_POS 16 +#define IELSRn_IR_MASK BIT_MASK(1) + +enum { + IRQCRi_OFFSET = 0x0, + IELSRn_OFFSET = 0x300, +}; + +int ra_icu_query_exists_irq(uint32_t event) +{ + for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) { + uint32_t els = sys_read32(IELSRn_REG(i)) & UINT8_MAX; + + if (event == els) { + return i; + } + } + + return -EINVAL; +} + +int ra_icu_query_available_irq(uint32_t event) +{ + int irq = -EINVAL; + + if (ra_icu_query_exists_irq(event) > 0) { + return -EINVAL; + } + + for (uint32_t i = 0; i < CONFIG_NUM_IRQS; i++) { + if (_sw_isr_table[i].isr == z_irq_spurious) { + irq = i; + break; + } + } + + return irq; +} + +void ra_icu_clear_int_flag(unsigned int irqn) +{ + uint32_t cfg = sys_read32(IELSRn_REG(irqn)); + + sys_write32(cfg & ~BIT(IELSRn_IR_POS), IELSRn_REG(irqn)); +} + +void ra_icu_query_irq_config(unsigned int irq, uint32_t *intcfg, ra_isr_handler *cb, + const void **cbarg) +{ + *intcfg = sys_read32(IELSRn_REG(irq)); + *cb = _sw_isr_table[irq].isr; + *cbarg = (void *)_sw_isr_table[irq].arg; +} + +static void ra_icu_irq_configure(unsigned int irqn, uint32_t intcfg) +{ + uint8_t reg = sys_read8(IRQCRi_REG(irqn)) & ~(IRQCRi_IRQMD_MASK); + + sys_write8(reg | (intcfg & IRQCRi_IRQMD_MASK), IRQCRi_REG(irqn)); +} + +int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), const void *parameter, + uint32_t flags) +{ + uint32_t event = ((flags & RA_ICU_FLAG_EVENT_MASK) >> RA_ICU_FLAG_EVENT_OFFSET); + uint32_t intcfg = ((flags & RA_ICU_FLAG_INTCFG_MASK) >> RA_ICU_FLAG_INTCFG_OFFSET); + int irqn = irq; + + if (irq == RA_ICU_IRQ_UNSPECIFIED) { + irqn = ra_icu_query_available_irq(event); + if (irqn < 0) { + return irqn; + } + } + + irq_disable(irqn); + sys_write32(event, IELSRn_REG(irqn)); + z_isr_install(irqn, routine, parameter); + z_arm_irq_priority_set(irqn, priority, flags); + ra_icu_irq_configure(event, intcfg); + + return irqn; +} + +int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), const void *parameter, + uint32_t flags) +{ + int irqn = irq; + + if (irq == RA_ICU_IRQ_UNSPECIFIED) { + return -EINVAL; + } + + irq_disable(irqn); + sys_write32(0, IELSRn_REG(irqn)); + z_isr_install(irqn, z_irq_spurious, NULL); + z_arm_irq_priority_set(irqn, 0, 0); + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); diff --git a/drivers/interrupt_controller/intc_shared_irq.c b/drivers/interrupt_controller/intc_shared_irq.c index 0ec50b0c2e6..337a1e432b7 100644 --- a/drivers/interrupt_controller/intc_shared_irq.c +++ b/drivers/interrupt_controller/intc_shared_irq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Intel Corporation. + * Copyright (c) 2015 - 2023 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ @@ -125,7 +125,7 @@ void shared_irq_isr(const struct device *dev) for (i = 0U; i < config->client_count; i++) { if (clients->client[i].isr_dev) { - clients->client[i].isr_func(clients->client[i].isr_dev); + clients->client[i].isr_func(clients->client[i].isr_dev, config->irq_num); } } } diff --git a/drivers/interrupt_controller/intc_swerv_pic.c b/drivers/interrupt_controller/intc_swerv_pic.c index 5c52ab49614..96eb248d27c 100644 --- a/drivers/interrupt_controller/intc_swerv_pic.c +++ b/drivers/interrupt_controller/intc_swerv_pic.c @@ -15,6 +15,7 @@ #include #include #include +#include #define SWERV_PIC_MAX_NUM CONFIG_NUM_IRQS #define SWERV_PIC_MAX_ID (SWERV_PIC_MAX_NUM + RISCV_MAX_GENERIC_IRQ) @@ -176,14 +177,14 @@ static int swerv_pic_init(const struct device *dev) __asm__ swerv_pic_writecsr(meicurpl, 0); /* Setup IRQ handler for SweRV PIC driver */ - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, + IRQ_CONNECT(RISCV_IRQ_MEXT, 0, swerv_pic_irq_handler, NULL, 0); /* Enable IRQ for SweRV PIC driver */ - irq_enable(RISCV_MACHINE_EXT_IRQ); + irq_enable(RISCV_IRQ_MEXT); return 0; } diff --git a/drivers/interrupt_controller/intc_vexriscv_litex.c b/drivers/interrupt_controller/intc_vexriscv_litex.c index efec4d2478e..2d5d2233ab2 100644 --- a/drivers/interrupt_controller/intc_vexriscv_litex.c +++ b/drivers/interrupt_controller/intc_vexriscv_litex.c @@ -11,6 +11,7 @@ #include #include #include +#include #define IRQ_MASK DT_INST_REG_ADDR_BY_NAME(0, irq_mask) #define IRQ_PENDING DT_INST_REG_ADDR_BY_NAME(0, irq_pending) @@ -122,9 +123,9 @@ int arch_irq_is_enabled(unsigned int irq) static int vexriscv_litex_irq_init(const struct device *dev) { __asm__ volatile ("csrrs x0, mie, %0" - :: "r"(1 << RISCV_MACHINE_EXT_IRQ)); + :: "r"(1 << RISCV_IRQ_MEXT)); vexriscv_litex_irq_setie(1); - IRQ_CONNECT(RISCV_MACHINE_EXT_IRQ, 0, vexriscv_litex_irq_handler, + IRQ_CONNECT(RISCV_IRQ_MEXT, 0, vexriscv_litex_irq_handler, NULL, 0); return 0; diff --git a/drivers/ipm/ipm_cavs_host.c b/drivers/ipm/ipm_cavs_host.c index 5877309d48d..2a6acef6efb 100644 --- a/drivers/ipm/ipm_cavs_host.c +++ b/drivers/ipm/ipm_cavs_host.c @@ -7,6 +7,7 @@ #include #include #include +#include /* Matches SOF_IPC_MSG_MAX_SIZE, though in practice nothing anywhere * near that big is ever sent. Should maybe consider making this a @@ -49,8 +50,9 @@ static int send(const struct device *dev, int wait, uint32_t id, return -ENODEV; } const struct mem_win_config *mw0_config = mw0->config; - uint32_t *buf = (uint32_t *)arch_xtensa_uncached_ptr((void *)((uint32_t)mw0_config->mem_base - + CONFIG_IPM_CAVS_HOST_OUTBOX_OFFSET)); + uint32_t *buf = (uint32_t *)sys_cache_uncached_ptr_get( + (void *)((uint32_t)mw0_config->mem_base + + CONFIG_IPM_CAVS_HOST_OUTBOX_OFFSET)); if (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) { return -EBUSY; @@ -108,7 +110,7 @@ static bool ipc_handler(const struct device *dev, void *arg, return -ENODEV; } const struct mem_win_config *mw1_config = mw1->config; - uint32_t *msg = arch_xtensa_uncached_ptr((void *)mw1_config->mem_base); + uint32_t *msg = sys_cache_uncached_ptr_get((void *)mw1_config->mem_base); /* We play tricks to leave one word available before the * beginning of the SRAM window, this way the host can see the diff --git a/drivers/ipm/ipm_esp32.c b/drivers/ipm/ipm_esp32.c index cbe6e42d90f..4fc504610a6 100644 --- a/drivers/ipm/ipm_esp32.c +++ b/drivers/ipm/ipm_esp32.c @@ -54,13 +54,13 @@ IRAM_ATTR static void esp32_ipm_isr(const struct device *dev) /* clear interrupt flag */ if (core_id == 0) { -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0); #endif } else { -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, 0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, 0); @@ -138,7 +138,7 @@ static int esp32_ipm_send(const struct device *dev, int wait, uint32_t id, memcpy(dev_data->shm.app_cpu_shm, data, size); atomic_set(&dev_data->control->lock, ESP32_IPM_LOCK_FREE_VAL); LOG_DBG("Generating interrupt on remote CPU 1 from CPU 0"); -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_1_REG, DPORT_CPU_INTR_FROM_CPU_1); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_1_REG, SYSTEM_CPU_INTR_FROM_CPU_1); @@ -148,7 +148,7 @@ static int esp32_ipm_send(const struct device *dev, int wait, uint32_t id, memcpy(dev_data->shm.pro_cpu_shm, data, size); atomic_set(&dev_data->control->lock, ESP32_IPM_LOCK_FREE_VAL); LOG_DBG("Generating interrupt on remote CPU 0 from CPU 1"); -#if defined(CONFIG_SOC_SERIES_ESP32) || defined(CONFIG_SOC_SERIES_ESP32_NET) +#if defined(CONFIG_SOC_SERIES_ESP32) DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0); #elif defined(CONFIG_SOC_SERIES_ESP32S3) WRITE_PERI_REG(SYSTEM_CPU_INTR_FROM_CPU_0_REG, SYSTEM_CPU_INTR_FROM_CPU_0); diff --git a/drivers/kscan/kscan_mchp_xec.c b/drivers/kscan/kscan_mchp_xec.c index e0960b1c946..e3e8fa4043e 100644 --- a/drivers/kscan/kscan_mchp_xec.c +++ b/drivers/kscan/kscan_mchp_xec.c @@ -373,9 +373,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) drive_keyboard_column(dev, KEYBOARD_COLUMN_DRIVE_ALL); k_sem_take(&data->poll_lock, K_FOREVER); -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + uint32_t start_poll_cycles = k_cycle_get_32(); while (atomic_get(&data->enable_scan) == 1U) { @@ -416,9 +415,8 @@ void polling_task(const struct device *dev, void *dummy2, void *dummy3) /* Allow other threads to run while we sleep */ k_usleep(wait_period); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } } diff --git a/drivers/led_strip/CMakeLists.txt b/drivers/led_strip/CMakeLists.txt index 6c950cac596..aa4e95722a7 100644 --- a/drivers/led_strip/CMakeLists.txt +++ b/drivers/led_strip/CMakeLists.txt @@ -7,4 +7,5 @@ zephyr_library_sources_ifdef(CONFIG_LPD880X_STRIP lpd880x.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_GPIO ws2812_gpio.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_SPI ws2812_spi.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_I2S ws2812_i2s.c) +zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_RPI_PICO_PIO ws2812_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_TLC5971_STRIP tlc5971.c) diff --git a/drivers/led_strip/Kconfig.ws2812 b/drivers/led_strip/Kconfig.ws2812 index fc91250c2f2..469b6d3f915 100644 --- a/drivers/led_strip/Kconfig.ws2812 +++ b/drivers/led_strip/Kconfig.ws2812 @@ -9,7 +9,6 @@ menuconfig WS2812_STRIP bool "WS2812 (and compatible) LED strip driver" - select LED_STRIP_RGB_SCRATCH help Enable LED strip driver for daisy chains of WS2812-ish (or WS2812B, WS2813, SK6812, Everlight B1414, or compatible) devices. @@ -39,6 +38,7 @@ config WS2812_STRIP_GPIO # Only an Cortex-M0 inline assembly implementation for the nRF51 # is supported currently. depends on SOC_SERIES_NRF51X + select LED_STRIP_RGB_SCRATCH help The GPIO driver does bit-banging with inline assembly, and is not available on all SoCs. @@ -46,4 +46,11 @@ config WS2812_STRIP_GPIO Note that this driver is not compatible with the Everlight B1414 controller. +config WS2812_STRIP_RPI_PICO_PIO + bool "Raspberry Pi Pico PIO" + depends on DT_HAS_WORLDSEMI_WS2812_RPI_PICO_PIO_ENABLED + select PICOSDK_USE_PIO + help + Use the PIO feature available on RaspberryPi Pico devices. + endchoice diff --git a/drivers/led_strip/ws2812_rpi_pico_pio.c b/drivers/led_strip/ws2812_rpi_pico_pio.c new file mode 100644 index 00000000000..b2bb2654977 --- /dev/null +++ b/drivers/led_strip/ws2812_rpi_pico_pio.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(ws2812_rpi_pico_pio, CONFIG_LED_STRIP_LOG_LEVEL); + +#define DT_DRV_COMPAT worldsemi_ws2812_rpi_pico_pio + +struct ws2812_led_strip_data { + uint32_t sm; +}; + +struct ws2812_led_strip_config { + const struct device *piodev; + uint32_t output_pin; + uint8_t num_colors; + uint32_t frequency; + const uint8_t *const color_mapping; + uint16_t reset_delay; + uint32_t cycles_per_bit; +}; + +struct ws2812_rpi_pico_pio_config { + const struct device *piodev; + const struct pinctrl_dev_config *const pcfg; + struct pio_program program; +}; + +static int ws2812_led_strip_sm_init(const struct device *dev) +{ + const struct ws2812_led_strip_config *config = dev->config; + const float clkdiv = + sys_clock_hw_cycles_per_sec() / (config->cycles_per_bit * config->frequency); + pio_sm_config sm_config = pio_get_default_sm_config(); + PIO pio; + int sm; + + pio = pio_rpi_pico_get_pio(config->piodev); + + sm = pio_claim_unused_sm(pio, false); + if (sm < 0) { + return -EINVAL; + } + + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_sideset_pins(&sm_config, config->output_pin); + sm_config_set_out_shift(&sm_config, false, true, (config->num_colors == 4 ? 32 : 24)); + sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX); + sm_config_set_clkdiv(&sm_config, clkdiv); + pio_sm_set_consecutive_pindirs(pio, sm, config->output_pin, 1, true); + pio_sm_init(pio, sm, -1, &sm_config); + pio_sm_set_enabled(pio, sm, true); + + return sm; +} + +/* + * Latch current color values on strip and reset its state machines. + */ +static inline void ws2812_led_strip_reset_delay(uint16_t delay) +{ + k_usleep(delay); +} + +static int ws2812_led_strip_update_rgb(const struct device *dev, struct led_rgb *pixels, + size_t num_pixels) +{ + const struct ws2812_led_strip_config *config = dev->config; + struct ws2812_led_strip_data *data = dev->data; + PIO pio = pio_rpi_pico_get_pio(config->piodev); + + for (size_t i = 0; i < num_pixels; i++) { + uint32_t color = 0; + + for (size_t j = 0; j < config->num_colors; j++) { + switch (config->color_mapping[j]) { + /* White channel is not supported by LED strip API. */ + case LED_COLOR_ID_WHITE: + color |= 0; + break; + case LED_COLOR_ID_RED: + color |= pixels[i].r << (8 * (2 - j)); + break; + case LED_COLOR_ID_GREEN: + color |= pixels[i].g << (8 * (2 - j)); + break; + case LED_COLOR_ID_BLUE: + color |= pixels[i].b << (8 * (2 - j)); + break; + } + } + + pio_sm_put_blocking(pio, data->sm, color << (config->num_colors == 4 ? 0 : 8)); + } + + ws2812_led_strip_reset_delay(config->reset_delay); + + return 0; +} + +static int ws2812_led_strip_update_channels(const struct device *dev, uint8_t *channels, + size_t num_channels) +{ + LOG_DBG("update_channels not implemented"); + return -ENOTSUP; +} + +static const struct led_strip_driver_api ws2812_led_strip_api = { + .update_rgb = ws2812_led_strip_update_rgb, + .update_channels = ws2812_led_strip_update_channels, +}; + +/* + * Retrieve the channel to color mapping (e.g. RGB, BGR, GRB, ...) from the + * "color-mapping" DT property. + */ +static int ws2812_led_strip_init(const struct device *dev) +{ + const struct ws2812_led_strip_config *config = dev->config; + struct ws2812_led_strip_data *data = dev->data; + int sm; + + if (!device_is_ready(config->piodev)) { + LOG_ERR("%s: PIO device not ready", dev->name); + return -ENODEV; + } + + for (uint32_t i = 0; i < config->num_colors; i++) { + switch (config->color_mapping[i]) { + case LED_COLOR_ID_WHITE: + case LED_COLOR_ID_RED: + case LED_COLOR_ID_GREEN: + case LED_COLOR_ID_BLUE: + break; + default: + LOG_ERR("%s: invalid channel to color mapping." + " Check the color-mapping DT property", + dev->name); + return -EINVAL; + } + } + + sm = ws2812_led_strip_sm_init(dev); + if (sm < 0) { + return sm; + } + + data->sm = sm; + + return 0; +} + +static int ws2812_rpi_pico_pio_init(const struct device *dev) +{ + const struct ws2812_rpi_pico_pio_config *config = dev->config; + PIO pio; + + if (!device_is_ready(config->piodev)) { + LOG_ERR("%s: PIO device not ready", dev->name); + return -ENODEV; + } + + pio = pio_rpi_pico_get_pio(config->piodev); + + pio_add_program(pio, &config->program); + + return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); +} + +#define CYCLES_PER_BIT(node) \ + (DT_PROP_BY_IDX(node, bit_waveform, 0) + DT_PROP_BY_IDX(node, bit_waveform, 1) + \ + DT_PROP_BY_IDX(node, bit_waveform, 2)) + +#define WS2812_CHILD_INIT(node) \ + static const uint8_t ws2812_led_strip_##node##_color_mapping[] = \ + DT_PROP(node, color_mapping); \ + struct ws2812_led_strip_data ws2812_led_strip_##node##_data; \ + \ + static const struct ws2812_led_strip_config ws2812_led_strip_##node##_config = { \ + .piodev = DEVICE_DT_GET(DT_PARENT(DT_PARENT(node))), \ + .output_pin = DT_PROP(node, output_pin), \ + .num_colors = DT_PROP_LEN(node, color_mapping), \ + .color_mapping = ws2812_led_strip_##node##_color_mapping, \ + .reset_delay = DT_PROP(node, reset_delay), \ + .frequency = DT_PROP(node, frequency), \ + .cycles_per_bit = CYCLES_PER_BIT(DT_PARENT(node)), \ + }; \ + \ + DEVICE_DT_DEFINE(node, &ws2812_led_strip_init, NULL, &ws2812_led_strip_##node##_data, \ + &ws2812_led_strip_##node##_config, POST_KERNEL, \ + CONFIG_LED_STRIP_INIT_PRIORITY, &ws2812_led_strip_api); + +#define SET_DELAY(op, inst, i) \ + (op | (((DT_INST_PROP_BY_IDX(inst, bit_waveform, i) - 1) & 0xF) << 8)) + +/* + * This pio program runs [T0+T1+T2] cycles per 1 loop. + * The first `out` instruction outputs 0 by [T2] times to the sideset pin. + * These zeros are padding. Here is the start of actual data transmission. + * The second `jmp` instruction output 1 by [T0] times to the sideset pin. + * This `jmp` instruction jumps to line 3 if the value of register x is true. + * Otherwise, jump to line 4. + * The third `jmp` instruction outputs 1 by [T1] times to the sideset pin. + * After output, return to the first line. + * The fourth `jmp` instruction outputs 0 by [T1] times. + * After output, return to the first line and output 0 by [T2] times. + * + * In the case of configuration, T0=3, T1=3, T2 =4, + * the final output is 1110000000 in case register x is false. + * It represents code 0, defined in the datasheet. + * And outputs 1111110000 in case of x is true. It represents code 1. + */ +#define WS2812_RPI_PICO_PIO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, WS2812_CHILD_INIT); \ + \ + static const uint16_t rpi_pico_pio_ws2812_instructions_##inst[] = { \ + SET_DELAY(0x6021, inst, 2), /* 0: out x, 1 side 0 [T2 - 1] */ \ + SET_DELAY(0x1023, inst, 0), /* 1: jmp !x, 3 side 1 [T0 - 1] */ \ + SET_DELAY(0x1000, inst, 1), /* 2: jmp 0 side 1 [T1 - 1] */ \ + SET_DELAY(0x0000, inst, 1), /* 3: jmp 0 side 0 [T1 - 1] */ \ + }; \ + \ + static const struct ws2812_rpi_pico_pio_config rpi_pico_pio_ws2812_##inst##_config = { \ + .piodev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .program = \ + { \ + .instructions = rpi_pico_pio_ws2812_instructions_##inst, \ + .length = ARRAY_SIZE(rpi_pico_pio_ws2812_instructions_##inst), \ + .origin = -1, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &ws2812_rpi_pico_pio_init, NULL, NULL, \ + &rpi_pico_pio_ws2812_##inst##_config, POST_KERNEL, \ + CONFIG_LED_STRIP_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(WS2812_RPI_PICO_PIO_INIT) diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index b81a3bb679f..89e5d58e65c 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -8,4 +8,5 @@ zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NRFX_IPC mbox_nrfx_ipc.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_S32_MRU mbox_nxp_s32_mru.c) zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_IMX_MU mbox_nxp_imx_mu.c) +zephyr_library_sources_ifdef(CONFIG_MBOX_NXP_MAILBOX mbox_nxp_mailbox.c) zephyr_library_sources_ifdef(CONFIG_MBOX_ANDES_PLIC_SW mbox_andes_plic_sw.c) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index 0668c9aab8b..67041e91f59 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -1,4 +1,5 @@ # Copyright (c) 2021 Carlo Caione +# Copyright 2024 NXP # SPDX-License-Identifier: Apache-2.0 menuconfig MBOX @@ -14,6 +15,7 @@ if MBOX source "drivers/mbox/Kconfig.nrfx" source "drivers/mbox/Kconfig.nxp_s32" source "drivers/mbox/Kconfig.nxp_imx" +source "drivers/mbox/Kconfig.nxp_mailbox" source "drivers/mbox/Kconfig.andes" config MBOX_INIT_PRIORITY diff --git a/drivers/mbox/Kconfig.nxp_mailbox b/drivers/mbox/Kconfig.nxp_mailbox new file mode 100644 index 00000000000..fa1c2dc79d1 --- /dev/null +++ b/drivers/mbox/Kconfig.nxp_mailbox @@ -0,0 +1,9 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MBOX_NXP_MAILBOX + bool "NXP Mailbox driver for MBOX" + default y + depends on DT_HAS_NXP_LPC_MAILBOX_ENABLED + help + Driver for NXP Mailbox Unit around MBOX. diff --git a/drivers/mbox/mbox_andes_plic_sw.c b/drivers/mbox/mbox_andes_plic_sw.c index bc01da73a30..e2c287ae216 100644 --- a/drivers/mbox/mbox_andes_plic_sw.c +++ b/drivers/mbox/mbox_andes_plic_sw.c @@ -199,11 +199,11 @@ static void andes_plic_sw_irq_handler(const struct device *dev) static int mbox_andes_init(const struct device *dev) { /* Setup IRQ handler for PLIC SW driver */ - IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 1, + IRQ_CONNECT(RISCV_IRQ_MSOFT, 1, andes_plic_sw_irq_handler, DEVICE_DT_INST_GET(0), 0); #ifndef CONFIG_SMP - irq_enable(RISCV_MACHINE_SOFT_IRQ); + irq_enable(RISCV_IRQ_MSOFT); #endif return 0; } diff --git a/drivers/mbox/mbox_nxp_imx_mu.c b/drivers/mbox/mbox_nxp_imx_mu.c index 3c708b95eca..664a88e2065 100644 --- a/drivers/mbox/mbox_nxp_imx_mu.c +++ b/drivers/mbox/mbox_nxp_imx_mu.c @@ -1,4 +1,8 @@ /* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * * Wrapper of the i.MX Message Unit driver into Zephyr's MBOX model. */ @@ -13,20 +17,20 @@ LOG_MODULE_REGISTER(nxp_mbox_imx_mu); #define DT_DRV_COMPAT nxp_mbox_imx_mu -#define MU_MAX_CHANNELS 4 -#define MU_MBOX_SIZE sizeof(uint32_t) +#define MU_MAX_CHANNELS 4 +#define MU_MBOX_SIZE sizeof(uint32_t) struct nxp_imx_mu_data { mbox_callback_t cb[MU_MAX_CHANNELS]; void *user_data[MU_MAX_CHANNELS]; + uint32_t received_data; }; struct nxp_imx_mu_config { MU_Type *base; }; -static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, - const struct mbox_msg *msg) +static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg) { uint32_t __aligned(4) data32; const struct nxp_imx_mu_config *cfg = dev->config; @@ -37,8 +41,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, /* Signalling mode. */ if (msg == NULL) { - return MU_TriggerInterrupts( - cfg->base, kMU_GenInt0InterruptTrigger); + return MU_TriggerInterrupts(cfg->base, kMU_GenInt0InterruptTrigger >> channel); } /* Data transfer mode. */ @@ -54,7 +57,7 @@ static int nxp_imx_mu_send(const struct device *dev, uint32_t channel, } static int nxp_imx_mu_register_callback(const struct device *dev, uint32_t channel, - mbox_callback_t cb, void *user_data) + mbox_callback_t cb, void *user_data) { struct nxp_imx_mu_data *data = dev->data; @@ -80,8 +83,7 @@ static uint32_t nxp_imx_mu_max_channels_get(const struct device *dev) return MU_MAX_CHANNELS; } -static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, - bool enable) +static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, bool enable) { struct nxp_imx_mu_data *data = dev->data; const struct nxp_imx_mu_config *cfg = dev->config; @@ -94,17 +96,17 @@ static int nxp_imx_mu_set_enabled(const struct device *dev, uint32_t channel, if (data->cb[channel] == NULL) { LOG_WRN("Enabling channel without a registered callback"); } - MU_EnableInterrupts(cfg->base, - kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | - kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | - kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | - kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); + MU_EnableInterrupts( + cfg->base, kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | + kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | + kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | + kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); } else { - MU_DisableInterrupts(cfg->base, - kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | - kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | - kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | - kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); + MU_DisableInterrupts( + cfg->base, kMU_GenInt0InterruptEnable | kMU_GenInt1InterruptEnable | + kMU_GenInt2InterruptEnable | kMU_GenInt3InterruptEnable | + kMU_Rx0FullInterruptEnable | kMU_Rx1FullInterruptEnable | + kMU_Rx2FullInterruptEnable | kMU_Rx3FullInterruptEnable); } return 0; @@ -118,62 +120,62 @@ static const struct mbox_driver_api nxp_imx_mu_driver_api = { .set_enabled = nxp_imx_mu_set_enabled, }; -#define MU_INSTANCE_DEFINE(idx) \ - static struct nxp_imx_mu_data nxp_imx_mu_##idx##_data; \ - static struct nxp_imx_mu_config nxp_imx_mu_##idx##_config = { \ - .base = (MU_Type *)DT_INST_REG_ADDR(idx), \ - }; \ - \ - void MU_##idx##_IRQHandler(void); \ - static int nxp_imx_mu_##idx##_init(const struct device *dev) \ - { \ - ARG_UNUSED(dev); \ - MU_Init(nxp_imx_mu_##idx##_config.base); \ - IRQ_CONNECT(DT_INST_IRQN(idx), \ - DT_INST_IRQ(idx, priority), \ - MU_##idx##_IRQHandler, \ - NULL, \ - 0); \ - irq_enable(DT_INST_IRQN(idx)); \ - return 0; \ - } \ - DEVICE_DT_INST_DEFINE(idx, nxp_imx_mu_##idx##_init, NULL, \ - &nxp_imx_mu_##idx##_data, &nxp_imx_mu_##idx##_config, \ - POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ - &nxp_imx_mu_driver_api) - -#define MU_IRQ_HANDLER(idx) \ - static uint32_t mu_##idx##_received_data; \ - void MU_##idx##_IRQHandler(void) \ - { \ - const struct device *dev = DEVICE_DT_INST_GET(idx); \ - const struct nxp_imx_mu_data *data = dev->data; \ - const struct nxp_imx_mu_config *config = dev->config; \ - int channel = 0; \ - struct mbox_msg msg; \ - struct mbox_msg *callback_msg_ptr = NULL; \ - uint32_t flag = MU_GetStatusFlags(config->base); \ - \ - if ((flag & kMU_Rx0FullFlag) == kMU_Rx0FullFlag) { \ - mu_##idx##_received_data = \ - MU_ReceiveMsgNonBlocking(config->base, 0); \ - msg.data = (const void *)&mu_##idx##_received_data; \ - msg.size = MU_MBOX_SIZE; \ - callback_msg_ptr = &msg; \ - } else if ((flag & kMU_GenInt0Flag) == kMU_GenInt0Flag) { \ - MU_ClearStatusFlags(config->base, kMU_GenInt0Flag); \ - callback_msg_ptr = NULL; \ - } \ - \ - if (data->cb[channel]) { \ - data->cb[channel](dev, channel, \ - data->user_data[channel], \ - callback_msg_ptr); \ - } \ +static void handle_irq(const struct device *dev); + +#define MU_INSTANCE_DEFINE(idx) \ + static struct nxp_imx_mu_data nxp_imx_mu_##idx##_data; \ + const static struct nxp_imx_mu_config nxp_imx_mu_##idx##_config = { \ + .base = (MU_Type *)DT_INST_REG_ADDR(idx), \ + }; \ + void MU_##idx##_IRQHandler(void); \ + static int nxp_imx_mu_##idx##_init(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + MU_Init(nxp_imx_mu_##idx##_config.base); \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), MU_##idx##_IRQHandler, \ + NULL, 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(idx, nxp_imx_mu_##idx##_init, NULL, &nxp_imx_mu_##idx##_data, \ + &nxp_imx_mu_##idx##_config, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ + &nxp_imx_mu_driver_api) + +#define MU_IRQ_HANDLER(idx) \ + void MU_##idx##_IRQHandler(void) \ + { \ + const struct device *dev = DEVICE_DT_INST_GET(idx); \ + handle_irq(dev); \ } -#define MU_INST(idx) \ - MU_INSTANCE_DEFINE(idx); \ +#define MU_INST(idx) \ + MU_INSTANCE_DEFINE(idx); \ MU_IRQ_HANDLER(idx); DT_INST_FOREACH_STATUS_OKAY(MU_INST) + +static void handle_irq(const struct device *dev) +{ + struct nxp_imx_mu_data *data = dev->data; + const struct nxp_imx_mu_config *config = dev->config; + const uint32_t flag = MU_GetStatusFlags(config->base); + + for (int i_channel = 0; i_channel < MU_MAX_CHANNELS; i_channel++) { + if ((flag & (kMU_Rx0FullFlag >> i_channel)) == (kMU_Rx0FullFlag >> i_channel)) { + data->received_data = MU_ReceiveMsgNonBlocking(config->base, i_channel); + struct mbox_msg msg = {(const void *)&data->received_data, MU_MBOX_SIZE}; + + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + &msg); + } + } else if ((flag & (kMU_GenInt0Flag >> i_channel)) == + (kMU_GenInt0Flag >> i_channel)) { + MU_ClearStatusFlags(config->base, (kMU_GenInt0Flag >> i_channel)); + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + NULL); + } + } + } +} diff --git a/drivers/mbox/mbox_nxp_mailbox.c b/drivers/mbox/mbox_nxp_mailbox.c new file mode 100644 index 00000000000..7c2818f0ffe --- /dev/null +++ b/drivers/mbox/mbox_nxp_mailbox.c @@ -0,0 +1,210 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + * + * Wrapper of NXP Mailbox driver for Zephyr's MBOX model. + */ + +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_MBOX_LOG_LEVEL +#include +LOG_MODULE_REGISTER(nxp_mbox_mailbox); + +#define DT_DRV_COMPAT nxp_mbox_mailbox + +#define MAILBOX_MAX_CHANNELS 4 +#define MAILBOX_MBOX_SIZE 3 + +#if (defined(LPC55S69_cm33_core0_SERIES) || defined(LPC55S69_cm33_core1_SERIES)) +#ifdef LPC55S69_cm33_core0_SERIES +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core0 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core1 +#else +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM33_Core1 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM33_Core0 +#endif +#else +#if defined(__CM4_CMSIS_VERSION) +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM4 +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM0Plus +#else +#define MAILBOX_ID_THIS_CPU kMAILBOX_CM0Plus +#define MAILBOX_ID_OTHER_CPU kMAILBOX_CM4 +#endif +#endif + +#define GENIRQ_SHIFT (28U) +#define GEN0_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 3U) /*!< General interrupt 3. */ +#define GEN1_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 2U) /*!< General interrupt 2. */ +#define GEN2_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 1U) /*!< General interrupt 1. */ +#define GEN3_IRQ_TRIGGER BIT(GENIRQ_SHIFT + 0U) /*!< General interrupt 0. */ + +#define DATA_MASK BIT_MASK(24U) +#define DATAIRQ_SHIFT (24U) +#define DATA0_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 3U) /*!< Data interrupt 3. */ +#define DATA1_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 2U) /*!< Data interrupt 2. */ +#define DATA2_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 1U) /*!< Data interrupt 1. */ +#define DATA3_IRQ_TRIGGER BIT(DATAIRQ_SHIFT + 0U) /*!< Data interrupt 0. */ + +struct nxp_mailbox_data { + mbox_callback_t cb[MAILBOX_MAX_CHANNELS]; + void *user_data[MAILBOX_MAX_CHANNELS]; + bool channel_enable[MAILBOX_MAX_CHANNELS]; + uint32_t received_data; +}; + +struct nxp_mailbox_config { + MAILBOX_Type *base; +}; + +static void mailbox_isr(const struct device *dev) +{ + struct nxp_mailbox_data *data = dev->data; + const struct nxp_mailbox_config *config = dev->config; + mailbox_cpu_id_t cpu_id; + + cpu_id = MAILBOX_ID_THIS_CPU; + + volatile uint32_t mailbox_value = MAILBOX_GetValue(config->base, cpu_id); + uint32_t flags = mailbox_value & (~DATA_MASK); + + /* Clear or the interrupt gets called intermittently */ + MAILBOX_ClearValueBits(config->base, cpu_id, mailbox_value); + + for (int i_channel = 0; i_channel < MAILBOX_MAX_CHANNELS; i_channel++) { + /* Continue to next channel if channel is not enabled */ + if (!data->channel_enable[i_channel]) { + continue; + } + + if ((flags & (DATA0_IRQ_TRIGGER >> i_channel))) { + data->received_data = mailbox_value & DATA_MASK; + struct mbox_msg msg = {(const void *)&data->received_data, + MAILBOX_MBOX_SIZE}; + + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + &msg); + } + } else if ((flags & (GEN0_IRQ_TRIGGER >> i_channel))) { + if (data->cb[i_channel]) { + data->cb[i_channel](dev, i_channel, data->user_data[i_channel], + NULL); + } + } + } + + /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F + * Store immediate overlapping exception return operation + * might vector to incorrect interrupt + */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + barrier_dsync_fence_full(); +#endif +} + +static int nxp_mailbox_send(const struct device *dev, uint32_t channel, const struct mbox_msg *msg) +{ + uint32_t __aligned(4) data32; + const struct nxp_mailbox_config *cfg = dev->config; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + /* Signalling mode. */ + if (msg == NULL) { + MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU, GEN0_IRQ_TRIGGER >> channel); + return 0; + } + + /* Data transfer mode. */ + if (msg->size != MAILBOX_MBOX_SIZE) { + /* We can only send this many bytes at a time. */ + return -EMSGSIZE; + } + + /* memcpy to avoid issues when msg->data is not word-aligned. */ + memcpy(&data32, msg->data, msg->size); + + MAILBOX_SetValueBits(cfg->base, MAILBOX_ID_OTHER_CPU, + (DATA0_IRQ_TRIGGER >> channel) | (data32 & DATA_MASK)); + + return 0; +} + +static int nxp_mailbox_register_callback(const struct device *dev, uint32_t channel, + mbox_callback_t cb, void *user_data) +{ + struct nxp_mailbox_data *data = dev->data; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + data->cb[channel] = cb; + data->user_data[channel] = user_data; + + return 0; +} + +static int nxp_mailbox_mtu_get(const struct device *dev) +{ + ARG_UNUSED(dev); + + return MAILBOX_MBOX_SIZE; +} + +static uint32_t nxp_mailbox_max_channels_get(const struct device *dev) +{ + ARG_UNUSED(dev); + return MAILBOX_MAX_CHANNELS; +} + +static int nxp_mailbox_set_enabled(const struct device *dev, uint32_t channel, bool enable) +{ + struct nxp_mailbox_data *data = dev->data; + + if (channel >= MAILBOX_MAX_CHANNELS) { + return -EINVAL; + } + + data->channel_enable[channel] = enable; + + return 0; +} + +static const struct mbox_driver_api nxp_mailbox_driver_api = { + .send = nxp_mailbox_send, + .register_callback = nxp_mailbox_register_callback, + .mtu_get = nxp_mailbox_mtu_get, + .max_channels_get = nxp_mailbox_max_channels_get, + .set_enabled = nxp_mailbox_set_enabled, +}; + +#define MAILBOX_INSTANCE_DEFINE(idx) \ + static struct nxp_mailbox_data nxp_mailbox_##idx##_data; \ + const static struct nxp_mailbox_config nxp_mailbox_##idx##_config = { \ + .base = (MAILBOX_Type *)DT_INST_REG_ADDR(idx), \ + }; \ + static int nxp_mailbox_##idx##_init(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + MAILBOX_Init(nxp_mailbox_##idx##_config.base); \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), mailbox_isr, \ + DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + return 0; \ + } \ + DEVICE_DT_INST_DEFINE(idx, nxp_mailbox_##idx##_init, NULL, &nxp_mailbox_##idx##_data, \ + &nxp_mailbox_##idx##_config, POST_KERNEL, CONFIG_MBOX_INIT_PRIORITY, \ + &nxp_mailbox_driver_api) + +#define MAILBOX_INST(idx) MAILBOX_INSTANCE_DEFINE(idx); + +DT_INST_FOREACH_STATUS_OKAY(MAILBOX_INST) diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 4972626cdb5..30c6b9f8306 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -6,5 +6,8 @@ zephyr_library_sources_ifdef(CONFIG_MDIO_SHELL mdio_shell.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ATMEL_SAM mdio_sam.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ESP32 mdio_esp32.c) zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_NETC mdio_nxp_s32_netc.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_S32_GMAC mdio_nxp_s32_gmac.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ADIN2111 mdio_adin2111.c) zephyr_library_sources_ifdef(CONFIG_MDIO_GPIO mdio_gpio.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_NXP_ENET mdio_nxp_enet.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_INFINEON_XMC4XXX mdio_xmc4xxx.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index b3831b2c2d7..2ff20df0b24 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -26,9 +26,12 @@ config MDIO_SHELL # overridden (by defining symbols in multiple locations) source "drivers/mdio/Kconfig.esp32" source "drivers/mdio/Kconfig.sam" -source "drivers/mdio/Kconfig.nxp_s32" +source "drivers/mdio/Kconfig.nxp_s32_netc" +source "drivers/mdio/Kconfig.nxp_s32_gmac" source "drivers/mdio/Kconfig.adin2111" source "drivers/mdio/Kconfig.gpio" +source "drivers/mdio/Kconfig.nxp_enet" +source "drivers/mdio/Kconfig.xmc4xxx" config MDIO_INIT_PRIORITY int "Init priority" diff --git a/drivers/mdio/Kconfig.esp32 b/drivers/mdio/Kconfig.esp32 index bdc8fb1221e..9c4d8f8bae5 100644 --- a/drivers/mdio/Kconfig.esp32 +++ b/drivers/mdio/Kconfig.esp32 @@ -3,7 +3,8 @@ config MDIO_ESP32 bool "ESP32 MDIO driver" - depends on SOC_SERIES_ESP32 default y + depends on SOC_SERIES_ESP32 + depends on DT_HAS_ESPRESSIF_ESP32_MDIO_ENABLED help Enable ESP32 MCU Family MDIO driver. diff --git a/drivers/mdio/Kconfig.nxp_enet b/drivers/mdio/Kconfig.nxp_enet new file mode 100644 index 00000000000..dd3c734e1b3 --- /dev/null +++ b/drivers/mdio/Kconfig.nxp_enet @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_NXP_ENET + bool "NXP ENET MDIO Driver" + default y + depends on DT_HAS_NXP_ENET_MDIO_ENABLED + help + Enable NXP ENET MDIO Driver. This Kconfig can be disabled manually + if all ethernet PHYs being used with ENET are not managed by MDIO bus. + +if MDIO_NXP_ENET + +config MDIO_NXP_ENET_TIMEOUT + int "NXP ENET MDIO Timeout time" + default 1 + help + Time in milliseconds before an MDIO transaction that has not + finished is considered to have timed out. + +endif # MDIO_NXP_ENET diff --git a/drivers/mdio/Kconfig.nxp_s32_gmac b/drivers/mdio/Kconfig.nxp_s32_gmac new file mode 100644 index 00000000000..01927b6a642 --- /dev/null +++ b/drivers/mdio/Kconfig.nxp_s32_gmac @@ -0,0 +1,21 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MDIO_NXP_S32_GMAC + bool "NXP S32 GMAC MDIO driver" + default y + depends on DT_HAS_NXP_S32_GMAC_MDIO_ENABLED + select CLOCK_CONTROL + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + help + Enable GMAC MDIO driver for NXP S32 SoCs. + +if MDIO_NXP_S32_GMAC + +config MDIO_NXP_S32_TIMEOUT + int "Timeout for read/write operations in milliseconds" + default 2 + help + Timeout (in milliseconds) for read/write operations over MDIO. + +endif # MDIO_NXP_S32_GMAC diff --git a/drivers/mdio/Kconfig.nxp_s32 b/drivers/mdio/Kconfig.nxp_s32_netc similarity index 100% rename from drivers/mdio/Kconfig.nxp_s32 rename to drivers/mdio/Kconfig.nxp_s32_netc diff --git a/drivers/mdio/Kconfig.xmc4xxx b/drivers/mdio/Kconfig.xmc4xxx new file mode 100644 index 00000000000..75793fa1508 --- /dev/null +++ b/drivers/mdio/Kconfig.xmc4xxx @@ -0,0 +1,9 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_INFINEON_XMC4XXX + bool "Infineon XMC4XXX MDIO driver" + default y + depends on DT_HAS_INFINEON_XMC4XXX_MDIO_ENABLED + help + Enable Infineon XMC4XXX MDIO driver. diff --git a/drivers/mdio/mdio_nxp_enet.c b/drivers/mdio/mdio_nxp_enet.c new file mode 100644 index 00000000000..6b5c128e075 --- /dev/null +++ b/drivers/mdio/mdio_nxp_enet.c @@ -0,0 +1,299 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_mdio + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nxp_enet_mdio_config { + ENET_Type *base; + const struct pinctrl_dev_config *pincfg; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + uint32_t mdc_freq; + uint16_t timeout; + bool disable_preamble; +}; + +struct nxp_enet_mdio_data { + struct k_mutex mdio_mutex; + struct k_sem mdio_sem; + bool interrupt_up; +}; + +/* + * This function is used for both read and write operations + * in order to wait for the completion of an MDIO transaction. + * It returns -ETIMEDOUT if timeout occurs as specified in DT, + * otherwise returns 0 if EIR MII bit is set indicting completed + * operation, otherwise -EIO. + */ +static int nxp_enet_mdio_wait_xfer(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + ENET_Type *base = config->base; + int ret = 0; + + /* This function will not make sense from IRQ context */ + if (k_is_in_isr()) { + return -EWOULDBLOCK; + } + + /* Enable the interrupt */ + base->EIMR |= ENET_EIMR_MII_MASK; + + /* Wait for operation to complete or time out */ + if (!data->interrupt_up) { + /* In the case where the interrupt has not been enabled yet because + * ethernet driver has not initiaized, just do a busy wait + */ + k_busy_wait(USEC_PER_MSEC * config->timeout); + if (base->EIR & ENET_EIR_MII_MASK) { + ret = 0; + } else { + ret = -ETIMEDOUT; + } + } else if (k_sem_take(&data->mdio_sem, K_MSEC(config->timeout))) { + /* Interrupt was enabled but did not occur in time */ + ret = -ETIMEDOUT; + } else if (base->EIR & ENET_EIR_MII_MASK) { + /* Interrupt happened meaning mdio transaction completed */ + ret = 0; + } else { + /* No idea what happened */ + ret = -EIO; + } + + return ret; +} + +/* MDIO Read API implementation */ +static int nxp_enet_mdio_read(const struct device *dev, + uint8_t prtad, uint8_t regad, uint16_t *read_data) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret; + + /* Only one MDIO bus operation attempt at a time */ + (void)k_mutex_lock(&data->mdio_mutex, K_FOREVER); + + /* + * Clear the bit (W1C) that indicates MDIO transfer is ready to + * prepare to wait for it to be set once this read is done + */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* + * Write MDIO frame to MII management register which will + * send the read command and data out to the MDIO bus as this frame: + * ST = start, 1 means start + * OP = operation, 2 means read + * PA = PHY/Port address + * RA = Register/Device Address + * TA = Turnaround, must be 2 to be valid + * data = data to be written to the PHY register + */ + config->base->MMFR = ENET_MMFR_ST(0x1U) | + ENET_MMFR_OP(MDIO_OP_C22_READ) | + ENET_MMFR_PA(prtad) | + ENET_MMFR_RA(regad) | + ENET_MMFR_TA(0x2U); + + ret = nxp_enet_mdio_wait_xfer(dev); + if (ret) { + (void)k_mutex_unlock(&data->mdio_mutex); + return ret; + } + + /* The data is received in the same register that we wrote the command to */ + *read_data = (config->base->MMFR & ENET_MMFR_DATA_MASK) >> ENET_MMFR_DATA_SHIFT; + + /* Clear the same bit as before because the event has been handled */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* This MDIO interaction is finished */ + (void)k_mutex_unlock(&data->mdio_mutex); + + return ret; +} + +/* MDIO Write API implementation */ +static int nxp_enet_mdio_write(const struct device *dev, + uint8_t prtad, uint8_t regad, uint16_t write_data) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret; + + /* Only one MDIO bus operation attempt at a time */ + (void)k_mutex_lock(&data->mdio_mutex, K_FOREVER); + + /* + * Clear the bit (W1C) that indicates MDIO transfer is ready to + * prepare to wait for it to be set once this write is done + */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* + * Write MDIO frame to MII management register which will + * send the write command and data out to the MDIO bus as this frame: + * ST = start, 1 means start + * OP = operation, 1 means write + * PA = PHY/Port address + * RA = Register/Device Address + * TA = Turnaround, must be 2 to be valid + * data = data to be written to the PHY register + */ + config->base->MMFR = ENET_MMFR_ST(0x1U) | + ENET_MMFR_OP(MDIO_OP_C22_WRITE) | + ENET_MMFR_PA(prtad) | + ENET_MMFR_RA(regad) | + ENET_MMFR_TA(0x2U) | + write_data; + + ret = nxp_enet_mdio_wait_xfer(dev); + if (ret) { + (void)k_mutex_unlock(&data->mdio_mutex); + return ret; + } + + /* Clear the same bit as before because the event has been handled */ + config->base->EIR |= ENET_EIR_MII_MASK; + + /* This MDIO interaction is finished */ + (void)k_mutex_unlock(&data->mdio_mutex); + + return ret; +} + +/* MDIO bus enable/disable "implementation" */ +static void nxp_enet_mdio_bus_fn(const struct device *dev) +{ + /* + * MDIO bus device is actually part of ethernet device, and + * does not support ability to disable/enable MDIO bus hardware + * independently of the ethernet/MAC hardware, so do nothing. + */ +} + +static const struct mdio_driver_api nxp_enet_mdio_api = { + .read = nxp_enet_mdio_read, + .write = nxp_enet_mdio_write, + .bus_enable = nxp_enet_mdio_bus_fn, + .bus_disable = nxp_enet_mdio_bus_fn, +}; + +static void nxp_enet_mdio_isr_cb(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + + /* Signal that operation finished */ + k_sem_give(&data->mdio_sem); + + /* Disable the interrupt */ + config->base->EIMR &= ~ENET_EIMR_MII_MASK; +} + +static void nxp_enet_mdio_post_module_reset_init(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + uint32_t enet_module_clock_rate; + + /* Set up MSCR register */ + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_module_clock_rate); + uint32_t mii_speed = (enet_module_clock_rate + 2 * config->mdc_freq - 1) / + (2 * config->mdc_freq) - 1; + uint32_t holdtime = (10 + NSEC_PER_SEC / enet_module_clock_rate - 1) / + (NSEC_PER_SEC / enet_module_clock_rate) - 1; + uint32_t mscr = ENET_MSCR_MII_SPEED(mii_speed) | ENET_MSCR_HOLDTIME(holdtime) | + (config->disable_preamble ? ENET_MSCR_DIS_PRE_MASK : 0); + config->base->MSCR = mscr; +} + +void nxp_enet_mdio_callback(const struct device *dev, + enum nxp_enet_callback_reason event, void *cb_data) +{ + struct nxp_enet_mdio_data *data = dev->data; + + ARG_UNUSED(cb_data); + + switch (event) { + case NXP_ENET_MODULE_RESET: + nxp_enet_mdio_post_module_reset_init(dev); + break; + case NXP_ENET_INTERRUPT: + nxp_enet_mdio_isr_cb(dev); + break; + case NXP_ENET_INTERRUPT_ENABLED: + data->interrupt_up = true; + break; + default: + break; + } +} + +static int nxp_enet_mdio_init(const struct device *dev) +{ + const struct nxp_enet_mdio_config *config = dev->config; + struct nxp_enet_mdio_data *data = dev->data; + int ret = 0; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + ret = k_mutex_init(&data->mdio_mutex); + if (ret) { + return ret; + } + + ret = k_sem_init(&data->mdio_sem, 0, 1); + if (ret) { + return ret; + } + + /* All operations done after module reset should be done during device init too */ + nxp_enet_mdio_post_module_reset_init(dev); + + return ret; +} + +#define NXP_ENET_MDIO_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static const struct nxp_enet_mdio_config nxp_enet_mdio_cfg_##inst = { \ + .base = (ENET_Type *) DT_REG_ADDR(DT_INST_PARENT(inst)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .timeout = CONFIG_MDIO_NXP_ENET_TIMEOUT, \ + .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(inst))), \ + .clock_subsys = (void *) DT_CLOCKS_CELL_BY_IDX( \ + DT_INST_PARENT(inst), 0, name), \ + .disable_preamble = DT_INST_PROP(inst, suppress_preamble), \ + .mdc_freq = DT_INST_PROP(inst, clock_frequency), \ + }; \ + \ + static struct nxp_enet_mdio_data nxp_enet_mdio_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &nxp_enet_mdio_init, NULL, \ + &nxp_enet_mdio_data_##inst, &nxp_enet_mdio_cfg_##inst, \ + POST_KERNEL, CONFIG_MDIO_INIT_PRIORITY, \ + &nxp_enet_mdio_api); + + +DT_INST_FOREACH_STATUS_OKAY(NXP_ENET_MDIO_INIT) diff --git a/drivers/mdio/mdio_nxp_s32_gmac.c b/drivers/mdio/mdio_nxp_s32_gmac.c new file mode 100644 index 00000000000..afd7c8ccedb --- /dev/null +++ b/drivers/mdio/mdio_nxp_s32_gmac.c @@ -0,0 +1,185 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_s32_gmac_mdio + +#include +LOG_MODULE_REGISTER(nxp_s32_mdio, CONFIG_MDIO_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include + +#define GMAC_MDIO_REG_OFFSET (0x200) + +#define GMAC_STATUS_TO_ERRNO(x) \ + ((x) == GMAC_STATUS_SUCCESS ? 0 : ((x) == GMAC_STATUS_TIMEOUT ? -ETIMEDOUT : -EIO)) + +struct mdio_nxp_s32_config { + uint8_t instance; + bool suppress_preamble; + const struct pinctrl_dev_config *pincfg; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; +}; + +struct mdio_nxp_s32_data { + struct k_mutex bus_mutex; + uint32_t clock_freq; +}; + +static int mdio_nxp_s32_read_c45(const struct device *dev, uint8_t prtad, uint8_t devad, + uint16_t regad, uint16_t *regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOReadMMD(cfg->instance, prtad, devad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_write_c45(const struct device *dev, uint8_t prtad, uint8_t devad, + uint16_t regad, uint16_t regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOWriteMMD(cfg->instance, prtad, devad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_read_c22(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t *regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIORead(cfg->instance, prtad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_write_c22(const struct device *dev, uint8_t prtad, + uint8_t regad, uint16_t regval) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + Gmac_Ip_StatusType status; + + k_mutex_lock(&data->bus_mutex, K_FOREVER); + + /* Configure MDIO controller before initiating a transmission */ + Gmac_Ip_EnableMDIO(cfg->instance, cfg->suppress_preamble, data->clock_freq); + + status = Gmac_Ip_MDIOWrite(cfg->instance, prtad, regad, regval, + CONFIG_MDIO_NXP_S32_TIMEOUT); + + k_mutex_unlock(&data->bus_mutex); + + return GMAC_STATUS_TO_ERRNO(status); +} + +static int mdio_nxp_s32_init(const struct device *dev) +{ + const struct mdio_nxp_s32_config *const cfg = dev->config; + struct mdio_nxp_s32_data *data = dev->data; + int err; + + if (!device_is_ready(cfg->clock_dev)) { + LOG_ERR("Clock control device not ready"); + return -ENODEV; + } + + if (clock_control_get_rate(cfg->clock_dev, cfg->clock_subsys, &data->clock_freq)) { + LOG_ERR("Failed to get clock frequency"); + return -EIO; + } + + err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); + if (err != 0) { + return err; + } + + k_mutex_init(&data->bus_mutex); + + return 0; +} + +static void mdio_nxp_s32_noop(const struct device *dev) +{ + ARG_UNUSED(dev); + /* Controller does not support enabling/disabling MDIO bus */ +} + +static const struct mdio_driver_api mdio_nxp_s32_driver_api = { + .read = mdio_nxp_s32_read_c22, + .write = mdio_nxp_s32_write_c22, + .read_c45 = mdio_nxp_s32_read_c45, + .write_c45 = mdio_nxp_s32_write_c45, + .bus_enable = mdio_nxp_s32_noop, + .bus_disable = mdio_nxp_s32_noop, +}; + +#define MDIO_NXP_S32_HW_INSTANCE_CHECK(i, n) \ + (((DT_INST_REG_ADDR(n) - GMAC_MDIO_REG_OFFSET) == IP_GMAC_##i##_BASE) ? i : 0) + +#define MDIO_NXP_S32_HW_INSTANCE(n) \ + LISTIFY(__DEBRACKET FEATURE_GMAC_NUM_INSTANCES, \ + MDIO_NXP_S32_HW_INSTANCE_CHECK, (|), n) + +#define MDIO_NXP_S32_DEVICE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct mdio_nxp_s32_data mdio_nxp_s32_data_##n; \ + static const struct mdio_nxp_s32_config mdio_nxp_s32_config_##n = { \ + .instance = MDIO_NXP_S32_HW_INSTANCE(n), \ + .suppress_preamble = (bool)DT_INST_PROP(n, suppress_preamble), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + &mdio_nxp_s32_init, \ + NULL, \ + &mdio_nxp_s32_data_##n, \ + &mdio_nxp_s32_config_##n, \ + POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, \ + &mdio_nxp_s32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MDIO_NXP_S32_DEVICE) diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index b70ff7bc1a0..376e95244fa 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -21,12 +21,18 @@ LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); #define DT_DRV_COMPAT espressif_esp32_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_netc_emdio) #define DT_DRV_COMPAT nxp_s32_netc_emdio +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_gmac_mdio) +#define DT_DRV_COMPAT nxp_s32_gmac_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(adi_adin2111_mdio) #define DT_DRV_COMPAT adi_adin2111_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(smsc_lan91c111_mdio) #define DT_DRV_COMPAT smsc_lan91c111_mdio #elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_mdio_gpio) #define DT_DRV_COMPAT zephyr_mdio_gpio +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_enet_mdio) +#define DT_DRV_COMPAT nxp_enet_mdio +#elif DT_HAS_COMPAT_STATUS_OKAY(infineon_xmc4xxx_mdio) +#define DT_DRV_COMPAT infineon_xmc4xxx_mdio #else #error "No known devicetree compatible match for MDIO shell" #endif diff --git a/drivers/mdio/mdio_xmc4xxx.c b/drivers/mdio/mdio_xmc4xxx.c new file mode 100644 index 00000000000..02ebfc5096d --- /dev/null +++ b/drivers/mdio/mdio_xmc4xxx.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2023 SLB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_xmc4xxx_mdio + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +LOG_MODULE_REGISTER(mdio_xmc4xxx, CONFIG_MDIO_LOG_LEVEL); + +#define MDIO_TRANSFER_TIMEOUT_US 250000 + +#define MAX_MDC_FREQUENCY 2500000u /* 400ns period */ +#define MIN_MDC_FREQUENCY 1000000u /* 1us period */ + +struct mdio_xmc4xxx_clock_divider { + uint8_t divider; + uint8_t reg_val; +}; + +static const struct mdio_xmc4xxx_clock_divider mdio_clock_divider[] = { + {.divider = 8, .reg_val = 2}, {.divider = 13, .reg_val = 3}, + {.divider = 21, .reg_val = 0}, {.divider = 31, .reg_val = 1}, + {.divider = 51, .reg_val = 4}, {.divider = 62, .reg_val = 5}, +}; + +struct mdio_xmc4xxx_dev_data { + struct k_mutex mutex; + uint32_t reg_value_gmii_address; +}; + +struct mdio_xmc4xxx_dev_config { + ETH_GLOBAL_TypeDef *const regs; + const struct pinctrl_dev_config *pcfg; + uint8_t mdi_port_ctrl; +}; + +static int mdio_xmc4xxx_transfer(const struct device *dev, uint8_t phy_addr, uint8_t reg_addr, + uint8_t is_write, uint16_t data_write, uint16_t *data_read) +{ + const struct mdio_xmc4xxx_dev_config *const dev_cfg = dev->config; + ETH_GLOBAL_TypeDef *const regs = dev_cfg->regs; + struct mdio_xmc4xxx_dev_data *const dev_data = dev->data; + uint32_t reg; + int ret = 0; + + k_mutex_lock(&dev_data->mutex, K_FOREVER); + + if ((regs->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) != 0) { + ret = -EBUSY; + goto finish; + } + + reg = dev_data->reg_value_gmii_address; + if (is_write) { + reg |= ETH_GMII_ADDRESS_MW_Msk; + regs->GMII_DATA = data_write; + } + + regs->GMII_ADDRESS = reg | ETH_GMII_ADDRESS_MB_Msk | + FIELD_PREP(ETH_GMII_ADDRESS_PA_Msk, phy_addr) | + FIELD_PREP(ETH_GMII_ADDRESS_MR_Msk, reg_addr); + + if (!WAIT_FOR((regs->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) == 0, + MDIO_TRANSFER_TIMEOUT_US, k_msleep(5))) { + LOG_WRN("mdio transfer timedout"); + ret = -ETIMEDOUT; + goto finish; + } + + if (!is_write && data_read != NULL) { + *data_read = regs->GMII_DATA; + } + +finish: + k_mutex_unlock(&dev_data->mutex); + + return ret; +} + +static int mdio_xmc4xxx_read(const struct device *dev, uint8_t phy_addr, uint8_t reg_addr, + uint16_t *data) +{ + return mdio_xmc4xxx_transfer(dev, phy_addr, reg_addr, 0, 0, data); +} + +static int mdio_xmc4xxx_write(const struct device *dev, uint8_t phy_addr, + uint8_t reg_addr, uint16_t data) +{ + return mdio_xmc4xxx_transfer(dev, phy_addr, reg_addr, 1, data, NULL); +} + +static void mdio_xmc4xxx_bus_enable(const struct device *dev) +{ + ARG_UNUSED(dev); + /* this will enable the clock for ETH, which generates to MDIO clk */ + XMC_ETH_MAC_Enable(NULL); +} + +static void mdio_xmc4xxx_bus_disable(const struct device *dev) +{ + ARG_UNUSED(dev); + XMC_ETH_MAC_Disable(NULL); +} + +static int mdio_xmc4xxx_set_clock_divider(const struct device *dev) +{ + struct mdio_xmc4xxx_dev_data *dev_data = dev->data; + uint32_t eth_mac_clk = XMC_SCU_CLOCK_GetEthernetClockFrequency(); + + for (int i = 0; i < ARRAY_SIZE(mdio_clock_divider); i++) { + uint8_t divider = mdio_clock_divider[i].divider; + uint8_t reg_val = mdio_clock_divider[i].reg_val; + uint32_t mdc_clk = eth_mac_clk / divider; + + if (mdc_clk > MIN_MDC_FREQUENCY && mdc_clk < MAX_MDC_FREQUENCY) { + LOG_DBG("Using MDC clock divider %d", divider); + LOG_DBG("MDC clock %dHz", mdc_clk); + dev_data->reg_value_gmii_address = + FIELD_PREP(ETH_GMII_ADDRESS_CR_Msk, reg_val); + return 0; + } + } + + return -EINVAL; +} + +static int mdio_xmc4xxx_initialize(const struct device *dev) +{ + const struct mdio_xmc4xxx_dev_config *dev_cfg = dev->config; + struct mdio_xmc4xxx_dev_data *dev_data = dev->data; + XMC_ETH_MAC_PORT_CTRL_t port_ctrl = {0}; + int ret; + + k_mutex_init(&dev_data->mutex); + + ret = pinctrl_apply_state(dev_cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret != 0) { + return ret; + } + + ret = mdio_xmc4xxx_set_clock_divider(dev); + if (ret != 0) { + LOG_ERR("Error setting MDIO clock divider"); + return -EINVAL; + } + + port_ctrl.mdio = dev_cfg->mdi_port_ctrl; + ETH0_CON->CON = port_ctrl.raw; + + return ret; +} + +static const struct mdio_driver_api mdio_xmc4xxx_driver_api = { + .read = mdio_xmc4xxx_read, + .write = mdio_xmc4xxx_write, + .bus_enable = mdio_xmc4xxx_bus_enable, + .bus_disable = mdio_xmc4xxx_bus_disable, +}; + +PINCTRL_DT_INST_DEFINE(0); +static const struct mdio_xmc4xxx_dev_config mdio_xmc4xxx_dev_config_0 = { + .regs = (ETH_GLOBAL_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(0)), + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), + .mdi_port_ctrl = DT_INST_ENUM_IDX(0, mdi_port_ctrl), +}; + +static struct mdio_xmc4xxx_dev_data mdio_xmc4xxx_dev_data_0; + +DEVICE_DT_INST_DEFINE(0, &mdio_xmc4xxx_initialize, NULL, &mdio_xmc4xxx_dev_data_0, + &mdio_xmc4xxx_dev_config_0, POST_KERNEL, + CONFIG_MDIO_INIT_PRIORITY, &mdio_xmc4xxx_driver_api); diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index 84ab86a793a..e0c8f6faf96 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,8 @@ struct memc_flexspi_data { struct port_lut port_luts[kFLEXSPI_PortCount]; struct memc_flexspi_buf_cfg *buf_cfg; uint8_t buf_cfg_cnt; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; }; void memc_flexspi_wait_bus_idle(const struct device *dev) @@ -79,30 +82,56 @@ bool memc_flexspi_is_running_xip(const struct device *dev) int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock) + flexspi_port_t port, uint32_t freq_hz) { -#if CONFIG_SOC_SERIES_IMX_RT10XX struct memc_flexspi_data *data = dev->data; + uint32_t rate; + uint32_t key; + int ret; + /* To reclock the FlexSPI, we should: + * - disable the module + * - set the new clock + * - reenable the module + * - reset the module + * We CANNOT XIP at any point during this process + */ + key = irq_lock(); memc_flexspi_wait_bus_idle(dev); - FLEXSPI_Enable(data->base, false); + ret = clock_control_set_rate(data->clock_dev, data->clock_subsys, + (clock_control_subsys_rate_t)freq_hz); + if (ret < 0) { + irq_unlock(key); + return ret; + } - flexspi_clock_set_div(clock == MEMC_FLEXSPI_CLOCK_166M ? 0 : 3); + /* + * We need to update the DLL value before we call clock_control_get_rate, + * because this will cause XIP (flash reads) to occur. Although the + * true flash clock is not known, assume the set_rate function programmed + * a value close to what we requested. + */ + device_config->flexspiRootClk = freq_hz; + FLEXSPI_UpdateDllValue(data->base, device_config, port); + memc_flexspi_reset(dev); - FLEXSPI_Enable(data->base, true); + memc_flexspi_wait_bus_idle(dev); + ret = clock_control_get_rate(data->clock_dev, data->clock_subsys, &rate); + if (ret < 0) { + irq_unlock(key); + return ret; + } - memc_flexspi_reset(dev); - device_config->flexspiRootClk = flexspi_clock_get_freq(); + device_config->flexspiRootClk = rate; FLEXSPI_UpdateDllValue(data->base, device_config, port); memc_flexspi_reset(dev); + irq_unlock(key); + return 0; -#else - return -ENOTSUP; -#endif } int memc_flexspi_set_device_config(const struct device *dev, @@ -332,6 +361,9 @@ static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_actio .buf_cfg_cnt = sizeof(buf_cfg_##n) / \ sizeof(struct memc_flexspi_buf_cfg), \ .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (clock_control_subsys_t) \ + DT_INST_CLOCKS_CELL(n, name), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(n, memc_flexspi_pm_action); \ diff --git a/drivers/memc/memc_mcux_flexspi.h b/drivers/memc/memc_mcux_flexspi.h index a8495fc9289..707d9f088cc 100644 --- a/drivers/memc/memc_mcux_flexspi.h +++ b/drivers/memc/memc_mcux_flexspi.h @@ -8,15 +8,10 @@ #include #include -enum memc_flexspi_clock_t { - /* Flexspi clock 332M, DDR mode, internal clock 166M. */ - MEMC_FLEXSPI_CLOCK_166M, - /* Flexspi clock 83M, DDR mode, internal clock 42M. */ - MEMC_FLEXSPI_CLOCK_42M, -}; - /* Size of a command in the LUT table */ #define MEMC_FLEXSPI_CMD_SIZE 4U +/* Number of commands in an instruction sequence */ +#define MEMC_FLEXSPI_CMD_PER_SEQ 4U /** * @brief Wait for the FlexSPI bus to be idle @@ -43,17 +38,17 @@ bool memc_flexspi_is_running_xip(const struct device *dev); /** * @brief Update clock selection of the FlexSPI device * - * Updates clock selection of the FlexSPI device to a new clock speed. + * Updates clock frequency of FlexSPI to new clock speed. * * @param dev: FlexSPI device * @param device_config: External device configuration. * @param port: FlexSPI port to use for this external device - * @param clock: new clock selection to apply + * @param freq_hz: new clock frequency to apply * @return 0 on success, negative value on failure */ int memc_flexspi_update_clock(const struct device *dev, flexspi_device_config_t *device_config, - flexspi_port_t port, enum memc_flexspi_clock_t clock); + flexspi_port_t port, uint32_t freq_hz); /** * @brief configure new FlexSPI device diff --git a/drivers/memc/memc_stm32.c b/drivers/memc/memc_stm32.c index 27786c16123..1609926b888 100644 --- a/drivers/memc/memc_stm32.c +++ b/drivers/memc/memc_stm32.c @@ -21,9 +21,18 @@ LOG_MODULE_REGISTER(memc_stm32, CONFIG_MEMC_LOG_LEVEL); #error "No compatible FMC devicetree node found" #endif +/* This symbol takes the value 1 if one of the device instances */ +/* is configured in dts with a domain clock */ +#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT +#define STM32_FMC_DOMAIN_CLOCK_SUPPORT 1 +#else +#define STM32_FMC_DOMAIN_CLOCK_SUPPORT 0 +#endif + struct memc_stm32_config { uint32_t fmc; - struct stm32_pclken pclken; + const struct stm32_pclken *pclken; + size_t pclk_len; const struct pinctrl_dev_config *pcfg; }; @@ -49,12 +58,21 @@ static int memc_stm32_init(const struct device *dev) return -ENODEV; } - r = clock_control_on(clk, (clock_control_subsys_t)&config->pclken); + r = clock_control_on(clk, (clock_control_subsys_t)&config->pclken[0]); if (r < 0) { LOG_ERR("Could not initialize FMC clock (%d)", r); return r; } + if (IS_ENABLED(STM32_FMC_DOMAIN_CLOCK_SUPPORT) && (config->pclk_len > 1)) { + /* Enable FMC clock source */ + r = clock_control_configure(clk, (clock_control_subsys_t)&config->pclken[1], NULL); + if (r < 0) { + LOG_ERR("Could not select FMC clock (%d)", r); + return r; + } + } + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_fmc) #if (DT_ENUM_IDX(DT_DRV_INST(0), st_mem_swap) == 1) /* sdram-sram */ @@ -70,10 +88,12 @@ static int memc_stm32_init(const struct device *dev) PINCTRL_DT_INST_DEFINE(0); +static const struct stm32_pclken pclken[] = STM32_DT_INST_CLOCKS(0); + static const struct memc_stm32_config config = { .fmc = DT_INST_REG_ADDR(0), - .pclken = { .bus = DT_INST_CLOCKS_CELL(0, bus), - .enr = DT_INST_CLOCKS_CELL(0, bits) }, + .pclken = pclken, + .pclk_len = DT_INST_NUM_CLOCKS(0), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; diff --git a/drivers/mfd/mfd_ad5592.c b/drivers/mfd/mfd_ad5592.c index d8f8f60de39..2c320fa549e 100644 --- a/drivers/mfd/mfd_ad5592.c +++ b/drivers/mfd/mfd_ad5592.c @@ -15,8 +15,9 @@ #define AD5592_GPIO_READBACK_EN BIT(10) #define AD5592_LDAC_READBACK_EN BIT(6) #define AD5592_REG_SOFTWARE_RESET 0x0FU -#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0xDAC -#define AD5592_REV_VAL_MASK 0x3FF +#define AD5592_SOFTWARE_RESET_MAGIC_VAL 0x5AC +#define AD5592_REG_VAL_MASK 0x3FF +#define AD5592_REG_RESET_VAL_MASK 0x7FF #define AD5592_REG_SHIFT_VAL 11 #define AD5592_REG_READBACK_SHIFT_VAL 2 @@ -115,7 +116,19 @@ int mfd_ad5592_read_reg(const struct device *dev, uint8_t reg, uint8_t reg_data, int mfd_ad5592_write_reg(const struct device *dev, uint8_t reg, uint16_t val) { - uint16_t msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & AD5592_REV_VAL_MASK)); + uint16_t write_mask; + uint16_t msg; + + switch (reg) { + case AD5592_REG_SOFTWARE_RESET: + write_mask = AD5592_REG_RESET_VAL_MASK; + break; + default: + write_mask = AD5592_REG_VAL_MASK; + break; + } + + msg = sys_cpu_to_be16((reg << AD5592_REG_SHIFT_VAL) | (val & write_mask)); return mfd_ad5592_write_raw(dev, msg); } diff --git a/drivers/mipi_dbi/CMakeLists.txt b/drivers/mipi_dbi/CMakeLists.txt new file mode 100644 index 00000000000..5f00319bc82 --- /dev/null +++ b/drivers/mipi_dbi/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_MIPI_DBI_SPI mipi_dbi_spi.c) diff --git a/drivers/mipi_dbi/Kconfig b/drivers/mipi_dbi/Kconfig new file mode 100644 index 00000000000..f8305d29833 --- /dev/null +++ b/drivers/mipi_dbi/Kconfig @@ -0,0 +1,26 @@ +# MIPI DBI controller options + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +menuconfig MIPI_DBI + bool "MIPI-DBI Host Controller drivers [EXPERIMENTAL]" + select EXPERIMENTAL + help + Add support for MIPI-DBI compliant host controllers + +if MIPI_DBI + +module = MIPI_DBI +module-str = mipi_dbi +source "subsys/logging/Kconfig.template.log_config" + +config MIPI_DBI_INIT_PRIORITY + int "Initialization priority" + default 80 + help + MIPI-DBI Host Controllers initialization priority. + +source "drivers/mipi_dbi/Kconfig.spi" + +endif diff --git a/drivers/mipi_dbi/Kconfig.spi b/drivers/mipi_dbi/Kconfig.spi new file mode 100644 index 00000000000..090646e1c3f --- /dev/null +++ b/drivers/mipi_dbi/Kconfig.spi @@ -0,0 +1,23 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config MIPI_DBI_SPI + bool "MIPI DBI SPI driver" + default y + depends on DT_HAS_ZEPHYR_MIPI_DBI_SPI_ENABLED + select SPI + help + Enable support for MIPI DBI SPI driver. This driver implements + a MIPI-DBI mode C compatible controller using a SPI device, as well + as GPIO outputs for the reset and D/C signals + +if MIPI_DBI_SPI + +config MIPI_DBI_SPI_3WIRE + bool "Emulated 3 wire SPI support" + help + Support 3 wire MIPI DBI (Mode C option 2) in MIPI DBI SPI + driver. This requires manually packing each byte with a data/command + bit, and may slow down display data transmission. + +endif # MIPI_DBI_SPI diff --git a/drivers/mipi_dbi/mipi_dbi_spi.c b/drivers/mipi_dbi/mipi_dbi_spi.c new file mode 100644 index 00000000000..bf1c1388e19 --- /dev/null +++ b/drivers/mipi_dbi/mipi_dbi_spi.c @@ -0,0 +1,323 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_mipi_dbi_spi + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(mipi_dbi_spi, CONFIG_MIPI_DBI_LOG_LEVEL); + +struct mipi_dbi_spi_config { + /* SPI hardware used to send data */ + const struct device *spi_dev; + /* Command/Data gpio */ + const struct gpio_dt_spec cmd_data; + /* Reset GPIO */ + const struct gpio_dt_spec reset; +}; + +struct mipi_dbi_spi_data { + /* Used for 3 wire mode */ + uint16_t spi_byte; + struct k_spinlock lock; +}; + +/* Expands to 1 if the node does not have the `write-only` property */ +#define _WRITE_ONLY_ABSENT(n) (!DT_INST_PROP(n, write_only)) | + +/* This macro will evaluate to 1 if any of the nodes with zephyr,mipi-dbi-spi + * lack a `write-only` property. The intention here is to allow the entire + * command_read function to be optimized out when it is not needed. + */ +#define MIPI_DBI_SPI_READ_REQUIRED DT_INST_FOREACH_STATUS_OKAY(_WRITE_ONLY_ABSENT) 0 +uint32_t var = MIPI_DBI_SPI_READ_REQUIRED; + +/* In Type C mode 1 MIPI BIT communication, the 9th bit of the word + * (first bit sent in each word) indicates if the word is a command or + * data. Typically 0 indicates a command and 1 indicates data, but some + * displays may vary. + */ +#define MIPI_DBI_DC_BIT BIT(9) + +static int mipi_dbi_spi_write_helper(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + bool cmd_present, uint8_t cmd, + const uint8_t *data_buf, size_t len) +{ + const struct mipi_dbi_spi_config *config = dev->config; + struct mipi_dbi_spi_data *data = dev->data; + struct spi_buf buffer; + struct spi_buf_set buf_set = { + .buffers = &buffer, + .count = 1, + }; + int ret = 0; + k_spinlock_key_t spinlock_key = k_spin_lock(&data->lock); + + if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE && + IS_ENABLED(CONFIG_MIPI_DBI_SPI_3WIRE)) { + struct spi_config tmp_cfg; + /* We have to emulate 3 wire mode by packing the data/command + * bit into the upper bit of the SPI transfer. + * switch SPI to 9 bit mode, and write the transfer + */ + memcpy(&tmp_cfg, &dbi_config->config, sizeof(tmp_cfg)); + tmp_cfg.operation &= ~SPI_WORD_SIZE_MASK; + tmp_cfg.operation |= SPI_WORD_SET(9); + buffer.buf = &data->spi_byte; + buffer.len = 1; + + /* Send command */ + if (cmd_present) { + data->spi_byte = cmd; + ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + if (ret < 0) { + goto out; + } + } + /* Write data, byte by byte */ + for (size_t i = 0; i < len; i++) { + data->spi_byte = MIPI_DBI_DC_BIT | data_buf[i]; + ret = spi_write(config->spi_dev, &tmp_cfg, &buf_set); + if (ret < 0) { + goto out; + } + } + } else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) { + /* 4 wire mode is much simpler. We just toggle the + * command/data GPIO to indicate if we are sending + * a command or data + */ + buffer.buf = &cmd; + buffer.len = sizeof(cmd); + + if (cmd_present) { + /* Set CD pin low for command */ + gpio_pin_set_dt(&config->cmd_data, 0); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); + if (ret < 0) { + goto out; + } + } + + if (len > 0) { + buffer.buf = (void *)data_buf; + buffer.len = len; + + /* Set CD pin high for data */ + gpio_pin_set_dt(&config->cmd_data, 1); + ret = spi_write(config->spi_dev, &dbi_config->config, + &buf_set); + if (ret < 0) { + goto out; + } + } + } else { + /* Otherwise, unsupported mode */ + ret = -ENOTSUP; + } +out: + k_spin_unlock(&data->lock, spinlock_key); + return ret; +} + +static int mipi_dbi_spi_command_write(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t cmd, const uint8_t *data_buf, + size_t len) +{ + return mipi_dbi_spi_write_helper(dev, dbi_config, true, cmd, + data_buf, len); +} + +static int mipi_dbi_spi_write_display(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + ARG_UNUSED(pixfmt); + + return mipi_dbi_spi_write_helper(dev, dbi_config, false, 0x0, + framebuf, desc->buf_size); +} + +#if MIPI_DBI_SPI_READ_REQUIRED + +static int mipi_dbi_spi_command_read(const struct device *dev, + const struct mipi_dbi_config *dbi_config, + uint8_t *cmds, size_t num_cmds, + uint8_t *response, size_t len) +{ + const struct mipi_dbi_spi_config *config = dev->config; + struct mipi_dbi_spi_data *data = dev->data; + struct spi_buf buffer; + struct spi_buf_set buf_set = { + .buffers = &buffer, + .count = 1, + }; + int ret = 0; + k_spinlock_key_t spinlock_key = k_spin_lock(&data->lock); + struct spi_config tmp_config; + + memcpy(&tmp_config, &dbi_config->config, sizeof(tmp_config)); + if (dbi_config->mode == MIPI_DBI_MODE_SPI_3WIRE && + IS_ENABLED(CONFIG_MIPI_DBI_SPI_3WIRE)) { + /* We have to emulate 3 wire mode by packing the data/command + * bit into the upper bit of the SPI transfer. + * switch SPI to 9 bit mode, and write the transfer + */ + tmp_config.operation &= ~SPI_WORD_SIZE_MASK; + tmp_config.operation |= SPI_WORD_SET(9); + + buffer.buf = &data->spi_byte; + buffer.len = 1; + /* Send each command */ + for (size_t i = 0; i < num_cmds; i++) { + data->spi_byte = cmds[i]; + ret = spi_write(config->spi_dev, &tmp_config, &buf_set); + if (ret < 0) { + goto out; + } + } + /* Now, we can switch to 8 bit mode, and read data */ + buffer.buf = (void *)response; + buffer.len = len; + ret = spi_read(config->spi_dev, &dbi_config->config, &buf_set); + } else if (dbi_config->mode == MIPI_DBI_MODE_SPI_4WIRE) { + /* 4 wire mode is much simpler. We just toggle the + * command/data GPIO to indicate if we are sending + * a command or data. Note that since some SPI displays + * require CS to be held low for the entire read sequence, + * we set SPI_HOLD_ON_CS + */ + tmp_config.operation |= SPI_HOLD_ON_CS; + + if (num_cmds > 0) { + buffer.buf = cmds; + buffer.len = num_cmds; + /* Set CD pin low for command */ + gpio_pin_set_dt(&config->cmd_data, 0); + + ret = spi_write(config->spi_dev, &tmp_config, + &buf_set); + if (ret < 0) { + goto out; + } + } + + if (len > 0) { + /* Set CD pin high for data */ + gpio_pin_set_dt(&config->cmd_data, 1); + + buffer.buf = (void *)response; + buffer.len = len; + ret = spi_read(config->spi_dev, &tmp_config, + &buf_set); + if (ret < 0) { + goto out; + } + } + } else { + /* Otherwise, unsupported mode */ + ret = -ENOTSUP; + } +out: + spi_release(config->spi_dev, &tmp_config); + k_spin_unlock(&data->lock, spinlock_key); + return ret; +} + +#endif /* MIPI_DBI_SPI_READ_REQUIRED */ + +static inline bool mipi_dbi_has_pin(const struct gpio_dt_spec *spec) +{ + return spec->port != NULL; +} + +static int mipi_dbi_spi_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_spi_config *config = dev->config; + int ret; + + if (!mipi_dbi_has_pin(&config->reset)) { + return -ENOTSUP; + } + + ret = gpio_pin_set_dt(&config->reset, 0); + if (ret < 0) { + return ret; + } + k_msleep(delay); + return gpio_pin_set_dt(&config->reset, 1); +} + +static int mipi_dbi_spi_init(const struct device *dev) +{ + const struct mipi_dbi_spi_config *config = dev->config; + int ret; + + if (!device_is_ready(config->spi_dev)) { + LOG_ERR("SPI device is not ready"); + return -ENODEV; + } + + if (mipi_dbi_has_pin(&config->cmd_data)) { + if (!gpio_is_ready_dt(&config->cmd_data)) { + return -ENODEV; + } + ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Could not configure command/data GPIO (%d)", ret); + return ret; + } + } + + if (mipi_dbi_has_pin(&config->reset)) { + if (!gpio_is_ready_dt(&config->reset)) { + return -ENODEV; + } + ret = gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Could not configure reset GPIO (%d)", ret); + return ret; + } + } + + return 0; +} + +static struct mipi_dbi_driver_api mipi_dbi_spi_driver_api = { + .reset = mipi_dbi_spi_reset, + .command_write = mipi_dbi_spi_command_write, + .write_display = mipi_dbi_spi_write_display, +#if MIPI_DBI_SPI_READ_REQUIRED + .command_read = mipi_dbi_spi_command_read, +#endif +}; + +#define MIPI_DBI_SPI_INIT(n) \ + static const struct mipi_dbi_spi_config \ + mipi_dbi_spi_config_##n = { \ + .spi_dev = DEVICE_DT_GET( \ + DT_INST_PHANDLE(n, spi_dev)), \ + .cmd_data = GPIO_DT_SPEC_INST_GET_OR(n, dc_gpios, {}), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {}), \ + }; \ + static struct mipi_dbi_spi_data mipi_dbi_spi_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, mipi_dbi_spi_init, NULL, \ + &mipi_dbi_spi_data_##n, \ + &mipi_dbi_spi_config_##n, \ + POST_KERNEL, \ + CONFIG_MIPI_DBI_INIT_PRIORITY, \ + &mipi_dbi_spi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MIPI_DBI_SPI_INIT) diff --git a/drivers/misc/CMakeLists.txt b/drivers/misc/CMakeLists.txt index 863f839184e..c23bdb185de 100644 --- a/drivers/misc/CMakeLists.txt +++ b/drivers/misc/CMakeLists.txt @@ -6,3 +6,5 @@ add_subdirectory_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb) add_subdirectory_ifdef(CONFIG_PIO_RPI_PICO pio_rpi_pico) add_subdirectory_ifdef(CONFIG_NXP_S32_EMIOS nxp_s32_emios) add_subdirectory_ifdef(CONFIG_TIMEAWARE_GPIO timeaware_gpio) +add_subdirectory_ifdef(CONFIG_DEVMUX devmux) +add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 66d83fc693d..3511b8b6fd4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -10,5 +10,7 @@ source "drivers/misc/grove_lcd_rgb/Kconfig" source "drivers/misc/pio_rpi_pico/Kconfig" source "drivers/misc/nxp_s32_emios/Kconfig" source "drivers/misc/timeaware_gpio/Kconfig" +source "drivers/misc/devmux/Kconfig" +source "drivers/misc/nordic_vpr_launcher/Kconfig" endmenu diff --git a/drivers/misc/devmux/CMakeLists.txt b/drivers/misc/devmux/CMakeLists.txt new file mode 100644 index 00000000000..94f74ea57ce --- /dev/null +++ b/drivers/misc/devmux/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_syscall_header( + ${ZEPHYR_BASE}/include/zephyr/drivers/misc/devmux/devmux.h +) + +zephyr_library_sources(devmux.c) diff --git a/drivers/misc/devmux/Kconfig b/drivers/misc/devmux/Kconfig new file mode 100644 index 00000000000..4f848b4e06c --- /dev/null +++ b/drivers/misc/devmux/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +config DEVMUX + bool "Device Multiplexer (devmux) [EXPERIMENTAL]" + depends on DT_HAS_ZEPHYR_DEVMUX_ENABLED + depends on DEVICE_MUTABLE + select EXPERIMENTAL + help + Devmux is a pseudo-device that operates as a device switch. It allows + software to select the data, config, and api from a number of linked + devices. + +if DEVMUX + +config DEVMUX_INIT_PRIORITY + int "Devmux init priority" + default 51 + help + Init priority for the devmux driver. It must be + greater than the priority of the initially selected muxed device. + +endif diff --git a/drivers/misc/devmux/devmux.c b/drivers/misc/devmux/devmux.c new file mode 100644 index 00000000000..653236f903d --- /dev/null +++ b/drivers/misc/devmux/devmux.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_devmux + +#include +#include +#include +#include + +struct devmux_config { + const struct device **devs; + const size_t n_devs; +}; + +struct devmux_data { + struct k_spinlock lock; + size_t selected; +}; + +/* The number of devmux devices */ +#define N DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) + +static const struct device *devmux_devices[N]; +static const struct devmux_config *devmux_configs[N]; +static struct devmux_data *devmux_datas[N]; + +static bool devmux_device_is_valid(const struct device *dev) +{ + for (size_t i = 0; i < N; ++i) { + if (dev == devmux_devices[i]) { + return true; + } + } + + return false; +} + +static size_t devmux_inst_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return i; + } + } + + return SIZE_MAX; +} + +const struct devmux_config *devmux_config_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return devmux_configs[i]; + } + } + + return NULL; +} + +struct devmux_data *devmux_data_get(const struct device *dev) +{ + for (size_t i = 0; i < N; i++) { + if (dev == devmux_devices[i]) { + return devmux_datas[i]; + } + } + + return NULL; +} + +ssize_t z_impl_devmux_select_get(const struct device *dev) +{ + ssize_t index; + struct devmux_data *const data = devmux_data_get(dev); + + if (!devmux_device_is_valid(dev)) { + return -EINVAL; + } + + K_SPINLOCK(&data->lock) + { + index = data->selected; + } + + return index; +} + +#ifdef CONFIG_USERSPACE +ssize_t z_vrfy_devmux_select_get(const struct device *dev) +{ + return z_impl_devmux_select_get(dev); +} +#include +#endif + +int z_impl_devmux_select_set(struct device *dev, size_t index) +{ + struct devmux_data *const data = devmux_data_get(dev); + const struct devmux_config *config = devmux_config_get(dev); + + if (!devmux_device_is_valid(dev) || index >= config->n_devs) { + return -EINVAL; + } + + if (!device_is_ready(config->devs[index])) { + return -ENODEV; + } + + K_SPINLOCK(&data->lock) + { + *dev = *config->devs[index]; + data->selected = index; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy_devmux_select_set(struct device *dev, size_t index) +{ + return z_impl_devmux_select_set(dev, index); +} +#include +#endif + +static int devmux_init(struct device *const dev) +{ + size_t inst = devmux_inst_get(dev); + struct devmux_data *const data = dev->data; + const struct devmux_config *config = dev->config; + size_t sel = data->selected; + + devmux_configs[inst] = config; + devmux_datas[inst] = data; + + if (!device_is_ready(config->devs[sel])) { + return -ENODEV; + } + + *dev = *config->devs[sel]; + + return 0; +} + +#define DEVMUX_PHANDLE_TO_DEVICE(node_id, prop, idx) \ + DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)) + +#define DEVMUX_PHANDLE_DEVICES(_n) \ + DT_INST_FOREACH_PROP_ELEM_SEP(_n, devices, DEVMUX_PHANDLE_TO_DEVICE, (,)) + +#define DEVMUX_SELECTED(_n) DT_INST_PROP(_n, selected) + +#define DEVMUX_DEFINE(_n) \ + BUILD_ASSERT(DT_INST_PROP_OR(_n, zephyr_mutable, 0), \ + "devmux nodes must contain the 'zephyr,mutable' property"); \ + BUILD_ASSERT(DT_INST_PROP_LEN(_n, devices) > 0, "devices array must have non-zero size"); \ + BUILD_ASSERT(DEVMUX_SELECTED(_n) >= 0, "selected must be > 0"); \ + BUILD_ASSERT(DEVMUX_SELECTED(_n) < DT_INST_PROP_LEN(_n, devices), \ + "selected must be within bounds of devices phandle array"); \ + static const struct device *demux_devs_##_n[] = {DEVMUX_PHANDLE_DEVICES(_n)}; \ + static const struct devmux_config devmux_config_##_n = { \ + .devs = demux_devs_##_n, \ + .n_devs = DT_INST_PROP_LEN(_n, devices), \ + }; \ + static struct devmux_data devmux_data_##_n = { \ + .selected = DEVMUX_SELECTED(_n), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(_n, devmux_init, NULL, &devmux_data_##_n, &devmux_config_##_n, \ + PRE_KERNEL_1, CONFIG_DEVMUX_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(DEVMUX_DEFINE) + +#define DEVMUX_DEVICE_GET(_n) DEVICE_DT_INST_GET(_n), +static const struct device *devmux_devices[] = {DT_INST_FOREACH_STATUS_OKAY(DEVMUX_DEVICE_GET)}; diff --git a/drivers/misc/nordic_vpr_launcher/CMakeLists.txt b/drivers/misc/nordic_vpr_launcher/CMakeLists.txt new file mode 100644 index 00000000000..70c84e84217 --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(nordic_vpr_launcher.c) diff --git a/drivers/misc/nordic_vpr_launcher/Kconfig b/drivers/misc/nordic_vpr_launcher/Kconfig new file mode 100644 index 00000000000..57605e505f2 --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config NORDIC_VPR_LAUNCHER + bool "Nordic VPR coprocessor launcher" + default y + depends on DT_HAS_NORDIC_NRF_VPR_COPROCESSOR_ENABLED + help + When enabled, the VPR coprocessors will be automatically launched + during system initialization. + +if NORDIC_VPR_LAUNCHER + +module = NORDIC_VPR_LAUNCHER +module-str = Nordic VPR Launcher +source "subsys/logging/Kconfig.template.log_config" + +config NORDIC_VPR_LAUNCHER_INIT_PRIORITY + int "Nordic VPR coprocessor launcher init priority" + default KERNEL_INIT_PRIORITY_DEVICE + help + The init priority of the VPR coprocessor launcher. + +endif # NORDIC_VPR_LAUNCHER diff --git a/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c new file mode 100644 index 00000000000..161465ba02c --- /dev/null +++ b/drivers/misc/nordic_vpr_launcher/nordic_vpr_launcher.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nordic_nrf_vpr_coprocessor + +#include + +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(nordic_vpr_launcher, CONFIG_NORDIC_VPR_LAUNCHER_LOG_LEVEL); + +struct nordic_vpr_launcher_config { + NRF_VPR_Type *vpr; + uintptr_t exec_addr; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(source_memory) + uintptr_t src_addr; + size_t src_size; +#endif +}; + +static int nordic_vpr_launcher_init(const struct device *dev) +{ + const struct nordic_vpr_launcher_config *config = dev->config; + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(source_memory) + if (config->src_size > 0U) { + LOG_DBG("Loading VPR (%p) from %p to %p (%zu bytes)", config->vpr, + (void *)config->src_addr, (void *)config->exec_addr, config->src_size); + memcpy((void *)config->exec_addr, (void *)config->src_addr, config->src_size); + } +#endif + + LOG_DBG("Launching VPR (%p) from %p", config->vpr, (void *)config->exec_addr); + nrf_vpr_initpc_set(config->vpr, config->exec_addr); + nrf_vpr_cpurun_set(config->vpr, true); + + return 0; +} + +/* obtain VPR source address either from memory or partition */ +#define VPR_SRC_ADDR(node_id) \ + (DT_REG_ADDR(node_id) + \ + COND_CODE_0(DT_FIXED_PARTITION_EXISTS(node_id), (0), (DT_REG_ADDR(DT_GPARENT(node_id))))) + +#define NORDIC_VPR_LAUNCHER_DEFINE(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(inst, source_memory), \ + (BUILD_ASSERT((DT_REG_SIZE(DT_INST_PHANDLE(inst, execution_memory)) == \ + DT_REG_SIZE(DT_INST_PHANDLE(inst, source_memory))), \ + "Source/execution memory sizes mismatch");), \ + ()) \ + \ + static const struct nordic_vpr_launcher_config config##inst = { \ + .vpr = (NRF_VPR_Type *)DT_INST_REG_ADDR(inst), \ + .exec_addr = DT_REG_ADDR(DT_INST_PHANDLE(inst, execution_memory)), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, source_memory), \ + (.src_addr = VPR_SRC_ADDR(DT_INST_PHANDLE(inst, source_memory)), \ + .src_size = DT_REG_SIZE(DT_INST_PHANDLE(inst, source_memory)),), \ + ())}; \ + \ + DEVICE_DT_INST_DEFINE(inst, nordic_vpr_launcher_init, NULL, NULL, &config##inst, \ + POST_KERNEL, CONFIG_NORDIC_VPR_LAUNCHER_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(NORDIC_VPR_LAUNCHER_DEFINE) diff --git a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c index 03a03e824c2..5182cdf32b0 100644 --- a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c +++ b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c @@ -6,13 +6,18 @@ */ #include +#include #include #include +#include #define DT_DRV_COMPAT raspberrypi_pico_pio struct pio_rpi_pico_config { PIO pio; + const struct device *clk_dev; + clock_control_subsys_t clk_id; + const struct reset_dt_spec reset; }; int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm) @@ -38,16 +43,31 @@ PIO pio_rpi_pico_get_pio(const struct device *dev) static int pio_rpi_pico_init(const struct device *dev) { + const struct pio_rpi_pico_config *config = dev->config; + int ret; + + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } + + ret = reset_line_toggle_dt(&config->reset); + if (ret < 0) { + return ret; + } + return 0; } -#define RPI_PICO_PIO_INIT(idx) \ - static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \ - .pio = (PIO)DT_INST_REG_ADDR(idx), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, \ - &pio_rpi_pico_config_##idx, PRE_KERNEL_2, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); +#define RPI_PICO_PIO_INIT(idx) \ + static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \ + .pio = (PIO)DT_INST_REG_ADDR(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, &pio_rpi_pico_config_##idx, \ + PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_PIO_INIT) diff --git a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c index ea3bb385b3b..a068abafc36 100644 --- a/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_mtl_tlb.c @@ -16,7 +16,7 @@ * Note that all passed in addresses should be in cached range * (aka cached addresses). Due to the need to calculate TLB * indexes, virtual addresses will be converted internally to - * cached one via z_soc_cached_ptr(). However, physical addresses + * cached one via sys_cache_cached_ptr_get(). However, physical addresses * are untouched. */ @@ -183,8 +183,8 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) * the cached physical address is needed to perform * bound check. */ - uintptr_t pa = POINTER_TO_UINT(z_soc_cached_ptr(UINT_TO_POINTER(phys))); - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(UINT_TO_POINTER(phys))); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); ARG_UNUSED(flags); @@ -215,7 +215,7 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) "unable to assign free phys page %d\n", ret); goto out; } - pa = POINTER_TO_UINT(z_soc_cached_ptr(phys_block_ptr)); + pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(phys_block_ptr)); } /* Check bounds of physical address space */ @@ -296,7 +296,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, goto out; } - va = (__sparse_force uint8_t *)z_soc_cached_ptr(virt); + va = (__sparse_force uint8_t *)sys_cache_cached_ptr_get(virt); pa = phys; key = k_spin_lock(&sys_mm_drv_common_lock); @@ -324,7 +324,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, int sys_mm_drv_map_array(void *virt, uintptr_t *phys, size_t cnt, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_array(va, phys, cnt, flags); } @@ -339,7 +339,7 @@ int sys_mm_drv_unmap_page(void *virt) int ret = 0; /* Use cached virtual address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); /* Check bounds of virtual address space */ CHECKIF((va < UNUSED_L2_START_ALIGNED) || @@ -396,7 +396,7 @@ int sys_mm_drv_unmap_page(void *virt) int sys_mm_drv_unmap_region(void *virt, size_t size) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_unmap_region(va, size); } @@ -408,7 +408,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) int ret = 0; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -449,7 +449,7 @@ int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags) uint16_t ent; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -487,8 +487,8 @@ int sys_mm_drv_page_flag_get(void *virt, uint32_t *flags) int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new) { - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); return sys_mm_drv_simple_remap_region(va_old, size, va_new); } @@ -500,8 +500,8 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, size_t offset; int ret = 0; - virt_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - virt_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + virt_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + virt_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); CHECKIF(!sys_mm_drv_is_virt_addr_aligned(virt_old) || !sys_mm_drv_is_virt_addr_aligned(virt_new) || @@ -598,8 +598,8 @@ int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_array(va_old, size, va_new, phys_new, phys_cnt); @@ -783,7 +783,7 @@ __imr void adsp_mm_restore_context(void *storage_buffer) while (phys_addr != 0) { uint32_t phys_addr_uncached = - POINTER_TO_UINT(z_soc_uncached_ptr( + POINTER_TO_UINT(sys_cache_uncached_ptr_get( (void __sparse_cache *)UINT_TO_POINTER(phys_addr))); uint32_t phys_offset = phys_addr - L2_SRAM_BASE; uint32_t bank_idx = (phys_offset / SRAM_BANK_SIZE); diff --git a/drivers/mm/mm_drv_intel_adsp_tlb.c b/drivers/mm/mm_drv_intel_adsp_tlb.c index 315496be8e0..0807bc787d1 100644 --- a/drivers/mm/mm_drv_intel_adsp_tlb.c +++ b/drivers/mm/mm_drv_intel_adsp_tlb.c @@ -16,7 +16,7 @@ * Note that all passed in addresses should be in cached range * (aka cached addresses). Due to the need to calculate TLB * indexes, virtual addresses will be converted internally to - * cached one via z_soc_cached_ptr(). However, physical addresses + * cached one via sys_cache_cached_ptr_get(). However, physical addresses * are untouched. */ @@ -32,7 +32,6 @@ #include #include -#include #include #include @@ -80,8 +79,8 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) * the cached physical address is needed to perform * bound check. */ - uintptr_t pa = POINTER_TO_UINT(z_soc_cached_ptr(UINT_TO_POINTER(phys))); - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t pa = POINTER_TO_UINT(sys_cache_cached_ptr_get(UINT_TO_POINTER(phys))); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); ARG_UNUSED(flags); @@ -145,7 +144,7 @@ int sys_mm_drv_map_page(void *virt, uintptr_t phys, uint32_t flags) int sys_mm_drv_map_region(void *virt, uintptr_t phys, size_t size, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_region(va, phys, size, flags); } @@ -153,7 +152,7 @@ int sys_mm_drv_map_region(void *virt, uintptr_t phys, int sys_mm_drv_map_array(void *virt, uintptr_t *phys, size_t cnt, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_map_array(va, phys, cnt, flags); } @@ -166,7 +165,7 @@ int sys_mm_drv_unmap_page(void *virt) int ret = 0; /* Use cached virtual address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); /* Check bounds of virtual address space */ CHECKIF((va < CONFIG_KERNEL_VM_BASE) || @@ -202,7 +201,7 @@ int sys_mm_drv_unmap_page(void *virt) int sys_mm_drv_unmap_region(void *virt, size_t size) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_unmap_region(va, size); } @@ -214,7 +213,7 @@ int sys_mm_drv_page_phys_get(void *virt, uintptr_t *phys) int ret = 0; /* Use cached address */ - uintptr_t va = POINTER_TO_UINT(z_soc_cached_ptr(virt)); + uintptr_t va = POINTER_TO_UINT(sys_cache_cached_ptr_get(virt)); CHECKIF(!sys_mm_drv_is_addr_aligned(va)) { ret = -EINVAL; @@ -274,7 +273,7 @@ int sys_mm_drv_update_page_flags(void *virt, uint32_t flags) int sys_mm_drv_update_region_flags(void *virt, size_t size, uint32_t flags) { - void *va = (__sparse_force void *)z_soc_cached_ptr(virt); + void *va = (__sparse_force void *)sys_cache_cached_ptr_get(virt); return sys_mm_drv_simple_update_region_flags(va, size, flags); } @@ -283,8 +282,8 @@ int sys_mm_drv_update_region_flags(void *virt, size_t size, int sys_mm_drv_remap_region(void *virt_old, size_t size, void *virt_new) { - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); return sys_mm_drv_simple_remap_region(va_old, size, va_new); } @@ -294,8 +293,8 @@ int sys_mm_drv_move_region(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_region(va_old, size, va_new, phys_new); @@ -314,8 +313,8 @@ int sys_mm_drv_move_array(void *virt_old, size_t size, void *virt_new, { int ret; - void *va_new = (__sparse_force void *)z_soc_cached_ptr(virt_new); - void *va_old = (__sparse_force void *)z_soc_cached_ptr(virt_old); + void *va_new = (__sparse_force void *)sys_cache_cached_ptr_get(virt_new); + void *va_old = (__sparse_force void *)sys_cache_cached_ptr_get(virt_old); ret = sys_mm_drv_simple_move_array(va_old, size, va_new, phys_new, phys_cnt); diff --git a/drivers/modem/Kconfig b/drivers/modem/Kconfig index c233d5db821..02e3557918f 100644 --- a/drivers/modem/Kconfig +++ b/drivers/modem/Kconfig @@ -142,6 +142,8 @@ config MODEM_CMD_HANDLER_MAX_PARAM_COUNT of the match_buf (match_buf_len) field as it needs to be large enough to hold a single line of data (ending with /r). +endif # MODEM_CONTEXT + config MODEM_SOCKET bool "Generic modem socket support layer" help @@ -165,8 +167,6 @@ config MODEM_SOCKET_PACKET_COUNT these values are organized into "packets". This setting limits the maximum number of packet sizes the socket can keep track of. -endif # MODEM_CONTEXT - config MODEM_SHELL bool "Modem shell utilities" select SHELL diff --git a/drivers/modem/Kconfig.cellular b/drivers/modem/Kconfig.cellular index 7817fb599e3..0460cda8d96 100644 --- a/drivers/modem/Kconfig.cellular +++ b/drivers/modem/Kconfig.cellular @@ -11,10 +11,11 @@ config MODEM_CELLULAR select MODEM_BACKEND_UART select RING_BUFFER select NET_L2_PPP_OPTION_MRU + select NET_L2_PPP_PAP depends on (DT_HAS_QUECTEL_BG95_ENABLED || DT_HAS_ZEPHYR_GSM_PPP_ENABLED || \ DT_HAS_SIMCOM_SIM7080_ENABLED || DT_HAS_U_BLOX_SARA_R4_ENABLED || \ - DT_HAS_SWIR_HL7800_ENABLED || DT_HAS_TELIT_ME910G1_ENABLED || \ - DT_HAS_QUECTEL_EG25_G_ENABLED) + DT_HAS_U_BLOX_SARA_R5_ENABLED || DT_HAS_SWIR_HL7800_ENABLED || \ + DT_HAS_TELIT_ME910G1_ENABLED || DT_HAS_QUECTEL_EG25_G_ENABLED) help This driver uses the generic 3gpp AT commands, along with the standard protocols CMUX and PPP, to configure diff --git a/drivers/modem/Kconfig.hl7800 b/drivers/modem/Kconfig.hl7800 index 01c607c391a..615dd5bdf87 100644 --- a/drivers/modem/Kconfig.hl7800 +++ b/drivers/modem/Kconfig.hl7800 @@ -354,6 +354,10 @@ endchoice config MODEM_HL7800_ALLOW_SLEEP_DELAY_MS int "Milliseconds to delay before allowing modem to sleep" default 5000 + range 5000 3600000 + help + This value should be set larger than the network latency. Otherwise + the modem can go to sleep before having a chance to receive socket data. config MODEM_HL7800_RSSI_RATE_SECONDS int "Rate to automatically query RSSI" @@ -361,11 +365,10 @@ config MODEM_HL7800_RSSI_RATE_SECONDS default 30 config MODEM_HL7800_CTS_FILTER_US - int "Duration in microseconds between samples of CTS signal" - default 10 - -config MODEM_HL7800_CTS_FILTER_MAX_ITERATIONS - int "Maximum filter loops" - default 5 + int "CTS signal filter time (microseconds)" + default 20 + help + This value is used to filter the CTS signal from the modem. + CTS pulses shorter than this value will be ignored. endif # MODEM_HL7800 diff --git a/drivers/modem/gsm_ppp.c b/drivers/modem/gsm_ppp.c index 154092ac356..88ea47b832a 100644 --- a/drivers/modem/gsm_ppp.c +++ b/drivers/modem/gsm_ppp.c @@ -814,7 +814,7 @@ static void gsm_finalize_connection(struct k_work *work) query_rssi_nolock(gsm); if (!((gsm->minfo.mdm_rssi) && (gsm->minfo.mdm_rssi != GSM_RSSI_INVALID) && - (gsm->minfo.mdm_rssi < GSM_RSSI_MAXVAL))) { + (gsm->minfo.mdm_rssi <= GSM_RSSI_MAXVAL))) { LOG_DBG("Not valid RSSI, %s", "retrying..."); if (gsm->retries-- > 0) { diff --git a/drivers/modem/hl7800.c b/drivers/modem/hl7800.c index c635016197e..9846cf86f84 100644 --- a/drivers/modem/hl7800.c +++ b/drivers/modem/hl7800.c @@ -82,7 +82,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_MODEM_LOG_LEVEL); #define HL7800_IO_DBG_LOG(fmt, ...) \ do { \ if (IS_ENABLED(HL7800_IO_LOG)) { \ - LOG_DBG(fmt, ##__VA_ARGS__); \ + LOG_WRN(fmt, ##__VA_ARGS__); \ } \ } while (false) @@ -208,6 +208,7 @@ struct xmodem_packet { * and that its actual ID hasn't been assigned yet. */ #define MDM_CREATE_SOCKET_ID (MDM_MAX_SOCKETS + 1) +#define MDM_INVALID_SOCKET_ID -1 #define BUF_ALLOC_TIMEOUT K_SECONDS(1) @@ -439,6 +440,8 @@ struct hl7800_iface_ctx { int dsr_state; int gpio6_state; int cts_state; + int last_cts_state; + int last_cts_time; /* RX specific attributes */ struct mdm_receiver_context mdm_ctx; @@ -504,8 +507,9 @@ struct hl7800_iface_ctx { char mdm_pdp_addr_fam[MDM_ADDR_FAM_MAX_LEN]; /* modem state */ + bool busy; + bool socket_cmd; bool allow_sleep; - bool uart_on; enum mdm_hl7800_sleep desired_sleep_level; enum mdm_hl7800_sleep sleep_state; enum hl7800_lpm low_power_mode; @@ -613,6 +617,7 @@ static int queue_stale_socket(enum net_sock_type type, uint8_t id) sock = alloc_stale_socket(); if (sock != NULL) { + LOG_DBG("Queueing stale socket %d", id); sock->type = type; sock->id = id; k_queue_append(&iface_ctx.stale_socket_queue, (void *)sock); @@ -805,6 +810,11 @@ static struct hl7800_socket *socket_from_id(int socket_id) return sock; } +static inline void set_busy(bool busy) +{ + iface_ctx.busy = busy; +} + static void socket_put(struct hl7800_socket *sock) { if (!sock) { @@ -812,7 +822,7 @@ static void socket_put(struct hl7800_socket *sock) } sock->context = NULL; - sock->socket_id = -1; + sock->socket_id = MDM_INVALID_SOCKET_ID; sock->created = false; sock->reconfig = false; sock->error = 0; @@ -859,6 +869,17 @@ void mdm_hl7800_register_cts_callback(void (*func)(int state)) iface_ctx.cts_callback = func; } +static void modem_assert_reset(bool assert) +{ + if (assert) { + HL7800_IO_DBG_LOG("MDM_RESET -> ASSERTED"); + gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1); + } else { + HL7800_IO_DBG_LOG("MDM_RESET -> NOT_ASSERTED"); + gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0); + } +} + static void modem_assert_wake(bool assert) { int state; @@ -903,19 +924,28 @@ static void modem_assert_fast_shutd(bool assert) static void allow_sleep_work_callback(struct k_work *item) { ARG_UNUSED(item); - LOG_DBG("Allow sleep"); - iface_ctx.allow_sleep = true; - set_sleep_state(iface_ctx.desired_sleep_level); - modem_assert_wake(false); + if (!iface_ctx.busy) { + LOG_DBG("Allow sleep"); + iface_ctx.allow_sleep = true; + set_sleep_state(iface_ctx.desired_sleep_level); + modem_assert_wake(false); + } else { + k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.allow_sleep_work, + K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + } } static void allow_sleep(bool allow) { #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE if (allow) { - k_work_reschedule_for_queue(&hl7800_workq, - &iface_ctx.allow_sleep_work, - K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + if (!iface_ctx.restarting && !iface_ctx.busy) { + k_work_reschedule_for_queue( + &hl7800_workq, &iface_ctx.allow_sleep_work, + K_MSEC(CONFIG_MODEM_HL7800_ALLOW_SLEEP_DELAY_MS)); + } else { + k_work_cancel_delayable(&iface_ctx.allow_sleep_work); + } } else { LOG_DBG("Keep awake"); k_work_cancel_delayable(&iface_ctx.allow_sleep_work); @@ -967,8 +997,10 @@ static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data, if (!sock) { k_sem_reset(&iface_ctx.response_sem); iface_ctx.last_socket_id = 0; + iface_ctx.socket_cmd = false; } else { sock->error = 0; + iface_ctx.socket_cmd = true; k_sem_reset(&sock->sock_send_sem); iface_ctx.last_socket_id = sock->socket_id; } @@ -1014,6 +1046,7 @@ static int send_at_cmd(struct hl7800_socket *sock, const uint8_t *data, static int wakeup_hl7800(void) { + set_busy(true); #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE int ret; @@ -1049,6 +1082,7 @@ int32_t mdm_hl7800_send_at_cmd(const uint8_t *data) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, data, MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1065,6 +1099,7 @@ int32_t mdm_hl7800_update_apn(char *access_point_name) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = write_apn(access_point_name); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1119,6 +1154,7 @@ int32_t mdm_hl7800_update_rat(enum mdm_hl7800_radio_mode value) error: + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1143,6 +1179,7 @@ int32_t mdm_hl7800_get_local_time(struct tm *tm, int32_t *offset) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+CCLK?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); if (iface_ctx.local_time_valid) { memcpy(tm, &iface_ctx.local_time, sizeof(struct tm)); @@ -1163,6 +1200,7 @@ int32_t mdm_hl7800_get_operator_index(void) iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+KCARRIERCFG?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); if (ret < 0) { @@ -1180,6 +1218,7 @@ int32_t mdm_hl7800_get_functionality(void) wakeup_hl7800(); iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, "AT+CFUN?", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1201,6 +1240,7 @@ int32_t mdm_hl7800_set_functionality(enum mdm_hl7800_functionality mode) iface_ctx.last_socket_id = 0; ret = send_at_cmd(NULL, buf, MDM_CMD_SEND_TIMEOUT, MDM_DEFAULT_AT_CMD_RETRIES, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -1247,6 +1287,7 @@ int32_t mdm_hl7800_set_gps_rate(uint32_t rate) } LOG_DBG("GPS status: %d rate: %u", ret, rate); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1267,6 +1308,7 @@ int32_t mdm_hl7800_polte_register(void) SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"REGISTER\""); error: LOG_DBG("PoLTE register status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1290,6 +1332,7 @@ int32_t mdm_hl7800_polte_enable(char *user, char *password) error: LOG_DBG("PoLTE register status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1304,6 +1347,7 @@ int32_t mdm_hl7800_polte_locate(void) SEND_AT_CMD_EXPECT_OK("AT%POLTECMD=\"LOCATE\",2,1"); error: LOG_DBG("PoLTE locate status: %d", ret); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1322,6 +1366,7 @@ int32_t mdm_hl7800_perform_site_survey(void) hl7800_lock(); wakeup_hl7800(); ret = send_at_cmd(NULL, "at%meas=\"97\"", MDM_CMD_SEND_TIMEOUT, 0, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -1841,6 +1886,7 @@ static void dns_work_cb(struct k_work *work) struct dns_resolve_context *dnsCtx; struct sockaddr temp_addr; bool valid_address = false; + bool retry = false; static const char *const dns_servers_str[] = { #ifdef CONFIG_NET_IPV6 iface_ctx.dns_v6_string, @@ -1874,12 +1920,29 @@ static void dns_work_cb(struct k_work *work) /* set new DNS addr in DNS resolver */ LOG_DBG("Refresh DNS resolver"); dnsCtx = dns_resolve_get_default(); - ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL); - if (ret < 0) { - LOG_ERR("dns_resolve_init fail (%d)", ret); - return; + if (dnsCtx->state == DNS_RESOLVE_CONTEXT_INACTIVE) { + LOG_DBG("Initializing DNS resolver"); + ret = dns_resolve_init(dnsCtx, (const char **)dns_servers_str, NULL); + if (ret < 0) { + LOG_ERR("dns_resolve_init fail (%d)", ret); + retry = true; + } + } else { + LOG_DBG("Reconfiguring DNS resolver"); + ret = dns_resolve_reconfigure(dnsCtx, (const char **)dns_servers_str, NULL); + if (ret < 0) { + LOG_ERR("dns_resolve_reconfigure fail (%d)", ret); + retry = true; + } + } + if (!retry) { + LOG_DBG("DNS ready"); + iface_ctx.dns_ready = true; + } else { + LOG_DBG("DNS not ready, schedule a retry"); + k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.dns_work, + K_SECONDS(DNS_WORK_DELAY_SECS * 2)); } - iface_ctx.dns_ready = true; } #endif } @@ -2374,6 +2437,7 @@ int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level) hl7800_lock(); wakeup_hl7800(); r = set_sleep_level(); + set_busy(false); allow_sleep(true); hl7800_unlock(); } @@ -2382,8 +2446,6 @@ int mdm_hl7800_set_desired_sleep_level(enum mdm_hl7800_sleep level) return r; } -#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE - static void initialize_sleep_level(void) { if (iface_ctx.desired_sleep_level == HL7800_SLEEP_UNINITIALIZED) { @@ -2399,6 +2461,7 @@ static void initialize_sleep_level(void) } } +#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE static int set_sleep_level(void) { char cmd[sizeof("AT+KSLEEP=#,#,##")]; @@ -2789,6 +2852,7 @@ static void rssi_query(void) hl7800_lock(); wakeup_hl7800(); hl7800_query_rssi(); + set_busy(false); allow_sleep(true); hl7800_unlock(); } @@ -2845,6 +2909,7 @@ static void gps_work_callback(struct k_work *work) hl7800_lock(); wakeup_hl7800(); r = send_at_cmd(NULL, "AT+GNSSLOC?", MDM_CMD_SEND_TIMEOUT, 1, false); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -3300,6 +3365,7 @@ static void iface_status_work_cb(struct k_work *work) SEND_AT_CMD_IGNORE_ERROR("AT+KBND?"); } LOG_DBG("Network state updated"); + set_busy(false); allow_sleep(true); done: hl7800_unlock(); @@ -3614,6 +3680,7 @@ static bool on_cmd_network_report(struct net_buf **buf, uint16_t len) } /* keep HL7800 awake because we want to process the network state soon */ + set_busy(true); allow_sleep(false); /* start work to adjust iface */ k_work_reschedule_for_queue(&hl7800_workq, &iface_ctx.iface_status_work, @@ -3675,7 +3742,7 @@ static bool on_cmd_sockok(struct net_buf **buf, uint16_t len) struct hl7800_socket *sock = NULL; sock = socket_from_id(iface_ctx.last_socket_id); - if (!sock) { + if (!sock || !iface_ctx.socket_cmd) { iface_ctx.last_error = 0; k_sem_give(&iface_ctx.response_sem); } else { @@ -3891,6 +3958,8 @@ static void delete_untracked_socket_work_cb(struct k_work *item) { struct stale_socket *sock = NULL; + hl7800_lock(); + wakeup_hl7800(); do { sock = dequeue_stale_socket(); if (sock != NULL) { @@ -3899,6 +3968,10 @@ static void delete_untracked_socket_work_cb(struct k_work *item) free_stale_socket(sock); } } while (sock != NULL); + + set_busy(false); + allow_sleep(true); + hl7800_unlock(); } static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uint16_t len) @@ -3921,7 +3994,7 @@ static bool on_cmd_sockcreate(enum net_sock_type type, struct net_buf **buf, uin if (!sock) { LOG_DBG("look up new socket by creation id"); sock = socket_from_id(MDM_CREATE_SOCKET_ID); - if (!sock) { + if (!sock || sock->type != type) { if (queue_stale_socket(type, iface_ctx.last_socket_id) == 0) { /* delay some time before socket cleanup in case there * are multiple sockets to cleanup @@ -4126,6 +4199,7 @@ static void sock_read(struct net_buf **buf, uint16_t len) sock->state = SOCK_IDLE; } exit: + set_busy(false); allow_sleep(true); hl7800_TX_unlock(); } @@ -4277,6 +4351,7 @@ static bool on_cmd_sockdataind(struct net_buf **buf, uint16_t len) k_work_submit_to_queue(&hl7800_workq, &sock->rx_data_work); } else { if (left_bytes > 0) { + wakeup_hl7800(); rc = start_socket_rx(sock, left_bytes); if (rc < 0) { goto error; @@ -4708,16 +4783,19 @@ static void shutdown_uart(void) { #ifdef CONFIG_PM_DEVICE int rc; + enum pm_device_state state; - if (iface_ctx.uart_on) { + rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state); + if (rc) { + LOG_ERR("Error getting UART power state (%d)", rc); + } + if (state != PM_DEVICE_STATE_SUSPENDED) { HL7800_IO_DBG_LOG("Power OFF the UART"); uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev); rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_SUSPEND); if (rc) { LOG_ERR("Error disabling UART peripheral (%d)", rc); uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev); - } else { - iface_ctx.uart_on = false; } } #endif @@ -4727,8 +4805,13 @@ static void power_on_uart(void) { #ifdef CONFIG_PM_DEVICE int rc; + enum pm_device_state state; - if (!iface_ctx.uart_on) { + rc = pm_device_state_get(iface_ctx.mdm_ctx.uart_dev, &state); + if (rc) { + LOG_ERR("Error getting UART power state (%d)", rc); + } + if (state != PM_DEVICE_STATE_ACTIVE) { HL7800_IO_DBG_LOG("Power ON the UART"); rc = pm_device_action_run(iface_ctx.mdm_ctx.uart_dev, PM_DEVICE_ACTION_RESUME); if (rc) { @@ -4736,7 +4819,6 @@ static void power_on_uart(void) uart_irq_rx_disable(iface_ctx.mdm_ctx.uart_dev); } else { uart_irq_rx_enable(iface_ctx.mdm_ctx.uart_dev); - iface_ctx.uart_on = true; } } #endif @@ -4774,9 +4856,12 @@ static void mdm_vgpio_work_cb(struct k_work *item) hl7800_unlock(); } -void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, - uint32_t pins) +void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.vgpio_state = read_pin(1, &hl7800_cfg.gpio[MDM_VGPIO]); HL7800_IO_DBG_LOG("VGPIO:%d", iface_ctx.vgpio_state); if (!iface_ctx.vgpio_state) { @@ -4784,7 +4869,6 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, if (!iface_ctx.restarting && iface_ctx.initialized) { iface_ctx.reconfig_IP_connection = true; } - check_hl7800_awake(); } else { if (iface_ctx.off) { return; @@ -4798,10 +4882,11 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, /* Keep the modem awake to see if it has anything to send to us. */ allow_sleep(false); /* Allow the modem to go back to sleep if it was the one who - * sourced the CTS transition. + * sourced the transition. */ allow_sleep(true); } + check_hl7800_awake(); /* When the network state changes a semaphore must be taken. * This can't be done in interrupt context because the wait time != 0. @@ -4809,9 +4894,12 @@ void mdm_vgpio_callback_isr(const struct device *port, struct gpio_callback *cb, k_work_submit_to_queue(&hl7800_workq, &iface_ctx.mdm_vgpio_work); } -void mdm_uart_dsr_callback_isr(const struct device *port, - struct gpio_callback *cb, uint32_t pins) +void mdm_uart_dsr_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.dsr_state = read_pin(1, &hl7800_cfg.gpio[MDM_UART_DSR]); HL7800_IO_DBG_LOG("MDM_UART_DSR:%d", iface_ctx.dsr_state); } @@ -4832,12 +4920,15 @@ static void mark_sockets_for_reconfig(void) } #endif -void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, - uint32_t pins) +void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { -#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE + ARG_UNUSED(port); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + iface_ctx.gpio6_state = read_pin(1, &hl7800_cfg.gpio[MDM_GPIO6]); HL7800_IO_DBG_LOG("MDM_GPIO6:%d", iface_ctx.gpio6_state); +#ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE if (!iface_ctx.gpio6_state) { /* HL7800 is not awake, shut down UART to save power */ shutdown_uart(); @@ -4845,102 +4936,95 @@ void mdm_gpio6_callback_isr(const struct device *port, struct gpio_callback *cb, iface_ctx.wait_for_KSUP_tries = 0; iface_ctx.reconfig_IP_connection = true; mark_sockets_for_reconfig(); - /* TODO: may need to indicate all TCP connections lost here */ } else { if (iface_ctx.off) { return; + } else if (iface_ctx.vgpio_state) { + power_on_uart(); + /* Keep the modem awake to see if it has anything to send to us. */ + allow_sleep(false); + /* Allow the modem to go back to sleep if it was the one who + * sourced the transition. + */ + allow_sleep(true); } - power_on_uart(); } + check_hl7800_awake(); if ((iface_ctx.gpio6_callback != NULL) && ((iface_ctx.desired_sleep_level == HL7800_SLEEP_HIBERNATE) || (iface_ctx.desired_sleep_level == HL7800_SLEEP_LITE_HIBERNATE))) { iface_ctx.gpio6_callback(iface_ctx.gpio6_state); } - - check_hl7800_awake(); -#else - HL7800_IO_DBG_LOG("Spurious gpio6 interrupt from the modem"); #endif } -/** - * @brief Short spikes in CTS can be removed in the signal used by the application - */ -static int glitch_filter(int default_state, const struct gpio_dt_spec *spec, - uint32_t usec_to_wait, uint32_t max_iterations) -{ - int i = 0; - int state1; - int state2; - - do { - state1 = read_pin(-1, spec); - k_busy_wait(usec_to_wait); - state2 = read_pin(-1, spec); - i += 1; - } while (((state1 != state2) || (state1 < 0) || (state2 < 0)) && (i < max_iterations)); - - if (i >= max_iterations) { - LOG_WRN("glitch filter max iterations exceeded %d", i); - if (state1 < 0) { - if (state2 < 0) { - state1 = read_pin(default_state, spec); - } else { - state1 = state2; - } - } - } - - return state1; -} - -void mdm_uart_cts_callback(const struct device *port, struct gpio_callback *cb, uint32_t pins) +void mdm_uart_cts_callback_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { ARG_UNUSED(port); ARG_UNUSED(cb); ARG_UNUSED(pins); - - iface_ctx.cts_state = - glitch_filter(0, &hl7800_cfg.gpio[MDM_UART_CTS], - CONFIG_MODEM_HL7800_CTS_FILTER_US, - CONFIG_MODEM_HL7800_CTS_FILTER_MAX_ITERATIONS); - - /* CTS toggles A LOT, - * comment out the debug print unless we really need it. - */ - /* HL7800_IO_DBG_LOG("MDM_UART_CTS:%d", iface_ctx.cts_state); */ - - if ((iface_ctx.cts_callback != NULL) && - (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP)) { - iface_ctx.cts_callback(iface_ctx.cts_state); + uint64_t now; + uint64_t elapsed; + int resample_state; + + iface_ctx.cts_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]); + + /* Debounce the CTS signal */ + now = k_ticks_to_us_floor64(k_uptime_ticks()); + elapsed = now - iface_ctx.last_cts_time; + if (iface_ctx.last_cts_time <= 0) { + /* This is the first transition we have seen, continue */ + } else if (elapsed <= CONFIG_MODEM_HL7800_CTS_FILTER_US) { + /* CTS changed too quickly, ignore this transition */ + iface_ctx.last_cts_time = now; + return; + } + iface_ctx.last_cts_time = now; + k_busy_wait(CONFIG_MODEM_HL7800_CTS_FILTER_US); + resample_state = read_pin(0, &hl7800_cfg.gpio[MDM_UART_CTS]); + if (iface_ctx.cts_state != resample_state) { + /* CTS changed while we were debouncing, ignore it */ + iface_ctx.cts_state = resample_state; + return; + } + iface_ctx.cts_state = resample_state; + if (iface_ctx.cts_state != iface_ctx.last_cts_state) { + iface_ctx.last_cts_state = iface_ctx.cts_state; + } else { + return; } + HL7800_IO_DBG_LOG("MDM_UART_CTS:%d(%llu)", iface_ctx.cts_state, elapsed); + #ifdef CONFIG_MODEM_HL7800_LOW_POWER_MODE - if (iface_ctx.cts_state) { - /* HL7800 is not awake, shut down UART to save power */ - if (iface_ctx.allow_sleep) { - shutdown_uart(); - } + if (iface_ctx.cts_state && iface_ctx.allow_sleep) { + /* HL7800 cannot receive UART data, shut down UART to save power. + * This is critical for proper low power operation. If the UART is disabled + * after VGPIO is low, the UART will not suspend properly. + */ + shutdown_uart(); } else { if (iface_ctx.off) { return; } - if (iface_ctx.desired_sleep_level != HL7800_SLEEP_HIBERNATE) { + if (iface_ctx.vgpio_state && iface_ctx.gpio6_state) { power_on_uart(); - if (iface_ctx.sleep_state == HL7800_SLEEP_SLEEP) { - /* Wake up the modem to see if it has anything to send to us. */ - allow_sleep(false); - /* Allow the modem to go back to sleep if it was the one who - * sourced the CTS transition. - */ - allow_sleep(true); - } + /* Wake up the modem to see if it has anything to send to us. */ + allow_sleep(false); + /* Allow the modem to go back to sleep if it was the one who + * sourced the CTS transition. + */ + allow_sleep(true); } } #endif + if ((iface_ctx.cts_callback != NULL) && + (iface_ctx.desired_sleep_level == HL7800_SLEEP_SLEEP)) { + iface_ctx.cts_callback(iface_ctx.cts_state); + } + check_hl7800_awake(); } @@ -4950,7 +5034,7 @@ static void modem_reset(void) LOG_INF("Modem Reset"); /* Hard reset the modem */ - gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 1); + modem_assert_reset(true); /* >20 milliseconds required for reset low */ k_sleep(MDM_RESET_LOW_TIME); @@ -4973,10 +5057,10 @@ static void modem_reset(void) static void modem_run(void) { LOG_INF("Modem Run"); - gpio_pin_set_dt(&hl7800_cfg.gpio[MDM_RESET], 0); - k_sleep(MDM_RESET_HIGH_TIME); iface_ctx.off = false; + modem_assert_reset(false); allow_sleep(false); + k_sleep(MDM_RESET_HIGH_TIME); } static int modem_boot_handler(char *reason) @@ -4986,9 +5070,7 @@ static int modem_boot_handler(char *reason) LOG_DBG("%s", reason); ret = k_sem_take(&iface_ctx.mdm_awake, MDM_BOOT_TIME); if (ret) { - LOG_ERR("Err waiting for boot: %d, DSR: %u", ret, - iface_ctx.dsr_state); - return -1; + LOG_WRN("Err waiting for boot: %d, DSR: %u", ret, iface_ctx.dsr_state); } else { LOG_INF("Modem booted!"); } @@ -5172,6 +5254,7 @@ static int modem_reset_and_configure(void) "\",\"" CONFIG_MODEM_HL7800_PSM_ACTIVE_TIME "\""; #endif + set_busy(true); iface_ctx.restarting = true; iface_ctx.dns_ready = false; if (iface_ctx.iface) { @@ -5179,6 +5262,7 @@ static int modem_reset_and_configure(void) } hl7800_stop_rssi_work(); + initialize_sleep_level(); reboot: modem_reset(); @@ -5352,7 +5436,6 @@ static int modem_reset_and_configure(void) /* enable GPIO6 low power monitoring */ SEND_AT_CMD_EXPECT_OK("AT+KHWIOCFG=3,1,6"); - initialize_sleep_level(); ret = set_sleep_level(); if (ret < 0) { goto error; @@ -5453,7 +5536,7 @@ static int modem_reset_and_configure(void) SEND_COMPLEX_AT_CMD("AT+CEREG?"); /* Turn on EPS network registration status reporting */ - SEND_AT_CMD_EXPECT_OK("AT+CEREG=4"); + SEND_AT_CMD_EXPECT_OK("AT+CEREG=5"); /* query all socket configs to cleanup any sockets that are not * tracked by the driver @@ -5472,6 +5555,7 @@ static int modem_reset_and_configure(void) LOG_INF("Modem ready!"); iface_ctx.restarting = false; iface_ctx.configured = true; + set_busy(false); allow_sleep(sleep); /* trigger APN update event */ event_handler(HL7800_EVENT_APN_UPDATE, &iface_ctx.mdm_apn); @@ -5563,6 +5647,7 @@ static void mdm_power_off_work_callback(struct k_work *item) iface_ctx.dns_ready = false; iface_ctx.configured = false; iface_ctx.off = true; + set_busy(false); /* bring the iface down */ if (iface_ctx.iface) { net_if_carrier_off(iface_ctx.iface); @@ -5771,6 +5856,9 @@ static int reconfigure_IP_connection(void) /* query all UDP socket configs */ ret = send_at_cmd(NULL, "AT+KUDPCFG?", MDM_CMD_SEND_TIMEOUT, 0, false); + + /* TODO: to make this better, wait for +KUDP_IND or timeout */ + k_sleep(K_SECONDS(1)); } done: @@ -5811,18 +5899,18 @@ static int offload_get(sa_family_t family, enum net_sock_type type, wakeup_hl7800(); /* reconfig IP connection if necessary */ - if (reconfigure_IP_connection() < 0) { - socket_put(sock); - goto done; - } + (void)reconfigure_IP_connection(); - ret = configure_UDP_socket(sock); - if (ret < 0) { - socket_put(sock); - goto done; + if (!sock->created) { + ret = configure_UDP_socket(sock); + if (ret < 0) { + socket_put(sock); + goto done; + } } } done: + set_busy(false); allow_sleep(true); hl7800_unlock(); return ret; @@ -5947,6 +6035,7 @@ static int offload_connect(struct net_context *context, } done: + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -6010,6 +6099,7 @@ static int offload_sendto(struct net_pkt *pkt, const struct sockaddr *dst_addr, ret = send_data(sock, pkt); + set_busy(false); allow_sleep(true); hl7800_unlock(); @@ -6109,6 +6199,7 @@ static int offload_put(struct net_context *context) /* delete session */ delete_socket(sock, sock->type, sock->socket_id); } + set_busy(false); allow_sleep(true); socket_put(sock); @@ -6216,6 +6307,9 @@ static int hl7800_init(const struct device *dev) LOG_DBG("HL7800 Init"); + /* The UART starts in the on state and CTS is set low by the HL7800 */ + iface_ctx.cts_state = iface_ctx.last_cts_state = 0; + /* Prevent the network interface from starting until * the modem has been initialized * because the modem may not have a valid SIM card. @@ -6229,7 +6323,7 @@ static int hl7800_init(const struct device *dev) /* init sockets */ for (i = 0; i < MDM_MAX_SOCKETS; i++) { - iface_ctx.sockets[i].socket_id = -1; + iface_ctx.sockets[i].socket_id = MDM_INVALID_SOCKET_ID; k_work_init(&iface_ctx.sockets[i].recv_cb_work, sockreadrecv_cb_work); k_work_init(&iface_ctx.sockets[i].rx_data_work, @@ -6334,9 +6428,6 @@ static int hl7800_init(const struct device *dev) return ret; } - /* when this driver starts, the UART peripheral is already enabled */ - iface_ctx.uart_on = true; - modem_assert_wake(false); modem_assert_pwr_on(false); modem_assert_fast_shutd(false); @@ -6394,7 +6485,7 @@ static int hl7800_init(const struct device *dev) } /* UART CTS */ - gpio_init_callback(&iface_ctx.mdm_uart_cts_cb, mdm_uart_cts_callback, + gpio_init_callback(&iface_ctx.mdm_uart_cts_cb, mdm_uart_cts_callback_isr, BIT(hl7800_cfg.gpio[MDM_UART_CTS].pin)); ret = gpio_add_callback(hl7800_cfg.gpio[MDM_UART_CTS].port, &iface_ctx.mdm_uart_cts_cb); diff --git a/drivers/modem/modem_cellular.c b/drivers/modem/modem_cellular.c index c3b97f0b618..8aca855f55b 100644 --- a/drivers/modem/modem_cellular.c +++ b/drivers/modem/modem_cellular.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,23 @@ LOG_MODULE_REGISTER(modem_cellular, CONFIG_MODEM_LOG_LEVEL); #define MODEM_CELLULAR_PERIODIC_SCRIPT_TIMEOUT \ K_MSEC(CONFIG_MODEM_CELLULAR_PERIODIC_SCRIPT_MS) +#define MODEM_CELLULAR_DATA_IMEI_LEN (15) +#define MODEM_CELLULAR_DATA_MODEL_ID_LEN (64) +#define MODEM_CELLULAR_DATA_IMSI_LEN (22) +#define MODEM_CELLULAR_DATA_ICCID_LEN (22) +#define MODEM_CELLULAR_DATA_MANUFACTURER_LEN (64) +#define MODEM_CELLULAR_DATA_FW_VERSION_LEN (64) + +/* Magic constants */ +#define CSQ_RSSI_UNKNOWN (99) +#define CESQ_RSRP_UNKNOWN (255) +#define CESQ_RSRQ_UNKNOWN (255) + +/* Magic numbers to units conversions */ +#define CSQ_RSSI_TO_DB(v) (-113 + (2 * (rssi))) +#define CESQ_RSRP_TO_DB(v) (-140 + (v)) +#define CESQ_RSRQ_TO_DB(v) (-20 + ((v) / 2)) + enum modem_cellular_state { MODEM_CELLULAR_STATE_IDLE = 0, MODEM_CELLULAR_STATE_RESET_PULSE, @@ -83,11 +101,18 @@ struct modem_cellular_data { uint8_t *chat_argv[32]; /* Status */ - uint8_t imei[15]; - uint8_t hwinfo[64]; uint8_t registration_status_gsm; uint8_t registration_status_gprs; uint8_t registration_status_lte; + uint8_t rssi; + uint8_t rsrp; + uint8_t rsrq; + uint8_t imei[MODEM_CELLULAR_DATA_IMEI_LEN]; + uint8_t model_id[MODEM_CELLULAR_DATA_MODEL_ID_LEN]; + uint8_t imsi[MODEM_CELLULAR_DATA_IMSI_LEN]; + uint8_t iccid[MODEM_CELLULAR_DATA_ICCID_LEN]; + uint8_t manufacturer[MODEM_CELLULAR_DATA_MANUFACTURER_LEN]; + uint8_t fw_version[MODEM_CELLULAR_DATA_FW_VERSION_LEN]; /* PPP */ struct modem_ppp *ppp; @@ -114,6 +139,7 @@ struct modem_cellular_config { const uint16_t reset_pulse_duration_ms; const uint16_t startup_time_ms; const uint16_t shutdown_time_ms; + const bool autostarts; const struct modem_chat_script *init_chat_script; const struct modem_chat_script *dial_chat_script; const struct modem_chat_script *periodic_chat_script; @@ -275,16 +301,34 @@ static void modem_cellular_chat_on_imei(struct modem_chat *chat, char **argv, ui return; } - if (strlen(argv[1]) != 15) { + strncpy(data->imei, argv[1], sizeof(data->imei)); +} + +static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 2) { return; } - for (uint8_t i = 0; i < 15; i++) { - data->imei[i] = argv[1][i] - '0'; + strncpy(data->model_id, argv[1], sizeof(data->model_id)); +} + +static void modem_cellular_chat_on_cgmi(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 2) { + return; } + + strncpy(data->manufacturer, argv[1], sizeof(data->manufacturer)); } -static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, uint16_t argc, +static void modem_cellular_chat_on_cgmr(struct modem_chat *chat, char **argv, uint16_t argc, void *user_data) { struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; @@ -293,7 +337,40 @@ static void modem_cellular_chat_on_cgmm(struct modem_chat *chat, char **argv, ui return; } - strncpy(data->hwinfo, argv[1], sizeof(data->hwinfo) - 1); + strncpy(data->fw_version, argv[1], sizeof(data->fw_version)); +} + +static void modem_cellular_chat_on_csq(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 3) { + return; + } + + data->rssi = (uint8_t)atoi(argv[1]); +} + +static void modem_cellular_chat_on_cesq(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + if (argc != 7) { + return; + } + + data->rsrq = (uint8_t)atoi(argv[5]); + data->rsrp = (uint8_t)atoi(argv[6]); +} + +static void modem_cellular_chat_on_imsi(struct modem_chat *chat, char **argv, uint16_t argc, + void *user_data) +{ + struct modem_cellular_data *data = (struct modem_cellular_data *)user_data; + + strncpy(data->imsi, (char *)argv[1], sizeof(data->imsi)); } static bool modem_cellular_is_registered(struct modem_cellular_data *data) @@ -345,6 +422,11 @@ MODEM_CHAT_MATCHES_DEFINE(allow_match, MODEM_CHAT_MATCH_DEFINE(imei_match, "", "", modem_cellular_chat_on_imei); MODEM_CHAT_MATCH_DEFINE(cgmm_match, "", "", modem_cellular_chat_on_cgmm); +MODEM_CHAT_MATCH_DEFINE(csq_match, "+CSQ: ", ",", modem_cellular_chat_on_csq); +MODEM_CHAT_MATCH_DEFINE(cesq_match, "+CESQ: ", ",", modem_cellular_chat_on_cesq); +MODEM_CHAT_MATCH_DEFINE(cimi_match, "", "", modem_cellular_chat_on_imsi); +MODEM_CHAT_MATCH_DEFINE(cgmi_match, "", "", modem_cellular_chat_on_cgmi); +MODEM_CHAT_MATCH_DEFINE(cgmr_match, "", "", modem_cellular_chat_on_cgmr); MODEM_CHAT_MATCHES_DEFINE(unsol_matches, MODEM_CHAT_MATCH("+CREG: ", ",", modem_cellular_chat_on_cxreg), @@ -444,6 +526,11 @@ static void modem_cellular_idle_event_handler(struct modem_cellular_data *data, switch (evt) { case MODEM_CELLULAR_EVENT_RESUME: + if (config->autostarts) { + modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_AWAIT_POWER_ON); + break; + } + if (modem_cellular_gpio_is_enabled(&config->power_gpio)) { modem_cellular_enter_state(data, MODEM_CELLULAR_STATE_POWER_ON_PULSE); break; @@ -1177,6 +1264,153 @@ static void modem_cellular_cmux_handler(struct modem_cmux *cmux, enum modem_cmux } } +MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_csq_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(get_signal_csq_chat_script, get_signal_csq_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 2); + +static inline int modem_cellular_csq_parse_rssi(uint8_t rssi, int16_t *value) +{ + /* AT+CSQ returns a response +CSQ: , where: + * - rssi is a integer from 0 to 31 whose values describes a signal strength + * between -113 dBm for 0 and -51dbM for 31 or unknown for 99 + * - ber is an integer from 0 to 7 that describes the error rate, it can also + * be 99 for an unknown error rate + */ + if (rssi == CSQ_RSSI_UNKNOWN) { + return -EINVAL; + } + + *value = (int16_t)CSQ_RSSI_TO_DB(rssi); + return 0; +} + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(get_signal_cesq_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CESQ", cesq_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(get_signal_cesq_chat_script, get_signal_cesq_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 2); + +/* AT+CESQ returns a response +CESQ: ,,,,, where: + * - rsrq is a integer from 0 to 34 whose values describes the Reference Signal Receive + * Quality between -20 dB for 0 and -3 dB for 34 (0.5 dB steps), or unknown for 255 + * - rsrp is an integer from 0 to 97 that describes the Reference Signal Receive Power + * between -140 dBm for 0 and -44 dBm for 97 (1 dBm steps), or unknown for 255 + */ +static inline int modem_cellular_cesq_parse_rsrp(uint8_t rsrp, int16_t *value) +{ + if (rsrp == CESQ_RSRP_UNKNOWN) { + return -EINVAL; + } + + *value = (int16_t)CESQ_RSRP_TO_DB(rsrp); + return 0; +} + +static inline int modem_cellular_cesq_parse_rsrq(uint8_t rsrq, int16_t *value) +{ + if (rsrq == CESQ_RSRQ_UNKNOWN) { + return -EINVAL; + } + + *value = (int16_t)CESQ_RSRQ_TO_DB(rsrq); + return 0; +} + +static int modem_cellular_get_signal(const struct device *dev, + const enum cellular_signal_type type, + int16_t *value) +{ + int ret = -ENOTSUP; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + + if ((data->state != MODEM_CELLULAR_STATE_AWAIT_REGISTERED) && + (data->state != MODEM_CELLULAR_STATE_CARRIER_ON)) { + return -ENODATA; + } + + /* Run chat script */ + switch (type) { + case CELLULAR_SIGNAL_RSSI: + ret = modem_chat_run_script(&data->chat, &get_signal_csq_chat_script); + break; + + case CELLULAR_SIGNAL_RSRP: + case CELLULAR_SIGNAL_RSRQ: + ret = modem_chat_run_script(&data->chat, &get_signal_cesq_chat_script); + break; + + default: + ret = -ENOTSUP; + break; + } + + /* Verify chat script ran successfully */ + if (ret < 0) { + return ret; + } + + /* Parse received value */ + switch (type) { + case CELLULAR_SIGNAL_RSSI: + ret = modem_cellular_csq_parse_rssi(data->rssi, value); + break; + + case CELLULAR_SIGNAL_RSRP: + ret = modem_cellular_cesq_parse_rsrp(data->rsrp, value); + break; + + case CELLULAR_SIGNAL_RSRQ: + ret = modem_cellular_cesq_parse_rsrq(data->rsrq, value); + break; + + default: + ret = -ENOTSUP; + break; + } + + return ret; +} + +static int modem_cellular_get_modem_info(const struct device *dev, + enum cellular_modem_info_type type, + char *info, size_t size) +{ + int ret = 0; + struct modem_cellular_data *data = (struct modem_cellular_data *)dev->data; + + switch (type) { + case CELLULAR_MODEM_INFO_IMEI: + strncpy(info, &data->imei[0], MIN(size, sizeof(data->imei))); + break; + case CELLULAR_MODEM_INFO_SIM_IMSI: + strncpy(info, &data->imsi[0], MIN(size, sizeof(data->imsi))); + break; + case CELLULAR_MODEM_INFO_MANUFACTURER: + strncpy(info, &data->manufacturer[0], MIN(size, sizeof(data->manufacturer))); + break; + case CELLULAR_MODEM_INFO_FW_VERSION: + strncpy(info, &data->fw_version[0], MIN(size, sizeof(data->fw_version))); + break; + case CELLULAR_MODEM_INFO_MODEL_ID: + strncpy(info, &data->model_id[0], MIN(size, sizeof(data->model_id))); + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +const static struct cellular_driver_api modem_cellular_api = { + .get_signal = modem_cellular_get_signal, + .get_modem_info = modem_cellular_get_modem_info, +}; + #ifdef CONFIG_PM_DEVICE static int modem_cellular_pm_action(const struct device *dev, enum pm_device_action action) { @@ -1286,7 +1520,6 @@ static int modem_cellular_init(const struct device *dev) .argv_size = ARRAY_SIZE(data->chat_argv), .unsol_matches = unsol_matches, .unsol_matches_size = ARRAY_SIZE(unsol_matches), - .process_timeout = K_MSEC(2), }; modem_chat_init(&data->chat, &chat_config); @@ -1330,6 +1563,12 @@ MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_bg95_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127", 300)); MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_init_chat_script, quectel_bg95_init_chat_script_cmds, @@ -1357,21 +1596,27 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_bg95_periodic_chat_script, #endif #if DT_HAS_COMPAT_STATUS_OKAY(quectel_eg25_g) -MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_init_chat_script_cmds, - MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), - MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), - MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", - 100)); +MODEM_CHAT_SCRIPT_CMDS_DEFINE( + quectel_eg25_g_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT+CMUX=0,0,5,127,10,3,30,10,2", 100)); MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_init_chat_script, quectel_eg25_g_init_chat_script_cmds, abort_matches, modem_cellular_chat_callback_handler, 10); @@ -1390,7 +1635,8 @@ MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_dial_chat_script, quectel_eg25_g_dial_ch MODEM_CHAT_SCRIPT_CMDS_DEFINE(quectel_eg25_g_periodic_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), - MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CSQ", csq_match)); MODEM_CHAT_SCRIPT_DEFINE(quectel_eg25_g_periodic_chat_script, quectel_eg25_g_periodic_chat_script_cmds, abort_matches, @@ -1538,6 +1784,57 @@ MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r4_periodic_chat_script, modem_cellular_chat_callback_handler, 4); #endif +#if DT_HAS_COMPAT_STATUS_OKAY(u_blox_sara_r5) +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_init_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), + MODEM_CHAT_SCRIPT_CMD_RESP("ATE0", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=4", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMEE=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGSN", imei_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMM", cgmm_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMI", cgmi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGMR", cgmr_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CIMI", cimi_match), + MODEM_CHAT_SCRIPT_CMD_RESP("", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CMUX=0,0,5,127", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_init_chat_script, u_blox_sara_r5_init_chat_script_cmds, + abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_dial_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP_MULT("AT+CGACT=0,1", allow_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGDCONT=1,\"IP\"," + "\""CONFIG_MODEM_CELLULAR_APN"\"", + ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CFUN=1", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP_NONE("ATD*99***1#", 0),); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_dial_chat_script, u_blox_sara_r5_dial_chat_script_cmds, + dial_abort_matches, modem_cellular_chat_callback_handler, 10); + +MODEM_CHAT_SCRIPT_CMDS_DEFINE(u_blox_sara_r5_periodic_chat_script_cmds, + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEREG?", ok_match), + MODEM_CHAT_SCRIPT_CMD_RESP("AT+CGREG?", ok_match)); + +MODEM_CHAT_SCRIPT_DEFINE(u_blox_sara_r5_periodic_chat_script, + u_blox_sara_r5_periodic_chat_script_cmds, abort_matches, + modem_cellular_chat_callback_handler, 4); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(swir_hl7800) MODEM_CHAT_SCRIPT_CMDS_DEFINE(swir_hl7800_init_chat_script_cmds, MODEM_CHAT_SCRIPT_CMD_RESP_NONE("AT", 100), @@ -1657,14 +1954,15 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, .shutdown_time_ms = 5000, \ .init_chat_script = &quectel_bg95_init_chat_script, \ .dial_chat_script = &quectel_bg95_dial_chat_script, \ - .periodic_chat_script = &quectel_bg95_periodic_chat_script, \ + .periodic_chat_script = &_CONCAT(DT_DRV_COMPAT, _periodic_chat_script), \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_QUECTEL_EG25_G(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1692,7 +1990,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_GSM_PPP(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1720,7 +2019,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1748,7 +2048,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1776,7 +2077,38 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); + +#define MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5(inst) \ + MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ + \ + static struct modem_cellular_data MODEM_CELLULAR_INST_NAME(data, inst) = { \ + .chat_delimiter = {'\r'}, \ + .chat_filter = {'\n'}, \ + .ppp = &MODEM_CELLULAR_INST_NAME(ppp, inst), \ + }; \ + \ + static struct modem_cellular_config MODEM_CELLULAR_INST_NAME(config, inst) = { \ + .uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .power_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_power_gpios, {}), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mdm_reset_gpios, {}), \ + .autostarts = true, \ + .power_pulse_duration_ms = 1500, \ + .reset_pulse_duration_ms = 100, \ + .startup_time_ms = 1500, \ + .shutdown_time_ms = 13000, \ + .init_chat_script = &u_blox_sara_r5_init_chat_script, \ + .dial_chat_script = &u_blox_sara_r5_dial_chat_script, \ + .periodic_chat_script = &u_blox_sara_r5_periodic_chat_script, \ + }; \ + \ + PM_DEVICE_DT_INST_DEFINE(inst, modem_cellular_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ + &MODEM_CELLULAR_INST_NAME(data, inst), \ + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_SWIR_HL7800(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1804,7 +2136,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define MODEM_CELLULAR_DEVICE_TELIT_ME910G1(inst) \ MODEM_PPP_DEFINE(MODEM_CELLULAR_INST_NAME(ppp, inst), NULL, 98, 1500, 64); \ @@ -1832,7 +2165,8 @@ MODEM_CHAT_SCRIPT_DEFINE(telit_me910g1_periodic_chat_script, \ DEVICE_DT_INST_DEFINE(inst, modem_cellular_init, PM_DEVICE_DT_INST_GET(inst), \ &MODEM_CELLULAR_INST_NAME(data, inst), \ - &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, NULL); + &MODEM_CELLULAR_INST_NAME(config, inst), POST_KERNEL, 99, \ + &modem_cellular_api); #define DT_DRV_COMPAT quectel_bg95 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_QUECTEL_BG95) @@ -1854,6 +2188,10 @@ DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SIMCOM_SIM7080) DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R4) #undef DT_DRV_COMPAT +#define DT_DRV_COMPAT u_blox_sara_r5 +DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_U_BLOX_SARA_R5) +#undef DT_DRV_COMPAT + #define DT_DRV_COMPAT swir_hl7800 DT_INST_FOREACH_STATUS_OKAY(MODEM_CELLULAR_DEVICE_SWIR_HL7800) #undef DT_DRV_COMPAT diff --git a/drivers/modem/simcom-sim7080.c b/drivers/modem/simcom-sim7080.c index f0b31a1d1b6..266558469fc 100644 --- a/drivers/modem/simcom-sim7080.c +++ b/drivers/modem/simcom-sim7080.c @@ -750,7 +750,7 @@ static int offload_getaddrinfo(const char *node, const char *service, static void offload_freeaddrinfo(struct zsock_addrinfo *res) { /* No need to free static memory. */ - res = NULL; + ARG_UNUSED(res); } /* diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f6e0faa334a..c83f0f42a08 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -94,11 +94,12 @@ config PPP_NET_IF_NO_AUTO_START if NET_PPP_ASYNC_UART config NET_PPP_ASYNC_UART_TX_BUF_LEN - int "Buffer length from where the write to async UART is done" + int "Length of the UART TX buffer to which data is written." default 2048 - help - This options sets the size of the UART TX buffer where data - is being written from to UART. + +config NET_PPP_ASYNC_UART_TX_TIMEOUT + int "The timeout for UART transfers in milliseconds, or 0 for no timeout." + default 0 config NET_PPP_ASYNC_UART_RX_RECOVERY_TIMEOUT int "UART RX recovery timeout in milliseconds" @@ -111,10 +112,6 @@ config NET_PPP_ASYNC_UART_RX_ENABLE_TIMEOUT int "A timeout for uart_rx_enable() in milliseconds" default 100 -config NET_PPP_ASYNC_UART_TX_TIMEOUT - int "A timeout for uart_tx() in milliseconds" - default 100 - endif # NET_PPP_ASYNC_UART module = NET_PPP diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index d8ae5ca1b05..2695875ae27 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -110,26 +110,6 @@ static int loopback_send(const struct device *dev, struct net_pkt *pkt) return -ENODATA; } - /* We need to swap the IP addresses because otherwise - * the packet will be dropped. - */ - - if (net_pkt_family(pkt) == AF_INET6) { - struct in6_addr addr; - - net_ipv6_addr_copy_raw((uint8_t *)&addr, NET_IPV6_HDR(pkt)->src); - net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->src, - NET_IPV6_HDR(pkt)->dst); - net_ipv6_addr_copy_raw(NET_IPV6_HDR(pkt)->dst, (uint8_t *)&addr); - } else { - struct in_addr addr; - - net_ipv4_addr_copy_raw((uint8_t *)&addr, NET_IPV4_HDR(pkt)->src); - net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->src, - NET_IPV4_HDR(pkt)->dst); - net_ipv4_addr_copy_raw(NET_IPV4_HDR(pkt)->dst, (uint8_t *)&addr); - } - /* We should simulate normal driver meaning that if the packet is * properly sent (which is always in this driver), then the packet * must be dropped. This is very much needed for TCP packets where @@ -141,6 +121,21 @@ static int loopback_send(const struct device *dev, struct net_pkt *pkt) goto out; } + /* We need to swap the IP addresses because otherwise + * the packet will be dropped. + */ + if (net_pkt_family(pkt) == AF_INET6) { + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->src, + NET_IPV6_HDR(pkt)->dst); + net_ipv6_addr_copy_raw(NET_IPV6_HDR(cloned)->dst, + NET_IPV6_HDR(pkt)->src); + } else { + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->src, + NET_IPV4_HDR(pkt)->dst); + net_ipv4_addr_copy_raw(NET_IPV4_HDR(cloned)->dst, + NET_IPV4_HDR(pkt)->src); + } + res = net_recv_data(net_pkt_iface(cloned), cloned); if (res < 0) { LOG_ERR("Data receive failed."); diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index ecfdb7c3af1..70fbe9631a5 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -121,14 +121,34 @@ static void uart_callback(const struct device *dev, switch (evt->type) { case UART_TX_DONE: - LOG_DBG("UART_TX_DONE: sent %d bytes", evt->data.tx.len); + LOG_DBG("UART_TX_DONE: sent %zu bytes", evt->data.tx.len); k_sem_give(&uarte_tx_finished); break; case UART_TX_ABORTED: - LOG_DBG("Tx aborted"); + { k_sem_give(&uarte_tx_finished); + if (CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT == 0) { + LOG_WRN("UART TX aborted."); + break; + } + struct uart_config uart_conf; + + err = uart_config_get(dev, &uart_conf); + if (err) { + LOG_ERR("uart_config_get() err: %d", err); + } else if (uart_conf.baudrate / 10 * CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT + / MSEC_PER_SEC > evt->data.tx.len * 2) { + /* The abort likely did not happen because of missing bandwidth. */ + LOG_DBG("UART_TX_ABORTED"); + } else { + LOG_WRN("UART TX aborted: Only %zu bytes were sent. You may want" + " to change either CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT" + " (%d ms) or the UART baud rate (%u).", evt->data.tx.len, + CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT, uart_conf.baudrate); + } break; + } case UART_RX_RDY: len = evt->data.rx.len; @@ -171,7 +191,7 @@ static void uart_callback(const struct device *dev, case UART_RX_BUF_REQUEST: { - LOG_DBG("UART_RX_BUF_REQUEST: buf %p", next_buf); + LOG_DBG("UART_RX_BUF_REQUEST: buf %p", (void *)next_buf); if (next_buf) { err = uart_rx_buf_rsp(dev, next_buf, sizeof(context->buf)); @@ -185,7 +205,7 @@ static void uart_callback(const struct device *dev, case UART_RX_BUF_RELEASED: next_buf = evt->data.rx_buf.buf; - LOG_DBG("UART_RX_BUF_RELEASED: buf %p", next_buf); + LOG_DBG("UART_RX_BUF_RELEASED: buf %p", (void *)next_buf); break; case UART_RX_DISABLED: @@ -243,7 +263,7 @@ static void uart_recovery(struct k_work *work) if (ret) { LOG_ERR("ppp_async_uart_rx_enable() failed, err %d", ret); } else { - LOG_WRN("UART RX recovered"); + LOG_DBG("UART RX recovered."); } uart_recovery_pending = false; } else { @@ -368,11 +388,13 @@ static int ppp_send_flush(struct ppp_driver_context *ppp, int off) } else if (IS_ENABLED(CONFIG_NET_PPP_ASYNC_UART)) { #if defined(CONFIG_NET_PPP_ASYNC_UART) int ret; + const int32_t timeout = CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT + ? CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT * USEC_PER_MSEC + : SYS_FOREVER_US; k_sem_take(&uarte_tx_finished, K_FOREVER); - ret = uart_tx(ppp->dev, buf, off, - CONFIG_NET_PPP_ASYNC_UART_TX_TIMEOUT * USEC_PER_MSEC); + ret = uart_tx(ppp->dev, buf, off, timeout); if (ret) { LOG_ERR("uart_tx() failed, err %d", ret); k_sem_give(&uarte_tx_finished); @@ -1027,7 +1049,7 @@ static int ppp_start(const struct device *dev) /* dts chosen zephyr,ppp-uart case */ context->dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ppp_uart)); #endif - LOG_INF("Initializing PPP to use %s", context->dev->name); + LOG_DBG("Initializing PPP to use %s", context->dev->name); if (!device_is_ready(context->dev)) { LOG_ERR("Device %s is not ready", context->dev->name); @@ -1056,6 +1078,9 @@ static int ppp_stop(const struct device *dev) struct ppp_driver_context *context = dev->data; net_if_carrier_off(context->iface); +#if defined(CONFIG_NET_PPP_ASYNC_UART) + uart_rx_disable(context->dev); +#endif context->modem_init_done = false; return 0; } diff --git a/drivers/pcie/host/pcie.c b/drivers/pcie/host/pcie.c index a4d9fdbe504..0a98d8e8e06 100644 --- a/drivers/pcie/host/pcie.c +++ b/drivers/pcie/host/pcie.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define DT_DRV_COMPAT pcie_controller + #include LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); @@ -28,6 +30,11 @@ LOG_MODULE_REGISTER(pcie, LOG_LEVEL_ERR); #include #endif +#ifdef CONFIG_PCIE_PRT +/* platform interrupt are hardwired or can be dynamically allocated. */ +static bool prt_en; +#endif + /* functions documented in drivers/pcie/pcie.h */ bool pcie_probe(pcie_bdf_t bdf, pcie_id_t id) @@ -126,6 +133,8 @@ static bool pcie_get_bar(pcie_bdf_t bdf, bool io) { uint32_t reg = bar_index + PCIE_CONF_BAR0; + uint32_t cmd_reg; + bool ret = false; #ifdef CONFIG_PCIE_CONTROLLER const struct device *dev; #endif @@ -156,6 +165,12 @@ static bool pcie_get_bar(pcie_bdf_t bdf, return false; } + cmd_reg = pcie_conf_read(bdf, PCIE_CONF_CMDSTAT); + + /* IO/memory decode should be disabled before sizing/update BAR. */ + pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, + cmd_reg & (~(PCIE_CONF_CMDSTAT_IO | PCIE_CONF_CMDSTAT_MEM))); + pcie_conf_write(bdf, reg, 0xFFFFFFFFU); size = pcie_conf_read(bdf, reg); pcie_conf_write(bdf, reg, (uint32_t)phys_addr); @@ -167,7 +182,7 @@ static bool pcie_get_bar(pcie_bdf_t bdf, if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL64 || PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { /* Discard on invalid address */ - return false; + goto err_exit; } pcie_conf_write(bdf, reg, 0xFFFFFFFFU); @@ -176,20 +191,20 @@ static bool pcie_get_bar(pcie_bdf_t bdf, } else if (PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_INVAL || PCIE_CONF_BAR_ADDR(phys_addr) == PCIE_CONF_BAR_NONE) { /* Discard on invalid address */ - return false; + goto err_exit; } if (PCIE_CONF_BAR_IO(phys_addr)) { size = PCIE_CONF_BAR_IO_ADDR(size); if (size == 0) { /* Discard on invalid size */ - return false; + goto err_exit; } } else { size = PCIE_CONF_BAR_ADDR(size); if (size == 0) { /* Discard on invalid size */ - return false; + goto err_exit; } } @@ -201,14 +216,18 @@ static bool pcie_get_bar(pcie_bdf_t bdf, PCIE_CONF_BAR_ADDR(phys_addr) : PCIE_CONF_BAR_IO_ADDR(phys_addr), &bar->phys_addr)) { - return false; + goto err_exit; } #else bar->phys_addr = PCIE_CONF_BAR_ADDR(phys_addr); #endif /* CONFIG_PCIE_CONTROLLER */ bar->size = size & ~(size-1); - return true; + ret = true; +err_exit: + pcie_conf_write(bdf, PCIE_CONF_CMDSTAT, cmd_reg); + + return ret; } /** @@ -291,8 +310,16 @@ unsigned int pcie_alloc_irq(pcie_bdf_t bdf) irq >= CONFIG_MAX_IRQ_LINES || arch_irq_is_used(irq)) { + /* In some platforms, PCI interrupts are hardwired to specific interrupt inputs + * on the interrupt controller and are not configurable. Hence we need to retrieve + * IRQ from acpi. But if it is configurable then we allocate irq dynamically. + */ #ifdef CONFIG_PCIE_PRT - irq = acpi_legacy_irq_get(bdf); + if (prt_en) { + irq = acpi_legacy_irq_get(bdf); + } else { + irq = arch_irq_allocate(); + } #else irq = arch_irq_allocate(); #endif @@ -533,6 +560,21 @@ static int pcie_init(void) .flags = PCIE_SCAN_RECURSIVE, }; +#ifdef CONFIG_PCIE_PRT + const char *hid, *uid = ACPI_DT_UID(DT_DRV_INST(0)); + int ret; + + BUILD_ASSERT(ACPI_DT_HAS_HID(DT_DRV_INST(0)), + "No HID property for PCIe devicetree node"); + hid = ACPI_DT_HID(DT_DRV_INST(0)); + + ret = acpi_legacy_irq_init(hid, uid); + if (!ret) { + prt_en = true; + } else { + __ASSERT(ret == -ENOENT, "Error retrieve interrupt routing table!"); + } +#endif STRUCT_SECTION_COUNT(pcie_dev, &data.max_dev); /* Don't bother calling pcie_scan() if there are no devices to look for */ diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index 9455b6e7c78..9f104c6e323 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -26,6 +26,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_ESP32 pinctrl_esp32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RV32M1 pinctrl_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_INFINEON_CAT1 pinctrl_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_XLNX_ZYNQ pinctrl_xlnx_zynq.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_XLNX_ZYNQMP pinctrl_xlnx_zynqmp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SMARTBOND pinctrl_smartbond.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_XMC4XXX pinctrl_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NXP_S32 pinctrl_nxp_s32.c) @@ -35,6 +36,6 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_EMSDP pinctrl_emsdp.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_TI_CC32XX pinctrl_ti_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NUMAKER pinctrl_numaker.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_QUICKLOGIC_EOS_S3 pinctrl_eos_s3.c) -zephyr_library_sources_ifdef(CONFIG_PINCTRL_RA pinctrl_ra.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_RENESAS_RA pinctrl_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX_SCU pinctrl_imx_scu.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RZT2M pinctrl_rzt2m.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8a165725e4d..f03af874bbf 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -64,7 +64,8 @@ source "drivers/pinctrl/Kconfig.emsdp" source "drivers/pinctrl/Kconfig.ti_cc32xx" source "drivers/pinctrl/Kconfig.numaker" source "drivers/pinctrl/Kconfig.eos_s3" -source "drivers/pinctrl/Kconfig.ra" +source "drivers/pinctrl/Kconfig.renesas_ra" source "drivers/pinctrl/Kconfig.rzt2m" +source "drivers/pinctrl/Kconfig.zynqmp" endif # PINCTRL diff --git a/drivers/pinctrl/Kconfig.ra b/drivers/pinctrl/Kconfig.ra deleted file mode 100644 index 6ad0ebd8c06..00000000000 --- a/drivers/pinctrl/Kconfig.ra +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 TOKITA Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -config PINCTRL_RA - bool "Renesas RA series pin controller driver" - default y - depends on DT_HAS_RENESAS_RA_PINCTRL_ENABLED - help - Enable Renesas RA series pin controller driver. diff --git a/drivers/pinctrl/Kconfig.rcar b/drivers/pinctrl/Kconfig.rcar index 5aabd54371d..cc3ff51b9d6 100644 --- a/drivers/pinctrl/Kconfig.rcar +++ b/drivers/pinctrl/Kconfig.rcar @@ -7,3 +7,8 @@ config PINCTRL_RCAR_PFC depends on DT_HAS_RENESAS_RCAR_PFC_ENABLED help Enable pin controller driver for Renesas RCar SoC + +config PINCTRL_RCAR_VOLTAGE_CONTROL + bool "Voltage control functionality of Renesas R-Car PFC driver" + default y if SOC_SERIES_RCAR_GEN3 + depends on PINCTRL_RCAR_PFC diff --git a/drivers/pinctrl/Kconfig.renesas_ra b/drivers/pinctrl/Kconfig.renesas_ra new file mode 100644 index 00000000000..6f3c301d07b --- /dev/null +++ b/drivers/pinctrl/Kconfig.renesas_ra @@ -0,0 +1,9 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_RENESAS_RA + bool "Renesas RA series pin controller driver" + default y + depends on DT_HAS_RENESAS_RA_PINCTRL_ENABLED + help + Enable Renesas RA series pin controller driver. diff --git a/drivers/pinctrl/Kconfig.zynqmp b/drivers/pinctrl/Kconfig.zynqmp new file mode 100644 index 00000000000..10e9b110584 --- /dev/null +++ b/drivers/pinctrl/Kconfig.zynqmp @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_XLNX_ZYNQMP + bool "Xilinx ZynqMP pin controller driver" + default y + depends on DT_HAS_XLNX_PINCTRL_ZYNQMP_ENABLED + help + Enable the Xilinx ZynqMP processor system MIO pin controller driver. diff --git a/drivers/pinctrl/pfc_rcar.c b/drivers/pinctrl/pfc_rcar.c index 17705e0a863..ad10b03fda0 100644 --- a/drivers/pinctrl/pfc_rcar.c +++ b/drivers/pinctrl/pfc_rcar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,6 +7,7 @@ #define DT_DRV_COMPAT renesas_rcar_pfc +#include "pfc_rcar.h" #include #include #include @@ -14,12 +15,37 @@ #include #include -DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); - -#define PFC_REG_BASE DEVICE_MMIO_TOPLEVEL_GET(pfc) #define PFC_RCAR_PMMR 0x0 + +/* Gen3 only has one base address, Gen4 has one per GPIO controller */ +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) #define PFC_RCAR_GPSR 0x100 #define PFC_RCAR_IPSR 0x200 +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) +#define PFC_RCAR_GPSR 0x040 +#define PFC_RCAR_IPSR 0x060 +#else +#error Unsupported SoC Series +#endif + +/* swap both arguments */ +#define PFC_REG_ADDRESS(idx, inst) DT_INST_REG_ADDR_BY_IDX(inst, idx) +static uintptr_t reg_base[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_ADDRESS, (,), 0) +}; + +#define PFC_REG_SIZE(idx, inst) DT_INST_REG_SIZE_BY_IDX(inst, idx) +static const uintptr_t __maybe_unused reg_sizes[] = { + LISTIFY(DT_NUM_REGS(DT_DRV_INST(0)), PFC_REG_SIZE, (,), 0) +}; + +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL +/* POC Control Register can control IO voltage level that is supplied to the pin */ +struct pfc_pocctrl_reg { + uint32_t offset; + const uint16_t pins[32]; +}; +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ /* * Each drive step is either encoded in 2 or 3 bits. @@ -33,18 +59,25 @@ DEVICE_MMIO_TOPLEVEL_STATIC(pfc, DT_DRV_INST(0)); /* Some registers such as IPSR GPSR or DRVCTRL are protected and * must be preceded to a write to PMMR with the inverse value. */ -static void pfc_rcar_write(uint32_t offs, uint32_t val) +static void pfc_rcar_write(uintptr_t pfc_base, uint32_t offs, uint32_t val) { - sys_write32(~val, PFC_REG_BASE + PFC_RCAR_PMMR); - sys_write32(val, PFC_REG_BASE + offs); + sys_write32(~val, pfc_base + PFC_RCAR_PMMR); + sys_write32(val, pfc_base + offs); } /* Set the pin either in gpio or peripheral */ -static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) +static void pfc_rcar_set_gpsr(uintptr_t pfc_base, + uint16_t pin, bool peripheral) { +#if defined(CONFIG_SOC_SERIES_RCAR_GEN3) + /* On Gen3 we have multiple GPSR at one base address */ uint8_t bank = pin / 32; +#elif defined(CONFIG_SOC_SERIES_RCAR_GEN4) + /* On Gen4 we have one GPSR at multiple base address */ + uint8_t bank = 0; +#endif uint8_t bit = pin % 32; - uint32_t val = sys_read32(PFC_REG_BASE + PFC_RCAR_GPSR + + uint32_t val = sys_read32(pfc_base + PFC_RCAR_GPSR + bank * sizeof(uint32_t)); if (peripheral) { @@ -52,18 +85,19 @@ static void pfc_rcar_set_gpsr(uint16_t pin, bool peripheral) } else { val &= ~BIT(bit); } - pfc_rcar_write(PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); + pfc_rcar_write(pfc_base, PFC_RCAR_GPSR + bank * sizeof(uint32_t), val); } /* Set peripheral function */ -static void pfc_rcar_set_ipsr(const struct rcar_pin_func *rcar_func) +static void pfc_rcar_set_ipsr(uintptr_t pfc_base, + const struct rcar_pin_func *rcar_func) { uint16_t reg_offs = PFC_RCAR_IPSR + rcar_func->bank * sizeof(uint32_t); - uint32_t val = sys_read32(PFC_REG_BASE + reg_offs); + uint32_t val = sys_read32(pfc_base + reg_offs); val &= ~(0xFU << rcar_func->shift); val |= (rcar_func->func << rcar_func->shift); - pfc_rcar_write(reg_offs, val); + pfc_rcar_write(pfc_base, reg_offs, val); } static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, @@ -90,7 +124,8 @@ static uint32_t pfc_rcar_get_drive_reg(uint16_t pin, uint8_t *offset, * using DRVCTRLx registers, some pins have 8 steps (3 bits size encoded) * some have 4 steps (2 bits size encoded). */ -static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) +static int pfc_rcar_set_drive_strength(uintptr_t pfc_base, uint16_t pin, + uint8_t strength) { uint8_t offset, size, step; uint32_t reg, val; @@ -110,11 +145,11 @@ static int pfc_rcar_set_drive_strength(uint16_t pin, uint8_t strength) */ strength = (strength / step) - 1U; /* clear previous drive strength value */ - val = sys_read32(PFC_REG_BASE + reg); + val = sys_read32(pfc_base + reg); val &= ~GENMASK(offset + size - 1U, offset); val |= strength << offset; - pfc_rcar_write(reg, val); + pfc_rcar_write(pfc_base, reg, val); return 0; } @@ -138,7 +173,7 @@ static const struct pfc_bias_reg *pfc_rcar_get_bias_reg(uint16_t pin, return NULL; } -int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) +int pfc_rcar_set_bias(uintptr_t pfc_base, uint16_t pin, uint16_t flags) { uint32_t val; uint8_t bit; @@ -149,45 +184,168 @@ int pfc_rcar_set_bias(uint16_t pin, uint16_t flags) } /* pull enable/disable*/ - val = sys_read32(PFC_REG_BASE + bias_reg->puen); + val = sys_read32(pfc_base + bias_reg->puen); if ((flags & RCAR_PIN_FLAGS_PUEN) == 0U) { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->puen); return 0; } - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->puen); + sys_write32(val | BIT(bit), pfc_base + bias_reg->puen); /* pull - up/down */ - val = sys_read32(PFC_REG_BASE + bias_reg->pud); + val = sys_read32(pfc_base + bias_reg->pud); if (flags & RCAR_PIN_FLAGS_PUD) { - sys_write32(val | BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val | BIT(bit), pfc_base + bias_reg->pud); } else { - sys_write32(val & ~BIT(bit), PFC_REG_BASE + bias_reg->pud); + sys_write32(val & ~BIT(bit), pfc_base + bias_reg->pud); } return 0; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + +const struct pfc_pocctrl_reg pfc_r8a77951_r8a77961_volt_regs[] = { + { + .offset = 0x0380, + .pins = { + [0] = RCAR_GP_PIN(3, 0), /* SD0_CLK */ + [1] = RCAR_GP_PIN(3, 1), /* SD0_CMD */ + [2] = RCAR_GP_PIN(3, 2), /* SD0_DAT0 */ + [3] = RCAR_GP_PIN(3, 3), /* SD0_DAT1 */ + [4] = RCAR_GP_PIN(3, 4), /* SD0_DAT2 */ + [5] = RCAR_GP_PIN(3, 5), /* SD0_DAT3 */ + [6] = RCAR_GP_PIN(3, 6), /* SD1_CLK */ + [7] = RCAR_GP_PIN(3, 7), /* SD1_CMD */ + [8] = RCAR_GP_PIN(3, 8), /* SD1_DAT0 */ + [9] = RCAR_GP_PIN(3, 9), /* SD1_DAT1 */ + [10] = RCAR_GP_PIN(3, 10), /* SD1_DAT2 */ + [11] = RCAR_GP_PIN(3, 11), /* SD1_DAT3 */ + [12] = RCAR_GP_PIN(4, 0), /* SD2_CLK */ + [13] = RCAR_GP_PIN(4, 1), /* SD2_CMD */ + [14] = RCAR_GP_PIN(4, 2), /* SD2_DAT0 */ + [15] = RCAR_GP_PIN(4, 3), /* SD2_DAT1 */ + [16] = RCAR_GP_PIN(4, 4), /* SD2_DAT2 */ + [17] = RCAR_GP_PIN(4, 5), /* SD2_DAT3 */ + [18] = RCAR_GP_PIN(4, 6), /* SD2_DS */ + [19] = RCAR_GP_PIN(4, 7), /* SD3_CLK */ + [20] = RCAR_GP_PIN(4, 8), /* SD3_CMD */ + [21] = RCAR_GP_PIN(4, 9), /* SD3_DAT0 */ + [22] = RCAR_GP_PIN(4, 10), /* SD3_DAT1 */ + [23] = RCAR_GP_PIN(4, 11), /* SD3_DAT2 */ + [24] = RCAR_GP_PIN(4, 12), /* SD3_DAT3 */ + [25] = RCAR_GP_PIN(4, 13), /* SD3_DAT4 */ + [26] = RCAR_GP_PIN(4, 14), /* SD3_DAT5 */ + [27] = RCAR_GP_PIN(4, 15), /* SD3_DAT6 */ + [28] = RCAR_GP_PIN(4, 16), /* SD3_DAT7 */ + [29] = RCAR_GP_PIN(4, 17), /* SD3_DS */ + [30] = -1, + [31] = -1, + } + }, + { /* sentinel */ }, +}; + +static const struct pfc_pocctrl_reg *pfc_rcar_get_io_voltage_regs(void) +{ + return pfc_r8a77951_r8a77961_volt_regs; +} + +static const struct pfc_pocctrl_reg *pfc_rcar_get_pocctrl_reg(uint16_t pin, uint8_t *bit) +{ + const struct pfc_pocctrl_reg *voltage_regs = pfc_rcar_get_io_voltage_regs(); + + BUILD_ASSERT(ARRAY_SIZE(voltage_regs->pins) < UINT8_MAX); + + /* Loop around all the registers to find the bit for a given pin */ + while (voltage_regs && voltage_regs->offset) { + uint8_t i; + + for (i = 0U; i < ARRAY_SIZE(voltage_regs->pins); i++) { + if (voltage_regs->pins[i] == pin) { + *bit = i; + return voltage_regs; + } + } + voltage_regs++; + } + + return NULL; +} + +static void pfc_rcar_set_voltage(uintptr_t pfc_base, uint16_t pin, uint16_t voltage) +{ + uint32_t val; + uint8_t bit; + const struct pfc_pocctrl_reg *voltage_reg; + + voltage_reg = pfc_rcar_get_pocctrl_reg(pin, &bit); + if (!voltage_reg) { + return; + } + + val = sys_read32(pfc_base + voltage_reg->offset); + + switch (voltage) { + case PIN_VOLTAGE_1P8V: + if (!(val & BIT(bit))) { + return; + } + val &= ~BIT(bit); + break; + case PIN_VOLTAGE_3P3V: + if (val & BIT(bit)) { + return; + } + val |= BIT(bit); + break; + default: + break; + } + + pfc_rcar_write(pfc_base, voltage_reg->offset, val); +} +#endif /* CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL */ + int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) { int ret = 0; + uint8_t reg_index; + uintptr_t pfc_base; + + ret = pfc_rcar_get_reg_index(pin->pin, ®_index); + if (ret) { + return ret; + } + + if (reg_index >= ARRAY_SIZE(reg_base)) { + return -EINVAL; + } + + pfc_base = reg_base[reg_index]; /* Set pin as GPIO if capable */ if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, false); + pfc_rcar_set_gpsr(pfc_base, pin->pin, false); } else if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) == 0U) { /* A function must be set for non GPIO capable pin */ return -EINVAL; } +#ifdef CONFIG_PINCTRL_RCAR_VOLTAGE_CONTROL + if (pin->voltage != PIN_VOLTAGE_NONE) { + pfc_rcar_set_voltage(pfc_base, pin->pin, pin->voltage); + } +#endif + /* Select function for pin */ if ((pin->flags & RCAR_PIN_FLAGS_FUNC_SET) != 0U) { - pfc_rcar_set_ipsr(&pin->func); + pfc_rcar_set_ipsr(pfc_base, &pin->func); if (RCAR_IS_GP_PIN(pin->pin)) { - pfc_rcar_set_gpsr(pin->pin, true); + pfc_rcar_set_gpsr(pfc_base, pin->pin, true); } if ((pin->flags & RCAR_PIN_FLAGS_PULL_SET) != 0U) { - ret = pfc_rcar_set_bias(pin->pin, pin->flags); + ret = pfc_rcar_set_bias(pfc_base, pin->pin, pin->flags); if (ret < 0) { return ret; } @@ -195,7 +353,7 @@ int pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) } if (pin->drive_strength != 0U) { - ret = pfc_rcar_set_drive_strength(pin->pin, + ret = pfc_rcar_set_drive_strength(pfc_base, pin->pin, pin->drive_strength); } @@ -218,10 +376,14 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, return ret; } +#if defined(DEVICE_MMIO_IS_IN_RAM) __boot_func static int pfc_rcar_driver_init(void) { - DEVICE_MMIO_TOPLEVEL_MAP(pfc, K_MEM_CACHE_NONE); + for (unsigned int i = 0; i < ARRAY_SIZE(reg_base); i++) { + device_map(reg_base + i, reg_base[i], reg_sizes[i], K_MEM_CACHE_NONE); + } return 0; } SYS_INIT(pfc_rcar_driver_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +#endif diff --git a/drivers/pinctrl/pfc_rcar.h b/drivers/pinctrl/pfc_rcar.h new file mode 100644 index 00000000000..cbef35ff76b --- /dev/null +++ b/drivers/pinctrl/pfc_rcar.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ +#define ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ + +#include +#include + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); + +/** + * @brief set the register index for a given pin + * + * @param the pin + * @param pointer for the resulting register index + * @return 0 if the register index is found, negative + * errno otherwise. + */ +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index); + +#endif /* ZEPHYR_DRIVERS_PINCTRL_PFC_RCAR_H_ */ diff --git a/drivers/pinctrl/pinctrl_ite_it8xxx2.c b/drivers/pinctrl/pinctrl_ite_it8xxx2.c index 886a035483f..33ed9130b62 100644 --- a/drivers/pinctrl/pinctrl_ite_it8xxx2.c +++ b/drivers/pinctrl/pinctrl_ite_it8xxx2.c @@ -144,22 +144,27 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) return -EINVAL; } + /* + * Default input mode prevents leakage during changes to extended + * setting (e.g. enabling i2c functionality on GPIO E1/E2 on IT82002) + */ + *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & + ~GPCR_PORT_PIN_MODE_OUTPUT; + /* * If pincfg is input, we don't need to handle * alternate function. */ if (IT8XXX2_DT_PINCFG_INPUT(pins->pincfg)) { - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & - ~GPCR_PORT_PIN_MODE_OUTPUT; return 0; } /* * Handle alternate function. */ - /* Common settings for alternate function. */ - *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | - GPCR_PORT_PIN_MODE_OUTPUT); + if (reg_func3_gcr != NULL) { + *reg_func3_gcr &= ~gpio->func3_en_mask[pin]; + } /* Ensure that func3-ext setting is in default state. */ if (reg_func3_ext != NULL) { *reg_func3_ext &= ~gpio->func3_ext_mask[pin]; @@ -167,19 +172,19 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) switch (pins->alt_func) { case IT8XXX2_ALT_FUNC_1: - /* Func1: Alternate function has been set above. */ + /* Func1: Alternate function will be set below. */ break; case IT8XXX2_ALT_FUNC_2: - /* Func2: WUI function: turn the pin into an input */ - *reg_gpcr |= GPCR_PORT_PIN_MODE_INPUT; - break; + /* Func2: WUI function: pin has been set as input above.*/ + return 0; case IT8XXX2_ALT_FUNC_3: /* * Func3: In addition to the alternate setting above, * Func3 also need to set the general control. */ - *reg_func3_gcr |= gpio->func3_en_mask[pin]; - + if (reg_func3_gcr != NULL) { + *reg_func3_gcr |= gpio->func3_en_mask[pin]; + } /* Func3-external: Some pins require external setting. */ if (reg_func3_ext != NULL) { *reg_func3_ext |= gpio->func3_ext_mask[pin]; @@ -193,16 +198,18 @@ static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins) *reg_func4_gcr |= gpio->func4_en_mask[pin]; break; case IT8XXX2_ALT_DEFAULT: - *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) & - ~GPCR_PORT_PIN_MODE_OUTPUT; *reg_func3_gcr &= ~gpio->func3_en_mask[pin]; *reg_func4_gcr &= ~gpio->func4_en_mask[pin]; - break; + return 0; default: LOG_ERR("This function is not supported."); return -EINVAL; } + /* Common settings for alternate function. */ + *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | + GPCR_PORT_PIN_MODE_OUTPUT); + return 0; } diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index c2ac538c93b..12ee1d52294 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -13,19 +13,24 @@ BUILD_ASSERT(((NRF_PULL_NONE == NRF_GPIO_PIN_NOPULL) && (NRF_PULL_UP == NRF_GPIO_PIN_PULLUP)), "nRF pinctrl pull settings do not match HAL values"); -BUILD_ASSERT(((NRF_DRIVE_S0S1 == NRF_GPIO_PIN_S0S1) && - (NRF_DRIVE_H0S1 == NRF_GPIO_PIN_H0S1) && - (NRF_DRIVE_S0H1 == NRF_GPIO_PIN_S0H1) && - (NRF_DRIVE_H0H1 == NRF_GPIO_PIN_H0H1) && - (NRF_DRIVE_D0S1 == NRF_GPIO_PIN_D0S1) && - (NRF_DRIVE_D0H1 == NRF_GPIO_PIN_D0H1) && - (NRF_DRIVE_S0D1 == NRF_GPIO_PIN_S0D1) && - (NRF_DRIVE_H0D1 == NRF_GPIO_PIN_H0D1) && -#if defined(GPIO_PIN_CNF_DRIVE_E0E1) - (NRF_DRIVE_E0E1 == NRF_GPIO_PIN_E0E1) && -#endif /* defined(GPIO_PIN_CNF_DRIVE_E0E1) */ - (1U)), - "nRF pinctrl drive settings do not match HAL values"); +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) +#define NRF_DRIVE_COUNT (NRF_DRIVE_E0E1 + 1) +#else +#define NRF_DRIVE_COUNT (NRF_DRIVE_H0D1 + 1) +#endif +static const nrf_gpio_pin_drive_t drive_modes[NRF_DRIVE_COUNT] = { + [NRF_DRIVE_S0S1] = NRF_GPIO_PIN_S0S1, + [NRF_DRIVE_H0S1] = NRF_GPIO_PIN_H0S1, + [NRF_DRIVE_S0H1] = NRF_GPIO_PIN_S0H1, + [NRF_DRIVE_H0H1] = NRF_GPIO_PIN_H0H1, + [NRF_DRIVE_D0S1] = NRF_GPIO_PIN_D0S1, + [NRF_DRIVE_D0H1] = NRF_GPIO_PIN_D0H1, + [NRF_DRIVE_S0D1] = NRF_GPIO_PIN_S0D1, + [NRF_DRIVE_H0D1] = NRF_GPIO_PIN_H0D1, +#if defined(GPIO_PIN_CNF_DRIVE_E0E1) || defined(GPIO_PIN_CNF_DRIVE0_E0) + [NRF_DRIVE_E0E1] = NRF_GPIO_PIN_E0E1, +#endif +}; /* value to indicate pin level doesn't need initialization */ #define NO_WRITE UINT32_MAX @@ -86,12 +91,19 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { for (uint8_t i = 0U; i < pin_cnt; i++) { - nrf_gpio_pin_drive_t drive = NRF_GET_DRIVE(pins[i]); + nrf_gpio_pin_drive_t drive; + uint8_t drive_idx = NRF_GET_DRIVE(pins[i]); uint32_t psel = NRF_GET_PIN(pins[i]); uint32_t write = NO_WRITE; nrf_gpio_pin_dir_t dir; nrf_gpio_pin_input_t input; + if (drive_idx < ARRAY_SIZE(drive_modes)) { + drive = drive_modes[drive_idx]; + } else { + return -EINVAL; + } + if (psel == NRF_PIN_DISCONNECTED) { psel = PSEL_DISCONNECTED; } @@ -165,22 +177,22 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, #if defined(NRF_PSEL_TWIM) case NRF_FUN_TWIM_SCL: NRF_PSEL_TWIM(reg, SCL) = psel; - if (drive == NRF_DRIVE_S0S1) { + if (drive == NRF_GPIO_PIN_S0S1) { /* Override the default drive setting with one * suitable for TWI/TWIM peripherals (S0D1). * This drive cannot be used always so that * users are able to select e.g. H0D1 or E0E1 * in devicetree. */ - drive = NRF_DRIVE_S0D1; + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; break; case NRF_FUN_TWIM_SDA: NRF_PSEL_TWIM(reg, SDA) = psel; - if (drive == NRF_DRIVE_S0S1) { - drive = NRF_DRIVE_S0D1; + if (drive == NRF_GPIO_PIN_S0S1) { + drive = NRF_GPIO_PIN_S0D1; } dir = NRF_GPIO_PIN_DIR_INPUT; input = NRF_GPIO_PIN_INPUT_CONNECT; diff --git a/drivers/pinctrl/pinctrl_ra.c b/drivers/pinctrl/pinctrl_ra.c deleted file mode 100644 index 54aa881748c..00000000000 --- a/drivers/pinctrl/pinctrl_ra.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2023 TOKITA Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#define DT_DRV_COMPAT renesas_ra_pinctrl - -#define PORT_NUM 15 -#define PIN_NUM 16 - -enum { - PWPR_PFSWE_POS = 6, - PWPR_B0WI_POS = 7, -}; - -static inline uint32_t pinctrl_ra_read_PmnFPS(size_t port, size_t pin) -{ - return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, pfs) + (port * PIN_NUM + pin) * 4); -} - -static inline void pinctrl_ra_write_PmnFPS(size_t port, size_t pin, uint32_t value) -{ - sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, pfs) + (port * PIN_NUM + pin) * 4); -} - -static inline uint32_t pinctrl_ra_read_PMISC_PWPR(size_t port, size_t pin) -{ - return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); -} - -static inline void pinctrl_ra_write_PMISC_PWPR(uint32_t value) -{ - sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); -} - -static void pinctrl_ra_configure_pfs(const pinctrl_soc_pin_t *pinc) -{ - pinctrl_soc_pin_t pincfg; - - memcpy(&pincfg, pinc, sizeof(pinctrl_soc_pin_t)); - pincfg.pin = 0; - pincfg.port = 0; - - /* Clear PMR bits before configuring */ - if ((pincfg.config & PmnPFS_PMR_POS)) { - uint32_t val = pinctrl_ra_read_PmnFPS(pinc->port, pinc->pin); - - pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, val & ~(BIT(PmnPFS_PMR_POS))); - pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, pincfg.config & ~PmnPFS_PMR_POS); - } - - pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, pincfg.config); -} - -int pinctrl_ra_query_config(uint32_t port, uint32_t pin, struct pinctrl_ra_pin *const pincfg) -{ - if (port >= PORT_NUM || pin >= PIN_NUM) { - return -EINVAL; - } - - pincfg->config = pinctrl_ra_read_PmnFPS(port, pin); - return 0; -} - -int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) -{ - pinctrl_ra_write_PMISC_PWPR(0); - pinctrl_ra_write_PMISC_PWPR(BIT(PWPR_PFSWE_POS)); - - for (int i = 0; i < pin_cnt; i++) { - pinctrl_ra_configure_pfs(&pins[i]); - } - - pinctrl_ra_write_PMISC_PWPR(0); - pinctrl_ra_write_PMISC_PWPR(BIT(PWPR_B0WI_POS)); - - return 0; -} diff --git a/drivers/pinctrl/pinctrl_renesas_ra.c b/drivers/pinctrl/pinctrl_renesas_ra.c new file mode 100644 index 00000000000..89f8a41d519 --- /dev/null +++ b/drivers/pinctrl/pinctrl_renesas_ra.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define DT_DRV_COMPAT renesas_ra_pinctrl + +#define PORT_NUM 15 +#define PIN_NUM 16 + +enum { + PWPR_PFSWE_POS = 6, + PWPR_B0WI_POS = 7, +}; + +static inline uint32_t pinctrl_ra_read_PmnFPS(size_t port, size_t pin) +{ + return sys_read32(DT_INST_REG_ADDR_BY_NAME(0, pfs) + (port * PIN_NUM + pin) * 4); +} + +static inline void pinctrl_ra_write_PmnFPS(size_t port, size_t pin, uint32_t value) +{ + sys_write32(value, DT_INST_REG_ADDR_BY_NAME(0, pfs) + (port * PIN_NUM + pin) * 4); +} + +static inline uint8_t pinctrl_ra_read_PMISC_PWPR(size_t port, size_t pin) +{ + return sys_read8(DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); +} + +static inline void pinctrl_ra_write_PMISC_PWPR(uint8_t value) +{ + sys_write8(value, DT_INST_REG_ADDR_BY_NAME(0, pmisc_pwpr)); +} + +static void pinctrl_ra_configure_pfs(const pinctrl_soc_pin_t *pinc) +{ + pinctrl_soc_pin_t pincfg; + + memcpy(&pincfg, pinc, sizeof(pinctrl_soc_pin_t)); + pincfg.pin = 0; + pincfg.port = 0; + + /* Clear PMR bits before configuring */ + if ((pincfg.config & PmnPFS_PMR_POS)) { + uint32_t val = pinctrl_ra_read_PmnFPS(pinc->port, pinc->pin); + + pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, val & ~(BIT(PmnPFS_PMR_POS))); + pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, pincfg.config & ~PmnPFS_PMR_POS); + } + + pinctrl_ra_write_PmnFPS(pinc->port, pinc->pin, pincfg.config); +} + +int pinctrl_ra_query_config(uint32_t port, uint32_t pin, struct pinctrl_ra_pin *const pincfg) +{ + if (port >= PORT_NUM || pin >= PIN_NUM) { + return -EINVAL; + } + + pincfg->config = pinctrl_ra_read_PmnFPS(port, pin); + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + pinctrl_ra_write_PMISC_PWPR(0); + pinctrl_ra_write_PMISC_PWPR(BIT(PWPR_PFSWE_POS)); + + for (int i = 0; i < pin_cnt; i++) { + pinctrl_ra_configure_pfs(&pins[i]); + } + + pinctrl_ra_write_PMISC_PWPR(0); + pinctrl_ra_write_PMISC_PWPR(BIT(PWPR_B0WI_POS)); + + return 0; +} diff --git a/drivers/pinctrl/pinctrl_sifive.c b/drivers/pinctrl/pinctrl_sifive.c index ff770b53a6a..7dd8c6f944f 100644 --- a/drivers/pinctrl/pinctrl_sifive.c +++ b/drivers/pinctrl/pinctrl_sifive.c @@ -13,6 +13,7 @@ #include +#define MAX_PIN_NUM DT_PROP(DT_INST_PARENT(0), ngpios) #define PINCTRL_BASE_ADDR DT_INST_REG_ADDR(0) #define PINCTRL_IOF_EN (PINCTRL_BASE_ADDR + 0x0) #define PINCTRL_IOF_SEL (PINCTRL_BASE_ADDR + 0x4) @@ -21,7 +22,7 @@ static int pinctrl_sifive_set(uint32_t pin, uint32_t func) { uint32_t val; - if (func > SIFIVE_PINMUX_IOF1 || pin >= SIFIVE_PINMUX_PINS) { + if (func > SIFIVE_PINMUX_IOF1 || pin >= MAX_PIN_NUM) { return -EINVAL; } diff --git a/drivers/pinctrl/pinctrl_xlnx_zynqmp.c b/drivers/pinctrl/pinctrl_xlnx_zynqmp.c new file mode 100644 index 00000000000..6d874801c51 --- /dev/null +++ b/drivers/pinctrl/pinctrl_xlnx_zynqmp.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "pinctrl_soc.h" + +LOG_MODULE_REGISTER(pinctrl_xlnx_zynqmp, CONFIG_PINCTRL_LOG_LEVEL); + +#define DT_DRV_COMPAT xlnx_pinctrl_zynqmp + +static mm_reg_t base = DT_INST_REG_ADDR(0); +static uint8_t mio_pin_offset = 0x04; + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + for (uint8_t i = 0U; i < pin_cnt; i++) { + uint32_t sel = 0; + + switch (pins[i].func) { + case UART_FUNCTION: { + sel = UARTX_SEL; + break; + } + + default: { + LOG_ERR("Unsupported function enum was selected"); + break; + } + } + sys_write32(sel, base + mio_pin_offset * pins[i].pin); + } + + return 0; +} diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig index 22ffc388503..c1fe5d3bd9b 100644 --- a/drivers/power_domain/Kconfig +++ b/drivers/power_domain/Kconfig @@ -23,9 +23,20 @@ config POWER_DOMAIN_GPIO default y depends on DT_HAS_POWER_DOMAIN_GPIO_ENABLED depends on GPIO + depends on PM_DEVICE || !PM_DEVICE_POWER_DOMAIN depends on TIMEOUT_64BIT select DEVICE_DEPS +if POWER_DOMAIN_GPIO + +config POWER_DOMAIN_GPIO_INIT_PRIORITY + int "GPIO power domain init priority" + default POWER_DOMAIN_INIT_PRIORITY + help + GPIO power domain initialization priority. + +endif #POWER_DOMAIN_GPIO_MONITOR + config POWER_DOMAIN_INTEL_ADSP bool "Use Intel ADSP power gating mechanisms" default y @@ -34,6 +45,16 @@ config POWER_DOMAIN_INTEL_ADSP help Include Intel ADSP power domain control mechanisms +if POWER_DOMAIN_INTEL_ADSP + +config POWER_DOMAIN_INTEL_ADSP_INIT_PRIORITY + int "Intel ADSP power domain init priority" + default KERNEL_INIT_PRIORITY_DEFAULT + help + Intel ADSP power domain initialization priority. + +endif #POWER_DOMAIN_INTEL_ADSP + config POWER_DOMAIN_GPIO_MONITOR bool "GPIO monitor for sensing power on rail" default y @@ -41,4 +62,14 @@ config POWER_DOMAIN_GPIO_MONITOR depends on GPIO select DEVICE_DEPS +if POWER_DOMAIN_GPIO_MONITOR + +config POWER_DOMAIN_GPIO_MONITOR_INIT_PRIORITY + int "GPIO monitor power domain init priority" + default POWER_DOMAIN_INIT_PRIORITY + help + GPIO monitor power domain initialization priority. + +endif #POWER_DOMAIN_GPIO_MONITOR + endif diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 15c60a65d75..c5517d42f11 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -37,7 +37,7 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) struct pd_visitor_context *visitor_context = context; /* Only run action if the device is on the specified domain */ - if (!dev->pm || (dev->pm->domain != visitor_context->domain)) { + if (!dev->pm || (dev->pm_base->domain != visitor_context->domain)) { return 0; } @@ -135,7 +135,7 @@ static int pd_gpio_init(const struct device *dev) PM_DEVICE_DT_INST_DEFINE(id, pd_gpio_pm_action); \ DEVICE_DT_INST_DEFINE(id, pd_gpio_init, PM_DEVICE_DT_INST_GET(id), \ &pd_gpio_##id##_data, &pd_gpio_##id##_cfg, \ - POST_KERNEL, CONFIG_POWER_DOMAIN_INIT_PRIORITY, \ + POST_KERNEL, CONFIG_POWER_DOMAIN_GPIO_INIT_PRIORITY, \ NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/drivers/power_domain/power_domain_gpio_monitor.c b/drivers/power_domain/power_domain_gpio_monitor.c index 55e44570553..62dfd60855b 100644 --- a/drivers/power_domain/power_domain_gpio_monitor.c +++ b/drivers/power_domain/power_domain_gpio_monitor.c @@ -35,7 +35,7 @@ static int pd_on_domain_visitor(const struct device *dev, void *context) struct pd_visitor_context *visitor_context = context; /* Only run action if the device is on the specified domain */ - if (!dev->pm || (dev->pm->domain != visitor_context->domain)) { + if (!dev->pm || (dev->pm_base->domain != visitor_context->domain)) { return 0; } @@ -145,6 +145,6 @@ static int pd_gpio_monitor_init(const struct device *dev) DEVICE_DT_INST_DEFINE(inst, pd_gpio_monitor_init, \ PM_DEVICE_DT_INST_GET(inst), &pd_gpio_monitor_data_##inst, \ &pd_gpio_monitor_config_##inst, POST_KERNEL, \ - CONFIG_POWER_DOMAIN_INIT_PRIORITY, NULL); + CONFIG_POWER_DOMAIN_GPIO_MONITOR_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/drivers/power_domain/power_domain_intel_adsp.c b/drivers/power_domain/power_domain_intel_adsp.c index 47828d6c744..8a82f26650f 100644 --- a/drivers/power_domain/power_domain_intel_adsp.c +++ b/drivers/power_domain/power_domain_intel_adsp.c @@ -9,6 +9,10 @@ #include #include +#if CONFIG_SOC_INTEL_ACE15_MTPM +#include +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ + #include LOG_MODULE_REGISTER(power_domain_intel_adsp, LOG_LEVEL_INF); @@ -28,9 +32,20 @@ static int pd_intel_adsp_set_power_enable(struct pg_bits *bits, bool power_enabl if (!WAIT_FOR(sys_read16((mem_addr_t)&ACE_DfPMCCU.dfpwrsts) & BIT(bits->CPA_bit), 10000, k_busy_wait(1))) { - return -1; + return -EIO; } } else { +#if CONFIG_SOC_INTEL_ACE15_MTPM + extern uint32_t g_key_read_holder; + + if (bits->SPA_bit == INTEL_ADSP_HST_DOMAIN_BIT) { + volatile uint32_t *key_read_ptr = &g_key_read_holder; + uint32_t key_value = *key_read_ptr; + + if (key_value != INTEL_ADSP_ACE15_MAGIC_KEY) + return -EINVAL; + } +#endif sys_write16(sys_read16((mem_addr_t)&ACE_DfPMCCU.dfpwrctl) & ~(SPA_bit_mask), (mem_addr_t)&ACE_DfPMCCU.dfpwrctl); } @@ -84,6 +99,6 @@ static int pd_intel_adsp_init(const struct device *dev) PM_DEVICE_DT_INST_DEFINE(id, pd_intel_adsp_pm_action); \ DEVICE_DT_INST_DEFINE(id, pd_intel_adsp_init, PM_DEVICE_DT_INST_GET(id), \ &pd_pg_reg##id, NULL, POST_KERNEL, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL); + CONFIG_POWER_DOMAIN_INTEL_ADSP_INIT_PRIORITY, NULL); DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/drivers/ps2/ps2_mchp_xec.c b/drivers/ps2/ps2_mchp_xec.c index f3b1a9e10bf..0a667786912 100644 --- a/drivers/ps2/ps2_mchp_xec.c +++ b/drivers/ps2/ps2_mchp_xec.c @@ -172,9 +172,9 @@ static int ps2_xec_write(const struct device *dev, uint8_t value) LOG_DBG("PS2 write timed out"); return -ETIMEDOUT; } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + /* Inhibit ps2 controller and clear status register */ regs->CTRL = 0x00; @@ -306,33 +306,29 @@ static void ps2_xec_isr(const struct device *dev) ps2_xec_girq_clr(config->girq_id, config->girq_bit); if (status & MCHP_PS2_STATUS_RXD_RDY) { -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + regs->CTRL = 0x00; if (data->callback_isr) { data->callback_isr(dev, regs->TRX_BUFF); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_TX_TMOUT | MCHP_PS2_STATUS_TX_ST_TMOUT)) { /* Clear sticky bits and go to read mode */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; LOG_ERR("TX time out: %0x", status); -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } else if (status & (MCHP_PS2_STATUS_RX_TMOUT | MCHP_PS2_STATUS_PE | MCHP_PS2_STATUS_FE)) { /* catch and clear rx error if any */ regs->STATUS = MCHP_PS2_STATUS_RW1C_MASK; } else if (status & MCHP_PS2_STATUS_TX_IDLE) { /* Transfer completed, release the lock to enter low per mode */ -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif } /* The control register reverts to RX automatically after diff --git a/drivers/ptp_clock/CMakeLists.txt b/drivers/ptp_clock/CMakeLists.txt index 7987b588cea..3dfde253e09 100644 --- a/drivers/ptp_clock/CMakeLists.txt +++ b/drivers/ptp_clock/CMakeLists.txt @@ -5,3 +5,4 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/ptp_clock.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK ptp_clock.c) +zephyr_library_sources_ifdef(CONFIG_PTP_CLOCK_NXP_ENET ptp_clock_nxp_enet.c) diff --git a/drivers/ptp_clock/Kconfig b/drivers/ptp_clock/Kconfig index 9417d7f0633..74ab3e14eb8 100644 --- a/drivers/ptp_clock/Kconfig +++ b/drivers/ptp_clock/Kconfig @@ -5,3 +5,15 @@ config PTP_CLOCK bool "Precision Time Protocol (PTP) Clock drivers" help Enable options for Precision Time Protocol Clock drivers. + +if PTP_CLOCK + +source "drivers/ptp_clock/Kconfig.nxp_enet" + +config PTP_CLOCK_INIT_PRIORITY + int "Init priority" + default 75 + help + PTP Clock device driver initialization priority + +endif # PTP_CLOCK diff --git a/drivers/ptp_clock/Kconfig.nxp_enet b/drivers/ptp_clock/Kconfig.nxp_enet new file mode 100644 index 00000000000..aa9c8d5e41b --- /dev/null +++ b/drivers/ptp_clock/Kconfig.nxp_enet @@ -0,0 +1,9 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config PTP_CLOCK_NXP_ENET + bool "NXP ENET PTP Clock driver" + default y if DT_HAS_NXP_ENET_PTP_CLOCK_ENABLED && \ + (PTP_CLOCK || NET_L2_PTP) + help + Enable NXP ENET PTP clock support. diff --git a/drivers/ptp_clock/ptp_clock_nxp_enet.c b/drivers/ptp_clock/ptp_clock_nxp_enet.c new file mode 100644 index 00000000000..943ff6ca4ea --- /dev/null +++ b/drivers/ptp_clock/ptp_clock_nxp_enet.c @@ -0,0 +1,268 @@ +/* + * Copyright 2023 NXP + * + * Based on a commit to drivers/ethernet/eth_mcux.c which was: + * Copyright (c) 2018 Intel Coporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_enet_ptp_clock + +#include +#include +#include +#include +#include +#include + +#include "fsl_enet.h" + +struct ptp_clock_nxp_enet_config { + ENET_Type *base; + const struct pinctrl_dev_config *pincfg; + const struct device *port; + const struct device *clock_dev; + struct device *clock_subsys; + void (*irq_config_func)(void); +}; + +struct ptp_clock_nxp_enet_data { + double clock_ratio; + enet_handle_t enet_handle; + struct k_mutex ptp_mutex; +}; + +static int ptp_clock_nxp_enet_set(const struct device *dev, + struct net_ptp_time *tm) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_time_t enet_time; + + enet_time.second = tm->second; + enet_time.nanosecond = tm->nanosecond; + + ENET_Ptp1588SetTimer(config->base, &data->enet_handle, &enet_time); + + return 0; +} + +static int ptp_clock_nxp_enet_get(const struct device *dev, + struct net_ptp_time *tm) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_time_t enet_time; + + ENET_Ptp1588GetTimer(config->base, &data->enet_handle, &enet_time); + + tm->second = enet_time.second; + tm->nanosecond = enet_time.nanosecond; + + return 0; +} + +static int ptp_clock_nxp_enet_adjust(const struct device *dev, + int increment) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + int ret = 0; + int key; + + if ((increment <= (int32_t)(-NSEC_PER_SEC)) || + (increment >= (int32_t)NSEC_PER_SEC)) { + ret = -EINVAL; + } else { + key = irq_lock(); + if (config->base->ATPER != NSEC_PER_SEC) { + ret = -EBUSY; + } else { + /* Seconds counter is handled by software. Change the + * period of one software second to adjust the clock. + */ + config->base->ATPER = NSEC_PER_SEC - increment; + ret = 0; + } + irq_unlock(key); + } + + return ret; + +} + +static int ptp_clock_nxp_enet_rate_adjust(const struct device *dev, + double ratio) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + int corr; + int32_t mul; + double val; + uint32_t enet_ref_pll_rate; + + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_ref_pll_rate); + int hw_inc = NSEC_PER_SEC / enet_ref_pll_rate; + + /* No change needed. */ + if ((ratio > 1.0 && ratio - 1.0 < 0.00000001) || + (ratio < 1.0 && 1.0 - ratio < 0.00000001)) { + return 0; + } + + ratio *= data->clock_ratio; + + /* Limit possible ratio. */ + if ((ratio > 1.0 + 1.0/(2 * hw_inc)) || + (ratio < 1.0 - 1.0/(2 * hw_inc))) { + return -EINVAL; + } + + /* Save new ratio. */ + data->clock_ratio = ratio; + + if (ratio < 1.0) { + corr = hw_inc - 1; + val = 1.0 / (hw_inc * (1.0 - ratio)); + } else if (ratio > 1.0) { + corr = hw_inc + 1; + val = 1.0 / (hw_inc * (ratio - 1.0)); + } else { + val = 0; + corr = hw_inc; + } + + if (val >= INT32_MAX) { + /* Value is too high. + * It is not possible to adjust the rate of the clock. + */ + mul = 0; + } else { + mul = val; + } + + k_mutex_lock(&data->ptp_mutex, K_FOREVER); + + ENET_Ptp1588AdjustTimer(config->base, corr, mul); + + k_mutex_unlock(&data->ptp_mutex); + + return 0; +} + +void nxp_enet_ptp_clock_callback(const struct device *dev, + enum nxp_enet_callback_reason event, + void *cb_data) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + + if (event == NXP_ENET_MODULE_RESET) { + enet_ptp_config_t ptp_config; + uint32_t enet_ref_pll_rate; + uint8_t ptp_multicast[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 }; + uint8_t ptp_peer_multicast[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E }; + + (void) clock_control_get_rate(config->clock_dev, config->clock_subsys, + &enet_ref_pll_rate); + + ENET_AddMulticastGroup(config->base, ptp_multicast); + ENET_AddMulticastGroup(config->base, ptp_peer_multicast); + + /* only for ERRATA_2579 */ + ptp_config.channel = kENET_PtpTimerChannel3; + ptp_config.ptp1588ClockSrc_Hz = enet_ref_pll_rate; + data->clock_ratio = 1.0; + + ENET_Ptp1588SetChannelMode(config->base, kENET_PtpTimerChannel3, + kENET_PtpChannelPulseHighonCompare, true); + ENET_Ptp1588Configure(config->base, &data->enet_handle, + &ptp_config); + } + + if (cb_data != NULL) { + /* Share the mutex with mac driver */ + *(uintptr_t *)cb_data = (uintptr_t)&data->ptp_mutex; + } +} + +static int ptp_clock_nxp_enet_init(const struct device *port) +{ + const struct ptp_clock_nxp_enet_config *config = port->config; + struct ptp_clock_nxp_enet_data *data = port->data; + int ret; + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + k_mutex_init(&data->ptp_mutex); + + config->irq_config_func(); + + return 0; +} + +static void ptp_clock_nxp_enet_isr(const struct device *dev) +{ + const struct ptp_clock_nxp_enet_config *config = dev->config; + struct ptp_clock_nxp_enet_data *data = dev->data; + enet_ptp_timer_channel_t channel; + + unsigned int irq_lock_key = irq_lock(); + + /* clear channel */ + for (channel = kENET_PtpTimerChannel1; channel <= kENET_PtpTimerChannel4; channel++) { + if (ENET_Ptp1588GetChannelStatus(config->base, channel)) { + ENET_Ptp1588ClearChannelStatus(config->base, channel); + } + } + + ENET_TimeStampIRQHandler(config->base, &data->enet_handle); + + irq_unlock(irq_lock_key); +} + +static const struct ptp_clock_driver_api ptp_clock_nxp_enet_api = { + .set = ptp_clock_nxp_enet_set, + .get = ptp_clock_nxp_enet_get, + .adjust = ptp_clock_nxp_enet_adjust, + .rate_adjust = ptp_clock_nxp_enet_rate_adjust, +}; + +#define PTP_CLOCK_NXP_ENET_INIT(n) \ + static void nxp_enet_ptp_clock_##n##_irq_config_func(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), \ + DT_INST_IRQ_BY_IDX(n, 0, priority), \ + ptp_clock_nxp_enet_isr, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + } \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct ptp_clock_nxp_enet_config \ + ptp_clock_nxp_enet_##n##_config = { \ + .base = (ENET_Type *) DT_REG_ADDR(DT_INST_PARENT(n)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .port = DEVICE_DT_INST_GET(n), \ + .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ + .clock_subsys = (void *) \ + DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \ + .irq_config_func = \ + nxp_enet_ptp_clock_##n##_irq_config_func, \ + }; \ + \ + static struct ptp_clock_nxp_enet_data ptp_clock_nxp_enet_##n##_data; \ + \ + DEVICE_DT_INST_DEFINE(n, &ptp_clock_nxp_enet_init, NULL, \ + &ptp_clock_nxp_enet_##n##_data, \ + &ptp_clock_nxp_enet_##n##_config, \ + POST_KERNEL, CONFIG_PTP_CLOCK_INIT_PRIORITY, \ + &ptp_clock_nxp_enet_api); + +DT_INST_FOREACH_STATUS_OKAY(PTP_CLOCK_NXP_ENET_INIT) diff --git a/drivers/pwm/pwm_led_esp32.c b/drivers/pwm/pwm_led_esp32.c index de89bf694a8..7e53877f69e 100644 --- a/drivers/pwm/pwm_led_esp32.c +++ b/drivers/pwm/pwm_led_esp32.c @@ -169,7 +169,17 @@ static int pwm_led_esp32_timer_config(struct pwm_ledc_esp32_channel_config *chan return 0; } - return -EINVAL; + /** + * ESP32 - S2,S3 and C3 variants have only 14 bits counter. + * where as the plain ESP32 variant has 20 bits counter. + * application failed to set low frequency(1Hz) in S2, S3 and C3 variants. + * to get very low frequencies on these variants, + * frequency needs to be tuned with 18 bits clock divider. + * so select the slow clock source (1MHz) with highest counter resolution. + * this can be handled on the func 'pwm_led_esp32_timer_set' with 'prescaler'. + */ + channel->resolution = SOC_LEDC_TIMER_BIT_WIDE_NUM; + return 0; } static int pwm_led_esp32_timer_set(const struct device *dev, @@ -193,11 +203,12 @@ static int pwm_led_esp32_timer_set(const struct device *dev, prescaler = ((uint64_t) REF_CLK_FREQ << 8) / channel->freq / precision; break; default: - LOG_ERR("Invalid clock source"); + LOG_ERR("Invalid clock source (%d)", channel->clock_src); return -EINVAL; } if (prescaler < 0x100 || prescaler > 0x3FFFF) { + LOG_ERR("Prescaler out of range: %#X", prescaler); return -EINVAL; } @@ -251,7 +262,10 @@ static int pwm_led_esp32_set_cycles(const struct device *dev, uint32_t channel_i } /* Update PWM frequency according to period_cycles */ - pwm_led_esp32_get_cycles_per_sec(dev, channel_idx, &clk_freq); + ret = pwm_led_esp32_get_cycles_per_sec(dev, channel_idx, &clk_freq); + if (ret < 0) { + return ret; + } channel->freq = (uint32_t) (clk_freq/period_cycles); if (!channel->freq) { diff --git a/drivers/pwm/pwm_mcux_ftm.c b/drivers/pwm/pwm_mcux_ftm.c index 27ed76df7ee..9f57be2dd71 100644 --- a/drivers/pwm/pwm_mcux_ftm.c +++ b/drivers/pwm/pwm_mcux_ftm.c @@ -78,6 +78,11 @@ static int mcux_ftm_set_cycles(const struct device *dev, uint32_t channel, return -ENOTSUP; } + if (period_cycles > UINT16_MAX) { + LOG_ERR("Period cycles must be less or equal than %u", UINT16_MAX); + return -EINVAL; + } + if (channel >= config->channel_count) { LOG_ERR("Invalid channel"); return -ENOTSUP; @@ -378,11 +383,24 @@ static void mcux_ftm_capture_second_edge(const struct device *dev, uint32_t chan } } -static void mcux_ftm_isr(const struct device *dev) +static bool mcux_ftm_handle_overflow(const struct device *dev) { const struct mcux_ftm_config *config = dev->config; struct mcux_ftm_data *data = dev->data; - bool overflow = false; + + if (FTM_GetStatusFlags(config->base) & kFTM_TimeOverflowFlag) { + data->overflows++; + FTM_ClearStatusFlags(config->base, kFTM_TimeOverflowFlag); + return true; + } + + return false; +} + +static void mcux_ftm_irq_handler(const struct device *dev, uint32_t chan_start, uint32_t chan_end) +{ + const struct mcux_ftm_config *config = dev->config; + bool overflow; uint32_t flags; uint32_t irqs; uint16_t cnt; @@ -392,13 +410,9 @@ static void mcux_ftm_isr(const struct device *dev) irqs = FTM_GetEnabledInterrupts(config->base); cnt = config->base->CNT; - if (flags & kFTM_TimeOverflowFlag) { - data->overflows++; - overflow = true; - FTM_ClearStatusFlags(config->base, kFTM_TimeOverflowFlag); - } + overflow = mcux_ftm_handle_overflow(dev); - for (ch = 0; ch < MAX_CHANNELS; ch++) { + for (ch = chan_start; ch < chan_end; ch++) { if ((flags & BIT(ch)) && (irqs & BIT(ch))) { if (ch & 1) { mcux_ftm_capture_second_edge(dev, ch, cnt, overflow); @@ -491,6 +505,14 @@ static const struct pwm_driver_api mcux_ftm_driver_api = { #define TO_FTM_PRESCALE_DIVIDE(val) _DO_CONCAT(kFTM_Prescale_Divide_, val) #ifdef CONFIG_PWM_CAPTURE +#if IS_EQ(DT_NUM_IRQS(DT_DRV_INST(0)), 1) +static void mcux_ftm_isr(const struct device *dev) +{ + const struct mcux_ftm_config *cfg = dev->config; + + mcux_ftm_irq_handler(dev, 0, cfg->channel_count); +} + #define FTM_CONFIG_FUNC(n) \ static void mcux_ftm_config_func_##n(const struct device *dev) \ { \ @@ -498,6 +520,49 @@ static void mcux_ftm_config_func_##n(const struct device *dev) \ mcux_ftm_isr, DEVICE_DT_INST_GET(n), 0); \ irq_enable(DT_INST_IRQN(n)); \ } +#else /* Multiple interrupts */ +#define FTM_ISR_FUNC_NAME(suffix) _DO_CONCAT(mcux_ftm_isr_, suffix) +#define FTM_ISR_FUNC(chan_start, chan_end) \ +static void mcux_ftm_isr_##chan_start##_##chan_end(const struct device *dev) \ +{ \ + mcux_ftm_irq_handler(dev, chan_start, chan_end + 1); \ +} + +#define FTM_ISR_CONFIG(node_id, prop, idx) \ +do { \ + IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \ + DT_IRQ_BY_IDX(node_id, idx, priority), \ + FTM_ISR_FUNC_NAME(DT_STRING_TOKEN_BY_IDX(node_id, prop, idx)), \ + DEVICE_DT_GET(node_id), \ + 0); \ + irq_enable(DT_IRQ_BY_IDX(node_id, idx, irq)); \ +} while (false); + +#define FTM_CONFIG_FUNC(n) \ +static void mcux_ftm_config_func_##n(const struct device *dev) \ +{ \ + DT_INST_FOREACH_PROP_ELEM(n, interrupt_names, FTM_ISR_CONFIG) \ +} + +#if DT_INST_IRQ_HAS_NAME(0, overflow) +static void mcux_ftm_isr_overflow(const struct device *dev) +{ + mcux_ftm_handle_overflow(dev); +} +#endif +#if DT_INST_IRQ_HAS_NAME(0, 0_1) +FTM_ISR_FUNC(0, 1) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 2_3) +FTM_ISR_FUNC(2, 3) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 4_5) +FTM_ISR_FUNC(4, 5) +#endif +#if DT_INST_IRQ_HAS_NAME(0, 6_7) +FTM_ISR_FUNC(6, 7) +#endif +#endif /* IS_EQ(DT_NUM_IRQS(DT_DRV_INST(0)), 1) */ #define FTM_CFG_CAPTURE_INIT(n) \ .irq_config_func = mcux_ftm_config_func_##n #define FTM_INIT_CFG(n) FTM_DECLARE_CFG(n, FTM_CFG_CAPTURE_INIT(n)) diff --git a/drivers/pwm/pwm_mcux_sctimer.c b/drivers/pwm/pwm_mcux_sctimer.c index 91d16092e8f..fcd3272cfdc 100644 --- a/drivers/pwm/pwm_mcux_sctimer.c +++ b/drivers/pwm/pwm_mcux_sctimer.c @@ -20,6 +20,9 @@ LOG_MODULE_REGISTER(pwm_mcux_sctimer, CONFIG_PWM_LOG_LEVEL); #define CHANNEL_COUNT FSL_FEATURE_SCT_NUMBER_OF_OUTPUTS +/* Constant identifying that no event number has been set */ +#define EVENT_NOT_SET FSL_FEATURE_SCT_NUMBER_OF_EVENTS + struct pwm_mcux_sctimer_config { SCT_Type *base; uint32_t prescale; @@ -29,11 +32,52 @@ struct pwm_mcux_sctimer_config { }; struct pwm_mcux_sctimer_data { - uint32_t period_cycles[CHANNEL_COUNT]; uint32_t event_number[CHANNEL_COUNT]; sctimer_pwm_signal_param_t channel[CHANNEL_COUNT]; + uint32_t match_period; + uint32_t configured_chan; }; +/* Helper to setup channel that has not previously been configured for PWM */ +static int mcux_sctimer_new_channel(const struct device *dev, + uint32_t channel, uint32_t period_cycles, + uint32_t duty_cycle) +{ + const struct pwm_mcux_sctimer_config *config = dev->config; + struct pwm_mcux_sctimer_data *data = dev->data; + uint32_t clock_freq; + uint32_t pwm_freq; + + data->match_period = period_cycles; + + if (clock_control_get_rate(config->clock_dev, config->clock_subsys, + &clock_freq)) { + return -EINVAL; + } + + pwm_freq = (clock_freq / config->prescale) / period_cycles; + + if (pwm_freq == 0) { + LOG_ERR("Could not set up pwm_freq=%d", pwm_freq); + return -EINVAL; + } + + SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + + LOG_DBG("SETUP dutycycle to %u\n", duty_cycle); + data->channel[channel].dutyCyclePercent = duty_cycle; + if (SCTIMER_SetupPwm(config->base, &data->channel[channel], + kSCTIMER_EdgeAlignedPwm, pwm_freq, + clock_freq, &data->event_number[channel]) == kStatus_Fail) { + LOG_ERR("Could not set up pwm"); + return -ENOTSUP; + } + + SCTIMER_StartTimer(config->base, kSCTIMER_Counter_U); + data->configured_chan++; + return 0; +} + static int mcux_sctimer_pwm_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles, uint32_t pulse_cycles, pwm_flags_t flags) @@ -41,6 +85,7 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, const struct pwm_mcux_sctimer_config *config = dev->config; struct pwm_mcux_sctimer_data *data = dev->data; uint8_t duty_cycle; + int ret; if (channel >= CHANNEL_COUNT) { LOG_ERR("Invalid channel"); @@ -60,10 +105,14 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, duty_cycle = 100 * pulse_cycles / period_cycles; - if (duty_cycle == 0) { + if (duty_cycle == 0 && data->configured_chan == 1) { + /* Only one channel is active. We can turn off the SCTimer + * global counter. + */ SCT_Type *base = config->base; - SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + /* Stop timer so we can set output directly */ + SCTIMER_StopTimer(base, kSCTIMER_Counter_U); /* Set the output to inactive State */ if (data->channel[channel].level == kSCTIMER_HighTrue) { @@ -75,39 +124,65 @@ static int mcux_sctimer_pwm_set_cycles(const struct device *dev, return 0; } - if (period_cycles != data->period_cycles[channel] && - duty_cycle != data->channel[channel].dutyCyclePercent) { - uint32_t clock_freq; - uint32_t pwm_freq; - - data->period_cycles[channel] = period_cycles; - - if (clock_control_get_rate(config->clock_dev, config->clock_subsys, - &clock_freq)) { - return -EINVAL; + /* SCTimer has some unique restrictions when operation as a PWM output. + * The peripheral is based around a single counter, with a block of + * match registers that can trigger corresponding events. When used + * as a PWM peripheral, MCUX SDK sets up the SCTimer as follows: + * - one match register is used to set PWM output high, and reset + * SCtimer counter. This sets the PWM period + * - one match register is used to set PWM output low. This sets the + * pulse length + * + * This means that when configured, multiple channels must have the + * same PWM period, since they all share the same SCTimer counter. + */ + if (period_cycles != data->match_period && + data->event_number[channel] == EVENT_NOT_SET && + data->match_period == 0U) { + /* No PWM signals have been configured. We can set up the first + * PWM output using the MCUX SDK. + */ + ret = mcux_sctimer_new_channel(dev, channel, period_cycles, + duty_cycle); + if (ret < 0) { + return ret; } - - pwm_freq = (clock_freq / config->prescale) / period_cycles; - - if (pwm_freq == 0) { - LOG_ERR("Could not set up pwm_freq=%d", pwm_freq); - return -EINVAL; + } else if (data->event_number[channel] == EVENT_NOT_SET) { + /* We have already configured a PWM signal, but this channel + * has not been setup. We can only support this channel + * if the period matches that of other PWM signals. + */ + if (period_cycles != data->match_period) { + LOG_ERR("Only one PWM period is supported between " + "multiple channels"); + return -ENOTSUP; } - - SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); - - LOG_DBG("SETUP dutycycle to %u\n", duty_cycle); - data->channel[channel].dutyCyclePercent = duty_cycle; - if (SCTIMER_SetupPwm(config->base, &data->channel[channel], - kSCTIMER_EdgeAlignedPwm, pwm_freq, - clock_freq, &data->event_number[channel]) == kStatus_Fail) { - LOG_ERR("Could not set up pwm"); + /* Setup PWM output using MCUX SDK */ + ret = mcux_sctimer_new_channel(dev, channel, period_cycles, + duty_cycle); + } else if (period_cycles != data->match_period) { + uint32_t period_event = data->event_number[channel]; + /* We are reconfiguring the period of a configured channel + * MCUX SDK does not provide support for this feature, and + * we cannot do this safely if multiple channels are setup. + */ + if (data->configured_chan != 1) { + LOG_ERR("Cannot change PWM period when multiple " + "channels active"); return -ENOTSUP; } + /* To make this change, we can simply set the MATCHREL + * registers for the period match, and the next match + * (which the SDK will setup as the pulse match event) + */ + SCTIMER_StopTimer(config->base, kSCTIMER_Counter_U); + config->base->MATCHREL[period_event] = period_cycles - 1U; + config->base->MATCHREL[period_event + 1] = pulse_cycles - 1U; SCTIMER_StartTimer(config->base, kSCTIMER_Counter_U); + data->match_period = period_cycles; } else { - data->period_cycles[channel] = period_cycles; + /* Only duty cycle needs to be updated */ SCTIMER_UpdatePwmDutycycle(config->base, channel, duty_cycle, data->event_number[channel]); } @@ -160,8 +235,10 @@ static int mcux_sctimer_pwm_init(const struct device *dev) data->channel[i].output = i; data->channel[i].level = kSCTIMER_HighTrue; data->channel[i].dutyCyclePercent = 0; - data->period_cycles[i] = 0; + data->event_number[i] = EVENT_NOT_SET; } + data->match_period = 0; + data->configured_chan = 0; return 0; } diff --git a/drivers/pwm/pwm_nrf_sw.c b/drivers/pwm/pwm_nrf_sw.c index f367bb59899..2b9a22a38f0 100644 --- a/drivers/pwm/pwm_nrf_sw.c +++ b/drivers/pwm/pwm_nrf_sw.c @@ -62,6 +62,7 @@ struct pwm_config { NRF_RTC_Type *rtc; NRF_TIMER_Type *timer; }; + nrfx_gpiote_t gpiote[PWM_0_MAP_SIZE]; uint8_t psel_ch[PWM_0_MAP_SIZE]; uint8_t initially_inverted; uint8_t map_size; @@ -123,6 +124,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, const struct pwm_config *config = dev->config; NRF_TIMER_Type *timer = pwm_config_timer(config); NRF_RTC_Type *rtc = pwm_config_rtc(config); + NRF_GPIOTE_Type *gpiote; struct pwm_data *data = dev->data; uint32_t ppi_mask; uint8_t active_level; @@ -161,6 +163,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, } } + gpiote = config->gpiote[channel].p_reg; psel_ch = config->psel_ch[channel]; gpiote_ch = data->gpiote_ch[channel]; ppi_chs = data->ppi_ch[channel]; @@ -186,7 +189,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, : active_level); /* clear GPIOTE config */ - nrf_gpiote_te_default(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_te_default(gpiote, gpiote_ch); /* No PWM generation for this channel. */ data->pulse_cycles[channel] = 0U; @@ -235,7 +238,7 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, } /* Configure GPIOTE - toggle task with proper initial output value. */ - NRF_GPIOTE->CONFIG[gpiote_ch] = + gpiote->CONFIG[gpiote_ch] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | ((uint32_t)psel_ch << 8) | (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) | @@ -256,9 +259,9 @@ static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel, pulse_end_task = period_end_task = nrf_gpiote_out_task_get(gpiote_ch); #endif uint32_t pulse_end_task_address = - nrf_gpiote_task_address_get(NRF_GPIOTE, pulse_end_task); + nrf_gpiote_task_address_get(gpiote, pulse_end_task); uint32_t period_end_task_address = - nrf_gpiote_task_address_get(NRF_GPIOTE, period_end_task); + nrf_gpiote_task_address_get(gpiote, period_end_task); if (USE_RTC) { uint32_t clear_task_address = @@ -359,7 +362,8 @@ static int pwm_nrf_sw_init(const struct device *dev) } } - err = nrfx_gpiote_channel_alloc(&data->gpiote_ch[i]); + err = nrfx_gpiote_channel_alloc(&config->gpiote[i], + &data->gpiote_ch[i]); if (err != NRFX_SUCCESS) { /* Do not free allocated resource. It is a fatal condition, * system requires reconfiguration. @@ -402,8 +406,14 @@ static int pwm_nrf_sw_init(const struct device *dev) ((DT_GPIO_FLAGS_BY_IDX(_node_id, _prop, _idx) & GPIO_ACTIVE_LOW) \ ? BIT(_idx) : 0) | +#define GPIOTE_AND_COMMA(_node_id, _prop, _idx) \ + NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST_BY_IDX(_node_id, _prop, _idx)), + static const struct pwm_config pwm_nrf_sw_0_config = { COND_CODE_1(USE_RTC, (.rtc), (.timer)) = GENERATOR_ADDR, + .gpiote = { + DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, GPIOTE_AND_COMMA) + }, .psel_ch = { DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, PSEL_AND_COMMA) }, diff --git a/drivers/pwm/pwm_rpi_pico.c b/drivers/pwm/pwm_rpi_pico.c index 4b23cc558f1..b36a468fe37 100644 --- a/drivers/pwm/pwm_rpi_pico.c +++ b/drivers/pwm/pwm_rpi_pico.c @@ -6,6 +6,7 @@ #define DT_DRV_COMPAT raspberrypi_pico_pwm #include +#include #include #include #include @@ -33,6 +34,8 @@ struct pwm_rpi_config { struct pwm_rpi_slice_config slice_configs[NUM_PWM_SLICES]; const struct pinctrl_dev_config *pcfg; const struct reset_dt_spec reset; + const struct device *clk_dev; + const clock_control_subsys_t clk_id; }; static float pwm_rpi_get_clkdiv(const struct device *dev, int slice) @@ -56,19 +59,24 @@ static inline uint32_t pwm_rpi_channel_to_pico_channel(uint32_t channel) static int pwm_rpi_get_cycles_per_sec(const struct device *dev, uint32_t ch, uint64_t *cycles) { - float f_clock_in; + const struct pwm_rpi_config *cfg = dev->config; int slice = pwm_rpi_channel_to_slice(ch); + uint32_t pclk; + int ret; if (ch >= PWM_RPI_NUM_CHANNELS) { return -EINVAL; } - f_clock_in = (float)sys_clock_hw_cycles_per_sec(); + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } /* No need to check for divide by 0 since the minimum value of * pwm_rpi_get_clkdiv is 1 */ - *cycles = (uint64_t)(f_clock_in / pwm_rpi_get_clkdiv(dev, slice)); + *cycles = (uint64_t)((float)pclk / pwm_rpi_get_clkdiv(dev, slice)); return 0; } @@ -136,6 +144,16 @@ static int pwm_rpi_init(const struct device *dev) return err; } + err = clock_control_on(cfg->clk_dev, cfg->clk_id); + if (err < 0) { + return err; + } + + err = reset_line_toggle_dt(&cfg->reset); + if (err < 0) { + return err; + } + for (slice_idx = 0; slice_idx < NUM_PWM_SLICES; slice_idx++) { slice_cfg = pwm_get_default_config(); pwm_config_set_clkdiv_mode(&slice_cfg, PWM_DIV_FREE_RUNNING); @@ -174,6 +192,8 @@ static int pwm_rpi_init(const struct device *dev) PWM_INST_RPI_SLICE_DIVIDER(idx, 7), \ }, \ .reset = RESET_DT_SPEC_INST_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ }; \ \ DEVICE_DT_INST_DEFINE(idx, pwm_rpi_init, NULL, NULL, &pwm_rpi_config_##idx, POST_KERNEL, \ diff --git a/drivers/pwm/pwm_stm32.c b/drivers/pwm/pwm_stm32.c index ca989facd5d..c8e44633ad5 100644 --- a/drivers/pwm/pwm_stm32.c +++ b/drivers/pwm/pwm_stm32.c @@ -141,8 +141,7 @@ static void (*const set_timer_compare[TIMER_MAX_CH])(TIM_TypeDef *, }; /** Channel to capture get function mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const get_channel_capture[])(const TIM_TypeDef *) = { @@ -167,8 +166,7 @@ static void __maybe_unused (*const disable_capture_interrupt[])(TIM_TypeDef *) = }; /** Channel to is capture active flag mapping. */ -#if !defined(CONFIG_SOC_SERIES_STM32F1X) && \ - !defined(CONFIG_SOC_SERIES_STM32F4X) && \ +#if !defined(CONFIG_SOC_SERIES_STM32F4X) && \ !defined(CONFIG_SOC_SERIES_STM32G4X) && \ !defined(CONFIG_SOC_SERIES_STM32MP1X) static uint32_t __maybe_unused (*const is_capture_active[])(const TIM_TypeDef *) = { @@ -734,11 +732,11 @@ static void pwm_stm32_isr(const struct device *dev) /* Still waiting for a complete capture */ return; } + } - if (cpt->overflows) { - LOG_ERR("counter overflow during PWM capture"); - status = -ERANGE; - } + if (cpt->overflows) { + LOG_ERR("counter overflow during PWM capture"); + status = -ERANGE; } if (!cpt->continuous) { diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 94c3a032aff..c7612fa2067 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library() zephyr_library_sources(regulator_common.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_AXP192 regulator_axp192.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_ADP5360 regulator_adp5360.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_DA1469X regulator_da1469x.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FAKE regulator_fake.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_FIXED regulator_fixed.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_GPIO regulator_gpio.c) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c35ae389669..754ba31783e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,6 +28,7 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/regulator/Kconfig.axp192" source "drivers/regulator/Kconfig.adp5360" +source "drivers/regulator/Kconfig.da1469x" source "drivers/regulator/Kconfig.fake" source "drivers/regulator/Kconfig.fixed" source "drivers/regulator/Kconfig.gpio" diff --git a/drivers/regulator/Kconfig.da1469x b/drivers/regulator/Kconfig.da1469x new file mode 100644 index 00000000000..d8205ed4925 --- /dev/null +++ b/drivers/regulator/Kconfig.da1469x @@ -0,0 +1,16 @@ +# Copyright 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config REGULATOR_DA1469X + bool "DA1469X regulators driver" + default y + depends on DT_HAS_RENESAS_SMARTBOND_REGULATOR_ENABLED + help + Enable support for the Smartbond DA1469x regulators. + +config REGULATOR_DA1469X_INIT_PRIORITY + int "Renesas DA1469x regulators driver init priority" + default KERNEL_INIT_PRIORITY_DEVICE + depends on REGULATOR_DA1469X + help + Init priority for the Renesas DA1469x regulators driver. diff --git a/drivers/regulator/Kconfig.max20335 b/drivers/regulator/Kconfig.max20335 index a9b739e1f2c..a92743afdb5 100644 --- a/drivers/regulator/Kconfig.max20335 +++ b/drivers/regulator/Kconfig.max20335 @@ -10,9 +10,20 @@ config REGULATOR_MAX20335 help Enable the Maxim MAX20335 PMIC regulator driver +if REGULATOR_MAX20335 + +config REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY + int "MAX20335 regulator driver init priority (common part)" + default 86 + help + Init priority for the Maxim MAX20335 regulator driver + (common part). It must be greater than I2C and MFD init priority. + config REGULATOR_MAXIM_MAX20335_INIT_PRIORITY int "MAX20335 regulator driver init priority" - default 86 - depends on REGULATOR_MAX20335 + default 87 help - Init priority for the Maxim MAX20335 regulator driver. + Init priority for the Maxim MAX20335 regulator driver. It must be + greater than REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY + +endif diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index 14866a3738f..f2d9f6275e6 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -1,5 +1,6 @@ /* * Copyright 2022 Nordic Semiconductor ASA + * Copyright 2023 Meta Platforms * SPDX-License-Identifier: Apache-2.0 */ @@ -42,6 +43,15 @@ int regulator_common_init(const struct device *dev, bool is_enabled) } } + if (REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags) != + REGULATOR_ACTIVE_DISCHARGE_DEFAULT) { + ret = regulator_set_active_discharge(dev, + (bool)REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags)); + if (ret < 0) { + return ret; + } + } + if (config->init_uv > INT32_MIN) { ret = regulator_set_voltage(dev, config->init_uv, config->init_uv); if (ret < 0) { @@ -49,6 +59,13 @@ int regulator_common_init(const struct device *dev, bool is_enabled) } } + if (config->init_ua > INT32_MIN) { + ret = regulator_set_current_limit(dev, config->init_ua, config->init_ua); + if (ret < 0) { + return ret; + } + } + /* If we have valid range values, we try to match them before enabling */ if ((config->min_uv > INT32_MIN) || (config->max_uv < INT32_MAX)) { diff --git a/drivers/regulator/regulator_da1469x.c b/drivers/regulator/regulator_da1469x.c new file mode 100644 index 00000000000..36d8fe1d35f --- /dev/null +++ b/drivers/regulator/regulator_da1469x.c @@ -0,0 +1,415 @@ +/* + * Copyright 2023 Renesas Electronics Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_regulator + +#include + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(regulator_da1469x, CONFIG_REGULATOR_LOG_LEVEL); + +#define DCDC_REQUESTED (DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk |\ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) + +#define DA1469X_LDO_3V0_MODE_VBAT BIT(8) +#define DA1469X_LDO_3V0_MODE_VBUS BIT(9) + +static const struct linear_range curren_ranges[] = { + LINEAR_RANGE_INIT(30000, 30000, 0, 31), +}; + +static const struct linear_range vdd_clamp_ranges[] = { + LINEAR_RANGE_INIT(706000, 0, 15, 15), + LINEAR_RANGE_INIT(798000, 0, 14, 14), + LINEAR_RANGE_INIT(828000, 0, 13, 13), + LINEAR_RANGE_INIT(861000, 0, 11, 11), + LINEAR_RANGE_INIT(862000, 0, 12, 12), + LINEAR_RANGE_INIT(889000, 0, 10, 10), + LINEAR_RANGE_INIT(918000, 0, 9, 9), + LINEAR_RANGE_INIT(946000, 0, 3, 3), + LINEAR_RANGE_INIT(952000, 0, 8, 8), + LINEAR_RANGE_INIT(978000, 0, 2, 2), + LINEAR_RANGE_INIT(1005000, 0, 1, 1), + LINEAR_RANGE_INIT(1030000, 0, 7, 7), + LINEAR_RANGE_INIT(1037000, 0, 0, 0), + LINEAR_RANGE_INIT(1058000, 0, 6, 6), + LINEAR_RANGE_INIT(1089000, 0, 5, 5), + LINEAR_RANGE_INIT(1120000, 0, 4, 4), +}; + +static const struct linear_range vdd_ranges[] = { + LINEAR_RANGE_INIT(900000, 100000, 0, 3), +}; + +static const struct linear_range vdd_sleep_ranges[] = { + LINEAR_RANGE_INIT(750000, 50000, 0, 3), +}; + +static const struct linear_range v14_ranges[] = { + LINEAR_RANGE_INIT(1200000, 50000, 0, 7), +}; + +static const struct linear_range v30_ranges[] = { + LINEAR_RANGE_INIT(3000000, 300000, 0, 1), +}; + +static const struct linear_range v18_ranges[] = { + LINEAR_RANGE_INIT(1200000, 600000, 0, 1), +}; + +static const struct linear_range v18p_ranges[] = { + LINEAR_RANGE_INIT(1800000, 0, 0, 0), +}; + +enum da1469x_rail { + VDD_CLAMP, + VDD_SLEEP, + VDD, + V14, + V18, + V18P, + V30, +}; + +struct regulator_da1469x_desc { + const struct linear_range *voltage_ranges; + const struct linear_range *current_ranges; + uint8_t voltage_range_count; + /* Bit from POWER_CTRL_REG that can be used for enabling rail */ + uint32_t enable_mask; + uint32_t voltage_idx_mask; + volatile uint32_t *dcdc_register; +}; + +static const struct regulator_da1469x_desc vdd_desc = { + .voltage_ranges = vdd_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_VDD_REG, +}; + +static const struct regulator_da1469x_desc vdd_sleep_desc = { + .voltage_ranges = vdd_sleep_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_sleep_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_SLEEP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc vdd_clamp_desc = { + .voltage_ranges = vdd_clamp_ranges, + .voltage_range_count = ARRAY_SIZE(vdd_clamp_ranges), + .enable_mask = 0, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_VDD_CLAMP_LEVEL_Msk, +}; + +static const struct regulator_da1469x_desc v14_desc = { + .voltage_ranges = v14_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v14_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V14_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V14_REG, +}; + +static const struct regulator_da1469x_desc v18_desc = { + .voltage_ranges = v18_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V18_LEVEL_Msk, + .dcdc_register = &DCDC->DCDC_V18_REG, +}; + +static const struct regulator_da1469x_desc v18p_desc = { + .voltage_ranges = v18p_ranges, + .current_ranges = curren_ranges, + .voltage_range_count = ARRAY_SIZE(v18p_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_1V8P_ENABLE_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk, + .voltage_idx_mask = 0, + .dcdc_register = &DCDC->DCDC_V18P_REG, +}; + +static const struct regulator_da1469x_desc v30_desc = { + .voltage_ranges = v30_ranges, + .voltage_range_count = ARRAY_SIZE(v30_ranges), + .enable_mask = CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk | + CRG_TOP_POWER_CTRL_REG_LDO_3V0_MODE_Msk, + .voltage_idx_mask = CRG_TOP_POWER_CTRL_REG_V30_LEVEL_Msk, +}; + +#define DA1469X_LDO_VDD_CLAMP_RET 0 +#define DA1469X_LDO_VDD_SLEEP_RET 0 +#define DA1469X_LDO_VDD_RET CRG_TOP_POWER_CTRL_REG_LDO_CORE_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V14_RET 0 +#define DA1469X_LDO_V18_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V18P_RET CRG_TOP_POWER_CTRL_REG_LDO_1V8P_RET_ENABLE_SLEEP_Msk +#define DA1469X_LDO_V30_RET CRG_TOP_POWER_CTRL_REG_LDO_3V0_RET_ENABLE_SLEEP_Msk + +struct regulator_da1469x_config { + struct regulator_common_config common; + enum da1469x_rail rail; + const struct regulator_da1469x_desc *desc; + uint32_t power_bits; + uint32_t dcdc_bits; +}; + +struct regulator_da1469x_data { + struct regulator_common_data common; +}; + +static int regulator_da1469x_enable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + reg_val = CRG_TOP->POWER_CTRL_REG & ~(config->desc->enable_mask); + reg_val |= config->power_bits & config->desc->enable_mask; + CRG_TOP->POWER_CTRL_REG |= reg_val; + } + + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + reg_val |= config->dcdc_bits; + *config->desc->dcdc_register = reg_val; + } + + /* + * Enable DCDC if: + * 1. it was not already enabled, and + * 2. VBAT is above minimal value + * 3. Just turned on rail requested DCDC + */ + if (((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) == 0) && + (CRG_TOP->ANA_STATUS_REG & CRG_TOP_ANA_STATUS_REG_COMP_VBAT_HIGH_Msk) && + config->dcdc_bits & DCDC_REQUESTED) { + DCDC->DCDC_CTRL1_REG |= DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static int regulator_da1469x_disable(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + uint32_t reg_val; + + if (config->desc->enable_mask & config->power_bits) { + CRG_TOP->POWER_CTRL_REG &= ~(config->desc->enable_mask & + config->power_bits); + } + if (config->desc->dcdc_register) { + reg_val = *config->desc->dcdc_register & + ~(DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_ENABLE_LV_Msk); + *config->desc->dcdc_register = reg_val; + } + + /* Turn off DCDC if it's no longer requested by any rail */ + if ((DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk) && + (DCDC->DCDC_VDD_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V14_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18_REG & DCDC_REQUESTED) == 0 && + (DCDC->DCDC_V18P_REG & DCDC_REQUESTED) == 0) { + DCDC->DCDC_CTRL1_REG &= ~DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; + } + + return 0; +} + +static unsigned int regulator_da1469x_count_voltages(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + return linear_range_group_values_count(config->desc->voltage_ranges, + config->desc->voltage_range_count); +} + +static int regulator_da1469x_list_voltage(const struct device *dev, + unsigned int idx, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + + if (config->desc->voltage_ranges) { + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, + idx, volt_uv); + } + + return -ENOTSUP; +} + +static int regulator_da1469x_set_voltage(const struct device *dev, int32_t min_uv, + int32_t max_uv) +{ + int ret; + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + uint32_t mask; + + ret = linear_range_group_get_win_index(config->desc->voltage_ranges, + config->desc->voltage_range_count, + min_uv, max_uv, &idx); + + if (ret == 0) { + mask = config->desc->voltage_idx_mask; + /* + * Mask is 0 for V18. + * Setting value 1.8V is accepted since range is valid and already checked. + */ + if (mask) { + CRG_TOP->POWER_CTRL_REG = (CRG_TOP->POWER_CTRL_REG & ~mask) | + FIELD_PREP(mask, idx); + } + } + + return ret; +} + +static int regulator_da1469x_get_voltage(const struct device *dev, + int32_t *volt_uv) +{ + const struct regulator_da1469x_config *config = dev->config; + uint16_t idx; + + if (config->desc->voltage_idx_mask) { + idx = FIELD_GET(CRG_TOP->POWER_CTRL_REG, config->desc->voltage_idx_mask); + } else { + idx = 0; + } + + return linear_range_group_get_value(config->desc->voltage_ranges, + config->desc->voltage_range_count, idx, volt_uv); +} + +static int regulator_da1469x_set_current_limit(const struct device *dev, + int32_t min_ua, int32_t max_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + uint32_t reg_val; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + + ret = linear_range_group_get_win_index(config->desc->current_ranges, + 1, + min_ua, max_ua, &idx); + if (ret) { + return ret; + } + + /* All registers have same bits layout */ + reg_val = *config->desc->dcdc_register & ~(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk | + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_LV_Msk, idx); + reg_val |= FIELD_PREP(DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MIN_Msk, idx); + + *config->desc->dcdc_register = reg_val; + + return ret; +} + +static int regulator_da1469x_get_current_limit(const struct device *dev, + int32_t *curr_ua) +{ + const struct regulator_da1469x_config *config = dev->config; + int ret; + uint16_t idx; + + if (config->desc->current_ranges == NULL) { + return -ENOTSUP; + } + idx = FIELD_GET(*config->desc->dcdc_register, + DCDC_DCDC_V14_REG_DCDC_V14_CUR_LIM_MAX_HV_Msk); + ret = linear_range_group_get_value(config->desc->current_ranges, 1, idx, curr_ua); + + return ret; +} + +static const struct regulator_driver_api regulator_da1469x_api = { + .enable = regulator_da1469x_enable, + .disable = regulator_da1469x_disable, + .count_voltages = regulator_da1469x_count_voltages, + .list_voltage = regulator_da1469x_list_voltage, + .set_voltage = regulator_da1469x_set_voltage, + .get_voltage = regulator_da1469x_get_voltage, + .set_current_limit = regulator_da1469x_set_current_limit, + .get_current_limit = regulator_da1469x_get_current_limit, +}; + +static int regulator_da1469x_init(const struct device *dev) +{ + const struct regulator_da1469x_config *config = dev->config; + + regulator_common_data_init(dev); + + if ((config->rail == V30) && + (config->power_bits & CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk)) { + CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk; + } + + return regulator_common_init(dev, 0); +} + +#define REGULATOR_DA1469X_DEFINE(node, id, rail_id) \ + static struct regulator_da1469x_data data_##id; \ + \ + static const struct regulator_da1469x_config config_##id = { \ + .common = REGULATOR_DT_COMMON_CONFIG_INIT(node), \ + .desc = &id ## _desc, \ + .power_bits = \ + (DT_PROP(node, renesas_regulator_v30_clamp) * \ + CRG_TOP_POWER_CTRL_REG_CLAMP_3V0_VBAT_ENABLE_Msk) | \ + (DT_PROP(node, renesas_regulator_v30_vbus) * \ + DA1469X_LDO_3V0_MODE_VBAT) | \ + (DT_PROP(node, renesas_regulator_v30_vbat) * \ + DA1469X_LDO_3V0_MODE_VBUS) | \ + (DT_PROP(node, renesas_regulator_sleep_ldo) * \ + (DA1469X_LDO_ ## rail_id ##_RET)) | \ + (DT_PROP(node, renesas_regulator_v30_ref_bandgap) * \ + CRG_TOP_POWER_CTRL_REG_LDO_3V0_REF_Msk), \ + .dcdc_bits = \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_high) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_HV_Msk) | \ + (DT_PROP(node, renesas_regulator_dcdc_vbat_low) * \ + DCDC_DCDC_VDD_REG_DCDC_VDD_ENABLE_LV_Msk) \ + }; \ + DEVICE_DT_DEFINE(node, regulator_da1469x_init, NULL, &data_##id, \ + &config_##id, PRE_KERNEL_1, \ + CONFIG_REGULATOR_DA1469X_INIT_PRIORITY, \ + ®ulator_da1469x_api); + +#define REGULATOR_DA1469X_DEFINE_COND(inst, child, source) \ + COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \ + (REGULATOR_DA1469X_DEFINE( \ + DT_INST_CHILD(inst, child), child, source)), \ + ()) + +#define REGULATOR_DA1469X_DEFINE_ALL(inst) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_clamp, VDD_CLAMP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd_sleep, VDD_SLEEP) \ + REGULATOR_DA1469X_DEFINE_COND(inst, vdd, VDD) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v14, V14) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18, V18) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v18p, V18P) \ + REGULATOR_DA1469X_DEFINE_COND(inst, v30, V30) \ + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_DA1469X_DEFINE_ALL) diff --git a/drivers/regulator/regulator_fake.c b/drivers/regulator/regulator_fake.c index 05b74bc56e1..129ef2f215e 100644 --- a/drivers/regulator/regulator_fake.c +++ b/drivers/regulator/regulator_fake.c @@ -39,6 +39,10 @@ DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *, regulator_mode_t); DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *, regulator_mode_t *); +DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *, + bool); +DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *, + bool *); DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags, const struct device *, regulator_error_flags_t *); @@ -53,6 +57,8 @@ static struct regulator_driver_api api = { .get_current_limit = regulator_fake_get_current_limit, .set_mode = regulator_fake_set_mode, .get_mode = regulator_fake_get_mode, + .set_active_discharge = regulator_fake_set_active_discharge, + .get_active_discharge = regulator_fake_get_active_discharge, .get_error_flags = regulator_fake_get_error_flags, }; diff --git a/drivers/regulator/regulator_fixed.c b/drivers/regulator/regulator_fixed.c index c0b58273987..5e7151f4941 100644 --- a/drivers/regulator/regulator_fixed.c +++ b/drivers/regulator/regulator_fixed.c @@ -84,33 +84,23 @@ static const struct regulator_driver_api regulator_fixed_api = { static int regulator_fixed_init(const struct device *dev) { const struct regulator_fixed_config *cfg = dev->config; - bool init_enabled; - int ret; regulator_common_data_init(dev); - init_enabled = regulator_common_is_init_enabled(dev); - if (cfg->enable.port != NULL) { if (!gpio_is_ready_dt(&cfg->enable)) { LOG_ERR("GPIO port: %s not ready", cfg->enable.port->name); return -ENODEV; } - if (init_enabled) { - ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_ACTIVE); - if (ret < 0) { - return ret; - } - } else { - ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); - if (ret < 0) { - return ret; - } + int ret = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT); + + if (ret < 0) { + return ret; } } - return regulator_common_init(dev, init_enabled); + return regulator_common_init(dev, false); } #define REGULATOR_FIXED_DEFINE(inst) \ diff --git a/drivers/regulator/regulator_max20335.c b/drivers/regulator/regulator_max20335.c index 5395c1de699..328e5179156 100644 --- a/drivers/regulator/regulator_max20335.c +++ b/drivers/regulator/regulator_max20335.c @@ -16,6 +16,7 @@ #define MAX20335_BUCK2_CFG 0x0FU #define MAX20335_BUCK2_VSET 0x10U #define MAX20335_BUCK12_CSET 0x11U +#define MAX20335_PWR_CMD 0x1FU #define MAX20335_BUCK1_CSET_MASK 0xF0U #define MAX20335_BUCK2_CSET_MASK 0x0FU #define MAX20335_BUCK2_CSET_SHIFT 4 @@ -32,6 +33,8 @@ #define MAX20335_LDO_EN BIT(1) #define MAX20335_LDO_EN_MASK GENMASK(2, 1) +#define MAX20335_OFF_MODE 0xB2U + enum max20335_pmic_sources { MAX20335_PMIC_SOURCE_BUCK1, MAX20335_PMIC_SOURCE_BUCK2, @@ -49,6 +52,10 @@ struct regulator_max20335_desc { const struct linear_range *ua_range; }; +struct regulator_max20335_common_config { + struct i2c_dt_spec bus; +}; + struct regulator_max20335_config { struct regulator_common_config common; struct i2c_dt_spec bus; @@ -67,7 +74,7 @@ static const struct linear_range buck12_current_limit_range = static const struct linear_range ldo1_range = LINEAR_RANGE_INIT(800000, 100000U, 0x0U, 0x1CU); static const struct linear_range ldo23_range = LINEAR_RANGE_INIT(900000, 100000U, 0x0U, 0x1FU); -static const struct regulator_max20335_desc buck1_desc = { +static const struct regulator_max20335_desc __maybe_unused buck1_desc = { .vsel_reg = MAX20335_BUCK1_VSET, .enable_mask = MAX20335_BUCK_EN_MASK, .enable_val = MAX20335_BUCK_EN, @@ -76,7 +83,7 @@ static const struct regulator_max20335_desc buck1_desc = { .ua_range = &buck12_current_limit_range, }; -static const struct regulator_max20335_desc buck2_desc = { +static const struct regulator_max20335_desc __maybe_unused buck2_desc = { .vsel_reg = MAX20335_BUCK2_VSET, .enable_mask = MAX20335_BUCK_EN_MASK, .enable_val = MAX20335_BUCK_EN, @@ -85,7 +92,7 @@ static const struct regulator_max20335_desc buck2_desc = { .ua_range = &buck12_current_limit_range, }; -static const struct regulator_max20335_desc ldo1_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo1_desc = { .vsel_reg = MAX20335_LDO1_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, @@ -93,7 +100,7 @@ static const struct regulator_max20335_desc ldo1_desc = { .uv_range = &ldo1_range, }; -static const struct regulator_max20335_desc ldo2_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo2_desc = { .vsel_reg = MAX20335_LDO2_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, @@ -101,7 +108,7 @@ static const struct regulator_max20335_desc ldo2_desc = { .uv_range = &ldo23_range, }; -static const struct regulator_max20335_desc ldo3_desc = { +static const struct regulator_max20335_desc __maybe_unused ldo3_desc = { .vsel_reg = MAX20335_LDO3_VSET, .enable_mask = MAX20335_LDO_EN_MASK, .enable_val = MAX20335_LDO_EN, @@ -224,6 +231,11 @@ static unsigned int regulator_max20335_count_current_limits(const struct device { const struct regulator_max20335_config *config = dev->config; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + return linear_range_values_count(config->desc->ua_range); } @@ -232,6 +244,11 @@ static int regulator_max20335_list_current_limit(const struct device *dev, unsig { const struct regulator_max20335_config *config = dev->config; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + return linear_range_get_value(config->desc->ua_range, idx, current_ua); } @@ -244,6 +261,11 @@ static int regulator_max20335_set_current_limit(const struct device *dev, uint16_t idx; int ret; + if (config->source != MAX20335_PMIC_SOURCE_BUCK1 && + config->source != MAX20335_PMIC_SOURCE_BUCK2) { + return -ENOTSUP; + } + ret = i2c_reg_read_byte_dt(&config->bus, MAX20335_BUCK12_CSET, &val); if (ret < 0) { return ret; @@ -268,6 +290,13 @@ static int regulator_max20335_set_current_limit(const struct device *dev, return i2c_reg_write_byte_dt(&config->bus, MAX20335_BUCK12_CSET, val); } +static int regulator_max20335_power_off(const struct device *dev) +{ + const struct regulator_max20335_common_config *common_config = dev->config; + + return i2c_reg_write_byte_dt(&common_config->bus, MAX20335_PWR_CMD, MAX20335_OFF_MODE); +} + static int regulator_max20335_init(const struct device *dev) { const struct regulator_max20335_config *config = dev->config; @@ -281,6 +310,21 @@ static int regulator_max20335_init(const struct device *dev) return regulator_common_init(dev, false); } +static int regulator_max20335_common_init(const struct device *dev) +{ + const struct regulator_max20335_common_config *common_config = dev->config; + + if (!i2c_is_ready_dt(&common_config->bus)) { + return -ENODEV; + } + + return 0; +} + +static const struct regulator_parent_driver_api parent_api = { + .ship_mode = regulator_max20335_power_off, +}; + static const struct regulator_driver_api api = { .enable = regulator_max20335_enable, .disable = regulator_max20335_disable, @@ -317,10 +361,19 @@ static const struct regulator_driver_api api = { ()) #define REGULATOR_MAX20335_DEFINE_ALL(inst) \ + static const struct regulator_max20335_common_config common_config_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, regulator_max20335_common_init, \ + NULL, NULL, &common_config_##inst, POST_KERNEL, \ + CONFIG_REGULATOR_MAXIM_MAX20335_COMMON_INIT_PRIORITY, \ + &parent_api); \ + \ REGULATOR_MAX20335_DEFINE_COND(inst, buck1, MAX20335_PMIC_SOURCE_BUCK1) \ REGULATOR_MAX20335_DEFINE_COND(inst, buck2, MAX20335_PMIC_SOURCE_BUCK2) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo1, MAX20335_PMIC_SOURCE_LDO1) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo2, MAX20335_PMIC_SOURCE_LDO2) \ REGULATOR_MAX20335_DEFINE_COND(inst, ldo3, MAX20335_PMIC_SOURCE_LDO3) -DT_INST_FOREACH_STATUS_OKAY(REGULATOR_MAX20335_DEFINE_ALL); +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_MAX20335_DEFINE_ALL) diff --git a/drivers/regulator/regulator_pca9420.c b/drivers/regulator/regulator_pca9420.c index c7978242871..705d4f3a8e9 100644 --- a/drivers/regulator/regulator_pca9420.c +++ b/drivers/regulator/regulator_pca9420.c @@ -24,6 +24,8 @@ #define PCA9420_TOP_CNTL3 0x0CU /** Regulator status indication registers */ +/** @brief Active Discharge configuration for mode 0_0 */ +#define PCA9420_ACT_DISCHARGE_CNTL 0x21U /** @brief Mode configuration for mode 0_0 */ #define PCA9420_MODECFG_0_0 0x22U /** @brief Mode configuration for mode 0_1 */ @@ -81,6 +83,18 @@ /** @brief LDO2_OUT offset and voltage level mask */ #define PCA9420_MODECFG_3_LDO2_OUT_MASK 0x3FU #define PCA9420_MODECFG_3_LDO2_OUT_POS 0U +/** @brief SW1 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK 0x08U +#define PCA9420_ACT_DISCHARGE_CNTL_SW1_POS 4U +/** @brief SW2 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK 0x04U +#define PCA9420_ACT_DISCHARGE_CNTL_SW2_POS 3U +/** @brief LDO1 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK 0x02U +#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS 2U +/** @brief LDO2 active discharge control */ +#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK 0x01U +#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS 1U /** VIN ILIM resolution, uA/LSB */ #define PCA9420_VIN_ILIM_UA_LSB 170000 @@ -99,6 +113,8 @@ struct regulator_pca9420_desc { uint8_t vsel_reg; uint8_t vsel_mask; uint8_t vsel_pos; + uint8_t ad_mask; + uint8_t ad_pos; int32_t max_ua; uint8_t num_ranges; const struct linear_range *ranges; @@ -159,6 +175,8 @@ static const struct regulator_pca9420_desc buck1_desc = { .vsel_mask = PCA9420_MODECFG_0_SW1_OUT_MASK, .vsel_pos = PCA9420_MODECFG_0_SW1_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_0, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW1_POS, .max_ua = 250000, .ranges = buck1_ranges, .num_ranges = ARRAY_SIZE(buck1_ranges), @@ -171,6 +189,8 @@ static const struct regulator_pca9420_desc buck2_desc = { .vsel_mask = PCA9420_MODECFG_1_SW2_OUT_MASK, .vsel_pos = PCA9420_MODECFG_1_SW2_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_1, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW2_POS, .max_ua = 500000, .ranges = buck2_ranges, .num_ranges = ARRAY_SIZE(buck2_ranges), @@ -183,6 +203,8 @@ static const struct regulator_pca9420_desc ldo1_desc = { .vsel_mask = PCA9420_MODECFG_2_LDO1_OUT_MASK, .vsel_pos = PCA9420_MODECFG_2_LDO1_OUT_POS, .vsel_reg = PCA9420_MODECFG_0_2, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS, .max_ua = 1000, .ranges = ldo1_ranges, .num_ranges = ARRAY_SIZE(ldo1_ranges), @@ -195,6 +217,8 @@ static const struct regulator_pca9420_desc ldo2_desc = { .vsel_reg = PCA9420_MODECFG_0_3, .vsel_mask = PCA9420_MODECFG_3_LDO2_OUT_MASK, .vsel_pos = PCA9420_MODECFG_3_LDO2_OUT_POS, + .ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK, + .ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS, .max_ua = 250000, .ranges = ldo2_ranges, .num_ranges = ARRAY_SIZE(ldo2_ranges), @@ -279,6 +303,36 @@ static int regulator_pca9420_get_current_limit(const struct device *dev, return 0; } +static int regulator_pca9420_set_active_discharge(const struct device *dev, + bool active_discharge) +{ + const struct regulator_pca9420_config *config = dev->config; + const struct regulator_pca9420_common_config *cconfig = config->parent->config; + uint8_t dis_val; + + dis_val = (!active_discharge) << config->desc->ad_pos; + return i2c_reg_update_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL, + config->desc->ad_mask, dis_val); +} + +static int regulator_pca9420_get_active_discharge(const struct device *dev, + bool *active_discharge) +{ + const struct regulator_pca9420_config *config = dev->config; + const struct regulator_pca9420_common_config *cconfig = config->parent->config; + uint8_t raw_reg; + int ret; + + ret = i2c_reg_read_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL, &raw_reg); + if (ret < 0) { + return ret; + } + + *active_discharge = !((raw_reg & config->desc->ad_mask) >> config->desc->ad_pos); + + return 0; +} + static int regulator_pca9420_enable(const struct device *dev) { const struct regulator_pca9420_config *config = dev->config; @@ -313,6 +367,8 @@ static const struct regulator_driver_api api = { .set_voltage = regulator_pca9420_set_voltage, .get_voltage = regulator_pca9420_get_voltage, .get_current_limit = regulator_pca9420_get_current_limit, + .set_active_discharge = regulator_pca9420_set_active_discharge, + .get_active_discharge = regulator_pca9420_get_active_discharge, }; static int regulator_pca9420_init(const struct device *dev) diff --git a/drivers/regulator/regulator_shell.c b/drivers/regulator/regulator_shell.c index 74aa1f22ca6..5dddbb5b8d7 100644 --- a/drivers/regulator/regulator_shell.c +++ b/drivers/regulator/regulator_shell.c @@ -364,6 +364,63 @@ static int cmd_modeget(const struct shell *sh, size_t argc, char **argv) return 0; } +static int cmd_adset(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + bool ad; + int ret; + + ARG_UNUSED(argc); + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + if (strcmp(argv[2], "enable")) { + ad = true; + } else if (strcmp(argv[2], "disable")) { + ad = false; + } else { + shell_error(sh, "Invalid parameter"); + return -EINVAL; + } + + ret = regulator_set_active_discharge(dev, ad); + if (ret < 0) { + shell_error(sh, "Could not set mode (%d)", ret); + return ret; + } + + return 0; +} + +static int cmd_adget(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + bool ad; + int ret; + + ARG_UNUSED(argc); + + dev = device_get_binding(argv[1]); + if (dev == NULL) { + shell_error(sh, "Regulator device %s not available", argv[1]); + return -ENODEV; + } + + ret = regulator_get_active_discharge(dev, &ad); + if (ret < 0) { + shell_error(sh, "Could not get active discharge (%d)", ret); + return ret; + } + + shell_print(sh, "Active Discharge: %s", ad ? "enabled" : "disabled"); + + return 0; +} + static int cmd_errors(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; @@ -503,6 +560,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "Get regulator mode\n" "Usage: modeget ", cmd_modeget, 2, 0), + SHELL_CMD_ARG(adset, NULL, + "Set active discharge\n" + "Usage: adset ", + cmd_adset, 3, 0), + SHELL_CMD_ARG(adget, NULL, + "Get active discharge\n" + "Usage: adset ", + cmd_adget, 2, 0), SHELL_CMD_ARG(errors, &dsub_device_name, "Get errors\n" "Usage: errors ", diff --git a/drivers/retained_mem/CMakeLists.txt b/drivers/retained_mem/CMakeLists.txt index c119347a767..4f9322c3a89 100644 --- a/drivers/retained_mem/CMakeLists.txt +++ b/drivers/retained_mem/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_USERSPACE retained_mem_handlers.c) zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_NRF_GPREGRET retained_mem_nrf_gpregret.c) zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_ZEPHYR_RAM retained_mem_zephyr_ram.c) +zephyr_library_sources_ifdef(CONFIG_RETAINED_MEM_ZEPHYR_REG retained_mem_zephyr_reg.c) diff --git a/drivers/retained_mem/Kconfig.zephyr b/drivers/retained_mem/Kconfig.zephyr index 4a4231c4968..0348efbab10 100644 --- a/drivers/retained_mem/Kconfig.zephyr +++ b/drivers/retained_mem/Kconfig.zephyr @@ -7,3 +7,10 @@ config RETAINED_MEM_ZEPHYR_RAM depends on DT_HAS_ZEPHYR_RETAINED_RAM_ENABLED help Enable driver for retained memory in RAM. + +config RETAINED_MEM_ZEPHYR_REG + bool "Generic Zephyr register retained memory driver" + default y + depends on DT_HAS_ZEPHYR_RETAINED_REG_ENABLED + help + Enable driver for retained memory in retained registers. diff --git a/drivers/retained_mem/retained_mem_zephyr_reg.c b/drivers/retained_mem/retained_mem_zephyr_reg.c new file mode 100644 index 00000000000..a302e175a6e --- /dev/null +++ b/drivers/retained_mem/retained_mem_zephyr_reg.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * Copyright (c) 2023, Bjarki Arge Andreasen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_retained_reg + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(retained_mem_zephyr_reg, CONFIG_RETAINED_MEM_LOG_LEVEL); + +struct zephyr_retained_mem_reg_data { +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct k_mutex lock; +#endif +}; + +struct zephyr_retained_mem_reg_config { + uint8_t *address; + size_t size; +}; + +static inline void zephyr_retained_mem_reg_lock_take(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_lock(&data->lock, K_FOREVER); +#else + ARG_UNUSED(dev); +#endif +} + +static inline void zephyr_retained_mem_reg_lock_release(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_unlock(&data->lock); +#else + ARG_UNUSED(dev); +#endif +} + +static int zephyr_retained_mem_reg_init(const struct device *dev) +{ +#ifdef CONFIG_RETAINED_MEM_MUTEXES + struct zephyr_retained_mem_reg_data *data = dev->data; + + k_mutex_init(&data->lock); +#endif + + return 0; +} + +static ssize_t zephyr_retained_mem_reg_size(const struct device *dev) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + return (ssize_t)config->size; +} + +static int zephyr_retained_mem_reg_read(const struct device *dev, off_t offset, uint8_t *buffer, + size_t size) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memcpy(buffer, (config->address + offset), size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static int zephyr_retained_mem_reg_write(const struct device *dev, off_t offset, + const uint8_t *buffer, size_t size) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memcpy((config->address + offset), buffer, size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static int zephyr_retained_mem_reg_clear(const struct device *dev) +{ + const struct zephyr_retained_mem_reg_config *config = dev->config; + + zephyr_retained_mem_reg_lock_take(dev); + + memset(config->address, 0, config->size); + + zephyr_retained_mem_reg_lock_release(dev); + + return 0; +} + +static const struct retained_mem_driver_api zephyr_retained_mem_reg_api = { + .size = zephyr_retained_mem_reg_size, + .read = zephyr_retained_mem_reg_read, + .write = zephyr_retained_mem_reg_write, + .clear = zephyr_retained_mem_reg_clear, +}; + +#define ZEPHYR_RETAINED_MEM_REG_DEVICE(inst) \ + static struct zephyr_retained_mem_reg_data zephyr_retained_mem_reg_data_##inst; \ + static const struct zephyr_retained_mem_reg_config \ + zephyr_retained_mem_reg_config_##inst = { \ + .address = (uint8_t *)DT_INST_REG_ADDR(inst), \ + .size = DT_INST_REG_SIZE(inst), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &zephyr_retained_mem_reg_init, \ + NULL, \ + &zephyr_retained_mem_reg_data_##inst, \ + &zephyr_retained_mem_reg_config_##inst, \ + POST_KERNEL, \ + CONFIG_RETAINED_MEM_INIT_PRIORITY, \ + &zephyr_retained_mem_reg_api); + +DT_INST_FOREACH_STATUS_OKAY(ZEPHYR_RETAINED_MEM_REG_DEVICE) diff --git a/drivers/rtc/rtc_emul.c b/drivers/rtc/rtc_emul.c index bf95fa87813..9ce6b5dbc25 100644 --- a/drivers/rtc/rtc_emul.c +++ b/drivers/rtc/rtc_emul.c @@ -461,7 +461,7 @@ static int rtc_emul_get_calibration(const struct device *dev, int32_t *calibrati } #endif /* CONFIG_RTC_CALIBRATION */ -struct rtc_driver_api rtc_emul_driver_api = { +static const struct rtc_driver_api rtc_emul_driver_api = { .set_time = rtc_emul_set_time, .get_time = rtc_emul_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_fake.c b/drivers/rtc/rtc_fake.c index 3a96da7141d..f02cf48b2e8 100644 --- a/drivers/rtc/rtc_fake.c +++ b/drivers/rtc/rtc_fake.c @@ -70,7 +70,7 @@ static void fake_rtc_reset_rule_before(const struct ztest_unit_test *test, void ZTEST_RULE(fake_rtc_reset_rule, fake_rtc_reset_rule_before, NULL); #endif /* CONFIG_ZTEST */ -struct rtc_driver_api rtc_fake_driver_api = { +static const struct rtc_driver_api rtc_fake_driver_api = { .set_time = rtc_fake_set_time, .get_time = rtc_fake_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_ll_stm32.c b/drivers/rtc/rtc_ll_stm32.c index 8714439ef47..8e1ee9419b5 100644 --- a/drivers/rtc/rtc_ll_stm32.c +++ b/drivers/rtc/rtc_ll_stm32.c @@ -77,34 +77,6 @@ struct rtc_stm32_data { struct k_mutex lock; }; -static int rtc_stm32_enter_initialization_mode(bool kernel_available) -{ - if (kernel_available) { - LL_RTC_EnableInitMode(RTC); - bool success = WAIT_FOR(LL_RTC_IsActiveFlag_INIT(RTC), RTC_TIMEOUT, k_msleep(1)); - - if (!success) { - return -EIO; - } - } else { - /* kernel is not available so use the blocking but otherwise equivalent function - * provided by LL - */ - ErrorStatus status = LL_RTC_EnterInitMode(RTC); - - if (status != SUCCESS) { - return -EIO; - } - } - - return 0; -} - -static inline void rtc_stm32_leave_initialization_mode(void) -{ - LL_RTC_DisableInitMode(RTC); -} - static int rtc_stm32_configure(const struct device *dev) { const struct rtc_stm32_config *cfg = dev->config; @@ -123,14 +95,17 @@ static int rtc_stm32_configure(const struct device *dev) if ((hour_format != LL_RTC_HOURFORMAT_24HOUR) || (sync_prescaler != cfg->sync_prescaler) || (async_prescaler != cfg->async_prescaler)) { - err = rtc_stm32_enter_initialization_mode(false); - if (err == 0) { + ErrorStatus status = LL_RTC_EnterInitMode(RTC); + + if (status == SUCCESS) { LL_RTC_SetHourFormat(RTC, LL_RTC_HOURFORMAT_24HOUR); LL_RTC_SetSynchPrescaler(RTC, cfg->sync_prescaler); LL_RTC_SetAsynchPrescaler(RTC, cfg->async_prescaler); + } else { + err = -EIO; } - rtc_stm32_leave_initialization_mode(); + LL_RTC_DisableInitMode(RTC); } #ifdef RTC_CR_BYPSHAD @@ -164,7 +139,6 @@ static int rtc_stm32_init(const struct device *dev) k_mutex_init(&data->lock); /* Enable Backup access */ - z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); #if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) LL_PWR_EnableBkUpAccess(); #endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ @@ -175,12 +149,18 @@ static int rtc_stm32_init(const struct device *dev) return -EIO; } + z_stm32_hsem_lock(CFG_HW_RCC_SEMID, HSEM_LOCK_DEFAULT_RETRY); + LL_RCC_EnableRTC(); z_stm32_hsem_unlock(CFG_HW_RCC_SEMID); err = rtc_stm32_configure(dev); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + return err; } @@ -208,12 +188,21 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t } LOG_INF("Setting clock"); + +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_EnableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + LL_RTC_DisableWriteProtection(RTC); - err = rtc_stm32_enter_initialization_mode(true); - if (err) { + ErrorStatus status = LL_RTC_EnterInitMode(RTC); + + if (status != SUCCESS) { +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ k_mutex_unlock(&data->lock); - return err; + return -EIO; } LL_RTC_DATE_SetYear(RTC, bin2bcd(real_year - RTC_YEAR_REF)); @@ -233,10 +222,14 @@ static int rtc_stm32_set_time(const struct device *dev, const struct rtc_time *t LL_RTC_TIME_SetMinute(RTC, bin2bcd(timeptr->tm_min)); LL_RTC_TIME_SetSecond(RTC, bin2bcd(timeptr->tm_sec)); - rtc_stm32_leave_initialization_mode(); + LL_RTC_DisableInitMode(RTC); LL_RTC_EnableWriteProtection(RTC); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + k_mutex_unlock(&data->lock); return err; @@ -259,6 +252,15 @@ static int rtc_stm32_get_time(const struct device *dev, struct rtc_time *timeptr return err; } + if (!LL_RTC_IsActiveFlag_INITS(RTC)) { + /* INITS flag is set when the calendar has been initialiazed. This flag is + * reset only on backup domain reset, so it can be read after a system + * reset to check if the calendar has been initialized. + */ + k_mutex_unlock(&data->lock); + return -ENODATA; + } + do { /* read date, time and subseconds and relaunch if a day increment occurred * while doing so as it will result in an erroneous result otherwise @@ -350,12 +352,20 @@ static int rtc_stm32_set_calibration(const struct device *dev, int32_t calibrati return -EIO; } +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_EnableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + LL_RTC_DisableWriteProtection(RTC); MODIFY_REG(RTC->CALR, RTC_CALR_CALP | RTC_CALR_CALM, calp | calm); LL_RTC_EnableWriteProtection(RTC); +#if defined(PWR_CR_DBP) || defined(PWR_CR1_DBP) || defined(PWR_DBPCR_DBP) || defined(PWR_DBPR_DBP) + LL_PWR_DisableBkUpAccess(); +#endif /* PWR_CR_DBP || PWR_CR1_DBP || PWR_DBPR_DBP */ + return 0; } @@ -381,7 +391,7 @@ static int rtc_stm32_get_calibration(const struct device *dev, int32_t *calibrat #endif #endif /* CONFIG_RTC_CALIBRATION */ -struct rtc_driver_api rtc_stm32_driver_api = { +static const struct rtc_driver_api rtc_stm32_driver_api = { .set_time = rtc_stm32_set_time, .get_time = rtc_stm32_get_time, /* RTC_ALARM not supported */ diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c index 6ecdfafa634..15d36c623b0 100644 --- a/drivers/rtc/rtc_mc146818.c +++ b/drivers/rtc/rtc_mc146818.c @@ -495,7 +495,7 @@ static void rtc_mc146818_isr(const struct device *dev) #endif } -struct rtc_driver_api rtc_mc146818_driver_api = { +static const struct rtc_driver_api rtc_mc146818_driver_api = { .set_time = rtc_mc146818_set_time, .get_time = rtc_mc146818_get_time, #if defined(CONFIG_RTC_ALARM) diff --git a/drivers/rtc/rtc_pcf8563.c b/drivers/rtc/rtc_pcf8563.c index 4b16707dee8..515adaf5584 100644 --- a/drivers/rtc/rtc_pcf8563.c +++ b/drivers/rtc/rtc_pcf8563.c @@ -427,10 +427,10 @@ static const struct rtc_driver_api pcf8563_driver_api = { .alarm_set_time = pcf8563_alarm_set_time, .alarm_get_time = pcf8563_alarm_get_time, .alarm_is_pending = pcf8563_alarm_is_pending, -#endif #ifdef PCF8563_INT1_GPIOS_IN_USE .alarm_set_callback = pcf8563_alarm_set_callback, #endif +#endif }; diff --git a/drivers/rtc/rtc_sam.c b/drivers/rtc/rtc_sam.c index 059a2b1b33e..e50edd94e3c 100644 --- a/drivers/rtc/rtc_sam.c +++ b/drivers/rtc/rtc_sam.c @@ -645,7 +645,7 @@ static int rtc_sam_get_calibration(const struct device *dev, int32_t *calibratio } #endif /* CONFIG_RTC_CALIBRATION */ -static struct rtc_driver_api rtc_sam_driver_api = { +static const struct rtc_driver_api rtc_sam_driver_api = { .set_time = rtc_sam_set_time, .get_time = rtc_sam_get_time, #ifdef CONFIG_RTC_ALARM diff --git a/drivers/rtc/rtc_shell.c b/drivers/rtc/rtc_shell.c index 8dcaf46f875..bc9980d20af 100644 --- a/drivers/rtc/rtc_shell.c +++ b/drivers/rtc/rtc_shell.c @@ -16,8 +16,6 @@ static const char format_iso8601[] = "%FT%T"; static const char format_time[] = "%T"; /* hh:mm:ss */ static const char format_date[] = " %F"; /* yyyy-mm-dd */ -#if !defined CONFIG_BOARD_NATIVE_POSIX - static const char *consume_chars(const char *s, char *dest, unsigned int cnt) { if (strlen(s) < cnt) { @@ -148,8 +146,6 @@ static char *strptime(const char *s, const char *format, struct tm *tm_time) } } -#endif - static int cmd_set(const struct shell *sh, size_t argc, char **argv) { const struct device *dev = device_get_binding(argv[1]); diff --git a/drivers/rtc/rtc_smartbond.c b/drivers/rtc/rtc_smartbond.c index a16c8ebaeef..bfac974e874 100644 --- a/drivers/rtc/rtc_smartbond.c +++ b/drivers/rtc/rtc_smartbond.c @@ -561,7 +561,7 @@ static int rtc_smartbond_update_set_callback(const struct device *dev, rtc_updat } #endif -struct rtc_driver_api rtc_smartbond_driver_api = { +static const struct rtc_driver_api rtc_smartbond_driver_api = { .get_time = rtc_smartbond_get_time, .set_time = rtc_smartbond_set_time, #if defined(CONFIG_RTC_ALARM) diff --git a/drivers/sdhc/CMakeLists.txt b/drivers/sdhc/CMakeLists.txt index 431867fb2b8..2675589bfc9 100644 --- a/drivers/sdhc/CMakeLists.txt +++ b/drivers/sdhc/CMakeLists.txt @@ -9,4 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_SDIF mcux_sdif.c) zephyr_library_sources_ifdef(CONFIG_SAM_HSMCI sam_hsmci.c) zephyr_library_sources_ifdef(CONFIG_INTEL_EMMC_HOST intel_emmc_host.c) zephyr_library_sources_ifdef(CONFIG_SDHC_INFINEON_CAT1 ifx_cat1_sdio.c) +zephyr_library_sources_ifdef(CONFIG_CDNS_SDHC sdhc_cdns_ll.c sdhc_cdns.c) endif() diff --git a/drivers/sdhc/Kconfig b/drivers/sdhc/Kconfig index 7e75e03a024..13b63cfcc9c 100644 --- a/drivers/sdhc/Kconfig +++ b/drivers/sdhc/Kconfig @@ -14,6 +14,7 @@ source "drivers/sdhc/Kconfig.spi" source "drivers/sdhc/Kconfig.mcux_sdif" source "drivers/sdhc/Kconfig.sam_hsmci" source "drivers/sdhc/Kconfig.intel" +source "drivers/sdhc/Kconfig.sdhc_cdns" config SDHC_INIT_PRIORITY int "SDHC driver init priority" diff --git a/drivers/sdhc/Kconfig.sdhc_cdns b/drivers/sdhc/Kconfig.sdhc_cdns new file mode 100644 index 00000000000..3558763fbf4 --- /dev/null +++ b/drivers/sdhc/Kconfig.sdhc_cdns @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config CDNS_SDHC + bool "CDNS SDHC" + default y + depends on DT_HAS_CDNS_SDHC_ENABLED + select SDHC_SUPPORTS_NATIVE_MODE + help + Enable Cadence SDMMC Host Controller. + +if CDNS_SDHC + +# Cadence SDHC DMA needs 64 bit aligned buffers +config SDHC_BUFFER_ALIGNMENT + default 8 + +config CDNS_DESC_COUNT + int "Allocate number of descriptors" + default 8 + help + SD host controllers require DMA preparation for read and write operation. + Creates static descriptors which can be used by ADMA. Devices should + configure this flag if they require to transfer more than 8*64Kb of data. + +endif # CDNS_SDHC diff --git a/drivers/sdhc/imx_usdhc.c b/drivers/sdhc/imx_usdhc.c index 8ae8fa9741f..84f8f2aee3b 100644 --- a/drivers/sdhc/imx_usdhc.c +++ b/drivers/sdhc/imx_usdhc.c @@ -404,6 +404,7 @@ static int imx_usdhc_set_io(const struct device *dev, struct sdhc_io *ios) case SDHC_TIMING_DDR52: /* Enable DDR mode */ USDHC_EnableDDRMode(cfg->base, true, 0); + __fallthrough; case SDHC_TIMING_SDR12: case SDHC_TIMING_SDR25: pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_SLOW); @@ -1031,7 +1032,15 @@ static int imx_usdhc_init(const struct device *dev) } data->dev = dev; k_mutex_init(&data->access_mutex); - memset(&data->host_io, 0, sizeof(data->host_io)); + /* Setup initial host IO values */ + data->host_io.clock = 0; + data->host_io.bus_mode = SDHC_BUSMODE_PUSHPULL; + data->host_io.power_mode = SDHC_POWER_OFF; + data->host_io.bus_width = SDHC_BUS_WIDTH1BIT; + data->host_io.timing = SDHC_TIMING_LEGACY; + data->host_io.driver_type = SD_DRIVER_TYPE_B; + data->host_io.signal_voltage = SD_VOL_3_3_V; + return k_sem_init(&data->transfer_sem, 0, 1); } diff --git a/drivers/sdhc/intel_emmc_host.c b/drivers/sdhc/intel_emmc_host.c index ec5c7934be1..6286965f156 100644 --- a/drivers/sdhc/intel_emmc_host.c +++ b/drivers/sdhc/intel_emmc_host.c @@ -1087,7 +1087,7 @@ static int emmc_set_io(const struct device *dev, struct sdhc_io *ios) host_io->timing = ios->timing; } - return ret; + return 0; } static int emmc_get_card_present(const struct device *dev) diff --git a/drivers/sdhc/sdhc_cdns.c b/drivers/sdhc/sdhc_cdns.c new file mode 100644 index 00000000000..f5a880e5fb4 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT cdns_sdhc + +#include +#include +#include +#include + +#include "sdhc_cdns_ll.h" + +#define SDHC_CDNS_DESC_SIZE (1<<20) +#define COMBOPHY_ADDR_MASK 0x0000FFFFU + +#define DEV_CFG(_dev) ((const struct sdhc_cdns_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct sdhc_cdns_data *const)(_dev)->data) + +LOG_MODULE_REGISTER(sdhc_cdns, CONFIG_SDHC_LOG_LEVEL); + +/* SDMMC operations FPs are the element of structure*/ +static const struct sdhc_cdns_ops *cdns_sdmmc_ops; + +struct sdhc_cdns_config { + DEVICE_MMIO_NAMED_ROM(reg_base); + DEVICE_MMIO_NAMED_ROM(combo_phy); + /* Clock rate for host */ + uint32_t clk_rate; + /* power delay prop for host */ + uint32_t power_delay_ms; + /* run time device structure */ + const struct device *cdns_clk_dev; + /* type to identify a clock controller sub-system */ + clock_control_subsys_t clkid; + /* Reset controller device configuration. */ + const struct reset_dt_spec reset_sdmmc; + const struct reset_dt_spec reset_sdmmcocp; + const struct reset_dt_spec reset_softphy; +}; + +struct sdhc_cdns_data { + DEVICE_MMIO_NAMED_RAM(reg_base); + DEVICE_MMIO_NAMED_RAM(combo_phy); + /* Host controller parameters */ + struct sdhc_cdns_params params; + /* sdmmc device informartaion for host */ + struct sdmmc_device_info info; + /* Input/Output configuration */ + struct sdhc_io host_io; +}; + +static int sdhc_cdns_request(const struct device *dev, + struct sdhc_command *cmd, + struct sdhc_data *data) +{ + int ret = 0; + struct sdmmc_cmd cdns_sdmmc_cmd; + + if (cmd == NULL) { + LOG_ERR("Wrong CMD parameter"); + return -EINVAL; + } + + /* Initialization of command structure */ + cdns_sdmmc_cmd.cmd_idx = cmd->opcode; + cdns_sdmmc_cmd.cmd_arg = cmd->arg; + cdns_sdmmc_cmd.resp_type = (cmd->response_type & SDHC_NATIVE_RESPONSE_MASK); + + /* Sending command as per the data or non data */ + if (data) { + ret = cdns_sdmmc_ops->prepare(data->block_addr, (uintptr_t)data->data, + data); + if (ret != 0) { + LOG_ERR("DMA Prepare failed"); + return -EINVAL; + } + } + + ret = cdns_sdmmc_ops->send_cmd(&cdns_sdmmc_cmd, data); + + if (ret == 0) { + if (cmd->opcode == SD_READ_SINGLE_BLOCK || cmd->opcode == SD_APP_SEND_SCR || + cmd->opcode == SD_READ_MULTIPLE_BLOCK) { + + if (data == NULL) { + LOG_ERR("Invalid data parameter"); + return -ENODATA; + } + ret = cdns_sdmmc_ops->cache_invd(data->block_addr, (uintptr_t)data->data, + data->block_size); + if (ret != 0) { + return ret; + } + } + } + /* copying all responses as per response type */ + for (int i = 0; i < 4; i++) { + cmd->response[i] = cdns_sdmmc_cmd.resp_data[i]; + } + return ret; +} + +static int sdhc_cdns_get_card_present(const struct device *dev) +{ + return cdns_sdmmc_ops->card_present(); +} + +static int sdhc_cdns_card_busy(const struct device *dev) +{ + return cdns_sdmmc_ops->busy(); +} + +static int sdhc_cdns_get_host_props(const struct device *dev, + struct sdhc_host_props *props) +{ + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + + memset(props, 0, sizeof(struct sdhc_host_props)); + props->f_min = SDMMC_CLOCK_400KHZ; + /* + * default max speed is 25MHZ, as per SCR register + * it will switch accordingly + */ + props->f_max = SD_CLOCK_25MHZ; + props->power_delay = sdhc_config->power_delay_ms; + props->host_caps.vol_330_support = true; + props->is_spi = false; + return 0; +} + +static int sdhc_cdns_reset(const struct device *dev) +{ + return cdns_sdmmc_ops->reset(); +} + +static int sdhc_cdns_init(const struct device *dev) +{ + struct sdhc_cdns_data *const data = DEV_DATA(dev); + const struct sdhc_cdns_config *sdhc_config = DEV_CFG(dev); + int ret; + + /* SDHC reg base */ + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE); + /* ComboPhy reg base */ + DEVICE_MMIO_NAMED_MAP(dev, combo_phy, K_MEM_CACHE_NONE); + + /* clock setting */ + if (sdhc_config->clk_rate == 0U) { + if (!device_is_ready(sdhc_config->cdns_clk_dev)) { + LOG_ERR("Clock controller device is not ready"); + return -EINVAL; + } + + ret = clock_control_get_rate(sdhc_config->cdns_clk_dev, + sdhc_config->clkid, &data->params.clk_rate); + + if (ret != 0) { + return ret; + } + } else { + data->params.clk_rate = sdhc_config->clk_rate; + } + + /* Setting regbase */ + data->params.reg_base = DEVICE_MMIO_NAMED_GET(dev, reg_base); + data->params.reg_phy = DEVICE_MMIO_NAMED_GET(dev, combo_phy); + data->params.combophy = (DEVICE_MMIO_NAMED_ROM_PTR((dev), + combo_phy)->phys_addr); + data->params.combophy = (data->params.combophy & COMBOPHY_ADDR_MASK); + + /* resetting the lines */ + if (sdhc_config->reset_sdmmc.dev != NULL) { + if (!device_is_ready(sdhc_config->reset_sdmmc.dev) || + !device_is_ready(sdhc_config->reset_sdmmcocp.dev) || + !device_is_ready(sdhc_config->reset_softphy.dev)) { + LOG_ERR("Reset device not found"); + return -ENODEV; + } + + ret = reset_line_toggle(sdhc_config->reset_softphy.dev, + sdhc_config->reset_softphy.id); + if (ret != 0) { + LOG_ERR("Softphy Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmc.dev, + sdhc_config->reset_sdmmc.id); + if (ret != 0) { + LOG_ERR("sdmmc Reset failed"); + return ret; + } + + ret = reset_line_toggle(sdhc_config->reset_sdmmcocp.dev, + sdhc_config->reset_sdmmcocp.id); + if (ret != 0) { + LOG_ERR("sdmmcocp Reset failed"); + return ret; + } + } + + /* Init function to call lower layer file */ + sdhc_cdns_sdmmc_init(&data->params, &data->info, &cdns_sdmmc_ops); + + ret = sdhc_cdns_reset(dev); + if (ret != 0U) { + LOG_ERR("Card reset failed"); + return ret; + } + + /* Init operation called for register initialisation */ + ret = cdns_sdmmc_ops->init(); + if (ret != 0U) { + LOG_ERR("Card initialization failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_set_io(const struct device *dev, struct sdhc_io *ios) +{ + struct sdhc_cdns_data *data = dev->data; + struct sdhc_io *host_io = &data->host_io; + + if (host_io->bus_width != ios->bus_width || host_io->clock != + ios->clock) { + host_io->bus_width = ios->bus_width; + host_io->clock = ios->clock; + return cdns_sdmmc_ops->set_ios(ios->clock, ios->bus_width); + } + return 0; +} + +static const struct sdhc_driver_api sdhc_cdns_api = { + .request = sdhc_cdns_request, + .set_io = sdhc_cdns_set_io, + .get_host_props = sdhc_cdns_get_host_props, + .get_card_present = sdhc_cdns_get_card_present, + .reset = sdhc_cdns_reset, + .card_busy = sdhc_cdns_card_busy, +}; + +#define SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ + ( \ + .clk_rate = DT_INST_PROP(inst, clock_frequency), \ + .cdns_clk_dev = NULL, \ + .clkid = (clock_control_subsys_t)0, \ + ), \ + ( \ + .clk_rate = 0, \ + .cdns_clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ + ) \ + ) + +#define SDHC_CDNS_RESET_SPEC_INIT(inst) \ + .reset_sdmmc = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0), \ + .reset_sdmmcocp = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 1),\ + .reset_softphy = RESET_DT_SPEC_INST_GET_BY_IDX(inst, 2), + +#define SDHC_CDNS_INIT(inst) \ + static struct sdhc_cdns_desc cdns_desc \ + [CONFIG_CDNS_DESC_COUNT]; \ + \ + static const struct sdhc_cdns_config sdhc_cdns_config_##inst = {\ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + reg_base, DT_DRV_INST(inst)), \ + DEVICE_MMIO_NAMED_ROM_INIT_BY_NAME( \ + combo_phy, DT_DRV_INST(inst)), \ + SDHC_CDNS_CLOCK_RATE_INIT(inst) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ + (SDHC_CDNS_RESET_SPEC_INIT(inst))) \ + .power_delay_ms = DT_INST_PROP(inst, power_delay_ms), \ + }; \ + static struct sdhc_cdns_data sdhc_cdns_data_##inst = { \ + .params = { \ + .bus_width = SDHC_BUS_WIDTH1BIT, \ + .desc_base = (uintptr_t) &cdns_desc, \ + .desc_size = SDHC_CDNS_DESC_SIZE, \ + .flags = 0, \ + }, \ + .info = { \ + .cdn_sdmmc_dev_type = SD_DS, \ + .ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3, \ + }, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + &sdhc_cdns_init, \ + NULL, \ + &sdhc_cdns_data_##inst, \ + &sdhc_cdns_config_##inst, \ + POST_KERNEL, \ + CONFIG_SDHC_INIT_PRIORITY, \ + &sdhc_cdns_api); + +DT_INST_FOREACH_STATUS_OKAY(SDHC_CDNS_INIT) diff --git a/drivers/sdhc/sdhc_cdns_ll.c b/drivers/sdhc/sdhc_cdns_ll.c new file mode 100644 index 00000000000..773b92b0e05 --- /dev/null +++ b/drivers/sdhc/sdhc_cdns_ll.c @@ -0,0 +1,793 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdhc_cdns_ll.h" +#include + +LOG_MODULE_REGISTER(sdhc_cdns_ll, CONFIG_SDHC_LOG_LEVEL); + +/* card busy and present */ +#define CARD_BUSY 1 +#define CARD_NOT_BUSY 0 +#define CARD_PRESENT 1 + +/* SRS12 error mask */ +#define CDNS_SRS12_ERR_MASK 0xFFFF8000U +#define CDNS_CSD_BYTE_MASK 0x000000FFU + +/* General define */ +#define SDHC_REG_MASK 0xFFFFFFFFU +#define SD_HOST_BLOCK_SIZE 0x200 + +#define SDMMC_DMA_MAX_BUFFER_SIZE (64 * 1024) +#define CDNSMMC_ADDRESS_MASK (CONFIG_SDHC_BUFFER_ALIGNMENT - 1) + +#define SRS10_VAL_READ (ADMA2_32 | HS_EN | DT_WIDTH) +#define SRS10_VAL_SW (ADMA2_32 | DT_WIDTH) +#define SRS11_VAL_GEN (READ_CLK | CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS11_VAL_CID (CDNS_SRS11_ICE | CDNS_SRS11_ICS | CDNS_SRS11_SDCE) +#define SRS15_VAL_GEN (CDNS_SRS15_BIT_AD_64 | CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) +#define SRS15_VAL_RD_WR (SRS15_VAL_GEN | CDNS_SRS15_SDR104 | CDNS_SRS15_PVE) +#define SRS15_VAL_CID (CDNS_SRS15_HV4E | CDNS_SRS15_V18SE) + +#define CARD_REG_TIME_DELAY_US 100000 +#define WAIT_ICS_TIME_DELAY_US 5000 +#define RESET_SRS14 0x00000000 + +static struct sdhc_cdns_params cdns_params; +static struct sdhc_cdns_combo_phy sdhc_cdns_combo_phy_reg_info; +static struct sdhc_cdns_sdmmc sdhc_cdns_sdmmc_reg_info; + +/* Function to write general phy registers */ +static int sdhc_cdns_write_phy_reg(uint32_t phy_reg_addr, uint32_t phy_reg_addr_value, + uint32_t phy_reg_data, uint32_t phy_reg_data_value) +{ + uint32_t data = 0; + + /* Set PHY register address, write HRS04*/ + sys_write32(phy_reg_addr_value, phy_reg_addr); + + /* Set PHY register data, write HRS05 */ + sys_write32(phy_reg_data_value, phy_reg_data); + data = sys_read32(phy_reg_data); + + if (data != phy_reg_data_value) { + LOG_ERR("PHY_REG_DATA is not set properly"); + return -ENXIO; + } + + return 0; +} + +int sdhc_cdns_wait_ics(uint16_t timeout, uint32_t cdn_srs_res) +{ + /* Wait status command response ready */ + if (!WAIT_FOR(((sys_read32(cdn_srs_res) & CDNS_SRS11_ICS) + == CDNS_SRS11_ICS), timeout, k_msleep(1))) { + LOG_ERR("Timed out waiting for ICS response"); + return -ETIMEDOUT; + } + + return 0; +} + +static int sdhc_cdns_busy(void) +{ + unsigned int data; + + data = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09); + return (data & CDNS_SRS09_STAT_DAT_BUSY) ? CARD_BUSY : CARD_NOT_BUSY; +} + +static int sdhc_cdns_card_present(void) +{ + uint32_t timeout = CARD_REG_TIME_DELAY_US; + + if (!WAIT_FOR((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS09)) + & CDNS_SRS09_CI) == CDNS_SRS09_CI), + timeout, k_msleep(1))) { + LOG_ERR("Card detection timeout"); + return -ETIMEDOUT; + } + + return CARD_PRESENT; +} + +static int sdhc_cdns_vol_reset(void) +{ + /* Reset embedded card, turn off supply voltage */ + sys_write32(BUS_VOLTAGE_3_3_V, + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + /* + * Turn on supply voltage + * CDNS_SRS10_BVS = 7, CDNS_SRS10_BP = 1, BP2 only in UHS2 mode + */ + sys_write32(BUS_VOLTAGE_3_3_V | CDNS_SRS10_BP, + (cdns_params.reg_base + SDHC_CDNS_SRS10)); + + return 0; +} + +/* + * Values are taken from IP documents and calc_setting.py script + * with input value- mode sd_ds, + * sdmclk 5000, + * sdclk 10000, + * iocell_input_delay 2500, + * iocell_output_delay 2500 and + * delay_element 24 + */ +void cdns_sdhc_set_sdmmc_params(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + /* Values are taken by the reference of cadence IP documents */ + sdhc_cdns_combo_phy_reg->cp_clk_wr_delay = 0; + sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_data_select_oe_end = 1; + sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode = 1; + sdhc_cdns_combo_phy_reg->cp_dll_locked_mode = 3; + sdhc_cdns_combo_phy_reg->cp_dll_start_point = 4; + sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on = 1; + sdhc_cdns_combo_phy_reg->cp_io_mask_always_on = 0; + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 2; + sdhc_cdns_combo_phy_reg->cp_io_mask_start = 0; + sdhc_cdns_combo_phy_reg->cp_rd_del_sel = 52; + sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay = 0; + sdhc_cdns_combo_phy_reg->cp_read_dqs_delay = 0; + sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift = 0; + sdhc_cdns_combo_phy_reg->cp_sync_method = 1; + sdhc_cdns_combo_phy_reg->cp_underrun_suppress = 1; + sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs = 1; + sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd = 1; + + sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode = 1; + sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj = 6; + sdhc_cdns_sdmmc_reg->sdhc_idelay_val = 1; + sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rddata_en = 1; + sdhc_cdns_sdmmc_reg->sdhc_rw_compensate = 10; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsh = 0; + sdhc_cdns_sdmmc_reg->sdhc_sdcfsl = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly = 1; + sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly = 0; + sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly = 0; +} + +/* Phy register programing for phy init */ +static int sdhc_cdns_program_phy_reg(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program PHY_DQS_TIMING_REG + * This register controls the DQS related timing + */ + value = (CP_USE_EXT_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_ext_lpbk_dqs)) + | (CP_USE_LPBK_DQS(sdhc_cdns_combo_phy_reg->cp_use_lpbk_dqs)) + | (CP_USE_PHONY_DQS(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs)) + | (CP_USE_PHONY_DQS_CMD(sdhc_cdns_combo_phy_reg->cp_use_phony_dqs_cmd)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQS_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQS_TIMING_REG programming"); + return ret; + } + + /* + * program PHY_GATE_LPBK_CTRL_REG + * This register controls the gate and loopback control related timing. + */ + value = (CP_SYNC_METHOD(sdhc_cdns_combo_phy_reg->cp_sync_method)) + | (CP_SW_HALF_CYCLE_SHIFT(sdhc_cdns_combo_phy_reg->cp_sw_half_cycle_shift)) + | (CP_RD_DEL_SEL(sdhc_cdns_combo_phy_reg->cp_rd_del_sel)) + | (CP_UNDERRUN_SUPPRESS(sdhc_cdns_combo_phy_reg->cp_underrun_suppress)) + | (CP_GATE_CFG_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_gate_cfg_always_on)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_GATE_LPBK_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_GATE_LPBK_CTRL_REG programming"); + return -ret; + } + + /* + * program PHY_DLL_MASTER_CTRL_REG + * This register holds the control for the Master DLL logic. + */ + value = (CP_DLL_BYPASS_MODE(sdhc_cdns_combo_phy_reg->cp_dll_bypass_mode)) + | (CP_DLL_START_POINT(sdhc_cdns_combo_phy_reg->cp_dll_start_point)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_MASTER_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_MASTER_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_DLL_SLAVE_CTRL_REG + * This register holds the control for the slave DLL logic. + */ + value = (CP_READ_DQS_CMD_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_cmd_delay)) + | (CP_CLK_WRDQS_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wrdqs_delay)) + | (CP_CLK_WR_DELAY(sdhc_cdns_combo_phy_reg->cp_clk_wr_delay)) + | (CP_READ_DQS_DELAY(sdhc_cdns_combo_phy_reg->cp_read_dqs_delay)); + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DLL_SLAVE_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DLL_SLAVE_CTRL_REG programming"); + return ret; + } + + /* + * program PHY_CTRL_REG + * This register handles the global control settings for the PHY. + */ + sys_write32(cdns_params.combophy + PHY_CTRL_REG, cdns_params.reg_base + + SDHC_CDNS_HRS04); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* phony_dqs_timing=0 */ + value &= ~(CP_PHONY_DQS_TIMING_MASK << CP_PHONY_DQS_TIMING_SHIFT); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS05); + + /* switch off DLL_RESET */ + do { + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + value |= CDNS_HRS09_PHY_SW_RESET; + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09); + /* polling PHY_INIT_COMPLETE */ + } while ((value & CDNS_HRS09_PHY_INIT_COMP) != CDNS_HRS09_PHY_INIT_COMP); + + /* + * program PHY_DQ_TIMING_REG + * This register controls the DQ related timing. + */ + sdhc_cdns_combo_phy_reg->cp_io_mask_end = 0U; + value = (CP_IO_MASK_ALWAYS_ON(sdhc_cdns_combo_phy_reg->cp_io_mask_always_on)) + | (CP_IO_MASK_END(sdhc_cdns_combo_phy_reg->cp_io_mask_end)) + | (CP_IO_MASK_START(sdhc_cdns_combo_phy_reg->cp_io_mask_start)) + | (CP_DATA_SELECT_OE_END(sdhc_cdns_combo_phy_reg->cp_data_select_oe_end)); + + ret = sdhc_cdns_write_phy_reg(cdns_params.reg_base + SDHC_CDNS_HRS04, + cdns_params.combophy + PHY_DQ_TIMING_REG, cdns_params.reg_base + + SDHC_CDNS_HRS05, value); + if (ret != 0U) { + LOG_ERR("Error in PHY_DQ_TIMING_REG programming"); + return ret; + } + return 0; +} + +static int sdhc_cdns_cache_invd(int lba, uintptr_t buf, size_t size) +{ + int ret = 0; + + ret = arch_dcache_invd_range((void *)buf, size); + if (ret != 0) { + LOG_ERR("%s: error in invalidate dcache with ret %d", __func__, ret); + return ret; + } + + return 0; +} + +/* DMA preparation for the read and write operation */ +static int sdhc_cdns_prepare(uint32_t dma_start_addr, uintptr_t dma_buff, + struct sdhc_data *data) +{ + struct sdhc_cdns_desc *desc; + uint32_t desc_cnt, i; + uintptr_t base; + uint64_t desc_base; + uint32_t size = data->blocks * data->block_size; + + __ASSERT_NO_MSG(((dma_buff & CDNSMMC_ADDRESS_MASK) == 0) && + (cdns_params.desc_size > 0) && + ((cdns_params.desc_size & MMC_BLOCK_MASK) == 0)); + + arch_dcache_flush_range((void *)dma_buff, size); + + desc_cnt = (size + (SDMMC_DMA_MAX_BUFFER_SIZE) - 1) / + (SDMMC_DMA_MAX_BUFFER_SIZE); + __ASSERT_NO_MSG(desc_cnt * sizeof(struct sdhc_cdns_desc) < + cdns_params.desc_size); + + if (desc_cnt > CONFIG_CDNS_DESC_COUNT) { + LOG_ERR("Requested data transfer length %u greater than configured length %u", + size, (CONFIG_CDNS_DESC_COUNT * SDMMC_DMA_MAX_BUFFER_SIZE)); + return -EINVAL; + } + + /* + * Creating descriptor as per the desc_count and linked list of + * descriptor for contiguous desc alignment + */ + base = cdns_params.reg_base; + desc = (struct sdhc_cdns_desc *)cdns_params.desc_base; + desc_base = (uint64_t)desc; + i = 0; + + while ((i+1) < desc_cnt) { + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA; + desc->reserved = 0; + desc->len = MAX_64KB_PAGE; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + size -= SDMMC_DMA_MAX_BUFFER_SIZE; + desc++; + i++; + } + + desc->attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA | + ADMA_DESC_ATTR_END; + desc->reserved = 0; + desc->len = size; + desc->addr_lo = (dma_buff & 0xffffffff) + (SDMMC_DMA_MAX_BUFFER_SIZE * i); + desc->addr_hi = (dma_buff >> 32) & 0xffffffff; + + sys_write32((uint32_t)desc_base, cdns_params.reg_base + SDHC_CDNS_SRS22); + sys_write32((uint32_t)(desc_base >> 32), cdns_params.reg_base + SDHC_CDNS_SRS23); + arch_dcache_flush_range((void *)cdns_params.desc_base, + desc_cnt * sizeof(struct sdhc_cdns_desc)); + + sys_write32((data->block_size << CDNS_SRS01_BLK_SIZE | + data->blocks << CDNS_SRS01_BLK_COUNT_CT | + BUFFER_BOUNDARY_512K << CDNS_SRS01_SDMA_BUF), + cdns_params.reg_base + SDHC_CDNS_SRS01); + + return 0; +} + +static int sdhc_cdns_host_set_clk(int clk) +{ + uint32_t sdclkfsval = 0; + uint32_t dtcvval = 0xe; + int ret = 0; + + sdclkfsval = (cdns_params.clk_rate / 2000) / clk; + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + CDNS_SRS11_ICE), cdns_params.reg_base + SDHC_CDNS_SRS11); + + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) + & 0xFFFFFFF7) | CDNS_HRS09_EXT_WR_MODE), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_RDCMD_EN_BIT | + CDNS_HRS09_RDDATA_EN_BIT); + + sys_write32(((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) + | CDNS_SRS11_ICE | CDNS_SRS11_SDCE), + cdns_params.reg_base + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + + return 0; +} + +static int sdhc_cdns_set_ios(unsigned int clk, unsigned int width) +{ + int ret = 0; + + switch (width) { + case SDHC_BUS_WIDTH1BIT: + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT1); + break; + case SDHC_BUS_WIDTH4BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT4); + break; + case SDHC_BUS_WIDTH8BIT: + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_SRS10, WIDTH_BIT8); + break; + default: + __ASSERT_NO_MSG(0); + break; + } + + /* Perform clock configuration when SD clock is not gated */ + if (clk != 0) { + ret = sdhc_cdns_host_set_clk(clk); + if (ret != 0) { + LOG_ERR("%s: Clock configuration failed", __func__); + return ret; + } + } + + return 0; +} + +/* Programming HRS register for initialisation */ +static int sdhc_cdns_init_hrs_io(struct sdhc_cdns_combo_phy *sdhc_cdns_combo_phy_reg, + struct sdhc_cdns_sdmmc *sdhc_cdns_sdmmc_reg) +{ + uint32_t value = 0; + int ret = 0; + + /* + * program HRS09, register 42 + * PHY Control and Status Register + */ + value = (CDNS_HRS09_RDDATA_EN(sdhc_cdns_sdmmc_reg->sdhc_rddata_en)) + | (CDNS_HRS09_RDCMD_EN(sdhc_cdns_sdmmc_reg->sdhc_rdcmd_en)) + | (CDNS_HRS09_EXTENDED_WR(sdhc_cdns_sdmmc_reg->sdhc_extended_wr_mode)) + | (CDNS_HRS09_EXT_RD_MODE(sdhc_cdns_sdmmc_reg->sdhc_extended_rd_mode)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS09); + + /* + * program HRS10, register 43 + * Host Controller SDCLK start point adjustment + */ + value = (SDHC_HRS10_HCSDCLKADJ(sdhc_cdns_sdmmc_reg->sdhc_hcsdclkadj)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS10); + + /* + * program HRS16, register 48 + * CMD/DAT output delay + */ + value = (CDNS_HRS16_WRDATA1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_sdclk_dly)) + | (CDNS_HRS16_WRDATA0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_sdclk_dly)) + | (CDNS_HRS16_WRCMD1_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_sdclk_dly)) + | (CDNS_HRS16_WRCMD0_SDCLK_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_sdclk_dly)) + | (CDNS_HRS16_WRDATA1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata1_dly)) + | (CDNS_HRS16_WRDATA0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrdata0_dly)) + | (CDNS_HRS16_WRCMD1_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd1_dly)) + | (CDNS_HRS16_WRCMD0_DLY(sdhc_cdns_sdmmc_reg->sdhc_wrcmd0_dly)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS16); + + /* + * program HRS07, register 40 + * IO Delay Information Register + */ + value = (CDNS_HRS07_RW_COMPENSATE(sdhc_cdns_sdmmc_reg->sdhc_rw_compensate)) + | (CDNS_HRS07_IDELAY_VAL(sdhc_cdns_sdmmc_reg->sdhc_idelay_val)); + sys_write32(value, cdns_params.reg_base + SDHC_CDNS_HRS07); + + return ret; +} + +static int sdhc_cdns_set_clk(struct sdhc_cdns_params *cdn_sdmmc_dev_type_params) +{ + uint32_t dtcvval, sdclkfsval; + int ret = 0; + + dtcvval = DTC_VAL; + sdclkfsval = 0; + + /* Condition for Default speed mode and SDR12 and SDR_BC */ + if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_DS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR12) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR_BC)) { + sdclkfsval = 4; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_HS) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR25) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_DDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_SDR)) { + sdclkfsval = 2; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR50) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_DDR) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS400ES)) { + sdclkfsval = 1; + } else if ((cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == SD_UHS_SDR104) || + (cdn_sdmmc_dev_type_params->cdn_sdmmc_dev_type == EMMC_HS200)) { + sdclkfsval = 0; + } + + /* Disabling SD clock enable */ + sys_write32(0, cdns_params.reg_base + SDHC_CDNS_SRS11); + sys_write32((dtcvval << CDNS_SRS11_DTCV) | + (sdclkfsval << CDNS_SRS11_SDCLKFS) | CDNS_SRS11_ICE, + cdns_params.reg_base + SDHC_CDNS_SRS11); + ret = sdhc_cdns_wait_ics(WAIT_ICS_TIME_DELAY_US, cdns_params.reg_base + SDHC_CDNS_SRS11); + if (ret != 0) { + return ret; + } + + /* Enable DLL reset */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, 0); + /* Set extended_wr_mode */ + sys_write32(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS09) & + 0xFFFFFFF7) | CDNS_HRS09_EXT_WR_MODE), (cdns_params.reg_base + + SDHC_CDNS_HRS09)); + /* Release DLL reset */ + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_RDCMD_EN_BIT | + CDNS_HRS09_RDDATA_EN_BIT); + + sys_write32((dtcvval << CDNS_SRS11_DTCV) | (sdclkfsval << CDNS_SRS11_SDCLKFS) | + CDNS_SRS11_ICE | CDNS_SRS11_SDCE, cdns_params.reg_base + + SDHC_CDNS_SRS11); + + sys_write32(0xFFFFFFFF, cdns_params.reg_base + SDHC_CDNS_SRS13); + return 0; +} + +static int sdhc_cdns_reset(void) +{ + int32_t timeout; + + sys_clear_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, 0xFFFF); + + /* Software reset */ + sys_set_bit(cdns_params.reg_base + SDHC_CDNS_HRS00, CDNS_HRS00_SWR); + + /* Wait status command response ready */ + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((sys_read32(cdns_params.reg_base + SDHC_CDNS_HRS00) & + CDNS_HRS00_SWR) == 0), timeout, k_msleep(1))) { + LOG_ERR("Software reset is not completed...timedout"); + return -ETIMEDOUT; + } + + /* Step 1, switch on DLL_RESET */ + sys_clear_bit(cdns_params.reg_base + SDHC_CDNS_HRS09, CDNS_HRS09_PHY_SW_RESET); + + return 0; +} + +static int sdhc_cdns_init(void) +{ + int ret = 0; + + ret = sdhc_cdns_program_phy_reg(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("SoftPhy register configuration failed"); + return ret; + } + + ret = sdhc_cdns_init_hrs_io(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); + if (ret != 0U) { + LOG_ERR("Configuration for HRS IO reg failed"); + return ret; + } + + ret = sdhc_cdns_card_present(); + if (ret != CARD_PRESENT) { + LOG_ERR("SD card does not detect"); + return -ETIMEDOUT; + } + + ret = sdhc_cdns_vol_reset(); + if (ret != 0U) { + LOG_ERR("SD/MMC card reset failed"); + return ret; + } + + ret = sdhc_cdns_set_clk(&cdns_params); + if (ret != 0U) { + LOG_ERR("Host controller set clk failed"); + return ret; + } + + return 0; +} + +static int sdhc_cdns_send_cmd(struct sdmmc_cmd *cmd, struct sdhc_data *data) +{ + uint32_t op = 0; + uint32_t value; + uintptr_t base; + int32_t timeout; + uint32_t cmd_indx; + uint32_t status_check = 0; + + __ASSERT(cmd, "Assert %s function call", __func__); + base = cdns_params.reg_base; + cmd_indx = (cmd->cmd_idx) << CDNS_SRS03_COM_IDX; + + if (data) { + switch (cmd->cmd_idx) { + case SD_SWITCH: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_SW); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + case SD_WRITE_SINGLE_BLOCK: + case SD_READ_SINGLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_WRITE_MULTIPLE_BLOCK: + case SD_READ_MULTIPLE_BLOCK: + op = CDNS_SRS03_DATA_PRSNT | AUTO_CMD23 | CDNS_SRS03_MULTI_BLK_READ; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, SRS10_VAL_READ); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_RD_WR); + sys_write32(CDNS_SRS00_SAAR, cdns_params.reg_base + SDHC_CDNS_SRS00); + break; + + case SD_APP_SEND_SCR: + op = CDNS_SRS03_DATA_PRSNT; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS10, ADMA2_32); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_GEN); + break; + + default: + op = 0; + break; + } + } else { + switch (cmd->cmd_idx) { + case SD_GO_IDLE_STATE: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_ALL_SEND_CID: + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_CID); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, SRS15_VAL_CID); + break; + + case SD_SEND_IF_COND: + op = CDNS_SRS03_CMD_IDX_CHK_EN; + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS11, SRS11_VAL_GEN); + sys_set_bits(cdns_params.reg_base + SDHC_CDNS_SRS15, CDNS_SRS15_HV4E); + break; + + case SD_STOP_TRANSMISSION: + op = CMD_STOP_ABORT_CMD; + break; + + case SD_SEND_STATUS: + break; + + case SD_SELECT_CARD: + op = CDNS_SRS03_MULTI_BLK_READ; + break; + + default: + op = 0; + break; + } + } + + switch (cmd->resp_type) { + case SD_RSP_TYPE_NONE: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN); + break; + + case SD_RSP_TYPE_R2: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | + RES_TYPE_SEL_136 | CDNS_SRS03_RESP_CRCCE); + break; + + case SD_RSP_TYPE_R3: + op |= (CDNS_SRS03_CMD_READ | CDNS_SRS03_MULTI_BLK_READ | + CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48); + break; + + case SD_RSP_TYPE_R1: + if ((cmd->cmd_idx == SD_WRITE_SINGLE_BLOCK) || (cmd->cmd_idx + == SD_WRITE_MULTIPLE_BLOCK)) { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | RES_TYPE_SEL_48 + | CDNS_SRS03_RESP_CRCCE | CDNS_SRS03_CMD_IDX_CHK_EN); + } else { + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ + | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRCCE | CDNS_SRS03_CMD_IDX_CHK_EN); + } + break; + + default: + op |= (CDNS_SRS03_DMA_EN | CDNS_SRS03_BLK_CNT_EN | CDNS_SRS03_CMD_READ | + CDNS_SRS03_MULTI_BLK_READ | RES_TYPE_SEL_48 | CDNS_SRS03_RESP_CRCCE | + CDNS_SRS03_CMD_IDX_CHK_EN); + break; + } + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR((sdhc_cdns_busy() == 0), timeout, k_msleep(1))) { + k_panic(); + } + + sys_write32(~0, cdns_params.reg_base + SDHC_CDNS_SRS12); + + sys_write32(cmd->cmd_arg, cdns_params.reg_base + SDHC_CDNS_SRS02); + sys_write32(RESET_SRS14, cdns_params.reg_base + SDHC_CDNS_SRS14); + sys_write32(op | cmd_indx, cdns_params.reg_base + SDHC_CDNS_SRS03); + + timeout = CARD_REG_TIME_DELAY_US; + if (!WAIT_FOR(((((sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12)) & + CDNS_SRS12_CC) == CDNS_SRS12_CC) | (((sys_read32(cdns_params.reg_base + + SDHC_CDNS_SRS12)) & CDNS_SRS12_EINT) == CDNS_SRS12_EINT)), + timeout, k_msleep(1))) { + LOG_ERR("Response timeout SRS12"); + return -ETIMEDOUT; + } + + value = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS12); + status_check = value & CDNS_SRS12_ERR_MASK; + if (status_check != 0U) { + LOG_ERR("SD host controller send command failed, SRS12 = %X", status_check); + return -EIO; + } + + if ((op & RES_TYPE_SEL_48) || (op & RES_TYPE_SEL_136)) { + cmd->resp_data[0] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS04); + if (op & RES_TYPE_SEL_136) { + cmd->resp_data[1] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS05); + cmd->resp_data[2] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS06); + cmd->resp_data[3] = sys_read32(cdns_params.reg_base + SDHC_CDNS_SRS07); + + /* 136-bit: RTS=01b, Response field R[127:8] - RESP3[23:0], + * RESP2[31:0], RESP1[31:0], RESP0[31:0] + * Subsystem expects 128 bits response but cadence SDHC sends + * 120 bits response from R[127:8]. Bits manupulation to address + * the correct responses for the 136 bit response type. + */ + cmd->resp_data[3] = ((cmd->resp_data[3] << 8) | ((cmd->resp_data[2] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[2] = ((cmd->resp_data[2] << 8) | ((cmd->resp_data[1] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[1] = ((cmd->resp_data[1] << 8) | ((cmd->resp_data[0] >> 24) + & CDNS_CSD_BYTE_MASK)); + cmd->resp_data[0] = (cmd->resp_data[0] << 8); + } + } + + return 0; +} + +static const struct sdhc_cdns_ops cdns_sdmmc_ops = { + .init = sdhc_cdns_init, + .send_cmd = sdhc_cdns_send_cmd, + .card_present = sdhc_cdns_card_present, + .set_ios = sdhc_cdns_set_ios, + .prepare = sdhc_cdns_prepare, + .cache_invd = sdhc_cdns_cache_invd, + .busy = sdhc_cdns_busy, + .reset = sdhc_cdns_reset, +}; + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops) +{ + __ASSERT_NO_MSG((params != NULL) && + ((params->reg_base & MMC_BLOCK_MASK) == 0) && + ((params->desc_size & MMC_BLOCK_MASK) == 0) && + ((params->reg_phy & MMC_BLOCK_MASK) == 0) && + (params->desc_size > 0) && + (params->clk_rate > 0) && + ((params->bus_width == MMC_BUS_WIDTH_1) || + (params->bus_width == MMC_BUS_WIDTH_4) || + (params->bus_width == MMC_BUS_WIDTH_8))); + + memcpy(&cdns_params, params, sizeof(struct sdhc_cdns_params)); + cdns_params.cdn_sdmmc_dev_type = info->cdn_sdmmc_dev_type; + *cb_sdmmc_ops = &cdns_sdmmc_ops; + + cdns_sdhc_set_sdmmc_params(&sdhc_cdns_combo_phy_reg_info, &sdhc_cdns_sdmmc_reg_info); +} diff --git a/drivers/sdhc/sdhc_cdns_ll.h b/drivers/sdhc/sdhc_cdns_ll.h new file mode 100644 index 00000000000..5ffaa75c79c --- /dev/null +++ b/drivers/sdhc/sdhc_cdns_ll.h @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* HRS09 */ +#define CDNS_HRS09_PHY_SW_RESET BIT(0) +#define CDNS_HRS09_PHY_INIT_COMP BIT(1) +#define CDNS_HRS09_EXT_WR_MODE BIT(3) +#define CDNS_HRS09_RDCMD_EN_BIT BIT(15) +#define CDNS_HRS09_RDDATA_EN_BIT BIT(16) +#define CDNS_HRS09_EXT_RD_MODE(x) ((x) << 2) +#define CDNS_HRS09_EXTENDED_WR(x) ((x) << 3) +#define CDNS_HRS09_RDCMD_EN(x) ((x) << 15) +#define CDNS_HRS09_RDDATA_EN(x) ((x) << 16) + +/* HRS00 */ +#define CDNS_HRS00_SWR BIT(0) + +/* CMD_DATA_OUTPUT */ +#define SDHC_CDNS_HRS16 0x40 + +/* SRS09 - Present State Register */ +#define CDNS_SRS09_STAT_DAT_BUSY BIT(2) +#define CDNS_SRS09_CI BIT(16) + +/* SRS10 - Host Control 1 (General / Power / Block-Gap / Wake-Up) */ +#define LEDC BIT(0) +#define DT_WIDTH BIT(1) +#define HS_EN BIT(2) + +#define CDNS_SRS10_DTW 1 +#define CDNS_SRS10_EDTW 5 +#define CDNS_SRS10_BP BIT(8) + +#define CDNS_SRS10_BVS 9 +#define BUS_VOLTAGE_1_8_V (5 << CDNS_SRS10_BVS) +#define BUS_VOLTAGE_3_0_V (6 << CDNS_SRS10_BVS) +#define BUS_VOLTAGE_3_3_V (7 << CDNS_SRS10_BVS) + + +/* data bus width */ +#define WIDTH_BIT1 CDNS_SRS10_DTW +#define WIDTH_BIT4 CDNS_SRS10_DTW +#define WIDTH_BIT8 CDNS_SRS10_EDTW + +/* SRS11 */ +#define CDNS_SRS11_ICE BIT(0) +#define CDNS_SRS11_ICS BIT(1) +#define CDNS_SRS11_SDCE BIT(2) +#define CDNS_SRS11_USDCLKFS 6 +#define CDNS_SRS11_SDCLKFS 8 +#define CDNS_SRS11_DTCV 16 +#define CDNS_SRS11_SRFA BIT(24) +#define CDNS_SRS11_SRCMD BIT(25) +#define CDNS_SRS11_SRDAT BIT(26) + +/* + * This value determines the interval by which DAT line timeouts are detected + * The interval can be computed as below: + * • 1111b - Reserved + * • 1110b - t_sdmclk*2(27+2) + * • 1101b - t_sdmclk*2(26+2) + */ +#define DTC_VAL 0xE +#define READ_CLK (0xa << CDNS_SRS11_DTCV) +#define WRITE_CLK (0xe << CDNS_SRS11_DTCV) + + +/* SRS12 */ +#define CDNS_SRS12_CC BIT(0) +#define CDNS_SRS12_TC BIT(1) +#define CDNS_SRS12_EINT BIT(15) + +/* SDMA Buffer Boundary */ +#define BUFFER_BOUNDARY_4K 0U +#define BUFFER_BOUNDARY_8K 1U +#define BUFFER_BOUNDARY_16K 2U +#define BUFFER_BOUNDARY_32K 3U +#define BUFFER_BOUNDARY_64K 4U +#define BUFFER_BOUNDARY_128K 5U +#define BUFFER_BOUNDARY_256K 6U +#define BUFFER_BOUNDARY_512K 7U + +/* SRS01 */ +#define CDNS_SRS01_BLK_SIZE 0U +#define CDNS_SRS01_SDMA_BUF 12 +#define CDNS_SRS01_BLK_COUNT_CT 16 + +/* SRS15 Registers */ +#define CDNS_SRS15_UMS 16 +#define CDNS_SRS15_SDR12 (0 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR25 (1 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR50 (2 << CDNS_SRS15_UMS) +#define CDNS_SRS15_SDR104 (3 << CDNS_SRS15_UMS) +#define CDNS_SRS15_DDR50 (4 << CDNS_SRS15_UMS) +/* V18SE is 0 for DS and HS, 1 for UHS-I */ +#define CDNS_SRS15_V18SE BIT(19) +#define CDNS_SRS15_CMD23_EN BIT(27) +/* HC4E is 0 means version 3.0 and 1 means v 4.0 */ +#define CDNS_SRS15_HV4E BIT(28) +#define CDNS_SRS15_BIT_AD_32 0U +#define CDNS_SRS15_BIT_AD_64 BIT(29) +#define CDNS_SRS15_PVE BIT(31) + +/* Combo PHY */ +#define PHY_DQ_TIMING_REG 0x0 +#define PHY_DQS_TIMING_REG 0x04 +#define PHY_GATE_LPBK_CTRL_REG 0x08 +#define PHY_DLL_MASTER_CTRL_REG 0x0C +#define PHY_DLL_SLAVE_CTRL_REG 0x10 +#define PHY_CTRL_REG 0x80 + +#define PERIPHERAL_SDMMC_MASK 0x60 +#define PERIPHERAL_SDMMC_OFFSET 6 +#define DFI_INTF_MASK 0x1 + +/* PHY_DQS_TIMING_REG */ +#define CP_USE_EXT_LPBK_DQS(x) (x << 22) +#define CP_USE_LPBK_DQS(x) (x << 21) +#define CP_USE_PHONY_DQS(x) (x << 20) +#define CP_USE_PHONY_DQS_CMD(x) (x << 19) + +/* PHY_GATE_LPBK_CTRL_REG */ +#define CP_SYNC_METHOD(x) ((x) << 31) +#define CP_SW_HALF_CYCLE_SHIFT(x) ((x) << 28) +#define CP_RD_DEL_SEL(x) ((x) << 19) +#define CP_UNDERRUN_SUPPRESS(x) ((x) << 18) +#define CP_GATE_CFG_ALWAYS_ON(x) ((x) << 6) + +/* PHY_DLL_MASTER_CTRL_REG */ +#define CP_DLL_BYPASS_MODE(x) ((x) << 23) +#define CP_DLL_START_POINT(x) ((x) << 0) + +/* PHY_DLL_SLAVE_CTRL_REG */ +#define CP_READ_DQS_CMD_DELAY(x) ((x) << 24) +#define CP_CLK_WRDQS_DELAY(x) ((x) << 16) +#define CP_CLK_WR_DELAY(x) ((x) << 8) +#define CP_READ_DQS_DELAY(x) (x) + +/* PHY_DQ_TIMING_REG */ +#define CP_IO_MASK_ALWAYS_ON(x) ((x) << 31) +#define CP_IO_MASK_END(x) ((x) << 27) +#define CP_IO_MASK_START(x) ((x) << 24) +#define CP_DATA_SELECT_OE_END(x) (x) + +/* SW RESET REG */ +#define SDHC_CDNS_HRS00 (0x00) +#define CDNS_HRS00_SWR BIT(0) + +/* PHY access port */ +#define SDHC_CDNS_HRS04 0x10 +#define CDNS_HRS04_ADDR GENMASK(5, 0) + +/* PHY data access port */ +#define SDHC_CDNS_HRS05 0x14 + +/* eMMC control registers */ +#define SDHC_CDNS_HRS06 0x18 + +/* PHY_CTRL_REG */ +#define CP_PHONY_DQS_TIMING_MASK 0x3F +#define CP_PHONY_DQS_TIMING_SHIFT 4 + +/* SRS */ +#define SDHC_CDNS_SRS00 0x200 +#define SDHC_CDNS_SRS01 0x204 +#define SDHC_CDNS_SRS02 0x208 +#define SDHC_CDNS_SRS03 0x20c +#define SDHC_CDNS_SRS04 0x210 +#define SDHC_CDNS_SRS05 0x214 +#define SDHC_CDNS_SRS06 0x218 +#define SDHC_CDNS_SRS07 0x21C +#define SDHC_CDNS_SRS08 0x220 +#define SDHC_CDNS_SRS09 0x224 +#define SDHC_CDNS_SRS10 0x228 +#define SDHC_CDNS_SRS11 0x22C +#define SDHC_CDNS_SRS12 0x230 +#define SDHC_CDNS_SRS13 0x234 +#define SDHC_CDNS_SRS14 0x238 +#define SDHC_CDNS_SRS15 0x23c +#define SDHC_CDNS_SRS21 0x254 +#define SDHC_CDNS_SRS22 0x258 +#define SDHC_CDNS_SRS23 0x25c + +/* SRS00 */ +#define CDNS_SRS00_SAAR 1 + +/* SRS03 */ +#define CDNS_SRS03_CMD_START BIT(31) +#define CDNS_SRS03_CMD_USE_HOLD_REG BIT(29) +#define CDNS_SRS03_COM_IDX 24 + +/* Command type */ +#define CDNS_SRS03_CMD_TYPE 22 +#define CMD_STOP_ABORT_CMD (3 << CDNS_SRS03_CMD_TYPE) +#define CMD_RESUME_CMD (2 << CDNS_SRS03_CMD_TYPE) +#define CMD_SUSPEND_CMD (1 << CDNS_SRS03_CMD_TYPE) + +#define CDNS_SRS03_DATA_PRSNT BIT(21) +#define CDNS_SRS03_CMD_IDX_CHK_EN BIT(20) +#define CDNS_SRS03_RESP_CRCCE BIT(19) +#define CDNS_SRS03_RESP_ERR BIT(7) +#define CDNS_SRS03_MULTI_BLK_READ BIT(5) +#define CDNS_SRS03_CMD_READ BIT(4) + +/* Response type select */ +#define CDNS_SRS03_RES_TYPE_SEL 16 +#define RES_TYPE_SEL_NO (0 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_136 (1 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_48 (2 << CDNS_SRS03_RES_TYPE_SEL) +#define RES_TYPE_SEL_48_B (3 << CDNS_SRS03_RES_TYPE_SEL) + +/* Auto CMD Enable */ +#define CDNS_SRS03_ACE 2 +#define NO_AUTO_COMMAND (0 << CDNS_SRS03_ACE) +#define AUTO_CMD12 (1 << CDNS_SRS03_ACE) +#define AUTO_CMD23 (2 << CDNS_SRS03_ACE) +#define AUTO_CMD_AUTO (3 << CDNS_SRS03_ACE) + +#define CDNS_SRS03_DMA_EN BIT(0) +#define CDNS_SRS03_BLK_CNT_EN BIT(1) + +/* HRS07 - IO Delay Information Register */ +#define SDHC_CDNS_HRS07 0x1c +#define CDNS_HRS07_IDELAY_VAL(x) (x) +#define CDNS_HRS07_RW_COMPENSATE(x) ((x) << 16) + +/* HRS09 - PHY Control and Status Register */ +#define SDHC_CDNS_HRS09 0x24 + +/* HRS10 - Host Controller SDCLK start point adjustment */ +#define SDHC_CDNS_HRS10 0x28 + +/* HCSDCLKADJ DATA; DDR Mode */ +#define SDHC_HRS10_HCSDCLKADJ(x) ((x) << 16) + +/* HRS16 */ +#define CDNS_HRS16_WRCMD0_DLY(x) (x) +#define CDNS_HRS16_WRCMD1_DLY(x) ((x) << 4) +#define CDNS_HRS16_WRDATA0_DLY(x) ((x) << 8) +#define CDNS_HRS16_WRDATA1_DLY(x) ((x) << 12) +#define CDNS_HRS16_WRCMD0_SDCLK_DLY(x) ((x) << 16) +#define CDNS_HRS16_WRCMD1_SDCLK_DLY(x) ((x) << 20) +#define CDNS_HRS16_WRDATA0_SDCLK_DLY(x) ((x) << 24) +#define CDNS_HRS16_WRDATA1_SDCLK_DLY(x) ((x) << 28) + +/* Shared Macros */ +#define SDMMC_CDN(_reg) (SDMMC_CDN_REG_BASE + \ + (SDMMC_CDN_##_reg)) + +/* MMC Peripheral Definition */ +#define MMC_BLOCK_SIZE 512U +#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1) +#define MMC_BOOT_CLK_RATE (400 * 1000) + +#define OCR_POWERUP BIT(31) +#define OCR_HCS BIT(30) + +#define OCR_3_5_3_6 BIT(23) +#define OCR_3_4_3_5 BIT(22) +#define OCR_3_3_3_4 BIT(21) +#define OCR_3_2_3_3 BIT(20) +#define OCR_3_1_3_2 BIT(19) +#define OCR_3_0_3_1 BIT(18) +#define OCR_2_9_3_0 BIT(17) +#define OCR_2_8_2_9 BIT(16) +#define OCR_2_7_2_8 BIT(15) +#define OCR_VDD_MIN_2V7 GENMASK(23, 15) +#define OCR_VDD_MIN_2V0 GENMASK(14, 8) +#define OCR_VDD_MIN_1V7 BIT(7) + +#define MMC_RSP_48 BIT(0) +#define MMC_RSP_136 BIT(1) /* 136 bit response */ +#define MMC_RSP_CRC BIT(2) /* expect valid crc */ +#define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */ +#define MMC_RSP_BUSY BIT(4) /* device may be busy */ + +/* JEDEC 4.51 chapter 6.12 */ +#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) +#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) +#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) +#define MMC_RESPONSE_R3 (MMC_RSP_48) +#define MMC_RESPONSE_R4 (MMC_RSP_48) +#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R6 (MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC) +#define MMC_RESPONSE_NONE 0 + +/* Value randomly chosen for eMMC RCA, it should be > 1 */ +#define MMC_FIX_RCA 6 +#define RCA_SHIFT_OFFSET 16 + +#define CMD_EXTCSD_PARTITION_CONFIG 179 +#define CMD_EXTCSD_BUS_WIDTH 183 +#define CMD_EXTCSD_HS_TIMING 185 +#define CMD_EXTCSD_SEC_CNT 212 + +#define PART_CFG_BOOT_PARTITION1_ENABLE BIT(3) +#define PART_CFG_PARTITION1_ACCESS 1 + +/* Values in EXT CSD register */ +#define MMC_BUS_WIDTH_1 0 +#define MMC_BUS_WIDTH_4 1 +#define MMC_BUS_WIDTH_8 2 +#define MMC_BUS_WIDTH_DDR_4 5 +#define MMC_BUS_WIDTH_DDR_8 6 +#define MMC_BOOT_MODE_BACKWARD 0 +#define MMC_BOOT_MODE_HS_TIMING BIT(3) +#define MMC_BOOT_MODE_DDR (2 << 3) + +#define EXTCSD_SET_CMD 0 +#define EXTCSD_SET_BITS BIT(24) +#define EXTCSD_CLR_BITS (2 << 24) +#define EXTCSD_WRITE_BYTES (3 << 24) +#define EXTCSD_CMD(x) (((x) & 0xff) << 16) +#define EXTCSD_VALUE(x) (((x) & 0xff) << 8) +#define EXTCSD_CMD_SET_NORMAL 1 + +#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) +#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) +#define CSD_TRAN_SPEED_MULT_SHIFT 3 + +#define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9) +#define STATUS_READY_FOR_DATA BIT(8) +#define STATUS_SWITCH_ERROR BIT(7) +#define MMC_GET_STATE(x) (((x) >> 9) & 0xf) +#define MMC_STATE_IDLE 0 +#define MMC_STATE_READY 1 +#define MMC_STATE_IDENT 2 +#define MMC_STATE_STBY 3 +#define MMC_STATE_TRAN 4 +#define MMC_STATE_DATA 5 +#define MMC_STATE_RCV 6 +#define MMC_STATE_PRG 7 +#define MMC_STATE_DIS 8 +#define MMC_STATE_BTST 9 +#define MMC_STATE_SLP 10 + +#define MMC_FLAG_CMD23 1 + +#define CMD8_CHECK_PATTERN 0xAA +#define VHS_2_7_3_6_V BIT(8) + +#define SD_SCR_BUS_WIDTH_1 BIT(8) +#define SD_SCR_BUS_WIDTH_4 BIT(10) + +/* ADMA table component */ +#define ADMA_DESC_ATTR_VALID BIT(0) +#define ADMA_DESC_ATTR_END BIT(1) +#define ADMA_DESC_ATTR_INT BIT(2) +#define ADMA_DESC_ATTR_ACT1 BIT(4) +#define ADMA_DESC_ATTR_ACT2 BIT(5) +#define ADMA_DESC_TRANSFER_DATA ADMA_DESC_ATTR_ACT2 + +/* Conf depends on SRS15.HV4E */ +#define SDMA 0 +#define ADMA2_32 (2 << 3) +#define ADMA2_64 (3 << 3) +/* here 0 defines the 64 Kb size */ +#define MAX_64KB_PAGE 0 + +struct sdmmc_cmd { + unsigned int cmd_idx; + unsigned int cmd_arg; + unsigned int resp_type; + unsigned int resp_data[4]; +}; + +struct sdhc_cdns_ops { + /* init function for card */ + int (*init)(void); + /* busy check function for card */ + int (*busy)(void); + /* card_present function check for card */ + int (*card_present)(void); + /* reset the card */ + int (*reset)(void); + /* send command and respective argument */ + int (*send_cmd)(struct sdmmc_cmd *cmd, struct sdhc_data *data); + /* io set up for card */ + int (*set_ios)(unsigned int clk, unsigned int width); + /* prepare dma descriptors */ + int (*prepare)(uint32_t lba, uintptr_t buf, struct sdhc_data *data); + /* cache invd api */ + int (*cache_invd)(int lba, uintptr_t buf, size_t size); +}; + +/* Combo Phy reg */ +struct sdhc_cdns_combo_phy { + uint32_t cp_clk_wr_delay; + uint32_t cp_clk_wrdqs_delay; + uint32_t cp_data_select_oe_end; + uint32_t cp_dll_bypass_mode; + uint32_t cp_dll_locked_mode; + uint32_t cp_dll_start_point; + uint32_t cp_gate_cfg_always_on; + uint32_t cp_io_mask_always_on; + uint32_t cp_io_mask_end; + uint32_t cp_io_mask_start; + uint32_t cp_rd_del_sel; + uint32_t cp_read_dqs_cmd_delay; + uint32_t cp_read_dqs_delay; + uint32_t cp_sw_half_cycle_shift; + uint32_t cp_sync_method; + uint32_t cp_underrun_suppress; + uint32_t cp_use_ext_lpbk_dqs; + uint32_t cp_use_lpbk_dqs; + uint32_t cp_use_phony_dqs; + uint32_t cp_use_phony_dqs_cmd; +}; + +/* sdmmc reg */ +struct sdhc_cdns_sdmmc { + uint32_t sdhc_extended_rd_mode; + uint32_t sdhc_extended_wr_mode; + uint32_t sdhc_hcsdclkadj; + uint32_t sdhc_idelay_val; + uint32_t sdhc_rdcmd_en; + uint32_t sdhc_rddata_en; + uint32_t sdhc_rw_compensate; + uint32_t sdhc_sdcfsh; + uint32_t sdhc_sdcfsl; + uint32_t sdhc_wrcmd0_dly; + uint32_t sdhc_wrcmd0_sdclk_dly; + uint32_t sdhc_wrcmd1_dly; + uint32_t sdhc_wrcmd1_sdclk_dly; + uint32_t sdhc_wrdata0_dly; + uint32_t sdhc_wrdata0_sdclk_dly; + uint32_t sdhc_wrdata1_dly; + uint32_t sdhc_wrdata1_sdclk_dly; +}; + +enum sdmmc_device_mode { + /* Identification */ + SD_DS_ID, + /* Default speed */ + SD_DS, + /* High speed */ + SD_HS, + /* Ultra high speed SDR12 */ + SD_UHS_SDR12, + /* Ultra high speed SDR25 */ + SD_UHS_SDR25, + /* Ultra high speed SDR`50 */ + SD_UHS_SDR50, + /* Ultra high speed SDR104 */ + SD_UHS_SDR104, + /* Ultra high speed DDR50 */ + SD_UHS_DDR50, + /* SDR backward compatible */ + EMMC_SDR_BC, + /* SDR */ + EMMC_SDR, + /* DDR */ + EMMC_DDR, + /* High speed 200Mhz in SDR */ + EMMC_HS200, + /* High speed 200Mhz in DDR */ + EMMC_HS400, + /* High speed 200Mhz in SDR with enhanced strobe */ + EMMC_HS400ES, +}; + +struct sdhc_cdns_params { + uintptr_t reg_base; + uintptr_t reg_phy; + uintptr_t desc_base; + size_t desc_size; + int clk_rate; + int bus_width; + unsigned int flags; + enum sdmmc_device_mode cdn_sdmmc_dev_type; + uint32_t combophy; +}; + +struct sdmmc_device_info { + /* Size of device in bytes */ + unsigned long long device_size; + /* Block size in bytes */ + unsigned int block_size; + /* Max bus freq in Hz */ + unsigned int max_bus_freq; + /* OCR voltage */ + unsigned int ocr_voltage; + /* Type of MMC */ + enum sdmmc_device_mode cdn_sdmmc_dev_type; +}; + +/*descriptor structure with 8 byte alignment*/ +struct sdhc_cdns_desc { + /* 8 bit attribute */ + uint8_t attr; + /* reserved bits in desc */ + uint8_t reserved; + /* page length for the descriptor */ + uint16_t len; + /* lower 32 bits for buffer (64 bit addressing) */ + uint32_t addr_lo; + /* higher 32 bits for buffer (64 bit addressing) */ + uint32_t addr_hi; +} __aligned(8); + +void sdhc_cdns_sdmmc_init(struct sdhc_cdns_params *params, struct sdmmc_device_info *info, + const struct sdhc_cdns_ops **cb_sdmmc_ops); diff --git a/drivers/sdhc/sdhc_spi.c b/drivers/sdhc/sdhc_spi.c index 42247044143..7462e711dcd 100644 --- a/drivers/sdhc/sdhc_spi.c +++ b/drivers/sdhc/sdhc_spi.c @@ -206,7 +206,7 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * struct sdhc_spi_data *dev_data = dev->data; uint8_t *response = dev_data->scratch; uint8_t *end = response + rx_len; - int ret; + int ret, timeout = cmd->timeout_ms; uint8_t value, i; /* First step is finding the first valid byte of the response. @@ -224,7 +224,7 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * */ response = dev_data->scratch; end = response + 1; - for (i = 0; i < 16; i++) { + while (timeout > 0) { ret = sdhc_spi_rx(config->spi_dev, dev_data->spi_cfg, response, 1); if (ret < 0) { @@ -233,6 +233,9 @@ static int sdhc_spi_response_get(const struct device *dev, struct sdhc_command * if (*response != 0xff) { break; } + /* Delay for a bit, and poll the card again */ + k_msleep(10); + timeout -= 10; } if (*response == 0xff) { return -ETIMEDOUT; @@ -759,7 +762,7 @@ static int sdhc_spi_init(const struct device *dev) return ret; } -static struct sdhc_driver_api sdhc_spi_api = { +static const struct sdhc_driver_api sdhc_spi_api = { .request = sdhc_spi_request, .set_io = sdhc_spi_set_io, .get_host_props = sdhc_spi_get_host_props, diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 2fa37289ac2..dd77976c086 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_ADXL345 adxl345) add_subdirectory_ifdef(CONFIG_ADXL362 adxl362) add_subdirectory_ifdef(CONFIG_ADXL367 adxl367) add_subdirectory_ifdef(CONFIG_ADXL372 adxl372) +add_subdirectory_ifdef(CONFIG_AGS10 ags10) add_subdirectory_ifdef(CONFIG_AK8975 ak8975) add_subdirectory_ifdef(CONFIG_AKM09918C akm09918c) add_subdirectory_ifdef(CONFIG_AMD_SB_TSI amd_sb_tsi) @@ -18,6 +19,7 @@ add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore) add_subdirectory_ifdef(CONFIG_APDS9960 apds9960) add_subdirectory_ifdef(CONFIG_BH1750 bh1750) add_subdirectory_ifdef(CONFIG_BMA280 bma280) +add_subdirectory_ifdef(CONFIG_BMA4XX bma4xx) add_subdirectory_ifdef(CONFIG_BMC150_MAGN bmc150_magn) add_subdirectory_ifdef(CONFIG_BME280 bme280) add_subdirectory_ifdef(CONFIG_BME680 bme680) @@ -28,6 +30,7 @@ add_subdirectory_ifdef(CONFIG_BMI270 bmi270) add_subdirectory_ifdef(CONFIG_BMI323 bmi323) add_subdirectory_ifdef(CONFIG_BMM150 bmm150) add_subdirectory_ifdef(CONFIG_BMP388 bmp388) +add_subdirectory_ifdef(CONFIG_BMP581 bmp581) add_subdirectory_ifdef(CONFIG_BQ274XX bq274xx) add_subdirectory_ifdef(CONFIG_CCS811 ccs811) add_subdirectory_ifdef(CONFIG_CURRENT_AMP current_amp) @@ -67,13 +70,15 @@ add_subdirectory_ifdef(CONFIG_ISL29035 isl29035) add_subdirectory_ifdef(CONFIG_ISM330DHCX ism330dhcx) add_subdirectory_ifdef(CONFIG_ITDS wsen_itds) add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh) +add_subdirectory_ifdef(CONFIG_LIS2DE12 lis2de12) add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12) +add_subdirectory_ifdef(CONFIG_LIS2DU12 lis2du12) add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12) add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl) add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl) add_subdirectory_ifdef(CONFIG_LM75 lm75) add_subdirectory_ifdef(CONFIG_LM77 lm77) -add_subdirectory_ifdef(CONFIG_LPS22DF lps22df) +add_subdirectory_ifdef(CONFIG_LPS2XDF lps2xdf) add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb) add_subdirectory_ifdef(CONFIG_LPS22HH lps22hh) add_subdirectory_ifdef(CONFIG_LPS25HB lps25hb) @@ -112,6 +117,7 @@ add_subdirectory_ifdef(CONFIG_OPT3001 opt3001) add_subdirectory_ifdef(CONFIG_PCNT_ESP32 pcnt_esp32) add_subdirectory_ifdef(CONFIG_PMS7003 pms7003) add_subdirectory_ifdef(CONFIG_QDEC_MCUX qdec_mcux) +add_subdirectory_ifdef(CONFIG_QDEC_NXP_S32 qdec_nxp_s32) add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx) add_subdirectory_ifdef(CONFIG_QDEC_SAM qdec_sam) add_subdirectory_ifdef(CONFIG_QDEC_STM32 qdec_stm32) @@ -152,6 +158,7 @@ add_subdirectory_ifdef(CONFIG_TSL2540 tsl2540) add_subdirectory_ifdef(CONFIG_TSL2561 tsl2561) add_subdirectory_ifdef(CONFIG_VCMP_IT8XXX2 ite_vcmp_it8xxx2) add_subdirectory_ifdef(CONFIG_VCNL4040 vcnl4040) +add_subdirectory_ifdef(CONFIG_VCNL36825T vcnl36825t) add_subdirectory_ifdef(CONFIG_VEML7700 veml7700) add_subdirectory_ifdef(CONFIG_VL53L0X vl53l0x) add_subdirectory_ifdef(CONFIG_VL53L1X vl53l1x) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 08d04774dcd..c27b3906405 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -68,6 +68,14 @@ config SENSOR_SHELL_TRIG_PRINT_TIMEOUT_MS Control the frequency of the sampling window over which the sensor interrupt handler will collect data. +config SENSOR_SHELL_MAX_TRIGGER_DEVICES + int "Maximum number of sensor devices that can have enabled triggers in shell" + default 1 + depends on SENSOR_SHELL + help + Maximum number of sensor devices that the shell cmd can have + enabled triggers for. + config SENSOR_INFO bool "Sensor Info iterable section" @@ -81,6 +89,7 @@ source "drivers/sensor/adxl345/Kconfig" source "drivers/sensor/adxl362/Kconfig" source "drivers/sensor/adxl367/Kconfig" source "drivers/sensor/adxl372/Kconfig" +source "drivers/sensor/ags10/Kconfig" source "drivers/sensor/ak8975/Kconfig" source "drivers/sensor/akm09918c/Kconfig" source "drivers/sensor/amd_sb_tsi/Kconfig" @@ -90,6 +99,7 @@ source "drivers/sensor/ams_iAQcore/Kconfig" source "drivers/sensor/apds9960/Kconfig" source "drivers/sensor/bh1750/Kconfig" source "drivers/sensor/bma280/Kconfig" +source "drivers/sensor/bma4xx/Kconfig" source "drivers/sensor/bmc150_magn/Kconfig" source "drivers/sensor/bme280/Kconfig" source "drivers/sensor/bme680/Kconfig" @@ -100,6 +110,7 @@ source "drivers/sensor/bmi270/Kconfig" source "drivers/sensor/bmi323/Kconfig" source "drivers/sensor/bmm150/Kconfig" source "drivers/sensor/bmp388/Kconfig" +source "drivers/sensor/bmp581/Kconfig" source "drivers/sensor/bq274xx/Kconfig" source "drivers/sensor/ccs811/Kconfig" source "drivers/sensor/current_amp/Kconfig" @@ -139,13 +150,15 @@ source "drivers/sensor/ism330dhcx/Kconfig" source "drivers/sensor/ite_tach_it8xxx2/Kconfig" source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig" source "drivers/sensor/lis2dh/Kconfig" +source "drivers/sensor/lis2de12/Kconfig" source "drivers/sensor/lis2ds12/Kconfig" +source "drivers/sensor/lis2du12/Kconfig" source "drivers/sensor/lis2dw12/Kconfig" source "drivers/sensor/lis2mdl/Kconfig" source "drivers/sensor/lis3mdl/Kconfig" source "drivers/sensor/lm75/Kconfig" source "drivers/sensor/lm77/Kconfig" -source "drivers/sensor/lps22df/Kconfig" +source "drivers/sensor/lps2xdf/Kconfig" source "drivers/sensor/lps22hb/Kconfig" source "drivers/sensor/lps22hh/Kconfig" source "drivers/sensor/lps25hb/Kconfig" @@ -189,6 +202,7 @@ source "drivers/sensor/opt3001/Kconfig" source "drivers/sensor/pcnt_esp32/Kconfig" source "drivers/sensor/pms7003/Kconfig" source "drivers/sensor/qdec_mcux/Kconfig" +source "drivers/sensor/qdec_nxp_s32/Kconfig" source "drivers/sensor/qdec_nrfx/Kconfig" source "drivers/sensor/qdec_sam/Kconfig" source "drivers/sensor/qdec_stm32/Kconfig" @@ -223,6 +237,7 @@ source "drivers/sensor/tmp116/Kconfig" source "drivers/sensor/tsl2540/Kconfig" source "drivers/sensor/tsl2561/Kconfig" source "drivers/sensor/vcnl4040/Kconfig" +source "drivers/sensor/vcnl36825t/Kconfig" source "drivers/sensor/veml7700/Kconfig" source "drivers/sensor/vl53l0x/Kconfig" source "drivers/sensor/vl53l1x/Kconfig" diff --git a/drivers/sensor/Kconfig.trigger_template b/drivers/sensor/Kconfig.trigger_template new file mode 100644 index 00000000000..7cb98e10e9e --- /dev/null +++ b/drivers/sensor/Kconfig.trigger_template @@ -0,0 +1,44 @@ +# Common Kconfig template for all sensors +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +choice "$(module)_TRIGGER_MODE" + prompt "Trigger mode" + help + Specify the type of triggering to be used by the sensor module. + +config $(module)_TRIGGER_NONE + bool "No trigger" + +config $(module)_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select $(module)_TRIGGER + +config $(module)_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select $(module)_TRIGGER + +endchoice + +config $(module)_TRIGGER + bool + +if $(module)_TRIGGER + +config $(module)_THREAD_PRIORITY + int "Thread priority" + depends on $(module)_TRIGGER_OWN_THREAD + default $(thread_priority) + help + Priority of thread used by the driver to handle interrupts. + +config $(module)_THREAD_STACK_SIZE + int "Thread stack size" + depends on $(module)_TRIGGER_OWN_THREAD + default $(thread_stack_size) + help + Stack size of thread used by the driver to handle interrupts. + +endif # $(module)_TRIGGER diff --git a/drivers/sensor/adltc2990/adltc2990.c b/drivers/sensor/adltc2990/adltc2990.c index d9ac1643306..ea56065ede6 100644 --- a/drivers/sensor/adltc2990/adltc2990.c +++ b/drivers/sensor/adltc2990/adltc2990.c @@ -93,13 +93,20 @@ static enum adltc2990_monitoring_type adltc2990_get_v3_v4_measurement_modes(uint return type; } -static bool adltc2990_is_busy(const struct device *dev) +static int adltc2990_is_busy(const struct device *dev, bool *is_busy) { const struct adltc2990_config *cfg = dev->config; uint8_t status_reg = 0; + int ret; - i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg); - return status_reg & BIT(0); + ret = i2c_reg_read_byte_dt(&cfg->bus, ADLTC2990_REG_STATUS, &status_reg); + if (ret) { + return ret; + } + + *is_busy = status_reg & BIT(0); + + return 0; } static void adltc2990_get_v1_v2_val(const struct device *dev, struct sensor_value *val, @@ -134,9 +141,10 @@ static int adltc2990_trigger_measurement(const struct device *dev) return i2c_reg_write_byte_dt(&cfg->bus, ADLTC2990_REG_TRIGGER, 0x1); } -static int32_t adltc2990_fetch_property_value(const struct device *dev, - enum adltc2990_monitoring_type type, - enum adltc2990_monitor_pins pin) +static int adltc2990_fetch_property_value(const struct device *dev, + enum adltc2990_monitoring_type type, + enum adltc2990_monitor_pins pin, + int32_t *output) { const struct adltc2990_config *cfg = dev->config; @@ -179,9 +187,17 @@ static int32_t adltc2990_fetch_property_value(const struct device *dev, return -EINVAL; } } + int ret; - i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value); - i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value); + ret = i2c_reg_read_byte_dt(&cfg->bus, msb_address, &msb_value); + if (ret) { + return ret; + } + + ret = i2c_reg_read_byte_dt(&cfg->bus, lsb_address, &lsb_value); + if (ret) { + return ret; + } uint16_t conversion_factor; uint8_t negative_bit_index = 14U, sensor_val_divisor = 100U; @@ -204,7 +220,9 @@ static int32_t adltc2990_fetch_property_value(const struct device *dev, int32_t voltage_value = (value << (31 - negative_bit_index)) >> (31 - negative_bit_index); - return (voltage_value * conversion_factor) / sensor_val_divisor; + *output = (voltage_value * conversion_factor) / sensor_val_divisor; + + return 0; } static int adltc2990_init(const struct device *dev) @@ -240,11 +258,17 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel cfg->measurement_mode[1], cfg->measurement_mode[0]); float voltage_divider_ratio; + int ret; + int32_t value; switch (chan) { case SENSOR_CHAN_DIE_TEMP: { - data->internal_temperature = - adltc2990_fetch_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, INTERNAL_TEMPERATURE, + &value); + if (ret) { + return ret; + } + data->internal_temperature = value; break; } case SENSOR_CHAN_CURRENT: { @@ -253,68 +277,91 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel return -EINVAL; } if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1, &value); + if (ret) { + return ret; + } data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1) * - (ADLTC2990_MICROOHM_CONVERSION_FACTOR / + value * (ADLTC2990_MICROOHM_CONVERSION_FACTOR / (float)cfg->pins_v1_v2.pins_current_resistor); } if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3) * - (ADLTC2990_MICROOHM_CONVERSION_FACTOR / + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value * (ADLTC2990_MICROOHM_CONVERSION_FACTOR / (float)cfg->pins_v3_v4.pins_current_resistor); } break; } case SENSOR_CHAN_VOLTAGE: { - data->supply_voltage = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE) + - 2500000; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, SUPPLY_VOLTAGE, + &value); + if (ret) { + return ret; + } + data->supply_voltage = value + 2500000; if (mode_v1_v2 == VOLTAGE_DIFFERENTIAL) { - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1); + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value; } else if (mode_v1_v2 == VOLTAGE_SINGLEENDED) { uint32_t v1_r1 = cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[0]; uint32_t v1_r2 = cfg->pins_v1_v2.voltage_divider_resistors.v1_r1_r2[1]; voltage_divider_ratio = (v1_r1 + v1_r2) / (float)v1_r2; - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V1) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value * voltage_divider_ratio; uint32_t v2_r1 = cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[0]; uint32_t v2_r2 = cfg->pins_v1_v2.voltage_divider_resistors.v2_r1_r2[1]; voltage_divider_ratio = (v2_r1 + v2_r2) / (float)v2_r2; - data->pins_v1_v2_values[1] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V2) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V2, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[1] = value * voltage_divider_ratio; } if (mode_v3_v4 == VOLTAGE_DIFFERENTIAL) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3); + ret = adltc2990_fetch_property_value(dev, VOLTAGE_DIFFERENTIAL, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value; } else if (mode_v3_v4 == VOLTAGE_SINGLEENDED) { uint32_t v3_r1 = cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[0]; uint32_t v3_r2 = cfg->pins_v3_v4.voltage_divider_resistors.v3_r1_r2[1]; voltage_divider_ratio = (v3_r1 + v3_r2) / (float)v3_r2; - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V3) * - voltage_divider_ratio; + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value * voltage_divider_ratio; uint32_t v4_r1 = cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[0]; uint32_t v4_r2 = cfg->pins_v3_v4.voltage_divider_resistors.v4_r1_r2[1]; voltage_divider_ratio = (v4_r1 + v4_r2) / (float)v4_r2; - data->pins_v3_v4_values[1] = - adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V4) * - voltage_divider_ratio; + + ret = adltc2990_fetch_property_value(dev, VOLTAGE_SINGLEENDED, V4, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[1] = value * voltage_divider_ratio; } break; } @@ -324,17 +371,30 @@ static int adltc2990_sample_fetch(const struct device *dev, enum sensor_channel return -EINVAL; } if (mode_v1_v2 == TEMPERATURE) { - data->pins_v1_v2_values[0] = - adltc2990_fetch_property_value(dev, TEMPERATURE, V1); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, V1, &value); + if (ret) { + return ret; + } + data->pins_v1_v2_values[0] = value; } if (mode_v3_v4 == TEMPERATURE) { - data->pins_v3_v4_values[0] = - adltc2990_fetch_property_value(dev, TEMPERATURE, V3); + ret = adltc2990_fetch_property_value(dev, TEMPERATURE, V3, &value); + if (ret) { + return ret; + } + data->pins_v3_v4_values[0] = value; } break; } case SENSOR_CHAN_ALL: { - if (adltc2990_is_busy(dev)) { + bool is_busy; + + ret = adltc2990_is_busy(dev, &is_busy); + if (ret) { + return ret; + } + + if (is_busy) { LOG_INF("ADLTC2990 conversion ongoing"); return -EBUSY; } diff --git a/drivers/sensor/ags10/CMakeLists.txt b/drivers/sensor/ags10/CMakeLists.txt new file mode 100644 index 00000000000..bbc0a09038b --- /dev/null +++ b/drivers/sensor/ags10/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + + +zephyr_library() +zephyr_library_sources(ags10.c) diff --git a/drivers/sensor/ags10/Kconfig b/drivers/sensor/ags10/Kconfig new file mode 100644 index 00000000000..f406e29d3b7 --- /dev/null +++ b/drivers/sensor/ags10/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Balthazar Deliers +# SPDX-License-Identifier: Apache-2.0 + +# AOSONG AGS10 TVOC sensor driver options. + +config AGS10 + bool "AOSONG AGS10 TVOC sensor" + default y + depends on DT_HAS_AOSONG_AGS10_ENABLED + select I2C + help + Enable AOSONG AGS10 TVOC sensor driver. diff --git a/drivers/sensor/ags10/ags10.c b/drivers/sensor/ags10/ags10.c new file mode 100644 index 00000000000..e5d761bfdf4 --- /dev/null +++ b/drivers/sensor/ags10/ags10.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2023 Balthazar Deliers + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT aosong_ags10 + +#include +#include +#include +#include +#include + +#include "ags10.h" + +LOG_MODULE_REGISTER(AGS10, CONFIG_SENSOR_LOG_LEVEL); + +#define AGS10_MAX_PAYLOAD_SIZE 5U /* Payload will be max 4 bytes + CRC (datasheet 3.1) */ + +static int ags10_read(const struct device *dev, uint8_t cmd, uint8_t *data, uint8_t rx_bytes) +{ + if (rx_bytes > AGS10_MAX_PAYLOAD_SIZE) { + return -EINVAL; + } + + const struct ags10_config *conf = dev->config; + + uint8_t recv_buf[AGS10_MAX_PAYLOAD_SIZE] = {0}; + int ret = i2c_write_read_dt(&conf->bus, &cmd, sizeof(cmd), &recv_buf, rx_bytes); + + if (ret < 0) { + return ret; + } + + memcpy(data, recv_buf, rx_bytes); + + return 0; +} + +static int ags10_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + if (chan != SENSOR_CHAN_VOC && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + struct ags10_data *data = dev->data; + int ret = -ENOTSUP; + uint8_t recv_buf[5] = {0}; + + ret = ags10_read(dev, AGS10_CMD_DATA_ACQUISITION, recv_buf, 5); + + if (ret == 0) { + /* If CRC is valid and data is valid too */ + if (crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4] && + ((recv_buf[0] & AGS10_MSK_STATUS) == AGS10_REG_STATUS_NRDY_READY)) { + data->status = recv_buf[0] & AGS10_MSK_STATUS; + data->tvoc_ppb = sys_get_be24(&recv_buf[1]); + return 0; + } + + LOG_WRN("Bad CRC or data not ready"); + ret = -EIO; + } + + return ret; +} + +static int ags10_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct ags10_data *data = dev->data; + + if (chan == SENSOR_CHAN_VOC) { + val->val1 = data->tvoc_ppb; + } else { + return -ENOTSUP; + } + + val->val2 = 0; + + return 0; +} + +static int ags10_init(const struct device *dev) +{ + const struct ags10_config *conf = dev->config; + struct ags10_data *data = dev->data; + int ret; + + if (!i2c_is_ready_dt(&conf->bus)) { + LOG_ERR("Device not ready"); + return -ENODEV; + } + + /* Set initial data values */ + data->tvoc_ppb = 0; + data->status = 0xFF; + data->version = 0; + + /* Read firmware version and check CRC */ + uint8_t recv_buf[5] = {0}; + + ret = ags10_read(dev, AGS10_CMD_READ_VERSION, recv_buf, 5); + + /* Bytes 0 to 2 are reserved, byte 3 is version, byte 4 is CRC */ + if (ret == 0 && crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4]) { + data->version = recv_buf[3]; + LOG_DBG("Sensor detected"); + } else if (ret != 0) { + LOG_ERR("No reply from sensor"); + ret = -ENODEV; + } else { + LOG_WRN("Bad CRC"); + ret = -EIO; + } + + return ret; +} + +static const struct sensor_driver_api ags10_api = {.sample_fetch = ags10_sample_fetch, + .channel_get = ags10_channel_get}; + +#define AGS10_INIT(n) \ + static struct ags10_data ags10_data_##n; \ + \ + static const struct ags10_config ags10_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, ags10_init, NULL, &ags10_data_##n, &ags10_config_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ags10_api); + +DT_INST_FOREACH_STATUS_OKAY(AGS10_INIT) diff --git a/drivers/sensor/ags10/ags10.h b/drivers/sensor/ags10/ags10.h new file mode 100644 index 00000000000..d3f73ccd11b --- /dev/null +++ b/drivers/sensor/ags10/ags10.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Balthazar Deliers + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define AGS10_CMD_DATA_ACQUISITION 0x00 +#define AGS10_CMD_ZERO_POINT_CALIBRATION 0x01 +#define AGS10_CMD_READ_VERSION 0x11 +#define AGS10_CMD_READ_RESISTANCE 0x20 +#define AGS10_CMD_MODIFY_SLAVE_ADDRESS 0x21 + +#define AGS10_REG_ZERO_POINT_CALIBRATION_RESET 0xFFFF /* Reset to the factory value */ +#define AGS10_REG_ZERO_POINT_CALIBRATION_SET 0x0000 /* Set sensor resistance to zero-point */ +#define AGS10_REG_STATUS_NRDY_READY 0x00 /* Device is ready */ +#define AGS10_REG_STATUS_CH_PPB 0x00 /* Unit is PPB */ + +#define AGS10_MSK_STATUS 0x0F +#define AGS10_MSK_STATUS_NRDY 0x01 +#define AGS10_MSK_STATUS_CH 0x0E + +struct ags10_config { + struct i2c_dt_spec bus; +}; + +struct ags10_data { + uint32_t tvoc_ppb; + uint8_t status; + uint32_t version; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ */ diff --git a/drivers/sensor/akm09918c/Kconfig b/drivers/sensor/akm09918c/Kconfig index 2765d70a21e..d90f8662dc5 100644 --- a/drivers/sensor/akm09918c/Kconfig +++ b/drivers/sensor/akm09918c/Kconfig @@ -16,4 +16,4 @@ config EMUL_AKM09918C depends on EMUL help Enable the hardware emulator for the AKM09918C. Doing so allows exercising - sensor APIs for this magnetometer in native_posix and qemu. + sensor APIs for this magnetometer in native_sim and qemu. diff --git a/drivers/sensor/akm09918c/akm09918c_emul.c b/drivers/sensor/akm09918c/akm09918c_emul.c index 02dc28b35db..adb237e1256 100644 --- a/drivers/sensor/akm09918c/akm09918c_emul.c +++ b/drivers/sensor/akm09918c/akm09918c_emul.c @@ -134,7 +134,7 @@ static int akm09918c_emul_init(const struct emul *target, const struct device *p } static int akm09918c_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->data) { return -EINVAL; @@ -162,8 +162,9 @@ static int akm09918c_emul_backend_set_channel(const struct emul *target, enum se data->reg[AKM09918C_REG_ST1] |= AKM09918C_ST1_DRDY; /* Convert fixed-point Gauss values into microgauss and then into its bit representation */ - int32_t microgauss = (shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift)) * - 1000000 / ((int64_t)INT32_MAX + 1); + int32_t microgauss = + (shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift)) * 1000000 / + ((int64_t)INT32_MAX + 1); int16_t reg_val = CLAMP(microgauss, AKM09918C_MAGN_MIN_MICRO_GAUSS, AKM09918C_MAGN_MAX_MICRO_GAUSS) / diff --git a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c index fee197f1d90..1c12942c876 100644 --- a/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c +++ b/drivers/sensor/amd_sb_tsi/sb_tsi_emul.c @@ -100,7 +100,7 @@ static int sb_tsi_emul_init(const struct emul *target, const struct device *pare } static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channel chan, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { struct sb_tsi_emul_data *data = target->data; int64_t scaled_value; @@ -111,7 +111,7 @@ static int sb_tsi_emul_set_channel(const struct emul *target, enum sensor_channe return -ENOTSUP; } - scaled_value = (int64_t)value << shift; + scaled_value = (int64_t)*value << shift; millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); diff --git a/drivers/sensor/bma4xx/CMakeLists.txt b/drivers/sensor/bma4xx/CMakeLists.txt new file mode 100644 index 00000000000..a0151e081d6 --- /dev/null +++ b/drivers/sensor/bma4xx/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(bma4xx.c) +zephyr_library_sources(bma4xx_i2c.c) +zephyr_library_sources(bma4xx_spi.c) diff --git a/drivers/sensor/bma4xx/Kconfig b/drivers/sensor/bma4xx/Kconfig new file mode 100644 index 00000000000..01a09ccdfd5 --- /dev/null +++ b/drivers/sensor/bma4xx/Kconfig @@ -0,0 +1,31 @@ +# BMA4XX 3-axis accelerometer config options +# +# Copyright (c) 2023 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 + +config BMA4XX + bool "BMA4XX 3-axis acceleration sensor" + default y + depends on DT_HAS_BOSCH_BMA4XX_ENABLED + depends on SENSOR_ASYNC_API + select I2C + help + Enable driver for Bosch BMA4XX (I2C-based) + +config BMA4XX_TEMPERATURE + bool "Allow reading the BMA4XX die temperature" + default n + depends on BMA4XX + help + Allow reading the BMA4xx's on-chip temperature sensor. This creates + extra bus activity and increases code size. + +config EMUL_BMA4XX + bool "Emulator for the BMA4XX" + default y + depends on BMA4XX + depends on EMUL + help + Enable the hardware emulator for the BMA4XX. Doing so allows exercising + sensor APIs for this sensor in native_posix and qemu. diff --git a/drivers/sensor/bma4xx/bma4xx.c b/drivers/sensor/bma4xx/bma4xx.c new file mode 100644 index 00000000000..9d8656d67aa --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx.c @@ -0,0 +1,701 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bma4xx, CONFIG_SENSOR_LOG_LEVEL); +#include "bma4xx.h" + +/** + * @brief Helper for converting m/s^2 offset values into register values + */ +static int bma4xx_offset_to_reg_val(const struct sensor_value *val, uint8_t *reg_val) +{ + int32_t ug = sensor_ms2_to_ug(val); + + if (ug < BMA4XX_OFFSET_MICROG_MIN || ug > BMA4XX_OFFSET_MICROG_MAX) { + return -ERANGE; + } + + *reg_val = ug / BMA4XX_OFFSET_MICROG_PER_BIT; + return 0; +} + +/** + * @brief Set the X, Y, or Z axis offsets. + */ +static int bma4xx_attr_set_offset(const struct device *dev, enum sensor_channel chan, + const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + uint8_t reg_addr; + uint8_t reg_val[3]; + int rc; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + reg_addr = BMA4XX_REG_OFFSET_0 + (chan - SENSOR_CHAN_ACCEL_X); + rc = bma4xx_offset_to_reg_val(val, ®_val[0]); + if (rc) { + return rc; + } + return bma4xx->hw_ops->write_reg(dev, reg_addr, reg_val[0]); + case SENSOR_CHAN_ACCEL_XYZ: + /* Expect val to point to an array of three sensor_values */ + reg_addr = BMA4XX_REG_OFFSET_0; + for (int i = 0; i < 3; i++) { + rc = bma4xx_offset_to_reg_val(&val[i], ®_val[i]); + if (rc) { + return rc; + } + } + return bma4xx->hw_ops->write_data(dev, reg_addr, (uint8_t *)reg_val, + sizeof(reg_val)); + default: + return -ENOTSUP; + } +} + +static const uint32_t odr_to_reg_map[] = { + 0, /* Invalid */ + 781250, /* 0.78125 Hz (25/32) => 0x1 */ + 1562500, /* 1.5625 Hz (25/16) => 0x2 */ + 3125000, /* 3.125 Hz (25/8) => 0x3 */ + 6250000, /* 6.25 Hz (25/4) => 0x4 */ + 12500000, /* 12.5 Hz (25/2) => 0x5 */ + 25000000, /* 25 Hz => 0x6 */ + 50000000, /* 50 Hz => 0x7*/ + 100000000, /* 100 Hz => 0x8*/ + 200000000, /* 200 Hz => 0x9*/ + 400000000, /* 400 Hz => 0xa*/ + 800000000, /* 800 Hz => 0xb*/ + 1600000000, /* 1600 Hz => 0xc*/ +}; + +/** + * @brief Convert an ODR rate in Hz to a register value + */ +static int bma4xx_odr_to_reg(uint32_t microhertz, uint8_t *reg_val) +{ + if (microhertz == 0) { + /* Illegal ODR value */ + return -ERANGE; + } + + for (uint8_t i = 0; i < ARRAY_SIZE(odr_to_reg_map); i++) { + if (microhertz <= odr_to_reg_map[i]) { + *reg_val = i; + return 0; + } + } + + /* Requested ODR too high */ + return -ERANGE; +} + +/** + * Set the sensor's acceleration offset (per axis). Use bma4xx_commit_nvm() to save these + * offsets to nonvolatile memory so they are automatically set during power-on-reset. + */ +static int bma4xx_attr_set_odr(const struct device *dev, const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + uint8_t reg_val; + + /* Convert ODR Hz value to microhertz and round up to closest register setting */ + status = bma4xx_odr_to_reg(val->val1 * 1000000 + val->val2, ®_val); + if (status < 0) { + return status; + } + + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_MASK_ACC_CONF_ODR, + reg_val); + if (status < 0) { + return status; + } + + bma4xx->accel_odr = reg_val; + return 0; +} + +static const uint32_t fs_to_reg_map[] = { + 2000000, /* +/-2G => 0x0 */ + 4000000, /* +/-4G => 0x1 */ + 8000000, /* +/-8G => 0x2 */ + 16000000, /* +/-16G => 0x3 */ +}; + +static int bma4xx_fs_to_reg(int32_t range_ug, uint8_t *reg_val) +{ + if (range_ug == 0) { + /* Illegal value */ + return -ERANGE; + } + + range_ug = abs(range_ug); + + for (uint8_t i = 0; i < 4; i++) { + if (range_ug <= fs_to_reg_map[i]) { + *reg_val = i; + return 0; + } + } + + /* Requested range too high */ + return -ERANGE; +} + +/** + * Set the sensor's full-scale range + */ +static int bma4xx_attr_set_range(const struct device *dev, const struct sensor_value *val) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + uint8_t reg_val; + + /* Convert m/s^2 to micro-G's and find closest register setting */ + status = bma4xx_fs_to_reg(sensor_ms2_to_ug(val), ®_val); + if (status < 0) { + return status; + } + + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_RANGE, BMA4XX_MASK_ACC_RANGE, + reg_val); + if (status < 0) { + return status; + } + + bma4xx->accel_fs_range = reg_val; + return 0; +} + +/** + * Set the sensor's bandwidth parameter (one of BMA4XX_BWP_*) + */ +static int bma4xx_attr_set_bwp(const struct device *dev, const struct sensor_value *val) +{ + /* Require that `val2` is unused, and that `val1` is in range of a valid BWP */ + if (val->val2 || val->val1 < BMA4XX_BWP_OSR4_AVG1 || val->val1 > BMA4XX_BWP_RES_AVG128) { + return -EINVAL; + } + + struct bma4xx_data *bma4xx = dev->data; + + return bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_MASK_ACC_CONF_BWP, + (((uint8_t)val->val1) << BMA4XX_SHIFT_ACC_CONF_BWP)); +} + +/** + * @brief Implement the sensor API attribute set method. + */ +static int bma4xx_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return bma4xx_attr_set_odr(dev, val); + case SENSOR_ATTR_FULL_SCALE: + return bma4xx_attr_set_range(dev, val); + case SENSOR_ATTR_OFFSET: + return bma4xx_attr_set_offset(dev, chan, val); + case SENSOR_ATTR_CONFIGURATION: + /* Use for setting the bandwidth parameter (BWP) */ + return bma4xx_attr_set_bwp(dev, val); + default: + return -ENOTSUP; + } +} + +/** + * Internal device initialization function for both bus types. + */ +static int bma4xx_chip_init(const struct device *dev) +{ + struct bma4xx_data *bma4xx = dev->data; + const struct bma4xx_config *cfg = dev->config; + int status; + + /* Sensor bus-specific initialization */ + status = cfg->bus_init(dev); + if (status) { + LOG_ERR("bus_init failed: %d", status); + return status; + } + + /* Read Chip ID */ + status = bma4xx->hw_ops->read_reg(dev, BMA4XX_REG_CHIP_ID, &bma4xx->chip_id); + if (status) { + LOG_ERR("could not read chip_id: %d", status); + return status; + } + LOG_DBG("chip_id is 0x%02x", bma4xx->chip_id); + + if (bma4xx->chip_id != BMA4XX_CHIP_ID_BMA422) { + LOG_WRN("Driver tested for BMA422. Check for unintended operation."); + } + + /* Issue soft reset command */ + status = bma4xx->hw_ops->write_reg(dev, BMA4XX_REG_CMD, BMA4XX_CMD_SOFT_RESET); + if (status) { + LOG_ERR("Could not soft-reset chip: %d", status); + return status; + } + + k_sleep(K_USEC(1000)); + + /* Default is: range = +/-4G, ODR = 100 Hz, BWP = "NORM_AVG4" */ + bma4xx->accel_fs_range = BMA4XX_RANGE_4G; + bma4xx->accel_bwp = BMA4XX_BWP_NORM_AVG4; + bma4xx->accel_odr = BMA4XX_ODR_100; + + /* Switch to performance power mode */ + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_ACCEL_CONFIG, BMA4XX_BIT_ACC_PERF_MODE, + BMA4XX_BIT_ACC_PERF_MODE); + if (status) { + LOG_ERR("Could not enable performance power save mode: %d", status); + return status; + } + + /* Enable accelerometer */ + status = bma4xx->hw_ops->update_reg(dev, BMA4XX_REG_POWER_CTRL, BMA4XX_BIT_ACC_EN, + BMA4XX_BIT_ACC_EN); + if (status) { + LOG_ERR("Could not enable accel: %d", status); + return status; + } + + return status; +} + +/* + * Sample fetch and conversion + */ + +/** + * @brief Read accelerometer data from the BMA4xx + */ +static int bma4xx_sample_fetch(const struct device *dev, int16_t *x, int16_t *y, int16_t *z) +{ + struct bma4xx_data *bma4xx = dev->data; + uint8_t read_data[6]; + int status; + + /* Burst read regs DATA_8 through DATA_13, which holds the accel readings */ + status = bma4xx->hw_ops->read_data(dev, BMA4XX_REG_DATA_8, (uint8_t *)&read_data, + BMA4XX_REG_DATA_13 - BMA4XX_REG_DATA_8 + 1); + if (status < 0) { + LOG_ERR("Cannot read accel data: %d", status); + return status; + } + + LOG_DBG("Raw values [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x]", read_data[0], + read_data[1], read_data[2], read_data[3], read_data[4], read_data[5]); + /* Values in accel_data[N] are left-aligned and will read 16x actual */ + *x = ((int16_t)read_data[1] << 4) | FIELD_GET(GENMASK(7, 4), read_data[0]); + *y = ((int16_t)read_data[3] << 4) | FIELD_GET(GENMASK(7, 4), read_data[2]); + *z = ((int16_t)read_data[5] << 4) | FIELD_GET(GENMASK(7, 4), read_data[4]); + + LOG_DBG("XYZ reg vals are %d, %d, %d", *x, *y, *z); + + return 0; +} + +#ifdef CONFIG_BMA4XX_TEMPERATURE +/** + * @brief Read temperature register on BMA4xx + */ +static int bma4xx_temp_fetch(const struct device *dev, int8_t *temp) +{ + struct bma4xx_data *bma4xx = dev->data; + int status; + + status = bma4xx->hw_ops->read_reg(dev, BMA4XX_REG_TEMPERATURE, temp); + if (status) { + LOG_ERR("could not read temp reg: %d", status); + return status; + } + + LOG_DBG("temp reg val is %d", *temp); + return 0; +} +#endif + +/* + * RTIO submit and encoding + */ + +static int bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + struct bma4xx_data *bma4xx = dev->data; + + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + const enum sensor_channel *const channels = cfg->channels; + const size_t num_channels = cfg->count; + + uint32_t min_buf_len = sizeof(struct bma4xx_encoded_data); + struct bma4xx_encoded_data *edata; + uint8_t *buf; + uint32_t buf_len; + int rc; + + /* Get the buffer for the frame, it may be allocated dynamically by the rtio context */ + rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len); + if (rc != 0) { + LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + + /* Prepare response */ + edata = (struct bma4xx_encoded_data *)buf; + edata->header.is_fifo = false; + edata->header.accel_fs = bma4xx->accel_fs_range; + edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->has_accel = 0; + edata->has_temp = 0; + + /* Determine what channels we need to fetch */ + for (int i = 0; i < num_channels; i++) { + switch (channels[i]) { + case SENSOR_CHAN_ALL: + edata->has_accel = 1; +#ifdef CONFIG_BMA4XX_TEMPERATURE + edata->has_temp = 1; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + break; + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + edata->has_accel = 1; + break; +#ifdef CONFIG_BMA4XX_TEMPERATURE + case SENSOR_CHAN_DIE_TEMP: + edata->has_temp = 1; + break; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + default: + LOG_ERR("Requested unsupported channel ID %d", channels[i]); + return -ENOTSUP; + } + } + + if (edata->has_accel) { + rc = bma4xx_sample_fetch(dev, &edata->accel_xyz[0], &edata->accel_xyz[1], + &edata->accel_xyz[2]); + if (rc != 0) { + LOG_ERR("Failed to fetch accel samples"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + } + +#ifdef CONFIG_BMA4XX_TEMPERATURE + if (edata->has_temp) { + rc = bma4xx_temp_fetch(dev, &edata->temp); + if (rc != 0) { + LOG_ERR("Failed to fetch temp sample"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return rc; + } + } +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + + rtio_iodev_sqe_ok(iodev_sqe, 0); + + return 0; +} + +static int bma4xx_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) +{ + const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; + + if (!cfg->is_streaming) { + return bma4xx_submit_one_shot(dev, iodev_sqe); + } + /* TODO: Add streaming support */ + + return -ENOTSUP; +} + +/* + * RTIO decoder + */ + +static int bma4xx_decoder_get_frame_count(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint16_t *frame_count) +{ + const struct bma4xx_encoded_data *edata = (const struct bma4xx_encoded_data *)buffer; + const struct bma4xx_decoder_header *header = &edata->header; + + if (channel_idx != 0) { + return -ENOTSUP; + } + + if (!header->is_fifo) { + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + *frame_count = edata->has_accel ? 1 : 0; + return 0; + case SENSOR_CHAN_DIE_TEMP: + *frame_count = edata->has_temp ? 1 : 0; + return 0; + default: + return -ENOTSUP; + } + return 0; + } + + /* FIFO (streaming) mode operation is not yet supported */ + return -ENOTSUP; +} + +static int bma4xx_decoder_get_size_info(enum sensor_channel channel, size_t *base_size, + size_t *frame_size) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + *base_size = sizeof(struct sensor_three_axis_data); + *frame_size = sizeof(struct sensor_three_axis_sample_data); + return 0; + case SENSOR_CHAN_DIE_TEMP: + *base_size = sizeof(struct sensor_q31_data); + *frame_size = sizeof(struct sensor_q31_sample_data); + return 0; + default: + return -ENOTSUP; + } +} + +static int bma4xx_get_shift(enum sensor_channel channel, uint8_t accel_fs, int8_t *shift) +{ + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + switch (accel_fs) { + case BMA4XX_RANGE_2G: + /* 2 G's = 19.62 m/s^2. Use shift of 5 (+/-32) */ + *shift = 5; + return 0; + case BMA4XX_RANGE_4G: + *shift = 6; + return 0; + case BMA4XX_RANGE_8G: + *shift = 7; + return 0; + case BMA4XX_RANGE_16G: + *shift = 8; + return 0; + default: + return -EINVAL; + } + case SENSOR_CHAN_DIE_TEMP: + *shift = BMA4XX_TEMP_SHIFT; + return 0; + default: + return -EINVAL; + } +} + +static void bma4xx_convert_raw_accel_to_q31(int16_t raw_val, q31_t *out) +{ + /* The full calculation is (assuming floating math): + * value_ms2 = raw_value * range * 9.8065 / BIT(11) + * We can treat 'range * 9.8065' as a scale, the scale is calculated by first getting 1g + * represented as a q31 value with the same shift as our result: + * 1g = (9.8065 * BIT(31)) >> shift + * Next, we need to multiply it by our range in g, which for this driver is one of + * [2, 4, 8, 16] and maps to a left shift of [1, 2, 3, 4]: + * 1g <<= log2(range) + * Note we used a right shift by 'shift' and left shift by log2(range). 'shift' is + * [5, 6, 7, 8] for range values [2, 4, 8, 16] since it's the final shift in m/s2. It is + * calculated via: + * shift = ceil(log2(range * 9.8065)) + * This means that we can shorten the above 1g alterations to: + * 1g = (1g >> ceil(log2(range * 9.8065))) << log2(range) + * For the range values [2, 4, 8, 16], the following is true: + * (x >> ceil(log2(range * 9.8065))) << log2(range) + * = x >> 4 + * Since the range cancels out in the right and left shift, we've now reduced the following: + * range * 9.8065 = 9.8065 * BIT(31 - 4) + * All that's left is to divide by the bma4xx's maximum range BIT(11). + */ + const int64_t scale = (int64_t)(9.8065 * BIT64(31 - 4)); + + *out = CLAMP(((int64_t)raw_val * scale) >> 11, INT32_MIN, INT32_MAX); +} + +#ifdef CONFIG_BMA4XX_TEMPERATURE +/** + * @brief Convert the 8-bit temp register value into a Q31 celsius value + */ +static void bma4xx_convert_raw_temp_to_q31(int8_t raw_val, q31_t *out) +{ + /* Value of 0 equals 23 degrees C. Each bit count equals 1 degree C */ + + int64_t intermediate = + ((int64_t)raw_val + 23) * ((int64_t)INT32_MAX + 1) / (1 << BMA4XX_TEMP_SHIFT); + + *out = CLAMP(intermediate, INT32_MIN, INT32_MAX); +} +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + +static int bma4xx_one_shot_decode(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) +{ + const struct bma4xx_encoded_data *edata = (const struct bma4xx_encoded_data *)buffer; + const struct bma4xx_decoder_header *header = &edata->header; + int rc; + + if (*fit != 0) { + return 0; + } + if (max_count == 0 || channel_idx != 0) { + return -EINVAL; + } + + switch (channel) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + if (!edata->has_accel) { + return -ENODATA; + } + + struct sensor_three_axis_data *out = (struct sensor_three_axis_data *)data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = bma4xx_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs, &out->shift); + if (rc != 0) { + return -EINVAL; + } + + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[0], &out->readings[0].x); + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[1], &out->readings[0].y); + bma4xx_convert_raw_accel_to_q31(edata->accel_xyz[2], &out->readings[0].z); + + *fit = 1; + return 1; + } +#ifdef CONFIG_BMA4XX_TEMPERATURE + case SENSOR_CHAN_DIE_TEMP: { + if (!edata->has_temp) { + return -ENODATA; + } + + struct sensor_q31_data *out = (struct sensor_q31_data *)data_out; + + out->header.base_timestamp_ns = edata->header.timestamp; + out->header.reading_count = 1; + rc = bma4xx_get_shift(SENSOR_CHAN_DIE_TEMP, 0, &out->shift); + if (rc != 0) { + return -EINVAL; + } + + bma4xx_convert_raw_temp_to_q31(edata->temp, &out->readings[0].temperature); + + *fit = 1; + return 1; + } +#endif /* CONFIG_BMA4XX_TEMPERATURE */ + default: + return -EINVAL; + } +} + +static int bma4xx_decoder_decode(const uint8_t *buffer, enum sensor_channel channel, + size_t channel_idx, uint32_t *fit, uint16_t max_count, + void *data_out) +{ + const struct bma4xx_decoder_header *header = (const struct bma4xx_decoder_header *)buffer; + + if (header->is_fifo) { + /* FIFO (streaming) mode operation is not yet supported */ + return -ENOTSUP; + } + + return bma4xx_one_shot_decode(buffer, channel, channel_idx, fit, max_count, data_out); +} + +SENSOR_DECODER_API_DT_DEFINE() = { + .get_frame_count = bma4xx_decoder_get_frame_count, + .get_size_info = bma4xx_decoder_get_size_info, + .decode = bma4xx_decoder_decode, +}; + +static int bma4xx_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder) +{ + ARG_UNUSED(dev); + *decoder = &SENSOR_DECODER_NAME(); + + return 0; +} + +/* + * Sensor driver API + */ + +static const struct sensor_driver_api bma4xx_driver_api = { + .attr_set = bma4xx_attr_set, + .submit = bma4xx_submit, + .get_decoder = bma4xx_get_decoder, +}; + +/* + * Device instantiation macros + */ + +/* Initializes a struct bma4xx_config for an instance on a SPI bus. + * SPI operation is not currently supported. + */ + +#define BMA4XX_CONFIG_SPI(inst) \ + { \ + .bus_cfg.spi = SPI_DT_SPEC_INST_GET(inst, 0, 0), .bus_init = &bma_spi_init, \ + } + +/* Initializes a struct bma4xx_config for an instance on an I2C bus. */ +#define BMA4XX_CONFIG_I2C(inst) \ + { \ + .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), .bus_init = &bma4xx_i2c_init, \ + } + +/* + * Main instantiation macro, which selects the correct bus-specific + * instantiation macros for the instance. + */ +#define BMA4XX_DEFINE(inst) \ + static struct bma4xx_data bma4xx_data_##inst; \ + static const struct bma4xx_config bma4xx_config_##inst = COND_CODE_1( \ + DT_INST_ON_BUS(inst, spi), (BMA4XX_CONFIG_SPI(inst)), (BMA4XX_CONFIG_I2C(inst))); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, bma4xx_chip_init, NULL, &bma4xx_data_##inst, \ + &bma4xx_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &bma4xx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BMA4XX_DEFINE) diff --git a/drivers/sensor/bma4xx/bma4xx.h b/drivers/sensor/bma4xx/bma4xx.h new file mode 100644 index 00000000000..6184e40b062 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ + +#include +#include +#include + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +/* + * Register definitions + */ + +#define BMA4XX_REG_CHIP_ID (0x00) +#define BMA4XX_REG_ERROR (0x02) +#define BMA4XX_REG_STATUS (0x03) +#define BMA4XX_REG_DATA_0 (0x0A) +#define BMA4XX_REG_DATA_1 (0x0B) +#define BMA4XX_REG_DATA_2 (0x0C) +#define BMA4XX_REG_DATA_3 (0x0D) +#define BMA4XX_REG_DATA_4 (0x0E) +#define BMA4XX_REG_DATA_5 (0x0F) +#define BMA4XX_REG_DATA_6 (0x10) +#define BMA4XX_REG_DATA_7 (0x11) +#define BMA4XX_REG_DATA_8 (0x12) +#define BMA4XX_REG_DATA_9 (0x13) +#define BMA4XX_REG_DATA_10 (0x14) +#define BMA4XX_REG_DATA_11 (0x15) +#define BMA4XX_REG_DATA_12 (0x16) +#define BMA4XX_REG_DATA_13 (0x17) +#define BMA4XX_REG_SENSORTIME_0 (0x18) +#define BMA4XX_REG_INT_STAT_0 (0x1C) +#define BMA4XX_REG_INT_STAT_1 (0x1D) +#define BMA4XX_REG_STEP_CNT_OUT_0 (0x1E) +#define BMA4XX_REG_HIGH_G_OUT (0x1F) +#define BMA4XX_REG_TEMPERATURE (0x22) +#define BMA4XX_REG_FIFO_LENGTH_0 (0x24) +#define BMA4XX_REG_FIFO_LENGTH_1 (0x25) +#define BMA4XX_REG_FIFO_DATA (0x26) +#define BMA4XX_REG_ACTIVITY_OUT (0x27) +#define BMA4XX_REG_ORIENTATION_OUT (0x28) +#define BMA4XX_REG_ACCEL_CONFIG (0x40) +#define BMA4XX_REG_ACCEL_RANGE (0x41) +#define BMA4XX_REG_AUX_CONFIG (0x44) +#define BMA4XX_REG_FIFO_DOWN (0x45) +#define BMA4XX_REG_FIFO_WTM_0 (0x46) +#define BMA4XX_REG_FIFO_CONFIG_0 (0x48) +#define BMA4XX_REG_FIFO_CONFIG_1 (0x49) +#define BMA4XX_REG_AUX_DEV_ID (0x4B) +#define BMA4XX_REG_AUX_IF_CONF (0x4C) +#define BMA4XX_REG_AUX_RD (0x4D) +#define BMA4XX_REG_AUX_WR (0x4E) +#define BMA4XX_REG_AUX_WR_DATA (0x4F) +#define BMA4XX_REG_INT1_IO_CTRL (0x53) +#define BMA4XX_REG_INT2_IO_CTRL (0x54) +#define BMA4XX_REG_INT_LATCH (0x55) +#define BMA4XX_REG_INT_MAP_1 (0x56) +#define BMA4XX_REG_INT_MAP_2 (0x57) +#define BMA4XX_REG_INT_MAP_DATA (0x58) +#define BMA4XX_REG_INIT_CTRL (0x59) +#define BMA4XX_REG_RESERVED_REG_5B (0x5B) +#define BMA4XX_REG_RESERVED_REG_5C (0x5C) +#define BMA4XX_REG_FEATURE_CONFIG (0x5E) +#define BMA4XX_REG_IF_CONFIG (0x6B) +#define BMA4XX_REG_ACC_SELF_TEST (0x6D) +#define BMA4XX_REG_NV_CONFIG (0x70) +#define BMA4XX_REG_OFFSET_0 (0x71) +#define BMA4XX_REG_OFFSET_1 (0x72) +#define BMA4XX_REG_OFFSET_2 (0x73) +#define BMA4XX_REG_POWER_CONF (0x7C) +#define BMA4XX_REG_POWER_CTRL (0x7D) +#define BMA4XX_REG_CMD (0x7E) + +/* + * Bit positions and masks + */ + +#define BMA4XX_BIT_ADV_PWR_SAVE BIT(0) + +#define BMA4XX_MASK_ACC_CONF_ODR GENMASK(3, 0) +#define BMA4XX_MASK_ACC_CONF_BWP GENMASK(6, 4) +#define BMA4XX_SHIFT_ACC_CONF_BWP (4) + +#define BMA4XX_MASK_ACC_RANGE GENMASK(1, 0) + +#define BMA4XX_BIT_ACC_PERF_MODE BIT(7) + +#define BMA4XX_BIT_ACC_EN BIT(2) + +/* INT_STATUS_1 accelerometer data ready to interrupt */ +#define BMA4XX_ACC_DRDY_INT BIT(7) + +/* CMD: Clears all data in FIFO, does not change FIFO_CONFIG and FIFO_DOWNS register */ +#define BMA4XX_CMD_FIFO_FLUSH (0xB0) + +/* FIFO_CONFIG_1 enable: Store Accelerometer data in FIFO (all 3 axes) */ +#define BMA4XX_FIFO_ACC_EN BIT(6) + +/* Bandwidth parameters */ +#define BMA4XX_BWP_OSR4_AVG1 (0x0) +#define BMA4XX_BWP_OSR2_AVG2 (0x1) +#define BMA4XX_BWP_NORM_AVG4 (0x2) +#define BMA4XX_BWP_CIC_AVG8 (0x3) +#define BMA4XX_BWP_RES_AVG16 (0x4) +#define BMA4XX_BWP_RES_AVG32 (0x5) +#define BMA4XX_BWP_RES_AVG64 (0x6) +#define BMA4XX_BWP_RES_AVG128 (0x7) + +/* Full-scale ranges */ +#define BMA4XX_RANGE_2G (0x0) +#define BMA4XX_RANGE_4G (0x1) +#define BMA4XX_RANGE_8G (0x2) +#define BMA4XX_RANGE_16G (0x3) + +/* Output data rates (ODR) */ +#define BMA4XX_ODR_RESERVED (0x00) +#define BMA4XX_ODR_0_78125 (0x01) +#define BMA4XX_ODR_1_5625 (0x02) +#define BMA4XX_ODR_3_125 (0x03) +#define BMA4XX_ODR_6_25 (0x04) +#define BMA4XX_ODR_12_5 (0x05) +#define BMA4XX_ODR_25 (0x06) +#define BMA4XX_ODR_50 (0x07) +#define BMA4XX_ODR_100 (0x08) +#define BMA4XX_ODR_200 (0x09) +#define BMA4XX_ODR_400 (0x0a) +#define BMA4XX_ODR_800 (0x0b) +#define BMA4XX_ODR_1600 (0x0c) +#define BMA4XX_ODR_3200 (0x0d) +#define BMA4XX_ODR_6400 (0x0e) +#define BMA4XX_ODR_12800 (0x0f) + +/* + * BMA4xx commands + */ + +#define BMA4XX_CMD_SOFT_RESET (0xB6) + +#define BMA4XX_CHIP_ID_BMA422 (0x12) +#define BMA4XX_CHIP_ID_BMA423 (0x13) + +/* + * Other constants + */ + +/* Each bit count is 3.9mG or 3900uG */ +#define BMA4XX_OFFSET_MICROG_PER_BIT (3900) +#define BMA4XX_OFFSET_MICROG_MIN (INT8_MIN * BMA4XX_OFFSET_MICROG_PER_BIT) +#define BMA4XX_OFFSET_MICROG_MAX (INT8_MAX * BMA4XX_OFFSET_MICROG_PER_BIT) + +/* Range is -104C to 150C. Use shift of 8 (+/-256) */ +#define BMA4XX_TEMP_SHIFT (8) + +/* The total number of used registers specified in bma422 datasheet is 7E */ +#define BMA4XX_NUM_REGS 0x7E + +/* + * Types + */ + +union bma4xx_bus_cfg { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ +}; + +struct bma4xx_config { + int (*bus_init)(const struct device *dev); + const union bma4xx_bus_cfg bus_cfg; +}; + +/** Used to implement bus-specific R/W operations. See bma4xx_i2c.c and + * bma4xx_spi.c. + */ +struct bma4xx_hw_operations { + int (*read_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*write_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*read_reg)(const struct device *dev, uint8_t reg_addr, uint8_t *value); + int (*write_reg)(const struct device *dev, uint8_t reg_addr, uint8_t value); + int (*update_reg)(const struct device *dev, uint8_t reg_addr, uint8_t mask, uint8_t value); +}; + +struct bma4xx_data { + /** Current full-scale range setting as a register value */ + uint8_t accel_fs_range; + /** Current bandwidth parameter (BWP) as a register value */ + uint8_t accel_bwp; + /** Current output data rate as a register value */ + uint8_t accel_odr; + /** Pointer to bus-specific I/O API */ + const struct bma4xx_hw_operations *hw_ops; + /** Chip ID value stored in BMA4XX_REG_CHIP_ID */ + uint8_t chip_id; +}; + +/* + * RTIO types + */ + +struct bma4xx_decoder_header { + uint64_t timestamp; + uint8_t is_fifo: 1; + uint8_t accel_fs: 2; + uint8_t reserved: 5; +} __attribute__((__packed__)); + +struct bma4xx_encoded_data { + struct bma4xx_decoder_header header; + struct { + /** Set if `accel_xyz` has data */ + uint8_t has_accel: 1; + /** Set if `temp` has data */ + uint8_t has_temp: 1; + uint8_t reserved: 6; + } __attribute__((__packed__)); + int16_t accel_xyz[3]; +#ifdef CONFIG_BMA4XX_TEMPERATURE + int8_t temp; +#endif /* CONFIG_BMA4XX_TEMPERATURE */ +}; + +int bma4xx_spi_init(const struct device *dev); +int bma4xx_i2c_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_H_ */ diff --git a/drivers/sensor/bma4xx/bma4xx_emul.c b/drivers/sensor/bma4xx/bma4xx_emul.c new file mode 100644 index 00000000000..b5c96d29817 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_emul.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +#include "bma4xx.h" +#include "bma4xx_emul.h" + +#include "zephyr/sys/util.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bma4xx + +LOG_MODULE_REGISTER(bma4xx_emul, CONFIG_SENSOR_LOG_LEVEL); + +struct bma4xx_emul_data { + /* Holds register data. */ + uint8_t regs[BMA4XX_NUM_REGS]; +}; + +struct bma4xx_emul_cfg { +}; + +void bma4xx_emul_set_reg(const struct emul *target, uint8_t reg_addr, const uint8_t *val, + size_t count) +{ + struct bma4xx_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count <= BMA4XX_NUM_REGS); + memcpy(data->regs + reg_addr, val, count); +} + +void bma4xx_emul_get_reg(const struct emul *target, uint8_t reg_addr, uint8_t *val, size_t count) +{ + struct bma4xx_emul_data *data = target->data; + + __ASSERT_NO_MSG(reg_addr + count <= BMA4XX_NUM_REGS); + memcpy(val, data->regs + reg_addr, count); +} + +uint8_t bma4xx_emul_get_interrupt_config(const struct emul *target, uint8_t *int1_io_ctrl, + bool *latched_mode) +{ + struct bma4xx_emul_data *data = target->data; + + *int1_io_ctrl = data->regs[BMA4XX_REG_INT1_IO_CTRL]; + *latched_mode = data->regs[BMA4XX_REG_INT_LATCH]; + return data->regs[BMA4XX_REG_INT_MAP_DATA]; +} + +static int bma4xx_emul_read_byte(const struct emul *target, int reg, uint8_t *val, int bytes) +{ + bma4xx_emul_get_reg(target, reg, val, bytes); + + return 0; +} + +static int bma4xx_emul_write_byte(const struct emul *target, int reg, uint8_t val, int bytes) +{ + struct bma4xx_emul_data *data = target->data; + + if (bytes != 1) { + LOG_ERR("multi-byte writes are not supported"); + return -ENOTSUP; + } + + switch (reg) { + case BMA4XX_REG_ACCEL_CONFIG: + if ((val & 0xF0) != 0xA0) { + LOG_ERR("unsupported acc_bwp/acc_perf_mode: %#x", val); + return -EINVAL; + } + data->regs[reg] = val & GENMASK(1, 0); + return 0; + case BMA4XX_REG_ACCEL_RANGE: + if ((val & GENMASK(1, 0)) != val) { + LOG_ERR("reserved bits set in ACC_RANGE write: %#x", val); + return -EINVAL; + } + data->regs[reg] = val; + return 0; + case BMA4XX_REG_FIFO_CONFIG_1: + if (val & ~BMA4XX_FIFO_ACC_EN) { + LOG_ERR("unsupported bits set in FIFO_CONFIG_1" + " write: %#x", + val); + return -EINVAL; + } + data->regs[reg] = (val & BMA4XX_FIFO_ACC_EN) != 0; + return 0; + case BMA4XX_REG_INT1_IO_CTRL: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_INT_LATCH: + if ((val & ~1) != 0) { + LOG_ERR("reserved bits set in INT_LATCH: %#x", val); + return -EINVAL; + } + data->regs[reg] = (val & 1) == 1; + return 0; + case BMA4XX_REG_INT_MAP_DATA: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_NV_CONFIG: + if (val & GENMASK(7, 4)) { + LOG_ERR("reserved bits set in NV_CONF write: %#x", val); + return -EINVAL; + } + data->regs[reg] = val; + return 0; + case BMA4XX_REG_OFFSET_0: + case BMA4XX_REG_OFFSET_1: + case BMA4XX_REG_OFFSET_2: + data->regs[reg] = val; + return 0; + case BMA4XX_REG_POWER_CTRL: + if ((val & ~BMA4XX_BIT_ACC_EN) != 0) { + LOG_ERR("unhandled bits in POWER_CTRL write: %#x", val); + return -ENOTSUP; + } + data->regs[reg] = (val & BMA4XX_BIT_ACC_EN) != 0; + return 0; + case BMA4XX_REG_CMD: + if (val == BMA4XX_CMD_FIFO_FLUSH) { /* fifo_flush */ + data->regs[BMA4XX_REG_FIFO_DATA] = 0; + data->regs[BMA4XX_REG_FIFO_LENGTH_0] = 0; + data->regs[BMA4XX_REG_FIFO_LENGTH_1] = 0; + return 0; + } + break; + } + + LOG_WRN("unhandled I2C write to register %#x", reg); + return -ENOTSUP; +} + +static int bma4xx_emul_init(const struct emul *target, const struct device *parent) +{ + struct bma4xx_emul_data *data = target->data; + + data->regs[BMA4XX_REG_CHIP_ID] = BMA4XX_CHIP_ID_BMA422; + data->regs[BMA4XX_REG_ACCEL_RANGE] = BMA4XX_RANGE_4G; + + return 0; +} + +static int bma4xx_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs, int num_msgs, + int addr) +{ + __ASSERT_NO_MSG(msgs && num_msgs); + if (num_msgs != 2) { + return 0; + } + + i2c_dump_msgs_rw(target->dev, msgs, num_msgs, addr, false); + + if (msgs->flags & I2C_MSG_READ) { + LOG_ERR("Unexpected read"); + return -EIO; + } + if (msgs->len != 1) { + LOG_ERR("Unexpected msg0 length %d", msgs->len); + return -EIO; + } + + uint32_t reg = msgs->buf[0]; + + msgs++; + if (msgs->flags & I2C_MSG_READ) { + /* Reads from regs in target->data to msgs->buf */ + bma4xx_emul_read_byte(target, reg, msgs->buf, msgs->len); + } else { + /* Writes msgs->buf[0] to regs in target->data */ + bma4xx_emul_write_byte(target, reg, msgs->buf[0], msgs->len); + } + + return 0; +}; + +void bma4xx_emul_set_accel_data(const struct emul *target, q31_t value, int8_t shift, int8_t reg) +{ + + struct bma4xx_emul_data *data = target->data; + + /* floor(9.80665 * 2^(31−4)) q31_t in (-2^4, 2^4) => range_g = shift of 4 */ + int64_t g = 1316226282; + int64_t range_g = 4; + + int64_t intermediate, unshifted; + int16_t reg_val; + + /* 0x00 -> +/-2g; 0x01 -> +/-4g; 0x02 -> +/-8g; 0x03 -> +/- 16g; */ + int64_t accel_range = (2 << data->regs[BMA4XX_REG_ACCEL_RANGE]); + + unshifted = shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift); + + intermediate = (unshifted * BIT(11)) / (g << range_g); + + intermediate /= accel_range; + + reg_val = CLAMP(intermediate, -2048, 2047); + + /* lsb register uses top 12 of 16 bits to hold value so shift by 4 to fill it */ + data->regs[reg] = FIELD_GET(GENMASK(3, 0), reg_val) << 4; + data->regs[reg + 1] = FIELD_GET(GENMASK(11, 4), reg_val); +} + +static int bma4xx_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + const q31_t *value, int8_t shift) +{ + + if (!target || !target->data) { + return -EINVAL; + } + + struct bma4xx_emul_data *data = target->data; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_8); + break; + case SENSOR_CHAN_ACCEL_Y: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_10); + break; + case SENSOR_CHAN_ACCEL_Z: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_12); + break; + case SENSOR_CHAN_ACCEL_XYZ: + bma4xx_emul_set_accel_data(target, value[0], shift, BMA4XX_REG_DATA_8); + bma4xx_emul_set_accel_data(target, value[1], shift, BMA4XX_REG_DATA_10); + bma4xx_emul_set_accel_data(target, value[2], shift, BMA4XX_REG_DATA_12); + default: + return -ENOTSUP; + } + + /* Set data ready flag */ + data->regs[BMA4XX_REG_INT_STAT_1] |= BMA4XX_ACC_DRDY_INT; + + return 0; +} + +static int bma4xx_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch, + q31_t *lower, q31_t *upper, q31_t *epsilon, + int8_t *shift) +{ + if (!lower || !upper || !epsilon || !shift) { + return -EINVAL; + } + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + break; + default: + return -ENOTSUP; + } + + struct bma4xx_emul_data *data = target->data; + + switch (data->regs[BMA4XX_REG_ACCEL_RANGE]) { + case BMA4XX_RANGE_2G: + *shift = 5; + *upper = (q31_t)(2 * 9.80665 * BIT(31 - 5)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 2 (where 2 comes from 2g range) */ + *epsilon = BIT(31 - 5 - 12 + 1); + break; + case BMA4XX_RANGE_4G: + *shift = 6; + *upper = (q31_t)(4 * 9.80665 * BIT(31 - 6)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 4 (where 4 comes from 4g range) */ + *epsilon = BIT(31 - 6 - 12 + 2); + break; + case BMA4XX_RANGE_8G: + *shift = 7; + *upper = (q31_t)(8 * 9.80665 * BIT(31 - 7)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 8 (where 8 comes from 8g range) */ + *epsilon = BIT(31 - 7 - 12 + 3); + break; + case BMA4XX_RANGE_16G: + *shift = 8; + *upper = (q31_t)(16 * 9.80665 * BIT(31 - 8)); + *lower = -*upper; + /* (1 << (31 - shift) >> 12) * 16 (where 16 comes from 16g range) */ + *epsilon = BIT(31 - 8 - 12 + 4); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct emul_sensor_backend_api bma4xx_emul_sensor_backend_api = { + .set_channel = bma4xx_emul_backend_set_channel, + .get_sample_range = bma4xx_emul_backend_get_sample_range, +}; + +static struct i2c_emul_api bma4xx_emul_api_i2c = { + .transfer = bma4xx_emul_transfer_i2c, +}; + +#define INIT_BMA4XX(n) \ + static struct bma4xx_emul_data bma4xx_emul_data_##n = {}; \ + static const struct bma4xx_emul_cfg bma4xx_emul_cfg_##n = {}; \ + EMUL_DT_INST_DEFINE(n, bma4xx_emul_init, &bma4xx_emul_data_##n, &bma4xx_emul_cfg_##n, \ + &bma4xx_emul_api_i2c, &bma4xx_emul_sensor_backend_api); + +DT_INST_FOREACH_STATUS_OKAY(INIT_BMA4XX) diff --git a/drivers/sensor/bma4xx/bma4xx_emul.h b/drivers/sensor/bma4xx/bma4xx_emul.h new file mode 100644 index 00000000000..2ea8c6f7fcb --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_emul.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ + +#include +#include "zephyr/dsp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Set the sensor's current acceleration reading. */ +void bma4xx_emul_set_accel_data(const struct emul *target, q31_t value, int8_t shift, int8_t reg); + +/** + * Return the current interrupt configuration. + * + * Provided pointers are out-parameters for the INT1_IO_CTRL register and + * whether interrupts are in latched mode. The return value is the current value + * of the INT_MAP_DATA register. + */ +uint8_t bma4xx_emul_get_interrupt_config(const struct emul *emul, uint8_t *int1_io_ctrl, + bool *latched_mode); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMA4XX_BMA4XX_EMUL_H_ */ diff --git a/drivers/sensor/bma4xx/bma4xx_i2c.c b/drivers/sensor/bma4xx/bma4xx_i2c.c new file mode 100644 index 00000000000..e21631c45fe --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_i2c.c @@ -0,0 +1,83 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include + +#include "bma4xx.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +LOG_MODULE_DECLARE(bma4xx, CONFIG_SENSOR_LOG_LEVEL); + +static int bma4xx_i2c_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_burst_read_dt(&cfg->bus_cfg.i2c, reg_addr, value, + len); +} + +static int bma4xx_i2c_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_burst_write_dt(&cfg->bus_cfg.i2c, reg_addr, value, + len); +} + +static int bma4xx_i2c_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_read_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value); +} + +static int bma4xx_i2c_write_reg(const struct device *dev, uint8_t reg_addr, + uint8_t value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_write_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value); +} + +static int bma4xx_i2c_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + const struct bma4xx_config *cfg = dev->config; + + return i2c_reg_update_byte_dt(&cfg->bus_cfg.i2c, reg_addr, mask, value); +} + +static const struct bma4xx_hw_operations i2c_ops = { + .read_data = bma4xx_i2c_read_data, + .write_data = bma4xx_i2c_write_data, + .read_reg = bma4xx_i2c_read_reg, + .write_reg = bma4xx_i2c_write_reg, + .update_reg = bma4xx_i2c_update_reg, +}; + +int bma4xx_i2c_init(const struct device *dev) +{ + struct bma4xx_data *data = dev->data; + const struct bma4xx_config *cfg = dev->config; + + if (!device_is_ready(cfg->bus_cfg.i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + data->hw_ops = &i2c_ops; + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ diff --git a/drivers/sensor/bma4xx/bma4xx_spi.c b/drivers/sensor/bma4xx/bma4xx_spi.c new file mode 100644 index 00000000000..708c9cc7ad0 --- /dev/null +++ b/drivers/sensor/bma4xx/bma4xx_spi.c @@ -0,0 +1,71 @@ +/* Bosch BMA4xx 3-axis accelerometer driver + * + * Copyright (c) 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT bosch_bma4xx + +#include +#include + +#include "bma4xx.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +LOG_MODULE_DECLARE(bma4xx, CONFIG_SENSOR_LOG_LEVEL); + +static int bma4xx_spi_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_write_reg(const struct device *dev, uint8_t reg_addr, + uint8_t value) +{ + return -ENOTSUP; +} + +static int bma4xx_spi_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + return -ENOTSUP; +} + +static const struct bma4xx_hw_operations spi_ops = { + .read_data = bma4xx_spi_read_data, + .write_data = bma4xx_spi_write_data, + .read_reg = bma4xx_spi_read_reg, + .write_reg = bma4xx_spi_write_reg, + .update_reg = bma4xx_spi_update_reg, +}; + +int bma4xx_spi_init(const struct device *dev) +{ + struct bma4xx_data *data = dev->data; + const struct bma4xx_config *cfg = dev->config; + + if (!device_is_ready(cfg->bus_cfg.spi.bus)) { + LOG_ERR("SPI bus device is not ready"); + return -ENODEV; + } + + data->hw_ops = &spi_ops; + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ diff --git a/drivers/sensor/bmi160/bmi160.c b/drivers/sensor/bmi160/bmi160.c index d79259c8ba2..8f19cedac78 100644 --- a/drivers/sensor/bmi160/bmi160.c +++ b/drivers/sensor/bmi160/bmi160.c @@ -251,7 +251,7 @@ struct { * SENSOR_ATTR_SAMPLING_FREQUENCY attribute. */ } bmi160_odr_map[] = { - {0, 0 }, {0, 780}, {1, 562}, {3, 120}, {6, 250}, + {0, 0 }, {0, 781}, {1, 562}, {3, 125}, {6, 250}, {12, 500}, {25, 0 }, {50, 0 }, {100, 0 }, {200, 0 }, {400, 0 }, {800, 0 }, {1600, 0 }, {3200, 0 }, }; @@ -281,21 +281,12 @@ static int bmi160_freq_to_odr_val(uint16_t freq_int, uint16_t freq_milli) static int bmi160_acc_odr_set(const struct device *dev, uint16_t freq_int, uint16_t freq_milli) { - struct bmi160_data *data = dev->data; int odr = bmi160_freq_to_odr_val(freq_int, freq_milli); if (odr < 0) { return odr; } - /* some odr values cannot be set in certain power modes */ - if ((data->pmu_sts.acc == BMI160_PMU_NORMAL && - odr < BMI160_ODR_25_2) || - (data->pmu_sts.acc == BMI160_PMU_LOW_POWER && - odr < BMI160_ODR_25_32) || odr > BMI160_ODR_1600) { - return -ENOTSUP; - } - return bmi160_reg_field_update(dev, BMI160_REG_ACC_CONF, BMI160_ACC_CONF_ODR_POS, BMI160_ACC_CONF_ODR_MASK, @@ -312,11 +303,11 @@ static const struct bmi160_range bmi160_acc_range_map[] = { #define BMI160_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi160_acc_range_map) static const struct bmi160_range bmi160_gyr_range_map[] = { - {2000, BMI160_GYR_RANGE_2000DPS}, - {1000, BMI160_GYR_RANGE_1000DPS}, - {500, BMI160_GYR_RANGE_500DPS}, - {250, BMI160_GYR_RANGE_250DPS}, {125, BMI160_GYR_RANGE_125DPS}, + {250, BMI160_GYR_RANGE_250DPS}, + {500, BMI160_GYR_RANGE_500DPS}, + {1000, BMI160_GYR_RANGE_1000DPS}, + {2000, BMI160_GYR_RANGE_2000DPS}, }; #define BMI160_GYR_RANGE_MAP_SIZE ARRAY_SIZE(bmi160_gyr_range_map) @@ -381,10 +372,11 @@ static int bmi160_do_calibration(const struct device *dev, uint8_t foc_conf) } #if defined(CONFIG_BMI160_ACCEL_RANGE_RUNTIME) -static int bmi160_acc_range_set(const struct device *dev, int32_t range) +static int bmi160_acc_range_set(const struct device *dev, const struct sensor_value *val) { + int32_t range_g = sensor_ms2_to_g(val); struct bmi160_data *data = dev->data; - int32_t reg_val = bmi160_range_to_reg_val(range, + int32_t reg_val = bmi160_range_to_reg_val(range_g, bmi160_acc_range_map, BMI160_ACC_RANGE_MAP_SIZE); @@ -392,12 +384,26 @@ static int bmi160_acc_range_set(const struct device *dev, int32_t range) return reg_val; } + switch (reg_val & 0xff) { + case BMI160_ACC_RANGE_2G: + range_g = 2; + break; + case BMI160_ACC_RANGE_4G: + range_g = 4; + break; + case BMI160_ACC_RANGE_8G: + range_g = 8; + break; + case BMI160_ACC_RANGE_16G: + range_g = 16; + break; + } + if (bmi160_byte_write(dev, BMI160_REG_ACC_RANGE, reg_val & 0xff) < 0) { return -EIO; } - data->scale.acc = BMI160_ACC_SCALE(range); - + data->scale.acc_numerator = BMI160_ACC_SCALE_NUMERATOR(range_g); return 0; } #endif @@ -418,8 +424,7 @@ static int bmi160_acc_ofs_set(const struct device *dev, BMI160_REG_OFFSET_ACC_Z }; int i; - int32_t ofs_u; - int8_t reg_val; + int32_t reg_val; /* we need the offsets for all axis */ if (chan != SENSOR_CHAN_ACCEL_XYZ) { @@ -428,8 +433,8 @@ static int bmi160_acc_ofs_set(const struct device *dev, for (i = 0; i < BMI160_AXES; i++, ofs++) { /* convert offset to micro m/s^2 */ - ofs_u = ofs->val1 * 1000000ULL + ofs->val2; - reg_val = ofs_u / BMI160_ACC_OFS_LSB; + reg_val = + CLAMP(sensor_value_to_micro(ofs) / BMI160_ACC_OFS_LSB, INT8_MIN, INT8_MAX); if (bmi160_byte_write(dev, reg_addr[i], reg_val) < 0) { return -EIO; @@ -502,7 +507,7 @@ static int bmi160_acc_config(const struct device *dev, switch (attr) { #if defined(CONFIG_BMI160_ACCEL_RANGE_RUNTIME) case SENSOR_ATTR_FULL_SCALE: - return bmi160_acc_range_set(dev, sensor_ms2_to_g(val)); + return bmi160_acc_range_set(dev, val); #endif #if defined(CONFIG_BMI160_ACCEL_ODR_RUNTIME) case SENSOR_ATTR_SAMPLING_FREQUENCY: @@ -548,8 +553,9 @@ static int bmi160_gyr_odr_set(const struct device *dev, uint16_t freq_int, #endif #if defined(CONFIG_BMI160_GYRO_RANGE_RUNTIME) -static int bmi160_gyr_range_set(const struct device *dev, uint16_t range) +static int bmi160_gyr_range_set(const struct device *dev, const struct sensor_value *val) { + uint16_t range = sensor_rad_to_degrees(val); struct bmi160_data *data = dev->data; int32_t reg_val = bmi160_range_to_reg_val(range, bmi160_gyr_range_map, @@ -558,12 +564,29 @@ static int bmi160_gyr_range_set(const struct device *dev, uint16_t range) if (reg_val < 0) { return reg_val; } + switch (reg_val) { + case BMI160_GYR_RANGE_125DPS: + range = 125; + break; + case BMI160_GYR_RANGE_250DPS: + range = 250; + break; + case BMI160_GYR_RANGE_500DPS: + range = 500; + break; + case BMI160_GYR_RANGE_1000DPS: + range = 1000; + break; + case BMI160_GYR_RANGE_2000DPS: + range = 2000; + break; + } if (bmi160_byte_write(dev, BMI160_REG_GYR_RANGE, reg_val) < 0) { return -EIO; } - data->scale.gyr = BMI160_GYR_SCALE(range); + data->scale.gyr_numerator = BMI160_GYR_SCALE_NUMERATOR(range); return 0; } @@ -600,15 +623,7 @@ static int bmi160_gyr_ofs_set(const struct device *dev, /* convert offset to micro rad/s */ ofs_u = ofs->val1 * 1000000ULL + ofs->val2; - val = ofs_u / BMI160_GYR_OFS_LSB; - - /* - * The gyro offset is a 10 bit two-complement value. Make sure - * the passed value is within limits. - */ - if (val < -512 || val > 512) { - return -EINVAL; - } + val = CLAMP(ofs_u / BMI160_GYR_OFS_LSB, -512, 511); /* write the LSB */ if (bmi160_byte_write(dev, ofs_desc[i].lsb_addr, @@ -661,7 +676,7 @@ static int bmi160_gyr_config(const struct device *dev, switch (attr) { #if defined(CONFIG_BMI160_GYRO_RANGE_RUNTIME) case SENSOR_ATTR_FULL_SCALE: - return bmi160_gyr_range_set(dev, sensor_rad_to_degrees(val)); + return bmi160_gyr_range_set(dev, val); #endif #if defined(CONFIG_BMI160_GYRO_ODR_RUNTIME) case SENSOR_ATTR_SAMPLING_FREQUENCY: @@ -709,6 +724,128 @@ static int bmi160_attr_set(const struct device *dev, enum sensor_channel chan, return 0; } +static int bmi160_attr_get(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, struct sensor_value *val) +{ + int rc; + + if (attr == SENSOR_ATTR_OFFSET) { + if (chan != SENSOR_CHAN_ACCEL_XYZ && chan != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + int8_t data[7]; + + rc = bmi160_read(dev, BMI160_REG_OFFSET_ACC_X, data, 7); + if (rc != 0) { + return rc; + } + + if ((chan == SENSOR_CHAN_ACCEL_XYZ && + FIELD_GET(BIT(BMI160_ACC_OFS_EN_POS), data[6]) == 0) || + (chan == SENSOR_CHAN_GYRO_XYZ && + FIELD_GET(BIT(BMI160_GYR_OFS_EN_POS), data[6]) == 0)) { + for (int i = 0; i < 3; ++i) { + val[i].val1 = 0; + val[i].val2 = 0; + } + } else { + for (int i = 0; i < 3; ++i) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + int32_t ug = data[i] * INT32_C(3900); + + sensor_ug_to_ms2(ug, &val[i]); + } else { + int32_t udeg = + (FIELD_GET(GENMASK((2 * i) + 1, 2 * i), data[6]) + << 8) | + data[3 + i]; + + udeg |= 0 - (udeg & 0x200); + udeg *= 61000; + sensor_10udegrees_to_rad(udeg / 10, &val[i]); + } + } + } + return 0; + } + if (attr == SENSOR_ATTR_SAMPLING_FREQUENCY) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + int64_t rate_uhz; + uint8_t acc_odr; + + if (IS_ENABLED(CONFIG_BMI160_ACCEL_ODR_RUNTIME)) { + /* Read the register */ + rc = bmi160_byte_read(dev, BMI160_REG_ACC_CONF, &acc_odr); + if (rc != 0) { + return rc; + } + acc_odr = FIELD_GET(BMI160_ACC_CONF_ODR_MASK, acc_odr); + } else { + acc_odr = BMI160_DEFAULT_ODR_ACC; + } + + rate_uhz = INT64_C(100000000) * BIT(acc_odr) / 256; + val->val1 = rate_uhz / 1000000; + val->val2 = rate_uhz - val->val1 * 1000000; + return 0; + } else if (chan == SENSOR_CHAN_GYRO_XYZ) { + int64_t rate_uhz; + uint8_t gyr_ord; + + if (IS_ENABLED(CONFIG_BMI160_GYRO_ODR_RUNTIME)) { + /* Read the register */ + rc = bmi160_byte_read(dev, BMI160_REG_GYR_CONF, &gyr_ord); + if (rc != 0) { + return rc; + } + gyr_ord = FIELD_GET(BMI160_GYR_CONF_ODR_MASK, gyr_ord); + } else { + gyr_ord = BMI160_DEFAULT_ODR_GYR; + } + + rate_uhz = INT64_C(100000000) * BIT(gyr_ord) / 256; + val->val1 = rate_uhz / 1000000; + val->val2 = rate_uhz - val->val1 * 1000000; + return 0; + + } + return -EINVAL; + + } + if (attr == SENSOR_ATTR_FULL_SCALE) { + if (chan == SENSOR_CHAN_ACCEL_XYZ) { + uint8_t acc_range; + + if (IS_ENABLED(CONFIG_BMI160_ACCEL_RANGE_RUNTIME)) { + rc = bmi160_byte_read(dev, BMI160_REG_ACC_RANGE, &acc_range); + if (rc != 0) { + return rc; + } + } else { + acc_range = BMI160_DEFAULT_RANGE_ACC; + } + sensor_g_to_ms2(bmi160_acc_reg_val_to_range(acc_range), val); + return 0; + } else if (chan == SENSOR_CHAN_GYRO_XYZ) { + uint8_t gyr_range; + + if (IS_ENABLED(CONFIG_BMI160_GYRO_RANGE_RUNTIME)) { + rc = bmi160_byte_read(dev, BMI160_REG_GYR_RANGE, &gyr_range); + if (rc != 0) { + return rc; + } + } else { + gyr_range = BMI160_DEFAULT_RANGE_GYR; + } + sensor_degrees_to_rad(bmi160_gyr_reg_val_to_range(gyr_range), val); + return 0; + } + return -EINVAL; + } + return -EINVAL; +} + static int bmi160_sample_fetch(const struct device *dev, enum sensor_channel chan) { @@ -725,6 +862,14 @@ static int bmi160_sample_fetch(const struct device *dev, goto out; } + if (chan == SENSOR_CHAN_DIE_TEMP) { + /* Die temperature is only valid when at least one measurement is active */ + if (data->pmu_sts.raw == 0U) { + return -EINVAL; + } + return bmi160_word_read(dev, BMI160_REG_TEMPERATURE0, &data->sample.temperature); + } + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); status = 0; @@ -754,24 +899,18 @@ static int bmi160_sample_fetch(const struct device *dev, return ret; } -static void bmi160_to_fixed_point(int16_t raw_val, uint16_t scale, - struct sensor_value *val) +static void bmi160_to_fixed_point(int16_t raw_val, int64_t scale_numerator, + uint32_t scale_denominator, struct sensor_value *val) { - int32_t converted_val; + int64_t converted_val = (int64_t)raw_val * scale_numerator / scale_denominator; - /* - * maximum converted value we can get is: max(raw_val) * max(scale) - * max(raw_val) = +/- 2^15 - * max(scale) = 4785 - * max(converted_val) = 156794880 which is less than 2^31 - */ - converted_val = raw_val * scale; val->val1 = converted_val / 1000000; val->val2 = converted_val % 1000000; } static void bmi160_channel_convert(enum sensor_channel chan, - uint16_t scale, + int64_t scale_numerator, + uint32_t scale_denominator, uint16_t *raw_xyz, struct sensor_value *val) { @@ -797,7 +936,7 @@ static void bmi160_channel_convert(enum sensor_channel chan, } for (i = ofs_start; i <= ofs_stop ; i++, val++) { - bmi160_to_fixed_point(raw_xyz[i], scale, val); + bmi160_to_fixed_point(raw_xyz[i], scale_numerator, scale_denominator, val); } } @@ -808,7 +947,8 @@ static inline void bmi160_gyr_channel_get(const struct device *dev, { struct bmi160_data *data = dev->data; - bmi160_channel_convert(chan, data->scale.gyr, data->sample.gyr, val); + bmi160_channel_convert(chan, data->scale.gyr_numerator, BMI160_GYR_SCALE_DENOMINATOR, + data->sample.gyr, val); } #endif @@ -819,27 +959,18 @@ static inline void bmi160_acc_channel_get(const struct device *dev, { struct bmi160_data *data = dev->data; - bmi160_channel_convert(chan, data->scale.acc, data->sample.acc, val); + bmi160_channel_convert(chan, data->scale.acc_numerator, BMI160_ACC_SCALE_DENOMINATOR, + data->sample.acc, val); } #endif static int bmi160_temp_channel_get(const struct device *dev, struct sensor_value *val) { - uint16_t temp_raw = 0U; - int32_t temp_micro = 0; struct bmi160_data *data = dev->data; - if (data->pmu_sts.raw == 0U) { - return -EINVAL; - } - - if (bmi160_word_read(dev, BMI160_REG_TEMPERATURE0, &temp_raw) < 0) { - return -EIO; - } - /* the scale is 1/2^9/LSB = 1953 micro degrees */ - temp_micro = BMI160_TEMP_OFFSET * 1000000ULL + temp_raw * 1953ULL; + int32_t temp_micro = BMI160_TEMP_OFFSET * 1000000ULL + data->sample.temperature * 1953ULL; val->val1 = temp_micro / 1000000ULL; val->val2 = temp_micro % 1000000ULL; @@ -880,6 +1011,7 @@ static int bmi160_channel_get(const struct device *dev, static const struct sensor_driver_api bmi160_api = { .attr_set = bmi160_attr_set, + .attr_get = bmi160_attr_get, #ifdef CONFIG_BMI160_TRIGGER .trigger_set = bmi160_trigger_set, #endif @@ -994,7 +1126,7 @@ int bmi160_init(const struct device *dev) acc_range = bmi160_acc_reg_val_to_range(BMI160_DEFAULT_RANGE_ACC); - data->scale.acc = BMI160_ACC_SCALE(acc_range); + data->scale.acc_numerator = BMI160_ACC_SCALE_NUMERATOR(acc_range); /* set gyro default range */ if (bmi160_byte_write(dev, BMI160_REG_GYR_RANGE, @@ -1005,7 +1137,7 @@ int bmi160_init(const struct device *dev) gyr_range = bmi160_gyr_reg_val_to_range(BMI160_DEFAULT_RANGE_GYR); - data->scale.gyr = BMI160_GYR_SCALE(gyr_range); + data->scale.gyr_numerator = BMI160_GYR_SCALE_NUMERATOR(gyr_range); if (bmi160_reg_field_update(dev, BMI160_REG_ACC_CONF, BMI160_ACC_CONF_ODR_POS, diff --git a/drivers/sensor/bmi160/bmi160.h b/drivers/sensor/bmi160/bmi160.h index 1399d88b76c..a0beb7f05bc 100644 --- a/drivers/sensor/bmi160/bmi160.h +++ b/drivers/sensor/bmi160/bmi160.h @@ -17,6 +17,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* registers */ #define BMI160_REG_CHIPID 0x00 #define BMI160_REG_ERR 0x02 @@ -296,9 +300,11 @@ enum bmi160_odr { #define BMI160_GYR_RANGE_250DPS 3 #define BMI160_GYR_RANGE_125DPS 4 -#define BMI160_ACC_SCALE(range_g) ((2 * range_g * SENSOR_G) / 65536LL) -#define BMI160_GYR_SCALE(range_dps)\ - ((2 * range_dps * SENSOR_PI) / 180LL / 65536LL) +#define BMI160_ACC_SCALE_NUMERATOR(range_g) (2 * (range_g) * SENSOR_G) +#define BMI160_ACC_SCALE_DENOMINATOR UINT16_MAX + +#define BMI160_GYR_SCALE_NUMERATOR(range_dps) (2 * (range_dps) * SENSOR_PI) +#define BMI160_GYR_SCALE_DENOMINATOR (UINT32_C(180) * UINT16_MAX) /* default settings, based on menuconfig options */ @@ -467,6 +473,7 @@ union bmi160_pmu_status { /* Each sample has X, Y and Z */ union bmi160_sample { uint8_t raw[BMI160_BUF_SIZE]; + uint16_t temperature; struct { #if !defined(CONFIG_BMI160_GYRO_PMU_SUSPEND) uint16_t gyr[BMI160_AXES]; @@ -478,8 +485,10 @@ union bmi160_sample { }; struct bmi160_scale { - uint16_t acc; /* micro m/s^2/lsb */ - uint16_t gyr; /* micro radians/s/lsb */ + /* numerator / denominator => micro m/s^2/lsb */ + int32_t acc_numerator; + /* numerator / denominator => micro radians/s/lsb */ + int64_t gyr_numerator; }; struct bmi160_data { @@ -541,4 +550,8 @@ int bmi160_acc_slope_config(const struct device *dev, int32_t bmi160_acc_reg_val_to_range(uint8_t reg_val); int32_t bmi160_gyr_reg_val_to_range(uint8_t reg_val); +#ifdef __cplusplus +} +#endif + #endif /* ZEPHYR_DRIVERS_SENSOR_BMI160_BMI160_H_ */ diff --git a/drivers/sensor/bmi160/emul_bmi160.c b/drivers/sensor/bmi160/emul_bmi160.c index 3870346cd30..3ed71790fbe 100644 --- a/drivers/sensor/bmi160/emul_bmi160.c +++ b/drivers/sensor/bmi160/emul_bmi160.c @@ -17,10 +17,12 @@ LOG_MODULE_REGISTER(bosch_bmi160); #include #include #include +#include #include #include #include #include +#include /** Run-time data used by the emulator */ struct bmi160_emul_data { @@ -42,25 +44,18 @@ struct bmi160_emul_cfg { }; /* Names for the PMU components */ -static const char *const pmu_name[] = { "acc", "gyr", "mag", "INV" }; +static const char *const pmu_name[] = {"acc", "gyr", "mag", "INV"}; -static void sample_read(union bmi160_sample *buf) +int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out, size_t count) { - /* - * Use hard-coded scales to get values just above 0, 1, 2 and - * 3, 4, 5. Values are stored in little endianness. - * gyr[x] = 0x0b01 // 3 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * gyr[y] = 0x0eac // 4 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * gyr[z] = 0x1257 // 5 * 1000000 / BMI160_GYR_SCALE(2000) + 1 - * acc[x] = 0x0001 // 0 * 1000000 / BMI160_ACC_SCALE(2) + 1 - * acc[y] = 0x0689 // 1 * 1000000 / BMI160_ACC_SCALE(2) + 1 - * acc[z] = 0x0d11 // 2 * 1000000 / BMI160_ACC_SCALE(2) + 1 - */ - static uint8_t raw_data[] = { 0x01, 0x0b, 0xac, 0x0e, 0x57, 0x12, - 0x01, 0x00, 0x89, 0x06, 0x11, 0x0d }; - - LOG_INF("Sample read"); - memcpy(buf->raw, raw_data, ARRAY_SIZE(raw_data)); + const struct bmi160_emul_cfg *cfg = target->cfg; + + if (reg_number < 0 || reg_number + count > BMI160_REG_COUNT) { + return -EINVAL; + } + + memcpy(out, cfg->reg + reg_number, count); + return 0; } static void reg_write(const struct emul *target, int regn, int val) @@ -68,25 +63,25 @@ static void reg_write(const struct emul *target, int regn, int val) struct bmi160_emul_data *data = target->data; const struct bmi160_emul_cfg *cfg = target->cfg; - LOG_INF("write %x = %x", regn, val); + LOG_DBG("write %x = %x", regn, val); cfg->reg[regn] = val; switch (regn) { case BMI160_REG_ACC_CONF: - LOG_INF(" * acc conf"); + LOG_DBG(" * acc conf"); break; case BMI160_REG_ACC_RANGE: - LOG_INF(" * acc range"); + LOG_DBG(" * acc range"); break; case BMI160_REG_GYR_CONF: - LOG_INF(" * gyr conf"); + LOG_DBG(" * gyr conf"); break; case BMI160_REG_GYR_RANGE: - LOG_INF(" * gyr range"); + LOG_DBG(" * gyr range"); break; case BMI160_REG_CMD: switch (val) { case BMI160_CMD_SOFT_RESET: - LOG_INF(" * soft reset"); + LOG_DBG(" * soft reset"); break; default: if ((val & BMI160_CMD_PMU_BIT) == BMI160_CMD_PMU_BIT) { @@ -108,16 +103,16 @@ static void reg_write(const struct emul *target, int regn, int val) } data->pmu_status &= 3 << shift; data->pmu_status |= pmu_val << shift; - LOG_INF(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val, + LOG_DBG(" * pmu %s = %x, new status %x", pmu_name[which], pmu_val, data->pmu_status); } else { - LOG_INF("Unknown command %x", val); + LOG_DBG("Unknown command %x", val); } break; } break; default: - LOG_INF("Unknown write %x", regn); + LOG_DBG("Unknown write %x", regn); } } @@ -127,39 +122,39 @@ static int reg_read(const struct emul *target, int regn) const struct bmi160_emul_cfg *cfg = target->cfg; int val; - LOG_INF("read %x =", regn); + LOG_DBG("read %x =", regn); val = cfg->reg[regn]; switch (regn) { case BMI160_REG_CHIPID: - LOG_INF(" * get chipid"); + LOG_DBG(" * get chipid"); break; case BMI160_REG_PMU_STATUS: - LOG_INF(" * get pmu"); + LOG_DBG(" * get pmu"); val = data->pmu_status; break; case BMI160_REG_STATUS: - LOG_INF(" * status"); + LOG_DBG(" * status"); val |= BMI160_DATA_READY_BIT_MASK; break; case BMI160_REG_ACC_CONF: - LOG_INF(" * acc conf"); + LOG_DBG(" * acc conf"); break; case BMI160_REG_GYR_CONF: - LOG_INF(" * gyr conf"); + LOG_DBG(" * gyr conf"); break; case BMI160_SPI_START: - LOG_INF(" * Bus start"); + LOG_DBG(" * Bus start"); break; case BMI160_REG_ACC_RANGE: - LOG_INF(" * acc range"); + LOG_DBG(" * acc range"); break; case BMI160_REG_GYR_RANGE: - LOG_INF(" * gyr range"); + LOG_DBG(" * gyr range"); break; default: - LOG_INF("Unknown read %x", regn); + LOG_DBG("Unknown read %x", regn); } - LOG_INF(" = %x", val); + LOG_DBG(" = %x", val); return val; } @@ -181,49 +176,44 @@ static int bmi160_emul_io_spi(const struct emul *target, const struct spi_config __ASSERT_NO_MSG(!tx_bufs || !rx_bufs || tx_bufs->count == rx_bufs->count); count = tx_bufs ? tx_bufs->count : rx_bufs->count; - switch (count) { - case 2: - tx = tx_bufs->buffers; - txd = &tx_bufs->buffers[1]; - rxd = rx_bufs ? &rx_bufs->buffers[1] : NULL; - switch (tx->len) { - case 1: - regn = *(uint8_t *)tx->buf; - if ((regn & BMI160_REG_READ) && rxd == NULL) { - LOG_ERR("Cannot read without rxd"); - return -EPERM; - } - switch (txd->len) { - case 1: - if (regn & BMI160_REG_READ) { - regn &= BMI160_REG_MASK; - val = reg_read(target, regn); - *(uint8_t *)rxd->buf = val; - } else { - val = *(uint8_t *)txd->buf; - reg_write(target, regn, val); - } - break; - case BMI160_SAMPLE_SIZE: - if (regn & BMI160_REG_READ) { - sample_read(rxd->buf); - } else { - LOG_INF("Unknown sample write"); - } - break; - default: - LOG_INF("Unknown A txd->len %d", txd->len); - break; + if (count != 2) { + LOG_DBG("Unknown tx_bufs->count %d", count); + return -EIO; + } + tx = tx_bufs->buffers; + txd = &tx_bufs->buffers[1]; + rxd = rx_bufs ? &rx_bufs->buffers[1] : NULL; + + if (tx->len != 1) { + LOG_DBG("Unknown tx->len %d", tx->len); + return -EIO; + } + + regn = *(uint8_t *)tx->buf; + if ((regn & BMI160_REG_READ) && rxd == NULL) { + LOG_ERR("Cannot read without rxd"); + return -EPERM; + } + + if (txd->len == 1) { + if (regn & BMI160_REG_READ) { + regn &= BMI160_REG_MASK; + val = reg_read(target, regn); + *(uint8_t *)rxd->buf = val; + } else { + val = *(uint8_t *)txd->buf; + reg_write(target, regn, val); + } + } else { + if (regn & BMI160_REG_READ) { + regn &= BMI160_REG_MASK; + for (int i = 0; i < txd->len; ++i) { + ((uint8_t *)rxd->buf)[i] = reg_read(target, regn + i); } - break; - default: - LOG_INF("Unknown tx->len %d", tx->len); - break; + } else { + LOG_ERR("Unknown sample write"); + return -EIO; } - break; - default: - LOG_INF("Unknown tx_bufs->count %d", count); - break; } return 0; @@ -235,7 +225,6 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m int addr) { struct bmi160_emul_data *data; - unsigned int val; data = target->data; @@ -257,17 +246,8 @@ static int bmi160_emul_transfer_i2c(const struct emul *target, struct i2c_msg *m /* Now process the 'read' part of the message */ msgs++; if (msgs->flags & I2C_MSG_READ) { - switch (msgs->len) { - case 1: - val = reg_read(target, data->cur_reg); - msgs->buf[0] = val; - break; - case BMI160_SAMPLE_SIZE: - sample_read((void *)msgs->buf); - break; - default: - LOG_ERR("Unexpected msg1 length %d", msgs->len); - return -EIO; + for (int i = 0; i < msgs->len; ++i) { + msgs->buf[i] = reg_read(target, data->cur_reg + i); } } else { if (msgs->len != 1) { @@ -299,6 +279,303 @@ static struct i2c_emul_api bmi160_emul_api_i2c = { }; #endif +static int bmi160_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, + const q31_t *value, int8_t shift) +{ + const struct bmi160_emul_cfg *cfg = target->cfg; + int64_t intermediate = *value; + q31_t scale; + int8_t scale_shift = 0; + int reg_lsb; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + reg_lsb = BMI160_REG_DATA_ACC_X + (ch - SENSOR_CHAN_ACCEL_X) * 2; + scale = 0x4e7404ea; + + switch (FIELD_GET(GENMASK(3, 0), cfg->reg[BMI160_REG_ACC_RANGE])) { + case BMI160_ACC_RANGE_4G: + scale_shift = 6; + break; + case BMI160_ACC_RANGE_8G: + scale_shift = 7; + break; + case BMI160_ACC_RANGE_16G: + scale_shift = 8; + break; + default: + scale_shift = 5; + break; + } + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + reg_lsb = BMI160_REG_DATA_GYR_X + (ch - SENSOR_CHAN_GYRO_X) * 2; + scale = 0x45d02bea; + + switch (FIELD_GET(GENMASK(2, 0), cfg->reg[BMI160_REG_GYR_RANGE])) { + case BMI160_GYR_RANGE_2000DPS: + scale_shift = 6; + break; + case BMI160_GYR_RANGE_1000DPS: + scale_shift = 5; + break; + case BMI160_GYR_RANGE_500DPS: + scale_shift = 4; + break; + case BMI160_GYR_RANGE_250DPS: + scale_shift = 3; + break; + case BMI160_GYR_RANGE_125DPS: + scale_shift = 2; + break; + default: + return -EINVAL; + } + break; + case SENSOR_CHAN_DIE_TEMP: + reg_lsb = BMI160_REG_TEMPERATURE0; + scale = 0x8000; + scale_shift = 7; + break; + default: + return -EINVAL; + } + + if (shift < scale_shift) { + /* Original value doesn't have enough int bits, fix it */ + intermediate >>= scale_shift - shift; + } else if (shift > 0 && shift > scale_shift) { + /* Original value might be out-of-bounds, fix it (we're going to lose precision) */ + intermediate <<= shift - scale_shift; + } + + if (ch == SENSOR_CHAN_DIE_TEMP) { + /* Need to subtract 23C */ + intermediate -= INT64_C(23) << (31 - scale_shift); + } + + intermediate = + CLAMP(DIV_ROUND_CLOSEST(intermediate * INT16_MAX, scale), INT16_MIN, INT16_MAX); + + cfg->reg[reg_lsb] = FIELD_GET(GENMASK64(7, 0), intermediate); + cfg->reg[reg_lsb + 1] = FIELD_GET(GENMASK64(15, 8), intermediate); + return 0; +} + +static int bmi160_emul_backend_get_sample_range(const struct emul *target, enum sensor_channel ch, + q31_t *lower, q31_t *upper, q31_t *epsilon, + int8_t *shift) +{ + const struct bmi160_emul_cfg *cfg = target->cfg; + + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: { + uint8_t acc_range = cfg->reg[BMI160_REG_ACC_RANGE]; + + switch (acc_range) { + case BMI160_ACC_RANGE_2G: + *shift = 5; + break; + case BMI160_ACC_RANGE_4G: + *shift = 6; + break; + case BMI160_ACC_RANGE_8G: + *shift = 7; + break; + case BMI160_ACC_RANGE_16G: + *shift = 8; + break; + default: + return -EINVAL; + } + int64_t intermediate = ((int64_t)(2 * 9.80665 * INT32_MAX)) >> 5; + + *upper = intermediate; + *lower = -(*upper); + *epsilon = intermediate * 2 / (1 << (16 - *shift)); + return 0; + } + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: { + uint8_t gyro_range = cfg->reg[BMI160_REG_GYR_RANGE]; + + switch (gyro_range) { + case BMI160_GYR_RANGE_125DPS: + *shift = 2; + break; + case BMI160_GYR_RANGE_250DPS: + *shift = 3; + break; + case BMI160_GYR_RANGE_500DPS: + *shift = 4; + break; + case BMI160_GYR_RANGE_1000DPS: + *shift = 5; + break; + case BMI160_GYR_RANGE_2000DPS: + *shift = 6; + break; + default: + return -EINVAL; + } + + int64_t intermediate = (int64_t)(125 * 3.141592654 * INT32_MAX / 180) >> 2; + + *upper = intermediate; + *lower = -(*upper); + *epsilon = intermediate * 2 / (1 << (16 - *shift)); + return 0; + } + default: + return -EINVAL; + } +} + +static int bmi160_emul_backend_set_offset(const struct emul *target, enum sensor_channel ch, + const q31_t *values, int8_t shift) +{ + if (ch != SENSOR_CHAN_ACCEL_XYZ && ch != SENSOR_CHAN_GYRO_XYZ) { + return -EINVAL; + } + + const struct bmi160_emul_cfg *cfg = target->cfg; + q31_t scale; + int8_t scale_shift = 0; + + if (values[0] == 0 && values[1] == 0 && values[2] == 0) { + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_ACC_OFS_EN_POS); + } else { + cfg->reg[BMI160_REG_OFFSET_EN] &= ~BIT(BMI160_GYR_OFS_EN_POS); + } + } else { + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_ACC_OFS_EN_POS); + } else { + cfg->reg[BMI160_REG_OFFSET_EN] |= BIT(BMI160_GYR_OFS_EN_POS); + } + } + + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + /* + * bits = (values[i]mps2 / 9.80665g/mps2) / 0.0039g + * = values[i] / 0.038245935mps2/bit + * 0.038245935 in Q31 format is 0x4e53e28 with shift 0 + */ + scale = 0x4e53e28; + } else { + /* + * bits = (values[i]rad/s * 180 / pi) / 0.061deg/s + * = values[i] / 0.001064651rad/s + */ + scale = 0x22e2f0; + } + + for (int i = 0; i < 3; ++i) { + int64_t intermediate = values[i]; + + if (shift > scale_shift) { + /* Input uses a bigger scale, we need to increase its value to match */ + intermediate <<= (shift - scale_shift); + } else if (shift < scale_shift) { + /* Scale uses a bigger shift, we need to decrease its value to match */ + scale >>= (scale_shift - shift); + } + + int64_t reg_value = intermediate / scale; + + __ASSERT_NO_MSG(ch != SENSOR_CHAN_ACCEL_XYZ || + (reg_value >= INT8_MIN && reg_value <= INT8_MAX)); + __ASSERT_NO_MSG(ch != SENSOR_CHAN_GYRO_XYZ || + (reg_value >= -0x1ff - 1 && reg_value <= 0x1ff)); + if (ch == SENSOR_CHAN_ACCEL_XYZ) { + cfg->reg[BMI160_REG_OFFSET_ACC_X + i] = reg_value & 0xff; + } else { + cfg->reg[BMI160_REG_OFFSET_GYR_X + i] = reg_value & 0xff; + cfg->reg[BMI160_REG_OFFSET_EN] = + (cfg->reg[BMI160_REG_OFFSET_EN] & ~GENMASK(i * 2 + 1, i * 2)) | + (reg_value & GENMASK(9, 8)); + } + } + + return 0; +} + +static int bmi160_emul_backend_set_attribute(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, const void *value) +{ + if (attribute == SENSOR_ATTR_OFFSET && + (ch == SENSOR_CHAN_ACCEL_XYZ || ch == SENSOR_CHAN_GYRO_XYZ)) { + const struct sensor_three_axis_attribute *attribute_value = value; + + return bmi160_emul_backend_set_offset(target, ch, attribute_value->values, + attribute_value->shift); + } + return -EINVAL; +} + +static int bmi160_emul_backend_get_attribute_metadata(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, q31_t *min, + q31_t *max, q31_t *increment, int8_t *shift) +{ + ARG_UNUSED(target); + switch (ch) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + if (attribute == SENSOR_ATTR_OFFSET) { + /* Offset uses 3.9mg per bit in an 8 bit register: + * 0.0039g * 9.8065m/s2: yields the increment in SI units + * * INT8_MIN (or MAX) : yields the minimum (or maximum) values + * * INT32_MAX >> 3 : converts to q31 format within range [-8, 8] + */ + *min = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MIN * INT32_MAX) >> 3); + *max = (q31_t)((int64_t)(0.0039 * 9.8065 * INT8_MAX * INT32_MAX) >> 3); + *increment = (q31_t)((int64_t)(0.0039 * 9.8065 * INT32_MAX) >> 3); + *shift = 3; + return 0; + } + return -EINVAL; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + if (attribute == SENSOR_ATTR_OFFSET) { + /* Offset uses 0.061deg/s per bit in an 10 bit register: + * 0.061deg/s * pi / 180: yields the increment in SI units + * * INT10_MIN (or MAX) : yields the minimum (or maximum) values + * * INT32_MAX : converts to q31 format within range [-1, 1] + */ + *min = (q31_t)(0.061 * 3.141593 / 180.0 * -512 * INT32_MAX); + *max = (q31_t)(0.061 * 3.141593 / 180.0 * 511 * INT32_MAX); + *increment = (q31_t)(0.061 * 3.141593 / 180.0 * INT32_MAX); + *shift = 0; + return 0; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct emul_sensor_backend_api backend_api = { + .set_channel = bmi160_emul_backend_set_channel, + .get_sample_range = bmi160_emul_backend_get_sample_range, + .set_attribute = bmi160_emul_backend_set_attribute, + .get_attribute_metadata = bmi160_emul_backend_get_attribute_metadata, +}; + static int emul_bosch_bmi160_init(const struct emul *target, const struct device *parent) { const struct bmi160_emul_cfg *cfg = target->cfg; @@ -320,22 +597,19 @@ static int emul_bosch_bmi160_init(const struct emul *target, const struct device #define BMI160_EMUL_DEFINE(n, bus_api) \ EMUL_DT_INST_DEFINE(n, emul_bosch_bmi160_init, &bmi160_emul_data_##n, \ - &bmi160_emul_cfg_##n, &bus_api, NULL) + &bmi160_emul_cfg_##n, &bus_api, &backend_api) /* Instantiation macros used when a device is on a SPI bus */ #define BMI160_EMUL_SPI(n) \ BMI160_EMUL_DATA(n) \ - static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ - .reg = bmi160_emul_reg_##n, \ - .chipsel = \ - DT_INST_REG_ADDR(n) }; \ + static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ + .reg = bmi160_emul_reg_##n, .chipsel = DT_INST_REG_ADDR(n)}; \ BMI160_EMUL_DEFINE(n, bmi160_emul_api_spi) #define BMI160_EMUL_I2C(n) \ BMI160_EMUL_DATA(n) \ - static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = { \ - .reg = bmi160_emul_reg_##n, \ - .addr = DT_INST_REG_ADDR(n) }; \ + static const struct bmi160_emul_cfg bmi160_emul_cfg_##n = {.reg = bmi160_emul_reg_##n, \ + .addr = DT_INST_REG_ADDR(n)}; \ BMI160_EMUL_DEFINE(n, bmi160_emul_api_i2c) /* diff --git a/drivers/sensor/bmi160/emul_bmi160.h b/drivers/sensor/bmi160/emul_bmi160.h new file mode 100644 index 00000000000..e16b089c461 --- /dev/null +++ b/drivers/sensor/bmi160/emul_bmi160.h @@ -0,0 +1,98 @@ +/* + * Copyright 2020 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Check if I2C messages are touching a given register (R or W) + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is either read or written to + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_touching_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (num_msgs != 2) { + return false; + } + if (msgs[0].len != 1) { + return false; + } + if (i2c_is_read_op(msgs)) { + return false; + } + + uint8_t start_reg = msgs[0].buf[0]; + uint8_t read_len = msgs[1].len; + + return (start_reg <= reg) && (reg < start_reg + read_len); +} + +/** + * @brief Check if I2C messages are reading a specific register. + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is read + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_reading_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) { + return false; + } + return i2c_is_read_op(&msgs[1]); +} + +/** + * @brief Check if I2C messages are writing to a specific register. + * + * @param[in] msgs The I2C messages in question + * @param[in] num_msgs The number of messages in the @p msgs array + * @param[in] reg The register to check for + * @return True if @p reg is written + * @return False otherwise + */ +__maybe_unused static bool emul_bmi160_i2c_is_writing_reg(struct i2c_msg *msgs, int num_msgs, + uint32_t reg) +{ + if (!emul_bmi160_i2c_is_touching_reg(msgs, num_msgs, reg)) { + return false; + } + return !i2c_is_read_op(&msgs[1]); +} + +/** + * @brief Get the internal register value of the emulator + * + * @param[in] target The emulator in question + * @param[in] reg_number The register number to start reading at + * @param[out] out Buffer to store the values into + * @param[in] count The number of registers to read + * @return 0 on success + * @return < 0 on error + */ +int emul_bmi160_get_reg_value(const struct emul *target, int reg_number, uint8_t *out, + size_t count); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMI160_EMUL_BMI160_H_ */ diff --git a/drivers/sensor/bmi323/bmi323.c b/drivers/sensor/bmi323/bmi323.c index a77e4271070..65bdef619ec 100644 --- a/drivers/sensor/bmi323/bmi323.c +++ b/drivers/sensor/bmi323/bmi323.c @@ -1142,7 +1142,7 @@ static int bosch_bmi323_init_irq(const struct device *dev) return ret; } - return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); } static int bosch_bmi323_init_int1(const struct device *dev) @@ -1172,6 +1172,7 @@ static void bosch_bmi323_irq_callback_handler(struct k_work *item) static int bosch_bmi323_pm_resume(const struct device *dev) { + const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; int ret; ret = bosch_bmi323_bus_init(dev); @@ -1218,6 +1219,12 @@ static int bosch_bmi323_pm_resume(const struct device *dev) if (ret < 0) { LOG_WRN("Failed to enable INT1"); + return ret; + } + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_WRN("Failed to configure int"); } return ret; @@ -1226,6 +1233,14 @@ static int bosch_bmi323_pm_resume(const struct device *dev) #ifdef CONFIG_PM_DEVICE static int bosch_bmi323_pm_suspend(const struct device *dev) { + const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_WRN("Failed to disable int"); + } + /* Soft reset device to put it into suspend */ return bosch_bmi323_soft_reset(dev); } diff --git a/drivers/sensor/bmp581/CMakeLists.txt b/drivers/sensor/bmp581/CMakeLists.txt new file mode 100644 index 00000000000..2f471fda359 --- /dev/null +++ b/drivers/sensor/bmp581/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Copyright (c) 2022 Badgerd Technologies B.V and its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_library() +zephyr_library_sources(bmp581.c) diff --git a/drivers/sensor/bmp581/Kconfig b/drivers/sensor/bmp581/Kconfig new file mode 100644 index 00000000000..325276b7a97 --- /dev/null +++ b/drivers/sensor/bmp581/Kconfig @@ -0,0 +1,11 @@ +# +# Copyright (c) 2022 Badgerd Technologies B.V and its affiliates +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BMP581 + bool "BMP581 barometric pressure sensor" + depends on DT_HAS_BOSCH_BMP581_ENABLED + select I2C + default y diff --git a/drivers/sensor/bmp581/bmp581.c b/drivers/sensor/bmp581/bmp581.c new file mode 100644 index 00000000000..9989f51d0ad --- /dev/null +++ b/drivers/sensor/bmp581/bmp581.c @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * Copyright (c) 2023 Metratec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bmp581.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bmp581, CONFIG_SENSOR_LOG_LEVEL); + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "BMP581 driver enabled without any devices" +#endif + +static int power_up_check(const struct device *dev); +static int get_nvm_status(uint8_t *nvm_status, const struct device *dev); +static int get_interrupt_status(uint8_t *int_status, const struct device *dev); +static int validate_chip_id(struct bmp581_data *drv); +static int get_osr_odr_press_config(struct bmp581_osr_odr_press_config *osr_odr_press_cfg, + const struct device *dev); +static int set_osr_config(const struct sensor_value *osr, enum sensor_channel chan, + const struct device *dev); +static int set_odr_config(const struct sensor_value *odr, const struct device *dev); +static int soft_reset(const struct device *dev); +static int set_iir_config(const struct sensor_value *iir, const struct device *dev); +static int get_power_mode(enum bmp5_powermode *powermode, const struct device *dev); +static int set_power_mode(enum bmp5_powermode powermode, const struct device *dev); + +static int set_power_mode(enum bmp5_powermode powermode, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + uint8_t odr = 0; + enum bmp5_powermode current_powermode; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + ret = get_power_mode(¤t_powermode, dev); + if (ret != BMP5_OK) { + LOG_ERR("Couldnt set the power mode because something went wrong when getting the " + "current power mode."); + return ret; + } + + if (current_powermode != BMP5_POWERMODE_STANDBY) { + /* + * Device should be set to standby before transitioning to forced mode or normal + * mode or continuous mode. + */ + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, &odr); + if (ret == BMP5_OK) { + /* Setting deep_dis = 1(BMP5_DEEP_DISABLED) disables the deep standby mode + */ + odr = BMP5_SET_BITSLICE(odr, BMP5_DEEP_DISABLE, BMP5_DEEP_DISABLED); + odr = BMP5_SET_BITS_POS_0(odr, BMP5_POWERMODE, BMP5_POWERMODE_STANDBY); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr); + + if (ret != BMP5_OK) { + LOG_DBG("Failed to set power mode to BMP5_POWERMODE_STANDBY."); + return ret; + } + } + } + + /* lets update the power mode */ + switch (powermode) { + case BMP5_POWERMODE_STANDBY: + /* this change is already done so we can just return */ + ret = BMP5_OK; + break; + case BMP5_POWERMODE_DEEP_STANDBY: + LOG_DBG("Setting power mode to DEEP STANDBY is not supported, current power mode " + "is BMP5_POWERMODE_STANDBY."); + ret = -ENOTSUP; + break; + case BMP5_POWERMODE_NORMAL: + case BMP5_POWERMODE_FORCED: + case BMP5_POWERMODE_CONTINUOUS: + odr = BMP5_SET_BITSLICE(odr, BMP5_DEEP_DISABLE, BMP5_DEEP_DISABLED); + odr = BMP5_SET_BITS_POS_0(odr, BMP5_POWERMODE, powermode); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr); + break; + default: + /* invalid power mode */ + ret = -EINVAL; + break; + } + + return ret; +} + +static int get_power_mode(enum bmp5_powermode *powermode, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + + CHECKIF(powermode == NULL || dev == NULL) { + return -EINVAL; + } + + uint8_t reg = 0; + uint8_t raw_power_mode = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, ®); + if (ret != BMP5_OK) { + LOG_DBG("Failed to read odr config to get power mode!"); + return ret; + } + + raw_power_mode = BMP5_GET_BITS_POS_0(reg, BMP5_POWERMODE); + + switch (raw_power_mode) { + case BMP5_POWERMODE_STANDBY: { + /* Getting deep disable status */ + uint8_t deep_dis = BMP5_GET_BITSLICE(reg, BMP5_DEEP_DISABLE); + + /* Checking deepstandby status only when powermode is in standby mode */ + + /* If deep_dis = 0(BMP5_DEEP_ENABLED) then deepstandby mode is enabled. + * If deep_dis = 1(BMP5_DEEP_DISABLED) then deepstandby mode is disabled + */ + if (deep_dis == BMP5_DEEP_ENABLED) { + /* TODO: check if it is really deep standby */ + *powermode = BMP5_POWERMODE_DEEP_STANDBY; + } else { + *powermode = BMP5_POWERMODE_STANDBY; + } + + break; + } + case BMP5_POWERMODE_NORMAL: + *powermode = BMP5_POWERMODE_NORMAL; + break; + case BMP5_POWERMODE_FORCED: + *powermode = BMP5_POWERMODE_FORCED; + break; + case BMP5_POWERMODE_CONTINUOUS: + *powermode = BMP5_POWERMODE_CONTINUOUS; + break; + default: + /* invalid power mode */ + ret = -EINVAL; + LOG_DBG("Something went wrong invalid powermode!"); + break; + } + + return ret; +} + +static int power_up_check(const struct device *dev) +{ + int8_t rslt = 0; + uint8_t nvm_status = 0; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + rslt = get_nvm_status(&nvm_status, dev); + + if (rslt == BMP5_OK) { + /* Check if nvm_rdy status = 1 and nvm_err status = 0 to proceed */ + if ((nvm_status & BMP5_INT_NVM_RDY) && (!(nvm_status & BMP5_INT_NVM_ERR))) { + rslt = BMP5_OK; + } else { + rslt = -EFAULT; + } + } + + return rslt; +} + +static int get_interrupt_status(uint8_t *int_status, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + CHECKIF(int_status == NULL || dev == NULL) { + return -EINVAL; + } + + return i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_INT_STATUS, int_status); +} + +static int get_nvm_status(uint8_t *nvm_status, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + CHECKIF(nvm_status == NULL || dev == NULL) { + return -EINVAL; + } + + return i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_STATUS, nvm_status); +} + +static int validate_chip_id(struct bmp581_data *drv) +{ + int8_t rslt = 0; + + CHECKIF(drv == NULL) { + return -EINVAL; + } + + if ((drv->chip_id == BMP5_CHIP_ID_PRIM) || (drv->chip_id == BMP5_CHIP_ID_SEC)) { + rslt = BMP5_OK; + } else { + drv->chip_id = 0; + rslt = -ENODEV; + } + + return rslt; +} + +/*! + * This API gets the configuration for oversampling of temperature, oversampling of + * pressure and ODR configuration along with pressure enable. + */ +static int get_osr_odr_press_config(struct bmp581_osr_odr_press_config *osr_odr_press_cfg, + const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + + /* Variable to store the function result */ + int8_t rslt = 0; + + /* Variable to store OSR and ODR config */ + uint8_t reg_data[2] = {0}; + + CHECKIF(osr_odr_press_cfg == NULL || dev == NULL) { + return -EINVAL; + } + + /* Get OSR and ODR configuration in burst read */ + rslt = i2c_burst_read_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, reg_data, 2); + + if (rslt == BMP5_OK) { + osr_odr_press_cfg->osr_t = BMP5_GET_BITS_POS_0(reg_data[0], BMP5_TEMP_OS); + osr_odr_press_cfg->osr_p = BMP5_GET_BITSLICE(reg_data[0], BMP5_PRESS_OS); + osr_odr_press_cfg->press_en = BMP5_GET_BITSLICE(reg_data[0], BMP5_PRESS_EN); + osr_odr_press_cfg->odr = BMP5_GET_BITSLICE(reg_data[1], BMP5_ODR); + } + + return rslt; +} + +static int set_osr_config(const struct sensor_value *osr, enum sensor_channel chan, + const struct device *dev) +{ + CHECKIF(osr == NULL || dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + + uint8_t oversampling = osr->val1; + uint8_t press_en = osr->val2 != 0; /* if it is not 0 then pressure is enabled */ + uint8_t osr_val = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, &osr_val); + if (ret == BMP5_OK) { + switch (chan) { + case SENSOR_CHAN_ALL: + osr_val = BMP5_SET_BITS_POS_0(osr_val, BMP5_TEMP_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_EN, press_en); + break; + case SENSOR_CHAN_PRESS: + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_OS, oversampling); + osr_val = BMP5_SET_BITSLICE(osr_val, BMP5_PRESS_EN, press_en); + break; + case SENSOR_CHAN_AMBIENT_TEMP: + osr_val = BMP5_SET_BITS_POS_0(osr_val, BMP5_TEMP_OS, oversampling); + break; + default: + ret = -ENOTSUP; + break; + } + + if (ret == BMP5_OK) { + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_OSR_CONFIG, osr_val); + get_osr_odr_press_config(&drv->osr_odr_press_config, dev); + } + } + + return ret; +} + +static int set_odr_config(const struct sensor_value *odr, const struct device *dev) +{ + CHECKIF(odr == NULL || dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + uint8_t odr_val = 0; + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, &odr_val); + if (ret != BMP5_OK) { + return ret; + } + odr_val = BMP5_SET_BITSLICE(odr_val, BMP5_ODR, odr->val1); + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_ODR_CONFIG, odr_val); + get_osr_odr_press_config(&drv->osr_odr_press_config, dev); + + return ret; +} + +static int soft_reset(const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = 0; + const uint8_t reset_cmd = BMP5_SOFT_RESET_CMD; + uint8_t int_status = 0; + + CHECKIF(dev == NULL) { + return -EINVAL; + } + + ret = i2c_reg_write_byte_dt(&conf->i2c, BMP5_REG_CMD, reset_cmd); + + if (ret == BMP5_OK) { + k_usleep(BMP5_DELAY_US_SOFT_RESET); + ret = get_interrupt_status(&int_status, dev); + if (ret == BMP5_OK) { + if (int_status & BMP5_INT_ASSERTED_POR_SOFTRESET_COMPLETE) { + ret = BMP5_OK; + } else { + ret = -EFAULT; + } + } + } else { + LOG_DBG("Failed perform soft-reset."); + } + + return ret; +} + +static int bmp581_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + CHECKIF(dev == NULL) { + return -EINVAL; + } + + if (chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + uint8_t data[6]; + int ret = 0; + + ret = i2c_burst_read_dt(&conf->i2c, BMP5_REG_TEMP_DATA_XLSB, data, 6); + if (ret == BMP5_OK) { + /* convert raw sensor data to sensor_value. Shift the decimal part by 1 decimal + * place to compensate for the conversion in sensor_value_to_double() + */ + drv->last_sample.temperature.val1 = data[2]; + drv->last_sample.temperature.val2 = (data[1] << 8 | data[0]) * 10; + + if (drv->osr_odr_press_config.press_en == BMP5_ENABLE) { + uint32_t raw_pressure = (uint32_t)((uint32_t)(data[5] << 16) | + (uint16_t)(data[4] << 8) | data[3]); + /* convert raw sensor data to sensor_value. Shift the decimal part by + * 4 decimal places to compensate for the conversion in + * sensor_value_to_double() + */ + drv->last_sample.pressure.val1 = raw_pressure >> 6; + drv->last_sample.pressure.val2 = (raw_pressure & BIT_MASK(6)) * 10000; + } else { + drv->last_sample.pressure.val1 = 0; + drv->last_sample.pressure.val2 = 0; + } + } + + return ret; +} + +static int bmp581_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + CHECKIF(dev == NULL || val == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + + switch (chan) { + case SENSOR_CHAN_PRESS: + /* returns pressure in Pa */ + *val = drv->last_sample.pressure; + return BMP5_OK; + case SENSOR_CHAN_AMBIENT_TEMP: + /* returns temperature in Celcius */ + *val = drv->last_sample.temperature; + return BMP5_OK; + default: + return -ENOTSUP; + } +} + +static int set_iir_config(const struct sensor_value *iir, const struct device *dev) +{ + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = BMP5_OK; + + CHECKIF((iir == NULL) | (dev == NULL)) { + return -EINVAL; + } + + /* Variable to store existing powermode */ + enum bmp5_powermode prev_powermode; + + ret = get_power_mode(&prev_powermode, dev); + if (ret != BMP5_OK) { + LOG_DBG("Not able to get current power mode."); + return ret; + } + /* IIR configuration is writable only during STANDBY mode(as per datasheet) */ + set_power_mode(BMP5_POWERMODE_STANDBY, dev); + + /* update IIR config */ + uint8_t dsp_config[2]; + + ret = i2c_burst_read_dt(&conf->i2c, BMP5_REG_DSP_CONFIG, dsp_config, 2); + if (ret != BMP5_OK) { + LOG_DBG("Failed to read dsp config register."); + return ret; + } + /* Put IIR filtered values in data registers */ + dsp_config[0] = BMP5_SET_BITSLICE(dsp_config[0], BMP5_SHDW_SET_IIR_TEMP, BMP5_ENABLE); + dsp_config[0] = BMP5_SET_BITSLICE(dsp_config[0], BMP5_SHDW_SET_IIR_PRESS, BMP5_ENABLE); + + /* Configure IIR filter */ + dsp_config[1] = iir->val1; + dsp_config[1] = BMP5_SET_BITSLICE(dsp_config[1], BMP5_SET_IIR_PRESS, iir->val2); + + /* Set IIR configuration */ + ret = i2c_burst_write_dt(&conf->i2c, BMP5_REG_DSP_CONFIG, dsp_config, 2); + + if (ret != BMP5_OK) { + LOG_DBG("Failed to configure IIR filter."); + return ret; + } + + /* Restore previous power mode if it is not standby already */ + if (prev_powermode != BMP5_POWERMODE_STANDBY) { + ret = set_power_mode(prev_powermode, dev); + } + + return ret; +} + +static int bmp581_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + CHECKIF(dev == NULL || val == NULL) { + return -EINVAL; + } + + int ret; + + switch ((int)attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + ret = set_odr_config(val, dev); + break; + case SENSOR_ATTR_OVERSAMPLING: + ret = set_osr_config(val, chan, dev); + break; + case BMP5_ATTR_POWER_MODE: { + enum bmp5_powermode powermode = (enum bmp5_powermode)val->val1; + + ret = set_power_mode(powermode, dev); + break; + } + case BMP5_ATTR_IIR_CONFIG: + ret = set_iir_config(val, dev); + break; + default: + ret = -ENOTSUP; + break; + } + return ret; +} + +static int bmp581_init(const struct device *dev) +{ + CHECKIF(dev == NULL) { + return -EINVAL; + } + + struct bmp581_data *drv = (struct bmp581_data *)dev->data; + struct bmp581_config *conf = (struct bmp581_config *)dev->config; + int ret = -1; + + /* Reset the chip id. */ + drv->chip_id = 0; + memset(&drv->osr_odr_press_config, 0, sizeof(drv->osr_odr_press_config)); + memset(&drv->last_sample, 0, sizeof(drv->last_sample)); + + soft_reset(dev); + + ret = i2c_reg_read_byte_dt(&conf->i2c, BMP5_REG_CHIP_ID, &drv->chip_id); + if (ret != BMP5_OK) { + return ret; + } + + if (drv->chip_id != 0) { + ret = power_up_check(dev); + if (ret == BMP5_OK) { + ret = validate_chip_id(drv); + if (ret != BMP5_OK) { + LOG_ERR("Unexpected chip id (%x). Expected (%x or %x)", + drv->chip_id, BMP5_CHIP_ID_PRIM, BMP5_CHIP_ID_SEC); + } + } + } else { + /* that means something went wrong */ + LOG_ERR("Unexpected chip id (%x). Expected (%x or %x)", drv->chip_id, + BMP5_CHIP_ID_PRIM, BMP5_CHIP_ID_SEC); + return -EINVAL; + } + return ret; +} + +static const struct sensor_driver_api bmp581_driver_api = {.sample_fetch = bmp581_sample_fetch, + .channel_get = bmp581_channel_get, + .attr_set = bmp581_attr_set}; + +#define BMP581_CONFIG(i) \ + static const struct bmp581_config bmp581_config_##i = { \ + .i2c = I2C_DT_SPEC_INST_GET(i), \ + } + +#define BMP581_INIT(i) \ + static struct bmp581_data bmp581_data_##i; \ + BMP581_CONFIG(i); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(i, bmp581_init, NULL, &bmp581_data_##i, &bmp581_config_##i, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &bmp581_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(BMP581_INIT) diff --git a/drivers/sensor/bmp581/bmp581.h b/drivers/sensor/bmp581/bmp581.h new file mode 100644 index 00000000000..cdbe7f7e0b8 --- /dev/null +++ b/drivers/sensor/bmp581/bmp581.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Driver is developed to be used with Zephyr. And it only supports i2c interface. + * + * Author: Talha Can Havadar + * + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ +#define ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT bosch_bmp581 + +/* UTILITY MACROS */ +#define BMP5_SET_LOW_BYTE 0x00FFu +#define BMP5_SET_HIGH_BYTE 0xFF00u + +/* BIT SLICE GET AND SET FUNCTIONS */ +#define BMP5_GET_BITSLICE(regvar, bitname) ((regvar & bitname##_MSK) >> bitname##_POS) + +#define BMP5_SET_BITSLICE(regvar, bitname, val) \ + ((regvar & ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK)) + +#define BMP5_GET_LSB(var) (uint8_t)(var & BMP5_SET_LOW_BYTE) +#define BMP5_GET_MSB(var) (uint8_t)((var & BMP5_SET_HIGH_BYTE) >> 8) + +#define BMP5_SET_BIT_VAL_0(reg_data, bitname) (reg_data & ~(bitname##_MSK)) + +#define BMP5_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | (data & bitname##_MSK)) + +#define BMP5_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +#define BMP5_OK 0 +#define BMP5_ENABLE 1u +#define BMP5_DISABLE 0u + +/* BMP5 Registers */ +#define BMP5_REG_CHIP_ID 0x01 +#define BMP5_REG_REV_ID 0x02 +#define BMP5_REG_CHIP_STATUS 0x11 +#define BMP5_REG_DRIVE_CONFIG 0x13 +#define BMP5_REG_INT_CONFIG 0x14 +#define BMP5_REG_INT_SOURCE 0x15 +#define BMP5_REG_FIFO_CONFIG 0x16 +#define BMP5_REG_FIFO_COUNT 0x17 +#define BMP5_REG_FIFO_SEL 0x18 +#define BMP5_REG_TEMP_DATA_XLSB 0x1D +#define BMP5_REG_TEMP_DATA_LSB 0x1E +#define BMP5_REG_TEMP_DATA_MSB 0x1F +#define BMP5_REG_PRESS_DATA_XLSB 0x20 +#define BMP5_REG_PRESS_DATA_LSB 0x21 +#define BMP5_REG_PRESS_DATA_MSB 0x22 +#define BMP5_REG_INT_STATUS 0x27 +#define BMP5_REG_STATUS 0x28 +#define BMP5_REG_FIFO_DATA 0x29 +#define BMP5_REG_NVM_ADDR 0x2B +#define BMP5_REG_NVM_DATA_LSB 0x2C +#define BMP5_REG_NVM_DATA_MSB 0x2D +#define BMP5_REG_DSP_CONFIG 0x30 +#define BMP5_REG_DSP_IIR 0x31 +#define BMP5_REG_OOR_THR_P_LSB 0x32 +#define BMP5_REG_OOR_THR_P_MSB 0x33 +#define BMP5_REG_OOR_RANGE 0x34 +#define BMP5_REG_OOR_CONFIG 0x35 +#define BMP5_REG_OSR_CONFIG 0x36 +#define BMP5_REG_ODR_CONFIG 0x37 +#define BMP5_REG_OSR_EFF 0x38 +#define BMP5_REG_CMD 0x7E +/* endof BMP5 Registers */ + +/* Chip id of BMP5 */ +#define BMP5_CHIP_ID_PRIM 0x50 +#define BMP5_CHIP_ID_SEC 0x51 + +/* I2C addresses */ +#define BMP5_I2C_ADDR_PRIM 0x46 +#define BMP5_I2C_ADDR_SEC 0x47 + +/* NVM addresses */ +#define BMP5_NVM_START_ADDR 0x20 +#define BMP5_NVM_END_ADDR 0x22 + +/* Interface settings */ +#define BMP5_SPI_RD_MASK 0x80 + +/* Delay definition */ +#define BMP5_DELAY_US_SOFT_RESET 2000 +#define BMP5_DELAY_US_STANDBY 2500 +#define BMP5_DELAY_US_NVM_READY_READ 800 +#define BMP5_DELAY_US_NVM_READY_WRITE 10000 + +/* Soft reset command */ +#define BMP5_SOFT_RESET_CMD 0xB6 + +/*! NVM command */ +#define BMP5_NVM_FIRST_CMND 0x5D +#define BMP5_NVM_READ_ENABLE_CMND 0xA5 +#define BMP5_NVM_WRITE_ENABLE_CMND 0xA0 + +/* Deepstandby enable/disable */ +#define BMP5_DEEP_ENABLED 0 +#define BMP5_DEEP_DISABLED 1 + +/*! Fifo frame configuration */ +#define BMP5_FIFO_EMPTY 0X7F +#define BMP5_FIFO_MAX_THRESHOLD_P_T_MODE 0x0F +#define BMP5_FIFO_MAX_THRESHOLD_P_MODE 0x1F + +/* Macro is used to bypass both iir_t and iir_p together */ +#define BMP5_IIR_BYPASS 0xC0 + +/* Pressure Out-of-range count limit */ +#define BMP5_OOR_COUNT_LIMIT_1 0x00 +#define BMP5_OOR_COUNT_LIMIT_3 0x01 +#define BMP5_OOR_COUNT_LIMIT_7 0x02 +#define BMP5_OOR_COUNT_LIMIT_15 0x03 + +/* Interrupt configurations */ +#define BMP5_INT_MODE_PULSED 0 +#define BMP5_INT_MODE_LATCHED 1 + +#define BMP5_INT_POL_ACTIVE_LOW 0 +#define BMP5_INT_POL_ACTIVE_HIGH 1 + +#define BMP5_INT_OD_PUSHPULL 0 +#define BMP5_INT_OD_OPENDRAIN 1 + +/* NVM and Interrupt status asserted macros */ +#define BMP5_INT_ASSERTED_DRDY 0x01 +#define BMP5_INT_ASSERTED_FIFO_FULL 0x02 +#define BMP5_INT_ASSERTED_FIFO_THRES 0x04 +#define BMP5_INT_ASSERTED_PRESSURE_OOR 0x08 +#define BMP5_INT_ASSERTED_POR_SOFTRESET_COMPLETE 0x10 +#define BMP5_INT_NVM_RDY 0x02 +#define BMP5_INT_NVM_ERR 0x04 +#define BMP5_INT_NVM_CMD_ERR 0x08 + +/* Interrupt configurations */ +#define BMP5_INT_MODE_MSK 0x01 + +#define BMP5_INT_POL_MSK 0x02 +#define BMP5_INT_POL_POS 1 + +#define BMP5_INT_OD_MSK 0x04 +#define BMP5_INT_OD_POS 2 + +#define BMP5_INT_EN_MSK 0x08 +#define BMP5_INT_EN_POS 3 + +#define BMP5_INT_DRDY_EN_MSK 0x01 + +#define BMP5_INT_FIFO_FULL_EN_MSK 0x02 +#define BMP5_INT_FIFO_FULL_EN_POS 1 + +#define BMP5_INT_FIFO_THRES_EN_MSK 0x04 +#define BMP5_INT_FIFO_THRES_EN_POS 2 + +#define BMP5_INT_OOR_PRESS_EN_MSK 0x08 +#define BMP5_INT_OOR_PRESS_EN_POS 3 + +/* ODR configuration */ +#define BMP5_ODR_MSK 0x7C +#define BMP5_ODR_POS 2 + +/* OSR configurations */ +#define BMP5_TEMP_OS_MSK 0x07 + +#define BMP5_PRESS_OS_MSK 0x38 +#define BMP5_PRESS_OS_POS 3 + +/* Pressure enable */ +#define BMP5_PRESS_EN_MSK 0x40 +#define BMP5_PRESS_EN_POS 6 + +/* IIR configurations */ +#define BMP5_SET_IIR_TEMP_MSK 0x07 + +#define BMP5_SET_IIR_PRESS_MSK 0x38 +#define BMP5_SET_IIR_PRESS_POS 3 + +#define BMP5_OOR_SEL_IIR_PRESS_MSK 0x80 +#define BMP5_OOR_SEL_IIR_PRESS_POS 7 + +#define BMP5_SHDW_SET_IIR_TEMP_MSK 0x08 +#define BMP5_SHDW_SET_IIR_TEMP_POS 3 + +#define BMP5_SHDW_SET_IIR_PRESS_MSK 0x20 +#define BMP5_SHDW_SET_IIR_PRESS_POS 5 + +#define BMP5_SET_FIFO_IIR_TEMP_MSK 0x10 +#define BMP5_SET_FIFO_IIR_TEMP_POS 4 + +#define BMP5_SET_FIFO_IIR_PRESS_MSK 0x40 +#define BMP5_SET_FIFO_IIR_PRESS_POS 6 + +#define BMP5_IIR_FLUSH_FORCED_EN_MSK 0x04 +#define BMP5_IIR_FLUSH_FORCED_EN_POS 2 + +/* Effective OSR configurations and ODR valid status */ +#define BMP5_OSR_TEMP_EFF_MSK 0x07 + +#define BMP5_OSR_PRESS_EFF_MSK 0x38 +#define BMP5_OSR_PRESS_EFF_POS 3 + +#define BMP5_ODR_IS_VALID_MSK 0x80 +#define BMP5_ODR_IS_VALID_POS 7 + +/* Powermode */ +#define BMP5_POWERMODE_MSK 0x03 + +#define BMP5_DEEP_DISABLE_MSK 0x80 +#define BMP5_DEEP_DISABLE_POS 7 + +/* Fifo configurations */ +#define BMP5_FIFO_THRESHOLD_MSK 0x1F + +#define BMP5_FIFO_MODE_MSK 0x20 +#define BMP5_FIFO_MODE_POS 5 + +#define BMP5_FIFO_DEC_SEL_MSK 0x1C +#define BMP5_FIFO_DEC_SEL_POS 2 + +#define BMP5_FIFO_COUNT_MSK 0x3F + +#define BMP5_FIFO_FRAME_SEL_MSK 0x03 + +/* Out-of-range configuration */ +#define BMP5_OOR_THR_P_LSB_MSK 0x0000FF + +#define BMP5_OOR_THR_P_MSB_MSK 0x00FF00 + +#define BMP5_OOR_THR_P_XMSB_MSK 0x010000 +#define BMP5_OOR_THR_P_XMSB_POS 16 + +/* Macro to mask xmsb value of oor threshold from register(0x35) value */ +#define BMP5_OOR_THR_P_XMSB_REG_MSK 0x01 + +#define BMP5_OOR_COUNT_LIMIT_MSK 0xC0 +#define BMP5_OOR_COUNT_LIMIT_POS 6 + +/* NVM configuration */ +#define BMP5_NVM_ADDR_MSK 0x3F + +#define BMP5_NVM_PROG_EN_MSK 0x40 +#define BMP5_NVM_PROG_EN_POS 6 + +#define BMP5_NVM_DATA_LSB_MSK 0x00FF + +#define BMP5_NVM_DATA_MSB_MSK 0xFF00 + +/*! + * @brief OSR, ODR and pressure configuration structure + */ +struct bmp581_osr_odr_press_config { + /*! Temperature oversampling + * Assignable macros : + * - BMP5_OVERSAMPLING_1X + * - BMP5_OVERSAMPLING_2X + * - BMP5_OVERSAMPLING_4X + * - BMP5_OVERSAMPLING_8X + * - BMP5_OVERSAMPLING_16X + * - BMP5_OVERSAMPLING_32X + * - BMP5_OVERSAMPLING_64X + * - BMP5_OVERSAMPLING_128X + */ + uint8_t osr_t; + + /*! Pressure oversampling + * Assignable macros : + * - BMP5_OVERSAMPLING_1X + * - BMP5_OVERSAMPLING_2X + * - BMP5_OVERSAMPLING_4X + * - BMP5_OVERSAMPLING_8X + * - BMP5_OVERSAMPLING_16X + * - BMP5_OVERSAMPLING_32X + * - BMP5_OVERSAMPLING_64X + * - BMP5_OVERSAMPLING_128X + */ + uint8_t osr_p; + + /*! Enable pressure + * BMP5_ENABLE = Enables pressure data + * BMP5_DISABLE = Disables pressure data + */ + uint8_t press_en; + + /*! Output Data Rate */ + uint8_t odr; +}; + +struct bmp581_sample { + struct sensor_value pressure; + struct sensor_value temperature; +}; + +struct bmp581_data { + uint8_t chip_id; + struct bmp581_sample last_sample; + struct bmp581_osr_odr_press_config osr_odr_press_config; +}; + +struct bmp581_config { + struct i2c_dt_spec i2c; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_BMP581_BMP581_H_ */ diff --git a/drivers/sensor/bq274xx/bq274xx.c b/drivers/sensor/bq274xx/bq274xx.c index 27810204798..13275638df5 100644 --- a/drivers/sensor/bq274xx/bq274xx.c +++ b/drivers/sensor/bq274xx/bq274xx.c @@ -62,6 +62,9 @@ LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL); #define BQ274XX_SUBCLASS_82 82 #define BQ274XX_SUBCLASS_105 105 +/* For temperature conversion */ +#define KELVIN_OFFSET 273.15 + static const struct bq274xx_regs bq27421_regs = { .dm_design_capacity = 10, .dm_design_energy = 12, @@ -485,7 +488,7 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha struct sensor_value *val) { struct bq274xx_data *data = dev->data; - float int_temp; + int32_t int_temp; switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: @@ -509,10 +512,12 @@ static int bq274xx_channel_get(const struct device *dev, enum sensor_channel cha break; case SENSOR_CHAN_GAUGE_TEMP: - int_temp = (data->internal_temperature * 0.1f); - int_temp = int_temp - 273.15f; - val->val1 = (int32_t)int_temp; - val->val2 = (int_temp - (int32_t)int_temp) * 1000000; + /* Convert units from 0.1K to 0.01K */ + int_temp = data->internal_temperature * 10; + /* Convert to 0.01C */ + int_temp -= (int32_t)(100.0 * KELVIN_OFFSET); + val->val1 = int_temp / 100; + val->val2 = (int_temp % 100) * 10000; break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: diff --git a/drivers/sensor/f75303/f75303_emul.c b/drivers/sensor/f75303/f75303_emul.c index 3e33a7b6f7b..5bab9cd4294 100644 --- a/drivers/sensor/f75303/f75303_emul.c +++ b/drivers/sensor/f75303/f75303_emul.c @@ -104,7 +104,7 @@ static int f75303_emul_init(const struct emul *target, const struct device *pare } static int f75303_emul_set_channel(const struct emul *target, enum sensor_channel chan, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { struct f75303_emul_data *data = target->data; int64_t scaled_value; @@ -129,7 +129,7 @@ static int f75303_emul_set_channel(const struct emul *target, enum sensor_channe return -ENOTSUP; } - scaled_value = (int64_t)value << shift; + scaled_value = (int64_t)*value << shift; millicelsius = scaled_value * 1000 / ((int64_t)INT32_MAX + 1); reg_value = CLAMP(millicelsius / 125, 0, 0x7ff); diff --git a/drivers/sensor/hts221/Kconfig b/drivers/sensor/hts221/Kconfig index 5c3ff69273a..bb2ce7d848a 100644 --- a/drivers/sensor/hts221/Kconfig +++ b/drivers/sensor/hts221/Kconfig @@ -5,6 +5,7 @@ menuconfig HTS221 bool "HTS221 temperature and humidity sensor" default y depends on DT_HAS_ST_HTS221_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_HTS221),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_HTS221),spi) select HAS_STMEMSC diff --git a/drivers/sensor/i3g4250d/Kconfig b/drivers/sensor/i3g4250d/Kconfig index 4a9d5b80fd6..6f9dd720a95 100644 --- a/drivers/sensor/i3g4250d/Kconfig +++ b/drivers/sensor/i3g4250d/Kconfig @@ -7,6 +7,7 @@ config I3G4250D bool "I3G4250D three-axis digital output gyroscope" default y depends on DT_HAS_ST_I3G4250D_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select SPI select HAS_STMEMSC select USE_STDC_I3G4250D diff --git a/drivers/sensor/icm42688/Kconfig b/drivers/sensor/icm42688/Kconfig index d7ee43bc761..aea3cc6480f 100644 --- a/drivers/sensor/icm42688/Kconfig +++ b/drivers/sensor/icm42688/Kconfig @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config ICM42688 +menuconfig ICM42688 bool "ICM42688 Six-Axis Motion Tracking Device" default y depends on DT_HAS_INVENSENSE_ICM42688_ENABLED @@ -12,25 +12,24 @@ config ICM42688 help Enable driver for ICM42688 SPI-based six-axis motion tracking device. +if ICM42688 + config EMUL_ICM42688 bool "Emulator for the ICM42688" default y - depends on ICM42688 depends on EMUL help Enable the hardware emulator for the ICM42688. Doing so allows exercising - sensor APIs for this IMU in native_posix and qemu. + sensor APIs for this IMU in native_sim and qemu. config ICM42688_DECODER bool "ICM42688 decoder logic" - default y if ICM42688 + default y select SENSOR_ASYNC_API help Compile the ICM42688 decoder API which allows decoding raw data returned from the sensor. -if ICM42688 - choice prompt "Trigger mode" default ICM42688_TRIGGER_NONE if ICM42688_STREAM diff --git a/drivers/sensor/icm42688/icm42688_emul.c b/drivers/sensor/icm42688/icm42688_emul.c index e01b90742e3..732af64289b 100644 --- a/drivers/sensor/icm42688/icm42688_emul.c +++ b/drivers/sensor/icm42688/icm42688_emul.c @@ -329,7 +329,7 @@ static int icm42688_emul_backend_get_sample_range(const struct emul *target, enu } static int icm42688_emul_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->data) { return -EINVAL; @@ -341,7 +341,7 @@ static int icm42688_emul_backend_set_channel(const struct emul *target, enum sen uint8_t reg_addr; int32_t reg_val; int64_t value_unshifted = - shift < 0 ? ((int64_t)value >> -shift) : ((int64_t)value << shift); + shift < 0 ? ((int64_t)*value >> -shift) : ((int64_t)*value << shift); switch (ch) { case SENSOR_CHAN_DIE_TEMP: diff --git a/drivers/sensor/icm42688/icm42688_trigger.c b/drivers/sensor/icm42688/icm42688_trigger.c index 32b60f3cd75..72ccd7e9059 100644 --- a/drivers/sensor/icm42688/icm42688_trigger.c +++ b/drivers/sensor/icm42688/icm42688_trigger.c @@ -99,9 +99,7 @@ int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger * data->data_ready_handler = handler; data->data_ready_trigger = trig; - icm42688_lock(dev); - icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); - icm42688_unlock(dev); + res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1); break; default: res = -ENOTSUP; diff --git a/drivers/sensor/iis2dh/Kconfig b/drivers/sensor/iis2dh/Kconfig index 5067b283ead..8e072265b0d 100644 --- a/drivers/sensor/iis2dh/Kconfig +++ b/drivers/sensor/iis2dh/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2DH bool "IIS2DH I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_IIS2DH_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DH),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DH),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2dlpc/Kconfig b/drivers/sensor/iis2dlpc/Kconfig index 6e241af0279..2a7daeb4cc6 100644 --- a/drivers/sensor/iis2dlpc/Kconfig +++ b/drivers/sensor/iis2dlpc/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2DLPC bool "IIS2DLPC I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_IIS2DLPC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DLPC),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2DLPC),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2iclx/Kconfig b/drivers/sensor/iis2iclx/Kconfig index 030fc0bbd96..8266a60b2f9 100644 --- a/drivers/sensor/iis2iclx/Kconfig +++ b/drivers/sensor/iis2iclx/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS2ICLX bool "IIS2ICLX I2C/SPI accelerometer Chip" default y depends on DT_HAS_ST_IIS2ICLX_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2ICLX),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2ICLX),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis2iclx/iis2iclx.c b/drivers/sensor/iis2iclx/iis2iclx.c index 8395f38c6ba..e45203da003 100644 --- a/drivers/sensor/iis2iclx/iis2iclx.c +++ b/drivers/sensor/iis2iclx/iis2iclx.c @@ -214,9 +214,10 @@ static int iis2iclx_sample_fetch_accel(const struct device *dev) static int iis2iclx_sample_fetch_temp(const struct device *dev) { struct iis2iclx_data *data = dev->data; + const struct iis2iclx_config *cfg = dev->config; int16_t buf; - if (iis2iclx_temperature_raw_get(&data->ctx, &buf) < 0) { + if (iis2iclx_temperature_raw_get((stmdev_ctx_t *)&cfg->ctx, &buf) < 0) { LOG_ERR("Failed to read sample"); return -EIO; } diff --git a/drivers/sensor/iis2mdc/Kconfig b/drivers/sensor/iis2mdc/Kconfig index 2215c778c28..1f4817a0a69 100644 --- a/drivers/sensor/iis2mdc/Kconfig +++ b/drivers/sensor/iis2mdc/Kconfig @@ -5,6 +5,7 @@ menuconfig IIS2MDC bool "IIS2MDC Magnetometer" default y depends on DT_HAS_ST_IIS2MDC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2MDC),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_IIS2MDC),spi) select HAS_STMEMSC diff --git a/drivers/sensor/iis3dhhc/Kconfig b/drivers/sensor/iis3dhhc/Kconfig index ecd112aa928..f48e35d81f6 100644 --- a/drivers/sensor/iis3dhhc/Kconfig +++ b/drivers/sensor/iis3dhhc/Kconfig @@ -7,6 +7,7 @@ menuconfig IIS3DHHC bool "IIS3DHHC accelerometer sensor" default y depends on DT_HAS_ST_IIS3DHHC_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select SPI select HAS_STMEMSC select USE_STDC_IIS3DHHC diff --git a/drivers/sensor/ism330dhcx/Kconfig b/drivers/sensor/ism330dhcx/Kconfig index 75eb6d9fec9..f5a6b7d891b 100644 --- a/drivers/sensor/ism330dhcx/Kconfig +++ b/drivers/sensor/ism330dhcx/Kconfig @@ -7,6 +7,7 @@ menuconfig ISM330DHCX bool "ISM330DHCX I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_ISM330DHCX_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_ISM330DHCX),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_ISM330DHCX),spi) select HAS_STMEMSC diff --git a/drivers/sensor/ism330dhcx/ism330dhcx.c b/drivers/sensor/ism330dhcx/ism330dhcx.c index 3dfa7a64137..97d0aaa5f44 100644 --- a/drivers/sensor/ism330dhcx/ism330dhcx.c +++ b/drivers/sensor/ism330dhcx/ism330dhcx.c @@ -473,9 +473,11 @@ static int ism330dhcx_gyro_channel_get(const struct device *dev, enum sensor_cha } #if defined(CONFIG_ISM330DHCX_ENABLE_TEMP) -static void ism330dhcx_gyro_channel_get_temp(struct sensor_value *val, - struct ism330dhcx_data *data) +static void ism330dhcx_gyro_channel_get_temp(const struct device *dev, + struct sensor_value *val) { + struct ism330dhcx_data *data = dev->data; + /* val = temp_sample / 256 + 25 */ val->val1 = data->temp_sample / 256 + 25; val->val2 = (data->temp_sample % 256) * (1000000 / 256); diff --git a/drivers/sensor/lis2de12/CMakeLists.txt b/drivers/sensor/lis2de12/CMakeLists.txt new file mode 100644 index 00000000000..d1ae338bc83 --- /dev/null +++ b/drivers/sensor/lis2de12/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver +# +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lis2de12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DE12_TRIGGER lis2de12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2de12/Kconfig b/drivers/sensor/lis2de12/Kconfig new file mode 100644 index 00000000000..fe8402ce6e9 --- /dev/null +++ b/drivers/sensor/lis2de12/Kconfig @@ -0,0 +1,30 @@ +# ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DE12 + bool "LIS2DE12 I2C/SPI smartxl Chip" + default y + depends on DT_HAS_ST_LIS2DE12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DE12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DE12 + help + Enable driver for LIS2DE12 smartxl sensor. + +if LIS2DE12 + +module = LIS2DE12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +config LIS2DE12_ENABLE_TEMP + bool "Die temperature sensor" + help + Enable/disable die temperature sensor + +endif # LIS2DE12 diff --git a/drivers/sensor/lis2de12/lis2de12.c b/drivers/sensor/lis2de12/lis2de12.c new file mode 100644 index 00000000000..9cceccdeb20 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.c @@ -0,0 +1,471 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_REGISTER(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lis2de12_odr_map[10] = { 0, 1, 10, 25, 50, 100, 200, 400, 1620, 5376}; + +static int lis2de12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_odr_map); i++) { + if (freq <= lis2de12_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} + +typedef struct { + uint16_t fs; + uint32_t gain; /* Accel sensor sensitivity in ug/LSB */ +} fs_map; + +static const fs_map lis2de12_accel_fs_map[] = { + {2, 15600}, + {4, 31200}, + {8, 62500}, + {16, 187500}, + }; + +static int lis2de12_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2de12_accel_fs_map); i++) { + if (range == lis2de12_accel_fs_map[i].fs) { + return i; + } + } + + return -EINVAL; +} + +static int lis2de12_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_full_scale_set(ctx, fs) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lis2de12_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_data_rate_set(ctx, odr) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lis2de12_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lis2de12_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lis2de12_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lis2de12_data *data = dev->data; + + fs = lis2de12_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lis2de12_accel_fs_map[fs].gain; + return 0; +} + +static int lis2de12_accel_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lis2de12_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lis2de12_accel_odr_set(dev, val->val1); + default: + LOG_WRN("Accel attribute %d not supported.", attr); + return -ENOTSUP; + } +} + +static int lis2de12_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lis2de12_accel_config(dev, chan, attr, val); + default: + LOG_WRN("attribute %d not supported on this channel.", chan); + return -ENOTSUP; + } +} + +static int lis2de12_sample_fetch_accel(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_acceleration_raw_get(ctx, data->acc) < 0) { + LOG_ERR("Failed to read sample"); + return -EIO; + } + + return 0; +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static int lis2de12_sample_fetch_temp(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *data = dev->data; + + if (lis2de12_temperature_raw_get(ctx, &data->temp_sample) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + return 0; +} +#endif + +static int lis2de12_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12_sample_fetch_accel(dev); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_sample_fetch_temp(dev); + break; +#endif + case SENSOR_CHAN_ALL: + lis2de12_sample_fetch_accel(dev); +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_sample_fetch_temp(dev); +#endif + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2de12_accel_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)(raw_val / 256) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lis2de12_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2de12_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2de12_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2de12_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lis2de12_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2de12_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lis2de12_data *data) +{ + return lis2de12_accel_get_channel(chan, val, data, data->acc_gain); +} + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) +static void lis2de12_temp_channel_get(struct sensor_value *val, struct lis2de12_data *data) +{ + int64_t micro_c; + + /* convert units to micro Celsius. Raw temperature samples are + * expressed in 256 LSB/deg_C units. And LSB output is 0 at 25 C. + */ + micro_c = ((int64_t)data->temp_sample * 1000000) / 256; + + val->val1 = micro_c / 1000000 + 25; + val->val2 = micro_c % 1000000; +} +#endif + +static int lis2de12_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2de12_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12_accel_channel_get(chan, val, data); + break; +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + case SENSOR_CHAN_DIE_TEMP: + lis2de12_temp_channel_get(val, data); + break; +#endif + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lis2de12_driver_api = { + .attr_set = lis2de12_attr_set, +#if CONFIG_LIS2DE12_TRIGGER + .trigger_set = lis2de12_trigger_set, +#endif + .sample_fetch = lis2de12_sample_fetch, + .channel_get = lis2de12_channel_get, +}; + +static int lis2de12_init_chip(const struct device *dev) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2de12_data *lis2de12 = dev->data; + uint8_t chip_id; + uint8_t odr, fs; + + if (lis2de12_device_id_get(ctx, &chip_id) < 0) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + if (chip_id != LIS2DE12_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id); + + if (lis2de12_block_data_update_set(ctx, 1) < 0) { + LOG_ERR("failed to set BDU"); + return -EIO; + } + + /* set FS from DT */ + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lis2de12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lis2de12->acc_gain = lis2de12_accel_fs_map[fs].gain; + + /* set odr from DT (the only way to go in high performance) */ + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lis2de12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + +#if defined(CONFIG_LIS2DE12_ENABLE_TEMP) + lis2de12_temperature_meas_set(ctx, LIS2DE12_TEMP_ENABLE); +#endif + + return 0; +} + +static int lis2de12_init(const struct device *dev) +{ +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct lis2de12_config *cfg = dev->config; +#endif + struct lis2de12_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lis2de12_init_chip(dev) < 0) { + LOG_ERR("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LIS2DE12_TRIGGER + if (cfg->trig_enabled) { + if (lis2de12_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} + +/* + * Device creation macro, shared by LIS2DE12_DEFINE_SPI() and + * LIS2DE12_DEFINE_I2C(). + */ + +#define LIS2DE12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lis2de12_init, \ + NULL, \ + &lis2de12_data_##inst, \ + &lis2de12_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &lis2de12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DE12_TRIGGER +#define LIS2DE12_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ + .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed) +#else +#define LIS2DE12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DE12_TRIGGER */ + +#define LIS2DE12_SPI_OP (SPI_WORD_SET(8) | \ + SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA) \ + +#define LIS2DE12_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DE12_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define LIS2DE12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LIS2DE12_SPI_OP, 0), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DE12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C_INCR(&lis2de12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LIS2DE12_CONFIG_COMMON(inst) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DE12_DEFINE(inst) \ + static struct lis2de12_data lis2de12_data_##inst; \ + static const struct lis2de12_config lis2de12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LIS2DE12_CONFIG_SPI(inst)), \ + (LIS2DE12_CONFIG_I2C(inst))); \ + LIS2DE12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DE12_DEFINE) diff --git a/drivers/sensor/lis2de12/lis2de12.h b/drivers/sensor/lis2de12/lis2de12.h new file mode 100644 index 00000000000..575fd50f962 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12.h @@ -0,0 +1,95 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ + +#include +#include +#include +#include +#include +#include "lis2de12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LIS2DE12_EN_BIT 0x01 +#define LIS2DE12_DIS_BIT 0x00 + +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lis2de12_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif + } stmemsc_cfg; + uint8_t accel_pm; + uint8_t accel_odr; + uint8_t accel_range; + uint8_t drdy_pulsed; +#ifdef CONFIG_LIS2DE12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + bool trig_enabled; +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +struct lis2de12_data { + const struct device *dev; + int16_t acc[3]; + int16_t temp_sample; + uint32_t acc_gain; + uint8_t accel_freq; + uint8_t accel_fs; + +#ifdef CONFIG_LIS2DE12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DE12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LIS2DE12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DE12_TRIGGER +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2de12_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DE12_LIS2DE12_H_ */ diff --git a/drivers/sensor/lis2de12/lis2de12_trigger.c b/drivers/sensor/lis2de12/lis2de12_trigger.c new file mode 100644 index 00000000000..feee823bb91 --- /dev/null +++ b/drivers/sensor/lis2de12/lis2de12_trigger.c @@ -0,0 +1,195 @@ +/* ST Microelectronics LIS2DE12 3-axis accelerometer sensor driver + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2de12.pdf + */ + +#define DT_DRV_COMPAT st_lis2de12 + +#include +#include +#include +#include + +#include "lis2de12.h" + +LOG_MODULE_DECLARE(LIS2DE12, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lis2de12_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lis2de12_enable_xl_int(const struct device *dev, int enable) +{ + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_ctrl_reg3_t val = {0}; + int ret; + + if (enable) { + int16_t xl_data[3]; + + /* dummy read: re-trigger interrupt */ + lis2de12_acceleration_raw_get(ctx, xl_data); + } + + /* set interrupt */ + ret = lis2de12_pin_int1_config_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.i1_zyxda = 1; + + return lis2de12_pin_int1_config_set(ctx, &val); +} + +/** + * lis2de12_trigger_set - link external trigger to event data ready + */ +int lis2de12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lis2de12_config *cfg = dev->config; + struct lis2de12_data *lis2de12 = dev->data; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + switch (trig->chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2de12->handler_drdy_acc = handler; + lis2de12->trig_drdy_acc = trig; + if (handler) { + return lis2de12_enable_xl_int(dev, LIS2DE12_EN_BIT); + } + + return lis2de12_enable_xl_int(dev, LIS2DE12_DIS_BIT); + + default: + return -ENOTSUP; + } + +} + +/** + * lis2de12_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lis2de12_handle_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2de12_status_reg_t status; + + while (1) { + if (lis2de12_status_get(ctx, &status) < 0) { + LOG_ERR("failed reading status reg"); + return; + } + + if (status.zyxda == 0) { + /* spurious interrupt */ + break; + } + + if ((status.zyxda) && (lis2de12->handler_drdy_acc != NULL)) { + lis2de12->handler_drdy_acc(dev, lis2de12->trig_drdy_acc); + } + } + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lis2de12_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(cb, struct lis2de12_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, GPIO_INT_DISABLE); + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_give(&lis2de12->gpio_sem); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lis2de12->work); +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LIS2DE12_TRIGGER_OWN_THREAD +static void lis2de12_thread(struct lis2de12_data *lis2de12) +{ + while (1) { + k_sem_take(&lis2de12->gpio_sem, K_FOREVER); + lis2de12_handle_interrupt(lis2de12->dev); + } +} +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD +static void lis2de12_work_cb(struct k_work *work) +{ + struct lis2de12_data *lis2de12 = + CONTAINER_OF(work, struct lis2de12_data, work); + + lis2de12_handle_interrupt(lis2de12->dev); +} +#endif /* CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD */ + +int lis2de12_init_interrupt(const struct device *dev) +{ + struct lis2de12_data *lis2de12 = dev->data; + const struct lis2de12_config *cfg = dev->config; + int ret; + + lis2de12->drdy_gpio = (struct gpio_dt_spec *)&cfg->int1_gpio; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(lis2de12->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device (%p)", + lis2de12->drdy_gpio); + return -EINVAL; + } + +#if defined(CONFIG_LIS2DE12_TRIGGER_OWN_THREAD) + k_sem_init(&lis2de12->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lis2de12->thread, lis2de12->thread_stack, + CONFIG_LIS2DE12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2de12_thread, lis2de12, + NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DE12_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lis2de12->thread, dev->name); +#elif defined(CONFIG_LIS2DE12_TRIGGER_GLOBAL_THREAD) + lis2de12->work.handler = lis2de12_work_cb; +#endif /* CONFIG_LIS2DE12_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(lis2de12->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio: %d", ret); + return ret; + } + + gpio_init_callback(&lis2de12->gpio_cb, + lis2de12_gpio_callback, + BIT(lis2de12->drdy_gpio->pin)); + + if (gpio_add_callback(lis2de12->drdy_gpio->port, &lis2de12->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback"); + return -EIO; + } + + return gpio_pin_interrupt_configure_dt(lis2de12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/drivers/sensor/lis2ds12/Kconfig b/drivers/sensor/lis2ds12/Kconfig index 14b063bd8ec..cc8331bdf5e 100644 --- a/drivers/sensor/lis2ds12/Kconfig +++ b/drivers/sensor/lis2ds12/Kconfig @@ -7,6 +7,7 @@ menuconfig LIS2DS12 bool "LIS2DS12 I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_LIS2DS12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DS12),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DS12),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2du12/CMakeLists.txt b/drivers/sensor/lis2du12/CMakeLists.txt new file mode 100644 index 00000000000..378cc8f7f0d --- /dev/null +++ b/drivers/sensor/lis2du12/CMakeLists.txt @@ -0,0 +1,12 @@ +# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver +# +# Copyright (c) 2023 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lis2du12.c) +zephyr_library_sources_ifdef(CONFIG_LIS2DU12_TRIGGER lis2du12_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lis2du12/Kconfig b/drivers/sensor/lis2du12/Kconfig new file mode 100644 index 00000000000..4c00b940ef1 --- /dev/null +++ b/drivers/sensor/lis2du12/Kconfig @@ -0,0 +1,25 @@ +# ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LIS2DU12 + bool "LIS2DU12 I2C/SPI smartxl Chip" + default y + depends on DT_HAS_ST_LIS2DU12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DU12),spi) + select HAS_STMEMSC + select USE_STDC_LIS2DU12 + help + Enable driver for LIS2DU12 smartxl sensor. + +if LIS2DU12 + +module = LIS2DU12 +thread_priority = 10 +thread_stack_size = 1024 +source "drivers/sensor/Kconfig.trigger_template" + +endif # LIS2DU12 diff --git a/drivers/sensor/lis2du12/lis2du12.c b/drivers/sensor/lis2du12/lis2du12.c new file mode 100644 index 00000000000..bd5d8b2faf0 --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12.c @@ -0,0 +1,471 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#define DT_DRV_COMPAT st_lis2du12 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis2du12.h" + +LOG_MODULE_REGISTER(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL); + +static const float lis2du12_odr_map[14] = { + 0.0f, 1.6f, 3.0f, 6.0f, 6.0f, 12.5f, 25.0f, + 50.0f, 100.0f, 200.0f, 400.0f, 800.0f, 0.0f, 0.0f}; + +static int lis2du12_freq_to_odr_val(const struct device *dev, uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2du12_odr_map); i++) { + if (freq <= lis2du12_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static const uint16_t lis2du12_accel_fs_map[] = {2, 4, 8, 16}; + +static int lis2du12_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lis2du12_accel_fs_map); i++) { + if (range == lis2du12_accel_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} + +static inline int lis2du12_reboot(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2du12_status_t status; + uint8_t tries = 10; + + if (lis2du12_init_set(ctx, LIS2DU12_RESET) < 0) { + return -EIO; + } + + do { + if (!--tries) { + LOG_ERR("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(50); + + if (lis2du12_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset != 0); + + if (lis2du12_init_set(ctx, LIS2DU12_DRV_RDY) < 0) { + return -EIO; + } + + return 0; +} + +static int lis2du12_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_md_t mode; + + if (lis2du12_mode_get(ctx, &mode) < 0) { + return -EIO; + } + + mode.fs = fs; + if (lis2du12_mode_set(ctx, &mode) < 0) { + return -EIO; + } + + data->accel_fs = fs; + + return 0; +} + +static int lis2du12_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_md_t mode; + + if (lis2du12_mode_get(ctx, &mode) < 0) { + return -EIO; + } + + mode.odr = odr; + if (lis2du12_mode_set(ctx, &mode) < 0) { + return -EIO; + } + + data->accel_freq = odr; + + return 0; +} + +static int lis2du12_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lis2du12_freq_to_odr_val(dev, freq); + if (odr < 0) { + return odr; + } + + if (lis2du12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} + +static int lis2du12_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lis2du12_data *data = dev->data; + + fs = lis2du12_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lis2du12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer full-scale"); + return -EIO; + } + + data->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + return 0; +} + +static int lis2du12_accel_config(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (attr) { + case SENSOR_ATTR_FULL_SCALE: + return lis2du12_accel_range_set(dev, sensor_ms2_to_g(val)); + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lis2du12_accel_odr_set(dev, val->val1); + default: + LOG_WRN("Accel attribute %d not supported.", attr); + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_attr_set(const struct device *dev, + enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lis2du12_accel_config(dev, chan, attr, val); + default: + LOG_WRN("attribute %d not supported on this channel.", chan); + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_sample_fetch_accel(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *data = dev->data; + lis2du12_data_t xl_data; + lis2du12_md_t md; + + md.fs = cfg->accel_range; + if (lis2du12_data_get(ctx, &md, &xl_data) < 0) { + LOG_ERR("Failed to read sample"); + return -EIO; + } + + data->acc[0] = xl_data.xl.raw[0]; + data->acc[1] = xl_data.xl.raw[1]; + data->acc[2] = xl_data.xl.raw[2]; + + return 0; +} + +static int lis2du12_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12_sample_fetch_accel(dev); + break; + case SENSOR_CHAN_ALL: + lis2du12_sample_fetch_accel(dev); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lis2du12_accel_convert(struct sensor_value *val, int raw_val, + uint32_t sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)(raw_val) * sensitivity * SENSOR_G_DOUBLE; + val->val1 = (int32_t)(dval / 1000000); + val->val2 = (int32_t)(dval % 1000000); + +} + +static inline int lis2du12_accel_get_channel(enum sensor_channel chan, + struct sensor_value *val, + struct lis2du12_data *data, + uint32_t sensitivity) +{ + uint8_t i; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lis2du12_accel_convert(val, data->acc[0], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lis2du12_accel_convert(val, data->acc[1], sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lis2du12_accel_convert(val, data->acc[2], sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + for (i = 0; i < 3; i++) { + lis2du12_accel_convert(val++, data->acc[i], sensitivity); + } + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lis2du12_accel_channel_get(enum sensor_channel chan, + struct sensor_value *val, + struct lis2du12_data *data) +{ + return lis2du12_accel_get_channel(chan, val, data, data->acc_gain); +} + +static int lis2du12_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct lis2du12_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12_accel_channel_get(chan, val, data); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api lis2du12_driver_api = { + .attr_set = lis2du12_attr_set, +#if CONFIG_LIS2DU12_TRIGGER + .trigger_set = lis2du12_trigger_set, +#endif + .sample_fetch = lis2du12_sample_fetch, + .channel_get = lis2du12_channel_get, +}; + +static int lis2du12_init_chip(const struct device *dev) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + struct lis2du12_data *lis2du12 = dev->data; + lis2du12_id_t chip_id; + uint8_t odr, fs; + + if (lis2du12_id_get(ctx, &chip_id) < 0) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + LOG_INF("chip id 0x%x", chip_id.whoami); + + if (chip_id.whoami != LIS2DU12_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id.whoami); + return -EIO; + } + + /* reboot device */ + if (lis2du12_reboot(dev) < 0) { + return -EIO; + } + + /* set FS from DT */ + fs = cfg->accel_range; + LOG_DBG("accel range is %d", fs); + if (lis2du12_accel_set_fs_raw(dev, fs) < 0) { + LOG_ERR("failed to set accelerometer range %d", fs); + return -EIO; + } + lis2du12->acc_gain = lis2du12_accel_fs_map[fs] * GAIN_UNIT_XL / 2; + + /* set odr from DT (the only way to go in high performance) */ + odr = cfg->accel_odr; + LOG_DBG("accel odr is %d", odr); + if (lis2du12_accel_set_odr_raw(dev, odr) < 0) { + LOG_ERR("failed to set accelerometer odr %d", odr); + return -EIO; + } + + return 0; +} + +static int lis2du12_init(const struct device *dev) +{ +#ifdef CONFIG_LIS2DU12_TRIGGER + const struct lis2du12_config *cfg = dev->config; +#endif + struct lis2du12_data *data = dev->data; + + LOG_INF("Initialize device %s", dev->name); + data->dev = dev; + + if (lis2du12_init_chip(dev) < 0) { + LOG_ERR("failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_LIS2DU12_TRIGGER + if (cfg->trig_enabled) { + if (lis2du12_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} + +/* + * Device creation macro, shared by LIS2DU12_DEFINE_SPI() and + * LIS2DU12_DEFINE_I2C(). + */ + +#define LIS2DU12_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, \ + lis2du12_init, \ + NULL, \ + &lis2du12_data_##inst, \ + &lis2du12_config_##inst, \ + POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, \ + &lis2du12_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#ifdef CONFIG_LIS2DU12_TRIGGER +#define LIS2DU12_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ + .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ + .drdy_pin = DT_INST_PROP(inst, drdy_pin) +#else +#define LIS2DU12_CFG_IRQ(inst) +#endif /* CONFIG_LIS2DU12_TRIGGER */ + +#define LIS2DU12_SPI_OP (SPI_WORD_SET(8) | \ + SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | \ + SPI_MODE_CPHA) \ + +#define LIS2DU12_CONFIG_COMMON(inst) \ + .accel_odr = DT_INST_PROP(inst, accel_odr), \ + .accel_range = DT_INST_PROP(inst, accel_range), \ + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LIS2DU12_CFG_IRQ(inst))) + +/* + * Instantiation macros used when a device is on a SPI bus. + */ + +#define LIS2DU12_CONFIG_SPI(inst) \ + { \ + STMEMSC_CTX_SPI(&lis2du12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, \ + LIS2DU12_SPI_OP, \ + 0), \ + }, \ + LIS2DU12_CONFIG_COMMON(inst) \ + } + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LIS2DU12_CONFIG_I2C(inst) \ + { \ + STMEMSC_CTX_I2C(&lis2du12_config_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LIS2DU12_CONFIG_COMMON(inst) \ + } + +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LIS2DU12_DEFINE(inst) \ + static struct lis2du12_data lis2du12_data_##inst; \ + static const struct lis2du12_config lis2du12_config_##inst = \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LIS2DU12_CONFIG_SPI(inst)), \ + (LIS2DU12_CONFIG_I2C(inst))); \ + LIS2DU12_DEVICE_INIT(inst) + +DT_INST_FOREACH_STATUS_OKAY(LIS2DU12_DEFINE) diff --git a/drivers/sensor/lis2du12/lis2du12.h b/drivers/sensor/lis2du12/lis2du12.h new file mode 100644 index 00000000000..f05d0511b7b --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12.h @@ -0,0 +1,98 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ +#define ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ + +#include +#include +#include +#include +#include +#include "lis2du12_reg.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LIS2DU12_EN_BIT 0x01 +#define LIS2DU12_DIS_BIT 0x00 + +/* Accel sensor sensitivity grain is 61 ug/LSB */ +#define GAIN_UNIT_XL (61LL) + +#define SENSOR_G_DOUBLE (SENSOR_G / 1000000.0) + +struct lis2du12_config { + stmdev_ctx_t ctx; + union { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + const struct i2c_dt_spec i2c; +#endif +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + const struct spi_dt_spec spi; +#endif + } stmemsc_cfg; + uint8_t accel_pm; + uint8_t accel_odr; + uint8_t accel_range; + uint8_t drdy_pulsed; +#ifdef CONFIG_LIS2DU12_TRIGGER + const struct gpio_dt_spec int1_gpio; + const struct gpio_dt_spec int2_gpio; + uint8_t drdy_pin; + bool trig_enabled; +#endif /* CONFIG_LIS2DU12_TRIGGER */ +}; + +union samples { + uint8_t raw[6]; + struct { + int16_t axis[3]; + }; +} __aligned(2); + +struct lis2du12_data { + const struct device *dev; + int16_t acc[3]; + uint32_t acc_gain; + uint16_t accel_freq; + uint8_t accel_fs; + +#ifdef CONFIG_LIS2DU12_TRIGGER + struct gpio_dt_spec *drdy_gpio; + + struct gpio_callback gpio_cb; + sensor_trigger_handler_t handler_drdy_acc; + const struct sensor_trigger *trig_drdy_acc; + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LIS2DU12_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif +#endif /* CONFIG_LIS2DU12_TRIGGER */ +}; + +#ifdef CONFIG_LIS2DU12_TRIGGER +int lis2du12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lis2du12_init_interrupt(const struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DU12_LIS2DU12_H_ */ diff --git a/drivers/sensor/lis2du12/lis2du12_trigger.c b/drivers/sensor/lis2du12/lis2du12_trigger.c new file mode 100644 index 00000000000..d2edbad3e2b --- /dev/null +++ b/drivers/sensor/lis2du12/lis2du12_trigger.c @@ -0,0 +1,215 @@ +/* ST Microelectronics LIS2DU12 3-axis accelerometer sensor driver + * + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lis2du12.pdf + */ + +#define DT_DRV_COMPAT st_lis2du12 + +#include +#include +#include +#include + +#include "lis2du12.h" + +LOG_MODULE_DECLARE(LIS2DU12, CONFIG_SENSOR_LOG_LEVEL); + +/** + * lis2du12_enable_xl_int - XL enable selected int pin to generate interrupt + */ +static int lis2du12_enable_xl_int(const struct device *dev, int enable) +{ + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + if (enable) { + lis2du12_md_t md; + lis2du12_data_t xl_data; + + /* dummy read: re-trigger interrupt */ + md.fs = cfg->accel_range; + lis2du12_data_get(ctx, &md, &xl_data); + } + + /* set interrupt */ + if (cfg->drdy_pin == 1) { + lis2du12_pin_int_route_t val; + + ret = lis2du12_pin_int1_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int1_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lis2du12_pin_int1_route_set(ctx, &val); + } else { + lis2du12_pin_int_route_t val; + + ret = lis2du12_pin_int2_route_get(ctx, &val); + if (ret < 0) { + LOG_ERR("pint_int2_route_get error"); + return ret; + } + + val.drdy_xl = 1; + + ret = lis2du12_pin_int2_route_set(ctx, &val); + } + + return ret; +} + +/** + * lis2du12_trigger_set - link external trigger to event data ready + */ +int lis2du12_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lis2du12_config *cfg = dev->config; + struct lis2du12_data *lis2du12 = dev->data; + + if (!cfg->trig_enabled) { + LOG_ERR("trigger_set op not supported"); + return -ENOTSUP; + } + + switch (trig->chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lis2du12->handler_drdy_acc = handler; + lis2du12->trig_drdy_acc = trig; + if (handler) { + return lis2du12_enable_xl_int(dev, LIS2DU12_EN_BIT); + } + + return lis2du12_enable_xl_int(dev, LIS2DU12_DIS_BIT); + + default: + return -ENOTSUP; + } + +} + +/** + * lis2du12_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +static void lis2du12_handle_interrupt(const struct device *dev) +{ + struct lis2du12_data *lis2du12 = dev->data; + const struct lis2du12_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lis2du12_status_t status; + + while (1) { + if (lis2du12_status_get(ctx, &status) < 0) { + LOG_ERR("failed reading status reg"); + return; + } + + if (status.drdy_xl == 0) { + break; + } + + if ((status.drdy_xl) && (lis2du12->handler_drdy_acc != NULL)) { + lis2du12->handler_drdy_acc(dev, lis2du12->trig_drdy_acc); + } + } + + gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} + +static void lis2du12_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lis2du12_data *lis2du12 = + CONTAINER_OF(cb, struct lis2du12_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, GPIO_INT_DISABLE); + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + k_sem_give(&lis2du12->gpio_sem); +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lis2du12->work); +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_LIS2DU12_TRIGGER_OWN_THREAD +static void lis2du12_thread(struct lis2du12_data *lis2du12) +{ + while (1) { + k_sem_take(&lis2du12->gpio_sem, K_FOREVER); + lis2du12_handle_interrupt(lis2du12->dev); + } +} +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD +static void lis2du12_work_cb(struct k_work *work) +{ + struct lis2du12_data *lis2du12 = + CONTAINER_OF(work, struct lis2du12_data, work); + + lis2du12_handle_interrupt(lis2du12->dev); +} +#endif /* CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD */ + +int lis2du12_init_interrupt(const struct device *dev) +{ + struct lis2du12_data *lis2du12 = dev->data; + const struct lis2du12_config *cfg = dev->config; + int ret; + + lis2du12->drdy_gpio = (cfg->drdy_pin == 1) ? + (struct gpio_dt_spec *)&cfg->int1_gpio : + (struct gpio_dt_spec *)&cfg->int2_gpio; + + /* setup data ready gpio interrupt (INT1 or INT2) */ + if (!gpio_is_ready_dt(lis2du12->drdy_gpio)) { + LOG_ERR("Cannot get pointer to drdy_gpio device (%p)", + lis2du12->drdy_gpio); + return -EINVAL; + } + +#if defined(CONFIG_LIS2DU12_TRIGGER_OWN_THREAD) + k_sem_init(&lis2du12->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lis2du12->thread, lis2du12->thread_stack, + CONFIG_LIS2DU12_THREAD_STACK_SIZE, + (k_thread_entry_t)lis2du12_thread, lis2du12, + NULL, NULL, K_PRIO_COOP(CONFIG_LIS2DU12_THREAD_PRIORITY), + 0, K_NO_WAIT); + k_thread_name_set(&lis2du12->thread, dev->name); +#elif defined(CONFIG_LIS2DU12_TRIGGER_GLOBAL_THREAD) + lis2du12->work.handler = lis2du12_work_cb; +#endif /* CONFIG_LIS2DU12_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure_dt(lis2du12->drdy_gpio, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio: %d", ret); + return ret; + } + + gpio_init_callback(&lis2du12->gpio_cb, + lis2du12_gpio_callback, + BIT(lis2du12->drdy_gpio->pin)); + + if (gpio_add_callback(lis2du12->drdy_gpio->port, &lis2du12->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback"); + return -EIO; + } + + return gpio_pin_interrupt_configure_dt(lis2du12->drdy_gpio, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/drivers/sensor/lis2dw12/Kconfig b/drivers/sensor/lis2dw12/Kconfig index 9e34bfaea84..2241505902f 100644 --- a/drivers/sensor/lis2dw12/Kconfig +++ b/drivers/sensor/lis2dw12/Kconfig @@ -7,6 +7,7 @@ menuconfig LIS2DW12 bool "LIS2DW12 I2C/SPI accelerometer sensor driver" default y depends on DT_HAS_ST_LIS2DW12_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DW12),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2DW12),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lis2mdl/Kconfig b/drivers/sensor/lis2mdl/Kconfig index 6970a60555d..637b883b26e 100644 --- a/drivers/sensor/lis2mdl/Kconfig +++ b/drivers/sensor/lis2mdl/Kconfig @@ -5,6 +5,7 @@ menuconfig LIS2MDL bool "LIS2MDL Magnetometer" default y depends on DT_HAS_ST_LIS2MDL_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2MDL),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LIS2MDL),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lps22df/CMakeLists.txt b/drivers/sensor/lps22df/CMakeLists.txt deleted file mode 100644 index bb5194cf9ba..00000000000 --- a/drivers/sensor/lps22df/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# ST Microelectronics LPS22DF pressure and temperature sensor -# -# Copyright (c) 2023 STMicroelectronics -# -# SPDX-License-Identifier: Apache-2.0 -# -zephyr_library() - -zephyr_library_sources(lps22df.c) -zephyr_library_sources_ifdef(CONFIG_LPS22DF_TRIGGER lps22df_trigger.c) - -zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lps22df/Kconfig b/drivers/sensor/lps22df/Kconfig deleted file mode 100644 index 843c6e755c4..00000000000 --- a/drivers/sensor/lps22df/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# ST Microelectronics LPS22DF pressure and temperature sensor - -# Copyright (c) 2023 STMicroelectronics -# SPDX-License-Identifier: Apache-2.0 - -menuconfig LPS22DF - bool "LPS22DF pressure and temperature" - default y - depends on DT_HAS_ST_LPS22DF_ENABLED - select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) - select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) - select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),spi) - select HAS_STMEMSC - select USE_STDC_LPS22DF - help - Enable driver for LPS22DF I2C-based pressure and temperature - sensor. - -if LPS22DF - -choice LPS22DF_TRIGGER_MODE - prompt "Trigger mode" - default LPS22DF_TRIGGER_GLOBAL_THREAD - help - Specify the type of triggering to be used by the driver. - -config LPS22DF_TRIGGER_NONE - bool "No trigger" - -config LPS22DF_TRIGGER_GLOBAL_THREAD - bool "Use global thread" - depends on GPIO - select LPS22DF_TRIGGER - -config LPS22DF_TRIGGER_OWN_THREAD - bool "Use own thread" - depends on GPIO - select LPS22DF_TRIGGER - -endchoice # LPS22DF_TRIGGER_MODE - -config LPS22DF_TRIGGER - bool - -config LPS22DF_THREAD_PRIORITY - int "Thread priority" - depends on LPS22DF_TRIGGER_OWN_THREAD - default 10 - help - Priority of thread used by the driver to handle interrupts. - -config LPS22DF_THREAD_STACK_SIZE - int "Thread stack size" - depends on LPS22DF_TRIGGER_OWN_THREAD - default 1024 - help - Stack size of thread used by the driver to handle interrupts. - -endif # LPS22DF diff --git a/drivers/sensor/lps22df/lps22df.c b/drivers/sensor/lps22df/lps22df.c deleted file mode 100644 index a74ef75c245..00000000000 --- a/drivers/sensor/lps22df/lps22df.c +++ /dev/null @@ -1,338 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#define DT_DRV_COMPAT st_lps22df - -#include -#include -#include -#include -#include -#include -#include - -#include "lps22df.h" - -#define LPS22DF_SWRESET_WAIT_TIME 50 - -LOG_MODULE_REGISTER(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); - -static inline int lps22df_set_odr_raw(const struct device *dev, uint8_t odr) -{ - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_md_t md; - - md.odr = odr; - md.avg = cfg->avg; - md.lpf = cfg->lpf; - - return lps22df_mode_set(ctx, &md); -} - -static int lps22df_sample_fetch(const struct device *dev, - enum sensor_channel chan) -{ - struct lps22df_data *data = dev->data; - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_data_t raw_data; - - __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); - - if (lps22df_data_get(ctx, &raw_data) < 0) { - LOG_DBG("Failed to read sample"); - return -EIO; - } - - data->sample_press = raw_data.pressure.raw; - data->sample_temp = raw_data.heat.raw; - - return 0; -} - -static inline void lps22df_press_convert(struct sensor_value *val, - int32_t raw_val) -{ - int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */ - - /* Pressure sensitivity is 4096 LSB/hPa */ - /* Also convert hPa into kPa */ - - val->val1 = press_tmp / 40960; - - /* For the decimal part use (3125 / 128) as a factor instead of - * (1000000 / 40960) to avoid int32 overflow - */ - val->val2 = (press_tmp % 40960) * 3125 / 128; -} - -static inline void lps22df_temp_convert(struct sensor_value *val, - int16_t raw_val) -{ - /* Temperature sensitivity is 100 LSB/deg C */ - val->val1 = raw_val / 100; - val->val2 = ((int32_t)raw_val % 100) * 10000; -} - -static int lps22df_channel_get(const struct device *dev, - enum sensor_channel chan, - struct sensor_value *val) -{ - struct lps22df_data *data = dev->data; - - if (chan == SENSOR_CHAN_PRESS) { - lps22df_press_convert(val, data->sample_press); - } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { - lps22df_temp_convert(val, data->sample_temp); - } else { - return -ENOTSUP; - } - - return 0; -} - -static const uint16_t lps22df_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; - -static int lps22df_odr_set(const struct device *dev, uint16_t freq) -{ - int odr; - - for (odr = 0; odr < ARRAY_SIZE(lps22df_map); odr++) { - if (freq == lps22df_map[odr]) { - break; - } - } - - if (odr == ARRAY_SIZE(lps22df_map)) { - LOG_DBG("bad frequency"); - return -EINVAL; - } - - if (lps22df_set_odr_raw(dev, odr) < 0) { - LOG_DBG("failed to set sampling rate"); - return -EIO; - } - - return 0; -} - -static int lps22df_attr_set(const struct device *dev, - enum sensor_channel chan, - enum sensor_attribute attr, - const struct sensor_value *val) -{ - if (chan != SENSOR_CHAN_ALL) { - LOG_WRN("attr_set() not supported on this channel."); - return -ENOTSUP; - } - - switch (attr) { - case SENSOR_ATTR_SAMPLING_FREQUENCY: - return lps22df_odr_set(dev, val->val1); - default: - LOG_DBG("operation not supported."); - return -ENOTSUP; - } - - return 0; -} - -static const struct sensor_driver_api lps22df_driver_api = { - .attr_set = lps22df_attr_set, - .sample_fetch = lps22df_sample_fetch, - .channel_get = lps22df_channel_get, -#if CONFIG_LPS22DF_TRIGGER - .trigger_set = lps22df_trigger_set, -#endif -}; - -static int lps22df_init_chip(const struct device *dev) -{ - const struct lps22df_config * const cfg = dev->config; - __maybe_unused struct lps22df_data *data = dev->data; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_id_t id; - lps22df_stat_t status; - uint8_t tries = 10; - int ret; - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - if (cfg->i3c.bus != NULL) { - /* - * Need to grab the pointer to the I3C device descriptor - * before we can talk to the sensor. - */ - data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); - if (data->i3c_dev == NULL) { - LOG_ERR("Cannot find I3C device descriptor"); - return -ENODEV; - } - } -#endif - - if (lps22df_id_get(ctx, &id) < 0) { - LOG_ERR("%s: Not able to read dev id", dev->name); - return -EIO; - } - - if (id.whoami != LPS22DF_ID) { - LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); - return -EIO; - } - - LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); - - /* Restore default configuration */ - if (lps22df_init_set(ctx, LPS22DF_RESET) < 0) { - LOG_ERR("%s: Not able to reset device", dev->name); - return -EIO; - } - - do { - if (!--tries) { - LOG_DBG("sw reset timed out"); - return -ETIMEDOUT; - } - k_usleep(LPS22DF_SWRESET_WAIT_TIME); - - if (lps22df_status_get(ctx, &status) < 0) { - return -EIO; - } - } while (status.sw_reset); - - /* Set bdu and if_inc recommended for driver usage */ - if (lps22df_init_set(ctx, LPS22DF_DRV_RDY) < 0) { - LOG_ERR("%s: Not able to set device to ready state", dev->name); - return -EIO; - } - - if (ON_I3C_BUS(cfg)) { - lps22df_bus_mode_t bus_mode; - - /* Select bus interface */ - bus_mode.filter = LPS22DF_AUTO; - bus_mode.interface = LPS22DF_SEL_BY_HW; - lps22df_bus_mode_set(ctx, &bus_mode); - - } - - /* set sensor default odr */ - LOG_DBG("%s: odr: %d", dev->name, cfg->odr); - ret = lps22df_set_odr_raw(dev, cfg->odr); - if (ret < 0) { - LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); - return ret; - } - - return 0; -} - -static int lps22df_init(const struct device *dev) -{ - if (lps22df_init_chip(dev) < 0) { - LOG_DBG("Failed to initialize chip"); - return -EIO; - } - -#ifdef CONFIG_LPS22DF_TRIGGER - if (lps22df_init_interrupt(dev) < 0) { - LOG_ERR("Failed to initialize interrupt."); - return -EIO; - } -#endif - - return 0; -} - -/* - * Instantiation macros used when a device is on a SPI bus. - */ - -#ifdef CONFIG_LPS22DF_TRIGGER -#define LPS22DF_CFG_IRQ(inst) \ - .gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios), -#else -#define LPS22DF_CFG_IRQ(inst) -#endif /* CONFIG_LPS22DF_TRIGGER */ - -#define LPS22DF_CONFIG_COMMON(inst) \ - .odr = DT_INST_PROP(inst, odr), \ - .lpf = DT_INST_PROP(inst, lpf), \ - .avg = DT_INST_PROP(inst, avg), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ - (LPS22DF_CFG_IRQ(inst)), ()) - -#define LPS22DF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | \ - SPI_MODE_CPOL | SPI_MODE_CPHA) \ - -#define LPS22DF_CONFIG_SPI(inst) \ - { \ - STMEMSC_CTX_SPI(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .spi = SPI_DT_SPEC_INST_GET(inst, \ - LPS22DF_SPI_OPERATION, \ - 0), \ - }, \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -/* - * Instantiation macros used when a device is on an I2C bus. - */ - -#define LPS22DF_CONFIG_I2C(inst) \ - { \ - STMEMSC_CTX_I2C(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .i2c = I2C_DT_SPEC_INST_GET(inst), \ - }, \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -/* - * Instantiation macros used when a device is on an I#C bus. - */ - -#define LPS22DF_CONFIG_I3C(inst) \ - { \ - STMEMSC_CTX_I3C(&lps22df_config_##inst.stmemsc_cfg), \ - .stmemsc_cfg = { \ - .i3c = &lps22df_data_##inst.i3c_dev, \ - }, \ - .i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \ - LPS22DF_CONFIG_COMMON(inst) \ - } - -#define LPS22DF_CONFIG_I3C_OR_I2C(inst) \ - COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \ - (LPS22DF_CONFIG_I2C(inst)), \ - (LPS22DF_CONFIG_I3C(inst))) - -/* - * Main instantiation macro. Use of COND_CODE_1() selects the right - * bus-specific macro at preprocessor time. - */ - -#define LPS22DF_DEFINE(inst) \ - static struct lps22df_data lps22df_data_##inst; \ - static const struct lps22df_config lps22df_config_##inst = \ - COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ - (LPS22DF_CONFIG_SPI(inst)), \ - (COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \ - (LPS22DF_CONFIG_I3C_OR_I2C(inst)), \ - (LPS22DF_CONFIG_I2C(inst))))); \ - SENSOR_DEVICE_DT_INST_DEFINE(inst, lps22df_init, NULL, &lps22df_data_##inst, \ - &lps22df_config_##inst, POST_KERNEL, \ - CONFIG_SENSOR_INIT_PRIORITY, &lps22df_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(LPS22DF_DEFINE) diff --git a/drivers/sensor/lps22df/lps22df.h b/drivers/sensor/lps22df/lps22df.h deleted file mode 100644 index 044c08cbd93..00000000000 --- a/drivers/sensor/lps22df/lps22df.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#ifndef ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ -#define ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ - -#include -#include -#include "lps22df_reg.h" - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) -#include -#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - #define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL) -#else - #define ON_I3C_BUS(cfg) (false) -#endif - -struct lps22df_config { - stmdev_ctx_t ctx; - union { -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) - const struct i2c_dt_spec i2c; -#endif -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) - const struct spi_dt_spec spi; -#endif -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct i3c_device_desc **i3c; -#endif - } stmemsc_cfg; - uint8_t odr; - uint8_t lpf; - uint8_t avg; - uint8_t drdy_pulsed; -#ifdef CONFIG_LPS22DF_TRIGGER - struct gpio_dt_spec gpio_int; -#endif - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct { - const struct device *bus; - const struct i3c_device_id dev_id; - } i3c; -#endif -}; - -struct lps22df_data { - int32_t sample_press; - int16_t sample_temp; - -#ifdef CONFIG_LPS22DF_TRIGGER - struct gpio_callback gpio_cb; - - const struct sensor_trigger *data_ready_trigger; - sensor_trigger_handler_t handler_drdy; - const struct device *dev; - -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS22DF_THREAD_STACK_SIZE); - struct k_thread thread; - struct k_sem intr_sem; -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - struct k_work work; -#endif - -#endif /* CONFIG_LPS22DF_TRIGGER */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - struct i3c_device_desc *i3c_dev; -#endif -}; - -#ifdef CONFIG_LPS22DF_TRIGGER -int lps22df_trigger_set(const struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler); - -int lps22df_init_interrupt(const struct device *dev); -#endif - -#endif /* ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ */ diff --git a/drivers/sensor/lps22df/lps22df_trigger.c b/drivers/sensor/lps22df/lps22df_trigger.c deleted file mode 100644 index c5d6a91dba8..00000000000 --- a/drivers/sensor/lps22df/lps22df_trigger.c +++ /dev/null @@ -1,251 +0,0 @@ -/* ST Microelectronics LPS22DF pressure and temperature sensor - * - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - * - * Datasheet: - * https://www.st.com/resource/en/datasheet/lps22df.pdf - */ - -#define DT_DRV_COMPAT st_lps22df - -#include -#include -#include -#include - -#include "lps22df.h" - -LOG_MODULE_DECLARE(LPS22DF, CONFIG_SENSOR_LOG_LEVEL); - -/** - * lps22df_enable_int - enable selected int pin to generate interrupt - */ -static int lps22df_enable_int(const struct device *dev, int enable) -{ - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_pin_int_route_t int_route; - - /* set interrupt */ - lps22df_pin_int_route_get(ctx, &int_route); - int_route.drdy_pres = enable; - return lps22df_pin_int_route_set(ctx, &int_route); -} - -/** - * lps22df_trigger_set - link external trigger to event data ready - */ -int lps22df_trigger_set(const struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler) -{ - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config * const cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_data_t raw_data; - - if (trig->chan != SENSOR_CHAN_ALL) { - LOG_WRN("trigger set not supported on this channel."); - return -ENOTSUP; - } - - lps22df->handler_drdy = handler; - lps22df->data_ready_trigger = trig; - if (handler) { - /* dummy read: re-trigger interrupt */ - if (lps22df_data_get(ctx, &raw_data) < 0) { - LOG_DBG("Failed to read sample"); - return -EIO; - } - return lps22df_enable_int(dev, 1); - } else { - return lps22df_enable_int(dev, 0); - } - - return -ENOTSUP; -} - -/** - * lps22df_handle_interrupt - handle the drdy event - * read data and call handler if registered any - */ -static void lps22df_handle_interrupt(const struct device *dev) -{ - int ret; - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_all_sources_t status; - - if (lps22df_all_sources_get(ctx, &status) < 0) { - LOG_DBG("failed reading status reg"); - goto exit; - } - - if (status.drdy_pres == 0) { - goto exit; /* spurious interrupt */ - } - - if (lps22df->handler_drdy != NULL) { - lps22df->handler_drdy(dev, lps22df->data_ready_trigger); - } - - if (ON_I3C_BUS(cfg)) { - /* - * I3C IBI does not rely on GPIO. - * So no need to enable GPIO pin for interrupt trigger. - */ - return; - } - -exit: - ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, - GPIO_INT_EDGE_TO_ACTIVE); - if (ret < 0) { - LOG_ERR("%s: Not able to configure pin_int", dev->name); - } -} - -static void lps22df_intr_callback(struct lps22df_data *lps22df) -{ -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - k_sem_give(&lps22df->intr_sem); -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - k_work_submit(&lps22df->work); -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ -} - -static void lps22df_gpio_callback(const struct device *dev, - struct gpio_callback *cb, uint32_t pins) -{ - struct lps22df_data *lps22df = - CONTAINER_OF(cb, struct lps22df_data, gpio_cb); - - ARG_UNUSED(pins); - const struct lps22df_config *cfg = lps22df->dev->config; - int ret; - - ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); - if (ret < 0) { - LOG_ERR("%s: Not able to configure pin_int", dev->name); - } - - lps22df_intr_callback(lps22df); -} - -#ifdef CONFIG_LPS22DF_TRIGGER_OWN_THREAD -static void lps22df_thread(struct lps22df_data *lps22df) -{ - while (1) { - k_sem_take(&lps22df->intr_sem, K_FOREVER); - lps22df_handle_interrupt(lps22df->dev); - } -} -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ - -#ifdef CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD -static void lps22df_work_cb(struct k_work *work) -{ - struct lps22df_data *lps22df = - CONTAINER_OF(work, struct lps22df_data, work); - - lps22df_handle_interrupt(lps22df->dev); -} -#endif /* CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD */ - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) -static int lps22df_ibi_cb(struct i3c_device_desc *target, - struct i3c_ibi_payload *payload) -{ - const struct device *dev = target->dev; - struct lps22df_data *lps22df = dev->data; - - ARG_UNUSED(payload); - - lps22df_intr_callback(lps22df); - - return 0; -} -#endif - -int lps22df_init_interrupt(const struct device *dev) -{ - struct lps22df_data *lps22df = dev->data; - const struct lps22df_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lps22df_int_mode_t mode; - int ret; - - /* setup data ready gpio interrupt */ - if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) { - if (cfg->gpio_int.port) { - LOG_ERR("%s: device %s is not ready", dev->name, - cfg->gpio_int.port->name); - return -ENODEV; - } - - LOG_DBG("%s: gpio_int not defined in DT", dev->name); - return 0; - } - - lps22df->dev = dev; - -#if defined(CONFIG_LPS22DF_TRIGGER_OWN_THREAD) - k_sem_init(&lps22df->intr_sem, 0, K_SEM_MAX_LIMIT); - - k_thread_create(&lps22df->thread, lps22df->thread_stack, - CONFIG_LPS22DF_THREAD_STACK_SIZE, - (k_thread_entry_t)lps22df_thread, lps22df, - NULL, NULL, K_PRIO_COOP(CONFIG_LPS22DF_THREAD_PRIORITY), - 0, K_NO_WAIT); -#elif defined(CONFIG_LPS22DF_TRIGGER_GLOBAL_THREAD) - lps22df->work.handler = lps22df_work_cb; -#endif /* CONFIG_LPS22DF_TRIGGER_OWN_THREAD */ - - if (!ON_I3C_BUS(cfg)) { - ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT); - if (ret < 0) { - LOG_ERR("Could not configure gpio"); - return ret; - } - - LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name, - cfg->gpio_int.pin); - - gpio_init_callback(&lps22df->gpio_cb, - lps22df_gpio_callback, - BIT(cfg->gpio_int.pin)); - - ret = gpio_add_callback(cfg->gpio_int.port, &lps22df->gpio_cb); - if (ret < 0) { - LOG_ERR("Could not set gpio callback"); - return ret; - } - } - - /* enable drdy in pulsed/latched mode */ - LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); - mode.drdy_latched = ~cfg->drdy_pulsed; - if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { - return -EIO; - } - -#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) - if (cfg->i3c.bus != NULL) { - /* I3C IBI does not utilize GPIO interrupt. */ - lps22df->i3c_dev->ibi_cb = lps22df_ibi_cb; - - if (i3c_ibi_enable(lps22df->i3c_dev) != 0) { - LOG_DBG("Could not enable I3C IBI"); - return -EIO; - } - - return 0; - } -#endif - - return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, - GPIO_INT_EDGE_TO_ACTIVE); -} diff --git a/drivers/sensor/lps22hh/Kconfig b/drivers/sensor/lps22hh/Kconfig index ad23e07068e..2fa57a6c485 100644 --- a/drivers/sensor/lps22hh/Kconfig +++ b/drivers/sensor/lps22hh/Kconfig @@ -7,6 +7,7 @@ menuconfig LPS22HH bool "LPS22HH pressure and temperature" default y depends on DT_HAS_ST_LPS22HH_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i2c) select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i3c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),spi) diff --git a/drivers/sensor/lps2xdf/CMakeLists.txt b/drivers/sensor/lps2xdf/CMakeLists.txt new file mode 100644 index 00000000000..24a1b5844a8 --- /dev/null +++ b/drivers/sensor/lps2xdf/CMakeLists.txt @@ -0,0 +1,15 @@ +# ST Microelectronics LPS22DF pressure and temperature sensor +# +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources(lps2xdf.c) +zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_LPS22DF_ENABLED lps22df.c ) +zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_LPS28DFW_ENABLED lps28dfw.c ) +zephyr_library_sources_ifdef(CONFIG_LPS2XDF_TRIGGER lps2xdf_trigger.c) + +zephyr_library_include_directories(../stmemsc) diff --git a/drivers/sensor/lps2xdf/Kconfig b/drivers/sensor/lps2xdf/Kconfig new file mode 100644 index 00000000000..754f8c3b451 --- /dev/null +++ b/drivers/sensor/lps2xdf/Kconfig @@ -0,0 +1,64 @@ +# ST Microelectronics LPS2xDF pressure and temperature sensor + +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LPS2XDF + bool "LPS2xDF pressure and temperature" + default y + depends on DT_HAS_ST_LPS22DF_ENABLED || DT_HAS_ST_LPS28DFW_ENABLED + depends on ZEPHYR_HAL_ST_MODULE + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i2c) ||\ + $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS28DFW),i2c) + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),i3c) ||\ + $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS28DFW),i3c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22DF),spi) + select HAS_STMEMSC + select USE_STDC_LPS22DF if DT_HAS_ST_LPS22DF_ENABLED + select USE_STDC_LPS28DFW if DT_HAS_ST_LPS28DFW_ENABLED + help + Enable driver for LPS2xDF I2C-based pressure and temperature + sensor. + +if LPS2XDF + +choice LPS2XDF_TRIGGER_MODE + prompt "Trigger mode" + default LPS2XDF_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config LPS2XDF_TRIGGER_NONE + bool "No trigger" + +config LPS2XDF_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select LPS2XDF_TRIGGER + +config LPS2XDF_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select LPS2XDF_TRIGGER + +endchoice # LPS2XDF_TRIGGER_MODE + +config LPS2XDF_TRIGGER + bool + +config LPS2XDF_THREAD_PRIORITY + int "Thread priority" + depends on LPS2XDF_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config LPS2XDF_THREAD_STACK_SIZE + int "Thread stack size" + depends on LPS2XDF_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +endif # LPS2XDF diff --git a/drivers/sensor/lps2xdf/lps22df.c b/drivers/sensor/lps2xdf/lps22df.c new file mode 100644 index 00000000000..ff5537cf37c --- /dev/null +++ b/drivers/sensor/lps2xdf/lps22df.c @@ -0,0 +1,234 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lps2xdf.h" +#include "lps22df.h" +#include + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static inline int lps22df_mode_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_md_t md; + + md.odr = odr; + md.avg = cfg->avg; + md.lpf = cfg->lpf; + + return lps22df_mode_set(ctx, &md); +} + +static int lps22df_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct lps2xdf_data *data = dev->data; + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_press = raw_data.pressure.raw; + data->sample_temp = raw_data.heat.raw; + + return 0; +} + +/** + * lps22df_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +#ifdef CONFIG_LPS2XDF_TRIGGER +static void lps22df_handle_interrupt(const struct device *dev) +{ + int ret; + struct lps2xdf_data *lps22df = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_all_sources_t status; + + if (lps22df_all_sources_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + goto exit; + } + + if (status.drdy_pres == 0) { + goto exit; /* spurious interrupt */ + } + + if (lps22df->handler_drdy != NULL) { + lps22df->handler_drdy(dev, lps22df->data_ready_trigger); + } + + if (ON_I3C_BUS(cfg)) { + /* + * I3C IBI does not rely on GPIO. + * So no need to enable GPIO pin for interrupt trigger. + */ + return; + } + +exit: + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +/** + * lps22df_enable_int - enable selected int pin to generate interrupt + */ +static int lps22df_enable_int(const struct device *dev, int enable) +{ + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_pin_int_route_t int_route; + + /* set interrupt */ + lps22df_pin_int_route_get(ctx, &int_route); + int_route.drdy_pres = enable; + return lps22df_pin_int_route_set(ctx, &int_route); +} + +/** + * lps22df_trigger_set - link external trigger to event data ready + */ +static int lps22df_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lps2xdf_data *lps22df = dev->data; + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_data_t raw_data; + + if (trig->chan != SENSOR_CHAN_ALL) { + LOG_WRN("trigger set not supported on this channel."); + return -ENOTSUP; + } + + lps22df->handler_drdy = handler; + lps22df->data_ready_trigger = trig; + if (handler) { + /* dummy read: re-trigger interrupt */ + if (lps22df_data_get(ctx, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + return lps22df_enable_int(dev, 1); + } else { + return lps22df_enable_int(dev, 0); + } + + return -ENOTSUP; +} +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +const struct lps2xdf_chip_api st_lps22df_chip_api = { + .mode_set_odr_raw = lps22df_mode_set_odr_raw, + .sample_fetch = lps22df_sample_fetch, +#if CONFIG_LPS2XDF_TRIGGER + .handle_interrupt = lps22df_handle_interrupt, + .trigger_set = lps22df_trigger_set, +#endif +}; + +int st_lps22df_init(const struct device *dev) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps22df_id_t id; + lps22df_stat_t status; + uint8_t tries = 10; + int ret; + +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) + if (cfg->i3c.bus != NULL) { + struct lps2xdf_data *data = dev->data; + /* + * Need to grab the pointer to the I3C device descriptor + * before we can talk to the sensor. + */ + data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); + if (data->i3c_dev == NULL) { + LOG_ERR("Cannot find I3C device descriptor"); + return -ENODEV; + } + } +#endif + + if (lps22df_id_get(ctx, &id) < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return -EIO; + } + + if (id.whoami != LPS22DF_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); + return -EIO; + } + + LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); + + /* Restore default configuration */ + if (lps22df_init_set(ctx, LPS22DF_RESET) < 0) { + LOG_ERR("%s: Not able to reset device", dev->name); + return -EIO; + } + + do { + if (!--tries) { + LOG_DBG("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(LPS2XDF_SWRESET_WAIT_TIME_US); + + if (lps22df_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset); + + /* Set bdu and if_inc recommended for driver usage */ + if (lps22df_init_set(ctx, LPS22DF_DRV_RDY) < 0) { + LOG_ERR("%s: Not able to set device to ready state", dev->name); + return -EIO; + } + + if (ON_I3C_BUS(cfg)) { + lps22df_bus_mode_t bus_mode; + + /* Select bus interface */ + lps22df_bus_mode_get(ctx, &bus_mode); + bus_mode.filter = LPS22DF_AUTO; + bus_mode.interface = LPS22DF_SEL_BY_HW; + lps22df_bus_mode_set(ctx, &bus_mode); + } + + /* set sensor default odr */ + LOG_DBG("%s: odr: %d", dev->name, cfg->odr); + ret = lps22df_mode_set_odr_raw(dev, cfg->odr); + if (ret < 0) { + LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); + return ret; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + if (cfg->trig_enabled) { + if (lps2xdf_init_interrupt(dev, DEVICE_VARIANT_LPS22DF) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} diff --git a/drivers/sensor/lps2xdf/lps22df.h b/drivers/sensor/lps2xdf/lps22df.h new file mode 100644 index 00000000000..bb03423ea8a --- /dev/null +++ b/drivers/sensor/lps2xdf/lps22df.h @@ -0,0 +1,23 @@ +/* ST Microelectronics LPS22DF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "lps22df_reg.h" + +#include + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS22DF_LPS22DF_H_ + +extern const struct lps2xdf_chip_api st_lps22df_chip_api; + +int st_lps22df_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS22DF_H_ */ diff --git a/drivers/sensor/lps2xdf/lps28dfw.c b/drivers/sensor/lps2xdf/lps28dfw.c new file mode 100644 index 00000000000..40ea39bb571 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps28dfw.c @@ -0,0 +1,241 @@ +/* ST Microelectronics LPS28DFW pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lps2xdf.h" +#include "lps28dfw.h" +#include + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static inline int lps28dfw_mode_set_odr_raw(const struct device *dev, uint8_t odr) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_md_t md; + + md.odr = odr; + md.avg = cfg->avg; + md.lpf = cfg->lpf; + md.fs = cfg->fs; + + return lps28dfw_mode_set(ctx, &md); +} + +static int lps28dfw_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct lps2xdf_data *data = dev->data; + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_data_t raw_data; + lps28dfw_md_t md; + + md.fs = cfg->fs; + + if (lps28dfw_data_get(ctx, &md, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_press = raw_data.pressure.raw; + data->sample_temp = raw_data.heat.raw; + + return 0; +} + +/** + * lps28dfw_handle_interrupt - handle the drdy event + * read data and call handler if registered any + */ +#ifdef CONFIG_LPS2XDF_TRIGGER +static void lps28dfw_handle_interrupt(const struct device *dev) +{ + int ret; + struct lps2xdf_data *lps28dfw = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_all_sources_t status; + + if (lps28dfw_all_sources_get(ctx, &status) < 0) { + LOG_DBG("failed reading status reg"); + goto exit; + } + + if (status.drdy_pres == 0) { + goto exit; /* spurious interrupt */ + } + + if (lps28dfw->handler_drdy != NULL) { + lps28dfw->handler_drdy(dev, lps28dfw->data_ready_trigger); + } + + if (ON_I3C_BUS(cfg)) { + /* + * I3C IBI does not rely on GPIO. + * So no need to enable GPIO pin for interrupt trigger. + */ + return; + } + +exit: + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } +} + +/** + * lps28dfw_enable_int - enable selected int pin to generate interrupt + */ +static int lps28dfw_enable_int(const struct device *dev, int enable) +{ + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_pin_int_route_t int_route; + + /* set interrupt */ + lps28dfw_pin_int_route_get(ctx, &int_route); + int_route.drdy_pres = enable; + return lps28dfw_pin_int_route_set(ctx, &int_route); +} + +/** + * lps22df_trigger_set - link external trigger to event data ready + */ +static int lps28dfw_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct lps2xdf_data *lps28dfw = dev->data; + const struct lps2xdf_config * const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_data_t raw_data; + lps28dfw_md_t md; + + md.fs = cfg->fs; + + if (trig->chan != SENSOR_CHAN_ALL) { + LOG_WRN("trigger set not supported on this channel."); + return -ENOTSUP; + } + + lps28dfw->handler_drdy = handler; + lps28dfw->data_ready_trigger = trig; + if (handler) { + /* dummy read: re-trigger interrupt */ + if (lps28dfw_data_get(ctx, &md, &raw_data) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + return lps28dfw_enable_int(dev, 1); + } else { + return lps28dfw_enable_int(dev, 0); + } + + return -ENOTSUP; +} +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +const struct lps2xdf_chip_api st_lps28dfw_chip_api = { + .mode_set_odr_raw = lps28dfw_mode_set_odr_raw, + .sample_fetch = lps28dfw_sample_fetch, +#if CONFIG_LPS2XDF_TRIGGER + .handle_interrupt = lps28dfw_handle_interrupt, + .trigger_set = lps28dfw_trigger_set, +#endif +}; + +int st_lps28dfw_init(const struct device *dev) +{ + const struct lps2xdf_config *const cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + lps28dfw_id_t id; + lps28dfw_stat_t status; + uint8_t tries = 10; + int ret; + +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c) + if (cfg->i3c.bus != NULL) { + struct lps2xdf_data *data = dev->data; + /* + * Need to grab the pointer to the I3C device descriptor + * before we can talk to the sensor. + */ + data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id); + if (data->i3c_dev == NULL) { + LOG_ERR("Cannot find I3C device descriptor"); + return -ENODEV; + } + } +#endif + + if (lps28dfw_id_get(ctx, &id) < 0) { + LOG_ERR("%s: Not able to read dev id", dev->name); + return -EIO; + } + + if (id.whoami != LPS28DFW_ID) { + LOG_ERR("%s: Invalid chip ID 0x%02x", dev->name, id.whoami); + return -EIO; + } + + LOG_DBG("%s: chip id 0x%x", dev->name, id.whoami); + + /* Restore default configuration */ + if (lps28dfw_init_set(ctx, LPS28DFW_RESET) < 0) { + LOG_ERR("%s: Not able to reset device", dev->name); + return -EIO; + } + + do { + if (!--tries) { + LOG_DBG("sw reset timed out"); + return -ETIMEDOUT; + } + k_usleep(LPS2XDF_SWRESET_WAIT_TIME_US); + + if (lps28dfw_status_get(ctx, &status) < 0) { + return -EIO; + } + } while (status.sw_reset); + + /* Set bdu and if_inc recommended for driver usage */ + if (lps28dfw_init_set(ctx, LPS28DFW_DRV_RDY) < 0) { + LOG_ERR("%s: Not able to set device to ready state", dev->name); + return -EIO; + } + + if (ON_I3C_BUS(cfg)) { + lps28dfw_bus_mode_t bus_mode; + + /* Select bus interface */ + lps28dfw_bus_mode_get(ctx, &bus_mode); + bus_mode.filter = LPS28DFW_AUTO; + bus_mode.interface = LPS28DFW_SEL_BY_HW; + lps28dfw_bus_mode_set(ctx, &bus_mode); + } + + /* set sensor default odr */ + LOG_DBG("%s: odr: %d", dev->name, cfg->odr); + ret = lps28dfw_mode_set_odr_raw(dev, cfg->odr); + if (ret < 0) { + LOG_ERR("%s: Failed to set odr %d", dev->name, cfg->odr); + return ret; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + if (cfg->trig_enabled) { + if (lps2xdf_init_interrupt(dev, DEVICE_VARIANT_LPS28DFW) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } + } +#endif + + return 0; +} diff --git a/drivers/sensor/lps2xdf/lps28dfw.h b/drivers/sensor/lps2xdf/lps28dfw.h new file mode 100644 index 00000000000..ba87caab094 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps28dfw.h @@ -0,0 +1,23 @@ +/* ST Microelectronics LPS28DFW pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#include "lps28dfw_reg.h" + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS28DFW_LPS28DFW_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS28DFW_LPS28DFW_H_ + +extern const struct lps2xdf_chip_api st_lps28dfw_chip_api; + +int st_lps28dfw_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS28DFW_H_ */ diff --git a/drivers/sensor/lps2xdf/lps2xdf.c b/drivers/sensor/lps2xdf/lps2xdf.c new file mode 100644 index 00000000000..33d909dfbf6 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf.c @@ -0,0 +1,223 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28df.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "lps2xdf.h" + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw.h" +#endif + +LOG_MODULE_REGISTER(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lps2xdf_map[] = {0, 1, 4, 10, 25, 50, 75, 100, 200}; + +static int lps2xdf_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + for (odr = 0; odr < ARRAY_SIZE(lps2xdf_map); odr++) { + if (freq == lps2xdf_map[odr]) { + break; + } + } + + if (odr == ARRAY_SIZE(lps2xdf_map)) { + LOG_DBG("bad frequency"); + return -EINVAL; + } + + if (chip_api->mode_set_odr_raw(dev, odr)) { + LOG_DBG("failed to set sampling rate"); + return -EIO; + } + + return 0; +} + +static int lps2xdf_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL) { + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lps2xdf_odr_set(dev, val->val1); + default: + LOG_DBG("operation not supported."); + return -ENOTSUP; + } + + return 0; +} + +static inline void lps2xdf_press_convert(const struct device *dev, + struct sensor_value *val, + int32_t raw_val) +{ + const struct lps2xdf_config *const cfg = dev->config; + int32_t press_tmp = raw_val >> 8; /* raw value is left aligned (24 msb) */ + int divider; + + /* Pressure sensitivity is: + * - 4096 LSB/hPa for Full-Scale of 260 - 1260 hPa: + * - 2048 LSB/hPa for Full-Scale of 260 - 4060 hPa: + * Also convert hPa into kPa + */ + if (cfg->fs == 0) { + divider = 40960; + } else { + divider = 20480; + } + val->val1 = press_tmp / divider; + + /* For the decimal part use (3125 / 128) as a factor instead of + * (1000000 / 40960) to avoid int32 overflow + */ + val->val2 = (press_tmp % divider) * 3125 / 128; +} + + +static inline void lps2xdf_temp_convert(struct sensor_value *val, int16_t raw_val) +{ + /* Temperature sensitivity is 100 LSB/deg C */ + val->val1 = raw_val / 100; + val->val2 = ((int32_t)raw_val % 100) * 10000; +} + +static int lps2xdf_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct lps2xdf_data *data = dev->data; + + if (chan == SENSOR_CHAN_PRESS) { + lps2xdf_press_convert(dev, val, data->sample_press); + } else if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + lps2xdf_temp_convert(val, data->sample_temp); + } else { + return -ENOTSUP; + } + + return 0; +} + +static int lps2xdf_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + return chip_api->sample_fetch(dev, chan); +} + +static const struct sensor_driver_api lps2xdf_driver_api = { + .attr_set = lps2xdf_attr_set, + .sample_fetch = lps2xdf_sample_fetch, + .channel_get = lps2xdf_channel_get, +#if CONFIG_LPS2XDF_TRIGGER + .trigger_set = lps2xdf_trigger_set, +#endif +}; + +#ifdef CONFIG_LPS2XDF_TRIGGER +#define LPS2XDF_CFG_IRQ(inst) \ + .trig_enabled = true, \ + .gpio_int = GPIO_DT_SPEC_INST_GET(inst, drdy_gpios), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed) +#else +#define LPS2XDF_CFG_IRQ(inst) +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +#define LPS2XDF_CONFIG_COMMON(inst, name) \ + .odr = DT_INST_PROP(inst, odr), \ + .lpf = DT_INST_PROP(inst, lpf), \ + .avg = DT_INST_PROP(inst, avg), \ + .chip_api = &name##_chip_api, \ + IF_ENABLED(DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lps28dfw), \ + (.fs = DT_INST_PROP(inst, fs),)) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, drdy_gpios), \ + (LPS2XDF_CFG_IRQ(inst))) + +#define LPS2XDF_SPI_OPERATION (SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | \ + SPI_MODE_CPOL | SPI_MODE_CPHA) + +#define LPS2XDF_CONFIG_SPI(inst, name) \ +{ \ + STMEMSC_CTX_SPI(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .spi = SPI_DT_SPEC_INST_GET(inst, LPS2XDF_SPI_OPERATION, 0), \ + }, \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I2C(inst, name) \ +{ \ + STMEMSC_CTX_I2C(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }, \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I3C(inst, name) \ +{ \ + STMEMSC_CTX_I3C(&lps2xdf_config_##name##_##inst.stmemsc_cfg), \ + .stmemsc_cfg = { \ + .i3c = &lps2xdf_data_##name##_##inst.i3c_dev, \ + }, \ + .i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \ + LPS2XDF_CONFIG_COMMON(inst, name) \ +} + +#define LPS2XDF_CONFIG_I3C_OR_I2C(inst, name) \ + COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \ + (LPS2XDF_CONFIG_I2C(inst, name)), \ + (LPS2XDF_CONFIG_I3C(inst, name))) + +#define LPS2XDF_DEFINE(inst, name) \ + static struct lps2xdf_data lps2xdf_data_##name##_##inst; \ + static const struct lps2xdf_config lps2xdf_config_##name##_##inst = COND_CODE_1( \ + DT_INST_ON_BUS(inst, spi), \ + (LPS2XDF_CONFIG_SPI(inst, name)), \ + (COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \ + (LPS2XDF_CONFIG_I3C_OR_I2C(inst, name)), \ + (LPS2XDF_CONFIG_I2C(inst, name))))); \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, name##_init, NULL, &lps2xdf_data_##name##_##inst, \ + &lps2xdf_config_##name##_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &lps2xdf_driver_api); + +#define DT_DRV_COMPAT st_lps22df +DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT) +#undef DT_DRV_COMPAT + +#define DT_DRV_COMPAT st_lps28dfw +DT_INST_FOREACH_STATUS_OKAY_VARGS(LPS2XDF_DEFINE, DT_DRV_COMPAT) +#undef DT_DRV_COMPAT diff --git a/drivers/sensor/lps2xdf/lps2xdf.h b/drivers/sensor/lps2xdf/lps2xdf.h new file mode 100644 index 00000000000..10a38a5a133 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf.h @@ -0,0 +1,136 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheets: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28dfw.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LPS2XDF_LPS2XDF_H_ +#define ZEPHYR_DRIVERS_SENSOR_LPS2XDF_LPS2XDF_H_ + +#include +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw_reg.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df_reg.h" +#endif + +#include +#include +#include +#include + +#define LPS2XDF_SWRESET_WAIT_TIME_US 50 + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + #define ON_I3C_BUS(cfg) (cfg->i3c.bus != NULL) +#else + #define ON_I3C_BUS(cfg) (false) +#endif + +typedef int32_t (*api_lps2xdf_mode_set_odr_raw)(const struct device *dev, uint8_t odr); +typedef int32_t (*api_lps2xdf_sample_fetch)(const struct device *dev, enum sensor_channel chan); +typedef void (*api_lps2xdf_handle_interrupt)(const struct device *dev); +#ifdef CONFIG_LPS2XDF_TRIGGER +typedef int (*api_lps2xdf_trigger_set)(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); +#endif + +struct lps2xdf_chip_api { + api_lps2xdf_mode_set_odr_raw mode_set_odr_raw; + api_lps2xdf_sample_fetch sample_fetch; + api_lps2xdf_handle_interrupt handle_interrupt; +#ifdef CONFIG_LPS2XDF_TRIGGER + api_lps2xdf_trigger_set trigger_set; +#endif +}; + + +enum sensor_variant { + DEVICE_VARIANT_LPS22DF = 0, + DEVICE_VARIANT_LPS28DFW = 1, +}; + + +struct lps2xdf_config { + stmdev_ctx_t ctx; + union { +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i2c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i2c)) + const struct i2c_dt_spec i2c; +#endif +#if DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, spi) + const struct spi_dt_spec spi; +#endif +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct i3c_device_desc **i3c; +#endif + } stmemsc_cfg; + uint8_t odr; + uint8_t lpf; + uint8_t avg; + uint8_t drdy_pulsed; + bool fs; +#ifdef CONFIG_LPS2XDF_TRIGGER + struct gpio_dt_spec gpio_int; + bool trig_enabled; +#endif + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct { + const struct device *bus; + const struct i3c_device_id dev_id; + } i3c; +#endif + const struct lps2xdf_chip_api *chip_api; +}; + +struct lps2xdf_data { + int32_t sample_press; + int16_t sample_temp; + +#ifdef CONFIG_LPS2XDF_TRIGGER + struct gpio_callback gpio_cb; + + const struct sensor_trigger *data_ready_trigger; + sensor_trigger_handler_t handler_drdy; + const struct device *dev; + +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS2XDF_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem intr_sem; +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_LPS2XDF_TRIGGER */ + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) || \ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + struct i3c_device_desc *i3c_dev; +#endif +}; + +#ifdef CONFIG_LPS2XDF_TRIGGER +int lps2xdf_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_LPS2XDF_H_ */ diff --git a/drivers/sensor/lps2xdf/lps2xdf_trigger.c b/drivers/sensor/lps2xdf/lps2xdf_trigger.c new file mode 100644 index 00000000000..b196e1f40c2 --- /dev/null +++ b/drivers/sensor/lps2xdf/lps2xdf_trigger.c @@ -0,0 +1,212 @@ +/* ST Microelectronics LPS2XDF pressure and temperature sensor + * + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/lps22df.pdf + * https://www.st.com/resource/en/datasheet/lps28dfw.pdf + */ + +#include +#include +#include +#include + +#include "lps2xdf.h" + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) +#include "lps22df.h" +#endif + +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) +#include "lps28dfw.h" +#endif + +LOG_MODULE_DECLARE(LPS2XDF, CONFIG_SENSOR_LOG_LEVEL); + +int lps2xdf_trigger_set(const struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + return chip_api->trigger_set(dev, trig, handler); +} + +static void lps2xdf_intr_callback(struct lps2xdf_data *lps2xdf) +{ +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + k_sem_give(&lps2xdf->intr_sem); +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + k_work_submit(&lps2xdf->work); +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ +} + +static void lps2xdf_gpio_callback(const struct device *dev, + struct gpio_callback *cb, uint32_t pins) +{ + struct lps2xdf_data *lps2xdf = + CONTAINER_OF(cb, struct lps2xdf_data, gpio_cb); + + ARG_UNUSED(pins); + const struct lps2xdf_config *cfg = lps2xdf->dev->config; + int ret; + + ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE); + if (ret < 0) { + LOG_ERR("%s: Not able to configure pin_int", dev->name); + } + + lps2xdf_intr_callback(lps2xdf); +} + +#ifdef CONFIG_LPS2XDF_TRIGGER_OWN_THREAD +static void lps2xdf_thread(struct lps2xdf_data *lps2xdf) +{ + const struct device *dev = lps2xdf->dev; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + while (1) { + k_sem_take(&lps2xdf->intr_sem, K_FOREVER); + chip_api->handle_interrupt(dev); + } +} +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD +static void lps2xdf_work_cb(struct k_work *work) +{ + struct lps2xdf_data *lps2xdf = + CONTAINER_OF(work, struct lps2xdf_data, work); + const struct device *dev = lps2xdf->dev; + const struct lps2xdf_config *const cfg = dev->config; + const struct lps2xdf_chip_api *chip_api = cfg->chip_api; + + chip_api->handle_interrupt(dev); +} +#endif /* CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD */ + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) +static int lps2xdf_ibi_cb(struct i3c_device_desc *target, + struct i3c_ibi_payload *payload) +{ + const struct device *dev = target->dev; + struct lps2xdf_data *lps2xdf = dev->data; + + ARG_UNUSED(payload); + + lps2xdf_intr_callback(lps2xdf); + + return 0; +} +#endif + +int lps2xdf_init_interrupt(const struct device *dev, enum sensor_variant variant) +{ + struct lps2xdf_data *lps2xdf = dev->data; + const struct lps2xdf_config *cfg = dev->config; + stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; + int ret; + + /* setup data ready gpio interrupt */ + if (!gpio_is_ready_dt(&cfg->gpio_int) && !ON_I3C_BUS(cfg)) { + if (cfg->gpio_int.port) { + LOG_ERR("%s: device %s is not ready", dev->name, + cfg->gpio_int.port->name); + return -ENODEV; + } + + LOG_DBG("%s: gpio_int not defined in DT", dev->name); + return 0; + } + + lps2xdf->dev = dev; + +#if defined(CONFIG_LPS2XDF_TRIGGER_OWN_THREAD) + k_sem_init(&lps2xdf->intr_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&lps2xdf->thread, lps2xdf->thread_stack, + CONFIG_LPS2XDF_THREAD_STACK_SIZE, + (k_thread_entry_t)lps2xdf_thread, lps2xdf, + NULL, NULL, K_PRIO_COOP(CONFIG_LPS2XDF_THREAD_PRIORITY), + 0, K_NO_WAIT); +#elif defined(CONFIG_LPS2XDF_TRIGGER_GLOBAL_THREAD) + lps2xdf->work.handler = lps2xdf_work_cb; +#endif /* CONFIG_LPS2XDF_TRIGGER_OWN_THREAD */ + + if (!ON_I3C_BUS(cfg)) { + ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT); + if (ret < 0) { + LOG_ERR("Could not configure gpio"); + return ret; + } + + LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name, + cfg->gpio_int.pin); + + gpio_init_callback(&lps2xdf->gpio_cb, + lps2xdf_gpio_callback, + BIT(cfg->gpio_int.pin)); + + ret = gpio_add_callback(cfg->gpio_int.port, &lps2xdf->gpio_cb); + if (ret < 0) { + LOG_ERR("Could not set gpio callback"); + return ret; + } + } + + LOG_DBG("drdy_pulsed is %d", (int)cfg->drdy_pulsed); + + /* enable drdy in pulsed/latched mode */ + if (variant == DEVICE_VARIANT_LPS22DF) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps22df) + lps22df_int_mode_t mode; + + if (lps22df_interrupt_mode_get(ctx, &mode) < 0) { + return -EIO; + } + mode.drdy_latched = ~cfg->drdy_pulsed; + if (lps22df_interrupt_mode_set(ctx, &mode) < 0) { + return -EIO; + } +#endif + } else if (variant == DEVICE_VARIANT_LPS28DFW) { +#if DT_HAS_COMPAT_STATUS_OKAY(st_lps28dfw) + lps28dfw_int_mode_t mode; + + if (lps28dfw_interrupt_mode_get(ctx, &mode) < 0) { + return -EIO; + } + mode.drdy_latched = ~cfg->drdy_pulsed; + if (lps28dfw_interrupt_mode_set(ctx, &mode) < 0) { + return -EIO; + } +#endif + } else { + return -ENOTSUP; + } + +#if (DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps22df, i3c) ||\ + DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(st_lps28dfw, i3c)) + if (cfg->i3c.bus == NULL) { + /* I3C IBI does not utilize GPIO interrupt. */ + lps2xdf->i3c_dev->ibi_cb = lps2xdf_ibi_cb; + + if (i3c_ibi_enable(lps2xdf->i3c_dev) != 0) { + LOG_DBG("Could not enable I3C IBI"); + return -EIO; + } + + return 0; + } +#endif + + return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, + GPIO_INT_EDGE_TO_ACTIVE); +} diff --git a/drivers/sensor/lsm6dso/Kconfig b/drivers/sensor/lsm6dso/Kconfig index f1948a9769e..272deb6be95 100644 --- a/drivers/sensor/lsm6dso/Kconfig +++ b/drivers/sensor/lsm6dso/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSO bool "LSM6DSO I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSO_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lsm6dso16is/Kconfig b/drivers/sensor/lsm6dso16is/Kconfig index eac3312d784..7994d6a782f 100644 --- a/drivers/sensor/lsm6dso16is/Kconfig +++ b/drivers/sensor/lsm6dso16is/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSO16IS bool "LSM6DSO16IS I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSO16IS_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO16IS),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSO16IS),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lsm6dsv16x/Kconfig b/drivers/sensor/lsm6dsv16x/Kconfig index eb894ac2e99..79463a0f4e8 100644 --- a/drivers/sensor/lsm6dsv16x/Kconfig +++ b/drivers/sensor/lsm6dsv16x/Kconfig @@ -7,6 +7,7 @@ menuconfig LSM6DSV16X bool "LSM6DSV16X I2C/SPI accelerometer and gyroscope Chip" default y depends on DT_HAS_ST_LSM6DSV16X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),i2c) select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSV16X),spi) select HAS_STMEMSC diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c index f7d53bc0b93..d4f9a2c850d 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x.c @@ -83,8 +83,9 @@ static int lsm6dsv16x_accel_range_to_fs_val(int32_t range) return -EINVAL; } -static const uint16_t lsm6dsv16x_gyro_fs_map[] = {250, 125, 500, 0, 1000, 0, 2000}; -static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {2, 1, 4, 0, 8, 0, 16}; +static const uint16_t lsm6dsv16x_gyro_fs_map[] = {125, 250, 500, 1000, 2000, 0, 0, + 0, 0, 0, 0, 0, 4000}; +static const uint16_t lsm6dsv16x_gyro_fs_sens[] = {1, 2, 4, 8, 16, 0, 0, 0, 0, 0, 0, 0, 32}; static int lsm6dsv16x_gyro_range_to_fs_val(int32_t range) { @@ -923,6 +924,7 @@ static int lsm6dsv16x_init(const struct device *dev) .trig_enabled = true, \ .int1_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, { 0 }), \ .int2_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int2_gpios, { 0 }), \ + .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ .drdy_pin = DT_INST_PROP(inst, drdy_pin) #else #define LSM6DSV16X_CFG_IRQ(inst) @@ -938,8 +940,9 @@ static int lsm6dsv16x_init(const struct device *dev) .accel_range = DT_INST_PROP(inst, accel_range), \ .gyro_odr = DT_INST_PROP(inst, gyro_odr), \ .gyro_range = DT_INST_PROP(inst, gyro_range), \ - .drdy_pulsed = DT_INST_PROP(inst, drdy_pulsed), \ - LSM6DSV16X_CFG_IRQ(inst) + IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \ + DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \ + (LSM6DSV16X_CFG_IRQ(inst))) #define LSM6DSV16X_CONFIG_SPI(inst) \ { \ diff --git a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c index 2911ee55cb7..52bd7d6c0dd 100644 --- a/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c +++ b/drivers/sensor/lsm6dsv16x/lsm6dsv16x_trigger.c @@ -19,41 +19,6 @@ LOG_MODULE_DECLARE(LSM6DSV16X, CONFIG_SENSOR_LOG_LEVEL); -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) -/** - * lsm6dsv16x_enable_t_int - TEMP enable selected int pin to generate interrupt - */ -static int lsm6dsv16x_enable_t_int(const struct device *dev, int enable) -{ - const struct lsm6dsv16x_config *cfg = dev->config; - stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx; - lsm6dsv16x_pin_int_route_t val; - int ret; - - if (enable) { - int16_t buf; - - /* dummy read: re-trigger interrupt */ - lsm6dsv16x_temperature_raw_get(ctx, &buf); - } - - /* set interrupt (TEMP DRDY interrupt is only on INT2) */ - if (cfg->drdy_pin == 1) { - return -EIO; - } - - ret = lsm6dsv16x_pin_int2_route_get(ctx, &val); - if (ret < 0) { - LOG_ERR("pint_int2_route_get error"); - return ret; - } - - val.drdy_temp = 1; - - return lsm6dsv16x_pin_int2_route_set(ctx, &val); -} -#endif - /** * lsm6dsv16x_enable_xl_int - XL enable selected int pin to generate interrupt */ @@ -178,17 +143,6 @@ int lsm6dsv16x_trigger_set(const struct device *dev, return lsm6dsv16x_enable_g_int(dev, LSM6DSV16X_DIS_BIT); } } -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - else if (trig->chan == SENSOR_CHAN_DIE_TEMP) { - lsm6dsv16x->handler_drdy_temp = handler; - lsm6dsv16x->trig_drdy_temp = trig; - if (handler) { - return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_EN_BIT); - } else { - return lsm6dsv16x_enable_t_int(dev, LSM6DSV16X_DIS_BIT); - } - } -#endif return -ENOTSUP; } @@ -210,11 +164,7 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev) return; } - if ((status.drdy_xl == 0) && (status.drdy_gy == 0) -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - && (status.drdy_temp == 0) -#endif - ) { + if ((status.drdy_xl == 0) && (status.drdy_gy == 0)) { break; } @@ -226,11 +176,6 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev) lsm6dsv16x->handler_drdy_gyr(dev, lsm6dsv16x->trig_drdy_gyr); } -#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP) - if ((status.drdy_temp) && (lsm6dsv16x->handler_drdy_temp != NULL)) { - lsm6dsv16x->handler_drdy_temp(dev, lsm6dsv16x->trig_drdy_temp); - } -#endif } gpio_pin_interrupt_configure_dt(lsm6dsv16x->drdy_gpio, diff --git a/drivers/sensor/max17055/max17055.c b/drivers/sensor/max17055/max17055.c index c2db8255623..139cef36a5d 100644 --- a/drivers/sensor/max17055/max17055.c +++ b/drivers/sensor/max17055/max17055.c @@ -348,6 +348,7 @@ static int max17055_write_config(const struct device *dev) uint16_t d_pacc = d_qacc * 44138 / design_capacity; uint16_t i_chg_term = current_ma_to_max17055(config->rsense_mohms, config->i_chg_term); uint16_t v_empty; + int ret; LOG_DBG("Writing configuration parameters"); LOG_DBG("DesignCap: %u, dQAcc: %u, IChgTerm: %u, dPAcc: %u", @@ -386,7 +387,10 @@ static int max17055_write_config(const struct device *dev) uint16_t model_cfg = MODELCFG_REFRESH; while (model_cfg & MODELCFG_REFRESH) { - max17055_reg_read(dev, MODEL_CFG, &model_cfg); + ret = max17055_reg_read(dev, MODEL_CFG, &model_cfg); + if (ret) { + return ret; + } k_sleep(K_MSEC(10)); } @@ -427,6 +431,7 @@ static int max17055_gauge_init(const struct device *dev) { int16_t tmp; const struct max17055_config *const config = dev->config; + int ret; if (!device_is_ready(config->i2c.bus)) { LOG_ERR("Bus device is not ready"); @@ -445,7 +450,10 @@ static int max17055_gauge_init(const struct device *dev) /* Wait for FSTAT_DNR to be cleared */ tmp = FSTAT_DNR; while (tmp & FSTAT_DNR) { - max17055_reg_read(dev, FSTAT, &tmp); + ret = max17055_reg_read(dev, FSTAT, &tmp); + if (ret) { + return ret; + } } if (max17055_init_config(dev)) { diff --git a/drivers/sensor/max31865/max31865.c b/drivers/sensor/max31865/max31865.c index bced243b1a8..f94de01fdc6 100644 --- a/drivers/sensor/max31865/max31865.c +++ b/drivers/sensor/max31865/max31865.c @@ -139,6 +139,14 @@ static int max31865_set_vbias(const struct device *dev, bool enable) return configure_device(dev); } +static int max31865_set_three_wire(const struct device *dev, bool enable) +{ + struct max31865_data *data = dev->data; + + WRITE_BIT(data->config_control_bits, 4, enable); + return configure_device(dev); +} + static char *max31865_error_to_string(uint8_t fault_register) { switch (fault_register) { @@ -242,13 +250,13 @@ static int max31865_init(const struct device *dev) WRITE_BIT(data->config_control_bits, 6, config->conversion_mode); WRITE_BIT(data->config_control_bits, 5, config->one_shot); - WRITE_BIT(data->config_control_bits, 4, config->three_wire); data->config_control_bits |= config->fault_cycle & 0b00001100; WRITE_BIT(data->config_control_bits, 0, config->filter_50hz); configure_device(dev); set_threshold_values(dev); max31865_set_vbias(dev, false); + max31865_set_three_wire(dev, config->three_wire); return 0; } @@ -274,9 +282,26 @@ static int max31865_channel_get(const struct device *dev, enum sensor_channel ch } } +static int max31865_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP) { + LOG_ERR("Invalid channel provided"); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_MAX31865_THREE_WIRE: + return max31865_set_three_wire(dev, val->val1); + default: + return -ENOTSUP; + } +} + static const struct sensor_driver_api max31865_api_funcs = { .sample_fetch = max31865_sample_fetch, .channel_get = max31865_channel_get, + .attr_set = max31865_attr_set, }; #define MAX31865_DEFINE(inst) \ diff --git a/drivers/sensor/max31865/max31865.h b/drivers/sensor/max31865/max31865.h index cff6bca9940..9efc3221499 100644 --- a/drivers/sensor/max31865/max31865.h +++ b/drivers/sensor/max31865/max31865.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c index 49fbbac8fe2..9ee732475da 100644 --- a/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c +++ b/drivers/sensor/mchp_tach_xec/tach_mchp_xec.c @@ -22,9 +22,7 @@ #include #include -#ifdef CONFIG_PM_DEVICE #include -#endif LOG_MODULE_REGISTER(tach_xec, CONFIG_SENSOR_LOG_LEVEL); @@ -58,9 +56,8 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) struct tach_regs * const tach = cfg->regs; uint8_t poll_count = 0; -#ifdef CONFIG_PM_DEVICE pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + while (poll_count < PIN_STS_TIMEOUT) { /* See whether internal counter is already latched */ if (tach->STATUS & MCHP_TACH_STS_CNT_RDY) { @@ -74,9 +71,9 @@ int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan) /* Allow other threads to run while we sleep */ k_usleep(USEC_PER_MSEC); } -#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); -#endif + if (poll_count == PIN_STS_TIMEOUT) { return -EINVAL; } diff --git a/drivers/sensor/mcp9600/mcp9600.c b/drivers/sensor/mcp9600/mcp9600.c index ed5fb8b97f7..dfec3a5d064 100644 --- a/drivers/sensor/mcp9600/mcp9600.c +++ b/drivers/sensor/mcp9600/mcp9600.c @@ -25,22 +25,23 @@ LOG_MODULE_REGISTER(MCP9600, CONFIG_SENSOR_LOG_LEVEL); #define MCP9600_REG_TC_CONFIG 0x05 #define MCP9600_REG_DEV_CONFIG 0x06 -#define MCP9600_REG_A1_CONFIG 0x07 - -#define MCP9600_REG_A2_CONFIG 0x08 -#define MCP9600_REG_A3_CONFIG 0x09 -#define MCP9600_REG_A4_CONFIG 0x0A -#define MCP9600_A1_HYST 0x0B - -#define MCP9600_A2_HYST 0x0C -#define MCP9600_A3_HYST 0x0D -#define MCP9600_A4_HYST 0x0E -#define MCP9600_A1_LIMIT 0x0F - -#define MCP9600_A2_LIMIT 0x10 -#define MCP9600_A3_LIMIT 0x11 -#define MCP9600_A4_LIMIT 0x12 -#define MCP9600_REG_ID_REVISION 0x13 + +#define MCP9600_REG_A1_CONFIG 0x08 +#define MCP9600_REG_A2_CONFIG 0x09 +#define MCP9600_REG_A3_CONFIG 0x0A +#define MCP9600_REG_A4_CONFIG 0x0B + +#define MCP9600_A1_HYST 0x0C +#define MCP9600_A2_HYST 0x0D +#define MCP9600_A3_HYST 0x0E +#define MCP9600_A4_HYST 0x0F + +#define MCP9600_A1_LIMIT 0x10 +#define MCP9600_A2_LIMIT 0x11 +#define MCP9600_A3_LIMIT 0x12 +#define MCP9600_A4_LIMIT 0x13 + +#define MCP9600_REG_ID_REVISION 0x20 struct mcp9600_data { int32_t temp; diff --git a/drivers/sensor/ntc_thermistor/Kconfig b/drivers/sensor/ntc_thermistor/Kconfig index 8ab04aaf184..140d324e9aa 100644 --- a/drivers/sensor/ntc_thermistor/Kconfig +++ b/drivers/sensor/ntc_thermistor/Kconfig @@ -7,7 +7,8 @@ config NTC_THERMISTOR default y depends on DT_HAS_NTC_THERMISTOR_GENERIC_ENABLED || \ DT_HAS_EPCOS_B57861S0103A039_ENABLED || \ - DT_HAS_MURATA_NCP15WB473_ENABLED + DT_HAS_MURATA_NCP15WB473_ENABLED || \ + DT_HAS_TDK_NTCG163JF103FT1_ENABLED select ADC help Enable driver for Zephyr NTC Thermistor. diff --git a/drivers/sensor/ntc_thermistor/ntc_thermistor.c b/drivers/sensor/ntc_thermistor/ntc_thermistor.c index 4f76ddc30f8..185e8c27673 100644 --- a/drivers/sensor/ntc_thermistor/ntc_thermistor.c +++ b/drivers/sensor/ntc_thermistor/ntc_thermistor.c @@ -217,3 +217,29 @@ static __unused const struct ntc_compensation comp_murata_ncp15wb473[] = { DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, comp_murata_ncp15wb473) + +/* tdk,ntcg163jf103ft1 */ +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT tdk_ntcg163jf103ft1 + +static __unused const struct ntc_compensation comp_tdk_ntcg163jf103ft1[] = { + { -25, 86560 }, + { -15, 53460 }, + { -5, 33930 }, + { 5, 22070 }, + { 15, 14700 }, + { 25, 10000 }, + { 35, 6942 }, + { 45, 4911 }, + { 55, 3536 }, + { 65, 2588 }, + { 75, 1924 }, + { 85, 1451 }, + { 95, 1110 }, + { 105, 860 }, + { 115, 674 }, + { 125, 534 }, +}; + +DT_INST_FOREACH_STATUS_OKAY_VARGS(NTC_THERMISTOR_DEFINE, DT_DRV_COMPAT, + comp_tdk_ntcg163jf103ft1) diff --git a/drivers/sensor/qdec_nxp_s32/CMakeLists.txt b/drivers/sensor/qdec_nxp_s32/CMakeLists.txt new file mode 100644 index 00000000000..a3065a37aba --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(qdec_nxp_s32.c) diff --git a/drivers/sensor/qdec_nxp_s32/Kconfig b/drivers/sensor/qdec_nxp_s32/Kconfig new file mode 100644 index 00000000000..4250d9b2654 --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config QDEC_NXP_S32 + bool "NXP Quad Decoder S32 drivers" + default y + depends on DT_HAS_NXP_QDEC_S32_ENABLED + select NXP_S32_EMIOS + help + Enable drivers for NXP S32 QUADRATURE DECODER diff --git a/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c b/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c new file mode 100644 index 00000000000..1b233d500e5 --- /dev/null +++ b/drivers/sensor/qdec_nxp_s32/qdec_nxp_s32.c @@ -0,0 +1,451 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define EMIOS_CHANNEL_COUNT 2U +#define EMIOS_CW_CH_IDX 0 +#define EMIOS_CCW_CH_IDX 1 + +/* LCU LUT control values for each of the 4 LC outputs */ +/* These values decide the direction of motor rotation */ +#define LCU_O0_LUT 0xAAAA +#define LCU_O1_LUT 0xCCCC +#define LCU_O2_LUT 0x4182 +#define LCU_O3_LUT 0x2814 + +LOG_MODULE_REGISTER(nxp_qdec_s32, CONFIG_SENSOR_LOG_LEVEL); + +#include +#include +#include + +#define DT_DRV_COMPAT nxp_qdec_s32 + +typedef void (*emios_callback_t)(void); + +/* Configuration variables from eMIOS Icu driver */ +extern eMios_Icu_Ip_ChStateType eMios_Icu_Ip_ChState[EMIOS_ICU_IP_NUM_OF_CHANNELS_USED]; +extern uint8 eMios_Icu_Ip_IndexInChState[EMIOS_ICU_IP_INSTANCE_COUNT][EMIOS_ICU_IP_NUM_OF_CHANNELS]; + +struct qdec_s32_config { + uint8_t emios_inst; + uint8_t emios_channels[EMIOS_CHANNEL_COUNT]; + const struct pinctrl_dev_config *pincfg; + + const Trgmux_Ip_InitType *trgmux_config; + + const Lcu_Ip_InitType *lcu_config; + emios_callback_t emios_cw_overflow_cb; + emios_callback_t emios_ccw_overflow_cb; +}; + +struct qdec_s32_data { + uint32_t counter_CW; + uint32_t counter_CCW; + int32_t abs_counter; + double micro_ticks_per_rev; + uint32_t ticks_per_sec; + uint32_t emios_cw_overflow_count; + uint32_t emios_ccw_overflow_count; +}; + +static void qdec_emios_overflow_count_cw_callback(const struct device *dev) +{ + struct qdec_s32_data *data = dev->data; + + data->emios_cw_overflow_count++; +} + +static void qdec_emios_overflow_count_ccw_callback(const struct device *dev) +{ + struct qdec_s32_data *data = dev->data; + + data->emios_ccw_overflow_count++; +} + +static int qdec_s32_fetch(const struct device *dev, enum sensor_channel ch) +{ + const struct qdec_s32_config *config = dev->config; + struct qdec_s32_data *data = dev->data; + + if (ch != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + data->counter_CW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers( + config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX])); /* CW counter */ + data->counter_CCW = (uint32_t)(Emios_Icu_Ip_GetEdgeNumbers( + config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]));/* CCW counter*/ + + data->abs_counter = (int32_t)( + +(data->counter_CW + EMIOS_ICU_IP_COUNTER_MASK * + data->emios_cw_overflow_count) + -(data->counter_CCW + EMIOS_ICU_IP_COUNTER_MASK * + data->emios_ccw_overflow_count)); + + LOG_DBG("ABS_COUNT = %d CW = %u OverFlow_CW = %u CCW = %u Overflow_CCW = %u", + data->abs_counter, data->counter_CW, + data->emios_cw_overflow_count, + data->counter_CCW, data->emios_ccw_overflow_count); + + return 0; +} + +static int qdec_s32_ch_get(const struct device *dev, enum sensor_channel ch, + struct sensor_value *val) +{ + struct qdec_s32_data *data = dev->data; + + double rotation = (data->abs_counter * 2.0 * M_PI) / data->micro_ticks_per_rev; + + switch (ch) { + case SENSOR_CHAN_ROTATION: + sensor_value_from_double(val, rotation); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api qdec_s32_api = { + .sample_fetch = &qdec_s32_fetch, + .channel_get = &qdec_s32_ch_get, +}; + +static int qdec_s32_initialize(const struct device *dev) +{ + const struct qdec_s32_config *config = dev->config; + uint8_t emios_inst, emios_hw_ch_cw, emios_hw_ch_ccw; + + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + + if (Trgmux_Ip_Init(config->trgmux_config)) { + LOG_ERR("Could not initialize Trgmux"); + return -EINVAL; + } + + LOG_DBG("TRGMUX ACCESS Input[0] =%d Output[0]=%d", + config->trgmux_config->paxLogicTrigger[0]->Input, + config->trgmux_config->paxLogicTrigger[0]->Output); + + if (Lcu_Ip_Init(config->lcu_config)) { + LOG_ERR("Could not initialize Lcu"); + return -EINVAL; + } + + /* Unmask relevant LCU OUT Channels */ + Lcu_Ip_SyncOutputValueType EncLcuEnable[4U]; + + EncLcuEnable[0].LogicOutputId = LCU_LOGIC_OUTPUT_0; + EncLcuEnable[0].Value = 1U; + EncLcuEnable[1].LogicOutputId = LCU_LOGIC_OUTPUT_1; + EncLcuEnable[1].Value = 1U; + EncLcuEnable[2].LogicOutputId = LCU_LOGIC_OUTPUT_2; + EncLcuEnable[2].Value = 1U; + EncLcuEnable[3].LogicOutputId = LCU_LOGIC_OUTPUT_3; + EncLcuEnable[3].Value = 1U; + Lcu_Ip_SetSyncOutputEnable(EncLcuEnable, 4U); + + emios_inst = config->emios_inst; + emios_hw_ch_cw = config->emios_channels[EMIOS_CW_CH_IDX]; + emios_hw_ch_ccw = config->emios_channels[EMIOS_CCW_CH_IDX]; + + /* Initialize the positions of the eMios hw channels used for QDEC + * to be beyond the eMios pwm hw channels. Currently only pwm and qdec + * are using the eMios channels so qdec ones are the last two. + */ + eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw] + = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 2; + eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw] + = EMIOS_ICU_IP_NUM_OF_CHANNELS_USED - 1; + + /* Set Overflow Notification for eMIOS channels meant + * for Clockwise and Counterclock rotation counters + */ + eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_cw]] + .eMiosOverflowNotification = config->emios_cw_overflow_cb; + eMios_Icu_Ip_ChState[eMios_Icu_Ip_IndexInChState[emios_inst][emios_hw_ch_ccw]] + .eMiosOverflowNotification = config->emios_ccw_overflow_cb; + + Emios_Icu_Ip_SetInitialCounterValue( + config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX], (uint32_t)0x1U); + Emios_Icu_Ip_SetInitialCounterValue( + config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX], (uint32_t)0x1U); + + Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst, + config->emios_channels[EMIOS_CW_CH_IDX], + EMIOS_ICU_IP_COUNTER_MASK); + Emios_Icu_Ip_SetMaxCounterValue(config->emios_inst, + config->emios_channels[EMIOS_CCW_CH_IDX], + EMIOS_ICU_IP_COUNTER_MASK); + + /* This API sets MCB/EMIOS_ICU_MODE_EDGE_COUNTER mode */ + Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CW_CH_IDX]); + Emios_Icu_Ip_EnableEdgeCount(config->emios_inst, config->emios_channels[EMIOS_CCW_CH_IDX]); + + LOG_DBG("Init complete"); + + return 0; +} + +#define EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \ + static void qdec##n##_emios_overflow_count_cw_callback(void) \ + { \ + qdec_emios_overflow_count_cw_callback(DEVICE_DT_INST_GET(n)); \ + } \ + \ + static void qdec##n##_emios_overflow_count_ccw_callback(void) \ + { \ + qdec_emios_overflow_count_ccw_callback(DEVICE_DT_INST_GET(n)); \ + } + +#define EMIOS_NXP_S32_INSTANCE_CHECK(idx, node_id) \ + ((DT_REG_ADDR(node_id) == IP_EMIOS_##idx##_BASE) ? idx : 0) + +#define EMIOS_NXP_S32_GET_INSTANCE(node_id) \ + LISTIFY(__DEBRACKET eMIOS_INSTANCE_COUNT, EMIOS_NXP_S32_INSTANCE_CHECK, (|), node_id) + +#define LCU_NXP_S32_INSTANCE_CHECK(idx, node_id) \ + ((DT_REG_ADDR(node_id) == IP_LCU_##idx##_BASE) ? idx : 0) + +#define LCU_NXP_S32_GET_INSTANCE(node_id) \ + LISTIFY(__DEBRACKET LCU_INSTANCE_COUNT, LCU_NXP_S32_INSTANCE_CHECK, (|), node_id) + +#define TRGMUX_NXP_S32_INSTANCE_CHECK(node_id) \ + ((DT_REG_ADDR(node_id) == IP_TRGMUX_BASE) ? 0 : -1) + +#define TRGMUX_NXP_S32_GET_INSTANCE(node_id) TRGMUX_NXP_S32_INSTANCE_CHECK(node_id) + +/* LCU Logic Input Configuration */ +#define LogicInputCfg_Common(n, mux_sel_idx) \ + { \ + .MuxSel = DT_INST_PROP_BY_IDX(n, lcu_mux_sel, mux_sel_idx), \ + .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \ + .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \ + }; +#define LogicInput_Config_Common(n, hw_lc_input_id, logic_input_n_cfg) \ + { \ + .xLogicInputId = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .HwLcInputId = DT_INST_PROP_BY_IDX(n, lcu_input_idx, hw_lc_input_id), \ + }, \ + .pxLcInputConfig = &logic_input_n_cfg, \ + }; + +/* LCU Logic Output Configuration */ +#define LogicOutputCfg_Common(En_Debug_Mode, Lut_Control, Lut_Rise_Filt, Lut_Fall_Filt) \ + { \ + .EnDebugMode = (boolean)En_Debug_Mode, \ + .LutControl = Lut_Control, \ + .LutRiseFilt = Lut_Rise_Filt, \ + .LutFallFilt = Lut_Fall_Filt, \ + .EnLutDma = (boolean)FALSE, \ + .EnForceDma = (boolean)FALSE, \ + .EnLutInt = (boolean)FALSE, \ + .EnForceInt = (boolean)FALSE, \ + .InvertOutput = (boolean)FALSE, \ + .ForceSignalSel = 0U, \ + .ClearForceMode = LCU_IP_CLEAR_FORCE_SIGNAL_IMMEDIATE, \ + .ForceSyncSel = LCU_IP_SYNC_SEL_INPUT0, \ + }; +#define LogicOutput_Config_Common(n, logic_output_cfg, hw_lc_output_id) \ + { \ + .xLogicOutputId = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .HwLcOutputId = hw_lc_output_id, \ + .IntCallback = NULL_PTR, \ + }, \ + .pxLcOutputConfig = &logic_output_cfg, \ + }; + +#define LCU_IP_INIT_CONFIG(n) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_0_Cfg = \ + LogicInputCfg_Common(n, 0) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_1_Cfg = \ + LogicInputCfg_Common(n, 1) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_2_Cfg = \ + LogicInputCfg_Common(n, 2) \ + const Lcu_Ip_LogicInputConfigType LogicInput##n##_3_Cfg = \ + LogicInputCfg_Common(n, 3) \ + \ + const Lcu_Ip_LogicInputType LogicInput##n##_0_Config = \ + LogicInput_Config_Common(n, 0, LogicInput##n##_0_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_1_Config = \ + LogicInput_Config_Common(n, 1, LogicInput##n##_1_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_2_Config = \ + LogicInput_Config_Common(n, 2, LogicInput##n##_2_Cfg) \ + const Lcu_Ip_LogicInputType LogicInput##n##_3_Config = \ + LogicInput_Config_Common(n, 3, LogicInput##n##_3_Cfg) \ + \ + const Lcu_Ip_LogicInputType \ + *const Lcu_Ip_ppxLogicInputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INPUTS] = { \ + &LogicInput##n##_0_Config, \ + &LogicInput##n##_1_Config, \ + &LogicInput##n##_2_Config, \ + &LogicInput##n##_3_Config, \ + }; \ + \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_0_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_DISABLE, LCU_O0_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 1), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 2)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_1_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_DISABLE, LCU_O1_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 4), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 5)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_2_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_ENABLE, LCU_O2_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 7), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 8)) \ + const Lcu_Ip_LogicOutputConfigType LogicOutput##n##_3_Cfg = LogicOutputCfg_Common( \ + LCU_IP_DEBUG_ENABLE, LCU_O3_LUT, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 10), \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 11)) \ + \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_0_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_0_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 0)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_1_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_1_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 3)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_2_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_2_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 6)) \ + const Lcu_Ip_LogicOutputType LogicOutput##n##_3_Config = \ + LogicOutput_Config_Common(n, LogicOutput##n##_3_Cfg, \ + DT_INST_PROP_BY_IDX(n, lcu_output_filter_config, 9)) \ + \ + const Lcu_Ip_LogicOutputType \ + *const Lcu_Ip_ppxLogicOutputArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \ + &LogicOutput##n##_0_Config, \ + &LogicOutput##n##_1_Config, \ + &LogicOutput##n##_2_Config, \ + &LogicOutput##n##_3_Config, \ + }; \ + \ + const Lcu_Ip_LogicInputConfigType Lcu_Ip_LogicInputResetConfig##n = { \ + .MuxSel = LCU_IP_MUX_SEL_LOGIC_0, \ + .SwSynMode = LCU_IP_SW_SYNC_IMMEDIATE, \ + .SwValue = LCU_IP_SW_OVERRIDE_LOGIC_LOW, \ + }; \ + \ + const Lcu_Ip_LogicOutputConfigType Lcu_Ip_LogicOutputResetConfig##n = \ + LogicOutputCfg_Common(LCU_IP_DEBUG_DISABLE, 0U, 0U, 0U) \ + \ + const Lcu_Ip_LogicInstanceType LcuLogicInstance##n##_0_Config = { \ + .HwInstId = LCU_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, lcu)), \ + .NumLogicCellConfig = 0U, \ + .ppxLogicCellConfigArray = NULL_PTR, \ + .OperationMode = LCU_IP_INTERRUPT_MODE, \ + }; \ + const Lcu_Ip_LogicInstanceType \ + *const Lcu_Ip_ppxLogicInstanceArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_INSTANCES] = { \ + &LcuLogicInstance##n##_0_Config, \ + }; \ + \ + Lcu_Ip_HwOutputStateType HwOutput##n##_0_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_1_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_2_State_Config; \ + Lcu_Ip_HwOutputStateType HwOutput##n##_3_State_Config; \ + Lcu_Ip_HwOutputStateType \ + *Lcu_Ip_ppxHwOutputStateArray##n##_Config[LCU_IP_NOF_CFG_LOGIC_OUTPUTS] = { \ + &HwOutput##n##_0_State_Config, \ + &HwOutput##n##_1_State_Config, \ + &HwOutput##n##_2_State_Config, \ + &HwOutput##n##_3_State_Config, \ + }; \ + \ + const Lcu_Ip_InitType Lcu_Ip_Init_Config##n = { \ + .ppxHwOutputStateArray = &Lcu_Ip_ppxHwOutputStateArray##n##_Config[0], \ + .ppxLogicInstanceConfigArray = &Lcu_Ip_ppxLogicInstanceArray##n##_Config[0], \ + .pxLogicOutputResetConfigArray = &Lcu_Ip_LogicOutputResetConfig##n, \ + .pxLogicInputResetConfigArray = &Lcu_Ip_LogicInputResetConfig##n, \ + .ppxLogicOutputConfigArray = &Lcu_Ip_ppxLogicOutputArray##n##_Config[0], \ + .ppxLogicInputConfigArray = &Lcu_Ip_ppxLogicInputArray##n##_Config[0], \ + }; + +#define Trgmux_Ip_LogicTrigger_Config(n, logic_channel, output, input) \ + { \ + .LogicChannel = logic_channel, \ + .Output = output, \ + .Input = input, \ + .HwInstId = TRGMUX_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, trgmux)), \ + .Lock = (boolean)FALSE, \ + }; + +#define TRGMUX_IP_INIT_CONFIG(n) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_0_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 0), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 1), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 2)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_1_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 3), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 4), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 5)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_2_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 6), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 7), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 8)) \ + const Trgmux_Ip_LogicTriggerType \ + Trgmux_Ip_LogicTrigger##n##_3_Config = Trgmux_Ip_LogicTrigger_Config(n, \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 9), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 10), \ + DT_INST_PROP_BY_IDX(n, trgmux_io_config, 11)) \ + const Trgmux_Ip_InitType Trgmux_Ip_Init_##n##_Config = { \ + .paxLogicTrigger = { \ + &Trgmux_Ip_LogicTrigger##n##_0_Config, \ + &Trgmux_Ip_LogicTrigger##n##_1_Config, \ + &Trgmux_Ip_LogicTrigger##n##_2_Config, \ + &Trgmux_Ip_LogicTrigger##n##_3_Config, \ + }, \ + }; + + +#define QDEC_NXP_S32_INIT(n) \ + \ + static struct qdec_s32_data qdec_s32_##n##_data = { \ + .micro_ticks_per_rev = (double)(DT_INST_PROP(n, micro_ticks_per_rev) / 1000000),\ + .counter_CW = 1, \ + .counter_CCW = 1, \ + }; \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + TRGMUX_IP_INIT_CONFIG(n) \ + LCU_IP_INIT_CONFIG(n) \ + EMIOS_NXP_S32_MCB_OVERFLOW_CALLBACK(n) \ + \ + static const struct qdec_s32_config qdec_s32_##n##_config = { \ + .emios_inst = EMIOS_NXP_S32_GET_INSTANCE(DT_INST_PHANDLE(n, emios)), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .trgmux_config = &Trgmux_Ip_Init_##n##_Config, \ + .lcu_config = &Lcu_Ip_Init_Config##n, \ + .emios_channels = {DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CW_CH_IDX), \ + DT_INST_PROP_BY_IDX(n, emios_channels, EMIOS_CCW_CH_IDX)}, \ + .emios_cw_overflow_cb = &qdec##n##_emios_overflow_count_cw_callback, \ + .emios_ccw_overflow_cb = &qdec##n##_emios_overflow_count_ccw_callback, \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_s32_initialize, NULL, &qdec_s32_##n##_data, \ + &qdec_s32_##n##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &qdec_s32_api); + +DT_INST_FOREACH_STATUS_OKAY(QDEC_NXP_S32_INIT) diff --git a/drivers/sensor/sensor_shell.c b/drivers/sensor/sensor_shell.c index bfeac4e452f..b0485b8378a 100644 --- a/drivers/sensor/sensor_shell.c +++ b/drivers/sensor/sensor_shell.c @@ -45,7 +45,7 @@ LOG_MODULE_REGISTER(sensor_shell); "Get or set the trigger type on a sensor. Currently only supports `data_ready`.\n" \ " " -const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { +static const char *sensor_channel_name[SENSOR_CHAN_COMMON_COUNT] = { [SENSOR_CHAN_ACCEL_X] = "accel_x", [SENSOR_CHAN_ACCEL_Y] = "accel_y", [SENSOR_CHAN_ACCEL_Z] = "accel_z", @@ -125,6 +125,33 @@ static const char *sensor_attribute_name[SENSOR_ATTR_COMMON_COUNT] = { [SENSOR_ATTR_BATCH_DURATION] = "batch_dur", }; +enum sample_stats_state { + SAMPLE_STATS_STATE_UNINITIALIZED = 0, + SAMPLE_STATS_STATE_ENABLED, + SAMPLE_STATS_STATE_DISABLED, +}; + +struct sample_stats { + int64_t accumulator; + uint64_t sample_window_start; + uint32_t count; + enum sample_stats_state state; +}; + +static struct sample_stats sensor_stats[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES][SENSOR_CHAN_ALL]; + +static const struct device *sensor_trigger_devices[CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES]; + +static int find_sensor_trigger_device(const struct device *sensor) +{ + for (int i = 0; i < CONFIG_SENSOR_SHELL_MAX_TRIGGER_DEVICES; i++) { + if (sensor_trigger_devices[i] == sensor) { + return i; + } + } + return -1; +} + /* Forward declaration */ static void data_ready_trigger_handler(const struct device *sensor, const struct sensor_trigger *trigger); @@ -882,25 +909,27 @@ static int cmd_get_sensor_info(const struct shell *sh, size_t argc, char **argv) #endif } -enum sample_stats_state { - SAMPLE_STATS_STATE_UNINITIALIZED = 0, - SAMPLE_STATS_STATE_ENABLED, - SAMPLE_STATS_STATE_DISABLED, -}; - -struct sample_stats { - int64_t accumulator; - uint32_t count; - uint64_t sample_window_start; - enum sample_stats_state state; -}; - static void data_ready_trigger_handler(const struct device *sensor, const struct sensor_trigger *trigger) { - static struct sample_stats stats[SENSOR_CHAN_ALL]; const int64_t now = k_uptime_get(); struct sensor_value value; + int sensor_idx = find_sensor_trigger_device(sensor); + struct sample_stats *stats; + int sensor_name_len_before_at; + const char *sensor_name; + + if (sensor_idx < 0) { + LOG_ERR("Unable to find sensor trigger device"); + return; + } + stats = sensor_stats[sensor_idx]; + sensor_name = sensor_trigger_devices[sensor_idx]->name; + if (sensor_name) { + sensor_name_len_before_at = strchr(sensor_name, '@') - sensor_name; + } else { + sensor_name_len_before_at = 0; + } if (sensor_sample_fetch(sensor)) { LOG_ERR("Failed to fetch samples on data ready handler"); @@ -919,9 +948,16 @@ static void data_ready_trigger_handler(const struct device *sensor, } rc = sensor_channel_get(sensor, i, &value); - if (rc == -ENOTSUP && stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) { - /* Stop reading this channel if the driver told us it's not supported. */ - stats[i].state = SAMPLE_STATS_STATE_DISABLED; + if (stats[i].state == SAMPLE_STATS_STATE_UNINITIALIZED) { + if (rc == -ENOTSUP) { + /* + * Stop reading this channel if the driver told us + * it's not supported. + */ + stats[i].state = SAMPLE_STATS_STATE_DISABLED; + } else if (rc == 0) { + stats[i].state = SAMPLE_STATS_STATE_ENABLED; + } } if (rc != 0) { /* Skip on any error. */ @@ -937,7 +973,10 @@ static void data_ready_trigger_handler(const struct device *sensor, value.val1 = micro_value / 1000000; value.val2 = (int32_t)llabs(micro_value - (value.val1 * 1000000)); - LOG_INF("chan=%d, num_samples=%u, data=%d.%06d", i, stats[i].count, + LOG_INF("sensor=%.*s, chan=%s, num_samples=%u, data=%d.%06d", + sensor_name_len_before_at, sensor_name, + sensor_channel_name[i], + stats[i].count, value.val1, value.val2); stats[i].accumulator = 0; @@ -973,11 +1012,37 @@ static int cmd_trig_sensor(const struct shell *sh, size_t argc, char **argv) /* Parse on/off */ if (strcmp(argv[2], "on") == 0) { - err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, - sensor_trigger_table[trigger].handler); + /* find a free entry in sensor_trigger_devices[] */ + int sensor_idx = find_sensor_trigger_device(NULL); + + if (sensor_idx < 0) { + shell_error(sh, "Unable to support more simultaneous sensor trigger" + " devices"); + err = -ENOTSUP; + } else { + struct sample_stats *stats = sensor_stats[sensor_idx]; + + sensor_trigger_devices[sensor_idx] = dev; + /* reset stats state to UNINITIALIZED */ + for (unsigned int ch = 0; ch < SENSOR_CHAN_ALL; ch++) { + stats[ch].state = SAMPLE_STATS_STATE_UNINITIALIZED; + } + err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, + sensor_trigger_table[trigger].handler); + } } else if (strcmp(argv[2], "off") == 0) { /* Clear the handler for the given trigger on this device */ err = sensor_trigger_set(dev, &sensor_trigger_table[trigger].trigger, NULL); + if (!err) { + /* find entry in sensor_trigger_devices[] and free it */ + int sensor_idx = find_sensor_trigger_device(dev); + + if (sensor_idx < 0) { + shell_error(sh, "Unable to find sensor device in trigger array"); + } else { + sensor_trigger_devices[sensor_idx] = NULL; + } + } } else { shell_error(sh, "Pass 'on' or 'off' to enable/disable trigger"); return -EINVAL; diff --git a/drivers/sensor/stm32_temp/stm32_temp.c b/drivers/sensor/stm32_temp/stm32_temp.c index 7ad72490e91..5e594b0fe0c 100644 --- a/drivers/sensor/stm32_temp/stm32_temp.c +++ b/drivers/sensor/stm32_temp/stm32_temp.c @@ -67,6 +67,7 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_temp_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { return -ENOTSUP; @@ -80,8 +81,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_TEMPSENSOR); + LL_ADC_PATH_INTERNAL_TEMPSENSOR | path); + k_usleep(LL_ADC_DELAY_TEMPSENSOR_STAB_US); rc = adc_read(data->adc, sp); @@ -89,6 +92,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_TEMPSENSOR); + unlock: k_mutex_unlock(&data->mutex); diff --git a/drivers/sensor/stm32_vbat/stm32_vbat.c b/drivers/sensor/stm32_vbat/stm32_vbat.c index 10c035baacf..8379670fab3 100644 --- a/drivers/sensor/stm32_vbat/stm32_vbat.c +++ b/drivers/sensor/stm32_vbat/stm32_vbat.c @@ -38,6 +38,7 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_vbat_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; @@ -52,14 +53,19 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_VBAT); + LL_ADC_PATH_INTERNAL_VBAT | path); rc = adc_read(data->adc, sp); if (rc == 0) { data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_VBAT); + unlock: k_mutex_unlock(&data->mutex); diff --git a/drivers/sensor/stm32_vref/stm32_vref.c b/drivers/sensor/stm32_vref/stm32_vref.c index 4dcb8324076..3532d2aeddd 100644 --- a/drivers/sensor/stm32_vref/stm32_vref.c +++ b/drivers/sensor/stm32_vref/stm32_vref.c @@ -38,6 +38,7 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel struct stm32_vref_data *data = dev->data; struct adc_sequence *sp = &data->adc_seq; int rc; + uint32_t path; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { return -ENOTSUP; @@ -51,8 +52,10 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel goto unlock; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), - LL_ADC_PATH_INTERNAL_VREFINT); + LL_ADC_PATH_INTERNAL_VREFINT | path); + #ifdef LL_ADC_DELAY_VREFINT_STAB_US k_usleep(LL_ADC_DELAY_VREFINT_STAB_US); #endif @@ -62,6 +65,11 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel data->raw = data->sample_buffer; } + path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base)); + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base), + path &= ~LL_ADC_PATH_INTERNAL_VREFINT); + + unlock: k_mutex_unlock(&data->mutex); diff --git a/drivers/sensor/stmemsc/CMakeLists.txt b/drivers/sensor/stmemsc/CMakeLists.txt index 6ea84e2063e..d6c2c40f68f 100644 --- a/drivers/sensor/stmemsc/CMakeLists.txt +++ b/drivers/sensor/stmemsc/CMakeLists.txt @@ -9,3 +9,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_I2C stmemsc_i2c.c) zephyr_library_sources_ifdef(CONFIG_I3C stmemsc_i3c.c) zephyr_library_sources_ifdef(CONFIG_SPI stmemsc_spi.c) +zephyr_library_sources(stmemsc_mdelay.c) diff --git a/drivers/sensor/stmemsc/stmemsc.h b/drivers/sensor/stmemsc/stmemsc.h index d4e6e0767bb..bd87e269b08 100644 --- a/drivers/sensor/stmemsc/stmemsc.h +++ b/drivers/sensor/stmemsc/stmemsc.h @@ -15,22 +15,18 @@ #include #include - -static inline void stmemsc_mdelay(uint32_t millisec) -{ - k_msleep(millisec); -} +void stmemsc_mdelay(uint32_t millisec); #ifdef CONFIG_I2C /* * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with - * stmemsc i2c APIs. + * standard stmemsc i2c APIs. */ #define STMEMSC_CTX_I2C(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_i2c_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_i2c_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_i2c_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_i2c_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -38,18 +34,49 @@ int stmemsc_i2c_read(const struct i2c_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); int stmemsc_i2c_write(const struct i2c_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * specific stmemsc i2c APIs that set reg_addr MSB to '1' in order to allow + * multiple read/write operations. This is common in some STMEMSC drivers + */ +#define STMEMSC_CTX_I2C_INCR(stmdev_ctx_ptr) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)stmemsc_i2c_read_incr, \ + .write_reg = (stmdev_write_ptr)stmemsc_i2c_write_incr, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + +int stmemsc_i2c_read_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); +int stmemsc_i2c_write_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * custom stmemsc i2c APIs specified by driver. + */ +#define STMEMSC_CTX_I2C_CUSTOM(stmdev_ctx_ptr, i2c_rd_api, i2c_wr_api) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)i2c_rd_api, \ + .write_reg = (stmdev_write_ptr)i2c_wr_api, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + #endif #ifdef CONFIG_I3C /* * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with - * stmemsc i3c APIs. + * standard stmemsc i3c APIs. */ #define STMEMSC_CTX_I3C(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_i3c_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_i3c_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_i3c_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_i3c_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -66,9 +93,9 @@ int stmemsc_i3c_write(void *stmemsc, */ #define STMEMSC_CTX_SPI(stmdev_ctx_ptr) \ .ctx = { \ - .read_reg = (stmdev_read_ptr) stmemsc_spi_read, \ - .write_reg = (stmdev_write_ptr) stmemsc_spi_write, \ - .mdelay = (stmdev_mdelay_ptr) stmemsc_mdelay, \ + .read_reg = (stmdev_read_ptr)stmemsc_spi_read, \ + .write_reg = (stmdev_write_ptr)stmemsc_spi_write, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ .handle = (void *)stmdev_ctx_ptr \ } @@ -76,5 +103,36 @@ int stmemsc_spi_read(const struct spi_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); int stmemsc_spi_write(const struct spi_dt_spec *stmemsc, uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * specific stmemsc sp APIs that set reg_addr bit6 to '1' in order to allow + * multiple read/write operations. This is common in some STMEMSC drivers + */ +#define STMEMSC_CTX_SPI_INCR(stmdev_ctx_ptr) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)stmemsc_spi_read_incr, \ + .write_reg = (stmdev_write_ptr)stmemsc_spi_write_incr, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + +int stmemsc_spi_read_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); +int stmemsc_spi_write_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len); + +/* + * Populate the stmdev_ctx_t structure pointed by stmdev_ctx_ptr with + * custom stmemsc spi APIs specified by driver. + */ +#define STMEMSC_CTX_SPI_CUSTOM(stmdev_ctx_ptr, spi_rd_api, spi_wr_api) \ + .ctx = { \ + .read_reg = (stmdev_read_ptr)spi_rd_api, \ + .write_reg = (stmdev_write_ptr)spi_wr_api, \ + .mdelay = (stmdev_mdelay_ptr)stmemsc_mdelay, \ + .handle = (void *)stmdev_ctx_ptr \ + } + #endif #endif /* ZEPHYR_DRIVERS_SENSOR_STMEMSC_STMEMSC_H_ */ diff --git a/drivers/sensor/stmemsc/stmemsc_i2c.c b/drivers/sensor/stmemsc/stmemsc_i2c.c index 1b7f1833293..bf6ddebbd4f 100644 --- a/drivers/sensor/stmemsc/stmemsc_i2c.c +++ b/drivers/sensor/stmemsc/stmemsc_i2c.c @@ -9,14 +9,31 @@ #include "stmemsc.h" + /* Enable address auto-increment on some stmemsc sensors */ +#define STMEMSC_I2C_ADDR_AUTO_INCR BIT(7) + int stmemsc_i2c_read(const struct i2c_dt_spec *stmemsc, - uint8_t reg_addr, uint8_t *value, uint8_t len) + uint8_t reg_addr, uint8_t *value, uint8_t len) { return i2c_burst_read_dt(stmemsc, reg_addr, value, len); } int stmemsc_i2c_write(const struct i2c_dt_spec *stmemsc, - uint8_t reg_addr, uint8_t *value, uint8_t len) + uint8_t reg_addr, uint8_t *value, uint8_t len) { return i2c_burst_write_dt(stmemsc, reg_addr, value, len); } + +int stmemsc_i2c_read_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_I2C_ADDR_AUTO_INCR; + return stmemsc_i2c_read(stmemsc, reg_addr, value, len); +} + +int stmemsc_i2c_write_incr(const struct i2c_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_I2C_ADDR_AUTO_INCR; + return stmemsc_i2c_write(stmemsc, reg_addr, value, len); +} diff --git a/drivers/sensor/stmemsc/stmemsc_mdelay.c b/drivers/sensor/stmemsc/stmemsc_mdelay.c new file mode 100644 index 00000000000..0123e95b14f --- /dev/null +++ b/drivers/sensor/stmemsc/stmemsc_mdelay.c @@ -0,0 +1,15 @@ +/* ST Microelectronics STMEMS hal i/f + * + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * zephyrproject-rtos/modules/hal/st/sensor/stmemsc/ + */ + +#include "stmemsc.h" + +void stmemsc_mdelay(uint32_t millisec) +{ + k_msleep(millisec); +} diff --git a/drivers/sensor/stmemsc/stmemsc_spi.c b/drivers/sensor/stmemsc/stmemsc_spi.c index 0d3557ce135..3d728c78d8b 100644 --- a/drivers/sensor/stmemsc/stmemsc_spi.c +++ b/drivers/sensor/stmemsc/stmemsc_spi.c @@ -11,6 +11,9 @@ #define SPI_READ (1 << 7) + /* Enable address auto-increment on some stmemsc sensors */ +#define STMEMSC_SPI_ADDR_AUTO_INCR BIT(6) + /* * SPI read */ @@ -56,3 +59,17 @@ int stmemsc_spi_write(const struct spi_dt_spec *stmemsc, return spi_write_dt(stmemsc, &tx); } + +int stmemsc_spi_read_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_SPI_ADDR_AUTO_INCR; + return stmemsc_spi_read(stmemsc, reg_addr, value, len); +} + +int stmemsc_spi_write_incr(const struct spi_dt_spec *stmemsc, + uint8_t reg_addr, uint8_t *value, uint8_t len) +{ + reg_addr |= STMEMSC_SPI_ADDR_AUTO_INCR; + return stmemsc_spi_write(stmemsc, reg_addr, value, len); +} diff --git a/drivers/sensor/stts751/Kconfig b/drivers/sensor/stts751/Kconfig index d048e117e10..d4bb8eeb700 100644 --- a/drivers/sensor/stts751/Kconfig +++ b/drivers/sensor/stts751/Kconfig @@ -7,6 +7,7 @@ menuconfig STTS751 bool "STTS751 temperature sensor" default y depends on DT_HAS_ST_STTS751_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STMEMSC select USE_STDC_STTS751 diff --git a/drivers/sensor/tmp108/tmp108.c b/drivers/sensor/tmp108/tmp108.c index 13480ff7aef..79f31a305ab 100644 --- a/drivers/sensor/tmp108/tmp108.c +++ b/drivers/sensor/tmp108/tmp108.c @@ -165,6 +165,7 @@ static int tmp108_attr_get(const struct device *dev, struct sensor_value *val) { int result; + uint16_t tmp_val; if (chan != SENSOR_CHAN_AMBIENT_TEMP && chan != SENSOR_CHAN_ALL) { return -ENOTSUP; @@ -174,7 +175,9 @@ static int tmp108_attr_get(const struct device *dev, case SENSOR_ATTR_CONFIGURATION: result = tmp108_reg_read(dev, TI_TMP108_REG_CONF, - (uint16_t *) &(val->val1)); + &tmp_val); + val->val1 = tmp_val; + val->val2 = 0; break; default: return -ENOTSUP; diff --git a/drivers/sensor/tsl2540/tsl2540.c b/drivers/sensor/tsl2540/tsl2540.c index fb3060d136e..98516d5f296 100644 --- a/drivers/sensor/tsl2540/tsl2540.c +++ b/drivers/sensor/tsl2540/tsl2540.c @@ -162,8 +162,12 @@ static int tsl2540_attr_set(const struct device *dev, enum sensor_channel chan, k_sem_take(&data->sem, K_FOREVER); - i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_ENABLE_ADDR, TSL2540_ENABLE_MASK & - ~TSL2540_ENABLE_CONF); + ret = i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_ENABLE_ADDR, TSL2540_ENABLE_MASK & + ~TSL2540_ENABLE_CONF); + if (ret) { + k_sem_give(&data->sem); + return ret; + } #if CONFIG_TSL2540_TRIGGER if (chan == SENSOR_CHAN_LIGHT) { @@ -288,6 +292,7 @@ static int tsl2540_init(const struct device *dev) { const struct tsl2540_config *cfg = dev->config; struct tsl2540_data *data = dev->data; + int ret; data->enable_mode = TSL2540_ENABLE_DISABLE; @@ -298,9 +303,18 @@ static int tsl2540_init(const struct device *dev) return -ENODEV; } - i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_REG_PERS, 1); - i2c_reg_update_byte_dt(&cfg->i2c_spec, TSL2540_CFG3_ADDR, TSL2540_CFG3_MASK, - TSL2540_CFG3_DFLT); + ret = i2c_reg_write_byte_dt(&cfg->i2c_spec, TSL2540_REG_PERS, 1); + if (ret) { + LOG_ERR("Failed to setup interrupt persistence filter"); + return ret; + } + + ret = i2c_reg_update_byte_dt(&cfg->i2c_spec, TSL2540_CFG3_ADDR, TSL2540_CFG3_MASK, + TSL2540_CFG3_DFLT); + if (ret) { + LOG_ERR("Failed to set configuration"); + return ret; + } if (tsl2540_setup(dev)) { LOG_ERR("Failed to setup ambient light functionality"); diff --git a/drivers/sensor/tsl2561/tsl2561.c b/drivers/sensor/tsl2561/tsl2561.c index 42efffb2242..0e5c0209b6b 100644 --- a/drivers/sensor/tsl2561/tsl2561.c +++ b/drivers/sensor/tsl2561/tsl2561.c @@ -136,7 +136,7 @@ static int tsl2561_sample_fetch(const struct device *dev, enum sensor_channel ch const struct tsl2561_config *config = dev->config; struct tsl2561_data *data = dev->data; uint8_t bytes[2]; - uint8_t ret; + int ret; if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_LIGHT) { LOG_ERR("Unsupported sensor channel"); diff --git a/drivers/sensor/vcnl36825t/CMakeLists.txt b/drivers/sensor/vcnl36825t/CMakeLists.txt new file mode 100644 index 00000000000..cbf96f6d2b7 --- /dev/null +++ b/drivers/sensor/vcnl36825t/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Juliane Schulze, deveritec Gmbh +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(vcnl36825t.c) diff --git a/drivers/sensor/vcnl36825t/Kconfig b/drivers/sensor/vcnl36825t/Kconfig new file mode 100644 index 00000000000..46d20598af4 --- /dev/null +++ b/drivers/sensor/vcnl36825t/Kconfig @@ -0,0 +1,12 @@ +# VCNL36825T Proximity Sensor configuration options + +# Copyright (c) 2024 Juliane Schulze, deveritec Gmbh +# SPDX-License-Identifier: Apache-2.0 + +config VCNL36825T + bool "VCNL36825T Proximity Sensor" + default y + depends on DT_HAS_VISHAY_VCNL36825T_ENABLED + select I2C + help + Enable driver for VCNL36825T sensors. diff --git a/drivers/sensor/vcnl36825t/vcnl36825t.c b/drivers/sensor/vcnl36825t/vcnl36825t.c new file mode 100644 index 00000000000..940943950a4 --- /dev/null +++ b/drivers/sensor/vcnl36825t/vcnl36825t.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2024 Juliane Schulze, deveritec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT vishay_vcnl36825t + +#include "vcnl36825t.h" + +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(VCNL36825T, CONFIG_SENSOR_LOG_LEVEL); + +static int vcnl36825t_read(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t *value) +{ + uint8_t rx_buf[2]; + int rc; + + rc = i2c_write_read_dt(spec, ®_addr, sizeof(reg_addr), rx_buf, sizeof(rx_buf)); + if (rc < 0) { + return rc; + } + + *value = sys_get_le16(rx_buf); + + return 0; +} + +static int vcnl36825t_write(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t value) +{ + uint8_t tx_buf[3] = {reg_addr}; + + sys_put_le16(value, &tx_buf[1]); + return i2c_write_dt(spec, tx_buf, sizeof(tx_buf)); +} + +static int vcnl36825t_update(const struct i2c_dt_spec *spec, uint8_t reg_addr, uint16_t mask, + uint16_t value) +{ + int rc; + uint16_t old_value, new_value; + + rc = vcnl36825t_read(spec, reg_addr, &old_value); + if (rc < 0) { + return rc; + } + + new_value = (old_value & ~mask) | (value & mask); + + if (new_value == old_value) { + return 0; + } + + return vcnl36825t_write(spec, reg_addr, new_value); +} + +#if CONFIG_PM_DEVICE +static int vcnl36825t_pm_action(const struct device *dev, enum pm_device_action action) +{ + const struct vcnl36825t_config *config = dev->config; + int rc = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF1, VCNL36825T_PS_ON_MSK, + VCNL36825T_PS_ON); + if (rc < 0) { + return rc; + } + + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_START); + if (rc < 0) { + return rc; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_STOP); + if (rc < 0) { + return rc; + } + + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF1, VCNL36825T_PS_ON_MSK, + VCNL36825T_PS_OFF); + if (rc < 0) { + return rc; + } + break; + default: + LOG_ERR("action %d not supported", (int)action); + return -ENOTSUP; + } + + return 0; +} + +#endif + +static int vcnl36825t_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct vcnl36825t_config *config = dev->config; + struct vcnl36825t_data *data = dev->data; + int rc; + +#if CONFIG_PM_DEVICE + enum pm_device_state state; + + (void)pm_device_state_get(dev, &state); + if (state != PM_DEVICE_STATE_ACTIVE) { + return -EBUSY; + } +#endif + + switch (chan) { + case SENSOR_CHAN_ALL: + case SENSOR_CHAN_PROX: + if (config->operation_mode == VCNL36825T_OPERATION_MODE_FORCE) { + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF3, + VCNL36825T_PS_TRIG_MSK, VCNL36825T_PS_TRIG_ONCE); + if (rc < 0) { + LOG_ERR("could not trigger proximity measurement %d", rc); + return rc; + } + + k_usleep(data->meas_timeout_us); + } + + rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_PS_DATA, &data->proximity); + if (rc < 0) { + LOG_ERR("could not fetch proximity measurement %d", rc); + return rc; + } + + break; + default: + LOG_ERR("invalid sensor channel"); + return -EINVAL; + } + + return 0; +} + +static int vcnl36825t_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct vcnl36825t_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ALL: + case SENSOR_CHAN_PROX: + val->val1 = data->proximity & VCNL36825T_OS_DATA_MSK; + val->val2 = 0; + break; + default: + return -ENOTSUP; + } + + return 0; +} + +/** + * @brief helper function to configure the registers + * + * @param dev pointer to the VCNL36825T instance + */ +static int vcnl36825t_init_registers(const struct device *dev) +{ + const struct vcnl36825t_config *config = dev->config; + struct vcnl36825t_data *data = dev->data; + + int rc; + uint16_t reg_value; + + /* reset registers as defined by the datasheet */ + const uint16_t resetValues[][2] = { + {VCNL36825T_REG_PS_CONF1, VCNL36825T_CONF1_DEFAULT}, + {VCNL36825T_REG_PS_CONF2, VCNL36825T_CONF2_DEFAULT}, + {VCNL36825T_REG_PS_CONF3, VCNL36825T_CONF3_DEFAULT}, + {VCNL36825T_REG_PS_THDL, VCNL36825T_THDL_DEFAULT}, + {VCNL36825T_REG_PS_THDH, VCNL36825T_THDH_DEFAULT}, + {VCNL36825T_REG_PS_CANC, VCNL36825T_CANC_DEFAULT}, + {VCNL36825T_REG_PS_CONF4, VCNL36825T_CONF4_DEFAULT}, + }; + + for (size_t i = 0; i < ARRAY_SIZE(resetValues); ++i) { + vcnl36825t_write(&config->i2c, resetValues[i][0], resetValues[i][1]); + } + + data->meas_timeout_us = 1; + + /* PS_CONF1 */ + reg_value = 0x01; /* must be set according to datasheet */ + reg_value |= VCNL36825T_PS_ON; + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF1, reg_value); + if (rc < 0) { + LOG_ERR("I2C for PS_ON returned %d", rc); + return -EIO; + } + + reg_value |= VCNL36825T_PS_CAL; + reg_value |= FIELD_PREP(1 << 9, 1); /* reserved, must be set by datasheet */ + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF1, reg_value); + if (rc < 0) { + LOG_ERR("I2C for PS_CAL returned %d", rc); + } + + /* PS_CONF2 */ + reg_value = 0; + + switch (config->period) { + case VCNL36825T_MEAS_PERIOD_10MS: + reg_value |= VCNL36825T_PS_PERIOD_10MS; + break; + case VCNL36825T_MEAS_PERIOD_20MS: + reg_value |= VCNL36825T_PS_PERIOD_20MS; + break; + case VCNL36825T_MEAS_PERIOD_40MS: + reg_value |= VCNL36825T_PS_PERIOD_40MS; + break; + case VCNL36825T_MEAS_PERIOD_80MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_PERIOD_80MS; + break; + } + + reg_value |= VCNL36825T_PS_PERS_1; + reg_value |= VCNL36825T_PS_ST_STOP; + + switch (config->proximity_it) { + case VCNL36825T_PROXIMITY_INTEGRATION_1T: + reg_value |= VCNL36825T_PS_IT_1T; + data->meas_timeout_us *= 1 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_1_5T: + reg_value |= VCNL36825T_PS_IT_1_5T; + data->meas_timeout_us *= 1.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_2T: + reg_value |= VCNL36825T_PS_IT_2T; + data->meas_timeout_us *= 2 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_2_5T: + reg_value |= VCNL36825T_PS_IT_2_5T; + data->meas_timeout_us *= 2.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_3T: + reg_value |= VCNL36825T_PS_IT_3T; + data->meas_timeout_us *= 3 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_3_5T: + reg_value |= VCNL36825T_PS_IT_3_5T; + data->meas_timeout_us *= 3.5 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_4T: + reg_value |= VCNL36825T_PS_IT_4T; + data->meas_timeout_us *= 4 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_8T: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_IT_8T; + data->meas_timeout_us *= 8 * VCNL36825T_FORCED_FACTOR_SCALE; + break; + } + + switch (config->multi_pulse) { + case VCNL38652T_MULTI_PULSE_1: + reg_value |= VCNL36825T_MPS_PULSES_1; + break; + case VCNL38652T_MULTI_PULSE_2: + reg_value |= VCNL36825T_MPS_PULSES_2; + break; + case VCNL38652T_MULTI_PULSE_4: + reg_value |= VCNL36825T_MPS_PULSES_4; + break; + case VCNL38652T_MULTI_PULSE_8: + __fallthrough; + default: + reg_value |= VCNL36825T_MPS_PULSES_8; + break; + } + + switch (config->proximity_itb) { + case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_25us: + reg_value |= VCNL36825T_PS_ITB_25us; + data->meas_timeout_us *= 25; + break; + case VCNL36825T_PROXIMITY_INTEGRATION_DURATION_50us: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_ITB_50us; + data->meas_timeout_us *= 50; + break; + } + + if (config->high_gain) { + reg_value |= VCNL36825T_PS_HG_HIGH; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF2, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF2 returned %d", rc); + return -EIO; + } + + /* PS_CONF3 */ + reg_value = 0; + + if (config->operation_mode == VCNL36825T_OPERATION_MODE_FORCE) { + reg_value |= VCNL36825T_PS_AF_FORCE; + } + + switch (config->laser_current) { + case VCNL36825T_LASER_CURRENT_10MS: + reg_value |= VCNL36825T_PS_I_VCSEL_10MA; + break; + case VCNL36825T_LASER_CURRENT_12MS: + reg_value |= VCNL36825T_PS_I_VCSEL_12MA; + break; + case VCNL36825T_LASER_CURRENT_14MS: + reg_value |= VCNL36825T_PS_I_VCSEL_14MA; + break; + case VCNL36825T_LASER_CURRENT_16MS: + reg_value |= VCNL36825T_PS_I_VCSEL_16MA; + break; + case VCNL36825T_LASER_CURRENT_18MS: + reg_value |= VCNL36825T_PS_I_VCSEL_18MA; + break; + case VCNL36825T_LASER_CURRENT_20MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_I_VCSEL_20MA; + break; + } + + if (config->high_dynamic_output) { + reg_value |= VCNL36825T_PS_HD_16BIT; + } + + if (config->sunlight_cancellation) { + reg_value |= VCNL36825T_PS_SC_ENABLED; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF3, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF3 returned %d", rc); + return -EIO; + } + + /* PS_CONF4 */ + reg_value = 0; + + if (config->low_power) { + reg_value |= VCNL36825T_PS_LPEN_ENABLED; + } + + switch (config->period) { + case VCNL36825T_MEAS_PERIOD_40MS: + reg_value |= VCNL36825T_PS_LPPER_40MS; + break; + case VCNL36825T_MEAS_PERIOD_80MS: + reg_value |= VCNL36825T_PS_LPPER_80MS; + break; + case VCNL36825T_MEAS_PERIOD_160MS: + reg_value |= VCNL36825T_PS_LPPER_160MS; + break; + case VCNL36825T_MEAS_PERIOD_320MS: + __fallthrough; + default: + reg_value |= VCNL36825T_PS_LPPER_320MS; + break; + } + + rc = vcnl36825t_write(&config->i2c, VCNL36825T_REG_PS_CONF4, reg_value); + if (rc < 0) { + LOG_ERR("I2C for setting PS_CONF4 returned %d", rc); + return -EIO; + } + + /* calculate measurement timeout + * Note: always add 1 to prevent corner case losses due to precision. + */ + data->meas_timeout_us = + (data->meas_timeout_us * VCNL36825T_FORCED_FACTOR_SUM) / + (VCNL36825T_FORCED_FACTOR_SCALE * VCNL36825T_FORCED_FACTOR_SCALE) + + 1; + + return 0; +} + +static int vcnl36825t_init(const struct device *dev) +{ + const struct vcnl36825t_config *config = dev->config; + int rc; + uint16_t reg_value; + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("device is not ready"); + return -ENODEV; + } + + rc = vcnl36825t_read(&config->i2c, VCNL36825T_REG_DEV_ID, ®_value); + if (rc < 0) { + LOG_ERR("could not read device id"); + return rc; + } + + if ((reg_value & VCNL36825T_ID_MSK) != VCNL36825T_DEVICE_ID) { + LOG_ERR("incorrect device id (%d)", reg_value); + return -EIO; + } + + LOG_INF("version code: 0x%X", + (unsigned int)FIELD_GET(VCNL36825T_VERSION_CODE_MSK, reg_value)); + + rc = vcnl36825t_init_registers(dev); + if (rc < 0) { + return rc; + } + + if (config->operation_mode == VCNL36825T_OPERATION_MODE_AUTO) { + rc = vcnl36825t_update(&config->i2c, VCNL36825T_REG_PS_CONF2, VCNL36825T_PS_ST_MSK, + VCNL36825T_PS_ST_START); + if (rc < 0) { + LOG_ERR("error starting measurement"); + return -EIO; + } + } + + return 0; +} + +static const struct sensor_driver_api vcnl36825t_driver_api = { + .sample_fetch = vcnl36825t_sample_fetch, + .channel_get = vcnl36825t_channel_get, +}; + +#define VCNL36825T_DEFINE(inst) \ + BUILD_ASSERT(!DT_INST_PROP(inst, low_power) || (DT_INST_PROP(inst, measurement_period) >= \ + VCNL36825T_PS_LPPER_VALUE_MIN_MS), \ + "measurement-period must be greater/equal 40 ms in low-power mode"); \ + BUILD_ASSERT( \ + DT_INST_PROP(inst, low_power) || (DT_INST_PROP(inst, measurement_period) <= \ + VCNL36825T_PS_PERIOD_VALUE_MAX_MS), \ + "measurement-period must be less/equal 80 ms with deactivated low-power mode"); \ + static struct vcnl36825t_data vcnl36825t_data_##inst; \ + static const struct vcnl36825t_config vcnl36825t_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + .operation_mode = DT_INST_ENUM_IDX(inst, operation_mode), \ + .period = DT_INST_ENUM_IDX(inst, measurement_period), \ + .proximity_it = DT_INST_ENUM_IDX(inst, proximity_it), \ + .proximity_itb = DT_INST_ENUM_IDX(inst, proximity_itb), \ + .multi_pulse = DT_INST_ENUM_IDX(inst, multi_pulse), \ + .low_power = DT_INST_PROP(inst, low_power), \ + .high_gain = DT_INST_PROP(inst, high_gain), \ + .laser_current = DT_INST_ENUM_IDX(inst, laser_current), \ + .high_dynamic_output = DT_INST_PROP(inst, high_dynamic_output), \ + .sunlight_cancellation = DT_INST_PROP(inst, sunlight_cancellation), \ + }; \ + IF_ENABLED(CONFIG_PM_DEVICE, (PM_DEVICE_DT_INST_DEFINE(inst, vcnl36825t_pm_action))); \ + SENSOR_DEVICE_DT_INST_DEFINE( \ + inst, vcnl36825t_init, \ + COND_CODE_1(CONFIG_PM_DEVICE, (PM_DEVICE_DT_INST_GET(inst)), (NULL)), \ + &vcnl36825t_data_##inst, &vcnl36825t_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &vcnl36825t_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(VCNL36825T_DEFINE) diff --git a/drivers/sensor/vcnl36825t/vcnl36825t.h b/drivers/sensor/vcnl36825t/vcnl36825t.h new file mode 100644 index 00000000000..8c022b34d2d --- /dev/null +++ b/drivers/sensor/vcnl36825t/vcnl36825t.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2024 Juliane Schulze, deveritec GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_VCNL36825T_VCNL36825T_H_ +#define ZEPHYR_DRIVERS_SENSOR_VCNL36825T_VCNL36825T_H_ + +#include +#include +#include +#include +#include + +#define VCNL36825T_REG_PS_CONF1 0x00 +#define VCNL36825T_REG_PS_CONF2 0x03 +#define VCNL36825T_REG_PS_CONF3 0x04 +#define VCNL36825T_REG_PS_THDL 0x05 +#define VCNL36825T_REG_PS_THDH 0x06 +#define VCNL36825T_REG_PS_CANC 0x07 +#define VCNL36825T_REG_PS_CONF4 0x08 +#define VCNL36825T_REG_PS_DATA 0xF8 +#define VCNL36825T_REG_INT_FLAG 0xF9 +#define VCNL36825T_REG_DEV_ID 0xFA +#define VCNL36825T_REG_PS_AC_DATA 0xFB + +/* default values */ +#define VCNL36825T_CONF1_DEFAULT 0x0001 +#define VCNL36825T_CONF2_DEFAULT 0x0000 +#define VCNL36825T_CONF3_DEFAULT 0x0000 +#define VCNL36825T_THDL_DEFAULT 0x0000 +#define VCNL36825T_THDH_DEFAULT 0x0000 +#define VCNL36825T_CANC_DEFAULT 0x0000 +#define VCNL36825T_CONF4_DEFAULT 0x0000 + +/* PS_CONF1 */ +#define VCNL36825T_PS_ON_POS 1 +#define VCNL36825T_PS_CAL_POS 7 + +#define VCNL36825T_PS_ON_MSK GENMASK(1, 1) + +#define VCNL36825T_PS_ON (1 << VCNL36825T_PS_ON_POS) +#define VCNL36825T_PS_OFF (0 << VCNL36825T_PS_ON_POS) + +#define VCNL36825T_PS_CAL (1 << VCNL36825T_PS_CAL_POS) + +/* PS_CONF2 */ +#define VCNL36825T_PS_ST_POS 0 +#define VCNL36825T_PS_PS_SMART_PERS_POS 1 +#define VCNL36825T_PS_INT_POS 2 +#define VCNL36825T_PS_PERS_POS 4 +#define VCNL36825T_PS_PERIOD_POS 6 +#define VCNL36825T_PS_HG_POS 10 +#define VCNL36825T_PS_ITB_POS 11 +#define VCNL36825T_PS_MPS_POS 12 +#define VCNL36825T_PS_IT_POS 14 + +#define VCNL36825T_PS_ST_MSK GENMASK(0, 0) + +#define VCNL36825T_PS_ST_START (0 << VCNL36825T_PS_ST_POS) +#define VCNL36825T_PS_ST_STOP (1 << VCNL36825T_PS_ST_POS) + +#define VCNL36825T_PS_SMART_PERS_DISABLED (0 << VCNL36825T_PS_PS_SMART_PERS_POS) +#define VCNL36825T_PS_SMART_PERS_ENABLED (1 << VCNL36825T_PS_PS_SMART_PERS_POS) + +#define VCNL36825T_PS_INT_DISABLE (0 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_THDH_PERS_LATCHED (1 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_THDH_FIRST_LATCHED (2 << VCNL36825T_PS_INT_POS) +#define VCNL36825T_PS_INT_ENABLED (3 << VCNL36825T_PS_INT_POS) + +#define VCNL36825T_PS_PERS_1 (0 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_2 (1 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_3 (2 << VCNL36825T_PS_PERS_POS) +#define VCNL36825T_PS_PERS_4 (3 << VCNL36825T_PS_PERS_POS) + +#define VCNL36825T_PS_PERIOD_10MS (0 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_20MS (1 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_40MS (2 << VCNL36825T_PS_PERIOD_POS) +#define VCNL36825T_PS_PERIOD_80MS (3 << VCNL36825T_PS_PERIOD_POS) + +#define VCNL36825T_PS_HG_LOW (0 << VCNL36825T_PS_HG_POS) +#define VCNL36825T_PS_HG_HIGH (1 << VCNL36825T_PS_HG_POS) + +#define VCNL36825T_PS_ITB_25us (0 << VCNL36825T_PS_ITB_POS) +#define VCNL36825T_PS_ITB_50us (1 << VCNL36825T_PS_ITB_POS) + +#define VCNL36825T_MPS_PULSES_1 (0 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_2 (1 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_4 (2 << VCNL36825T_PS_MPS_POS) +#define VCNL36825T_MPS_PULSES_8 (4 << VCNL36825T_PS_MPS_POS) + +#define VCNL36825T_PS_IT_1T (0 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_1_5T (1 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_2T (2 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_2_5T (3 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_3T (4 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_3_5T (5 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_4T (6 << VCNL36825T_PS_IT_POS) +#define VCNL36825T_PS_IT_8T (7 << VCNL36825T_PS_IT_POS) + +/* PS_CONF3 */ +#define VCNL36825T_PS_SP_INT_POS 2 +#define VCNL36825T_PS_FORCENUM_POS 4 +#define VCNL36825T_PS_TRIG_POS 5 +#define VCNL36825T_PS_AF_POS 6 +#define VCNL36825T_PS_I_VCSEL_POS 8 +#define VCNL36825T_PS_HD_POS 12 +#define VCNL36825T_PS_SC_POS 13 + +#define VCNL36825T_PS_TRIG_MSK GENMASK(5, 5) + +#define VCNL36825T_PS_SP_INT_DISABLED (0 << VCNL36825T_PS_SP_INT_POS) +#define VCNL36825T_PS_SP_INT_ENABLED (1 << VCNL36825T_PS_SP_INT_POS) + +#define VCNL36825T_PS_FORCENUM_ONE_CYCLE (0 << VCNL36825T_PS_FORCENUM_POS) +#define VCNL36825T_PS_FORCENUM_TWO_CYCLES (1 << VCNL36825T_PS_FORCENUM_POS) + +#define VCNL36825T_PS_TRIG_NONE (0 << VCNL36825T_PS_TRIG_POS) +#define VCNL36825T_PS_TRIG_ONCE (1 << VCNL36825T_PS_TRIG_POS) + +#define VCNL36825T_PS_AF_AUTO (0 << VCNL36825T_PS_AF_POS) +#define VCNL36825T_PS_AF_FORCE (1 << VCNL36825T_PS_AF_POS) + +#define VCNL36825T_PS_I_VCSEL_10MA (2 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_12MA (3 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_14MA (4 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_16MA (5 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_18MA (6 << VCNL36825T_PS_I_VCSEL_POS) +#define VCNL36825T_PS_I_VCSEL_20MA (7 << VCNL36825T_PS_I_VCSEL_POS) + +#define VCNL36825T_PS_HD_12BIT (0 << VCNL36825T_PS_HD_POS) +#define VCNL36825T_PS_HD_16BIT (1 << VCNL36825T_PS_HD_POS) + +#define VCNL36825T_PS_SC_DISABLED (0 << VCNL36825T_PS_SC_POS) +#define VCNL36825T_PS_SC_ENABLED (7 << VCNL36825T_PS_SC_POS) + +/* PS CONF4 */ +#define VCNL36825T_PS_AC_INT_POS 0 +#define VCNL36825T_PS_AC_TRIG_POS 2 +#define VCNL36825T_PS_AC_POS 3 +#define VCNL36825T_PS_AC_NUM_POS 4 +#define VCNL36825T_PS_AC_PERIOD_POS 6 +#define VCNL36825T_PS_LPEN_POS 8 +#define VCNL36825T_PS_LPPER_POS 9 + +#define VCNL36825T_PS_AC_INT_DISABLED (0 << VCNL36825T_PS_AC_INT_POS) +#define VCNL36825T_PS_AC_INT_ENABLED (1 << VCNL36825T_PS_AC_INT_POS) + +#define VCNL36825T_PS_AC_TRIG_DISABLED (0 << VCNL36825T_PS_AC_TRIG_POS) +#define VCNL36825T_PS_AC_TRIG_ONCE (1 << VCNL36825T_PS_AC_TRIG_POS) + +#define VCNL36825T_PS_AC_DISABLED (0 << VCNL36825T_PS_AC_POS) +#define VCNL36825T_PS_AC_ENABLED (1 << VCNL36825T_PS_AC_POS) + +#define VCNL36825T_PS_AC_NUM_1 (0 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_2 (1 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_4 (2 << VCNL36825T_PS_AC_NUM_POS) +#define VCNL36825T_PS_AC_NUM_8 (3 << VCNL36825T_PS_AC_NUM_POS) + +#define VCNL36825T_PS_AC_PERIOD_3MS (0 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_6MS (1 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_12MS (2 << VCNL36825T_PS_AC_PERIOD_POS) +#define VCNL36825T_PS_AC_PERIOD_24MS (3 << VCNL36825T_PS_AC_PERIOD_POS) + +#define VCNL36825T_PS_LPEN_DISABLED (0 << VCNL36825T_PS_LPEN_POS) +#define VCNL36825T_PS_LPEN_ENABLED (1 << VCNL36825T_PS_LPEN_POS) + +#define VCNL36825T_PS_LPPER_40MS (0 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_80MS (1 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_160MS (2 << VCNL36825T_PS_LPPER_POS) +#define VCNL36825T_PS_LPPER_320MS (3 << VCNL36825T_PS_LPPER_POS) + +/* PS_DATA */ +#define VCNL36825T_PS_DATA_L_POS 0 +#define VCNL36825T_PS_DATA_H_POS 8 + +#define VCNL36825T_PS_DATA_L_MSK GENMASK(7, 0) +#define VCNL36825T_PS_DATA_H_MSK GENMASK(11, 8) +#define VCNL36825T_OS_DATA_MSK (VCNL36825T_PS_DATA_L_MSK | VCNL36825T_PS_DATA_H_MSK) + +/* INT_FLAG */ +#define VCNL36825T_PS_IF_AWAY_POS 8 +#define VCNL36825T_PS_IF_CLOSE_POS 9 +#define VCNL36825T_PS_SPFLAG_POS 12 +#define VCNL36825T_PS_ACFLAG_POS 13 + +#define VCNL36825T_PS_IF_AWAY_MSK GENMASK(8, 8) +#define VCNL36825T_PS_IF_CLOSE_MSK GENMASK(9, 9) +#define VCNL36825T_PS_SPFLAG_MSK GENMASK(12, 12) +#define VCNL36825T_PS_ACFLAG_MSK GENMASK(13, 13) + +/* ID */ +#define VCNL36825T_ID_POS 0 +#define VCNL36825T_VERSION_CODE_POS 8 + +#define VCNL36825T_ID_MSK GENMASK(7, 0) +#define VCNL36825T_VERSION_CODE_MSK GENMASK(11, 8) + +#define VCNL36825T_DEVICE_ID 0b00100110 + +/* PS_AC_DATA */ +#define VCNL36825T_AC_DATA_L_POS 0 +#define VCNL36825T_AC_DATA_H_POS 8 +#define VCNL36825T_AC_SUN_POS 14 +#define VCNL36825T_AC_BUSY_POS 15 + +#define VCNL36825T_AC_DATA_L_MSK GENMASK(7, 0) +#define VCNL36825T_AC_DATA_H_MSK GENMASK(11, 8) +#define VCNL36825T_AC_SUN_MSK GENMASK(14, 14) +#define VCNL36825T_AC_BUSY_MSK GENMASK(15, 15) + +/* --- */ + +#define VCNL36825T_PS_PERIOD_VALUE_MAX_MS 80 +#define VCNL36825T_PS_LPPER_VALUE_MIN_MS 40 + +#define VCNL36825T_FORCED_FACTOR_TIME_TO_TRIGGER 0.5 +#define VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT 3 +#define VCNL36825T_FORCED_FACTOR_MEASUREMENT 1 +#define VCNL36825T_FORCED_FACTOR_SHUTDOWN 1 +#define VCNL36825T_FORCED_FACTOR_SCALE 10 +#define VCNL36825T_FORCED_FACTOR_SUM \ + ((VCNL36825T_FORCED_FACTOR_TIME_TO_TRIGGER + VCNL36825T_FORCED_FACTOR_DC_KILL_AMBIENT + \ + VCNL36825T_FORCED_FACTOR_MEASUREMENT + VCNL36825T_FORCED_FACTOR_SHUTDOWN) * \ + VCNL36825T_FORCED_FACTOR_SCALE) + +enum vcnl36825t_operation_mode { + VCNL36825T_OPERATION_MODE_AUTO, + VCNL36825T_OPERATION_MODE_FORCE, +}; + +enum vcnl36825t_measurement_period { + VCNL36825T_MEAS_PERIOD_10MS, + VCNL36825T_MEAS_PERIOD_20MS, + VCNL36825T_MEAS_PERIOD_40MS, + VCNL36825T_MEAS_PERIOD_80MS, + VCNL36825T_MEAS_PERIOD_160MS, + VCNL36825T_MEAS_PERIOD_320MS, +}; + +enum vcnl36825t_proximity_integration_time { + VCNL36825T_PROXIMITY_INTEGRATION_1T, + VCNL36825T_PROXIMITY_INTEGRATION_1_5T, + VCNL36825T_PROXIMITY_INTEGRATION_2T, + VCNL36825T_PROXIMITY_INTEGRATION_2_5T, + VCNL36825T_PROXIMITY_INTEGRATION_3T, + VCNL36825T_PROXIMITY_INTEGRATION_3_5T, + VCNL36825T_PROXIMITY_INTEGRATION_4T, + VCNL36825T_PROXIMITY_INTEGRATION_8T, +}; + +enum vcnl36825t_proximity_integration_duration { + VCNL36825T_PROXIMITY_INTEGRATION_DURATION_25us, + VCNL36825T_PROXIMITY_INTEGRATION_DURATION_50us, +}; + +enum vcnl36825t_multi_pulse { + VCNL38652T_MULTI_PULSE_1, + VCNL38652T_MULTI_PULSE_2, + VCNL38652T_MULTI_PULSE_4, + VCNL38652T_MULTI_PULSE_8, +}; + +enum vcnl38625t_laser_current { + VCNL36825T_LASER_CURRENT_10MS, + VCNL36825T_LASER_CURRENT_12MS, + VCNL36825T_LASER_CURRENT_14MS, + VCNL36825T_LASER_CURRENT_16MS, + VCNL36825T_LASER_CURRENT_18MS, + VCNL36825T_LASER_CURRENT_20MS, +}; + +struct vcnl36825t_config { + struct i2c_dt_spec i2c; + + enum vcnl36825t_operation_mode operation_mode; + + enum vcnl36825t_measurement_period period; + enum vcnl36825t_proximity_integration_time proximity_it; + enum vcnl36825t_proximity_integration_duration proximity_itb; + enum vcnl36825t_multi_pulse multi_pulse; + + bool low_power; + bool high_gain; + + enum vcnl38625t_laser_current laser_current; + bool high_dynamic_output; + bool sunlight_cancellation; +}; + +struct vcnl36825t_data { + uint16_t proximity; + + int meas_timeout_us; /** wait time for finished measurement for "forced" operation mode */ +}; + +#endif diff --git a/drivers/sensor/veml7700/veml7700.c b/drivers/sensor/veml7700/veml7700.c index e008b725167..7aed13cbdca 100644 --- a/drivers/sensor/veml7700/veml7700.c +++ b/drivers/sensor/veml7700/veml7700.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Andreas Kilian + * Copyright (c) 2024 Jeff Welder (Ellenby Technologies, Inc.) * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +88,7 @@ struct veml7700_data { uint16_t thresh_low; uint16_t als_counts; uint32_t als_lux; + uint16_t white_counts; uint32_t int_flags; }; @@ -293,6 +295,23 @@ static int veml7700_fetch_als(const struct device *dev) return 0; } +static int veml7700_fetch_white(const struct device *dev) +{ + struct veml7700_data *data = dev->data; + uint16_t counts; + int ret; + + ret = veml7700_read(dev, VEML7700_CMDCODE_WHITE, &counts); + if (ret < 0) { + return ret; + } + + data->white_counts = counts; + LOG_DBG("Read White Light measurement: counts=%d", data->white_counts); + + return 0; +} + static int veml7700_fetch_int_flags(const struct device *dev) { struct veml7700_data *data = dev->data; @@ -428,6 +447,8 @@ static int veml7700_sample_fetch(const struct device *dev, } else { return -ENOTSUP; } + } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS) { + return veml7700_fetch_white(dev); } else if (chan == SENSOR_CHAN_ALL) { data = dev->data; if (data->int_mode != VEML7700_INT_DISABLED) { @@ -436,7 +457,10 @@ static int veml7700_sample_fetch(const struct device *dev, return ret; } } - + ret = veml7700_fetch_white(dev); + if (ret < 0) { + return ret; + } return veml7700_fetch_als(dev); } else { return -ENOTSUP; @@ -453,6 +477,8 @@ static int veml7700_channel_get(const struct device *dev, val->val1 = data->als_lux; } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_RAW_COUNTS) { val->val1 = data->als_counts; + } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS) { + val->val1 = data->white_counts; } else if ((enum sensor_channel_veml7700)chan == SENSOR_CHAN_VEML7700_INTERRUPT) { val->val1 = data->int_flags; } else { @@ -514,6 +540,7 @@ static int veml7700_init(const struct device *dev) data->int_mode = VEML7700_INT_DISABLED; data->als_counts = 0; data->als_lux = 0; + data->white_counts = 0; data->shut_down = (conf->psm != VEML7700_PSM_DISABLED) ? 0 : 1; /* Initialize sensor configuration */ diff --git a/drivers/sensor/vl53l0x/Kconfig b/drivers/sensor/vl53l0x/Kconfig index 936ef923c87..246962a2571 100644 --- a/drivers/sensor/vl53l0x/Kconfig +++ b/drivers/sensor/vl53l0x/Kconfig @@ -7,6 +7,7 @@ menuconfig VL53L0X bool "VL53L0X time of flight sensor" default y depends on DT_HAS_ST_VL53L0X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STLIB help diff --git a/drivers/sensor/vl53l1x/Kconfig b/drivers/sensor/vl53l1x/Kconfig index 0865ff79549..99a69ae7276 100644 --- a/drivers/sensor/vl53l1x/Kconfig +++ b/drivers/sensor/vl53l1x/Kconfig @@ -7,6 +7,7 @@ menuconfig VL53L1X bool "VL53L1X time of flight sensor" default y depends on DT_HAS_ST_VL53L1X_ENABLED + depends on ZEPHYR_HAL_ST_MODULE select I2C select HAS_STLIB help diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index bfc38603864..1648f3a7081 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -26,7 +26,13 @@ zephyr_library_sources_ifdef(CONFIG_UART_MIV uart_miv.c) zephyr_library_sources_ifdef(CONFIG_UART_MSP432P4XX uart_msp432p4xx.c) zephyr_library_sources_ifdef(CONFIG_UART_NS16550 uart_ns16550.c) zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UART uart_nrfx_uart.c) -zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UARTE uart_nrfx_uarte.c) +if (CONFIG_UART_NRFX_UARTE) + if (CONFIG_UART_NRFX_UARTE_LEGACY_SHIM) + zephyr_library_sources(uart_nrfx_uarte.c) + else() + zephyr_library_sources(uart_nrfx_uarte2.c) + endif() +endif() zephyr_library_sources_ifdef(CONFIG_UART_NUMICRO uart_numicro.c) zephyr_library_sources_ifdef(CONFIG_UART_SAM uart_sam.c) zephyr_library_sources_ifdef(CONFIG_USART_SAM usart_sam.c) @@ -66,7 +72,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_EFINIX_SAPPIHIRE uart_efinix_sapphire.c zephyr_library_sources_ifdef(CONFIG_UART_SEDI uart_sedi.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_UART_INTEL_LW uart_intel_lw.c) -zephyr_library_sources_ifdef(CONFIG_UART_RA uart_ra.c) +zephyr_library_sources_ifdef(CONFIG_UART_RENESAS_RA uart_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_UART_RZT2M uart_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c) @@ -93,3 +99,4 @@ endif() zephyr_library_sources_ifdef(CONFIG_SERIAL_TEST serial_test.c) zephyr_library_sources_ifdef(CONFIG_UART_ASYNC_RX_HELPER uart_async_rx.c) +zephyr_library_sources_ifdef(CONFIG_UART_ASYNC_TO_INT_DRIVEN_API uart_async_to_irq.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5eb183c9a3e..a3041b2cae6 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -133,6 +133,21 @@ config UART_ASYNC_RX_HELPER is delayed. Module implements zero-copy approach with multiple reception buffers. +config UART_ASYNC_TO_INT_DRIVEN_API + bool + select UART_ASYNC_RX_HELPER + help + Asynchronous to Interrupt driven adaptation layer. When enabled device + which implements only asynchronous API can be used with interrupt driven + API implemented by the generic adaptation layer. + +config UART_ASYNC_TO_INT_DRIVEN_RX_TIMEOUT + int "Receiver timeout (in bauds)" + depends on UART_ASYNC_TO_INT_DRIVEN_API + default 100 + help + Receiver inactivity timeout. It is used to calculate timeout in microseconds. + comment "Serial Drivers" source "drivers/serial/Kconfig.b91" @@ -253,7 +268,7 @@ source "drivers/serial/Kconfig.bcm2711" source "drivers/serial/Kconfig.intel_lw" -source "drivers/serial/Kconfig.ra" +source "drivers/serial/Kconfig.renesas_ra" source "drivers/serial/Kconfig.rzt2m" diff --git a/drivers/serial/Kconfig.emul b/drivers/serial/Kconfig.emul index b5362eb79ee..e61130a13c7 100644 --- a/drivers/serial/Kconfig.emul +++ b/drivers/serial/Kconfig.emul @@ -20,7 +20,7 @@ config UART_EMUL_WORK_Q_STACK_SIZE default 2048 config UART_EMUL_WORK_Q_PRIORITY - int "UART emulator work queue tread priority" + int "UART emulator work queue thread priority" default 1 endif # UART_EMUL diff --git a/drivers/serial/Kconfig.native_posix b/drivers/serial/Kconfig.native_posix index 39acf155f9b..3af6601b5c7 100644 --- a/drivers/serial/Kconfig.native_posix +++ b/drivers/serial/Kconfig.native_posix @@ -1,14 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 config UART_NATIVE_POSIX - bool "UART driver for native_posix" + bool "UART driver for native_sim/posix" default y depends on DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED select SERIAL_HAS_DRIVER help This enables a UART driver for the POSIX ARCH with up to 2 UARTs. For the first UART port, the driver can be configured - to either connect to the terminal from which native_posix was run, or into + to either connect to the terminal from which the executable was run, or into one dedicated pseudoterminal for that UART. if UART_NATIVE_POSIX @@ -22,14 +22,14 @@ config NATIVE_UART_0_ON_OWN_PTY help Connect this UART to its own pseudoterminal. This is the preferred option for users who want to use Zephyr's shell. - Moreover this option does not conflict with any other native_posix - backend which may use the calling shell standard input/output. + Moreover this option does not conflict with any other native + backend which may use the invoking shell standard input/output. config NATIVE_UART_0_ON_STDINOUT bool "Connect the UART to the invoking shell stdin/stdout" help Connect this UART to the stdin & stdout of the calling shell/terminal - which invoked the native_posix executable. This is good enough for + which invoked the native executable. This is good enough for automated testing, or when feeding from a file/pipe. Note that other, non UART messages, will also be printed to the terminal. @@ -60,7 +60,7 @@ config NATIVE_UART_AUTOATTACH_DEFAULT_CMD string "Default command to attach the UART to a new terminal" default "xterm -e screen %s &" help - If the native_posix executable is called with the --attach_uart + If the native executable is called with the --attach_uart command line option, this will be the default command which will be run to attach a new terminal to the 1st UART. Note that this command must have one, and only one, '%s' as diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 53553e3d06e..158731404e6 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -25,11 +25,20 @@ config UART_NRFX_UART config UART_NRFX_UARTE def_bool y depends on DT_HAS_NORDIC_NRF_UARTE_ENABLED + imply NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG if !UART_NRFX_UARTE_LEGACY_SHIM + imply NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG if !UART_NRFX_UARTE_LEGACY_SHIM + +config UART_NRFX_UARTE_LEGACY_SHIM + bool "Legacy UARTE shim" + depends on UART_NRFX_UARTE + depends on !SOC_SERIES_NRF54LX && !SOC_SERIES_NRF54HX + # New shim takes more ROM. Until it is fixed use legacy shim. + default y config UART_ASYNC_TX_CACHE_SIZE int "TX cache buffer size" depends on UART_ASYNC_API - depends on UART_NRFX_UARTE + depends on UART_NRFX_UARTE_LEGACY_SHIM default 8 help For UARTE, TX cache buffer is used when provided TX buffer is not located @@ -56,6 +65,76 @@ nrfx_uart_num = 3 rsource "Kconfig.nrfx_uart_instance" endif +if HAS_HW_NRF_UARTE00 +nrfx_uart_num = 00 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE20 +nrfx_uart_num = 20 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE21 +nrfx_uart_num = 21 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE22 +nrfx_uart_num = 22 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE30 +nrfx_uart_num = 30 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE120 +nrfx_uart_num = 120 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE130 +nrfx_uart_num = 130 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE131 +nrfx_uart_num = 131 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE132 +nrfx_uart_num = 132 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE133 +nrfx_uart_num = 133 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE134 +nrfx_uart_num = 134 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE135 +nrfx_uart_num = 135 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE136 +nrfx_uart_num = 136 +rsource "Kconfig.nrfx_uart_instance" +endif + +if HAS_HW_NRF_UARTE137 +nrfx_uart_num = 137 +rsource "Kconfig.nrfx_uart_instance" +endif + config NRFX_TIMER0 default y depends on UART_0_NRF_HW_ASYNC_TIMER = 0 \ diff --git a/drivers/serial/Kconfig.nrfx_uart_instance b/drivers/serial/Kconfig.nrfx_uart_instance index 39e774e2544..9e992ca9737 100644 --- a/drivers/serial/Kconfig.nrfx_uart_instance +++ b/drivers/serial/Kconfig.nrfx_uart_instance @@ -6,6 +6,7 @@ config UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN bool "Interrupt support on port $(nrfx_uart_num)" depends on UART_INTERRUPT_DRIVEN + select UART_ASYNC_TO_INT_DRIVEN_API if !UART_NRFX_UARTE_LEGACY_SHIM default y help This option enables UART interrupt support on port $(nrfx_uart_num). @@ -19,14 +20,19 @@ config UART_$(nrfx_uart_num)_ASYNC config UART_$(nrfx_uart_num)_ENHANCED_POLL_OUT bool "Efficient poll out on port $(nrfx_uart_num)" + depends on !SOC_SERIES_NRF54LX default y depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on HAS_HW_NRF_PPI || HAS_HW_NRF_DPPIC select NRFX_PPI if HAS_HW_NRF_PPI select NRFX_DPPI if HAS_HW_NRF_DPPIC help When enabled, polling out does not trigger interrupt which stops TX. Feature uses a PPI channel. +config NRFX_UARTE$(nrfx_uart_num) + def_bool y if HAS_HW_NRF_UARTE$(nrfx_uart_num) && !UART_NRFX_UARTE_LEGACY_SHIM + config UART_$(nrfx_uart_num)_NRF_PARITY_BIT bool "Parity bit" help @@ -34,7 +40,8 @@ config UART_$(nrfx_uart_num)_NRF_PARITY_BIT config UART_$(nrfx_uart_num)_NRF_TX_BUFFER_SIZE int "Size of RAM buffer" - depends on UART_INTERRUPT_DRIVEN + depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) + depends on UART_NRFX_UARTE_LEGACY_SHIM range 1 65535 default 32 help @@ -46,6 +53,7 @@ config UART_$(nrfx_uart_num)_NRF_HW_ASYNC bool "Use hardware RX byte counting" depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) depends on UART_ASYNC_API + depends on UART_NRFX_UARTE_LEGACY_SHIM select NRFX_PPI if HAS_HW_NRF_PPI select NRFX_DPPI if HAS_HW_NRF_DPPIC help @@ -58,6 +66,7 @@ config UART_$(nrfx_uart_num)_NRF_ASYNC_LOW_POWER bool "Low power mode" depends on HAS_HW_NRF_UARTE$(nrfx_uart_num) depends on UART_ASYNC_API + depends on UART_NRFX_UARTE_LEGACY_SHIM help When enabled, UARTE is enabled before each TX or RX usage and disabled when not used. Disabling UARTE while in idle allows to achieve lowest @@ -67,6 +76,42 @@ config UART_$(nrfx_uart_num)_NRF_HW_ASYNC_TIMER int "Timer instance" depends on UART_$(nrfx_uart_num)_NRF_HW_ASYNC +config UART_$(nrfx_uart_num)_TX_CACHE_SIZE + int "TX cache buffer size" + depends on !UART_NRFX_UARTE_LEGACY_SHIM + default 8 + help + For UARTE, TX cache buffer is used when provided TX buffer is not located + in memory which can be used by the EasyDMA. + +config UART_$(nrfx_uart_num)_RX_CACHE_SIZE + int "RX cache buffer size" + depends on !UART_NRFX_UARTE_LEGACY_SHIM + default 32 if $(dt_nodelabel_has_compat,ram3x,$(DT_COMPAT_MMIO_SRAM)) + default 5 + range 5 255 + help + For UARTE, RX cache buffer is used when provided RX buffer is not located + in memory which can be used by the EasyDMA. It is also used to store + flushed data. + +config UART_$(nrfx_uart_num)_A2I_RX_SIZE + depends on !UART_NRFX_UARTE_LEGACY_SHIM + int "Asynchronous to interrupt driven adaptation layer RX buffer size" + default 64 if UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default 0 + help + Amount of space dedicated for RX. It is divided into chunks with some + amount of that space used for control data. + +config UART_$(nrfx_uart_num)_A2I_RX_BUF_COUNT + depends on !UART_NRFX_UARTE_LEGACY_SHIM + int "Asynchronous to interrupt driven adaptation layer RX buffer count" + default 8 if UART_$(nrfx_uart_num)_INTERRUPT_DRIVEN + default 0 + help + Number of chunks into RX space is divided. + config UART_$(nrfx_uart_num)_GPIO_MANAGEMENT bool "GPIO management on port $(nrfx_uart_num)" depends on PM_DEVICE diff --git a/drivers/serial/Kconfig.ns16550 b/drivers/serial/Kconfig.ns16550 index 1c97a08637e..fd7f1156a14 100644 --- a/drivers/serial/Kconfig.ns16550 +++ b/drivers/serial/Kconfig.ns16550 @@ -30,6 +30,13 @@ config UART_NS16550_DRV_CMD Says n if not sure. +config UART_NS16550_INTEL_LPSS_DMA + bool "INTEL LPSS support for NS16550" + select SERIAL_SUPPORT_ASYNC + select DMA if UART_ASYNC_API + help + This enables the usage of INTEL LPSS internal DMA for Async operations. + choice UART_NS16550_VARIANT prompt "UART variant" default UART_NS16550_VARIANT_NS16550 @@ -60,16 +67,6 @@ config UART_NS16550_ACCESS_WORD_ONLY 16550 (DesignWare UART) only allows word access, byte access will raise exception. -config UART_NS16550_PARENT_INIT_LEVEL - bool "Boot level based on parent node" - default y if ACPI - help - Boot level based on parent node (PCI or no PCI device). Some platforms the - PCI bus driver depends on ACPI sub system to retrieve platform information - such as interrupt routing information. But ACPI sub system currently support - only post kernel and hence such platforms the UART driver instance init - should be invoked only post kernel in case parent node is PCI. - config UART_NS16550_TI_K3 bool "Add support for NS16550 variant specific to TI K3 SoCs" help diff --git a/drivers/serial/Kconfig.ra b/drivers/serial/Kconfig.ra deleted file mode 100644 index 3e35afed2de..00000000000 --- a/drivers/serial/Kconfig.ra +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2023 TOKITA Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -config UART_RA - bool "Renesas RA Series UART Driver" - default y - depends on DT_HAS_RENESAS_RA_UART_SCI_ENABLED - select SERIAL_HAS_DRIVER - select SERIAL_SUPPORT_INTERRUPT - help - Enable Renesas RA series UART driver. diff --git a/drivers/serial/Kconfig.renesas_ra b/drivers/serial/Kconfig.renesas_ra new file mode 100644 index 00000000000..14311f27fe4 --- /dev/null +++ b/drivers/serial/Kconfig.renesas_ra @@ -0,0 +1,11 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config UART_RENESAS_RA + bool "Renesas RA Series UART Driver" + default y + depends on DT_HAS_RENESAS_RA_UART_SCI_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + Enable Renesas RA series UART driver. diff --git a/drivers/serial/Kconfig.stm32 b/drivers/serial/Kconfig.stm32 index c6aa6051993..75d0e22c157 100644 --- a/drivers/serial/Kconfig.stm32 +++ b/drivers/serial/Kconfig.stm32 @@ -21,3 +21,18 @@ config UART_STM32 This option enables the UART driver for STM32 family of processors. Say y if you wish to use serial port on STM32 MCU. + +if UART_STM32 + +config UART_STM32U5_ERRATA_DMAT + bool + default y + depends on SOC_STM32U575XX || SOC_STM32U585XX || \ + SOC_STM32H562XX || SOC_STM32H563XX || SOC_STM32H573XX + help + Handles erratum "USART does not generate DMA requests after + setting/clearing DMAT bit". + Seen in Errata Sheet 0499 § 2.19.2 and §2.20.1 for stm32u57x/u58x, + Errata Sheet 0565 § 2.14.1 and §2.15.1 for stm32h56x/h57x + +endif diff --git a/drivers/serial/Kconfig.xen b/drivers/serial/Kconfig.xen index 471e5eb7269..02492e7483f 100644 --- a/drivers/serial/Kconfig.xen +++ b/drivers/serial/Kconfig.xen @@ -18,7 +18,7 @@ config UART_XEN_HVC config UART_XEN_HVC_CONSOLEIO bool "Xen hypervisor consoleio UART driver" select SERIAL_HAS_DRIVER - depends on XEN_DOM0 || XEN_DOM0LESS + depends on DT_HAS_XEN_HVC_CONSOLEIO_ENABLED && (XEN_DOM0 || XEN_DOM0LESS) default y help Enable Xen hypervisor console driver. Used for Zephyr as diff --git a/drivers/serial/uart_async_to_irq.c b/drivers/serial/uart_async_to_irq.c new file mode 100644 index 00000000000..209e8d4f205 --- /dev/null +++ b/drivers/serial/uart_async_to_irq.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +LOG_MODULE_REGISTER(UART_ASYNC_TO_IRQ_LOG_NAME, CONFIG_UART_LOG_LEVEL); + +/* Internal state flags. */ + +/* RX interrupt enabled. */ +#define A2I_RX_IRQ_ENABLED BIT(0) + +/* TX interrupt enabled. */ +#define A2I_TX_IRQ_ENABLED BIT(1) + +/* Error interrupt enabled. */ +#define A2I_ERR_IRQ_ENABLED BIT(2) + +/* Receiver to be kept enabled. */ +#define A2I_RX_ENABLE BIT(3) + +/* TX busy. */ +#define A2I_TX_BUSY BIT(4) + +static struct uart_async_to_irq_data *get_data(const struct device *dev) +{ + struct uart_async_to_irq_data **data = dev->data; + + return *data; +} + +static const struct uart_async_to_irq_config *get_config(const struct device *dev) +{ + const struct uart_async_to_irq_config * const *config = dev->config; + + return *config; +} + +/* Function calculates RX timeout based on baudrate. */ +static uint32_t get_rx_timeout(const struct device *dev) +{ + struct uart_config cfg; + int err; + uint32_t baudrate; + + err = uart_config_get(dev, &cfg); + if (err == 0) { + baudrate = cfg.baudrate; + } else { + baudrate = get_config(dev)->baudrate; + } + + uint32_t us = (CONFIG_UART_ASYNC_TO_INT_DRIVEN_RX_TIMEOUT * 1000000) / baudrate; + + return us; +} + +static int rx_enable(const struct device *dev, + struct uart_async_to_irq_data *data, + uint8_t *buf, + size_t len) +{ + int err; + const struct uart_async_to_irq_config *config = get_config(dev); + + err = config->api->rx_enable(dev, buf, len, get_rx_timeout(dev)); + + return err; +} + +static int try_rx_enable(const struct device *dev, struct uart_async_to_irq_data *data) +{ + uint8_t *buf = uart_async_rx_buf_req(&data->rx.async_rx); + size_t len = uart_async_rx_get_buf_len(&data->rx.async_rx); + + if (buf == NULL) { + return -EBUSY; + } + + return rx_enable(dev, data, buf, len); +} + +static void on_rx_buf_req(const struct device *dev, + const struct uart_async_to_irq_config *config, + struct uart_async_to_irq_data *data) +{ + struct uart_async_rx *async_rx = &data->rx.async_rx; + uint8_t *buf = uart_async_rx_buf_req(async_rx); + size_t len = uart_async_rx_get_buf_len(async_rx); + + if (buf) { + int err = config->api->rx_buf_rsp(dev, buf, len); + + if (err < 0) { + uart_async_rx_on_buf_rel(async_rx, buf); + } + } else { + atomic_inc(&data->rx.pending_buf_req); + } +} + +static void on_rx_dis(const struct device *dev, struct uart_async_to_irq_data *data) +{ + if (data->flags & A2I_RX_ENABLE) { + data->rx.pending_buf_req = 0; + + int err = try_rx_enable(dev, data); + + LOG_INST_DBG(get_config(dev)->log, "Reenabling RX from RX_DISABLED (err:%d)", err); + __ASSERT_NO_MSG(err >= 0); + return; + } + + k_sem_give(&data->rx.sem); +} + +static void uart_async_to_irq_callback(const struct device *dev, + struct uart_event *evt, + void *user_data) +{ + struct uart_async_to_irq_data *data = (struct uart_async_to_irq_data *)user_data; + const struct uart_async_to_irq_config *config = get_config(dev); + bool call_handler = false; + + switch (evt->type) { + case UART_TX_DONE: + atomic_and(&data->flags, ~A2I_TX_BUSY); + call_handler = data->flags & A2I_TX_IRQ_ENABLED; + break; + case UART_RX_RDY: + uart_async_rx_on_rdy(&data->rx.async_rx, evt->data.rx.buf, evt->data.rx.len); + call_handler = data->flags & A2I_RX_IRQ_ENABLED; + break; + case UART_RX_BUF_REQUEST: + on_rx_buf_req(dev, config, data); + break; + case UART_RX_BUF_RELEASED: + uart_async_rx_on_buf_rel(&data->rx.async_rx, evt->data.rx_buf.buf); + break; + case UART_RX_STOPPED: + call_handler = data->flags & A2I_ERR_IRQ_ENABLED; + break; + case UART_RX_DISABLED: + on_rx_dis(dev, data); + break; + default: + break; + } + + if (data->callback && call_handler) { + atomic_inc(&data->irq_req); + config->trampoline(dev); + } +} + +int z_uart_async_to_irq_fifo_fill(const struct device *dev, const uint8_t *buf, int len) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + len = MIN(len, data->tx.len); + if (atomic_or(&data->flags, A2I_TX_BUSY) & A2I_TX_BUSY) { + return 0; + } + + memcpy(data->tx.buf, buf, len); + + err = config->api->tx(dev, data->tx.buf, len, SYS_FOREVER_US); + if (err < 0) { + atomic_and(&data->flags, ~A2I_TX_BUSY); + return 0; + } + + return len; +} + +/** Interrupt driven FIFO read function */ +int z_uart_async_to_irq_fifo_read(const struct device *dev, + uint8_t *buf, + const int len) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + struct uart_async_rx *async_rx = &data->rx.async_rx; + size_t claim_len; + uint8_t *claim_buf; + + claim_len = uart_async_rx_data_claim(async_rx, &claim_buf, len); + if (claim_len == 0) { + return 0; + } + + memcpy(buf, claim_buf, claim_len); + uart_async_rx_data_consume(async_rx, claim_len); + + if (data->rx.pending_buf_req) { + buf = uart_async_rx_buf_req(async_rx); + if (buf) { + int err; + size_t rx_len = uart_async_rx_get_buf_len(async_rx); + + atomic_dec(&data->rx.pending_buf_req); + err = config->api->rx_buf_rsp(dev, buf, rx_len); + if (err < 0) { + if (err == -EACCES) { + data->rx.pending_buf_req = 0; + err = rx_enable(dev, data, buf, rx_len); + } + if (err < 0) { + return err; + } + } + } + } + + return (int)claim_len; +} + +static void dir_disable(const struct device *dev, uint32_t flag) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + atomic_and(&data->flags, ~flag); +} + +static void dir_enable(const struct device *dev, uint32_t flag) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + atomic_or(&data->flags, flag); + + atomic_inc(&data->irq_req); + get_config(dev)->trampoline(dev); +} + +/** Interrupt driven transfer enabling function */ +void z_uart_async_to_irq_irq_tx_enable(const struct device *dev) +{ + dir_enable(dev, A2I_TX_IRQ_ENABLED); +} + +/** Interrupt driven transfer disabling function */ +void z_uart_async_to_irq_irq_tx_disable(const struct device *dev) +{ + dir_disable(dev, A2I_TX_IRQ_ENABLED); +} + +/** Interrupt driven transfer ready function */ +int z_uart_async_to_irq_irq_tx_ready(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + return (data->flags & A2I_TX_IRQ_ENABLED) && !(data->flags & A2I_TX_BUSY); +} + +/** Interrupt driven receiver enabling function */ +void z_uart_async_to_irq_irq_rx_enable(const struct device *dev) +{ + dir_enable(dev, A2I_RX_IRQ_ENABLED); +} + +/** Interrupt driven receiver disabling function */ +void z_uart_async_to_irq_irq_rx_disable(const struct device *dev) +{ + dir_disable(dev, A2I_RX_IRQ_ENABLED); +} + +/** Interrupt driven transfer complete function */ +int z_uart_async_to_irq_irq_tx_complete(const struct device *dev) +{ + return z_uart_async_to_irq_irq_tx_ready(dev); +} + +/** Interrupt driven receiver ready function */ +int z_uart_async_to_irq_irq_rx_ready(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + return (data->flags & A2I_RX_IRQ_ENABLED) && (data->rx.async_rx.pending_bytes > 0); +} + +/** Interrupt driven error enabling function */ +void z_uart_async_to_irq_irq_err_enable(const struct device *dev) +{ + dir_enable(dev, A2I_ERR_IRQ_ENABLED); +} + +/** Interrupt driven error disabling function */ +void z_uart_async_to_irq_irq_err_disable(const struct device *dev) +{ + dir_disable(dev, A2I_ERR_IRQ_ENABLED); +} + +/** Interrupt driven pending status function */ +int z_uart_async_to_irq_irq_is_pending(const struct device *dev) +{ + return z_uart_async_to_irq_irq_tx_ready(dev) || z_uart_async_to_irq_irq_rx_ready(dev); +} + +/** Interrupt driven interrupt update function */ +int z_uart_async_to_irq_irq_update(const struct device *dev) +{ + return 1; +} + +/** Set the irq callback function */ +void z_uart_async_to_irq_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + data->callback = cb; + data->user_data = user_data; +} + +int uart_async_to_irq_rx_enable(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + err = config->api->callback_set(dev, uart_async_to_irq_callback, data); + if (err < 0) { + return err; + } + + uart_async_rx_reset(&data->rx.async_rx); + + err = try_rx_enable(dev, data); + if (err == 0) { + atomic_or(&data->flags, A2I_RX_ENABLE); + } + + return err; +} + +int uart_async_to_irq_rx_disable(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + const struct uart_async_to_irq_config *config = get_config(dev); + int err; + + if (atomic_and(&data->flags, ~A2I_RX_ENABLE) & A2I_RX_ENABLE) { + err = config->api->rx_disable(dev); + if (err < 0) { + return err; + } + k_sem_take(&data->rx.sem, K_FOREVER); + } + + return 0; +} + +void uart_async_to_irq_trampoline_cb(const struct device *dev) +{ + struct uart_async_to_irq_data *data = get_data(dev); + + do { + data->callback(dev, data->user_data); + } while (atomic_dec(&data->irq_req) > 1); +} + +int uart_async_to_irq_init(struct uart_async_to_irq_data *data, + const struct uart_async_to_irq_config *config) +{ + data->tx.buf = config->tx_buf; + data->tx.len = config->tx_len; + + k_sem_init(&data->rx.sem, 0, 1); + + return uart_async_rx_init(&data->rx.async_rx, &config->async_rx); +} diff --git a/drivers/serial/uart_b91.c b/drivers/serial/uart_b91.c index cb2d7ebd190..e2502f4fd9b 100644 --- a/drivers/serial/uart_b91.c +++ b/drivers/serial/uart_b91.c @@ -11,6 +11,7 @@ #include #include #include +#include /* Driver dts compatibility: telink,b91_uart */ diff --git a/drivers/serial/uart_cdns.h b/drivers/serial/uart_cdns.h index 70c8e5d6220..d9e1769df5f 100644 --- a/drivers/serial/uart_cdns.h +++ b/drivers/serial/uart_cdns.h @@ -122,7 +122,7 @@ struct uart_cdns_regs { volatile uint32_t flow_ctrl_delay; /* Flow Control Delay Register */ volatile uint32_t rpwr; /* IR Minimum Received Pulse Register */ volatile uint32_t tpwr; /* IR TRansmitted Pulse Width Register */ - volatile uint32_t tx_fifo_trigger_level; /* Transmiter FIFO trigger level */ + volatile uint32_t tx_fifo_trigger_level; /* Transmitter FIFO trigger level */ volatile uint32_t rbrs; /* RX FIFO Byte Status Register */ }; diff --git a/drivers/serial/uart_esp32.c b/drivers/serial/uart_esp32.c index 6608d91a44a..be5d2487e13 100644 --- a/drivers/serial/uart_esp32.c +++ b/drivers/serial/uart_esp32.c @@ -603,7 +603,7 @@ static int uart_esp32_async_tx_abort(const struct device *dev) err = dma_stop(config->dma_dev, config->tx_dma_channel); if (err) { - LOG_ERR("Error stoping Tx DMA (%d)", err); + LOG_ERR("Error stopping Tx DMA (%d)", err); goto unlock; } @@ -838,7 +838,7 @@ static int uart_esp32_async_rx_disable(const struct device *dev) err = dma_stop(config->dma_dev, config->rx_dma_channel); if (err) { - LOG_ERR("Error stoping Rx DMA (%d)", err); + LOG_ERR("Error stopping Rx DMA (%d)", err); goto unlock; } @@ -999,9 +999,11 @@ static const DRAM_ATTR struct uart_driver_api uart_esp32_api = { \ static struct uart_esp32_data uart_esp32_data_##idx = { \ .uart_config = {.baudrate = DT_INST_PROP(idx, current_speed), \ - .parity = UART_CFG_PARITY_NONE, \ - .stop_bits = UART_CFG_STOP_BITS_1, \ - .data_bits = UART_CFG_DATA_BITS_8, \ + .parity = DT_INST_ENUM_IDX_OR(idx, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(idx, stop_bits, \ + UART_CFG_STOP_BITS_1), \ + .data_bits = DT_INST_ENUM_IDX_OR(idx, data_bits, \ + UART_CFG_DATA_BITS_8), \ .flow_ctrl = MAX(COND_CODE_1(DT_INST_PROP(idx, hw_rs485_hd_mode), \ (UART_CFG_FLOW_CTRL_RS485), \ (UART_CFG_FLOW_CTRL_NONE)), \ diff --git a/drivers/serial/uart_hostlink.c b/drivers/serial/uart_hostlink.c index a129c67d30f..396422b6e19 100644 --- a/drivers/serial/uart_hostlink.c +++ b/drivers/serial/uart_hostlink.c @@ -254,7 +254,7 @@ static void hl_static_send(size_t payload_used) * It is responsibility of debugger to set this back to HL_NOADDRESS * after receiving the packet. * Please note that we don't wait here because some implementations - * use hl_blockedPeek() function as a signal that we send a messege. + * use hl_blockedPeek() function as a signal that we send a message. */ hl_write32(&__HOSTLINK__.hdr.target2host_addr, buf_addr); diff --git a/drivers/serial/uart_hvc_xen_consoleio.c b/drivers/serial/uart_hvc_xen_consoleio.c index d60289565a8..97e411a9306 100644 --- a/drivers/serial/uart_hvc_xen_consoleio.c +++ b/drivers/serial/uart_hvc_xen_consoleio.c @@ -17,6 +17,8 @@ #include #include +#define DT_DRV_COMPAT xen_hvc_consoleio + static int xen_consoleio_poll_in(const struct device *dev, unsigned char *c) { @@ -44,12 +46,12 @@ static const struct uart_driver_api xen_consoleio_hvc_api = { .poll_out = xen_consoleio_poll_out, }; -int xen_consoleio_init(const struct device *dev) +static int xen_consoleio_init(const struct device *dev) { /* Nothing to do, but still needed for device API */ return 0; } -DEVICE_DT_DEFINE(DT_NODELABEL(xen_consoleio_hvc), xen_consoleio_init, NULL, NULL, +DEVICE_DT_INST_DEFINE(0, xen_consoleio_init, NULL, NULL, NULL, PRE_KERNEL_1, CONFIG_XEN_HVC_INIT_PRIORITY, &xen_consoleio_hvc_api); diff --git a/drivers/serial/uart_liteuart.c b/drivers/serial/uart_liteuart.c index d23b68b7c5c..fe5e2580d08 100644 --- a/drivers/serial/uart_liteuart.c +++ b/drivers/serial/uart_liteuart.c @@ -14,6 +14,8 @@ #include #include +#include + #define UART_RXTX_ADDR DT_INST_REG_ADDR_BY_NAME(0, rxtx) #define UART_TXFULL_ADDR DT_INST_REG_ADDR_BY_NAME(0, txfull) #define UART_RXEMPTY_ADDR DT_INST_REG_ADDR_BY_NAME(0, rxempty) diff --git a/drivers/serial/uart_mcux_lpuart.c b/drivers/serial/uart_mcux_lpuart.c index e46d8d73607..3c2f318f90e 100644 --- a/drivers/serial/uart_mcux_lpuart.c +++ b/drivers/serial/uart_mcux_lpuart.c @@ -1116,7 +1116,7 @@ static const struct uart_driver_api mcux_lpuart_driver_api = { #ifdef CONFIG_UART_MCUX_LPUART_ISR_SUPPORT #define MCUX_LPUART_IRQ_INSTALL(n, i) \ do { \ - IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, i, irq), \ + IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, i), \ DT_INST_IRQ_BY_IDX(n, i, priority), \ mcux_lpuart_isr, DEVICE_DT_INST_GET(n), 0); \ \ diff --git a/drivers/serial/uart_miv.c b/drivers/serial/uart_miv.c index 24dbf3af370..bf35b4cf656 100644 --- a/drivers/serial/uart_miv.c +++ b/drivers/serial/uart_miv.c @@ -106,6 +106,8 @@ #define BAUDVALUE_MSB ((uint16_t)(0xFF00)) #define BAUDVALUE_SHIFT ((uint8_t)(5)) +#define MIV_UART_0_LINECFG 0x1 + #ifdef CONFIG_UART_INTERRUPT_DRIVEN static struct k_thread rx_thread; static K_KERNEL_STACK_DEFINE(rx_stack, 512); diff --git a/drivers/serial/uart_native_ptty_bottom.c b/drivers/serial/uart_native_ptty_bottom.c index 51348423cc9..7c44ccf68cc 100644 --- a/drivers/serial/uart_native_ptty_bottom.c +++ b/drivers/serial/uart_native_ptty_bottom.c @@ -5,6 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +#undef _XOPEN_SOURCE +/* Note: This is used only for interaction with the host C library, and is therefore exempt of + * coding guidelines rule A.4&5 which applies to the embedded code using embedded libraries + */ +#define _XOPEN_SOURCE 600 + #include #include #include diff --git a/drivers/serial/uart_native_tty.c b/drivers/serial/uart_native_tty.c index 22f2b0e539f..5f6de6e0cbe 100644 --- a/drivers/serial/uart_native_tty.c +++ b/drivers/serial/uart_native_tty.c @@ -6,9 +6,9 @@ * command line options or at runtime. * * To learn more see Native TTY section at: - * https://docs.zephyrproject.org/latest/boards/posix/native_posix/doc/index.html + * https://docs.zephyrproject.org/latest/boards/posix/native_sim/doc/index.html * or - * ${ZEPHYR_BASE}/boards/posix/native_posix/doc/index.rst + * ${ZEPHYR_BASE}/boards/posix/native_sim/doc/index.rst * * Copyright (c) 2023 Marko Sagadin * SPDX-License-Identifier: Apache-2.0 diff --git a/drivers/serial/uart_neorv32.c b/drivers/serial/uart_neorv32.c index 547d1f46efb..5c14b18060e 100644 --- a/drivers/serial/uart_neorv32.c +++ b/drivers/serial/uart_neorv32.c @@ -11,9 +11,11 @@ #include #include #include - #include #include + +#include + LOG_MODULE_REGISTER(uart_neorv32, CONFIG_UART_LOG_LEVEL); /* NEORV32 UART registers offsets */ diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 3a62057a47a..099a4f55937 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -484,7 +484,11 @@ static int wait_tx_ready(const struct device *dev) /* wait arbitrary time before back off. */ bool res; +#if defined(CONFIG_ARCH_POSIX) + NRFX_WAIT_FOR(is_tx_ready(dev), 33, 3, res); +#else NRFX_WAIT_FOR(is_tx_ready(dev), 100, 1, res); +#endif if (res) { key = irq_lock(); @@ -1378,8 +1382,9 @@ static void txstopped_isr(const struct device *dev) user_callback(dev, &evt); } -static void uarte_nrfx_isr_async(const struct device *dev) +static void uarte_nrfx_isr_async(const void *arg) { + const struct device *dev = arg; NRF_UARTE_Type *uarte = get_uarte_instance(dev); struct uarte_nrfx_data *data = dev->data; @@ -1501,6 +1506,7 @@ static void uarte_nrfx_poll_out(const struct device *dev, unsigned char c) } irq_unlock(key); + Z_SPIN_DELAY(3); } } else { key = wait_tx_ready(dev); @@ -1745,6 +1751,11 @@ static int uarte_instance_init(const struct device *dev, data->dev = dev; +#ifdef CONFIG_ARCH_POSIX + /* For simulation the DT provided peripheral address needs to be corrected */ + ((struct pinctrl_dev_config *)cfg->pcfg)->reg = (uintptr_t)cfg->uarte_regs; +#endif + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (err < 0) { return err; @@ -1918,6 +1929,7 @@ static int uarte_nrfx_pm_action(const struct device *dev, !nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ERROR)) { /* Busy wait for event to register */ + Z_SPIN_DELAY(2); } nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED); nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXTO); @@ -1983,7 +1995,7 @@ static int uarte_nrfx_pm_action(const struct device *dev, }; \ static const struct uarte_nrfx_config uarte_##idx##z_config = { \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \ - .uarte_regs = (NRF_UARTE_Type *)DT_REG_ADDR(UARTE(idx)), \ + .uarte_regs = _CONCAT(NRF_UARTE, idx), \ .flags = \ (IS_ENABLED(CONFIG_UART_##idx##_GPIO_MANAGEMENT) ? \ UARTE_CFG_FLAG_GPIO_MGMT : 0) | \ diff --git a/drivers/serial/uart_nrfx_uarte2.c b/drivers/serial/uart_nrfx_uarte2.c new file mode 100644 index 00000000000..750c211efb0 --- /dev/null +++ b/drivers/serial/uart_nrfx_uarte2.c @@ -0,0 +1,1036 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Driver for Nordic Semiconductor nRF UARTE + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define LOG_MODULE_NAME uarte +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_UART_LOG_LEVEL); + +#define INSTANCE_INT_DRIVEN(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_INTERRUPT_DRIVEN) + +#define INSTANCE_ASYNC(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_ASYNC) + +#define INSTANCE_POLLING(periph, prefix, id, _) \ + UTIL_AND(CONFIG_HAS_HW_NRF_UARTE##prefix##id, \ + UTIL_AND(COND_CODE_1(CONFIG_UART_##prefix##id##_INTERRUPT_DRIVEN, (0), (1)), \ + COND_CODE_1(CONFIG_UART_##prefix##id##_ASYNC, (0), (1)))) + +#define INSTANCE_ENHANCED_POLL_OUT(periph, prefix, i, _) \ + IS_ENABLED(CONFIG_UART_##prefix##i##_ENHANCED_POLL_OUT) + +/* Macro determining if any instance is using interrupt driven API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_INT_DRIVEN, (+), (0), _)) +#define UARTE_ANY_INTERRUPT_DRIVEN 1 +#else +#define UARTE_ANY_INTERRUPT_DRIVEN 0 +#endif + +/* Macro determining if any instance is enabled and using ASYNC API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ASYNC, (+), (0), _)) +#define UARTE_ANY_ASYNC 1 +#else +#define UARTE_ANY_ASYNC 0 +#endif + +/* Macro determining if any instance is using only polling API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_POLLING, (+), (0), _)) +#define UARTE_ANY_POLLING 1 +#else +#define UARTE_ANY_POLLING 0 +#endif + +/* Macro determining if any instance is using interrupt driven API. */ +#if (NRFX_FOREACH_ENABLED(UARTE, INSTANCE_ENHANCED_POLL_OUT, (+), (0), _)) +#define UARTE_ENHANCED_POLL_OUT 1 +#else +#define UARTE_ENHANCED_POLL_OUT 0 +#endif + +#if UARTE_ANY_INTERRUPT_DRIVEN || UARTE_ANY_ASYNC +#define UARTE_INT_ASYNC 1 +#else +#define UARTE_INT_ASYNC 0 +#endif + +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) +#define UARTE_ODD_PARITY_ALLOWED 1 +#else +#define UARTE_ODD_PARITY_ALLOWED 0 +#endif + +/* + * RX timeout is divided into time slabs, this define tells how many divisions + * should be made. More divisions - higher timeout accuracy and processor usage. + */ +#define RX_TIMEOUT_DIV 5 + +/* Macro for converting numerical baudrate to register value. It is convenient + * to use this approach because for constant input it can calculate nrf setting + * at compile time. + */ +#define NRF_BAUDRATE(baudrate) ((baudrate) == 300 ? 0x00014000 :\ + (baudrate) == 600 ? 0x00027000 : \ + (baudrate) == 1200 ? NRF_UARTE_BAUDRATE_1200 : \ + (baudrate) == 2400 ? NRF_UARTE_BAUDRATE_2400 : \ + (baudrate) == 4800 ? NRF_UARTE_BAUDRATE_4800 : \ + (baudrate) == 9600 ? NRF_UARTE_BAUDRATE_9600 : \ + (baudrate) == 14400 ? NRF_UARTE_BAUDRATE_14400 : \ + (baudrate) == 19200 ? NRF_UARTE_BAUDRATE_19200 : \ + (baudrate) == 28800 ? NRF_UARTE_BAUDRATE_28800 : \ + (baudrate) == 31250 ? NRF_UARTE_BAUDRATE_31250 : \ + (baudrate) == 38400 ? NRF_UARTE_BAUDRATE_38400 : \ + (baudrate) == 56000 ? NRF_UARTE_BAUDRATE_56000 : \ + (baudrate) == 57600 ? NRF_UARTE_BAUDRATE_57600 : \ + (baudrate) == 76800 ? NRF_UARTE_BAUDRATE_76800 : \ + (baudrate) == 115200 ? NRF_UARTE_BAUDRATE_115200 : \ + (baudrate) == 230400 ? NRF_UARTE_BAUDRATE_230400 : \ + (baudrate) == 250000 ? NRF_UARTE_BAUDRATE_250000 : \ + (baudrate) == 460800 ? NRF_UARTE_BAUDRATE_460800 : \ + (baudrate) == 921600 ? NRF_UARTE_BAUDRATE_921600 : \ + (baudrate) == 1000000 ? NRF_UARTE_BAUDRATE_1000000 : 0) + +#define UARTE_DATA_FLAG_TRAMPOLINE BIT(0) +#define UARTE_DATA_FLAG_RX_ENABLED BIT(1) + +struct uarte_async_data { + uart_callback_t user_callback; + void *user_data; + + struct k_timer tx_timer; + struct k_timer rx_timer; + + k_timeout_t rx_timeout; + + /* Keeps the most recent error mask. */ + uint32_t err; + + uint8_t idle_cnt; +}; + +/* Device data structure */ +struct uarte_nrfx_data { + struct uart_async_to_irq_data *a2i_data; +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + struct uart_config uart_config; +#endif + struct uarte_async_data *async; + atomic_t flags; + uint8_t rx_byte; +}; +BUILD_ASSERT(offsetof(struct uarte_nrfx_data, a2i_data) == 0); + +/* If set then pins are managed when going to low power mode. */ +#define UARTE_CFG_FLAG_GPIO_MGMT BIT(0) + +/* If set then receiver is not used. */ +#define UARTE_CFG_FLAG_NO_RX BIT(1) + +/* If set then instance is using interrupt driven API. */ +#define UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API BIT(2) + +/** + * @brief Structure for UARTE configuration. + */ +struct uarte_nrfx_config { + const struct uart_async_to_irq_config *a2i_config; + nrfx_uarte_t nrfx_dev; + nrfx_uarte_config_t nrfx_config; + const struct pinctrl_dev_config *pcfg; + uint32_t flags; + + LOG_INSTANCE_PTR_DECLARE(log); +}; +BUILD_ASSERT(offsetof(struct uarte_nrfx_config, a2i_config) == 0); + +#define UARTE_ERROR_FROM_MASK(mask) \ + ((mask) & NRF_UARTE_ERROR_OVERRUN_MASK ? UART_ERROR_OVERRUN \ + : (mask) & NRF_UARTE_ERROR_PARITY_MASK ? UART_ERROR_PARITY \ + : (mask) & NRF_UARTE_ERROR_FRAMING_MASK ? UART_ERROR_FRAMING \ + : (mask) & NRF_UARTE_ERROR_BREAK_MASK ? UART_BREAK \ + : 0) + +/* Determine if the device has interrupt driven API enabled. */ +#define IS_INT_DRIVEN_API(dev) \ + (UARTE_ANY_INTERRUPT_DRIVEN && \ + (((const struct uarte_nrfx_config *)dev->config)->flags & \ + UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API)) + +/* Determine if the device supports only polling API. */ +#define IS_POLLING_API(dev) \ + (!UARTE_INT_ASYNC || (((struct uarte_nrfx_data *)dev->data)->async == NULL)) + +/* Determine if the device supports asynchronous API. */ +#define IS_ASYNC_API(dev) (!IS_INT_DRIVEN_API(dev) && !IS_POLLING_API(dev)) + +static inline const nrfx_uarte_t *get_nrfx_dev(const struct device *dev) +{ + const struct uarte_nrfx_config *config = dev->config; + + return &config->nrfx_dev; +} + +static int callback_set(const struct device *dev, uart_callback_t callback, void *user_data) +{ + struct uarte_nrfx_data *data = dev->data; + + data->async->user_callback = callback; + data->async->user_data = user_data; + + return 0; +} + +#if UARTE_ANY_ASYNC +static int api_callback_set(const struct device *dev, uart_callback_t callback, void *user_data) +{ + if (!IS_ASYNC_API(dev)) { + return -ENOTSUP; + } + + return callback_set(dev, callback, user_data); +} +#endif + +static void on_tx_done(const struct device *dev, const nrfx_uarte_event_t *event) +{ + struct uarte_nrfx_data *data = dev->data; + struct uart_event evt = { + .type = (event->data.tx.flags & NRFX_UARTE_TX_DONE_ABORTED) ? + UART_TX_ABORTED : UART_TX_DONE, + .data.tx.buf = event->data.tx.p_buffer, + .data.tx.len = event->data.tx.length + }; + bool hwfc; + +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS; +#else + const struct uarte_nrfx_config *config = dev->config; + + hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED; +#endif + + if (hwfc) { + k_timer_stop(&data->async->tx_timer); + } + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void on_rx_done(const struct device *dev, const nrfx_uarte_event_t *event) +{ + struct uarte_nrfx_data *data = dev->data; + struct uart_event evt; + + if (event->data.rx.length) { + if (data->async->err) { + evt.type = UART_RX_STOPPED; + evt.data.rx_stop.reason = UARTE_ERROR_FROM_MASK(data->async->err); + evt.data.rx_stop.data.buf = event->data.rx.p_buffer; + evt.data.rx_stop.data.len = event->data.rx.length; + /* Keep error code for uart_err_check(). */ + if (!IS_INT_DRIVEN_API(dev)) { + data->async->err = 0; + } + } else { + evt.type = UART_RX_RDY, + evt.data.rx.buf = event->data.rx.p_buffer, + evt.data.rx.len = event->data.rx.length, + evt.data.rx.offset = 0; + } + data->async->user_callback(dev, &evt, data->async->user_data); + } + + evt.type = UART_RX_BUF_RELEASED; + evt.data.rx_buf.buf = event->data.rx.p_buffer; + + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void start_rx_timer(struct uarte_nrfx_data *data) +{ + struct uarte_async_data *adata = data->async; + + k_timer_start(&adata->rx_timer, adata->rx_timeout, K_NO_WAIT); +} + +static void on_rx_byte(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + nrfx_uarte_rxdrdy_disable(nrfx_dev); + adata->idle_cnt = RX_TIMEOUT_DIV; + start_rx_timer(data); +} + +static void on_rx_buf_req(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + struct uart_event evt = { + .type = UART_RX_BUF_REQUEST + }; + + /* If counter reached zero that indicates that timeout was reached and + * reception of one buffer was terminated to restart another transfer. + */ + if (!K_TIMEOUT_EQ(adata->rx_timeout, K_NO_WAIT)) { + /* Read and clear any pending new data information. */ + nrfx_uarte_rx_new_data_check(nrfx_dev); + nrfx_uarte_rxdrdy_enable(nrfx_dev); + } + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void on_rx_disabled(const struct device *dev, struct uarte_nrfx_data *data) +{ + struct uart_event evt = { + .type = UART_RX_DISABLED + }; + + atomic_and(&data->flags, ~UARTE_DATA_FLAG_RX_ENABLED); + k_timer_stop(&data->async->rx_timer); + + data->async->user_callback(dev, &evt, data->async->user_data); +} + +static void trigger_handler(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + + if (UARTE_ANY_INTERRUPT_DRIVEN && + atomic_and(&data->flags, ~UARTE_DATA_FLAG_TRAMPOLINE) & + UARTE_DATA_FLAG_TRAMPOLINE) { + uart_async_to_irq_trampoline_cb(dev); + } +} + +static void evt_handler(nrfx_uarte_event_t const *event, void *context) +{ + const struct device *dev = context; + struct uarte_nrfx_data *data = dev->data; + + switch (event->type) { + case NRFX_UARTE_EVT_TX_DONE: + on_tx_done(dev, event); + break; + case NRFX_UARTE_EVT_RX_DONE: + on_rx_done(dev, event); + break; + case NRFX_UARTE_EVT_RX_BYTE: + on_rx_byte(dev); + break; + case NRFX_UARTE_EVT_ERROR: + data->async->err = event->data.error.error_mask; + break; + case NRFX_UARTE_EVT_RX_BUF_REQUEST: + on_rx_buf_req(dev); + break; + case NRFX_UARTE_EVT_RX_DISABLED: + on_rx_disabled(dev, data); + break; + case NRFX_UARTE_EVT_RX_BUF_TOO_LATE: + /* No support */ + break; + case NRFX_UARTE_EVT_TRIGGER: + trigger_handler(dev); + break; + default: + __ASSERT_NO_MSG(0); + } +} + +static int api_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout) +{ + struct uarte_nrfx_data *data = dev->data; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + bool hwfc; + +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + hwfc = data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS; +#else + const struct uarte_nrfx_config *config = dev->config; + + hwfc = config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED; +#endif + + err = nrfx_uarte_tx(nrfx_dev, buf, len, 0); + if (err != NRFX_SUCCESS) { + return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO; + } + + if (hwfc && timeout != SYS_FOREVER_US) { + k_timer_start(&data->async->tx_timer, K_USEC(timeout), K_NO_WAIT); + } + + return 0; +} + +static int api_tx_abort(const struct device *dev) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + + err = nrfx_uarte_tx_abort(nrfx_dev, false); + return (err == NRFX_SUCCESS) ? 0 : -EFAULT; +} + +static void tx_timeout_handler(struct k_timer *timer) +{ + const struct device *dev = k_timer_user_data_get(timer); + + (void)api_tx_abort(dev); +} + +static void rx_timeout_handler(struct k_timer *timer) +{ + const struct device *dev = (const struct device *)k_timer_user_data_get(timer); + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + + if (nrfx_uarte_rx_new_data_check(nrfx_dev)) { + adata->idle_cnt = RX_TIMEOUT_DIV - 1; + } else { + adata->idle_cnt--; + if (adata->idle_cnt == 0) { + (void)nrfx_uarte_rx_abort(nrfx_dev, false, false); + return; + } + } + + start_rx_timer(data); +} + +/* Determine if RX FIFO content shall be kept when device is being disabled. + * When flow-control is used then we expect to keep RX FIFO content since HWFC + * enforces lossless communication. However, when HWFC is not used (by any instance + * then RX FIFO handling feature is disabled in the nrfx_uarte to save space. + * It is based on assumption that without HWFC it is expected that some data may + * be lost and there are means to prevent that (keeping receiver always opened by + * provided reception buffers on time). + */ +static inline uint32_t get_keep_fifo_content_flag(const struct device *dev) +{ +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + struct uarte_nrfx_data *data = dev->data; + + if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { + return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT; + } +#else + const struct uarte_nrfx_config *config = dev->config; + + if (config->nrfx_config.config.hwfc == NRF_UARTE_HWFC_ENABLED) { + return NRFX_UARTE_RX_ENABLE_KEEP_FIFO_CONTENT; + } +#endif + + return 0; +} + +static int api_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout) +{ + nrfx_err_t err; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + struct uarte_async_data *adata = data->async; + uint32_t flags = NRFX_UARTE_RX_ENABLE_CONT | + get_keep_fifo_content_flag(dev) | + (IS_ASYNC_API(dev) ? NRFX_UARTE_RX_ENABLE_STOP_ON_END : 0); + + if (cfg->flags & UARTE_CFG_FLAG_NO_RX) { + return -ENOTSUP; + } + + if (timeout != SYS_FOREVER_US) { + adata->idle_cnt = RX_TIMEOUT_DIV + 1; + adata->rx_timeout = K_USEC(timeout / RX_TIMEOUT_DIV); + } else { + adata->rx_timeout = K_NO_WAIT; + } + + err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); + if (err != NRFX_SUCCESS) { + return -EIO; + } + + err = nrfx_uarte_rx_enable(nrfx_dev, flags); + if (err != NRFX_SUCCESS) { + return (err == NRFX_ERROR_BUSY) ? -EBUSY : -EIO; + } + + atomic_or(&data->flags, UARTE_DATA_FLAG_RX_ENABLED); + + return 0; +} + +static int api_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + struct uarte_nrfx_data *data = dev->data; + nrfx_err_t err; + + if (!(data->flags & UARTE_DATA_FLAG_RX_ENABLED)) { + return -EACCES; + } + + err = nrfx_uarte_rx_buffer_set(nrfx_dev, buf, len); + switch (err) { + case NRFX_SUCCESS: + return 0; + case NRFX_ERROR_BUSY: + return -EBUSY; + default: + return -EIO; + } +} + +static int api_rx_disable(const struct device *dev) +{ + struct uarte_nrfx_data *data = dev->data; + + k_timer_stop(&data->async->rx_timer); + + return (nrfx_uarte_rx_abort(get_nrfx_dev(dev), true, false) == NRFX_SUCCESS) ? 0 : -EFAULT; +} + +static int api_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uarte_nrfx_config *cfg = dev->config; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + nrfx_err_t err; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_fifo_read(dev, c, 1) == 0 ? -1 : 0; + } + + if (IS_ASYNC_API(dev)) { + return -EBUSY; + } + + err = nrfx_uarte_rx_ready(instance, NULL); + if (err == NRFX_SUCCESS) { + uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer; + + *c = *rx_byte; + err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + return 0; + } + + return -1; +} + +static void api_poll_out(const struct device *dev, unsigned char out_char) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + nrfx_err_t err; + + do { + /* When runtime PM is used we cannot use early return because then + * we have no information when UART is actually done with the + * transmission. It reduces UART performance however, polling in + * general is not power efficient and should be avoided in low + * power applications. + */ + err = nrfx_uarte_tx(nrfx_dev, &out_char, 1, NRFX_UARTE_TX_EARLY_RETURN); + __ASSERT(err != NRFX_ERROR_INVALID_ADDR, "Invalid address of the buffer"); + + if (err == NRFX_ERROR_BUSY) { + if (IS_ENABLED(CONFIG_MULTITHREADING) && k_is_preempt_thread()) { + k_msleep(1); + } else { + Z_SPIN_DELAY(3); + } + } + } while (err == NRFX_ERROR_BUSY); +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +/** + * @brief Set the baud rate + * + * This routine set the given baud rate for the UARTE. + * + * @param dev UARTE device struct + * @param baudrate Baud rate + * + * @return 0 on success or error code + */ +static int baudrate_set(NRF_UARTE_Type *uarte, uint32_t baudrate) +{ + nrf_uarte_baudrate_t nrf_baudrate = NRF_BAUDRATE(baudrate); + + if (baudrate == 0) { + return -EINVAL; + } + + nrfy_uarte_baudrate_set(uarte, nrf_baudrate); + + return 0; +} + +static int uarte_nrfx_configure(const struct device *dev, + const struct uart_config *cfg) +{ + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + struct uarte_nrfx_data *data = dev->data; + nrf_uarte_config_t uarte_cfg; + +#if defined(UARTE_CONFIG_STOP_Msk) + switch (cfg->stop_bits) { + case UART_CFG_STOP_BITS_1: + uarte_cfg.stop = NRF_UARTE_STOP_ONE; + break; + case UART_CFG_STOP_BITS_2: + uarte_cfg.stop = NRF_UARTE_STOP_TWO; + break; + default: + return -ENOTSUP; + } +#else + if (cfg->stop_bits != UART_CFG_STOP_BITS_1) { + return -ENOTSUP; + } +#endif + + if (cfg->data_bits != UART_CFG_DATA_BITS_8) { + return -ENOTSUP; + } + + switch (cfg->flow_ctrl) { + case UART_CFG_FLOW_CTRL_NONE: + uarte_cfg.hwfc = NRF_UARTE_HWFC_DISABLED; + break; + case UART_CFG_FLOW_CTRL_RTS_CTS: + uarte_cfg.hwfc = NRF_UARTE_HWFC_ENABLED; + break; + default: + return -ENOTSUP; + } + +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) + uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_EVEN; +#endif + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + uarte_cfg.parity = NRF_UARTE_PARITY_EXCLUDED; + break; + case UART_CFG_PARITY_EVEN: + uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED; + break; +#if defined(UARTE_CONFIG_PARITYTYPE_Msk) + case UART_CFG_PARITY_ODD: + uarte_cfg.parity = NRF_UARTE_PARITY_INCLUDED; + uarte_cfg.paritytype = NRF_UARTE_PARITYTYPE_ODD; + break; +#endif + default: + return -ENOTSUP; + } + + if (baudrate_set(nrfx_dev->p_reg, cfg->baudrate) != 0) { + return -ENOTSUP; + } + + nrfy_uarte_configure(nrfx_dev->p_reg, &uarte_cfg); + + data->uart_config = *cfg; + + return 0; +} + +static int uarte_nrfx_config_get(const struct device *dev, + struct uart_config *cfg) +{ + struct uarte_nrfx_data *data = dev->data; + + *cfg = data->uart_config; + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN +static int api_err_check(const struct device *dev) +{ + if (IS_POLLING_API(dev)) { + const struct uarte_nrfx_config *cfg = dev->config; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + uint32_t mask = nrfx_uarte_errorsrc_get(instance); + + return mask; + } + + struct uarte_nrfx_data *data = dev->data; + uint32_t rv = data->async->err; + + data->async->err = 0; + + return rv; +} +#endif + +static const struct uart_async_to_irq_async_api a2i_api = { + .callback_set = callback_set, + .tx = api_tx, + .tx_abort = api_tx_abort, + .rx_enable = api_rx_enable, + .rx_buf_rsp = api_rx_buf_rsp, + .rx_disable = api_rx_disable, +}; + +static const struct uart_driver_api uart_nrfx_uarte_driver_api = { + .poll_in = api_poll_in, + .poll_out = api_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uarte_nrfx_configure, + .config_get = uarte_nrfx_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if UARTE_ANY_POLLING || UARTE_ANY_INTERRUPT_DRIVEN + .err_check = api_err_check, +#endif +#if UARTE_ANY_ASYNC + .callback_set = api_callback_set, + .tx = api_tx, + .tx_abort = api_tx_abort, + .rx_enable = api_rx_enable, + .rx_buf_rsp = api_rx_buf_rsp, + .rx_disable = api_rx_disable, +#endif /* UARTE_ANY_ASYNC */ +#if UARTE_ANY_INTERRUPT_DRIVEN + UART_ASYNC_TO_IRQ_API_INIT(), +#endif /* UARTE_ANY_INTERRUPT_DRIVEN */ +}; + +static int endtx_stoptx_ppi_init(NRF_UARTE_Type *uarte) +{ + nrfx_err_t ret; + uint8_t ch; + + ret = nrfx_gppi_channel_alloc(&ch); + if (ret != NRFX_SUCCESS) { + LOG_ERR("Failed to allocate PPI Channel"); + return -EIO; + } + + nrfx_gppi_channel_endpoints_setup(ch, + nrfy_uarte_event_address_get(uarte, NRF_UARTE_EVENT_ENDTX), + nrfy_uarte_task_address_get(uarte, NRF_UARTE_TASK_STOPTX)); + nrfx_gppi_channels_enable(BIT(ch)); + + return 0; +} + +static int start_rx(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_async_to_irq_rx_enable(dev); + } + + __ASSERT_NO_MSG(IS_POLLING_API(dev)); + + nrfx_err_t err; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + uint8_t *rx_byte = cfg->nrfx_config.rx_cache.p_buffer; + + err = nrfx_uarte_rx_buffer_set(instance, rx_byte, 1); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + err = nrfx_uarte_rx_enable(instance, 0); + __ASSERT_NO_MSG(err == NRFX_SUCCESS || err == NRFX_ERROR_BUSY); + + (void)err; + + return 0; +} + +static void async_to_irq_trampoline(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + uint32_t prev = atomic_or(&data->flags, UARTE_DATA_FLAG_TRAMPOLINE); + + if (!(prev & UARTE_DATA_FLAG_TRAMPOLINE)) { + nrfx_uarte_int_trigger(&cfg->nrfx_dev); + } +} + +static int uarte_nrfx_init(const struct device *dev) +{ + int err; + nrfx_err_t nerr; + const nrfx_uarte_t *nrfx_dev = get_nrfx_dev(dev); + const struct uarte_nrfx_config *cfg = dev->config; + struct uarte_nrfx_data *data = dev->data; + +#ifdef CONFIG_ARCH_POSIX + /* For simulation the DT provided peripheral address needs to be corrected */ + ((struct pinctrl_dev_config *)cfg->pcfg)->reg = (uintptr_t)nrfx_dev->p_reg; +#endif + + err = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } + + if (UARTE_ENHANCED_POLL_OUT && cfg->nrfx_config.tx_stop_on_end) { + err = endtx_stoptx_ppi_init(nrfx_dev->p_reg); + if (err < 0) { + return err; + } + } + + if (UARTE_ANY_INTERRUPT_DRIVEN) { + if (cfg->a2i_config) { + err = uart_async_to_irq_init(data->a2i_data, cfg->a2i_config); + if (err < 0) { + return err; + } + } + } + + if (IS_ENABLED(UARTE_INT_ASYNC) && data->async) { + k_timer_init(&data->async->rx_timer, rx_timeout_handler, NULL); + k_timer_user_data_set(&data->async->rx_timer, (void *)dev); + k_timer_init(&data->async->tx_timer, tx_timeout_handler, NULL); + k_timer_user_data_set(&data->async->tx_timer, (void *)dev); + } + + nerr = nrfx_uarte_init(nrfx_dev, &cfg->nrfx_config, + IS_ENABLED(UARTE_INT_ASYNC) ? + (IS_POLLING_API(dev) ? NULL : evt_handler) : NULL); + if (nerr == NRFX_SUCCESS && !IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + err = start_rx(dev); + } + + switch (nerr) { + case NRFX_ERROR_INVALID_STATE: + return -EBUSY; + case NRFX_ERROR_BUSY: + return -EACCES; + case NRFX_ERROR_INVALID_PARAM: + return -EINVAL; + default: + return 0; + } +} + +#ifdef CONFIG_PM_DEVICE +static int stop_rx(const struct device *dev) +{ + const struct uarte_nrfx_config *cfg = dev->config; + + if (IS_INT_DRIVEN_API(dev)) { + return uart_async_to_irq_rx_disable(dev); + } + + __ASSERT_NO_MSG(IS_POLLING_API(dev)); + nrfx_err_t err; + const nrfx_uarte_t *instance = &cfg->nrfx_dev; + + err = nrfx_uarte_rx_abort(instance, true, true); + __ASSERT_NO_MSG(err == NRFX_SUCCESS); + + return 0; +} + +static int uarte_nrfx_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct uarte_nrfx_config *cfg = dev->config; + int ret; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) { + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + } + if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + return start_rx(dev); + } + + break; + case PM_DEVICE_ACTION_SUSPEND: + if (!IS_ASYNC_API(dev) && !(cfg->flags & UARTE_CFG_FLAG_NO_RX)) { + stop_rx(dev); + } + + if (cfg->flags & UARTE_CFG_FLAG_GPIO_MGMT) { + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_SLEEP); + if (ret < 0) { + return ret; + } + } + + break; + default: + return -ENOTSUP; + } + + return 0; +} +#endif + +#if defined(UARTE_CONFIG_STOP_Msk) +#define UARTE_HAS_STOP_CONFIG 1 +#endif + +#define UARTE(idx) DT_NODELABEL(uart##idx) +#define UARTE_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(UARTE(idx), prop) +#define UARTE_PROP(idx, prop) DT_PROP(UARTE(idx), prop) + +/* Macro returning initial log level. Logs are off for UART used for console. */ +#define GET_INIT_LOG_LEVEL(idx) \ + COND_CODE_1(DT_HAS_CHOSEN(zephyr_console), \ + (DT_SAME_NODE(UARTE(idx), \ + DT_CHOSEN(zephyr_console)) ? \ + LOG_LEVEL_NONE : CONFIG_UART_LOG_LEVEL), \ + (CONFIG_UART_LOG_LEVEL)) + +/* Macro puts buffers in dedicated section if device tree property is set. */ +#define UARTE_MEMORY_SECTION(idx) \ + COND_CODE_1(UARTE_HAS_PROP(idx, memory_regions), \ + (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \ + DT_PHANDLE(UARTE(idx), memory_regions)))))), \ + ()) + +#define UART_NRF_UARTE_DEVICE(idx) \ + LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, GET_INIT_LOG_LEVEL(idx)); \ + static uint8_t uarte##idx##_tx_cache[CONFIG_UART_##idx##_TX_CACHE_SIZE] \ + UARTE_MEMORY_SECTION(idx) __aligned(4); \ + static uint8_t uarte##idx##_rx_cache[CONFIG_UART_##idx##_RX_CACHE_SIZE] \ + UARTE_MEMORY_SECTION(idx) __aligned(4); \ + static nrfx_uarte_rx_cache_t uarte##idx##_rx_cache_scratch; \ + IF_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (static uint8_t a2i_rx_buf##idx[CONFIG_UART_##idx##_A2I_RX_SIZE];)) \ + PINCTRL_DT_DEFINE(UARTE(idx)); \ + static const struct uart_async_to_irq_config uarte_a2i_config_##idx = \ + UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(&a2i_api, \ + async_to_irq_trampoline, \ + UARTE_PROP(idx, current_speed), \ + uarte##idx##_tx_cache, \ + /* nrfx_uarte driver is using the last byte in the */ \ + /* cache buffer for keeping a byte that is currently*/\ + /* polled out so it cannot be used as a cache buffer*/\ + /* by the adaptation layer. */ \ + sizeof(uarte##idx##_tx_cache) - 1, \ + COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (a2i_rx_buf##idx), (NULL)), \ + COND_CODE_1(CONFIG_UART_##idx##_INTERRUPT_DRIVEN, \ + (sizeof(a2i_rx_buf##idx)), (0)), \ + CONFIG_UART_##idx##_A2I_RX_BUF_COUNT, \ + LOG_INSTANCE_PTR(LOG_MODULE_NAME, idx)); \ + static const struct uarte_nrfx_config uarte_config_##idx = { \ + .a2i_config = IS_ENABLED(CONFIG_UART_##idx## _INTERRUPT_DRIVEN) ? \ + &uarte_a2i_config_##idx : NULL, \ + .nrfx_dev = NRFX_UARTE_INSTANCE(idx), \ + .nrfx_config = { \ + .p_context = (void *)DEVICE_DT_GET(UARTE(idx)), \ + .tx_cache = { \ + .p_buffer = uarte##idx##_tx_cache, \ + .length = CONFIG_UART_##idx##_TX_CACHE_SIZE \ + }, \ + .rx_cache = { \ + .p_buffer = uarte##idx##_rx_cache, \ + .length = CONFIG_UART_##idx##_RX_CACHE_SIZE \ + }, \ + .p_rx_cache_scratch = &uarte##idx##_rx_cache_scratch, \ + .baudrate = NRF_BAUDRATE(UARTE_PROP(idx, current_speed)), \ + .interrupt_priority = DT_IRQ(UARTE(idx), priority), \ + .config = { \ + .hwfc = (UARTE_PROP(idx, hw_flow_control) == \ + UART_CFG_FLOW_CTRL_RTS_CTS) ? \ + NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED, \ + .parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \ + NRF_UARTE_PARITY_INCLUDED : NRF_UARTE_PARITY_EXCLUDED, \ + IF_ENABLED(UARTE_HAS_STOP_CONFIG, (.stop = NRF_UARTE_STOP_ONE,))\ + IF_ENABLED(UARTE_ODD_PARITY_ALLOWED, \ + (.paritytype = NRF_UARTE_PARITYTYPE_EVEN,)) \ + }, \ + .tx_stop_on_end = IS_ENABLED(CONFIG_UART_##idx##_ENHANCED_POLL_OUT), \ + .skip_psel_cfg = true, \ + .skip_gpio_cfg = true, \ + }, \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \ + .flags = (UARTE_PROP(idx, disable_rx) ? UARTE_CFG_FLAG_NO_RX : 0) | \ + (IS_ENABLED(CONFIG_UART_##idx##_GPIO_MANAGEMENT) ? \ + UARTE_CFG_FLAG_GPIO_MGMT : 0) | \ + (IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \ + UARTE_CFG_FLAG_INTERRUPT_DRIVEN_API : 0), \ + LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \ + }; \ + static struct uart_async_to_irq_data uarte_a2i_data_##idx; \ + static struct uarte_async_data uarte_async_##idx; \ + static struct uarte_nrfx_data uarte_data_##idx = { \ + .a2i_data = IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) ? \ + &uarte_a2i_data_##idx : NULL, \ + IF_ENABLED(CONFIG_UART_USE_RUNTIME_CONFIGURE, \ + (.uart_config = { \ + .baudrate = UARTE_PROP(idx, current_speed), \ + .parity = IS_ENABLED(CONFIG_UART_##idx##_NRF_PARITY_BIT) ? \ + UART_CFG_PARITY_EVEN : UART_CFG_PARITY_NONE, \ + .stop_bits = UART_CFG_STOP_BITS_1, \ + .data_bits = UART_CFG_DATA_BITS_8, \ + .flow_ctrl = UARTE_PROP(idx, hw_flow_control) ? \ + UART_CFG_FLOW_CTRL_RTS_CTS : UART_CFG_FLOW_CTRL_NONE, \ + },)) \ + .async = (IS_ENABLED(CONFIG_UART_##idx##_INTERRUPT_DRIVEN) || \ + IS_ENABLED(CONFIG_UART_##idx##_ASYNC)) ? &uarte_async_##idx : NULL \ + }; \ + static int uarte_init_##idx(const struct device *dev) \ + { \ + COND_CODE_1(INSTANCE_POLLING(_, /*empty*/, idx, _), (), \ + ( \ + IRQ_CONNECT(DT_IRQN(UARTE(idx)), DT_IRQ(UARTE(idx), priority), \ + nrfx_isr, nrfx_uarte_##idx##_irq_handler, 0); \ + irq_enable(DT_IRQN(UARTE(idx))); \ + ) \ + ) \ + return uarte_nrfx_init(dev); \ + } \ + PM_DEVICE_DT_DEFINE(UARTE(idx), uarte_nrfx_pm_action); \ + DEVICE_DT_DEFINE(UARTE(idx), \ + uarte_init_##idx, \ + PM_DEVICE_DT_GET(UARTE(idx)), \ + &uarte_data_##idx, \ + &uarte_config_##idx, \ + PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &uart_nrfx_uarte_driver_api) + +/* Macro creates device instance if it is enabled in devicetree. */ +#define UARTE_DEVICE(periph, prefix, id, _) \ + IF_ENABLED(CONFIG_HAS_HW_NRF_UARTE##prefix##id, (UART_NRF_UARTE_DEVICE(prefix##id);)) + +/* Macro iterates over nrfx_uarte instances enabled in the nrfx_config.h. */ +NRFX_FOREACH_ENABLED(UARTE, UARTE_DEVICE, (), (), _) diff --git a/drivers/serial/uart_ns16550.c b/drivers/serial/uart_ns16550.c index a41cdca7843..bf07240c0ce 100644 --- a/drivers/serial/uart_ns16550.c +++ b/drivers/serial/uart_ns16550.c @@ -45,6 +45,7 @@ LOG_MODULE_REGISTER(uart_ns16550, CONFIG_UART_LOG_LEVEL); #define UART_NS16550_PCP_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(pcp) #define UART_NS16550_DLF_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dlf) +#define UART_NS16550_DMAS_ENABLED DT_ANY_INST_HAS_PROP_STATUS_OKAY(dmas) #if DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); @@ -58,6 +59,16 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #include #endif +#if defined(CONFIG_UART_ASYNC_API) +#include +#include + +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#include +#endif + +#endif + /* If any node has property io-mapped set, we need to support IO port * access in the code and device config struct. * @@ -90,6 +101,12 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define REG_PCP 0x200 /* PRV_CLOCK_PARAMS (Apollo Lake) */ #define REG_MDR1 0x08 /* Mode control reg. (TI_K3) */ +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define REG_LPSS_SRC_TRAN 0xAF8 /* SRC Transfer LPSS DMA */ +#define REG_LPSS_CLR_SRC_TRAN 0xB48 /* Clear SRC Tran LPSS DMA */ +#define REG_LPSS_MST 0xB20 /* Mask SRC Transfer LPSS DMA */ +#endif + /* equates for interrupt enable register */ #define IER_RXRDY 0x01 /* receiver data ready */ @@ -240,6 +257,14 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define DLF(dev) (get_port(dev) + REG_DLF) #define PCP(dev) (get_port(dev) + REG_PCP) +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#define SRC_TRAN(dev) (get_port(dev) + REG_LPSS_SRC_TRAN) +#define CLR_SRC_TRAN(dev) (get_port(dev) + REG_LPSS_CLR_SRC_TRAN) +#define MST(dev) (get_port(dev) + REG_LPSS_MST) + +#define UNMASK_LPSS_INT(chan) (BIT(chan) | (BIT(8) << chan)) /* unmask LPSS DMA Interrupt */ +#endif + #define IIRC(dev) (((struct uart_ns16550_dev_data *)(dev)->data)->iir_cache) #ifdef CONFIG_UART_NS16550_ITE_HIGH_SPEED_BUADRATE @@ -259,6 +284,45 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_PCIE), "NS16550(s) in DT need CONFIG_PCIE"); #define ECSPMR(dev) (get_port(dev) + REG_ECSPMR * reg_interval(dev)) #endif +#if defined(CONFIG_UART_ASYNC_API) +struct uart_ns16550_rx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + uint8_t *buf; + size_t buf_len; + size_t offset; + size_t counter; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_tx_dma_params { + const struct device *dma_dev; + uint8_t dma_channel; + struct dma_config dma_cfg; + struct dma_block_config active_dma_block; + const uint8_t *buf; + size_t buf_len; + struct k_work_delayable timeout_work; + size_t timeout_us; +}; + +struct uart_ns16550_async_data { + const struct device *uart_dev; + struct uart_ns16550_tx_dma_params tx_dma_params; + struct uart_ns16550_rx_dma_params rx_dma_params; + uint8_t *next_rx_buffer; + size_t next_rx_buffer_len; + uart_callback_t user_callback; + void *user_data; +}; + +static void uart_ns16550_async_rx_timeout(struct k_work *work); +static void uart_ns16550_async_tx_timeout(struct k_work *work); +#endif + /* device config */ struct uart_ns16550_device_config { union { @@ -309,6 +373,11 @@ struct uart_ns16550_dev_data { #if defined(CONFIG_UART_INTERRUPT_DRIVEN) && defined(CONFIG_PM) bool tx_stream_on; #endif + +#if defined(CONFIG_UART_ASYNC_API) + uint64_t phys_addr; + struct uart_ns16550_async_data async; +#endif }; static void ns16550_outbyte(const struct uart_ns16550_device_config *cfg, @@ -358,7 +427,8 @@ static uint8_t ns16550_inbyte(const struct uart_ns16550_device_config *cfg, return 0; } -#if UART_NS16550_PCP_ENABLED +#if (defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) & (defined(CONFIG_UART_ASYNC_API)))\ + | UART_NS16550_PCP_ENABLED static void ns16550_outword(const struct uart_ns16550_device_config *cfg, uintptr_t port, uint32_t val) { @@ -689,6 +759,16 @@ static int uart_reset_config(const struct reset_dt_spec *reset_spec) } #endif /* UART_NS16550_RESET_ENABLED */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static inline void async_timer_start(struct k_work_delayable *work, size_t timeout_us) +{ + if ((timeout_us != SYS_FOREVER_US) && (timeout_us != 0)) { + k_work_reschedule(work, K_USEC(timeout_us)); + } +} + +#endif + /** * @brief Initialize individual UART port * @@ -729,6 +809,12 @@ static int uart_ns16550_init(const struct device *dev) device_map(DEVICE_MMIO_RAM_PTR(dev), mbar.phys_addr, mbar.size, K_MEM_CACHE_NONE); +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + pcie_set_cmd(dev_cfg->pcie->bdf, PCIE_CONF_CMDSTAT_MASTER, true); + data->phys_addr = mbar.phys_addr; + } +#endif } else #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(pcie) */ { @@ -741,7 +827,37 @@ static int uart_ns16550_init(const struct device *dev) DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); } } - +#if defined(CONFIG_UART_ASYNC_API) + if (data->async.tx_dma_params.dma_dev != NULL) { + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + data->async.uart_dev = dev; + k_work_init_delayable(&data->async.rx_dma_params.timeout_work, + uart_ns16550_async_rx_timeout); + k_work_init_delayable(&data->async.tx_dma_params.timeout_work, + uart_ns16550_async_tx_timeout); + data->async.rx_dma_params.dma_cfg.head_block = + &data->async.rx_dma_params.active_dma_block; + data->async.tx_dma_params.dma_cfg.head_block = + &data->async.tx_dma_params.active_dma_block; +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) +#if UART_NS16550_IOPORT_ENABLED + if (!dev_cfg->io_map) +#endif + { + uintptr_t base; + + base = DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_OFFSET; + dma_intel_lpss_set_base(data->async.tx_dma_params.dma_dev, base); + dma_intel_lpss_setup(data->async.tx_dma_params.dma_dev); + sys_write32((uint32_t)data->phys_addr, + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_LOW); + sys_write32((uint32_t)(data->phys_addr >> DMA_INTEL_LPSS_ADDR_RIGHT_SHIFT), + DEVICE_MMIO_GET(dev) + DMA_INTEL_LPSS_REMAP_HI); + } +#endif + } +#endif ret = uart_ns16550_configure(dev, &data->uart_config); if (ret != 0) { return ret; @@ -1155,6 +1271,29 @@ static void uart_ns16550_isr(const struct device *dev) if (dev_data->cb) { dev_data->cb(dev, dev_data->cb_data); } +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) + if (dev_data->async.tx_dma_params.dma_dev != NULL) { + const struct uart_ns16550_device_config * const config = dev->config; + uint8_t IIR_status = ns16550_inbyte(config, IIR(dev)); +#if (IS_ENABLED(CONFIG_UART_NS16550_INTEL_LPSS_DMA)) + uint32_t dma_status = ns16550_inword(config, SRC_TRAN(dev)); + + if (dma_status & BIT(dev_data->async.rx_dma_params.dma_channel)) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + ns16550_outword(config, CLR_SRC_TRAN(dev), + BIT(dev_data->async.rx_dma_params.dma_channel)); + return; + } + dma_intel_lpss_isr(dev_data->async.rx_dma_params.dma_dev); +#endif + if (IIR_status & IIR_RBRF) { + async_timer_start(&dev_data->async.rx_dma_params.timeout_work, + dev_data->async.rx_dma_params.timeout_us); + return; + } + } +#endif #ifdef CONFIG_UART_NS16550_WA_ISR_REENABLE_INTERRUPT const struct uart_ns16550_device_config * const dev_cfg = dev->config; @@ -1257,6 +1396,351 @@ static int uart_ns16550_drv_cmd(const struct device *dev, uint32_t cmd, #endif /* CONFIG_UART_NS16550_DRV_CMD */ +#if (IS_ENABLED(CONFIG_UART_ASYNC_API)) +static void async_user_callback(const struct device *dev, struct uart_event *evt) +{ + const struct uart_ns16550_dev_data *data = dev->data; + + if (data->async.user_callback) { + data->async.user_callback(dev, evt, data->async.user_data); + } +} + +#if UART_NS16550_DMAS_ENABLED +static void async_evt_tx_done(struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + struct uart_event event = { + .type = UART_TX_DONE, + .data.tx.buf = tx_params->buf, + .data.tx.len = tx_params->buf_len + }; + + tx_params->buf = NULL; + tx_params->buf_len = 0U; + + async_user_callback(dev, &event); +} +#endif + +static void async_evt_rx_rdy(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + + struct uart_event event = { + .type = UART_RX_RDY, + .data.rx.buf = dma_params->buf, + .data.rx.len = dma_params->counter - dma_params->offset, + .data.rx.offset = dma_params->offset + }; + + dma_params->offset = dma_params->counter; + + if (event.data.rx.len > 0) { + async_user_callback(dev, &event); + } +} + +static void async_evt_rx_buf_release(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_event evt = { + .type = UART_RX_BUF_RELEASED, + .data.rx_buf.buf = data->async.rx_dma_params.buf + }; + + async_user_callback(dev, &evt); + data->async.rx_dma_params.buf = NULL; + data->async.rx_dma_params.buf_len = 0U; + data->async.rx_dma_params.offset = 0U; + data->async.rx_dma_params.counter = 0U; +} + +static void async_evt_rx_buf_request(const struct device *dev) +{ + struct uart_event evt = { + .type = UART_RX_BUF_REQUEST + }; + async_user_callback(dev, &evt); +} + +static void uart_ns16550_async_rx_flush(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + struct dma_status status; + + dma_get_status(dma_params->dma_dev, + dma_params->dma_channel, + &status); + + const int rx_count = dma_params->buf_len - status.pending_length; + + if (rx_count > dma_params->counter) { + dma_params->counter = rx_count; + async_evt_rx_rdy(dev); + } +} + +static int uart_ns16550_rx_disable(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *dma_params = &data->async.rx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.rx_dma_params.timeout_work); + + if (dma_params->buf && (dma_params->buf_len > 0)) { + uart_ns16550_async_rx_flush(dev); + async_evt_rx_buf_release(dev); + if (data->async.next_rx_buffer != NULL) { + dma_params->buf = data->async.next_rx_buffer; + dma_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0; + async_evt_rx_buf_release(dev); + } + } + ret = dma_stop(dma_params->dma_dev, + dma_params->dma_channel); + + struct uart_event event = { + .type = UART_RX_DISABLED + }; + + async_user_callback(dev, &event); + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static void prepare_rx_dma_block_config(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)dev->data; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + + assert(rx_dma_params->buf != NULL); + assert(rx_dma_params->buf_len > 0); + + struct dma_block_config *head_block_config = &rx_dma_params->active_dma_block; + + head_block_config->dest_address = (uintptr_t)rx_dma_params->buf; + head_block_config->source_address = data->phys_addr; + head_block_config->block_size = rx_dma_params->buf_len; +} + +#if UART_NS16550_DMAS_ENABLED +static void dma_callback(const struct device *dev, void *user_data, uint32_t channel, + int status) +{ + struct device *uart_dev = (struct device *)user_data; + struct uart_ns16550_dev_data *data = (struct uart_ns16550_dev_data *)uart_dev->data; + struct uart_ns16550_rx_dma_params *rx_params = &data->async.rx_dma_params; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + + if (channel == tx_params->dma_channel) { + async_evt_tx_done(uart_dev); + } else if (channel == rx_params->dma_channel) { + + rx_params->counter = rx_params->buf_len; + + async_evt_rx_rdy(uart_dev); + async_evt_rx_buf_release(uart_dev); + + rx_params->buf = data->async.next_rx_buffer; + rx_params->buf_len = data->async.next_rx_buffer_len; + data->async.next_rx_buffer = NULL; + data->async.next_rx_buffer_len = 0U; + + if (rx_params->buf != NULL && + rx_params->buf_len > 0) { + dma_reload(dev, rx_params->dma_channel, data->phys_addr, + (uintptr_t)rx_params->buf, rx_params->buf_len); + dma_start(dev, rx_params->dma_channel); + async_evt_rx_buf_request(uart_dev); + } else { + uart_ns16550_rx_disable(uart_dev); + } + } +} +#endif + +static int uart_ns16550_callback_set(const struct device *dev, uart_callback_t callback, + void *user_data) +{ + struct uart_ns16550_dev_data *data = dev->data; + + data->async.user_callback = callback; + data->async.user_data = user_data; + + return 0; +} + +static int uart_ns16550_tx(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + k_spinlock_key_t key = k_spin_lock(&data->lock); + int ret = 0; + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + tx_params->buf = buf; + tx_params->buf_len = len; + tx_params->active_dma_block.source_address = (uintptr_t)buf; + tx_params->active_dma_block.dest_address = data->phys_addr; + tx_params->active_dma_block.block_size = len; + tx_params->active_dma_block.next_block = NULL; + + ret = dma_config(tx_params->dma_dev, + tx_params->dma_channel, + (struct dma_config *)&tx_params->dma_cfg); + + if (ret == 0) { + ret = dma_start(tx_params->dma_dev, + tx_params->dma_channel); + if (ret) { + ret = -EIO; + goto out; + } + async_timer_start(&data->async.tx_dma_params.timeout_work, timeout_us); + } + +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_tx_abort(const struct device *dev) +{ + struct uart_ns16550_dev_data *data = dev->data; + struct uart_ns16550_tx_dma_params *tx_params = &data->async.tx_dma_params; + struct dma_status status; + int ret = 0; + size_t bytes_tx; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(tx_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + (void)k_work_cancel_delayable(&data->async.tx_dma_params.timeout_work); + + ret = dma_stop(tx_params->dma_dev, tx_params->dma_channel); + dma_get_status(tx_params->dma_dev, + tx_params->dma_channel, + &status); + bytes_tx = tx_params->buf_len - status.pending_length; + + if (ret == 0) { + struct uart_event tx_aborted_event = { + .type = UART_TX_ABORTED, + .data.tx.buf = tx_params->buf, + .data.tx.len = bytes_tx + }; + async_user_callback(dev, &tx_aborted_event); + } +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_enable(const struct device *dev, uint8_t *buf, const size_t len, + const int32_t timeout_us) +{ + struct uart_ns16550_dev_data *data = dev->data; + const struct uart_ns16550_device_config *config = dev->config; + struct uart_ns16550_rx_dma_params *rx_dma_params = &data->async.rx_dma_params; + int ret = 0; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + if (!device_is_ready(rx_dma_params->dma_dev)) { + ret = -ENODEV; + goto out; + } + + rx_dma_params->timeout_us = timeout_us; + rx_dma_params->buf = buf; + rx_dma_params->buf_len = len; + +#if defined(CONFIG_UART_NS16550_INTEL_LPSS_DMA) + ns16550_outword(config, MST(dev), UNMASK_LPSS_INT(rx_dma_params->dma_channel)); +#else + ns16550_outbyte(config, IER(dev), + (ns16550_inbyte(config, IER(dev)) | IER_RXRDY)); + ns16550_outbyte(config, FCR(dev), FCR_FIFO); +#endif + prepare_rx_dma_block_config(dev); + dma_config(rx_dma_params->dma_dev, + rx_dma_params->dma_channel, + (struct dma_config *)&rx_dma_params->dma_cfg); + dma_start(rx_dma_params->dma_dev, rx_dma_params->dma_channel); + async_evt_rx_buf_request(dev); +out: + k_spin_unlock(&data->lock, key); + return ret; +} + +static int uart_ns16550_rx_buf_rsp(const struct device *dev, uint8_t *buf, size_t len) +{ + struct uart_ns16550_dev_data *data = dev->data; + + assert(data->async.next_rx_buffer == NULL); + assert(data->async.next_rx_buffer_len == 0); + data->async.next_rx_buffer = buf; + data->async.next_rx_buffer_len = len; + + return 0; +} + +static void uart_ns16550_async_rx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_rx_dma_params *rx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_rx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(rx_params, struct uart_ns16550_async_data, + rx_dma_params); + const struct device *dev = async_data->uart_dev; + + uart_ns16550_async_rx_flush(dev); + +} + +static void uart_ns16550_async_tx_timeout(struct k_work *work) +{ + struct k_work_delayable *work_delay = CONTAINER_OF(work, struct k_work_delayable, work); + struct uart_ns16550_tx_dma_params *tx_params = + CONTAINER_OF(work_delay, struct uart_ns16550_tx_dma_params, + timeout_work); + struct uart_ns16550_async_data *async_data = + CONTAINER_OF(tx_params, struct uart_ns16550_async_data, + tx_dma_params); + const struct device *dev = async_data->uart_dev; + + (void)uart_ns16550_tx_abort(dev); +} + +#endif /* CONFIG_UART_ASYNC_API */ static const struct uart_driver_api uart_ns16550_driver_api = { .poll_in = uart_ns16550_poll_in, @@ -1285,6 +1769,15 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #endif +#ifdef CONFIG_UART_ASYNC_API + .callback_set = uart_ns16550_callback_set, + .tx = uart_ns16550_tx, + .tx_abort = uart_ns16550_tx_abort, + .rx_enable = uart_ns16550_rx_enable, + .rx_disable = uart_ns16550_rx_disable, + .rx_buf_rsp = uart_ns16550_rx_buf_rsp, +#endif + #ifdef CONFIG_UART_NS16550_LINE_CTRL .line_ctrl_set = uart_ns16550_line_ctrl_set, #endif @@ -1356,6 +1849,67 @@ static const struct uart_driver_api uart_ns16550_driver_api = { #define UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +#ifdef CONFIG_UART_ASYNC_API +#define DMA_PARAMS(n) \ + .async.tx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, tx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = MEMORY_TO_PERIPHERAL, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, tx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = \ + DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, rx)), \ + .dma_channel = \ + DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_cfg = { \ + .source_burst_length = 1, \ + .dest_burst_length = 1, \ + .source_data_size = 1, \ + .dest_data_size = 1, \ + .complete_callback_en = 0, \ + .error_callback_en = 1, \ + .block_count = 1, \ + .channel_direction = PERIPHERAL_TO_MEMORY, \ + .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, channel), \ + .dma_callback = dma_callback, \ + .user_data = (void *)DEVICE_DT_INST_GET(n) \ + }, \ + }, \ + COND_CODE_0(DT_INST_ON_BUS(n, pcie), \ + (.phys_addr = DT_INST_REG_ADDR(n),), ()) + +#define DMA_PARAMS_NULL(n) \ + .async.tx_dma_params = { \ + .dma_dev = NULL \ + }, \ + .async.rx_dma_params = { \ + .dma_dev = NULL \ + }, \ + +#define DEV_DATA_ASYNC(n) \ + COND_CODE_0(DT_INST_PROP(n, io_mapped), \ + (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \ + (DMA_PARAMS(n)), (DMA_PARAMS_NULL(n)))), \ + (DMA_PARAMS_NULL(n))) +#else +#define DEV_DATA_ASYNC(n) +#endif /* CONFIG_UART_ASYNC_API */ + + #define UART_NS16550_COMMON_DEV_CFG_INITIALIZER(n) \ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \ .sys_clk_freq = DT_INST_PROP(n, clock_frequency), \ @@ -1386,7 +1940,8 @@ static const struct uart_driver_api uart_ns16550_driver_api = { (UART_CFG_FLOW_CTRL_RTS_CTS), \ (UART_CFG_FLOW_CTRL_NONE)), \ IF_ENABLED(DT_INST_NODE_HAS_PROP(n, dlf), \ - (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) + (.dlf = DT_INST_PROP_OR(n, dlf, 0),)) \ + DEV_DATA_ASYNC(n) \ #define UART_NS16550_DEVICE_IO_MMIO_INIT(n) \ UART_NS16550_IRQ_FUNC_DECLARE(n); \ @@ -1423,8 +1978,7 @@ static const struct uart_driver_api uart_ns16550_driver_api = { }; \ DEVICE_DT_INST_DEFINE(n, &uart_ns16550_init, NULL, \ &uart_ns16550_dev_data_##n, &uart_ns16550_dev_cfg_##n, \ - COND_CODE_1(CONFIG_UART_NS16550_PARENT_INIT_LEVEL, \ - (POST_KERNEL), (PRE_KERNEL_1)), \ + PRE_KERNEL_1, \ CONFIG_SERIAL_INIT_PRIORITY, \ &uart_ns16550_driver_api); \ UART_NS16550_PCIE_IRQ_FUNC_DEFINE(n) diff --git a/drivers/serial/uart_opentitan.c b/drivers/serial/uart_opentitan.c index a762d75dac0..0d27c7a3d04 100644 --- a/drivers/serial/uart_opentitan.c +++ b/drivers/serial/uart_opentitan.c @@ -7,7 +7,6 @@ #include #include #include -#include #include /* Register offsets within the UART device register space. */ diff --git a/drivers/serial/uart_pl011_ambiq.h b/drivers/serial/uart_pl011_ambiq.h index 2223cbed577..470e0e35a95 100644 --- a/drivers/serial/uart_pl011_ambiq.h +++ b/drivers/serial/uart_pl011_ambiq.h @@ -50,9 +50,9 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) return pl011_ambiq_clk_set(dev, clk); } -/* Problem: writes to pwrcfg reg take at most PWCTRL_MAX_WAIT_US time to propagate. - * Solution: busy wait for PWCTRL_MAX_WAIT_US microseconds to ensure that register - * writes have propagated. +/* Problem: writes to power configure register takes some time to take effective. + * Solution: Check device's power status to ensure that register has taken effective. + * Note: busy wait is not allowed to use here due to UART is initiated before timer starts. */ #define QUIRK_AMBIQ_UART_DEFINE(n) \ @@ -60,8 +60,12 @@ static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk) { \ uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \ DT_INST_PHA(n, ambiq_pwrcfg, offset); \ + uint32_t pwr_status_addr = addr + 4; \ sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \ - k_busy_wait(PWRCTRL_MAX_WAIT_US); \ + while ((sys_read32(pwr_status_addr) & DT_INST_PHA(n, ambiq_pwrcfg, mask)) != \ + DT_INST_PHA(n, ambiq_pwrcfg, mask)) { \ + arch_nop(); \ + }; \ return 0; \ } diff --git a/drivers/serial/uart_ql_usbserialport_s3b.h b/drivers/serial/uart_ql_usbserialport_s3b.h index c4397ff6d85..47899d2ebb8 100644 --- a/drivers/serial/uart_ql_usbserialport_s3b.h +++ b/drivers/serial/uart_ql_usbserialport_s3b.h @@ -34,8 +34,8 @@ #define USBSERIAL_TX_FIFO_16_TO_31 (0x0B) /* 1011 Room for 16 to 31 */ #define USBSERIAL_TX_FIFO_8_TO_15 (0x0C) /* 1100 Room for 8 to 15 */ #define USBSERIAL_TX_FIFO_4_TO_7 (0x0D) /* 1101 Room for 4 to 7 */ -#define USBSERIAL_TX_FIFO_GE_2 (0x0E) /* 1110 Room for atleast 2 */ -#define USBSERIAL_TX_FIFO_GE_1 (0x0F) /* 1111 Room for atleast 1 */ +#define USBSERIAL_TX_FIFO_GE_2 (0x0E) /* 1110 Room for at least 2 */ +#define USBSERIAL_TX_FIFO_GE_1 (0x0F) /* 1111 Room for at least 1 */ struct fpga_usbserial_regs { uint32_t device_id; diff --git a/drivers/serial/uart_ra.c b/drivers/serial/uart_ra.c deleted file mode 100644 index a93ffff4b45..00000000000 --- a/drivers/serial/uart_ra.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2023 TOKITA Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT renesas_ra_uart_sci - -#include -#include -#include -#include - -#include - -LOG_MODULE_REGISTER(ra_uart_sci, CONFIG_UART_LOG_LEVEL); - -struct uart_ra_cfg { - mem_addr_t regs; - const struct device *clock_dev; - clock_control_subsys_t clock_id; - const struct pinctrl_dev_config *pcfg; -}; - -struct uart_ra_data { - struct uart_config current_config; - uint32_t clk_rate; - struct k_spinlock lock; -}; - -#define REG_MASK(reg) (BIT_MASK(_CONCAT(reg, _LEN)) << _CONCAT(reg, _POS)) - -/* Registers */ -#define SMR 0x00 /*!< Serial Mode Register */ -#define BRR 0x01 /*!< Bit Rate Register */ -#define SCR 0x02 /*!< Serial Control Register */ -#define TDR 0x03 /*!< Transmit Data Register */ -#define SSR 0x04 /*!< Serial Status Register */ -#define RDR 0x05 /*!< Receive Data Register */ -#define SEMR 0x07 /*!< Serial Extended Mode Register */ -#define MDDR 0x12 /*!< Modulation Duty Register */ -#define LSR 0x18 /*!< Line Status Register */ - -/* - * SMR (Serial Mode Register) - * - * - CKS[0..2]: Clock Select - * - MP[2..3]: Multi-Processor Mode(Valid only in asynchronous mode) - * - STOP[3..4]: Stop Bit Length(Valid only in asynchronous mode) - * - PM[4..5]: Parity Mode (Valid only when the PE bit is 1) - * - PE[5..6]: Parity Enable(Valid only in asynchronous mode) - * - CHR[6..7]: Character Length(Valid only in asynchronous mode) - * - CM[7..8]: Communication Mode - */ -#define SMR_CKS_POS (0) -#define SMR_CKS_LEN (2) -#define SMR_MP_POS (2) -#define SMR_MP_LEN (1) -#define SMR_STOP_POS (3) -#define SMR_STOP_LEN (1) -#define SMR_PM_POS (4) -#define SMR_PM_LEN (1) -#define SMR_PE_POS (5) -#define SMR_PE_LEN (1) -#define SMR_CHR_POS (6) -#define SMR_CHR_LEN (1) -#define SMR_CM_POS (7) -#define SMR_CM_LEN (1) - -/** - * SCR (Serial Control Register) - * - * - CKE[0..2]: Clock Enable - * - TEIE[2..3]: Transmit End Interrupt Enable - * - MPIE[3..4]: Multi-Processor Interrupt Enable (Valid in asynchronous - * - RE[4..5]: Receive Enable - * - TE[5..6]: Transmit Enable - * - RIE[6..7]: Receive Interrupt Enable - * - TIE[7..8]: Transmit Interrupt Enable - */ -#define SCR_CKE_POS (0) -#define SCR_CKE_LEN (2) -#define SCR_TEIE_POS (2) -#define SCR_TEIE_LEN (1) -#define SCR_MPIE_POS (3) -#define SCR_MPIE_LEN (1) -#define SCR_RE_POS (4) -#define SCR_RE_LEN (1) -#define SCR_TE_POS (5) -#define SCR_TE_LEN (1) -#define SCR_RIE_POS (6) -#define SCR_RIE_LEN (1) -#define SCR_TIE_POS (7) -#define SCR_TIE_LEN (1) - -/** - * SSR (Serial Status Register) - * - * - MPBT[0..1]: Multi-Processor Bit Transfer - * - MPB[1..2]: Multi-Processor - * - TEND[2..3]: Transmit End Flag - * - PER[3..4]: Parity Error Flag - * - FER[4..5]: Framing Error Flag - * - ORER[5..6]: Overrun Error Flag - * - RDRF[6..7]: Receive Data Full Flag - * - TDRE[7..8]: Transmit Data Empty Flag - */ -#define SSR_MPBT_POS (0) -#define SSR_MPBT_LEN (1) -#define SSR_MPB_POS (1) -#define SSR_MPB_LEN (1) -#define SSR_TEND_POS (2) -#define SSR_TEND_LEN (1) -#define SSR_PER_POS (3) -#define SSR_PER_LEN (1) -#define SSR_FER_POS (4) -#define SSR_FER_LEN (1) -#define SSR_ORER_POS (5) -#define SSR_ORER_LEN (1) -#define SSR_RDRF_POS (6) -#define SSR_RDRF_LEN (1) -#define SSR_TDRE_POS (7) -#define SSR_TDRE_LEN (1) - -/** - * SEMR (Serial Extended Mode Register) - * - * - ACS0[0..1]: Asynchronous Mode Clock Source Select - * - PADIS[1..2]: Preamble function Disable - * - BRME[2..3]: Bit Rate Modulation Enable - * - ABCSE[3..4]: Asynchronous Mode Extended Base Clock Select - * - ABCS[4..5]: Asynchronous Mode Base Clock Select - * - NFEN[5..6]: Digital Noise Filter Function Enable - * - BGDM[6..7]: Baud Rate Generator Double-Speed Mode Select - * - RXDESEL[7..8]: Asynchronous Start Bit Edge Detection Select - */ -#define SEMR_ACS0_POS (0) -#define SEMR_ACS0_LEN (1) -#define SEMR_PADIS_POS (1) -#define SEMR_PADIS_LEN (1) -#define SEMR_BRME_POS (2) -#define SEMR_BRME_LEN (1) -#define SEMR_ABCSE_POS (3) -#define SEMR_ABCSE_LEN (1) -#define SEMR_ABCS_POS (4) -#define SEMR_ABCS_LEN (1) -#define SEMR_NFEN_POS (5) -#define SEMR_NFEN_LEN (1) -#define SEMR_BGDM_POS (6) -#define SEMR_BGDM_LEN (1) -#define SEMR_RXDESEL_POS (7) -#define SEMR_RXDESEL_LEN (1) - -/** - * LSR (Line Status Register) - * - * - ORER[0..1]: Overrun Error Flag - * - FNUM[2..7]: Framing Error Count - * - PNUM[8..13]: Parity Error Count - */ -#define LSR_ORER_POS (0) -#define LSR_ORER_LEN (1) -#define LSR_FNUM_POS (2) -#define LSR_FNUM_LEN (5) -#define LSR_PNUM_POS (8) -#define LSR_PNUM_LEN (5) - -static uint8_t uart_ra_read_8(const struct device *dev, - uint32_t offs) -{ - const struct uart_ra_cfg *config = dev->config; - - return sys_read8(config->regs + offs); -} - -static void uart_ra_write_8(const struct device *dev, - uint32_t offs, uint8_t value) -{ - const struct uart_ra_cfg *config = dev->config; - - sys_write8(value, config->regs + offs); -} - -static uint16_t uart_ra_read_16(const struct device *dev, - uint32_t offs) -{ - const struct uart_ra_cfg *config = dev->config; - - return sys_read16(config->regs + offs); -} - -static void uart_ra_write_16(const struct device *dev, - uint32_t offs, uint16_t value) -{ - const struct uart_ra_cfg *config = dev->config; - - sys_write16(value, config->regs + offs); -} - -static void uart_ra_set_baudrate(const struct device *dev, - uint32_t baud_rate) -{ - struct uart_ra_data *data = dev->data; - uint8_t reg_val; - - reg_val = uart_ra_read_8(dev, SEMR); - reg_val |= REG_MASK(SEMR_BGDM); - reg_val &= ~(REG_MASK(SEMR_BRME) | REG_MASK(SEMR_ABCSE) | REG_MASK(SEMR_ABCS)); - uart_ra_write_8(dev, SEMR, reg_val); - - reg_val = (data->clk_rate / (16 * data->current_config.baudrate)) - 1; - uart_ra_write_8(dev, BRR, reg_val); -} - -static int uart_ra_poll_in(const struct device *dev, unsigned char *p_char) -{ - struct uart_ra_data *data = dev->data; - int ret = 0; - - k_spinlock_key_t key = k_spin_lock(&data->lock); - - if ((uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)) == 0) { - ret = -1; - goto unlock; - } - - *p_char = uart_ra_read_8(dev, RDR); -unlock: - k_spin_unlock(&data->lock, key); - - return ret; -} - -static void uart_ra_poll_out(const struct device *dev, unsigned char out_char) -{ - struct uart_ra_data *data = dev->data; - k_spinlock_key_t key = k_spin_lock(&data->lock); - - uart_ra_write_8(dev, TDR, out_char); - while (!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TEND)) || - !(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TDRE))) { - ; - } - k_spin_unlock(&data->lock, key); -} - -static int uart_ra_configure(const struct device *dev, - const struct uart_config *cfg) -{ - struct uart_ra_data *data = dev->data; - - uint16_t reg_val; - k_spinlock_key_t key; - - if (cfg->parity != UART_CFG_PARITY_NONE || cfg->stop_bits != UART_CFG_STOP_BITS_1 || - cfg->data_bits != UART_CFG_DATA_BITS_8 || cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { - return -ENOTSUP; - } - - key = k_spin_lock(&data->lock); - - /* Disable Transmit and Receive */ - reg_val = uart_ra_read_8(dev, SCR); - reg_val &= ~(REG_MASK(SCR_TE) | REG_MASK(SCR_RE)); - uart_ra_write_8(dev, SCR, reg_val); - - /* Resetting Errors Registers */ - reg_val = uart_ra_read_8(dev, SSR); - reg_val &= ~(REG_MASK(SSR_PER) | REG_MASK(SSR_FER) | REG_MASK(SSR_ORER) | - REG_MASK(SSR_RDRF) | REG_MASK(SSR_TDRE)); - uart_ra_write_8(dev, SSR, reg_val); - - reg_val = uart_ra_read_16(dev, LSR); - reg_val &= ~(REG_MASK(LSR_ORER)); - uart_ra_write_16(dev, LSR, reg_val); - - /* Select internal clock */ - reg_val = uart_ra_read_8(dev, SCR); - reg_val &= ~(REG_MASK(SCR_CKE)); - uart_ra_write_8(dev, SCR, reg_val); - - /* Serial Configuration (8N1) & Clock divider selection */ - reg_val = uart_ra_read_8(dev, SMR); - reg_val &= ~(REG_MASK(SMR_CM) | REG_MASK(SMR_CHR) | REG_MASK(SMR_PE) | REG_MASK(SMR_PM) | - REG_MASK(SMR_STOP) | REG_MASK(SMR_CKS)); - uart_ra_write_8(dev, SMR, reg_val); - - /* Set baudrate */ - uart_ra_set_baudrate(dev, cfg->baudrate); - - /* Enable Transmit & Receive + disable Interrupts */ - reg_val = uart_ra_read_8(dev, SCR); - reg_val |= (REG_MASK(SCR_TE) | REG_MASK(SCR_RE)); - reg_val &= - ~(REG_MASK(SCR_TIE) | REG_MASK(SCR_RIE) | REG_MASK(SCR_MPIE) | REG_MASK(SCR_TEIE)); - uart_ra_write_8(dev, SCR, reg_val); - - data->current_config = *cfg; - - k_spin_unlock(&data->lock, key); - - return 0; -} - -#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE -static int uart_ra_config_get(const struct device *dev, - struct uart_config *cfg) -{ - struct uart_ra_data *data = dev->data; - - *cfg = data->current_config; - - return 0; -} -#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ - -static int uart_ra_init(const struct device *dev) -{ - const struct uart_ra_cfg *config = dev->config; - struct uart_ra_data *data = dev->data; - int ret; - - /* Configure dt provided device signals when available */ - ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - - if (!device_is_ready(config->clock_dev)) { - return -ENODEV; - } - - ret = clock_control_on(config->clock_dev, config->clock_id); - if (ret < 0) { - return ret; - } - - ret = clock_control_get_rate(config->clock_dev, config->clock_id, &data->clk_rate); - if (ret < 0) { - return ret; - } - - DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); - - ret = uart_ra_configure(dev, &data->current_config); - if (ret != 0) { - return ret; - } - - return 0; -} - -static const struct uart_driver_api uart_ra_driver_api = { - .poll_in = uart_ra_poll_in, - .poll_out = uart_ra_poll_out, -#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE - .configure = uart_ra_configure, - .config_get = uart_ra_config_get, -#endif -}; - -/* Device Instantiation */ -#define UART_RCAR_INIT_CFG(n) \ - PINCTRL_DT_DEFINE(DT_INST_PARENT(n)); \ - static const struct uart_ra_cfg uart_ra_cfg_##n = { \ - .regs = DT_REG_ADDR(DT_INST_PARENT(n)), \ - .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(n))), \ - .clock_id = \ - (clock_control_subsys_t)DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(n), 0, id), \ - .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ - } - -#define UART_RCAR_INIT(n) \ - UART_RCAR_INIT_CFG(n); \ - \ - static struct uart_ra_data uart_ra_data_##n = { \ - .current_config = { \ - .baudrate = DT_INST_PROP(n, current_speed), \ - .parity = UART_CFG_PARITY_NONE, \ - .stop_bits = UART_CFG_STOP_BITS_1, \ - .data_bits = UART_CFG_DATA_BITS_8, \ - .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ - }, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - uart_ra_init, \ - NULL, \ - &uart_ra_data_##n, \ - &uart_ra_cfg_##n, \ - PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ - &uart_ra_driver_api); \ - \ - -DT_INST_FOREACH_STATUS_OKAY(UART_RCAR_INIT) diff --git a/drivers/serial/uart_rcar.c b/drivers/serial/uart_rcar.c index b8011244a46..081d2d48959 100644 --- a/drivers/serial/uart_rcar.c +++ b/drivers/serial/uart_rcar.c @@ -104,6 +104,11 @@ struct uart_rcar_data { #define SCLSR_TO BIT(2) /* Timeout */ #define SCLSR_ORER BIT(0) /* Overrun Error */ +static uint8_t uart_rcar_read_8(const struct device *dev, uint32_t offs) +{ + return sys_read8(DEVICE_MMIO_GET(dev) + offs); +} + static void uart_rcar_write_8(const struct device *dev, uint32_t offs, uint8_t value) { @@ -146,7 +151,7 @@ static int uart_rcar_poll_in(const struct device *dev, unsigned char *p_char) goto unlock; } - *p_char = uart_rcar_read_16(dev, SCFRDR); + *p_char = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~SCFSR_RDF; @@ -347,7 +352,7 @@ static int uart_rcar_fifo_read(const struct device *dev, uint8_t *rx_data, while (((size - num_rx) > 0) && (uart_rcar_read_16(dev, SCFSR) & SCFSR_RDF)) { /* Receive current byte */ - rx_data[num_rx++] = uart_rcar_read_16(dev, SCFRDR); + rx_data[num_rx++] = uart_rcar_read_8(dev, SCFRDR); reg_val = uart_rcar_read_16(dev, SCFSR); reg_val &= ~(SCFSR_RDF); diff --git a/drivers/serial/uart_renesas_ra.c b/drivers/serial/uart_renesas_ra.c new file mode 100644 index 00000000000..81f6c567c84 --- /dev/null +++ b/drivers/serial/uart_renesas_ra.c @@ -0,0 +1,730 @@ +/* + * Copyright (c) 2023 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_ra_uart_sci + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(ra_uart_sci, CONFIG_UART_LOG_LEVEL); + +enum { + UART_RA_INT_RXI, + UART_RA_INT_TXI, + UART_RA_INT_ERI, + NUM_OF_UART_RA_INT, +}; + +struct uart_ra_cfg { + mem_addr_t regs; + const struct device *clock_dev; + clock_control_subsys_t clock_id; + const struct pinctrl_dev_config *pcfg; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + int (*irq_config_func)(const struct device *dev); +#endif +}; + +struct uart_ra_data { + struct uart_config current_config; + uint32_t clk_rate; + struct k_spinlock lock; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uint32_t irqn[NUM_OF_UART_RA_INT]; + uart_irq_callback_user_data_t callback; + void *cb_data; +#endif +}; + +#define REG_MASK(reg) (BIT_MASK(_CONCAT(reg, _LEN)) << _CONCAT(reg, _POS)) + +/* Registers */ +#define SMR 0x00 /*!< Serial Mode Register */ +#define BRR 0x01 /*!< Bit Rate Register */ +#define SCR 0x02 /*!< Serial Control Register */ +#define TDR 0x03 /*!< Transmit Data Register */ +#define SSR 0x04 /*!< Serial Status Register */ +#define RDR 0x05 /*!< Receive Data Register */ +#define SEMR 0x07 /*!< Serial Extended Mode Register */ +#define MDDR 0x12 /*!< Modulation Duty Register */ +#define LSR 0x18 /*!< Line Status Register */ + +/* + * SMR (Serial Mode Register) + * + * - CKS[0..2]: Clock Select + * - MP[2..3]: Multi-Processor Mode(Valid only in asynchronous mode) + * - STOP[3..4]: Stop Bit Length(Valid only in asynchronous mode) + * - PM[4..5]: Parity Mode (Valid only when the PE bit is 1) + * - PE[5..6]: Parity Enable(Valid only in asynchronous mode) + * - CHR[6..7]: Character Length(Valid only in asynchronous mode) + * - CM[7..8]: Communication Mode + */ +#define SMR_CKS_POS (0) +#define SMR_CKS_LEN (2) +#define SMR_MP_POS (2) +#define SMR_MP_LEN (1) +#define SMR_STOP_POS (3) +#define SMR_STOP_LEN (1) +#define SMR_PM_POS (4) +#define SMR_PM_LEN (1) +#define SMR_PE_POS (5) +#define SMR_PE_LEN (1) +#define SMR_CHR_POS (6) +#define SMR_CHR_LEN (1) +#define SMR_CM_POS (7) +#define SMR_CM_LEN (1) + +/** + * SCR (Serial Control Register) + * + * - CKE[0..2]: Clock Enable + * - TEIE[2..3]: Transmit End Interrupt Enable + * - MPIE[3..4]: Multi-Processor Interrupt Enable (Valid in asynchronous + * - RE[4..5]: Receive Enable + * - TE[5..6]: Transmit Enable + * - RIE[6..7]: Receive Interrupt Enable + * - TIE[7..8]: Transmit Interrupt Enable + */ +#define SCR_CKE_POS (0) +#define SCR_CKE_LEN (2) +#define SCR_TEIE_POS (2) +#define SCR_TEIE_LEN (1) +#define SCR_MPIE_POS (3) +#define SCR_MPIE_LEN (1) +#define SCR_RE_POS (4) +#define SCR_RE_LEN (1) +#define SCR_TE_POS (5) +#define SCR_TE_LEN (1) +#define SCR_RIE_POS (6) +#define SCR_RIE_LEN (1) +#define SCR_TIE_POS (7) +#define SCR_TIE_LEN (1) + +/** + * SSR (Serial Status Register) + * + * - MPBT[0..1]: Multi-Processor Bit Transfer + * - MPB[1..2]: Multi-Processor + * - TEND[2..3]: Transmit End Flag + * - PER[3..4]: Parity Error Flag + * - FER[4..5]: Framing Error Flag + * - ORER[5..6]: Overrun Error Flag + * - RDRF[6..7]: Receive Data Full Flag + * - TDRE[7..8]: Transmit Data Empty Flag + */ +#define SSR_MPBT_POS (0) +#define SSR_MPBT_LEN (1) +#define SSR_MPB_POS (1) +#define SSR_MPB_LEN (1) +#define SSR_TEND_POS (2) +#define SSR_TEND_LEN (1) +#define SSR_PER_POS (3) +#define SSR_PER_LEN (1) +#define SSR_FER_POS (4) +#define SSR_FER_LEN (1) +#define SSR_ORER_POS (5) +#define SSR_ORER_LEN (1) +#define SSR_RDRF_POS (6) +#define SSR_RDRF_LEN (1) +#define SSR_TDRE_POS (7) +#define SSR_TDRE_LEN (1) + +/** + * SEMR (Serial Extended Mode Register) + * + * - ACS0[0..1]: Asynchronous Mode Clock Source Select + * - PADIS[1..2]: Preamble function Disable + * - BRME[2..3]: Bit Rate Modulation Enable + * - ABCSE[3..4]: Asynchronous Mode Extended Base Clock Select + * - ABCS[4..5]: Asynchronous Mode Base Clock Select + * - NFEN[5..6]: Digital Noise Filter Function Enable + * - BGDM[6..7]: Baud Rate Generator Double-Speed Mode Select + * - RXDESEL[7..8]: Asynchronous Start Bit Edge Detection Select + */ +#define SEMR_ACS0_POS (0) +#define SEMR_ACS0_LEN (1) +#define SEMR_PADIS_POS (1) +#define SEMR_PADIS_LEN (1) +#define SEMR_BRME_POS (2) +#define SEMR_BRME_LEN (1) +#define SEMR_ABCSE_POS (3) +#define SEMR_ABCSE_LEN (1) +#define SEMR_ABCS_POS (4) +#define SEMR_ABCS_LEN (1) +#define SEMR_NFEN_POS (5) +#define SEMR_NFEN_LEN (1) +#define SEMR_BGDM_POS (6) +#define SEMR_BGDM_LEN (1) +#define SEMR_RXDESEL_POS (7) +#define SEMR_RXDESEL_LEN (1) + +/** + * LSR (Line Status Register) + * + * - ORER[0..1]: Overrun Error Flag + * - FNUM[2..7]: Framing Error Count + * - PNUM[8..13]: Parity Error Count + */ +#define LSR_ORER_POS (0) +#define LSR_ORER_LEN (1) +#define LSR_FNUM_POS (2) +#define LSR_FNUM_LEN (5) +#define LSR_PNUM_POS (8) +#define LSR_PNUM_LEN (5) + +static uint8_t uart_ra_read_8(const struct device *dev, uint32_t offs) +{ + const struct uart_ra_cfg *config = dev->config; + + return sys_read8(config->regs + offs); +} + +static void uart_ra_write_8(const struct device *dev, uint32_t offs, uint8_t value) +{ + const struct uart_ra_cfg *config = dev->config; + + sys_write8(value, config->regs + offs); +} + +static uint16_t uart_ra_read_16(const struct device *dev, uint32_t offs) +{ + const struct uart_ra_cfg *config = dev->config; + + return sys_read16(config->regs + offs); +} + +static void uart_ra_write_16(const struct device *dev, uint32_t offs, uint16_t value) +{ + const struct uart_ra_cfg *config = dev->config; + + sys_write16(value, config->regs + offs); +} + +static void uart_ra_set_baudrate(const struct device *dev, uint32_t baud_rate) +{ + struct uart_ra_data *data = dev->data; + uint8_t reg_val; + + reg_val = uart_ra_read_8(dev, SEMR); + reg_val |= (REG_MASK(SEMR_BGDM) | REG_MASK(SEMR_ABCS)); + reg_val &= ~(REG_MASK(SEMR_BRME) | REG_MASK(SEMR_ABCSE)); + uart_ra_write_8(dev, SEMR, reg_val); + + reg_val = (data->clk_rate / (8 * data->current_config.baudrate)) - 1; + uart_ra_write_8(dev, BRR, reg_val); +} + +static int uart_ra_poll_in(const struct device *dev, unsigned char *p_char) +{ + struct uart_ra_data *data = dev->data; + int ret = 0; + + k_spinlock_key_t key = k_spin_lock(&data->lock); + + /* If interrupts are enabled, return -EINVAL */ + if ((uart_ra_read_8(dev, SCR) & REG_MASK(SCR_RIE))) { + ret = -EINVAL; + goto unlock; + } + + if ((uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)) == 0) { + ret = -1; + goto unlock; + } + + *p_char = uart_ra_read_8(dev, RDR); +unlock: + k_spin_unlock(&data->lock, key); + + return ret; +} + +static void uart_ra_poll_out(const struct device *dev, unsigned char out_char) +{ + struct uart_ra_data *data = dev->data; + uint8_t reg_val; + k_spinlock_key_t key = k_spin_lock(&data->lock); + + while (!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TEND)) || + !(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TDRE))) { + ; + } + + /* If interrupts are enabled, temporarily disable them */ + reg_val = uart_ra_read_8(dev, SCR); + uart_ra_write_8(dev, SCR, reg_val & ~REG_MASK(SCR_TIE)); + + uart_ra_write_8(dev, TDR, out_char); + while (!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TEND)) || + !(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_TDRE))) { + ; + } + + uart_ra_write_8(dev, SCR, reg_val); + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_err_check(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + uint8_t reg_val; + int errors = 0; + k_spinlock_key_t key; + + key = k_spin_lock(&data->lock); + reg_val = uart_ra_read_8(dev, SSR); + + if (reg_val & REG_MASK(SSR_PER)) { + errors |= UART_ERROR_PARITY; + } + + if (reg_val & REG_MASK(SSR_FER)) { + errors |= UART_ERROR_FRAMING; + } + + if (reg_val & REG_MASK(SSR_ORER)) { + errors |= UART_ERROR_OVERRUN; + } + + reg_val &= ~(REG_MASK(SSR_PER) | REG_MASK(SSR_FER) | REG_MASK(SSR_ORER)); + uart_ra_write_8(dev, SSR, reg_val); + + k_spin_unlock(&data->lock, key); + + return errors; +} + +static int uart_ra_configure(const struct device *dev, const struct uart_config *cfg) +{ + struct uart_ra_data *data = dev->data; + + uint16_t reg_val; + k_spinlock_key_t key; + + if (cfg->parity != UART_CFG_PARITY_NONE || cfg->stop_bits != UART_CFG_STOP_BITS_1 || + cfg->data_bits != UART_CFG_DATA_BITS_8 || cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { + return -ENOTSUP; + } + + key = k_spin_lock(&data->lock); + + /* Disable Transmit and Receive */ + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_TE) | REG_MASK(SCR_RE)); + uart_ra_write_8(dev, SCR, reg_val); + + /* Resetting Errors Registers */ + reg_val = uart_ra_read_8(dev, SSR); + reg_val &= ~(REG_MASK(SSR_PER) | REG_MASK(SSR_FER) | REG_MASK(SSR_ORER) | + REG_MASK(SSR_RDRF) | REG_MASK(SSR_TDRE)); + uart_ra_write_8(dev, SSR, reg_val); + + reg_val = uart_ra_read_16(dev, LSR); + reg_val &= ~(REG_MASK(LSR_ORER)); + uart_ra_write_16(dev, LSR, reg_val); + + /* Select internal clock */ + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_CKE)); + uart_ra_write_8(dev, SCR, reg_val); + + /* Serial Configuration (8N1) & Clock divider selection */ + reg_val = uart_ra_read_8(dev, SMR); + reg_val &= ~(REG_MASK(SMR_CM) | REG_MASK(SMR_CHR) | REG_MASK(SMR_PE) | REG_MASK(SMR_PM) | + REG_MASK(SMR_STOP) | REG_MASK(SMR_CKS)); + uart_ra_write_8(dev, SMR, reg_val); + + /* Set baudrate */ + uart_ra_set_baudrate(dev, cfg->baudrate); + + /* Enable Transmit & Receive + disable Interrupts */ + reg_val = uart_ra_read_8(dev, SCR); + reg_val |= (REG_MASK(SCR_TE) | REG_MASK(SCR_RE)); + reg_val &= + ~(REG_MASK(SCR_TIE) | REG_MASK(SCR_RIE) | REG_MASK(SCR_MPIE) | REG_MASK(SCR_TEIE)); + uart_ra_write_8(dev, SCR, reg_val); + + data->current_config = *cfg; + + k_spin_unlock(&data->lock, key); + + return 0; +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_ra_config_get(const struct device *dev, struct uart_config *cfg) +{ + struct uart_ra_data *data = dev->data; + + *cfg = data->current_config; + + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +static int uart_ra_init(const struct device *dev) +{ + const struct uart_ra_cfg *config = dev->config; + struct uart_ra_data *data = dev->data; + int ret; + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + if (!device_is_ready(config->clock_dev)) { + return -ENODEV; + } + + ret = clock_control_on(config->clock_dev, config->clock_id); + if (ret < 0) { + return ret; + } + + ret = clock_control_get_rate(config->clock_dev, config->clock_id, &data->clk_rate); + if (ret < 0) { + return ret; + } + + ret = uart_ra_configure(dev, &data->current_config); + if (ret != 0) { + return ret; + } + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + ret = config->irq_config_func(dev); + if (ret != 0) { + return ret; + } +#endif + + return 0; +} + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static bool uart_ra_irq_is_enabled(const struct device *dev, uint32_t irq) +{ + return uart_ra_read_8(dev, SCR) & irq; +} + +static int uart_ra_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + struct uart_ra_data *data = dev->data; + uint8_t reg_val; + k_spinlock_key_t key; + + if (len <= 0 || tx_data == NULL) { + return 0; + } + + key = k_spin_lock(&data->lock); + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + uart_ra_write_8(dev, TDR, tx_data[0]); + + reg_val |= REG_MASK(SCR_TIE); + uart_ra_write_8(dev, SCR, reg_val); + + k_spin_unlock(&data->lock, key); + + return 1; +} + +static int uart_ra_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) +{ + uint8_t data; + + if (size <= 0) { + return 0; + } + + if ((uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)) == 0) { + return 0; + } + + data = uart_ra_read_8(dev, RDR); + + if (rx_data) { + rx_data[0] = data; + } + + return 1; +} + +static void uart_ra_irq_tx_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val |= (REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + irq_enable(data->irqn[UART_RA_INT_TXI]); + + k_spin_unlock(&data->lock, key); +} + +static void uart_ra_irq_tx_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~(REG_MASK(SCR_TIE)); + uart_ra_write_8(dev, SCR, reg_val); + + irq_disable(data->irqn[UART_RA_INT_TXI]); + + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_irq_tx_ready(const struct device *dev) +{ + const uint8_t reg_val = uart_ra_read_8(dev, SSR); + const uint8_t mask = REG_MASK(SSR_TEND) & REG_MASK(SSR_TDRE); + + return (reg_val & mask) == mask; +} + +static void uart_ra_irq_rx_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val |= REG_MASK(SCR_RIE); + uart_ra_write_8(dev, SCR, reg_val); + + irq_enable(data->irqn[UART_RA_INT_RXI]); + + k_spin_unlock(&data->lock, key); +} + +static void uart_ra_irq_rx_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + k_spinlock_key_t key; + uint16_t reg_val; + + key = k_spin_lock(&data->lock); + + reg_val = uart_ra_read_8(dev, SCR); + reg_val &= ~REG_MASK(SCR_RIE); + uart_ra_write_8(dev, SCR, reg_val); + + irq_disable(data->irqn[UART_RA_INT_RXI]); + + k_spin_unlock(&data->lock, key); +} + +static int uart_ra_irq_rx_ready(const struct device *dev) +{ + return !!(uart_ra_read_8(dev, SSR) & REG_MASK(SSR_RDRF)); +} + +static void uart_ra_irq_err_enable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + irq_enable(data->irqn[UART_RA_INT_ERI]); +} + +static void uart_ra_irq_err_disable(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + irq_disable(data->irqn[UART_RA_INT_ERI]); +} + +static int uart_ra_irq_is_pending(const struct device *dev) +{ + return (uart_ra_irq_rx_ready(dev) && uart_ra_irq_is_enabled(dev, REG_MASK(SCR_RIE))) || + (uart_ra_irq_tx_ready(dev) && uart_ra_irq_is_enabled(dev, REG_MASK(SCR_TIE))); +} + +static int uart_ra_irq_update(const struct device *dev) +{ + return 1; +} + +static void uart_ra_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct uart_ra_data *data = dev->data; + + data->callback = cb; + data->cb_data = cb_data; +} + +/** + * @brief Interrupt service routine. + * + * This simply calls the callback function, if one exists. + * + * @param arg Argument to ISR. + */ +static inline void uart_ra_isr(const struct device *dev) +{ + struct uart_ra_data *data = dev->data; + + if (data->callback) { + data->callback(dev, data->cb_data); + } +} + +static void uart_ra_isr_rxi(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_RXI]); +} + +static void uart_ra_isr_txi(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_TXI]); +} + +static void uart_ra_isr_eri(const void *param) +{ + const struct device *dev = param; + struct uart_ra_data *data = dev->data; + + uart_ra_isr(dev); + ra_icu_clear_int_flag(data->irqn[UART_RA_INT_ERI]); +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_ra_driver_api = { + .poll_in = uart_ra_poll_in, + .poll_out = uart_ra_poll_out, + .err_check = uart_ra_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_ra_configure, + .config_get = uart_ra_config_get, +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_ra_fifo_fill, + .fifo_read = uart_ra_fifo_read, + .irq_tx_enable = uart_ra_irq_tx_enable, + .irq_tx_disable = uart_ra_irq_tx_disable, + .irq_tx_ready = uart_ra_irq_tx_ready, + .irq_rx_enable = uart_ra_irq_rx_enable, + .irq_rx_disable = uart_ra_irq_rx_disable, + .irq_rx_ready = uart_ra_irq_rx_ready, + .irq_err_enable = uart_ra_irq_err_enable, + .irq_err_disable = uart_ra_irq_err_disable, + .irq_is_pending = uart_ra_irq_is_pending, + .irq_update = uart_ra_irq_update, + .irq_callback_set = uart_ra_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +/* Device Instantiation */ +#define UART_RA_INIT_CFG(n) \ + PINCTRL_DT_DEFINE(DT_INST_PARENT(n)); \ + static const struct uart_ra_cfg uart_ra_cfg_##n = { \ + .regs = DT_REG_ADDR(DT_INST_PARENT(n)), \ + .clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_INST_PARENT(n))), \ + .clock_id = \ + (clock_control_subsys_t)DT_CLOCKS_CELL_BY_IDX(DT_INST_PARENT(n), 0, id), \ + .pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(n)), \ + IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, ( \ + .irq_config_func = irq_config_func_##n, \ + )) \ + } + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +#define RA_IRQ_CONNECT_DYNAMIC(n, name, dev, isr) \ + ra_icu_irq_connect_dynamic(DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, irq), \ + DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, priority), isr, dev, \ + DT_IRQ_BY_NAME(DT_INST_PARENT(n), name, flags)); + +#define RA_IRQ_DISCONNECT_DYNAMIC(n, name, dev, isr) \ + ra_icu_irq_disconnect_dynamic(irqn, 0, NULL, NULL, 0) + +#define UART_RA_CONFIG_FUNC(n) \ + static int irq_config_func_##n(const struct device *dev) \ + { \ + struct uart_ra_data *data = dev->data; \ + int irqn; \ + \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, rxi, dev, uart_ra_isr_rxi); \ + if (irqn < 0) { \ + return irqn; \ + } \ + data->irqn[UART_RA_INT_RXI] = irqn; \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, txi, dev, uart_ra_isr_txi); \ + if (irqn < 0) { \ + goto err_txi; \ + } \ + data->irqn[UART_RA_INT_TXI] = irqn; \ + irqn = RA_IRQ_CONNECT_DYNAMIC(n, eri, dev, uart_ra_isr_eri); \ + if (irqn < 0) { \ + goto err_eri; \ + } \ + data->irqn[UART_RA_INT_ERI] = irqn; \ + return 0; \ + \ +err_eri: \ + RA_IRQ_DISCONNECT_DYNAMIC(data->irq[UART_RA_INT_TXI], eri, dev, uart_ra_isr_eri); \ +err_txi: \ + RA_IRQ_DISCONNECT_DYNAMIC(data->irq[UART_RA_INT_RXI], txi, dev, uart_ra_isr_txi); \ + \ + return irqn; \ + } +#else +#define UART_RA_CONFIG_FUNC(n) +#endif + +#define UART_RA_INIT(n) \ + UART_RA_CONFIG_FUNC(n) \ + UART_RA_INIT_CFG(n); \ + \ + static struct uart_ra_data uart_ra_data_##n = { \ + .current_config = { \ + .baudrate = DT_INST_PROP(n, current_speed), \ + .parity = UART_CFG_PARITY_NONE, \ + .stop_bits = UART_CFG_STOP_BITS_1, \ + .data_bits = UART_CFG_DATA_BITS_8, \ + .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \ + }, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uart_ra_init, NULL, &uart_ra_data_##n, &uart_ra_cfg_##n, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_ra_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(UART_RA_INIT) diff --git a/drivers/serial/uart_rpi_pico.c b/drivers/serial/uart_rpi_pico.c index 9eb820d6224..a423c94cc9c 100644 --- a/drivers/serial/uart_rpi_pico.c +++ b/drivers/serial/uart_rpi_pico.c @@ -5,11 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#include #include +#include +#include #include -#include /* pico-sdk includes */ #include @@ -17,10 +17,11 @@ #define DT_DRV_COMPAT raspberrypi_pico_uart struct uart_rpi_config { - uart_inst_t *const uart_dev; uart_hw_t *const uart_regs; const struct pinctrl_dev_config *pcfg; const struct reset_dt_spec reset; + const struct device *clk_dev; + clock_control_subsys_t clk_id; #ifdef CONFIG_UART_INTERRUPT_DRIVEN uart_irq_config_func_t irq_config_func; #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ @@ -59,13 +60,51 @@ static void uart_rpi_poll_out(const struct device *dev, unsigned char c) uart_hw->dr = c; } +static int uart_rpi_set_baudrate(const struct device *dev, uint32_t input_baudrate, + uint32_t *output_baudrate) +{ + const struct uart_rpi_config *cfg = dev->config; + uart_hw_t * const uart_hw = cfg->uart_regs; + uint32_t baudrate_frac; + uint32_t baudrate_int; + uint32_t baudrate_div; + uint32_t pclk; + int ret; + + if (input_baudrate == 0) { + return -EINVAL; + } + + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } + + baudrate_div = (8 * pclk / input_baudrate); + baudrate_int = baudrate_div >> 7; + baudrate_frac = (baudrate_int == 0) || (baudrate_int >= UINT16_MAX) ? 0 : + ((baudrate_div & 0x7f) + 1) / 2; + baudrate_int = (baudrate_int == 0) ? 1 : + (baudrate_int >= UINT16_MAX) ? UINT16_MAX : baudrate_int; + + uart_hw->ibrd = baudrate_int; + uart_hw->fbrd = baudrate_frac; + + uart_hw->lcr_h |= 0; + + *output_baudrate = (4 * pclk) / (64 * baudrate_int + baudrate_frac); + + return 0; +} + static int uart_rpi_set_format(const struct device *dev, const struct uart_config *cfg) { const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; - uart_parity_t parity = 0; - uint data_bits = 0; - uint stop_bits = 0; + uart_hw_t * const uart_hw = config->uart_regs; + uint32_t data_bits; + uint32_t stop_bits; + uint32_t lcr_value; + uint32_t lcr_mask; switch (cfg->data_bits) { case UART_CFG_DATA_BITS_5: @@ -95,30 +134,25 @@ static int uart_rpi_set_format(const struct device *dev, const struct uart_confi return -EINVAL; } - switch (cfg->parity) { - case UART_CFG_PARITY_NONE: - parity = UART_PARITY_NONE; - break; - case UART_CFG_PARITY_EVEN: - parity = UART_PARITY_EVEN; - break; - case UART_CFG_PARITY_ODD: - parity = UART_PARITY_ODD; - break; - default: - return -EINVAL; - } + lcr_mask = UART_UARTLCR_H_WLEN_BITS | UART_UARTLCR_H_STP2_BITS | + UART_UARTLCR_H_PEN_BITS | UART_UARTLCR_H_EPS_BITS; + + lcr_value = ((data_bits - 5) << UART_UARTLCR_H_WLEN_LSB) | + ((stop_bits - 1) << UART_UARTLCR_H_STP2_LSB) | + (!!(cfg->parity != UART_CFG_PARITY_NONE) << UART_UARTLCR_H_PEN_LSB) | + (!!(cfg->parity == UART_CFG_PARITY_EVEN) << UART_UARTLCR_H_EPS_LSB); + + uart_hw->lcr_h = (uart_hw->lcr_h & ~lcr_mask) | (lcr_value & lcr_mask); - uart_set_format(uart_inst, data_bits, stop_bits, parity); return 0; } static int uart_rpi_init(const struct device *dev) { const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; uart_hw_t * const uart_hw = config->uart_regs; struct uart_rpi_data * const data = dev->data; + uint32_t baudrate; int ret; ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); @@ -126,20 +160,32 @@ static int uart_rpi_init(const struct device *dev) return ret; } - /* - * uart_init() may be replaced by register based API once rpi-pico platform - * has a clock controller driver - */ - data->uart_config.baudrate = uart_init(uart_inst, data->uart_config.baudrate); + ret = clock_control_on(config->clk_dev, config->clk_id); + if (ret < 0) { + return ret; + } - /* Check if baudrate adjustment returned by 'uart_init' function is a positive value */ - if (data->uart_config.baudrate == 0) { - return -EINVAL; + ret = reset_line_toggle(config->reset.dev, config->reset.id); + if (ret < 0) { + return ret; } + + ret = uart_rpi_set_baudrate(dev, data->uart_config.baudrate, &baudrate); + if (ret < 0) { + return ret; + } + + uart_rpi_set_format(dev, &data->uart_config); + + uart_hw->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS; + uart_hw->lcr_h |= UART_UARTLCR_H_FEN_BITS; + + uart_hw->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS; + /* * initialize uart_config with hardware reset values * https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_uart page:431 - * data bits set default to 8 instaed of hardware reset 5 to increase compatibility. + * data bits set default to 8 instead of hardware reset 5 to increase compatibility. */ data->uart_config.data_bits = UART_CFG_DATA_BITS_8; data->uart_config.parity = UART_CFG_PARITY_NONE; @@ -149,7 +195,7 @@ static int uart_rpi_init(const struct device *dev) uart_hw->dr = 0U; if (data->uart_config.flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS) { - uart_set_hw_flow(uart_inst, true, true); + uart_set_hw_flow((uart_inst_t *)uart_hw, true, true); } #ifdef CONFIG_UART_INTERRUPT_DRIVEN @@ -163,24 +209,25 @@ static int uart_rpi_config_get(const struct device *dev, struct uart_config *cfg { struct uart_rpi_data *data = dev->data; - memcpy(cfg, &data->uart_config, sizeof(struct uart_config)); + *cfg = data->uart_config; + return 0; } static int uart_rpi_configure(const struct device *dev, const struct uart_config *cfg) { - const struct uart_rpi_config *config = dev->config; - uart_inst_t * const uart_inst = config->uart_dev; struct uart_rpi_data *data = dev->data; - uint baudrate = 0; + uint32_t baudrate = 0; + int ret; - baudrate = uart_set_baudrate(uart_inst, cfg->baudrate); - if (baudrate == 0) { - return -EINVAL; + ret = uart_rpi_set_baudrate(dev, cfg->baudrate, &baudrate); + if (ret < 0) { + return ret; } - if (uart_rpi_set_format(dev, cfg) != 0) { - return -EINVAL; + ret = uart_rpi_set_format(dev, cfg); + if (ret < 0) { + return ret; } data->uart_config = *cfg; @@ -389,37 +436,38 @@ static const struct uart_driver_api uart_rpi_driver_api = { #define RPI_UART_IRQ_CONFIG_INIT(idx) #endif /* CONFIG_UART_INTERRUPT_DRIVEN*/ -#define RPI_UART_INIT(idx) \ - PINCTRL_DT_INST_DEFINE(idx); \ - \ - static void uart##idx##_rpi_irq_config_func(const struct device *port) \ - { \ - IRQ_CONNECT(DT_INST_IRQN(idx), \ - DT_INST_IRQ(idx, priority), \ - uart_rpi_isr, \ - DEVICE_DT_INST_GET(idx), 0); \ - irq_enable(DT_INST_IRQN(idx)); \ - } \ - \ - static const struct uart_rpi_config uart##idx##_rpi_config = { \ - .uart_dev = (uart_inst_t *const)DT_INST_REG_ADDR(idx), \ - .uart_regs = (uart_hw_t *const)DT_INST_REG_ADDR(idx), \ - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ - .reset = RESET_DT_SPEC_INST_GET(idx), \ - RPI_UART_IRQ_CONFIG_INIT(idx), \ - }; \ - \ - static struct uart_rpi_data uart##idx##_rpi_data = { \ - .uart_config.baudrate = DT_INST_PROP(idx, current_speed), \ - .uart_config.flow_ctrl = DT_INST_PROP(idx, hw_flow_control) \ - ? UART_CFG_FLOW_CTRL_RTS_CTS \ - : UART_CFG_FLOW_CTRL_NONE, \ - }; \ - \ - DEVICE_DT_INST_DEFINE(idx, &uart_rpi_init, \ - NULL, &uart##idx##_rpi_data, \ - &uart##idx##_rpi_config, PRE_KERNEL_1, \ - CONFIG_SERIAL_INIT_PRIORITY, \ - &uart_rpi_driver_api); \ +#define RPI_UART_INIT(idx) \ + PINCTRL_DT_INST_DEFINE(idx); \ + \ + static void uart##idx##_rpi_irq_config_func(const struct device *port) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(idx), \ + DT_INST_IRQ(idx, priority), \ + uart_rpi_isr, \ + DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + } \ + \ + static const struct uart_rpi_config uart##idx##_rpi_config = { \ + .uart_regs = (uart_hw_t *const)DT_INST_REG_ADDR(idx), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ + .reset = RESET_DT_SPEC_INST_GET(idx), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ + RPI_UART_IRQ_CONFIG_INIT(idx), \ + }; \ + \ + static struct uart_rpi_data uart##idx##_rpi_data = { \ + .uart_config.baudrate = DT_INST_PROP(idx, current_speed), \ + .uart_config.flow_ctrl = DT_INST_PROP(idx, hw_flow_control) \ + ? UART_CFG_FLOW_CTRL_RTS_CTS \ + : UART_CFG_FLOW_CTRL_NONE, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(idx, &uart_rpi_init, \ + NULL, &uart##idx##_rpi_data, \ + &uart##idx##_rpi_config, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_rpi_driver_api); DT_INST_FOREACH_STATUS_OKAY(RPI_UART_INIT) diff --git a/drivers/serial/uart_rzt2m.c b/drivers/serial/uart_rzt2m.c index e4ebe251f21..0e40ff78712 100644 --- a/drivers/serial/uart_rzt2m.c +++ b/drivers/serial/uart_rzt2m.c @@ -376,7 +376,7 @@ static int rzt2m_uart_init(const struct device *dev) config->irq_config_func(dev); #endif /* CONFIG_UART_INTERRUPT_DRIVEN */ - /* Start trasmitter and receiver. */ + /* Start transmitter and receiver. */ *CCR0(config->base) |= (CCR0_MASK_TE | CCR0_MASK_RE); while (!(*CCR0(config->base) & CCR0_MASK_RE)) { } diff --git a/drivers/serial/uart_sam.c b/drivers/serial/uart_sam.c index 0173c15b6bc..2c54f6e550a 100644 --- a/drivers/serial/uart_sam.c +++ b/drivers/serial/uart_sam.c @@ -49,7 +49,7 @@ static int uart_sam_poll_in(const struct device *dev, unsigned char *c) Uart * const uart = cfg->regs; if (!(uart->UART_SR & UART_SR_RXRDY)) { - return -EBUSY; + return -1; } /* got a character */ diff --git a/drivers/serial/uart_sam0.c b/drivers/serial/uart_sam0.c index ce1f8ef73c7..35931fe5a17 100644 --- a/drivers/serial/uart_sam0.c +++ b/drivers/serial/uart_sam0.c @@ -1270,7 +1270,7 @@ static void uart_sam0_irq_config_##n(const struct device *dev) \ (DT_INST_PROP(n, txpo) << SERCOM_USART_CTRLA_TXPO_Pos) #define UART_SAM0_SERCOM_COLLISION_DETECT(n) \ - (DT_INST_PROP_OR(n, collision_detection, false)) + (DT_INST_PROP(n, collision_detection)) #ifdef MCLK #define UART_SAM0_CONFIG_DEFN(n) \ diff --git a/drivers/serial/uart_sedi.c b/drivers/serial/uart_sedi.c index 6bbecb407cf..74fcc4a5040 100644 --- a/drivers/serial/uart_sedi.c +++ b/drivers/serial/uart_sedi.c @@ -92,7 +92,7 @@ struct uart_sedi_config_info { /* Specifies the baudrate for the uart instance. */ uint32_t baud_rate; - /* Specifies the port line contorl settings */ + /* Specifies the port line control settings */ sedi_uart_lc_t line_ctrl; struct k_mutex *mutex; diff --git a/drivers/serial/uart_stm32.c b/drivers/serial/uart_stm32.c index fa2371cc1df..834012ca3c1 100644 --- a/drivers/serial/uart_stm32.c +++ b/drivers/serial/uart_stm32.c @@ -96,6 +96,9 @@ static void uart_stm32_pm_policy_state_lock_get(const struct device *dev) if (!data->pm_policy_state_on) { data->pm_policy_state_on = true; pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } } } @@ -106,6 +109,9 @@ static void uart_stm32_pm_policy_state_lock_put(const struct device *dev) if (data->pm_policy_state_on) { data->pm_policy_state_on = false; pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + if (IS_ENABLED(CONFIG_PM_S2RAM)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES); + } } } #endif /* CONFIG_PM */ @@ -567,7 +573,7 @@ static int uart_stm32_configure(const struct device *dev, LL_USART_Disable(config->usart); - /* Set basic parmeters, such as data-/stop-bit, parity, and baudrate */ + /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */ uart_stm32_parameters_set(dev, cfg); LL_USART_Enable(config->usart); @@ -1257,7 +1263,6 @@ static void uart_stm32_isr(const struct device *dev) LL_USART_IsActiveFlag_TC(config->usart)) { LL_USART_DisableIT_TC(config->usart); - LL_USART_ClearFlag_TC(config->usart); /* Generate TX_DONE event when transmission is done */ async_evt_tx_done(data); @@ -1278,6 +1283,19 @@ static void uart_stm32_isr(const struct device *dev) /* Clear errors */ uart_stm32_err_check(dev); #endif /* CONFIG_UART_ASYNC_API */ + +#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) \ + && defined(USART_CR3_WUFIE) + if (LL_USART_IsEnabledIT_WKUP(config->usart) && + LL_USART_IsActiveFlag_WKUP(config->usart)) { + + LL_USART_ClearFlag_WKUP(config->usart); +#ifdef USART_ISR_REACK + while (LL_USART_IsActiveFlag_REACK(config->usart) == 0) { + } +#endif + } +#endif } #endif /* CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API || CONFIG_PM */ @@ -1309,7 +1327,7 @@ static inline void uart_stm32_dma_tx_enable(const struct device *dev) static inline void uart_stm32_dma_tx_disable(const struct device *dev) { -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) +#ifdef CONFIG_UART_STM32U5_ERRATA_DMAT ARG_UNUSED(dev); /* @@ -1321,7 +1339,7 @@ static inline void uart_stm32_dma_tx_disable(const struct device *dev) const struct uart_stm32_config *config = dev->config; LL_USART_DisableDMAReq_TX(config->usart); -#endif /* ! st_stm32u5_dma */ +#endif } static inline void uart_stm32_dma_rx_enable(const struct device *dev) @@ -1623,7 +1641,7 @@ static int uart_stm32_async_tx_abort(const struct device *dev) #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) dma_suspend(data->dma_tx.dma_dev, data->dma_tx.dma_channel); -#endif /* st_stm32u5_dma */ +#endif dma_stop(data->dma_tx.dma_dev, data->dma_tx.dma_channel); async_evt_tx_abort(data); @@ -1901,7 +1919,7 @@ static int uart_stm32_registers_configure(const struct device *dev) LL_USART_SetTransferDirection(config->usart, LL_USART_DIRECTION_TX_RX); - /* Set basic parmeters, such as data-/stop-bit, parity, and baudrate */ + /* Set basic parameters, such as data-/stop-bit, parity, and baudrate */ uart_stm32_parameters_set(dev, uart_cfg); /* Enable the single wire / half-duplex mode */ @@ -1944,6 +1962,33 @@ static int uart_stm32_registers_configure(const struct device *dev) } #endif +#ifdef USART_CR1_FIFOEN + if (config->fifo_enable) { + LL_USART_EnableFIFO(config->usart); + } +#endif + +#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) + if (config->wakeup_source) { + /* Enable ability to wakeup device in Stop mode + * Effect depends on CONFIG_PM_DEVICE status: + * CONFIG_PM_DEVICE=n : Always active + * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() + */ +#ifdef USART_CR3_WUFIE + LL_USART_SetWKUPType(config->usart, LL_USART_WAKEUP_ON_RXNE); + LL_USART_EnableIT_WKUP(config->usart); + LL_USART_ClearFlag_WKUP(config->usart); +#endif + LL_USART_EnableInStopMode(config->usart); + + if (config->wakeup_line != STM32_EXTI_LINE_NONE) { + /* Prepare the WAKEUP with the expected EXTI line */ + LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); + } + } +#endif /* CONFIG_PM */ + LL_USART_Enable(config->usart); #ifdef USART_ISR_TEACK @@ -1998,21 +2043,6 @@ static int uart_stm32_init(const struct device *dev) config->irq_config_func(dev); #endif /* CONFIG_PM || CONFIG_UART_INTERRUPT_DRIVEN || CONFIG_UART_ASYNC_API */ -#if defined(CONFIG_PM) && defined(IS_UART_WAKEUP_FROMSTOP_INSTANCE) - if (config->wakeup_source) { - /* Enable ability to wakeup device in Stop mode - * Effect depends on CONFIG_PM_DEVICE status: - * CONFIG_PM_DEVICE=n : Always active - * CONFIG_PM_DEVICE=y : Controlled by pm_device_wakeup_enable() - */ - LL_USART_EnableInStopMode(config->usart); - if (config->wakeup_line != STM32_EXTI_LINE_NONE) { - /* Prepare the WAKEUP with the expected EXTI line */ - LL_EXTI_EnableIT_0_31(BIT(config->wakeup_line)); - } - } -#endif /* CONFIG_PM */ - #ifdef CONFIG_UART_ASYNC_API return uart_stm32_async_init(dev); #else @@ -2051,17 +2081,26 @@ static int uart_stm32_pm_action(const struct device *dev, switch (action) { case PM_DEVICE_ACTION_RESUME: - /* Set pins to active state */ - err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - return err; - } + /* When exiting low power mode, check whether UART is enabled. + * If not, it means we are exiting Suspend to RAM mode (STM32 + * Standby), and the driver need to be reinitialized + */ + if (LL_USART_IsEnabled(config->usart)) { + /* Set pins to active state */ + err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (err < 0) { + return err; + } - /* enable clock */ - err = clock_control_on(data->clock, (clock_control_subsys_t)&config->pclken[0]); - if (err != 0) { - LOG_ERR("Could not enable (LP)UART clock"); - return err; + /* enable clock */ + err = clock_control_on(data->clock, + (clock_control_subsys_t)&config->pclken[0]); + if (err != 0) { + LOG_ERR("Could not enable (LP)UART clock"); + return err; + } + } else { + uart_stm32_init(dev); } break; case PM_DEVICE_ACTION_SUSPEND: @@ -2306,14 +2345,15 @@ static const struct uart_stm32_config uart_stm32_cfg_##index = { \ .pclken = pclken_##index, \ .pclk_len = DT_INST_NUM_CLOCKS(index), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ - .single_wire = DT_INST_PROP_OR(index, single_wire, false), \ - .tx_rx_swap = DT_INST_PROP_OR(index, tx_rx_swap, false), \ + .single_wire = DT_INST_PROP(index, single_wire), \ + .tx_rx_swap = DT_INST_PROP(index, tx_rx_swap), \ .rx_invert = DT_INST_PROP(index, rx_invert), \ .tx_invert = DT_INST_PROP(index, tx_invert), \ .de_enable = DT_INST_PROP(index, de_enable), \ .de_assert_time = DT_INST_PROP(index, de_assert_time), \ .de_deassert_time = DT_INST_PROP(index, de_deassert_time), \ .de_invert = DT_INST_PROP(index, de_invert), \ + .fifo_enable = DT_INST_PROP(index, fifo_enable), \ STM32_UART_IRQ_HANDLER_FUNC(index) \ STM32_UART_PM_WAKEUP(index) \ }; \ diff --git a/drivers/serial/uart_stm32.h b/drivers/serial/uart_stm32.h index ed8e8584cd6..7c6f432a504 100644 --- a/drivers/serial/uart_stm32.h +++ b/drivers/serial/uart_stm32.h @@ -49,6 +49,8 @@ struct uart_stm32_config { uint8_t de_deassert_time; /* enable de pin inversion */ bool de_invert; + /* enable fifo */ + bool fifo_enable; /* pin muxing */ const struct pinctrl_dev_config *pcfg; #if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API) || \ diff --git a/drivers/serial/usart_sam.c b/drivers/serial/usart_sam.c index ac87c41bdbf..2b050e74205 100644 --- a/drivers/serial/usart_sam.c +++ b/drivers/serial/usart_sam.c @@ -50,7 +50,7 @@ static int usart_sam_poll_in(const struct device *dev, unsigned char *c) Usart * const usart = config->regs; if (!(usart->US_CSR & US_CSR_RXRDY)) { - return -EBUSY; + return -1; } /* got a character */ diff --git a/drivers/smbus/CMakeLists.txt b/drivers/smbus/CMakeLists.txt index 13a260681f0..b7677a9bf6f 100644 --- a/drivers/smbus/CMakeLists.txt +++ b/drivers/smbus/CMakeLists.txt @@ -4,7 +4,10 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/smbus.h) zephyr_library() +zephyr_library_sources(smbus_utils.c) + zephyr_library_sources_ifdef(CONFIG_SMBUS_SHELL smbus_shell.c) zephyr_library_sources_ifdef(CONFIG_SMBUS_INTEL_PCH intel_pch_smbus.c) +zephyr_library_sources_ifdef(CONFIG_SMBUS_STM32 smbus_stm32.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE smbus_handlers.c) diff --git a/drivers/smbus/Kconfig b/drivers/smbus/Kconfig index 88eff8b0030..74efaae29f1 100644 --- a/drivers/smbus/Kconfig +++ b/drivers/smbus/Kconfig @@ -77,4 +77,22 @@ config SMBUS_INTEL_PCH_SMBALERT endif # SMBUS_INTEL_PCH +config SMBUS_STM32 + bool "STM32 SMBus driver" + default y + depends on DT_HAS_ST_STM32_SMBUS_ENABLED + depends on I2C_STM32 + help + Enable STM32 SMBus driver. + +if SMBUS_STM32 + +config SMBUS_STM32_SMBALERT + bool "SMBus STM32 SMBALERT signal support" + default y + help + Support SMBALERT signal from peripheral devices. + +endif # SMBUS_STM32 + endif # SMBUS diff --git a/drivers/smbus/intel_pch_smbus.c b/drivers/smbus/intel_pch_smbus.c index e40fc3d0cb6..9452efecf22 100644 --- a/drivers/smbus/intel_pch_smbus.c +++ b/drivers/smbus/intel_pch_smbus.c @@ -143,33 +143,7 @@ static void smbalert_work(struct k_work *work) smb_alert_work); const struct device *dev = data->dev; - /** - * There might be several peripheral devices and the he highest - * priority (lowest address) device wins arbitration, we need to - * read them all. - * - * The format of the transaction is: - * - * 0 1 2 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |S| Alert Addr |R|A| Address |X|N|P| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - do { - uint8_t addr; - int ret; - - ret = smbus_byte_read(dev, SMBUS_ADDRESS_ARA, &addr); - if (ret < 0) { - LOG_DBG("Cannot read peripheral address (anymore)"); - return; - } - - LOG_DBG("Read addr 0x%02x, ret %d", addr, ret); - - smbus_fire_callbacks(&data->smbalert_cbs, dev, addr); - } while (true); + smbus_loop_alert_devices(dev, &data->smbalert_cbs); } static int pch_smbus_smbalert_set_sb(const struct device *dev, diff --git a/drivers/smbus/smbus_stm32.c b/drivers/smbus/smbus_stm32.c new file mode 100644 index 00000000000..56636cc84bf --- /dev/null +++ b/drivers/smbus/smbus_stm32.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "smbus_utils.h" + +LOG_MODULE_REGISTER(stm32_smbus, CONFIG_SMBUS_LOG_LEVEL); + +struct smbus_stm32_config { + const struct pinctrl_dev_config *pcfg; + const struct device *i2c_dev; +}; + +struct smbus_stm32_data { + uint32_t config; + const struct device *dev; +#ifdef CONFIG_SMBUS_STM32_SMBALERT + sys_slist_t smbalert_callbacks; + struct k_work smbalert_work; +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ +}; + +#ifdef CONFIG_SMBUS_STM32_SMBALERT +static void smbus_stm32_smbalert_isr(const struct device *dev) +{ + struct smbus_stm32_data *data = dev->data; + + k_work_submit(&data->smbalert_work); +} + +static void smbus_stm32_smbalert_work(struct k_work *work) +{ + struct smbus_stm32_data *data = CONTAINER_OF(work, struct smbus_stm32_data, smbalert_work); + const struct device *dev = data->dev; + + LOG_DBG("%s: got SMB alert", dev->name); + + smbus_loop_alert_devices(dev, &data->smbalert_callbacks); +} + +static int smbus_stm32_smbalert_set_cb(const struct device *dev, struct smbus_callback *cb) +{ + struct smbus_stm32_data *data = dev->data; + + return smbus_callback_set(&data->smbalert_callbacks, cb); +} + +static int smbus_stm32_smbalert_remove_cb(const struct device *dev, struct smbus_callback *cb) +{ + struct smbus_stm32_data *data = dev->data; + + return smbus_callback_remove(&data->smbalert_callbacks, cb); +} +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +static int smbus_stm32_init(const struct device *dev) +{ + const struct smbus_stm32_config *config = dev->config; + struct smbus_stm32_data *data = dev->data; + int result; + + data->dev = dev; + + if (!device_is_ready(config->i2c_dev)) { + LOG_ERR("%s: I2C device is not ready", dev->name); + return -ENODEV; + } + + result = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (result < 0) { + LOG_ERR("%s: pinctrl setup failed (%d)", dev->name, result); + return result; + } + +#ifdef CONFIG_SMBUS_STM32_SMBALERT + k_work_init(&data->smbalert_work, smbus_stm32_smbalert_work); + + i2c_stm32_smbalert_set_callback(config->i2c_dev, smbus_stm32_smbalert_isr, dev); +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + + return 0; +} + +static int smbus_stm32_configure(const struct device *dev, uint32_t config_value) +{ + const struct smbus_stm32_config *config = dev->config; + struct smbus_stm32_data *data = dev->data; + + if (config_value & SMBUS_MODE_PEC) { + LOG_ERR("%s: not implemented", dev->name); + return -EINVAL; + } + + if (config_value & SMBUS_MODE_HOST_NOTIFY) { + LOG_ERR("%s: not available", dev->name); + return -EINVAL; + } + + if (config_value & SMBUS_MODE_CONTROLLER) { + LOG_DBG("%s: configuring SMB in host mode", dev->name); + i2c_stm32_set_smbus_mode(config->i2c_dev, I2CSTM32MODE_SMBUSHOST); + } else { + LOG_DBG("%s: configuring SMB in device mode", dev->name); + i2c_stm32_set_smbus_mode(config->i2c_dev, I2CSTM32MODE_SMBUSDEVICE); + } + + if (config_value & SMBUS_MODE_SMBALERT) { + LOG_DBG("%s: activating SMB alert", dev->name); + i2c_stm32_smbalert_enable(config->i2c_dev); + } else { + LOG_DBG("%s: deactivating SMB alert", dev->name); + i2c_stm32_smbalert_disable(config->i2c_dev); + } + + data->config = config_value; + return 0; +} + +static int smbus_stm32_get_config(const struct device *dev, uint32_t *config) +{ + struct smbus_stm32_data *data = dev->data; + *config = data->config; + return 0; +} + +static int smbus_stm32_quick(const struct device *dev, uint16_t periph_addr, + enum smbus_direction rw) +{ + const struct smbus_stm32_config *config = dev->config; + + switch (rw) { + case SMBUS_MSG_WRITE: + return i2c_write(config->i2c_dev, NULL, 0, periph_addr); + case SMBUS_MSG_READ: + return i2c_read(config->i2c_dev, NULL, 0, periph_addr); + default: + LOG_ERR("%s: invalid smbus direction %i", dev->name, rw); + return -EINVAL; + } +} + +static int smbus_stm32_byte_write(const struct device *dev, uint16_t periph_addr, uint8_t command) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_write(config->i2c_dev, &command, sizeof(command), periph_addr); +} + +static int smbus_stm32_byte_read(const struct device *dev, uint16_t periph_addr, uint8_t *byte) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_read(config->i2c_dev, byte, sizeof(*byte), periph_addr); +} + +static int smbus_stm32_byte_data_write(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint8_t byte) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[] = { + command, + byte, + }; + + return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr); +} + +static int smbus_stm32_byte_data_read(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint8_t *byte) +{ + const struct smbus_stm32_config *config = dev->config; + + return i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), byte, + sizeof(*byte)); +} + +static int smbus_stm32_word_data_write(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint16_t word) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[sizeof(command) + sizeof(word)]; + + buffer[0] = command; + sys_put_le16(word, buffer + 1); + + return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr); +} + +static int smbus_stm32_word_data_read(const struct device *dev, uint16_t periph_addr, + uint8_t command, uint16_t *word) +{ + const struct smbus_stm32_config *config = dev->config; + int result; + + result = i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), word, + sizeof(*word)); + *word = sys_le16_to_cpu(*word); + + return result; +} + +static int smbus_stm32_pcall(const struct device *dev, uint16_t periph_addr, uint8_t command, + uint16_t send_word, uint16_t *recv_word) +{ + const struct smbus_stm32_config *config = dev->config; + uint8_t buffer[sizeof(command) + sizeof(send_word)]; + int result; + + buffer[0] = command; + sys_put_le16(send_word, buffer + 1); + + result = i2c_write_read(config->i2c_dev, periph_addr, buffer, ARRAY_SIZE(buffer), recv_word, + sizeof(*recv_word)); + *recv_word = sys_le16_to_cpu(*recv_word); + + return result; +} + +static int smbus_stm32_block_write(const struct device *dev, uint16_t periph_addr, uint8_t command, + uint8_t count, uint8_t *buf) +{ + const struct smbus_stm32_config *config = dev->config; + struct i2c_msg messages[] = { + { + .buf = &command, + .len = sizeof(command), + .flags = 0, + }, + { + .buf = buf, + .len = count, + .flags = 0, + }, + }; + + return i2c_transfer(config->i2c_dev, messages, ARRAY_SIZE(messages), periph_addr); +} + +static const struct smbus_driver_api smbus_stm32_api = { + .configure = smbus_stm32_configure, + .get_config = smbus_stm32_get_config, + .smbus_quick = smbus_stm32_quick, + .smbus_byte_write = smbus_stm32_byte_write, + .smbus_byte_read = smbus_stm32_byte_read, + .smbus_byte_data_write = smbus_stm32_byte_data_write, + .smbus_byte_data_read = smbus_stm32_byte_data_read, + .smbus_word_data_write = smbus_stm32_word_data_write, + .smbus_word_data_read = smbus_stm32_word_data_read, + .smbus_pcall = smbus_stm32_pcall, + .smbus_block_write = smbus_stm32_block_write, +#ifdef CONFIG_SMBUS_STM32_SMBALERT + .smbus_smbalert_set_cb = smbus_stm32_smbalert_set_cb, + .smbus_smbalert_remove_cb = smbus_stm32_smbalert_remove_cb, +#else + .smbus_smbalert_set_cb = NULL, + .smbus_smbalert_remove_cb = NULL, +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + .smbus_block_read = NULL, + .smbus_block_pcall = NULL, + .smbus_host_notify_set_cb = NULL, + .smbus_host_notify_remove_cb = NULL, +}; + +#define DT_DRV_COMPAT st_stm32_smbus + +#define SMBUS_STM32_DEVICE_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static struct smbus_stm32_config smbus_stm32_config_##n = { \ + .i2c_dev = DEVICE_DT_GET(DT_INST_PROP(n, i2c)), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct smbus_stm32_data smbus_stm32_data_##n; \ + \ + SMBUS_DEVICE_DT_INST_DEFINE(n, smbus_stm32_init, NULL, &smbus_stm32_data_##n, \ + &smbus_stm32_config_##n, POST_KERNEL, \ + CONFIG_SMBUS_INIT_PRIORITY, &smbus_stm32_api); + +DT_INST_FOREACH_STATUS_OKAY(SMBUS_STM32_DEVICE_INIT) diff --git a/drivers/smbus/smbus_utils.c b/drivers/smbus/smbus_utils.c new file mode 100644 index 00000000000..5ff3076da9e --- /dev/null +++ b/drivers/smbus/smbus_utils.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smbus_utils.h" + +#include + +LOG_MODULE_REGISTER(smbus_utils, CONFIG_SMBUS_LOG_LEVEL); + +void smbus_loop_alert_devices(const struct device *dev, sys_slist_t *callbacks) +{ + int result; + uint8_t address; + + /** + * There might be several peripheral devices which could have triggered the alert and + * the one with the highest priority (lowest address) device wins the arbitration. In + * any case, we will have to loop through all of them. + * + * The format of the transaction is: + * + * 0 1 2 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |S| Alert Addr |R|A| Address |X|N|P| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + while (true) { + result = smbus_byte_read(dev, SMBUS_ADDRESS_ARA, &address); + if (result != 0) { + LOG_DBG("%s: no more peripheral devices left which triggered an alert", + dev->name); + return; + } + + LOG_DBG("%s: address 0x%02X triggered an alert", dev->name, address); + + smbus_fire_callbacks(callbacks, dev, address); + } +} diff --git a/drivers/smbus/smbus_utils.h b/drivers/smbus/smbus_utils.h index 0158d2c5a52..a4f7ecd0c72 100644 --- a/drivers/smbus/smbus_utils.h +++ b/drivers/smbus/smbus_utils.h @@ -7,6 +7,11 @@ #ifndef ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ #define ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ +#include +#include +#include +#include + /** * @brief Generic function to insert a callback to a callback list * @@ -91,5 +96,15 @@ static inline void smbus_init_callback(struct smbus_callback *callback, callback->addr = addr; } +/** + * @brief Helper for handling an SMB alert + * + * This loops through all devices which triggered the SMB alert and + * fires the callbacks. + * + * @param dev SMBus device + * @param callbacks list of SMB alert callbacks + */ +void smbus_loop_alert_devices(const struct device *dev, sys_slist_t *callbacks); #endif /* ZEPHYR_DRIVERS_SMBUS_SMBUS_UTILS_H_ */ diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index 956b6d3397a..cd4699850f2 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -44,9 +44,11 @@ zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c) zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ spi_ambiq.c) zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ mspi_ambiq.c) - +zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_MSS spi_mchp_mss.c) zephyr_library_sources_ifdef(CONFIG_SPI_RTIO spi_rtio.c) zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c) zephyr_library_sources_ifdef(CONFIG_SPI_INFINEON_CAT1 spi_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_SPI_SEDI spi_sedi.c) +zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_SPIP spi_npcx_spip.c) +zephyr_library_sources_ifdef(CONFIG_SPI_GRLIB_SPIMCTRL spi_grlib_spimctrl.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 24982cae90e..2cb7c83bd1c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -137,4 +137,10 @@ source "drivers/spi/Kconfig.ifx_cat1" source "drivers/spi/Kconfig.sedi" +source "drivers/spi/Kconfig.npcx" + +source "drivers/spi/Kconfig.mchp_mss" + +source "drivers/spi/Kconfig.grlib_spimctrl" + endif # SPI diff --git a/drivers/spi/Kconfig.andes_atcspi200 b/drivers/spi/Kconfig.andes_atcspi200 index 41b331023af..ad7dfca16cc 100644 --- a/drivers/spi/Kconfig.andes_atcspi200 +++ b/drivers/spi/Kconfig.andes_atcspi200 @@ -11,3 +11,12 @@ config SPI_ANDES_ATCSPI200 depends on DT_HAS_ANDESTECH_ATCSPI200_ENABLED help Enable driver for Andes ATCSPI200 SPI controller + +if SPI_ANDES_ATCSPI200 + +config ANDES_SPI_DMA_MODE + bool "Using DMA mode for spi" + default y + depends on DMA + +endif # SPI_ANDES_ATCSPI200 diff --git a/drivers/spi/Kconfig.dw b/drivers/spi/Kconfig.dw index 1902d36bc4d..3ebdd54ee93 100644 --- a/drivers/spi/Kconfig.dw +++ b/drivers/spi/Kconfig.dw @@ -1,18 +1,13 @@ # DesignWare SPI driver configuration options # Copyright (c) 2015-2016 Intel Corporation +# Copyright (c) 2023 Meta Platforms # SPDX-License-Identifier: Apache-2.0 -config HAS_SPI_DW - bool - help - Signifies whether DesignWare SPI compatible HW is available - menuconfig SPI_DW bool "Designware SPI controller driver" default y depends on DT_HAS_SNPS_DESIGNWARE_SPI_ENABLED - depends on HAS_SPI_DW help Enable support for Designware's SPI controllers. diff --git a/drivers/spi/Kconfig.grlib_spimctrl b/drivers/spi/Kconfig.grlib_spimctrl new file mode 100644 index 00000000000..faea0ff1038 --- /dev/null +++ b/drivers/spi/Kconfig.grlib_spimctrl @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Frontgrade Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +config SPI_GRLIB_SPIMCTRL + bool "GRLIB SPI memory controller" + depends on SOC_SPARC_LEON + help + Enable the GRLIB SPIMCTRL diff --git a/drivers/spi/Kconfig.mchp_mss b/drivers/spi/Kconfig.mchp_mss new file mode 100644 index 00000000000..a12d64e36eb --- /dev/null +++ b/drivers/spi/Kconfig.mchp_mss @@ -0,0 +1,11 @@ +# Microchip Polarfire SOC SPI + +# Copyright (c) 2022 Microchip Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SPI_MCHP_MSS + bool "Microchip Polarfire SOC SPI driver" + default y + depends on DT_HAS_MICROCHIP_MPFS_SPI_ENABLED + help + Enable support for the Polarfire SOC SPI driver. diff --git a/drivers/spi/Kconfig.mcux_lpspi b/drivers/spi/Kconfig.mcux_lpspi index 1b1cc4675fb..bad4191fbdc 100644 --- a/drivers/spi/Kconfig.mcux_lpspi +++ b/drivers/spi/Kconfig.mcux_lpspi @@ -19,4 +19,18 @@ config SPI_MCUX_LPSPI_DMA help Enable the SPI DMA mode for SPI instances that enable dma channels in their device tree node. + +if SPI_RTIO +config SPI_MCUX_RTIO_SQ_SIZE + int "number of available submission queue entries" + default 8 # sensible default that covers most common spi transactions + help + when rtio is use with spi each driver holds a context with which blocking + api calls use to perform spi transactions. this queue needs to be as deep + as the longest set of spi_buf_sets used, where normal spi operations are + used (equal length buffers). it may need to be slightly deeper where the + spi buffer sets for transmit/receive are not always matched equally in + length as these are transformed into normal transceives. +endif # SPI_RTIO + endif # SPI_MCUX_LPSPI diff --git a/drivers/spi/Kconfig.npcx b/drivers/spi/Kconfig.npcx new file mode 100644 index 00000000000..196e85cf02d --- /dev/null +++ b/drivers/spi/Kconfig.npcx @@ -0,0 +1,17 @@ +# Nuvoton NPCX SPI Driver configuration options + +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig SPI_NPCX_SPIP + bool "Nuvoton NPCX embedded controller (EC) SPI driver" + default y + depends on DT_HAS_NUVOTON_NPCX_SPIP_ENABLED + help + Enable the SPI peripherals on NPCX MCU. + +config SPI_NPCX_SPIP_INTERRUPT + bool "NPCX SPIP Interrupt Support" + depends on SPI_NPCX_SPIP + help + Enable Interrupt support for the SPI Driver of NPCX chip. diff --git a/drivers/spi/Kconfig.nrfx b/drivers/spi/Kconfig.nrfx index c185efa9f8f..0ee1c03065b 100644 --- a/drivers/spi/Kconfig.nrfx +++ b/drivers/spi/Kconfig.nrfx @@ -54,6 +54,7 @@ config SPI_NRFX_SPIS config SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 depends on SOC_NRF52832 + select NRFX_PPI bool "Allow enabling the SPIM driver despite PAN 58" help Allow enabling the nRF SPI Master with EasyDMA, despite @@ -74,14 +75,20 @@ config SPI_NRFX_RAM_BUFFER_SIZE default 8 depends on SPI_NRFX_SPIM help - SPIM peripherals cannot transmit data directly from flash. Therefore, - a buffer in RAM needs to be provided for each instance of SPI driver - using SPIM peripheral, so that the driver can copy there a chunk of - data from flash and transmit it. - The size is specified in bytes. A size of 0 means that this feature - should be disabled, and the application must then take care of not - supplying buffers located in flash to the driver, otherwise such - transfers will fail. + Because of using EasyDMA, SPIM peripherals cannot use transmit and + receive buffers from all memory locations. They are restricted to + buffers located in certain RAM memories only. Therefore, each SPIM + driver instance needs to use an intermediate local RAM buffer, + to transfer data in chunks not exceeding the size of that buffer, + and to copy those chunks between the local buffer and the one + specified in the transfer request if the latter is not accessible + by EasyDMA. + + This option specifies the size in bytes of such local RAM buffers + for both TX and RX paths. A size of 0 means that this feature should + be disabled and the driver user must take care of not making transfer + requests with buffers not accessible by EasyDMA since such transfers + will fail. config SPI_NRFX_WAKE_TIMEOUT_US int "Maximum time to wait for SPI slave to wake up" diff --git a/drivers/spi/Kconfig.sam b/drivers/spi/Kconfig.sam index 6423390a024..1a7e0b5916b 100644 --- a/drivers/spi/Kconfig.sam +++ b/drivers/spi/Kconfig.sam @@ -22,7 +22,7 @@ config SPI_SAM_DMA if SPI_RTIO config SPI_SAM_RTIO_SQ_SIZE - int "Number of avialable submission queue entries" + int "Number of available submission queue entries" default 8 # Sensible default that covers most common spi transactions help When RTIO is use with SPI each driver holds a context with which blocking diff --git a/drivers/spi/Kconfig.stm32 b/drivers/spi/Kconfig.stm32 index 6a53f30cbc4..04bc6dabcd2 100644 --- a/drivers/spi/Kconfig.stm32 +++ b/drivers/spi/Kconfig.stm32 @@ -32,22 +32,21 @@ config SPI_STM32_USE_HW_SS help Use Slave Select pin instead of software Slave Select. -config SPI_STM32F7_ERRATA_BUSY +config SPI_STM32_ERRATA_BUSY bool default y - depends on SOC_STM32F745XX || SOC_STM32F746XX || \ - SOC_STM32F750XX || SOC_STM32F756XX + depends on SOC_SERIES_STM32F7X || SOC_SERIES_STM32L4X help Handles erratum "BSY bit may stay high at the end of a data - transfer in Slave mode". - Seen in Errata Sheet 0290 §2.11.2 + transfer in slave mode". + Seen for instance in Errata Sheet 0290 §2.11.2 -if SPI_STM32F7_ERRATA_BUSY +if SPI_STM32_ERRATA_BUSY config SPI_STM32_BUSY_FLAG_TIMEOUT int "timeout in us for the STM32 busy flag workaround" default 10000 -endif # SPI_STM32F7_ERRATA_BUSY +endif # SPI_STM32_ERRATA_BUSY endif # SPI_STM32 diff --git a/drivers/spi/mspi_ambiq.c b/drivers/spi/mspi_ambiq.c index 03ad8b2c0ac..0f24fcdfe4f 100644 --- a/drivers/spi/mspi_ambiq.c +++ b/drivers/spi/mspi_ambiq.c @@ -197,7 +197,7 @@ static int mspi_ambiq_release(const struct device *dev, const struct spi_config return 0; } -static struct spi_driver_api mspi_ambiq_driver_api = { +static const struct spi_driver_api mspi_ambiq_driver_api = { .transceive = mspi_ambiq_transceive, .release = mspi_ambiq_release, }; diff --git a/drivers/spi/spi_ambiq.c b/drivers/spi/spi_ambiq.c index 16614798e32..61d71e3f567 100644 --- a/drivers/spi/spi_ambiq.c +++ b/drivers/spi/spi_ambiq.c @@ -219,7 +219,7 @@ static int spi_ambiq_release(const struct device *dev, const struct spi_config * return 0; } -static struct spi_driver_api spi_ambiq_driver_api = { +static const struct spi_driver_api spi_ambiq_driver_api = { .transceive = spi_ambiq_transceive, .release = spi_ambiq_release, }; diff --git a/drivers/spi/spi_andes_atcspi200.c b/drivers/spi/spi_andes_atcspi200.c index 87726fd90ca..adc7b2e9157 100644 --- a/drivers/spi/spi_andes_atcspi200.c +++ b/drivers/spi/spi_andes_atcspi200.c @@ -12,14 +12,38 @@ typedef void (*atcspi200_cfg_func_t)(void); +#ifdef CONFIG_ANDES_SPI_DMA_MODE + +#define ANDES_SPI_DMA_ERROR_FLAG 0x01 +#define ANDES_SPI_DMA_RX_DONE_FLAG 0x02 +#define ANDES_SPI_DMA_TX_DONE_FLAG 0x04 +#define ANDES_SPI_DMA_DONE_FLAG \ + (ANDES_SPI_DMA_RX_DONE_FLAG | ANDES_SPI_DMA_TX_DONE_FLAG) + +struct stream { + const struct device *dma_dev; + uint32_t channel; + uint32_t block_idx; + struct dma_config dma_cfg; + struct dma_block_config dma_blk_cfg; + struct dma_block_config chain_block[MAX_CHAIN_SIZE]; + uint8_t priority; + bool src_addr_increment; + bool dst_addr_increment; +}; +#endif + struct spi_atcspi200_data { struct spi_context ctx; uint32_t tx_fifo_size; uint32_t rx_fifo_size; int tx_cnt; - uint32_t is_cmdaddr_mode; size_t chunk_len; bool busy; +#ifdef CONFIG_ANDES_SPI_DMA_MODE + struct stream dma_rx; + struct stream dma_tx; +#endif }; struct spi_atcspi200_cfg { @@ -39,61 +63,67 @@ static int spi_config(const struct device *dev, /* Set the divisor for SPI interface sclk */ sclk_div = (cfg->f_sys / (config->frequency << 1)) - 1; - CLR_MASK(SPI_TIMIN(dev), TIMIN_SCLK_DIV_MSK); - SET_MASK(SPI_TIMIN(dev), sclk_div); + sys_clear_bits(SPI_TIMIN(cfg->base), TIMIN_SCLK_DIV_MSK); + sys_set_bits(SPI_TIMIN(cfg->base), sclk_div); /* Set Master mode */ - CLR_MASK(SPI_TFMAT(dev), TFMAT_SLVMODE_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_SLVMODE_MSK); /* Disable data merge mode */ - CLR_MASK(SPI_TFMAT(dev), TFMAT_DATA_MERGE_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_DATA_MERGE_MSK); /* Set data length */ data_len = SPI_WORD_SIZE_GET(config->operation) - 1; - CLR_MASK(SPI_TFMAT(dev), TFMAT_DATA_LEN_MSK); - SET_MASK(SPI_TFMAT(dev), (data_len << TFMAT_DATA_LEN_OFFSET)); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_DATA_LEN_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), (data_len << TFMAT_DATA_LEN_OFFSET)); /* Set SPI frame format */ if (config->operation & SPI_MODE_CPHA) { - SET_MASK(SPI_TFMAT(dev), TFMAT_CPHA_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_CPHA_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_CPHA_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_CPHA_MSK); } if (config->operation & SPI_MODE_CPOL) { - SET_MASK(SPI_TFMAT(dev), TFMAT_CPOL_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_CPOL_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_CPOL_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_CPOL_MSK); } /* Set SPI bit order */ if (config->operation & SPI_TRANSFER_LSB) { - SET_MASK(SPI_TFMAT(dev), TFMAT_LSB_MSK); + sys_set_bits(SPI_TFMAT(cfg->base), TFMAT_LSB_MSK); } else { - CLR_MASK(SPI_TFMAT(dev), TFMAT_LSB_MSK); + sys_clear_bits(SPI_TFMAT(cfg->base), TFMAT_LSB_MSK); } /* Set TX/RX FIFO threshold */ - CLR_MASK(SPI_CTRL(dev), CTRL_TX_THRES_MSK); - CLR_MASK(SPI_CTRL(dev), CTRL_RX_THRES_MSK); + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_TX_THRES_MSK); + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_RX_THRES_MSK); - SET_MASK(SPI_CTRL(dev), TX_FIFO_THRESHOLD << CTRL_TX_THRES_OFFSET); - SET_MASK(SPI_CTRL(dev), RX_FIFO_THRESHOLD << CTRL_RX_THRES_OFFSET); + sys_set_bits(SPI_CTRL(cfg->base), TX_FIFO_THRESHOLD << CTRL_TX_THRES_OFFSET); + sys_set_bits(SPI_CTRL(cfg->base), RX_FIFO_THRESHOLD << CTRL_RX_THRES_OFFSET); return 0; } -static int spi_transfer(const struct device *dev, uint32_t len) +static int spi_transfer(const struct device *dev) { struct spi_atcspi200_data * const data = dev->data; + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_context *ctx = &data->ctx; uint32_t data_len, tctrl, int_msk; - if (len > MAX_TRANSFER_CNT) { + if (data->chunk_len != 0) { + data_len = data->chunk_len - 1; + } else { + data_len = 0; + } + + if (data_len > MAX_TRANSFER_CNT) { return -EINVAL; } - data_len = len - 1; data->tx_cnt = 0; if (!spi_context_rx_on(ctx)) { @@ -113,15 +143,13 @@ static int spi_transfer(const struct device *dev, uint32_t len) IEN_END_MSK; } - sys_write32(tctrl, SPI_TCTRL(dev)); + sys_write32(tctrl, SPI_TCTRL(cfg->base)); /* Enable TX/RX FIFO interrupts */ - sys_write32(int_msk, SPI_INTEN(dev)); + sys_write32(int_msk, SPI_INTEN(cfg->base)); - if (!data->is_cmdaddr_mode) { - /* Start transferring */ - sys_write32(0, SPI_CMD(dev)); - } + /* Start transferring */ + sys_write32(0, SPI_CMD(cfg->base)); return 0; } @@ -162,31 +190,412 @@ static int configure(const struct device *dev, return 0; } -static void transfer_next_chunk(const struct device *dev) + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + +static int spi_dma_tx_load(const struct device *dev); +static int spi_dma_rx_load(const struct device *dev); + +static inline void spi_tx_dma_enable(const struct device *dev) { - struct spi_atcspi200_data * const data = dev->data; + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Enable TX DMA */ + sys_set_bits(SPI_CTRL(cfg->base), CTRL_TX_DMA_EN_MSK); +} + +static inline void spi_tx_dma_disable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Disable TX DMA */ + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_TX_DMA_EN_MSK); +} + +static inline void spi_rx_dma_enable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Enable RX DMA */ + sys_set_bits(SPI_CTRL(cfg->base), CTRL_RX_DMA_EN_MSK); +} + +static inline void spi_rx_dma_disable(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + /* Disable RX DMA */ + sys_clear_bits(SPI_CTRL(cfg->base), CTRL_RX_DMA_EN_MSK); +} + +static int spi_dma_move_buffers(const struct device *dev) +{ + struct spi_atcspi200_data *data = dev->data; struct spi_context *ctx = &data->ctx; - int error = 0; + uint32_t error = 0; - size_t chunk_len = spi_context_max_continuous_chunk(ctx); + data->dma_rx.dma_blk_cfg.next_block = NULL; + data->dma_tx.dma_blk_cfg.next_block = NULL; - if (chunk_len > 0) { - data->chunk_len = chunk_len; - error = spi_transfer(dev, chunk_len); - if (error == 0) { + if (spi_context_tx_on(ctx)) { + error = spi_dma_tx_load(dev); + if (error != 0) { + return error; + } + } + + if (spi_context_rx_on(ctx)) { + error = spi_dma_rx_load(dev); + if (error != 0) { + return error; + } + } + + return 0; +} + +static inline void dma_rx_callback(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *spi_dev = (struct device *)user_data; + struct spi_atcspi200_data *data = spi_dev->data; + struct spi_context *ctx = &data->ctx; + int error; + + dma_stop(data->dma_rx.dma_dev, data->dma_rx.channel); + spi_rx_dma_disable(spi_dev); + + if (spi_context_rx_on(ctx)) { + if (spi_dma_rx_load(spi_dev) != 0) { return; } + spi_rx_dma_enable(spi_dev); + error = dma_start(data->dma_rx.dma_dev, data->dma_rx.channel); + __ASSERT(error == 0, "dma_start was failed in rx callback"); + } +} + +static inline void dma_tx_callback(const struct device *dev, void *user_data, + uint32_t channel, int status) +{ + const struct device *spi_dev = (struct device *)user_data; + struct spi_atcspi200_data *data = spi_dev->data; + struct spi_context *ctx = &data->ctx; + int error; + + dma_stop(data->dma_tx.dma_dev, data->dma_tx.channel); + spi_tx_dma_disable(spi_dev); + + if (spi_context_tx_on(ctx)) { + if (spi_dma_tx_load(spi_dev) != 0) { + return; + } + spi_tx_dma_enable(spi_dev); + error = dma_start(data->dma_tx.dma_dev, data->dma_tx.channel); + __ASSERT(error == 0, "dma_start was failed in tx callback"); + } +} + +/* + * dummy value used for transferring NOP when tx buf is null + * and use as dummy sink for when rx buf is null + */ +uint32_t dummy_rx_tx_buffer; + +static int spi_dma_tx_load(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int remain_len, ret, dfs; + + /* prepare the block for this TX DMA channel */ + memset(&data->dma_tx.dma_blk_cfg, 0, sizeof(struct dma_block_config)); + + if (ctx->current_tx->len > data->chunk_len) { + data->dma_tx.dma_blk_cfg.block_size = data->chunk_len / + data->dma_tx.dma_cfg.dest_data_size; + } else { + data->dma_tx.dma_blk_cfg.block_size = ctx->current_tx->len / + data->dma_tx.dma_cfg.dest_data_size; + } + + /* tx direction has memory as source and periph as dest. */ + if (ctx->current_tx->buf == NULL) { + dummy_rx_tx_buffer = 0; + /* if tx buff is null, then sends NOP on the line. */ + data->dma_tx.dma_blk_cfg.source_address = (uintptr_t)&dummy_rx_tx_buffer; + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + data->dma_tx.dma_blk_cfg.source_address = (uintptr_t)ctx->current_tx->buf; + if (data->dma_tx.src_addr_increment) { + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_tx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; + remain_len = data->chunk_len - ctx->current_tx->len; + spi_context_update_tx(ctx, dfs, ctx->current_tx->len); + + data->dma_tx.dma_blk_cfg.dest_address = (uint32_t)SPI_DATA(cfg->base); + /* fifo mode NOT USED there */ + if (data->dma_tx.dst_addr_increment) { + data->dma_tx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_tx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + /* direction is given by the DT */ + data->dma_tx.dma_cfg.head_block = &data->dma_tx.dma_blk_cfg; + data->dma_tx.dma_cfg.head_block->next_block = NULL; + /* give the client dev as arg, as the callback comes from the dma */ + data->dma_tx.dma_cfg.user_data = (void *)dev; + + if (data->dma_tx.dma_cfg.source_chaining_en) { + data->dma_tx.dma_cfg.block_count = ctx->tx_count; + data->dma_tx.dma_cfg.dma_callback = NULL; + data->dma_tx.block_idx = 0; + struct dma_block_config *blk_cfg = &data->dma_tx.dma_blk_cfg; + const struct spi_buf *current_tx = ctx->current_tx; + + while (remain_len > 0) { + struct dma_block_config *next_blk_cfg; + + next_blk_cfg = &data->dma_tx.chain_block[data->dma_tx.block_idx]; + data->dma_tx.block_idx += 1; + + blk_cfg->next_block = next_blk_cfg; + current_tx = ctx->current_tx; + + next_blk_cfg->block_size = current_tx->len / + data->dma_tx.dma_cfg.dest_data_size; + + /* tx direction has memory as source and periph as dest. */ + if (current_tx->buf == NULL) { + dummy_rx_tx_buffer = 0; + /* if tx buff is null, then sends NOP on the line. */ + next_blk_cfg->source_address = (uintptr_t)&dummy_rx_tx_buffer; + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + next_blk_cfg->source_address = (uintptr_t)current_tx->buf; + if (data->dma_tx.src_addr_increment) { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + next_blk_cfg->dest_address = (uint32_t)SPI_DATA(cfg->base); + /* fifo mode NOT USED there */ + if (data->dma_tx.dst_addr_increment) { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + blk_cfg = next_blk_cfg; + next_blk_cfg->next_block = NULL; + remain_len -= ctx->current_tx->len; + spi_context_update_tx(ctx, dfs, ctx->current_tx->len); + } + + } else { + data->dma_tx.dma_blk_cfg.next_block = NULL; + data->dma_tx.dma_cfg.block_count = 1; + data->dma_tx.dma_cfg.dma_callback = dma_tx_callback; + } + + /* pass our client origin to the dma: data->dma_tx.dma_channel */ + ret = dma_config(data->dma_tx.dma_dev, data->dma_tx.channel, + &data->dma_tx.dma_cfg); + /* the channel is the actual stream from 0 */ + if (ret != 0) { + data->dma_tx.block_idx = 0; + data->dma_tx.dma_blk_cfg.next_block = NULL; + return ret; + } + + return 0; +} + +static int spi_dma_rx_load(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int remain_len, ret, dfs; + + /* prepare the block for this RX DMA channel */ + memset(&data->dma_rx.dma_blk_cfg, 0, sizeof(struct dma_block_config)); + + if (ctx->current_rx->len > data->chunk_len) { + data->dma_rx.dma_blk_cfg.block_size = data->chunk_len / + data->dma_rx.dma_cfg.dest_data_size; + } else { + data->dma_rx.dma_blk_cfg.block_size = ctx->current_rx->len / + data->dma_rx.dma_cfg.dest_data_size; + } + + /* rx direction has periph as source and mem as dest. */ + if (ctx->current_rx->buf == NULL) { + /* if rx buff is null, then write data to dummy address. */ + data->dma_rx.dma_blk_cfg.dest_address = (uintptr_t)&dummy_rx_tx_buffer; + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + data->dma_rx.dma_blk_cfg.dest_address = (uintptr_t)ctx->current_rx->buf; + if (data->dma_rx.dst_addr_increment) { + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_rx.dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; + remain_len = data->chunk_len - ctx->current_rx->len; + spi_context_update_rx(ctx, dfs, ctx->current_rx->len); + + data->dma_rx.dma_blk_cfg.source_address = (uint32_t)SPI_DATA(cfg->base); + + if (data->dma_rx.src_addr_increment) { + data->dma_rx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + data->dma_rx.dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + data->dma_rx.dma_cfg.head_block = &data->dma_rx.dma_blk_cfg; + data->dma_rx.dma_cfg.head_block->next_block = NULL; + data->dma_rx.dma_cfg.user_data = (void *)dev; + + if (data->dma_rx.dma_cfg.source_chaining_en) { + data->dma_rx.dma_cfg.block_count = ctx->rx_count; + data->dma_rx.dma_cfg.dma_callback = NULL; + data->dma_rx.block_idx = 0; + struct dma_block_config *blk_cfg = &data->dma_rx.dma_blk_cfg; + const struct spi_buf *current_rx = ctx->current_rx; + + while (remain_len > 0) { + struct dma_block_config *next_blk_cfg; + + next_blk_cfg = &data->dma_rx.chain_block[data->dma_rx.block_idx]; + data->dma_rx.block_idx += 1; + + blk_cfg->next_block = next_blk_cfg; + current_rx = ctx->current_rx; + + next_blk_cfg->block_size = current_rx->len / + data->dma_rx.dma_cfg.dest_data_size; + + /* rx direction has periph as source and mem as dest. */ + if (current_rx->buf == NULL) { + /* if rx buff is null, then write data to dummy address. */ + next_blk_cfg->dest_address = (uintptr_t)&dummy_rx_tx_buffer; + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } else { + next_blk_cfg->dest_address = (uintptr_t)current_rx->buf; + if (data->dma_rx.dst_addr_increment) { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + } + + next_blk_cfg->source_address = (uint32_t)SPI_DATA(cfg->base); + + if (data->dma_rx.src_addr_increment) { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_INCREMENT; + } else { + next_blk_cfg->source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE; + } + + blk_cfg = next_blk_cfg; + next_blk_cfg->next_block = NULL; + remain_len -= ctx->current_rx->len; + spi_context_update_rx(ctx, dfs, ctx->current_rx->len); + } + } else { + data->dma_rx.dma_blk_cfg.next_block = NULL; + data->dma_rx.dma_cfg.block_count = 1; + data->dma_rx.dma_cfg.dma_callback = dma_rx_callback; } - spi_context_cs_control(ctx, false); - /* Reset TX/RX FIFO */ - SET_MASK(SPI_CTRL(dev), CTRL_TX_FIFO_RST_MSK); - SET_MASK(SPI_CTRL(dev), CTRL_RX_FIFO_RST_MSK); + /* pass our client origin to the dma: data->dma_rx.channel */ + ret = dma_config(data->dma_rx.dma_dev, data->dma_rx.channel, + &data->dma_rx.dma_cfg); + /* the channel is the actual stream from 0 */ + if (ret != 0) { + data->dma_rx.block_idx = 0; + data->dma_rx.dma_blk_cfg.next_block = NULL; + return ret; + } - spi_context_complete(ctx, dev, error); - data->busy = false; + return 0; } +static int spi_transfer_dma(const struct device *dev) +{ + const struct spi_atcspi200_cfg * const cfg = dev->config; + struct spi_atcspi200_data * const data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t data_len, tctrl, dma_rx_enable, dma_tx_enable; + int error = 0; + + data_len = data->chunk_len - 1; + if (data_len > MAX_TRANSFER_CNT) { + return -EINVAL; + } + + if (!spi_context_rx_on(ctx)) { + tctrl = (TRNS_MODE_WRITE_ONLY << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_WR_TCNT_OFFSET); + dma_rx_enable = 0; + dma_tx_enable = 1; + } else if (!spi_context_tx_on(ctx)) { + tctrl = (TRNS_MODE_READ_ONLY << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_RD_TCNT_OFFSET); + dma_rx_enable = 1; + dma_tx_enable = 0; + } else { + tctrl = (TRNS_MODE_WRITE_READ << TCTRL_TRNS_MODE_OFFSET) | + (data_len << TCTRL_WR_TCNT_OFFSET) | + (data_len << TCTRL_RD_TCNT_OFFSET); + dma_rx_enable = 1; + dma_tx_enable = 1; + } + + sys_write32(tctrl, SPI_TCTRL(cfg->base)); + + /* Set sclk_div to zero */ + sys_clear_bits(SPI_TIMIN(cfg->base), 0xff); + + /* Enable END Interrupts */ + sys_write32(IEN_END_MSK, SPI_INTEN(cfg->base)); + + /* Setting DMA config*/ + error = spi_dma_move_buffers(dev); + if (error != 0) { + return error; + } + + /* Start transferring */ + sys_write32(0, SPI_CMD(cfg->base)); + + if (dma_rx_enable) { + spi_rx_dma_enable(dev); + error = dma_start(data->dma_rx.dma_dev, data->dma_rx.channel); + if (error != 0) { + return error; + } + } + if (dma_tx_enable) { + spi_tx_dma_enable(dev); + error = dma_start(data->dma_tx.dma_dev, data->dma_tx.channel); + if (error != 0) { + return error; + } + } + + return 0; +} +#endif + static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -195,12 +604,13 @@ static int transceive(const struct device *dev, spi_callback_t cb, void *userdata) { + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_atcspi200_data * const data = dev->data; struct spi_context *ctx = &data->ctx; int error, dfs; + size_t chunk_len; spi_context_lock(ctx, asynchronous, cb, userdata, config); - error = configure(dev, config); if (error == 0) { data->busy = true; @@ -209,9 +619,41 @@ static int transceive(const struct device *dev, spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, dfs); spi_context_cs_control(ctx, true); - transfer_next_chunk(dev); + sys_set_bits(SPI_CTRL(cfg->base), CTRL_TX_FIFO_RST_MSK); + sys_set_bits(SPI_CTRL(cfg->base), CTRL_RX_FIFO_RST_MSK); + if (!spi_context_rx_on(ctx)) { + chunk_len = spi_context_total_tx_len(ctx); + } else if (!spi_context_tx_on(ctx)) { + chunk_len = spi_context_total_rx_len(ctx); + } else { + size_t rx_len = spi_context_total_rx_len(ctx); + size_t tx_len = spi_context_total_tx_len(ctx); + + chunk_len = MIN(rx_len, tx_len); + } + + data->chunk_len = chunk_len; + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if ((data->dma_tx.dma_dev != NULL) && (data->dma_rx.dma_dev != NULL)) { + error = spi_transfer_dma(dev); + if (error != 0) { + return error; + } + } else { +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ + + error = spi_transfer(dev); + if (error != 0) { + return error; + } + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + } +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ error = spi_context_wait_for_completion(ctx); + spi_context_cs_control(ctx, false); } spi_context_release(ctx, error); @@ -267,9 +709,21 @@ int spi_atcspi200_init(const struct device *dev) spi_context_unlock_unconditionally(&data->ctx); +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if (!data->dma_tx.dma_dev) { + LOG_ERR("DMA device not found"); + return -ENODEV; + } + + if (!data->dma_rx.dma_dev) { + LOG_ERR("DMA device not found"); + return -ENODEV; + } +#endif + /* Get the TX/RX FIFO size of this device */ - data->tx_fifo_size = TX_FIFO_SIZE(dev); - data->rx_fifo_size = RX_FIFO_SIZE(dev); + data->tx_fifo_size = TX_FIFO_SIZE(cfg->base); + data->rx_fifo_size = RX_FIFO_SIZE(cfg->base); cfg->cfg_func(); @@ -283,7 +737,7 @@ int spi_atcspi200_init(const struct device *dev) return 0; } -static struct spi_driver_api spi_atcspi200_api = { +static const struct spi_driver_api spi_atcspi200_api = { .transceive = spi_atcspi200_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_atcspi200_transceive_async, @@ -294,20 +748,22 @@ static struct spi_driver_api spi_atcspi200_api = { static void spi_atcspi200_irq_handler(void *arg) { const struct device * const dev = (const struct device *) arg; + const struct spi_atcspi200_cfg * const cfg = dev->config; struct spi_atcspi200_data * const data = dev->data; struct spi_context *ctx = &data->ctx; uint32_t rx_data, cur_tx_fifo_num, cur_rx_fifo_num; uint32_t i, dfs, intr_status, spi_status; uint32_t tx_num = 0, tx_data = 0; + int error = 0; - intr_status = sys_read32(SPI_INTST(dev)); + intr_status = sys_read32(SPI_INTST(cfg->base)); dfs = SPI_WORD_SIZE_GET(ctx->config->operation) >> 3; if ((intr_status & INTST_TX_FIFO_INT_MSK) && !(intr_status & INTST_END_INT_MSK)) { - spi_status = sys_read32(SPI_STAT(dev)); - cur_tx_fifo_num = GET_TX_NUM(dev); + spi_status = sys_read32(SPI_STAT(cfg->base)); + cur_tx_fifo_num = GET_TX_NUM(cfg->base); tx_num = data->tx_fifo_size - cur_tx_fifo_num; @@ -317,7 +773,7 @@ static void spi_atcspi200_irq_handler(void *arg) /* Have already sent a chunk of data, so stop * sending data! */ - CLR_MASK(SPI_INTEN(dev), IEN_TX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_TX_FIFO_MSK); break; } @@ -335,26 +791,26 @@ static void spi_atcspi200_irq_handler(void *arg) } else if (spi_context_tx_on(ctx)) { tx_data = 0; } else { - CLR_MASK(SPI_INTEN(dev), IEN_TX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_TX_FIFO_MSK); break; } - sys_write32(tx_data, SPI_DATA(dev)); + sys_write32(tx_data, SPI_DATA(cfg->base)); spi_context_update_tx(ctx, dfs, 1); data->tx_cnt++; } - sys_write32(INTST_TX_FIFO_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_TX_FIFO_INT_MSK, SPI_INTST(cfg->base)); } if (intr_status & INTST_RX_FIFO_INT_MSK) { - cur_rx_fifo_num = GET_RX_NUM(dev); + cur_rx_fifo_num = GET_RX_NUM(cfg->base); for (i = cur_rx_fifo_num; i > 0; i--) { - rx_data = sys_read32(SPI_DATA(dev)); + rx_data = sys_read32(SPI_DATA(cfg->base)); if (spi_context_rx_buf_on(ctx)) { @@ -368,28 +824,108 @@ static void spi_atcspi200_irq_handler(void *arg) } } else if (!spi_context_rx_on(ctx)) { - CLR_MASK(SPI_INTEN(dev), IEN_RX_FIFO_MSK); + sys_clear_bits(SPI_INTEN(cfg->base), IEN_RX_FIFO_MSK); } spi_context_update_rx(ctx, dfs, 1); } - sys_write32(INTST_RX_FIFO_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_RX_FIFO_INT_MSK, SPI_INTST(cfg->base)); } if (intr_status & INTST_END_INT_MSK) { /* Clear end interrupt */ - sys_write32(INTST_END_INT_MSK, SPI_INTST(dev)); + sys_write32(INTST_END_INT_MSK, SPI_INTST(cfg->base)); /* Disable all SPI interrupts */ - sys_write32(0, SPI_INTEN(dev)); + sys_write32(0, SPI_INTEN(cfg->base)); + +#ifdef CONFIG_ANDES_SPI_DMA_MODE + if ((data->dma_tx.dma_dev != NULL) && data->dma_tx.dma_cfg.source_chaining_en) { + + spi_tx_dma_disable(dev); + dma_stop(data->dma_tx.dma_dev, data->dma_tx.channel); + data->dma_tx.block_idx = 0; + data->dma_tx.dma_blk_cfg.next_block = NULL; + } + + if ((data->dma_rx.dma_dev != NULL) && data->dma_rx.dma_cfg.source_chaining_en) { + + spi_rx_dma_disable(dev); + dma_stop(data->dma_rx.dma_dev, data->dma_rx.channel); + data->dma_rx.block_idx = 0; + data->dma_rx.dma_blk_cfg.next_block = NULL; + } +#endif /* CONFIG_ANDES_SPI_DMA_MODE */ + + data->busy = false; + + spi_context_complete(ctx, dev, error); - transfer_next_chunk(dev); } } +#if CONFIG_ANDES_SPI_DMA_MODE + +#define ANDES_DMA_CONFIG_DIRECTION(config) (FIELD_GET(GENMASK(1, 0), config)) +#define ANDES_DMA_CONFIG_PERIPHERAL_ADDR_INC(config) (FIELD_GET(BIT(2), config)) +#define ANDES_DMA_CONFIG_MEMORY_ADDR_INC(config) (FIELD_GET(BIT(3), config)) +#define ANDES_DMA_CONFIG_PERIPHERAL_DATA_SIZE(config) (1 << (FIELD_GET(GENMASK(6, 4), config))) +#define ANDES_DMA_CONFIG_MEMORY_DATA_SIZE(config) (1 << (FIELD_GET(GENMASK(9, 7), config))) +#define ANDES_DMA_CONFIG_PRIORITY(config) (FIELD_GET(BIT(10), config)) + +#define DMA_CHANNEL_CONFIG(id, dir) \ + DT_INST_DMAS_CELL_BY_NAME(id, dir, channel_config) + +#define SPI_DMA_CHANNEL_INIT(index, dir, dir_cap, src_dev, dest_dev) \ + .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(index, dir)), \ + .channel = \ + DT_INST_DMAS_CELL_BY_NAME(index, dir, channel), \ + .dma_cfg = { \ + .dma_slot = \ + DT_INST_DMAS_CELL_BY_NAME(index, dir, slot), \ + .channel_direction = ANDES_DMA_CONFIG_DIRECTION( \ + DMA_CHANNEL_CONFIG(index, dir)), \ + .complete_callback_en = 0, \ + .error_callback_en = 0, \ + .source_data_size = \ + ANDES_DMA_CONFIG_##src_dev##_DATA_SIZE( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .dest_data_size = \ + ANDES_DMA_CONFIG_##dest_dev##_DATA_SIZE( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .source_burst_length = 1, /* SINGLE transfer */ \ + .dest_burst_length = 1, /* SINGLE transfer */ \ + .channel_priority = ANDES_DMA_CONFIG_PRIORITY( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .source_chaining_en = DT_PROP(DT_INST_DMAS_CTLR_BY_NAME( \ + index, dir), chain_transfer), \ + .dest_chaining_en = DT_PROP(DT_INST_DMAS_CTLR_BY_NAME( \ + index, dir), chain_transfer), \ + }, \ + .src_addr_increment = \ + ANDES_DMA_CONFIG_##src_dev##_ADDR_INC( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ), \ + .dst_addr_increment = \ + ANDES_DMA_CONFIG_##dest_dev##_ADDR_INC( \ + DMA_CHANNEL_CONFIG(index, dir) \ + ) + +#define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) \ + .dma_##dir = { \ + COND_CODE_1(DT_INST_DMAS_HAS_NAME(id, dir), \ + (SPI_DMA_CHANNEL_INIT(id, dir, DIR, src, dest)), \ + (NULL)) \ + }, + +#else #define SPI_DMA_CHANNEL(id, dir, DIR, src, dest) -#define SPI_IF_NO_CMD(num) .is_cmdaddr_mode = 0, +#endif + #define SPI_BUSY_INIT .busy = false, #if (CONFIG_XIP) @@ -398,43 +934,40 @@ static void spi_atcspi200_irq_handler(void *arg) #define SPI_ROM_CFG_XIP(node_id) false #endif -#define SPI_INIT(n) \ - static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = { \ - SPI_CONTEXT_INIT_LOCK(spi_atcspi200_dev_data_##n, ctx), \ - SPI_CONTEXT_INIT_SYNC(spi_atcspi200_dev_data_##n, ctx), \ - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ - SPI_IF_NO_CMD(n) \ - SPI_BUSY_INIT \ - SPI_DMA_CHANNEL(n, rx, RX, PERIPHERAL, MEMORY) \ - SPI_DMA_CHANNEL(n, tx, TX, MEMORY, PERIPHERAL) \ - }; \ - static void spi_atcspi200_cfg_##n(void); \ - static const struct spi_atcspi200_cfg spi_atcspi200_dev_cfg_##n = { \ - .cfg_func = spi_atcspi200_cfg_##n, \ - .base = DT_INST_REG_ADDR(n), \ - .irq_num = DT_INST_IRQN(n), \ - .f_sys = DT_INST_PROP(n, clock_frequency), \ - .xip = SPI_ROM_CFG_XIP(DT_DRV_INST(n)), \ - }; \ - \ - DEVICE_DT_INST_DEFINE(n, \ - spi_atcspi200_init, \ - NULL, \ - &spi_atcspi200_dev_data_##n, \ - &spi_atcspi200_dev_cfg_##n, \ - POST_KERNEL, \ - CONFIG_SPI_INIT_PRIORITY, \ - &spi_atcspi200_api); \ - \ - static void spi_atcspi200_cfg_##n(void) \ - { \ - \ - IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - spi_atcspi200_irq_handler, \ - DEVICE_DT_INST_GET(n), \ - 0); \ - \ - } +#define SPI_INIT(n) \ + static struct spi_atcspi200_data spi_atcspi200_dev_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(spi_atcspi200_dev_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_atcspi200_dev_data_##n, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ + SPI_BUSY_INIT \ + SPI_DMA_CHANNEL(n, rx, RX, PERIPHERAL, MEMORY) \ + SPI_DMA_CHANNEL(n, tx, TX, MEMORY, PERIPHERAL) \ + }; \ + static void spi_atcspi200_cfg_##n(void); \ + static struct spi_atcspi200_cfg spi_atcspi200_dev_cfg_##n = { \ + .cfg_func = spi_atcspi200_cfg_##n, \ + .base = DT_INST_REG_ADDR(n), \ + .irq_num = DT_INST_IRQN(n), \ + .f_sys = DT_INST_PROP(n, clock_frequency), \ + .xip = SPI_ROM_CFG_XIP(DT_DRV_INST(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + spi_atcspi200_init, \ + NULL, \ + &spi_atcspi200_dev_data_##n, \ + &spi_atcspi200_dev_cfg_##n, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &spi_atcspi200_api); \ + \ + static void spi_atcspi200_cfg_##n(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + spi_atcspi200_irq_handler, \ + DEVICE_DT_INST_GET(n), \ + 0); \ + }; DT_INST_FOREACH_STATUS_OKAY(SPI_INIT) diff --git a/drivers/spi/spi_andes_atcspi200.h b/drivers/spi/spi_andes_atcspi200.h index f7b73ec6716..e498105f3e5 100644 --- a/drivers/spi/spi_andes_atcspi200.h +++ b/drivers/spi/spi_andes_atcspi200.h @@ -11,34 +11,31 @@ LOG_MODULE_REGISTER(spi_atcspi200); #include #include -#define REG_IDR 0x00 -#define REG_TFMAT 0x10 -#define REG_DIRIO 0x14 -#define REG_TCTRL 0x20 -#define REG_CMD 0x24 -#define REG_ADDR 0x28 -#define REG_DATA 0x2c -#define REG_CTRL 0x30 -#define REG_STAT 0x34 -#define REG_INTEN 0x38 -#define REG_INTST 0x3c -#define REG_TIMIN 0x40 -#define REG_MCTRL 0x50 -#define REG_SLVST 0x60 -#define REG_SDCNT 0x64 -#define REG_CONFIG 0x7c - -#define SPI_BASE (((const struct spi_atcspi200_cfg *)(dev)->config)->base) -#define SPI_TFMAT(dev) (SPI_BASE + REG_TFMAT) -#define SPI_TCTRL(dev) (SPI_BASE + REG_TCTRL) -#define SPI_CMD(dev) (SPI_BASE + REG_CMD) -#define SPI_DATA(dev) (SPI_BASE + REG_DATA) -#define SPI_CTRL(dev) (SPI_BASE + REG_CTRL) -#define SPI_STAT(dev) (SPI_BASE + REG_STAT) -#define SPI_INTEN(dev) (SPI_BASE + REG_INTEN) -#define SPI_INTST(dev) (SPI_BASE + REG_INTST) -#define SPI_TIMIN(dev) (SPI_BASE + REG_TIMIN) -#define SPI_CONFIG(dev) (SPI_BASE + REG_CONFIG) +#ifdef CONFIG_ANDES_SPI_DMA_MODE +#include +#endif + +#define REG_TFMAT 0x10 +#define REG_TCTRL 0x20 +#define REG_CMD 0x24 +#define REG_DATA 0x2c +#define REG_CTRL 0x30 +#define REG_STAT 0x34 +#define REG_INTEN 0x38 +#define REG_INTST 0x3c +#define REG_TIMIN 0x40 +#define REG_CONFIG 0x7c + +#define SPI_TFMAT(base) (base + REG_TFMAT) +#define SPI_TCTRL(base) (base + REG_TCTRL) +#define SPI_CMD(base) (base + REG_CMD) +#define SPI_DATA(base) (base + REG_DATA) +#define SPI_CTRL(base) (base + REG_CTRL) +#define SPI_STAT(base) (base + REG_STAT) +#define SPI_INTEN(base) (base + REG_INTEN) +#define SPI_INTST(base) (base + REG_INTST) +#define SPI_TIMIN(base) (base + REG_TIMIN) +#define SPI_CONFIG(base) (base + REG_CONFIG) /* Field mask of SPI transfer format register */ #define TFMAT_DATA_LEN_OFFSET (8) @@ -75,8 +72,8 @@ LOG_MODULE_REGISTER(spi_atcspi200); #define INTST_END_INT_MSK BIT(4) /* Field mask of SPI config register */ -#define CFG_RX_FIFO_SIZE_MSK GENMASK(1, 0) -#define CFG_TX_FIFO_SIZE_MSK GENMASK(5, 4) +#define CFG_RX_FIFO_SIZE_MSK GENMASK(3, 0) +#define CFG_TX_FIFO_SIZE_MSK GENMASK(7, 4) /* Field mask of SPI status register */ #define STAT_RX_NUM_MSK GENMASK(12, 8) @@ -90,30 +87,30 @@ LOG_MODULE_REGISTER(spi_atcspi200); #define CTRL_RX_FIFO_RST_MSK BIT(1) #define CTRL_TX_FIFO_RST_MSK BIT(2) +#define CTRL_RX_DMA_EN_MSK BIT(3) +#define CTRL_TX_DMA_EN_MSK BIT(4) #define CTRL_RX_THRES_MSK GENMASK(12, 8) #define CTRL_TX_THRES_MSK GENMASK(20, 16) /* Field mask of SPI status register */ #define TIMIN_SCLK_DIV_MSK GENMASK(7, 0) -#define SET_MASK(x, msk) sys_write32(sys_read32(x) | msk, x) -#define CLR_MASK(x, msk) sys_write32(sys_read32(x) & ~msk, x) - #define TX_FIFO_THRESHOLD (1) #define RX_FIFO_THRESHOLD (1) #define MAX_TRANSFER_CNT (512) - -#define TX_FIFO_SIZE_SETTING(dev) \ - (sys_read32(SPI_CONFIG(dev)) & CFG_TX_FIFO_SIZE_MSK) -#define TX_FIFO_SIZE(dev) \ - (2 << (TX_FIFO_SIZE_SETTING(dev) >> 4)) - -#define RX_FIFO_SIZE_SETTING(dev) \ - (sys_read32(SPI_CONFIG(dev)) & CFG_RX_FIFO_SIZE_MSK) -#define RX_FIFO_SIZE(dev) \ - (2 << (RX_FIFO_SIZE_SETTING(dev) >> 0)) - -#define TX_NUM_STAT(dev) (sys_read32(SPI_STAT(dev)) & STAT_TX_NUM_MSK) -#define RX_NUM_STAT(dev) (sys_read32(SPI_STAT(dev)) & STAT_RX_NUM_MSK) -#define GET_TX_NUM(dev) (TX_NUM_STAT(dev) >> 16) -#define GET_RX_NUM(dev) (RX_NUM_STAT(dev) >> 8) +#define MAX_CHAIN_SIZE (8) + +#define TX_FIFO_SIZE_SETTING(base) \ + (sys_read32(SPI_CONFIG(base)) & CFG_TX_FIFO_SIZE_MSK) +#define TX_FIFO_SIZE(base) \ + (2 << (TX_FIFO_SIZE_SETTING(base) >> 4)) + +#define RX_FIFO_SIZE_SETTING(base) \ + (sys_read32(SPI_CONFIG(base)) & CFG_RX_FIFO_SIZE_MSK) +#define RX_FIFO_SIZE(base) \ + (2 << (RX_FIFO_SIZE_SETTING(base) >> 0)) + +#define TX_NUM_STAT(base) (sys_read32(SPI_STAT(base)) & STAT_TX_NUM_MSK) +#define RX_NUM_STAT(base) (sys_read32(SPI_STAT(base)) & STAT_RX_NUM_MSK) +#define GET_TX_NUM(base) (TX_NUM_STAT(base) >> 16) +#define GET_RX_NUM(base) (RX_NUM_STAT(base) >> 8) diff --git a/drivers/spi/spi_b91.c b/drivers/spi/spi_b91.c index bdc580a521f..f3f1202df29 100644 --- a/drivers/spi/spi_b91.c +++ b/drivers/spi/spi_b91.c @@ -228,7 +228,7 @@ static void spi_b91_txrx(const struct device *dev, uint32_t len) BM_SET(reg_spi_fifo_state(cfg->peripheral_id), FLD_SPI_RXF_CLR); } - /* wait fot SPI is ready */ + /* wait for SPI is ready */ while (spi_is_busy(cfg->peripheral_id)) { }; @@ -452,7 +452,7 @@ static int spi_b91_release(const struct device *dev, } /* SPI driver APIs structure */ -static struct spi_driver_api spi_b91_api = { +static const struct spi_driver_api spi_b91_api = { .transceive = spi_b91_transceive, .release = spi_b91_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index cf6a2973934..cffd25abd9a 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -247,7 +247,7 @@ int spi_bitbang_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_bitbang_api = { +static const struct spi_driver_api spi_bitbang_api = { .transceive = spi_bitbang_transceive, .release = spi_bitbang_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index e5700863932..7126cac00a8 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2015 Intel Corporation. * Copyright (c) 2023 Synopsys, Inc. All rights reserved. + * Copyright (c) 2023 Meta Platforms * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,19 +14,6 @@ #include LOG_MODULE_REGISTER(spi_dw); -#if (CONFIG_SPI_LOG_LEVEL == 4) -#define DBG_COUNTER_INIT() \ - uint32_t __cnt = 0 -#define DBG_COUNTER_INC() \ - (__cnt++) -#define DBG_COUNTER_RESULT() \ - (__cnt) -#else -#define DBG_COUNTER_INIT() {; } -#define DBG_COUNTER_INC() {; } -#define DBG_COUNTER_RESULT() 0 -#endif - #include #include @@ -62,6 +50,7 @@ static void completed(const struct device *dev, int error) { const struct spi_dw_config *info = dev->config; struct spi_dw_data *spi = dev->data; + struct spi_context *ctx = &spi->ctx; if (error) { goto out; @@ -82,7 +71,13 @@ static void completed(const struct device *dev, int error) /* Disabling the controller */ clear_bit_ssienr(info); - spi_context_cs_control(&spi->ctx, false); + if (!spi_dw_is_slave(spi)) { + if (spi_cs_is_gpio(ctx->config)) { + spi_context_cs_control(ctx, false); + } else { + write_ser(info, 0); + } + } LOG_DBG("SPI transaction completed %s error", error ? "with" : "without"); @@ -97,8 +92,6 @@ static void push_data(const struct device *dev) uint32_t data = 0U; uint32_t f_tx; - DBG_COUNTER_INIT(); - if (spi_context_rx_on(&spi->ctx)) { f_tx = info->fifo_depth - read_txflr(info) - read_rxflr(info); @@ -120,12 +113,10 @@ static void push_data(const struct device *dev) data = UNALIGNED_GET((uint16_t *) (spi->ctx.tx_buf)); break; -#ifndef CONFIG_ARC case 4: data = UNALIGNED_GET((uint32_t *) (spi->ctx.tx_buf)); break; -#endif } } else if (spi_context_rx_on(&spi->ctx)) { /* No need to push more than necessary */ @@ -147,16 +138,12 @@ static void push_data(const struct device *dev) spi->fifo_diff++; f_tx--; - - DBG_COUNTER_INC(); } if (!spi_context_tx_on(&spi->ctx)) { /* prevents any further interrupts demanding TX fifo fill */ write_txftlr(info, 0); } - - LOG_DBG("Pushed: %d", DBG_COUNTER_RESULT()); } static void pull_data(const struct device *dev) @@ -164,13 +151,9 @@ static void pull_data(const struct device *dev) const struct spi_dw_config *info = dev->config; struct spi_dw_data *spi = dev->data; - DBG_COUNTER_INIT(); - while (read_rxflr(info)) { uint32_t data = read_dr(info); - DBG_COUNTER_INC(); - if (spi_context_rx_buf_on(&spi->ctx)) { switch (spi->dfs) { case 1: @@ -179,11 +162,9 @@ static void pull_data(const struct device *dev) case 2: UNALIGNED_PUT(data, (uint16_t *)spi->ctx.rx_buf); break; -#ifndef CONFIG_ARC case 4: UNALIGNED_PUT(data, (uint32_t *)spi->ctx.rx_buf); break; -#endif } } @@ -196,8 +177,6 @@ static void pull_data(const struct device *dev) } else if (read_rxftlr(info) >= spi->ctx.rx_len) { write_rxftlr(info, spi->ctx.rx_len - 1); } - - LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT()); } static int spi_dw_configure(const struct spi_dw_config *info, @@ -220,12 +199,12 @@ static int spi_dw_configure(const struct spi_dw_config *info, /* Verify if requested op mode is relevant to this controller */ if (config->operation & SPI_OP_MODE_SLAVE) { - if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_SLAVE)) { + if (!(info->serial_target)) { LOG_ERR("Slave mode not supported"); return -ENOTSUP; } } else { - if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_MASTER)) { + if (info->serial_target) { LOG_ERR("Master mode not supported"); return -ENOTSUP; } @@ -239,8 +218,18 @@ static int spi_dw_configure(const struct spi_dw_config *info, return -EINVAL; } + if (info->max_xfer_size < SPI_WORD_SIZE_GET(config->operation)) { + LOG_ERR("Max xfer size is %u, word size of %u not allowed", + info->max_xfer_size, SPI_WORD_SIZE_GET(config->operation)); + return -ENOTSUP; + } + /* Word size */ - ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(config->operation)); + if (info->max_xfer_size == 32) { + ctrlr0 |= DW_SPI_CTRLR0_DFS_32(SPI_WORD_SIZE_GET(config->operation)); + } else { + ctrlr0 |= DW_SPI_CTRLR0_DFS_16(SPI_WORD_SIZE_GET(config->operation)); + } /* Determine how many bytes are required per-frame */ spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation)); @@ -268,7 +257,6 @@ static int spi_dw_configure(const struct spi_dw_config *info, /* Baud rate and Slave select, for master only */ write_baudr(info, SPI_DW_CLK_DIVIDER(info->clock_frequency, config->frequency)); - write_ser(info, 1 << config->slave); } if (spi_dw_is_slave(spi)) { @@ -439,12 +427,26 @@ static int transceive(const struct device *dev, DW_SPI_IMR_UNMASK; write_imr(info, reg_data); - spi_context_cs_control(&spi->ctx, true); + if (!spi_dw_is_slave(spi)) { + /* if cs is not defined as gpio, use hw cs */ + if (spi_cs_is_gpio(config)) { + spi_context_cs_control(&spi->ctx, true); + } else { + write_ser(info, BIT(config->slave)); + } + } LOG_DBG("Enabling controller"); set_bit_ssienr(info); ret = spi_context_wait_for_completion(&spi->ctx); + +#ifdef CONFIG_SPI_SLAVE + if (spi_context_is_slave(&spi->ctx) && !ret) { + ret = spi->ctx.recv_frames; + } +#endif /* CONFIG_SPI_SLAVE */ + out: spi_context_release(&spi->ctx, ret); @@ -558,339 +560,70 @@ int spi_dw_init(const struct device *dev) return 0; } - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) -void spi_config_0_irq(void); - -struct spi_dw_data spi_dw_data_port_0 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_0, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_0, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(0), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(0, clocks), clock_frequency) -#define INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(0, clocks, clock_frequency) -#else -#define INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(0, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(0); -#endif -const struct spi_dw_config spi_dw_config_0 = { - .regs = DT_INST_REG_ADDR(0), - .clock_frequency = INST_0_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_0_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(0, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), -#endif -#if DT_INST_PROP(0, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(0, spi_dw_init, NULL, - &spi_dw_data_port_0, &spi_dw_config_0, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_0_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(0)) == 1 -#if DT_INST_IRQ_HAS_NAME(0, flags) -#define INST_0_IRQ_FLAGS DT_INST_IRQ_BY_NAME(0, flags, irq) -#else -#define INST_0_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(0), - DT_INST_IRQ(0, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - INST_0_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(0)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, rx_avail, irq), - DT_INST_IRQ_BY_NAME(0, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, tx_req, irq), - DT_INST_IRQ_BY_NAME(0, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, err_int, irq), - DT_INST_IRQ_BY_NAME(0, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(0), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(0, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(0, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(0, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) */ - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(1), okay) -void spi_config_1_irq(void); - -struct spi_dw_data spi_dw_data_port_1 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_1, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_1, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(1), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(1, clocks), clock_frequency) -#define INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(1, clocks, clock_frequency) -#else -#define INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(1, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(1); -#endif -static const struct spi_dw_config spi_dw_config_1 = { - .regs = DT_INST_REG_ADDR(1), - .clock_frequency = INST_1_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_1_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(1, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(1), -#endif -#if DT_INST_PROP(1, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(1, spi_dw_init, NULL, - &spi_dw_data_port_1, &spi_dw_config_1, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_1_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(1)) == 1 -#if DT_INST_IRQ_HAS_NAME(1, flags) -#define INST_1_IRQ_FLAGS DT_INST_IRQ_BY_NAME(1, flags, irq) -#else -#define INST_1_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(1), - DT_INST_IRQ(1, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - INST_1_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(1)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, rx_avail, irq), - DT_INST_IRQ_BY_NAME(1, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, tx_req, irq), - DT_INST_IRQ_BY_NAME(1, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(1, err_int, irq), - DT_INST_IRQ_BY_NAME(1, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(1), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(1, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(1, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(1, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(1), okay) */ - -#if DT_NODE_HAS_STATUS(DT_DRV_INST(2), okay) -void spi_config_2_irq(void); - -struct spi_dw_data spi_dw_data_port_2 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_2, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_2, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(2), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(2, clocks), clock_frequency) -#define INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(2, clocks, clock_frequency) -#else -#define INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(2, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(2); -#endif -static const struct spi_dw_config spi_dw_config_2 = { - .regs = DT_INST_REG_ADDR(2), - .clock_frequency = INST_2_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_2_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(2, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(2), -#endif -#if DT_INST_PROP(2, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(2, spi_dw_init, NULL, - &spi_dw_data_port_2, &spi_dw_config_2, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_2_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(2)) == 1 -#if DT_INST_IRQ_HAS_NAME(2, flags) -#define INST_2_IRQ_FLAGS DT_INST_IRQ_BY_NAME(2, flags, irq) -#else -#define INST_2_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(2), - DT_INST_IRQ(2, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - INST_2_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(2)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, rx_avail, irq), - DT_INST_IRQ_BY_NAME(2, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, tx_req, irq), - DT_INST_IRQ_BY_NAME(2, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(2, err_int, irq), - DT_INST_IRQ_BY_NAME(2, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(2), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(2, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(2, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(2, err_int, irq)); - -#endif +#define SPI_DW_IRQ_HANDLER(inst) \ +void spi_dw_irq_config_##inst(void) \ +{ \ +COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \ + (IRQ_CONNECT(DT_INST_IRQN(inst), \ + DT_INST_IRQ(inst, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQN(inst));), \ + (IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, rx_avail, irq), \ + DT_INST_IRQ_BY_NAME(inst, rx_avail, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, tx_req, irq), \ + DT_INST_IRQ_BY_NAME(inst, tx_req, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, err_int, irq), \ + DT_INST_IRQ_BY_NAME(inst, err_int, priority), \ + spi_dw_isr, DEVICE_DT_INST_GET(inst), \ + 0); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, rx_avail, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, tx_req, irq)); \ + irq_enable(DT_INST_IRQ_BY_NAME(inst, err_int, irq));)) \ } -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(2), okay) */ -#if DT_NODE_HAS_STATUS(DT_DRV_INST(3), okay) -void spi_config_3_irq(void); - -struct spi_dw_data spi_dw_data_port_3 = { - SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_3, ctx), - SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_3, ctx), - SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(3), ctx) -}; - -#if DT_NODE_HAS_PROP(DT_INST_PHANDLE(3, clocks), clock_frequency) -#define INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP_BY_PHANDLE(3, clocks, clock_frequency) -#else -#define INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ \ - DT_INST_PROP(3, clock_frequency) -#endif - -#ifdef CONFIG_PINCTRL -PINCTRL_DT_INST_DEFINE(3); -#endif -static const struct spi_dw_config spi_dw_config_3 = { - .regs = DT_INST_REG_ADDR(3), - .clock_frequency = INST_3_SNPS_DESIGNWARE_SPI_CLOCK_FREQ, - .config_func = spi_config_3_irq, - .op_modes = SPI_CTX_RUNTIME_OP_MODE_MASTER, - .fifo_depth = DT_INST_PROP(3, fifo_depth), -#ifdef CONFIG_PINCTRL - .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(3), -#endif -#if DT_INST_PROP(3, aux_reg) - .read_func = aux_reg_read, - .write_func = aux_reg_write, - .set_bit_func = aux_reg_set_bit, - .clear_bit_func = aux_reg_clear_bit, - .test_bit_func = aux_reg_test_bit -#else - .read_func = reg_read, - .write_func = reg_write, - .set_bit_func = reg_set_bit, - .clear_bit_func = reg_clear_bit, - .test_bit_func = reg_test_bit -#endif -}; - -DEVICE_DT_INST_DEFINE(3, spi_dw_init, NULL, - &spi_dw_data_port_3, &spi_dw_config_3, - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, - &dw_spi_api); - -void spi_config_3_irq(void) -{ -#if DT_NUM_IRQS(DT_DRV_INST(3)) == 1 -#if DT_INST_IRQ_HAS_NAME(3, flags) -#define INST_3_IRQ_FLAGS DT_INST_IRQ_BY_NAME(3, flags, irq) -#else -#define INST_3_IRQ_FLAGS 0 -#endif - IRQ_CONNECT(DT_INST_IRQN(3), - DT_INST_IRQ(3, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - INST_3_IRQ_FLAGS); - irq_enable(DT_INST_IRQN(3)); -#else - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, rx_avail, irq), - DT_INST_IRQ_BY_NAME(3, rx_avail, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, tx_req, irq), - DT_INST_IRQ_BY_NAME(3, tx_req, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - IRQ_CONNECT(DT_INST_IRQ_BY_NAME(3, err_int, irq), - DT_INST_IRQ_BY_NAME(3, err_int, priority), - spi_dw_isr, DEVICE_DT_INST_GET(3), - 0); - - irq_enable(DT_INST_IRQ_BY_NAME(3, rx_avail, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(3, tx_req, irq)); - irq_enable(DT_INST_IRQ_BY_NAME(3, err_int, irq)); - -#endif -} -#endif /* DT_NODE_HAS_STATUS(DT_DRV_INST(3), okay) */ +#define SPI_DW_INIT(inst) \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(inst);)) \ + SPI_DW_IRQ_HANDLER(inst); \ + static struct spi_dw_data spi_dw_data_##inst = { \ + SPI_CONTEXT_INIT_LOCK(spi_dw_data_##inst, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_dw_data_##inst, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), ctx) \ + }; \ + static const struct spi_dw_config spi_dw_config_##inst = { \ + .regs = DT_INST_REG_ADDR(inst), \ + .clock_frequency = COND_CODE_1( \ + DT_NODE_HAS_PROP(DT_INST_PHANDLE(inst, clocks), clock_frequency), \ + (DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)), \ + (DT_INST_PROP(inst, clock_frequency))), \ + .config_func = spi_dw_irq_config_##inst, \ + .serial_target = DT_INST_PROP(inst, serial_target), \ + .fifo_depth = DT_INST_PROP(inst, fifo_depth), \ + .max_xfer_size = DT_INST_PROP(inst, max_xfer_size), \ + IF_ENABLED(CONFIG_PINCTRL, (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),)) \ + COND_CODE_1(DT_INST_PROP(inst, aux_reg), \ + (.read_func = aux_reg_read, \ + .write_func = aux_reg_write, \ + .set_bit_func = aux_reg_set_bit, \ + .clear_bit_func = aux_reg_clear_bit, \ + .test_bit_func = aux_reg_test_bit,), \ + (.read_func = reg_read, \ + .write_func = reg_write, \ + .set_bit_func = reg_set_bit, \ + .clear_bit_func = reg_clear_bit, \ + .test_bit_func = reg_test_bit,)) \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + spi_dw_init, \ + NULL, \ + &spi_dw_data_##inst, \ + &spi_dw_config_##inst, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &dw_spi_api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_DW_INIT) diff --git a/drivers/spi/spi_dw.h b/drivers/spi/spi_dw.h index dd518c9b853..54eeaa1ece1 100644 --- a/drivers/spi/spi_dw.h +++ b/drivers/spi/spi_dw.h @@ -31,8 +31,9 @@ struct spi_dw_config { uint32_t regs; uint32_t clock_frequency; spi_dw_config_t config_func; - uint8_t op_modes; + bool serial_target; uint8_t fifo_depth; + uint8_t max_xfer_size; #ifdef CONFIG_PINCTRL const struct pinctrl_dev_config *pcfg; #endif @@ -47,7 +48,6 @@ struct spi_dw_data { struct spi_context ctx; uint8_t dfs; /* dfs in bytes: 1,2 or 4 */ uint8_t fifo_diff; /* cannot be bigger than FIFO depth */ - uint16_t _unused; }; /* Register operation functions */ @@ -194,12 +194,6 @@ static int reg_test_bit(uint8_t bit, uint32_t addr, uint32_t off) #define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1) #define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16) -#if defined(CONFIG_ARC) -#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_16 -#else -#define DW_SPI_CTRLR0_DFS DW_SPI_CTRLR0_DFS_32 -#endif - /* 0x38 represents the bits 8, 16 and 32. Knowing that 24 is bits 8 and 16 * These are the bits were when you divide by 8, you keep the result as it is. * For all the other ones, 4 to 7, 9 to 15, etc... you need a +1, diff --git a/drivers/spi/spi_emul.c b/drivers/spi/spi_emul.c index 9c8f3a6cd70..d8e89b1ae7f 100644 --- a/drivers/spi/spi_emul.c +++ b/drivers/spi/spi_emul.c @@ -68,6 +68,7 @@ static int spi_emul_io(const struct device *dev, const struct spi_config *config { struct spi_emul *emul; const struct spi_emul_api *api; + int ret; emul = spi_emul_find(dev, config->slave); if (!emul) { @@ -78,9 +79,28 @@ static int spi_emul_io(const struct device *dev, const struct spi_config *config __ASSERT_NO_MSG(emul->api); __ASSERT_NO_MSG(emul->api->io); + if (emul->mock_api != NULL && emul->mock_api->io != NULL) { + ret = emul->mock_api->io(emul->target, config, tx_bufs, rx_bufs); + if (ret != -ENOSYS) { + return ret; + } + } + return api->io(emul->target, config, tx_bufs, rx_bufs); } +/** + * @brief This is a no-op stub of the SPI API's `release` method to protect drivers under test + * from hitting a segmentation fault when using SPI_LOCK_ON plus spi_release() + */ +static int spi_emul_release(const struct device *dev, const struct spi_config *config) +{ + ARG_UNUSED(dev); + ARG_UNUSED(config); + + return 0; +} + /** * Set up a new emulator and add it to the list * @@ -109,8 +129,9 @@ int spi_emul_register(const struct device *dev, struct spi_emul *emul) /* Device instantiation */ -static struct spi_driver_api spi_emul_api = { +static const struct spi_driver_api spi_emul_api = { .transceive = spi_emul_io, + .release = spi_emul_release, }; #define EMUL_LINK_AND_COMMA(node_id) \ diff --git a/drivers/spi/spi_esp32_spim.c b/drivers/spi/spi_esp32_spim.c index a6ace4f263f..0bfed3fc8be 100644 --- a/drivers/spi/spi_esp32_spim.c +++ b/drivers/spi/spi_esp32_spim.c @@ -71,7 +71,8 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) size_t max_buf_sz = cfg->dma_enabled ? SPI_DMA_MAX_BUFFER_SIZE : SOC_SPI_MAXIMUM_BUFFER_SIZE; size_t transfer_len_bytes = MIN(chunk_len_bytes, max_buf_sz); - size_t bit_len = transfer_len_bytes << 3; + size_t transfer_len_frames = transfer_len_bytes / data->dfs; + size_t bit_len = transfer_len_bytes << 3; uint8_t *rx_temp = NULL; uint8_t *tx_temp = NULL; uint8_t dma_len_tx = MIN(ctx->tx_len * data->dfs, SPI_DMA_MAX_BUFFER_SIZE); @@ -90,7 +91,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(tx_temp, &ctx->tx_buf[0], dma_len_tx); } if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) || - ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_tx % 4 != 0))) { + ((int)&ctx->rx_buf[0] % 4 != 0) || (dma_len_rx % 4 != 0))) { /* The rx buffer need to be length of * multiples of 32 bits to avoid heap * corruption. @@ -112,9 +113,11 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) hal_trans->tx_bitlen = bit_len; hal_trans->rx_bitlen = bit_len; - /* keep cs line active ultil last transmission */ + /* keep cs line active until last transmission */ hal_trans->cs_keep_active = - (!ctx->num_cs_gpios && (ctx->rx_count > 1 || ctx->tx_count > 1)); + (!ctx->num_cs_gpios && + (ctx->rx_count > 1 || ctx->tx_count > 1 || ctx->rx_len > transfer_len_frames || + ctx->tx_len > transfer_len_frames)); /* configure SPI */ spi_hal_setup_trans(hal, hal_dev, hal_trans); @@ -122,7 +125,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) /* send data */ spi_hal_user_start(hal); - spi_context_update_tx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_tx(&data->ctx, data->dfs, transfer_len_frames); while (!spi_hal_usr_is_done(hal)) { /* nop */ @@ -135,7 +138,7 @@ static int IRAM_ATTR spi_esp32_transfer(const struct device *dev) memcpy(&ctx->rx_buf[0], rx_temp, transfer_len_bytes); } - spi_context_update_rx(&data->ctx, data->dfs, transfer_len_bytes/data->dfs); + spi_context_update_rx(&data->ctx, data->dfs, transfer_len_frames); k_free(tx_temp); k_free(rx_temp); diff --git a/drivers/spi/spi_gd32.c b/drivers/spi/spi_gd32.c index 7f9ecaf90fb..c5c37a82f21 100644 --- a/drivers/spi/spi_gd32.c +++ b/drivers/spi/spi_gd32.c @@ -567,7 +567,7 @@ static int spi_gd32_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_gd32_driver_api = { +static const struct spi_driver_api spi_gd32_driver_api = { .transceive = spi_gd32_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_gd32_transceive_async, diff --git a/drivers/spi/spi_gecko.c b/drivers/spi/spi_gecko.c index c223986d8d4..d07485793b0 100644 --- a/drivers/spi/spi_gecko.c +++ b/drivers/spi/spi_gecko.c @@ -357,7 +357,7 @@ static int spi_gecko_release(const struct device *dev, } /* Device Instantiation */ -static struct spi_driver_api spi_gecko_api = { +static const struct spi_driver_api spi_gecko_api = { .transceive = spi_gecko_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_gecko_transceive_async, diff --git a/drivers/spi/spi_grlib_spimctrl.c b/drivers/spi/spi_grlib_spimctrl.c new file mode 100644 index 00000000000..788ffa888fd --- /dev/null +++ b/drivers/spi/spi_grlib_spimctrl.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2023 Frontgrade Gaisler AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT gaisler_spimctrl + +#include + +#include +LOG_MODULE_REGISTER(spi_spimctrl); +#include "spi_context.h" + + +struct spimctrl_regs { + uint32_t conf; + uint32_t ctrl; + uint32_t stat; + uint32_t rx; + uint32_t tx; +}; + +#define CONF_READCMD 0x0000007f +#define CTRL_RST 0x00000010 +#define CTRL_CSN 0x00000008 +#define CTRL_EAS 0x00000004 +#define CTRL_IEN 0x00000002 +#define CTRL_USRC 0x00000001 +#define STAT_INIT 0x00000004 +#define STAT_BUSY 0x00000002 +#define STAT_DONE 0x00000001 + +#define SPI_DATA(dev) ((struct data *) ((dev)->data)) + +struct cfg { + volatile struct spimctrl_regs *regs; + int interrupt; +}; + +struct data { + struct spi_context ctx; +}; + +static int spi_config(struct spi_context *ctx, const struct spi_config *config) +{ + if (config->slave != 0) { + LOG_ERR("More slaves than supported"); + return -ENOTSUP; + } + + if (SPI_WORD_SIZE_GET(config->operation) != 8) { + LOG_ERR("Word size must be 8"); + return -ENOTSUP; + } + + if (config->operation & SPI_CS_ACTIVE_HIGH) { + LOG_ERR("CS active high not supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_LOCK_ON) { + LOG_ERR("Lock On not supported"); + return -ENOTSUP; + } + + if ((config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only supports single mode"); + return -ENOTSUP; + } + + if (config->operation & SPI_TRANSFER_LSB) { + LOG_ERR("LSB first not supported"); + return -ENOTSUP; + } + + if (config->operation & (SPI_MODE_CPOL | SPI_MODE_CPHA)) { + LOG_ERR("Only supports CPOL=CPHA=0"); + return -ENOTSUP; + } + + if (config->operation & SPI_OP_MODE_SLAVE) { + LOG_ERR("Slave mode not supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback not supported"); + return -ENOTSUP; + } + + ctx->config = config; + + return 0; +} + +static int transceive(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + struct spi_context *ctx = &SPI_DATA(dev)->ctx; + uint8_t txval; + int rc; + + spi_context_lock(ctx, false, NULL, NULL, config); + + rc = spi_config(ctx, config); + if (rc) { + LOG_ERR("%s: config", __func__); + spi_context_release(ctx, rc); + return rc; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); + + regs->ctrl |= (CTRL_USRC | CTRL_IEN); + regs->ctrl &= ~CTRL_CSN; + + if (spi_context_tx_buf_on(ctx)) { + txval = *ctx->tx_buf; + spi_context_update_tx(ctx, 1, 1); + } else { + txval = 0; + } + /* This will eventually trig the interrupt */ + regs->tx = txval; + + rc = spi_context_wait_for_completion(ctx); + + regs->ctrl |= CTRL_CSN; + regs->ctrl &= ~CTRL_USRC; + spi_context_release(ctx, rc); + + return 0; +} + +#ifdef CONFIG_SPI_ASYNC +static int transceive_async(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + struct k_poll_signal *async) +{ + return -ENOTSUP; +} +#endif /* CONFIG_SPI_ASYNC */ + +static int release(const struct device *dev, const struct spi_config *config) +{ + spi_context_unlock_unconditionally(&SPI_DATA(dev)->ctx); + return 0; +} + +static void spim_isr(struct device *dev) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + struct spi_context *ctx = &SPI_DATA(dev)->ctx; + uint8_t rx_byte; + uint8_t val; + + if ((regs->stat & STAT_DONE) == 0) { + return; + } + + regs->stat = STAT_DONE; + + /* Always read register and maybe write mem. */ + rx_byte = regs->rx; + if (spi_context_rx_on(ctx)) { + *ctx->rx_buf = rx_byte; + spi_context_update_rx(ctx, 1, 1); + } + + if (spi_context_tx_buf_on(ctx) == false && spi_context_rx_buf_on(ctx) == false) { + regs->ctrl &= ~CTRL_IEN; + spi_context_complete(ctx, dev, 0); + return; + } + + val = 0; + if (spi_context_tx_buf_on(ctx)) { + val = *ctx->tx_buf; + spi_context_update_tx(ctx, 1, 1); + } + regs->tx = val; +} + +static int init(const struct device *dev) +{ + const struct cfg *const cfg = dev->config; + volatile struct spimctrl_regs *const regs = cfg->regs; + + regs->ctrl = CTRL_CSN; + while (regs->stat & STAT_BUSY) { + ; + } + regs->stat = STAT_DONE; + + irq_connect_dynamic( + cfg->interrupt, + 0, + (void (*)(const void *)) spim_isr, + dev, + 0 + ); + irq_enable(cfg->interrupt); + + spi_context_unlock_unconditionally(&SPI_DATA(dev)->ctx); + + return 0; +} + +static struct spi_driver_api api = { + .transceive = transceive, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = transceive_async, +#endif /* CONFIG_SPI_ASYNC */ + .release = release, +}; + +#define SPI_INIT(n) \ + static const struct cfg cfg_##n = { \ + .regs = (struct spimctrl_regs *) \ + DT_INST_REG_ADDR(n), \ + .interrupt = DT_INST_IRQN(n), \ + }; \ + static struct data data_##n = { \ + SPI_CONTEXT_INIT_LOCK(data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(data_##n, ctx), \ + }; \ + DEVICE_DT_INST_DEFINE(n, \ + init, \ + NULL, \ + &data_##n, \ + &cfg_##n, \ + POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_INIT) diff --git a/drivers/spi/spi_ifx_cat1.c b/drivers/spi/spi_ifx_cat1.c index ceafe8e6635..dd5295c3960 100644 --- a/drivers/spi/spi_ifx_cat1.c +++ b/drivers/spi/spi_ifx_cat1.c @@ -333,24 +333,11 @@ static int ifx_cat1_spi_init(const struct device *dev) .rxDataWidth = 8, /* overwrite by cfg */ \ .txDataWidth = 8, /* overwrite by cfg */ \ .enableMsbFirst = true, /* overwrite by cfg */ \ - .subMode = DT_INST_PROP_OR(n, sub_mode, CY_SCB_SPI_MOTOROLA), \ - .oversample = \ - DT_INST_PROP_OR(n, oversample, IFX_CAT1_SPI_DEFAULT_OVERSAMPLE), \ - .enableFreeRunSclk = DT_INST_PROP_OR(n, enable_free_run_sclk, false), \ - .enableInputFilter = DT_INST_PROP_OR(n, enable_input_filter, false), \ - .enableMisoLateSample = \ - DT_INST_PROP_OR(n, enable_miso_late_sample, true), \ - .enableTransferSeperation = \ - DT_INST_PROP_OR(n, enable_transfer_seperation, false), \ - .enableWakeFromSleep = DT_INST_PROP_OR(n, enableWakeFromSleep, false), \ - .ssPolarity = DT_INST_PROP_OR(n, ss_polarity, CY_SCB_SPI_ACTIVE_LOW), \ - .rxFifoTriggerLevel = DT_INST_PROP_OR(n, rx_fifo_trigger_level, 0), \ - .rxFifoIntEnableMask = DT_INST_PROP_OR(n, rx_fifo_int_enable_mask, 0), \ - .txFifoTriggerLevel = DT_INST_PROP_OR(n, tx_fifo_trigger_level, 0), \ - .txFifoIntEnableMask = DT_INST_PROP_OR(n, tx_fifo_int_enable_mask, 0), \ - .masterSlaveIntEnableMask = \ - DT_INST_PROP_OR(n, master_slave_int_enable_mask, 0)}, \ - \ + .subMode = CY_SCB_SPI_MOTOROLA, \ + .oversample = IFX_CAT1_SPI_DEFAULT_OVERSAMPLE, \ + .enableMisoLateSample = true, \ + .ssPolarity = CY_SCB_SPI_ACTIVE_LOW, \ + }, \ .irq_priority = DT_INST_IRQ(n, priority), \ }; \ DEVICE_DT_INST_DEFINE(n, &ifx_cat1_spi_init, NULL, &spi_cat1_data_##n, \ diff --git a/drivers/spi/spi_litespi.c b/drivers/spi/spi_litespi.c index 974f94af5ee..dff26a6fc31 100644 --- a/drivers/spi/spi_litespi.c +++ b/drivers/spi/spi_litespi.c @@ -160,7 +160,7 @@ static int spi_litespi_release(const struct device *dev, } /* Device Instantiation */ -static struct spi_driver_api spi_litespi_api = { +static const struct spi_driver_api spi_litespi_api = { .transceive = spi_litespi_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_litespi_transceive_async, diff --git a/drivers/spi/spi_ll_stm32.c b/drivers/spi/spi_ll_stm32.c index 0241dbde254..7f444f664ba 100644 --- a/drivers/spi/spi_ll_stm32.c +++ b/drivers/spi/spi_ll_stm32.c @@ -272,6 +272,48 @@ static int spi_dma_move_buffers(const struct device *dev, size_t len) /* Value to shift out when no application data needs transmitting. */ #define SPI_STM32_TX_NOP 0x00 +static void spi_stm32_send_next_frame(SPI_TypeDef *spi, + struct spi_stm32_data *data) +{ + const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); + uint32_t tx_frame = SPI_STM32_TX_NOP; + + if (frame_size == 8) { + if (spi_context_tx_buf_on(&data->ctx)) { + tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); + } + LL_SPI_TransmitData8(spi, tx_frame); + spi_context_update_tx(&data->ctx, 1, 1); + } else { + if (spi_context_tx_buf_on(&data->ctx)) { + tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); + } + LL_SPI_TransmitData16(spi, tx_frame); + spi_context_update_tx(&data->ctx, 2, 1); + } +} + +static void spi_stm32_read_next_frame(SPI_TypeDef *spi, + struct spi_stm32_data *data) +{ + const uint8_t frame_size = SPI_WORD_SIZE_GET(data->ctx.config->operation); + uint32_t rx_frame = 0; + + if (frame_size == 8) { + rx_frame = LL_SPI_ReceiveData8(spi); + if (spi_context_rx_buf_on(&data->ctx)) { + UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); + } + spi_context_update_rx(&data->ctx, 1, 1); + } else { + rx_frame = LL_SPI_ReceiveData16(spi); + if (spi_context_rx_buf_on(&data->ctx)) { + UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); + } + spi_context_update_rx(&data->ctx, 2, 1); + } +} + static bool spi_stm32_transfer_ongoing(struct spi_stm32_data *data) { return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx); @@ -296,69 +338,42 @@ static int spi_stm32_get_err(SPI_TypeDef *spi) return 0; } -/* Shift a SPI frame as master. */ -static void spi_stm32_shift_m(SPI_TypeDef *spi, struct spi_stm32_data *data) +static void spi_stm32_shift_fifo(SPI_TypeDef *spi, struct spi_stm32_data *data) { - uint16_t tx_frame = SPI_STM32_TX_NOP; - uint16_t rx_frame; - - while (!ll_func_tx_is_empty(spi)) { - /* NOP */ + if (ll_func_rx_is_not_empty(spi)) { + spi_stm32_read_next_frame(spi, data); } -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) - /* With the STM32MP1, STM32U5 and the STM32H7, - * if the device is the SPI master, - * we need to enable the start of the transfer with - * LL_SPI_StartMasterTransfer(spi) - */ - if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) { - LL_SPI_StartMasterTransfer(spi); - while (!LL_SPI_IsActiveMasterTransfer(spi)) { - /* NOP */ - } + if (ll_func_tx_is_not_full(spi)) { + spi_stm32_send_next_frame(spi, data); } -#endif +} - if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { - if (spi_context_tx_buf_on(&data->ctx)) { - tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); - } - LL_SPI_TransmitData8(spi, tx_frame); - /* The update is ignored if TX is off. */ - spi_context_update_tx(&data->ctx, 1, 1); +/* Shift a SPI frame as master. */ +static void spi_stm32_shift_m(const struct spi_stm32_config *cfg, + struct spi_stm32_data *data) +{ + if (cfg->fifo_enabled) { + spi_stm32_shift_fifo(cfg->spi, data); } else { - if (spi_context_tx_buf_on(&data->ctx)) { - tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); + while (!ll_func_tx_is_not_full(cfg->spi)) { + /* NOP */ } - LL_SPI_TransmitData16(spi, tx_frame); - /* The update is ignored if TX is off. */ - spi_context_update_tx(&data->ctx, 2, 1); - } - while (!ll_func_rx_is_not_empty(spi)) { - /* NOP */ - } + spi_stm32_send_next_frame(cfg->spi, data); - if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { - rx_frame = LL_SPI_ReceiveData8(spi); - if (spi_context_rx_buf_on(&data->ctx)) { - UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); - } - spi_context_update_rx(&data->ctx, 1, 1); - } else { - rx_frame = LL_SPI_ReceiveData16(spi); - if (spi_context_rx_buf_on(&data->ctx)) { - UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); + while (!ll_func_rx_is_not_empty(cfg->spi)) { + /* NOP */ } - spi_context_update_rx(&data->ctx, 2, 1); + + spi_stm32_read_next_frame(cfg->spi, data); } } /* Shift a SPI frame as slave. */ static void spi_stm32_shift_s(SPI_TypeDef *spi, struct spi_stm32_data *data) { - if (ll_func_tx_is_empty(spi) && spi_context_tx_on(&data->ctx)) { + if (ll_func_tx_is_not_full(spi) && spi_context_tx_on(&data->ctx)) { uint16_t tx_frame; if (SPI_WORD_SIZE_GET(data->ctx.config->operation) == 8) { @@ -396,17 +411,18 @@ static void spi_stm32_shift_s(SPI_TypeDef *spi, struct spi_stm32_data *data) * * TODO: support 16-bit data frames. */ -static int spi_stm32_shift_frames(SPI_TypeDef *spi, struct spi_stm32_data *data) +static int spi_stm32_shift_frames(const struct spi_stm32_config *cfg, + struct spi_stm32_data *data) { uint16_t operation = data->ctx.config->operation; if (SPI_OP_MODE_GET(operation) == SPI_OP_MODE_MASTER) { - spi_stm32_shift_m(spi, data); + spi_stm32_shift_m(cfg, data); } else { - spi_stm32_shift_s(spi, data); + spi_stm32_shift_s(cfg->spi, data); } - return spi_stm32_get_err(spi); + return spi_stm32_get_err(cfg->spi); } static void spi_stm32_cs_control(const struct device *dev, bool on) @@ -438,9 +454,15 @@ static void spi_stm32_complete(const struct device *dev, int status) ll_func_disable_int_tx_empty(spi); ll_func_disable_int_rx_not_empty(spi); ll_func_disable_int_errors(spi); + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_DisableIT_EOT(spi); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #endif - spi_stm32_cs_control(dev, false); #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) /* Flush RX buffer */ @@ -453,12 +475,24 @@ static void spi_stm32_complete(const struct device *dev, int status) while (ll_func_spi_is_busy(spi)) { /* NOP */ } + + spi_stm32_cs_control(dev, false); } + /* BSY flag is cleared when MODF flag is raised */ if (LL_SPI_IsActiveFlag_MODF(spi)) { LL_SPI_ClearFlag_MODF(spi); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_ClearFlag_TXTF(spi); + LL_SPI_ClearFlag_OVR(spi); + LL_SPI_ClearFlag_EOT(spi); + LL_SPI_SetTransferSize(spi, 0); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + ll_func_disable_spi(spi); #ifdef CONFIG_SPI_STM32_INTERRUPT @@ -474,6 +508,15 @@ static void spi_stm32_isr(const struct device *dev) SPI_TypeDef *spi = cfg->spi; int err; + /* Some spurious interrupts are triggered when SPI is not enabled; ignore them. + * Do it only when fifo is enabled to leave non-fifo functionality untouched for now + */ + if (cfg->fifo_enabled) { + if (!LL_SPI_IsEnabled(spi)) { + return; + } + } + err = spi_stm32_get_err(spi); if (err) { spi_stm32_complete(dev, err); @@ -481,7 +524,7 @@ static void spi_stm32_isr(const struct device *dev) } if (spi_stm32_transfer_ongoing(data)) { - err = spi_stm32_shift_frames(spi, data); + err = spi_stm32_shift_frames(cfg, data); } if (err || !spi_stm32_transfer_ongoing(data)) { @@ -617,6 +660,11 @@ static int spi_stm32_configure(const struct device *dev, LL_SPI_SetDataWidth(spi, LL_SPI_DATAWIDTH_16BIT); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + LL_SPI_SetMasterSSIdleness(spi, cfg->mssi_clocks); + LL_SPI_SetInterDataIdleness(spi, (cfg->midi_clocks << SPI_CFG2_MIDI_Pos)); +#endif + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) ll_func_set_fifo_threshold_8bit(spi); #endif @@ -645,6 +693,52 @@ static int spi_stm32_release(const struct device *dev, return 0; } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) +static int32_t spi_stm32_count_bufset_frames(const struct spi_config *config, + const struct spi_buf_set *bufs) +{ + if (bufs == NULL) { + return 0; + } + + uint32_t num_bytes = 0; + + for (size_t i = 0; i < bufs->count; i++) { + num_bytes += bufs->buffers[i].len; + } + + uint8_t bytes_per_frame = SPI_WORD_SIZE_GET(config->operation) / 8; + + if ((num_bytes % bytes_per_frame) != 0) { + return -EINVAL; + } + return num_bytes / bytes_per_frame; +} + +static int32_t spi_stm32_count_total_frames(const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + int tx_frames = spi_stm32_count_bufset_frames(config, tx_bufs); + + if (tx_frames < 0) { + return tx_frames; + } + + int rx_frames = spi_stm32_count_bufset_frames(config, rx_bufs); + + if (rx_frames < 0) { + return rx_frames; + } + + if (tx_frames > UINT16_MAX || rx_frames > UINT16_MAX) { + return -EMSGSIZE; + } + + return MAX(rx_frames, tx_frames); +} +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, @@ -682,6 +776,19 @@ static int transceive(const struct device *dev, spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 2); } +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled && SPI_OP_MODE_GET(config->operation) == SPI_OP_MODE_MASTER) { + int total_frames = spi_stm32_count_total_frames( + config, tx_bufs, rx_bufs); + if (total_frames < 0) { + ret = total_frames; + goto end; + } + LL_SPI_SetTransferSize(spi, (uint32_t)total_frames); + } + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) /* Flush RX buffer */ while (ll_func_rx_is_not_empty(spi)) { @@ -691,6 +798,20 @@ static int transceive(const struct device *dev, LL_SPI_Enable(spi); +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + /* With the STM32MP1, STM32U5 and the STM32H7, + * if the device is the SPI master, + * we need to enable the start of the transfer with + * LL_SPI_StartMasterTransfer(spi) + */ + if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) { + LL_SPI_StartMasterTransfer(spi); + while (!LL_SPI_IsActiveMasterTransfer(spi)) { + /* NOP */ + } + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + #if CONFIG_SOC_SERIES_STM32H7X /* * Add a small delay after enabling to prevent transfer stalling at high @@ -703,6 +824,13 @@ static int transceive(const struct device *dev, spi_stm32_cs_control(dev, true); #ifdef CONFIG_SPI_STM32_INTERRUPT + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + if (cfg->fifo_enabled) { + LL_SPI_EnableIT_EOT(spi); + } +#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) */ + ll_func_enable_int_errors(spi); if (rx_bufs) { @@ -714,7 +842,7 @@ static int transceive(const struct device *dev, ret = spi_context_wait_for_completion(&data->ctx); #else do { - ret = spi_stm32_shift_frames(spi, data); + ret = spi_stm32_shift_frames(cfg, data); } while (!ret && spi_stm32_transfer_ongoing(data)); spi_stm32_complete(dev, ret); @@ -902,7 +1030,7 @@ static int transceive_dma(const struct device *dev, } #endif -#ifdef CONFIG_SPI_STM32F7_ERRATA_BUSY +#ifdef CONFIG_SPI_STM32_ERRATA_BUSY WAIT_FOR(ll_func_spi_dma_busy(spi) != 0, CONFIG_SPI_STM32_BUSY_FLAG_TIMEOUT, k_yield()); @@ -1126,15 +1254,9 @@ static void spi_stm32_irq_config_func_##id(const struct device *dev) \ #define SPI_DMA_STATUS_SEM(id) #endif -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz) -#define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \ - .use_subghzspi_nss = DT_INST_PROP_OR( \ - id, use_subghzspi_nss, false), -#else -#define STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) -#endif - - +#define SPI_SUPPORTS_FIFO(id) DT_INST_NODE_HAS_PROP(id, fifo_enable) +#define SPI_GET_FIFO_PROP(id) DT_INST_PROP(id, fifo_enable) +#define SPI_FIFO_ENABLED(id) COND_CODE_1(SPI_SUPPORTS_FIFO(id), (SPI_GET_FIFO_PROP(id)), (0)) #define STM32_SPI_INIT(id) \ STM32_SPI_IRQ_HANDLER_DECL(id); \ @@ -1149,8 +1271,17 @@ static const struct spi_stm32_config spi_stm32_cfg_##id = { \ .pclken = pclken_##id, \ .pclk_len = DT_INST_NUM_CLOCKS(id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + .fifo_enabled = SPI_FIFO_ENABLED(id), \ STM32_SPI_IRQ_HANDLER_FUNC(id) \ - STM32_SPI_USE_SUBGHZSPI_NSS_CONFIG(id) \ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz), \ + (.use_subghzspi_nss = \ + DT_INST_PROP_OR(id, use_subghzspi_nss, false),))\ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi), \ + (.midi_clocks = \ + DT_INST_PROP(id, midi_clock),)) \ + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi), \ + (.mssi_clocks = \ + DT_INST_PROP(id, mssi_clock),)) \ }; \ \ static struct spi_stm32_data spi_stm32_dev_data_##id = { \ diff --git a/drivers/spi/spi_ll_stm32.h b/drivers/spi/spi_ll_stm32.h index 949b8882dd7..23a08e24208 100644 --- a/drivers/spi/spi_ll_stm32.h +++ b/drivers/spi/spi_ll_stm32.h @@ -27,9 +27,14 @@ struct spi_stm32_config { #endif #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz) bool use_subghzspi_nss; +#endif +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) + int midi_clocks; + int mssi_clocks; #endif size_t pclk_len; const struct stm32_pclken *pclken; + bool fifo_enabled; }; #ifdef CONFIG_SPI_STM32_DMA @@ -94,7 +99,7 @@ static inline uint32_t ll_func_spi_dma_busy(SPI_TypeDef *spi) } #endif /* CONFIG_SPI_STM32_DMA */ -static inline uint32_t ll_func_tx_is_empty(SPI_TypeDef *spi) +static inline uint32_t ll_func_tx_is_not_full(SPI_TypeDef *spi) { #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi) return LL_SPI_IsActiveFlag_TXP(spi); diff --git a/drivers/spi/spi_mchp_mss.c b/drivers/spi/spi_mchp_mss.c new file mode 100644 index 00000000000..10ce776367f --- /dev/null +++ b/drivers/spi/spi_mchp_mss.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2022 Microchip Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT microchip_mpfs_spi + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(mss_spi, CONFIG_SPI_LOG_LEVEL); + +#include "spi_context.h" + +/* MSS SPI Register offsets */ +#define MSS_SPI_REG_CONTROL (0x00) +#define MSS_SPI_REG_TXRXDF_SIZE (0x04) +#define MSS_SPI_REG_STATUS (0x08) +#define MSS_SPI_REG_INT_CLEAR (0x0c) +#define MSS_SPI_REG_RX_DATA (0x10) +#define MSS_SPI_REG_TX_DATA (0x14) +#define MSS_SPI_REG_CLK_GEN (0x18) +#define MSS_SPI_REG_SS (0x1c) +#define MSS_SPI_REG_MIS (0x20) +#define MSS_SPI_REG_RIS (0x24) +#define MSS_SPI_REG_CONTROL2 (0x28) +#define MSS_SPI_REG_COMMAND (0x2c) +#define MSS_SPI_REG_PKTSIZE (0x30) +#define MSS_SPI_REG_CMD_SIZE (0x34) +#define MSS_SPI_REG_HWSTATUS (0x38) +#define MSS_SPI_REG_FRAMESUP (0x50) + +/* SPICR bit definitions */ +#define MSS_SPI_CONTROL_ENABLE BIT(0) +#define MSS_SPI_CONTROL_MASTER BIT(1) +#define MSS_SPI_CONTROL_PROTO_MSK BIT(2) +#define MSS_SPI_CONTROL_PROTO_MOTO (0 << 2) +#define MSS_SPI_CONTROL_RX_DATA_INT BIT(4) +#define MSS_SPI_CONTROL_TX_DATA_INT BIT(5) +#define MSS_SPI_CONTROL_RX_OVER_INT BIT(6) +#define MSS_SPI_CONTROL_TX_UNDER_INT BIT(7) +#define MSS_SPI_CONTROL_CNT_MSK (0xffff << 8) +#define MSS_SPI_CONTROL_CNT_SHF (8) +#define MSS_SPI_CONTROL_SPO BIT(24) +#define MSS_SPI_CONTROL_SPH BIT(25) +#define MSS_SPI_CONTROL_SPS BIT(26) +#define MSS_SPI_CONTROL_FRAMEURUN BIT(27) +#define MSS_SPI_CONTROL_CLKMODE BIT(28) +#define MSS_SPI_CONTROL_BIGFIFO BIT(29) +#define MSS_SPI_CONTROL_OENOFF BIT(30) +#define MSS_SPI_CONTROL_RESET BIT(31) + +/* SPIFRAMESIZE bit definitions */ +#define MSS_SPI_FRAMESIZE_DEFAULT (8) + +/* SPISS bit definitions */ +#define MSS_SPI_SSEL_MASK (0xff) +#define MSS_SPI_DIRECT (0x100) +#define MSS_SPI_SSELOUT (0x200) +#define MSS_SPI_MIN_SLAVE (0) +#define MSS_SPI_MAX_SLAVE (7) + +/* SPIST bit definitions */ +#define MSS_SPI_STATUS_ACTIVE BIT(14) +#define MSS_SPI_STATUS_SSEL BIT(13) +#define MSS_SPI_STATUS_FRAMESTART BIT(12) +#define MSS_SPI_STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11) +#define MSS_SPI_STATUS_TXFIFO_EMPTY BIT(10) +#define MSS_SPI_STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9) +#define MSS_SPI_STATUS_TXFIFO_FULL BIT(8) +#define MSS_SPI_STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7) +#define MSS_SPI_STATUS_RXFIFO_EMPTY BIT(6) +#define MSS_SPI_STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5) +#define MSS_SPI_STATUS_RXFIFO_FULL BIT(4) +#define MSS_SPI_STATUS_TX_UNDERRUN BIT(3) +#define MSS_SPI_STATUS_RX_OVERFLOW BIT(2) +#define MSS_SPI_STATUS_RXDAT_RCED BIT(1) +#define MSS_SPI_STATUS_TXDAT_SENT BIT(0) + +/* SPIINT register defines */ +#define MSS_SPI_INT_TXDONE BIT(0) +#define MSS_SPI_INT_RXRDY BIT(1) +#define MSS_SPI_INT_RX_CH_OVRFLW BIT(2) +#define MSS_SPI_INT_TX_CH_UNDRUN BIT(3) +#define MSS_SPI_INT_CMD BIT(4) +#define MSS_SPI_INT_SSEND BIT(5) + +/* SPICOMMAND bit definitions */ +#define MSS_SPI_COMMAND_FIFO_MASK (0xC) + +/* SPIFRAMESUP bit definitions */ +#define MSS_SPI_FRAMESUP_UP_BYTES_MSK (0xFFFF << 16) +#define MSS_SPI_FRAMESUP_LO_BYTES_MSK (0xFFFF << 0) + +struct mss_spi_config { + mm_reg_t base; + uint8_t clk_gen; + int clock_freq; +}; + +struct mss_spi_transfer { + uint32_t rx_len; + uint32_t control; +}; + +struct mss_spi_data { + struct spi_context ctx; + struct mss_spi_transfer xfer; +}; + +static inline uint32_t mss_spi_read(const struct mss_spi_config *cfg, mm_reg_t offset) +{ + return sys_read32(cfg->base + offset); +} + +static inline void mss_spi_write(const struct mss_spi_config *cfg, mm_reg_t offset, uint32_t val) +{ + sys_write32(val, cfg->base + offset); +} + +static inline void mss_spi_hw_tfsz_set(const struct mss_spi_config *cfg, int len) +{ + uint32_t control; + + mss_spi_write(cfg, MSS_SPI_REG_FRAMESUP, (len & MSS_SPI_FRAMESUP_UP_BYTES_MSK)); + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_CNT_MSK; + control |= ((len & MSS_SPI_FRAMESUP_LO_BYTES_MSK) << MSS_SPI_CONTROL_CNT_SHF); + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_enable_controller(const struct mss_spi_config *cfg) +{ + uint32_t control; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control |= MSS_SPI_CONTROL_ENABLE; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_disable_controller(const struct mss_spi_config *cfg) +{ + uint32_t control; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_ENABLE; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static void mss_spi_enable_ints(const struct mss_spi_config *cfg) +{ + uint32_t control; + uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | + MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; + + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control |= mask; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static void mss_spi_disable_ints(const struct mss_spi_config *cfg) +{ + uint32_t control; + uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | + MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; + + mask = ~mask; + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~mask; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); +} + +static inline void mss_spi_readwr_fifo(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + uint32_t rx_raw = 0, rd_byte_size, tr_len; + uint32_t data8, transfer_idx = 0; + int count; + + tr_len = spi_context_longest_current_buf(ctx); + count = spi_context_total_tx_len(ctx); + if (ctx->rx_buf) { + rd_byte_size = count - tr_len; + } else { + rd_byte_size = 0; + } + mss_spi_hw_tfsz_set(cfg, count); + + mss_spi_enable_ints(cfg); + spi_context_update_rx(ctx, 1, xfer->rx_len); + while (transfer_idx < count) { + if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_RXFIFO_EMPTY)) { + rx_raw = mss_spi_read(cfg, MSS_SPI_REG_RX_DATA); + if (transfer_idx >= tr_len) { + if (spi_context_rx_buf_on(ctx)) { + UNALIGNED_PUT(rx_raw, (uint8_t *)ctx->rx_buf); + spi_context_update_rx(ctx, 1, 1); + } + } + ++transfer_idx; + } + + if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_TXFIFO_FULL)) { + if (spi_context_tx_buf_on(ctx)) { + data8 = ctx->tx_buf[0]; + mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, data8); + spi_context_update_tx(ctx, 1, 1); + } else { + mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, 0x0); + } + } + } +} + +static inline int mss_spi_select_slave(const struct mss_spi_config *cfg, int cs) +{ + uint32_t slave; + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + slave = (cs >= MSS_SPI_MIN_SLAVE && cs <= MSS_SPI_MAX_SLAVE) ? (1 << cs) : 0; + reg &= ~MSS_SPI_SSEL_MASK; + reg |= slave; + + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); + + return 0; +} + +static inline void mss_spi_activate_cs(struct mss_spi_config *cfg) +{ + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + reg |= MSS_SPI_SSELOUT; + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); +} + +static inline void mss_spi_deactivate_cs(const struct mss_spi_config *cfg) +{ + uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); + + reg &= ~MSS_SPI_SSELOUT; + mss_spi_write(cfg, MSS_SPI_REG_SS, reg); +} + +static inline int mss_spi_clk_gen_set(const struct mss_spi_config *cfg, + const struct spi_config *spi_cfg) +{ + uint32_t idx, clkrate, val = 0, speed; + + if (spi_cfg->frequency > cfg->clock_freq) { + speed = cfg->clock_freq / 2; + } + + for (idx = 1; idx < 16; idx++) { + clkrate = cfg->clock_freq / (2 * idx); + if (clkrate <= spi_cfg->frequency) { + val = idx; + break; + } + } + + mss_spi_write(cfg, MSS_SPI_REG_CLK_GEN, val); + + return 0; +} + +static inline int mss_spi_hw_mode_set(const struct mss_spi_config *cfg, unsigned int mode) +{ + uint32_t control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + + /* set the mode */ + if (mode & SPI_MODE_CPHA) { + control |= MSS_SPI_CONTROL_SPH; + } else { + control &= ~MSS_SPI_CONTROL_SPH; + } + + if (mode & SPI_MODE_CPOL) { + control |= MSS_SPI_CONTROL_SPO; + } else { + control &= ~MSS_SPI_CONTROL_SPO; + } + + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); + + return 0; +} + +static void mss_spi_interrupt(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int intfield = mss_spi_read(cfg, MSS_SPI_REG_MIS) & 0xf; + + if (intfield == 0) { + return; + } + + mss_spi_write(cfg, MSS_SPI_REG_INT_CLEAR, intfield); + spi_context_complete(ctx, dev, 0); +} + +static int mss_spi_release(const struct device *dev, const struct spi_config *config) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + + mss_spi_disable_ints(cfg); + + /* release kernel resources */ + spi_context_unlock_unconditionally(&data->ctx); + mss_spi_disable_controller(cfg); + + return 0; +} + +static int mss_spi_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + uint32_t control; + + if (spi_cfg->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE | SPI_MODE_LOOP)) { + LOG_WRN("not supported operation\n\r"); + return -ENOTSUP; + } + + if (SPI_WORD_SIZE_GET(spi_cfg->operation) != MSS_SPI_FRAMESIZE_DEFAULT) { + return -ENOTSUP; + } + + ctx->config = spi_cfg; + mss_spi_select_slave(cfg, spi_cfg->slave); + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + + /* + * Fill up the default values + * Slave select behaviour set + * Fifo depth greater than 4 frames + * Methodology to calculate SPI Clock: + * 0: SPICLK = 1 / (2 CLK_GEN + 1) , CLK_GEN is from 0 to 15 + * 1: SPICLK = 1 / (2 * (CLK_GEN + 1)) , CLK_GEN is from 0 to 255 + */ + + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, xfer->control); + + if (mss_spi_clk_gen_set(cfg, spi_cfg)) { + LOG_ERR("can't set clk divider\n"); + return -EINVAL; + } + + mss_spi_hw_mode_set(cfg, spi_cfg->operation); + mss_spi_write(cfg, MSS_SPI_REG_TXRXDF_SIZE, MSS_SPI_FRAMESIZE_DEFAULT); + mss_spi_enable_controller(cfg); + mss_spi_write(cfg, MSS_SPI_REG_COMMAND, MSS_SPI_COMMAND_FIFO_MASK); + + return 0; +} + +static int mss_spi_transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, + bool async, spi_callback_t cb, void *userdata) +{ + + const struct mss_spi_config *config = dev->config; + struct mss_spi_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + struct mss_spi_transfer *xfer = &data->xfer; + int ret = 0; + + spi_context_lock(ctx, async, cb, userdata, spi_cfg); + + ret = mss_spi_configure(dev, spi_cfg); + if (ret) { + LOG_ERR("Fail to configure\n\r"); + goto out; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); + xfer->rx_len = ctx->rx_len; + mss_spi_readwr_fifo(dev); + ret = spi_context_wait_for_completion(ctx); +out: + spi_context_release(ctx, ret); + mss_spi_disable_ints(config); + mss_spi_disable_controller(config); + + return ret; +} + +static int mss_spi_transceive_blocking(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + + return mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +} + +#ifdef CONFIG_SPI_ASYNC +static int mss_spi_transceive_async(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, spi_callback_t cb, + void *userdata) +{ + return mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); +} +#endif /* CONFIG_SPI_ASYNC */ + +static int mss_spi_init(const struct device *dev) +{ + const struct mss_spi_config *cfg = dev->config; + struct mss_spi_data *data = dev->data; + struct mss_spi_transfer *xfer = &data->xfer; + int ret = 0; + uint32_t control = 0; + + /* Remove SPI from Reset */ + control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); + control &= ~MSS_SPI_CONTROL_RESET; + mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); + + /* Set master mode */ + mss_spi_disable_controller(cfg); + xfer->control = (MSS_SPI_CONTROL_SPS | MSS_SPI_CONTROL_BIGFIFO | MSS_SPI_CONTROL_MASTER | + MSS_SPI_CONTROL_CLKMODE); + + spi_context_unlock_unconditionally(&data->ctx); + + return ret; +} + +#define MICROCHIP_SPI_PM_OPS (NULL) + +static const struct spi_driver_api mss_spi_driver_api = { + .transceive = mss_spi_transceive_blocking, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = mss_spi_transceive_async, +#endif /* CONFIG_SPI_ASYNC */ + .release = mss_spi_release, +}; + +#define MSS_SPI_INIT(n) \ + static int mss_spi_init_##n(const struct device *dev) \ + { \ + mss_spi_init(dev); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), mss_spi_interrupt, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + \ + return 0; \ + } \ + \ + static const struct mss_spi_config mss_spi_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .clock_freq = DT_INST_PROP(n, clock_frequency), \ + }; \ + \ + static struct mss_spi_data mss_spi_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(mss_spi_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(mss_spi_data_##n, ctx), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, mss_spi_init_##n, NULL, &mss_spi_data_##n, &mss_spi_config_##n, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &mss_spi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MSS_SPI_INIT) diff --git a/drivers/spi/spi_mcux_dspi.c b/drivers/spi/spi_mcux_dspi.c index 63bccd70499..14d47db4dd9 100644 --- a/drivers/spi/spi_mcux_dspi.c +++ b/drivers/spi/spi_mcux_dspi.c @@ -195,11 +195,11 @@ static int spi_mcux_transfer_next_packet(const struct device *dev) status = DSPI_MasterTransferNonBlocking(base, &data->handle, &transfer); if (status != kStatus_Success) { - LOG_ERR("Transfer could not start"); + LOG_ERR("Transfer could not start on %s: %d", dev->name, status); + return status == kDSPI_Busy ? -EBUSY : -EINVAL; } - return status == kStatus_Success ? 0 : - status == kDSPI_Busy ? -EBUSY : -EINVAL; + return 0; } static void spi_mcux_isr(const struct device *dev) diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 32b5638d49d..cb20fcea6e3 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -830,10 +830,11 @@ static void spi_mcux_config_func_##id(const struct device *dev) \ .dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(id, tx)), \ .channel = \ DT_INST_DMAS_CELL_BY_NAME(id, tx, channel), \ - .dma_cfg = { \ + .dma_cfg = { \ .channel_direction = MEMORY_TO_PERIPHERAL, \ .dma_callback = spi_mcux_dma_callback, \ - .block_count = 2, \ + .complete_callback_en = true, \ + .block_count = 2, \ } \ }, \ .dma_rx = { \ diff --git a/drivers/spi/spi_mcux_lpspi.c b/drivers/spi/spi_mcux_lpspi.c index 9b230d1c53f..a1b805d98e0 100644 --- a/drivers/spi/spi_mcux_lpspi.c +++ b/drivers/spi/spi_mcux_lpspi.c @@ -16,6 +16,10 @@ #include #endif #include +#ifdef CONFIG_SPI_RTIO +#include +#include +#endif LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL); @@ -24,8 +28,13 @@ LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL); #define CHIP_SELECT_COUNT 4 #define MAX_DATA_WIDTH 4096 +/* Required by DEVICE_MMIO_NAMED_* macros */ +#define DEV_CFG(_dev) \ + ((const struct spi_mcux_config *)(_dev)->config) +#define DEV_DATA(_dev) ((struct spi_mcux_data *)(_dev)->data) + struct spi_mcux_config { - LPSPI_Type *base; + DEVICE_MMIO_NAMED_ROM(reg_base); const struct device *clock_dev; clock_control_subsys_t clock_subsys; void (*irq_config_func)(const struct device *dev); @@ -52,10 +61,21 @@ struct stream { #endif struct spi_mcux_data { + DEVICE_MMIO_NAMED_RAM(reg_base); const struct device *dev; lpspi_master_handle_t handle; struct spi_context ctx; size_t transfer_len; + +#ifdef CONFIG_SPI_RTIO + struct rtio *r; + struct rtio_iodev iodev; + struct rtio_iodev_sqe *txn_head; + struct rtio_iodev_sqe *txn_curr; + struct spi_dt_spec dt_spec; + struct k_spinlock lock; +#endif + #ifdef CONFIG_SPI_MCUX_LPSPI_DMA volatile uint32_t status_flags; struct stream dma_rx; @@ -67,11 +87,11 @@ struct spi_mcux_data { #endif }; -static void spi_mcux_transfer_next_packet(const struct device *dev) +static int spi_mcux_transfer_next_packet(const struct device *dev) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); struct spi_context *ctx = &data->ctx; lpspi_transfer_t transfer; status_t status; @@ -80,11 +100,11 @@ static void spi_mcux_transfer_next_packet(const struct device *dev) /* nothing left to rx or tx, we're done! */ spi_context_cs_control(&data->ctx, false); spi_context_complete(&data->ctx, dev, 0); - return; + return 0; } transfer.configFlags = kLPSPI_MasterPcsContinuous | - (ctx->config->slave << LPSPI_MASTER_PCS_SHIFT); + (ctx->config->slave << LPSPI_MASTER_PCS_SHIFT); if (ctx->tx_len == 0) { /* rx only, nothing to tx */ @@ -130,24 +150,37 @@ static void spi_mcux_transfer_next_packet(const struct device *dev) status = LPSPI_MasterTransferNonBlocking(base, &data->handle, &transfer); if (status != kStatus_Success) { - LOG_ERR("Transfer could not start"); + LOG_ERR("Transfer could not start on %s: %d", dev->name, status); + return status == kStatus_LPSPI_Busy ? -EBUSY : -EINVAL; } + + return 0; } static void spi_mcux_isr(const struct device *dev) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); LPSPI_MasterTransferHandleIRQ(base, &data->handle); } +#ifdef CONFIG_SPI_RTIO +static void spi_mcux_iodev_complete(const struct device *dev, int status); +#endif + static void spi_mcux_master_transfer_callback(LPSPI_Type *base, lpspi_master_handle_t *handle, status_t status, void *userData) { struct spi_mcux_data *data = userData; +#ifdef CONFIG_SPI_RTIO + if (data->txn_head != NULL) { + spi_mcux_iodev_complete(data->dev, status); + return; + } +#endif spi_context_update_tx(&data->ctx, 1, data->transfer_len); spi_context_update_rx(&data->ctx, 1, data->transfer_len); @@ -155,11 +188,11 @@ static void spi_mcux_master_transfer_callback(LPSPI_Type *base, } static int spi_mcux_configure(const struct device *dev, - const struct spi_config *spi_cfg) + const struct spi_config *spi_cfg) { const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); lpspi_master_config_t master_config; uint32_t clock_freq; uint32_t word_size; @@ -178,15 +211,15 @@ static int spi_mcux_configure(const struct device *dev, if (spi_cfg->slave > CHIP_SELECT_COUNT) { LOG_ERR("Slave %d is greater than %d", - spi_cfg->slave, - CHIP_SELECT_COUNT); + spi_cfg->slave, + CHIP_SELECT_COUNT); return -EINVAL; } word_size = SPI_WORD_SIZE_GET(spi_cfg->operation); if (word_size > MAX_DATA_WIDTH) { LOG_ERR("Word size %d is greater than %d", - word_size, MAX_DATA_WIDTH); + word_size, MAX_DATA_WIDTH); return -EINVAL; } @@ -225,13 +258,18 @@ static int spi_mcux_configure(const struct device *dev, return -EINVAL; } - /* Setting the baud rate in LPSPI_MasterInit requires module to be disabled */ - LPSPI_Enable(base, false); - while ((base->CR & LPSPI_CR_MEN_MASK) != 0U) { - /* Wait until LPSPI is disabled. Datasheet: - * After writing 0, MEN (Module Enable) remains set until the LPSPI has completed - * the current transfer and is idle. + if (data->ctx.config != NULL) { + /* Setting the baud rate in LPSPI_MasterInit requires module to be disabled. Only + * disable if already configured, otherwise the clock is not enabled and the + * CR register cannot be written. */ + LPSPI_Enable(base, false); + while ((base->CR & LPSPI_CR_MEN_MASK) != 0U) { + /* Wait until LPSPI is disabled. Datasheet: + * After writing 0, MEN (Module Enable) remains set until the LPSPI has + * completed the current transfer and is idle. + */ + } } LPSPI_MasterInit(base, &master_config, clock_freq); @@ -303,10 +341,10 @@ static void spi_mcux_dma_callback(const struct device *dev, void *arg, static int spi_mcux_dma_tx_load(const struct device *dev, const uint8_t *buf, size_t len) { - const struct spi_mcux_config *cfg = dev->config; + /* const struct spi_mcux_config *cfg = dev->config; */ struct spi_mcux_data *data = dev->data; struct dma_block_config *blk_cfg; - LPSPI_Type *base = cfg->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); /* remember active TX DMA channel (used in callback) */ struct stream *stream = &data->dma_tx; @@ -346,10 +384,10 @@ static int spi_mcux_dma_tx_load(const struct device *dev, const uint8_t *buf, si static int spi_mcux_dma_rx_load(const struct device *dev, uint8_t *buf, size_t len) { - const struct spi_mcux_config *cfg = dev->config; + /*const struct spi_mcux_config *cfg = dev->config; */ struct spi_mcux_data *data = dev->data; struct dma_block_config *blk_cfg; - LPSPI_Type *base = cfg->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); /* retrieve active RX DMA channel (used in callback) */ struct stream *stream = &data->dma_rx; @@ -448,16 +486,16 @@ static inline int spi_mcux_dma_rxtx_load(const struct device *dev, } static int transceive_dma(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - bool asynchronous, - spi_callback_t cb, - void *userdata) + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + bool asynchronous, + spi_callback_t cb, + void *userdata) { - const struct spi_mcux_config *config = dev->config; + /* const struct spi_mcux_config *config = dev->config; */ struct spi_mcux_data *data = dev->data; - LPSPI_Type *base = config->base; + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); int ret; size_t dma_size; @@ -532,12 +570,12 @@ static int transceive_dma(const struct device *dev, #endif static int transceive(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - bool asynchronous, - spi_callback_t cb, - void *userdata) + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + bool asynchronous, + spi_callback_t cb, + void *userdata) { struct spi_mcux_data *data = dev->data; int ret; @@ -553,7 +591,10 @@ static int transceive(const struct device *dev, spi_context_cs_control(&data->ctx, true); - spi_mcux_transfer_next_packet(dev); + ret = spi_mcux_transfer_next_packet(dev); + if (ret) { + goto out; + } ret = spi_context_wait_for_completion(&data->ctx); out: @@ -564,9 +605,9 @@ static int transceive(const struct device *dev, static int spi_mcux_transceive(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) { #ifdef CONFIG_SPI_MCUX_LPSPI_DMA const struct spi_mcux_data *data = dev->data; @@ -581,11 +622,11 @@ static int spi_mcux_transceive(const struct device *dev, #ifdef CONFIG_SPI_ASYNC static int spi_mcux_transceive_async(const struct device *dev, - const struct spi_config *spi_cfg, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs, - spi_callback_t cb, - void *userdata) + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + spi_callback_t cb, + void *userdata) { #ifdef CONFIG_SPI_MCUX_LPSPI_DMA struct spi_mcux_data *data = dev->data; @@ -602,7 +643,7 @@ static int spi_mcux_transceive_async(const struct device *dev, #endif /* CONFIG_SPI_ASYNC */ static int spi_mcux_release(const struct device *dev, - const struct spi_config *spi_cfg) + const struct spi_config *spi_cfg) { struct spi_mcux_data *data = dev->data; @@ -617,6 +658,8 @@ static int spi_mcux_init(const struct device *dev) const struct spi_mcux_config *config = dev->config; struct spi_mcux_data *data = dev->data; + DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP); + config->irq_config_func(dev); err = spi_context_cs_configure_all(&data->ctx); @@ -642,6 +685,13 @@ static int spi_mcux_init(const struct device *dev) } #endif /* CONFIG_SPI_MCUX_LPSPI_DMA */ +#ifdef CONFIG_SPI_RTIO + data->dt_spec.bus = dev; + data->iodev.api = &spi_iodev_api; + data->iodev.data = &data->dt_spec; + rtio_mpsc_init(&data->iodev.iodev_sq); +#endif + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); if (err) { return err; @@ -652,14 +702,162 @@ static int spi_mcux_init(const struct device *dev) return 0; } +#ifdef CONFIG_SPI_RTIO +static inline k_spinlock_key_t spi_spin_lock(const struct device *dev) +{ + struct spi_mcux_data *data = dev->data; + + return k_spin_lock(&data->lock); +} + +static inline void spi_spin_unlock(const struct device *dev, k_spinlock_key_t key) +{ + struct spi_mcux_data *data = dev->data; + + k_spin_unlock(&data->lock, key); +} + + +static void spi_mcux_iodev_next(const struct device *dev, bool completion); + +static void spi_mcux_iodev_start(const struct device *dev) +{ + /* const struct spi_mcux_config *config = dev->config; */ + struct spi_mcux_data *data = dev->data; + struct rtio_sqe *sqe = &data->txn_curr->sqe; + struct spi_dt_spec *spi_dt_spec = sqe->iodev->data; + struct spi_config *spi_cfg = &spi_dt_spec->config; + struct rtio_iodev_sqe *txn_head = data->txn_head; + + LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base); + lpspi_transfer_t transfer; + status_t status; + + transfer.configFlags = kLPSPI_MasterPcsContinuous | + (spi_cfg->slave << LPSPI_MASTER_PCS_SHIFT); + + switch (sqe->op) { + case RTIO_OP_RX: + transfer.txData = NULL; + transfer.rxData = sqe->buf; + transfer.dataSize = sqe->buf_len; + break; + case RTIO_OP_TX: + transfer.rxData = NULL; + transfer.txData = sqe->buf; + transfer.dataSize = sqe->buf_len; + break; + case RTIO_OP_TINY_TX: + transfer.rxData = NULL; + transfer.txData = sqe->tiny_buf; + transfer.dataSize = sqe->tiny_buf_len; + break; + case RTIO_OP_TXRX: + transfer.txData = sqe->tx_buf; + transfer.rxData = sqe->rx_buf; + transfer.dataSize = sqe->txrx_buf_len; + break; + default: + LOG_ERR("Invalid op code %d for submission %p\n", sqe->op, (void *)sqe); + + spi_mcux_iodev_next(dev, true); + rtio_iodev_sqe_err(txn_head, -EINVAL); + spi_mcux_iodev_complete(dev, 0); + return; + } + + data->transfer_len = transfer.dataSize; + + k_spinlock_key_t key = spi_spin_lock(dev); + + status = LPSPI_MasterTransferNonBlocking(base, &data->handle, + &transfer); + spi_spin_unlock(dev, key); + if (status != kStatus_Success) { + LOG_ERR("Transfer could not start"); + rtio_iodev_sqe_err(txn_head, -EIO); + } +} + +static void spi_mcux_iodev_next(const struct device *dev, bool completion) +{ + struct spi_mcux_data *data = dev->data; + + k_spinlock_key_t key = spi_spin_lock(dev); + + if (!completion && data->txn_curr != NULL) { + spi_spin_unlock(dev, key); + return; + } + + struct rtio_mpsc_node *next = rtio_mpsc_pop(&data->iodev.iodev_sq); + + if (next != NULL) { + struct rtio_iodev_sqe *next_sqe = CONTAINER_OF(next, struct rtio_iodev_sqe, q); + + data->txn_head = next_sqe; + data->txn_curr = next_sqe; + } else { + data->txn_head = NULL; + data->txn_curr = NULL; + } + + spi_spin_unlock(dev, key); + + if (data->txn_curr != NULL) { + struct spi_dt_spec *spi_dt_spec = data->txn_curr->sqe.iodev->data; + struct spi_config *spi_cfg = &spi_dt_spec->config; + + spi_mcux_configure(dev, spi_cfg); + spi_context_cs_control(&data->ctx, true); + spi_mcux_iodev_start(dev); + } +} + +static void spi_mcux_iodev_submit(const struct device *dev, + struct rtio_iodev_sqe *iodev_sqe) +{ + struct spi_mcux_data *data = dev->data; + + rtio_mpsc_push(&data->iodev.iodev_sq, &iodev_sqe->q); + spi_mcux_iodev_next(dev, false); +} + +static void spi_mcux_iodev_complete(const struct device *dev, int status) +{ + struct spi_mcux_data *data = dev->data; + + if (data->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) { + data->txn_curr = rtio_txn_next(data->txn_curr); + spi_mcux_iodev_start(dev); + } else { + struct rtio_iodev_sqe *txn_head = data->txn_head; + + spi_context_cs_control(&data->ctx, false); + spi_mcux_iodev_next(dev, true); + rtio_iodev_sqe_ok(txn_head, status); + } +} + + +#endif + + static const struct spi_driver_api spi_mcux_driver_api = { .transceive = spi_mcux_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_mcux_transceive_async, +#endif +#ifdef CONFIG_SPI_RTIO + .iodev_submit = spi_mcux_iodev_submit, #endif .release = spi_mcux_release, }; + +#define SPI_MCUX_RTIO_DEFINE(n) RTIO_DEFINE(spi_mcux_rtio_##n, CONFIG_SPI_MCUX_RTIO_SQ_SIZE, \ + CONFIG_SPI_MCUX_RTIO_SQ_SIZE) + #ifdef CONFIG_SPI_MCUX_LPSPI_DMA #define SPI_DMA_CHANNELS(n) \ IF_ENABLED(DT_INST_DMAS_HAS_NAME(n, tx), \ @@ -692,7 +890,7 @@ static const struct spi_driver_api spi_mcux_driver_api = { .block_count = 1, \ .dma_slot = DT_INST_DMAS_CELL_BY_NAME(n, rx, source) \ } \ - } \ + }, \ )) #else #define SPI_DMA_CHANNELS(n) @@ -700,11 +898,12 @@ static const struct spi_driver_api spi_mcux_driver_api = { #define SPI_MCUX_LPSPI_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ + COND_CODE_1(CONFIG_SPI_RTIO, (SPI_MCUX_RTIO_DEFINE(n)), ()); \ \ static void spi_mcux_config_func_##n(const struct device *dev); \ \ static const struct spi_mcux_config spi_mcux_config_##n = { \ - .base = (LPSPI_Type *) DT_INST_REG_ADDR(n), \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \ .clock_subsys = \ (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name), \ @@ -727,18 +926,21 @@ static const struct spi_driver_api spi_mcux_driver_api = { SPI_CONTEXT_INIT_SYNC(spi_mcux_data_##n, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \ SPI_DMA_CHANNELS(n) \ + IF_ENABLED(CONFIG_SPI_RTIO, \ + (.r = &spi_mcux_rtio_##n,)) \ + \ }; \ \ DEVICE_DT_INST_DEFINE(n, &spi_mcux_init, NULL, \ - &spi_mcux_data_##n, \ - &spi_mcux_config_##n, POST_KERNEL, \ - CONFIG_SPI_INIT_PRIORITY, \ - &spi_mcux_driver_api); \ + &spi_mcux_data_##n, \ + &spi_mcux_config_##n, POST_KERNEL, \ + CONFIG_SPI_INIT_PRIORITY, \ + &spi_mcux_driver_api); \ \ static void spi_mcux_config_func_##n(const struct device *dev) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ - spi_mcux_isr, DEVICE_DT_INST_GET(n), 0); \ + spi_mcux_isr, DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } diff --git a/drivers/spi/spi_npcx_spip.c b/drivers/spi/spi_npcx_spip.c new file mode 100644 index 00000000000..f82d090d693 --- /dev/null +++ b/drivers/spi/spi_npcx_spip.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2024 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_spip + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(spi_npcx_spip, CONFIG_SPI_LOG_LEVEL); + +#include "spi_context.h" + +/* Transfer this NOP value when tx buf is null */ +#define SPI_NPCX_SPIP_TX_NOP 0x00 +#define SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US 1000 + +/* The max allowed prescaler divider */ +#define SPI_NPCX_MAX_PRESCALER_DIV INT8_MAX + +struct spi_npcx_spip_data { + struct spi_context ctx; + uint32_t src_clock_freq; + uint8_t bytes_per_frame; +}; + +struct spi_npcx_spip_cfg { + struct spip_reg *reg_base; + struct npcx_clk_cfg clk_cfg; +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + /* routine for configuring SPIP ISR */ + void (*irq_cfg_func)(const struct device *dev); +#endif + const struct pinctrl_dev_config *pcfg; +}; + +static int spi_npcx_spip_configure(const struct device *dev, const struct spi_config *spi_cfg) +{ + uint8_t prescaler_divider; + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spi_npcx_spip_data *const data = dev->data; + struct spip_reg *const reg_base = config->reg_base; + spi_operation_t operation = spi_cfg->operation; + uint8_t frame_size; + + if (spi_context_configured(&data->ctx, spi_cfg)) { + /* This configuration is already in use */ + return 0; + } + + if (operation & SPI_HALF_DUPLEX) { + LOG_ERR("Half duplex mode is not supported"); + return -ENOTSUP; + } + + if (SPI_OP_MODE_GET(operation) != SPI_OP_MODE_MASTER) { + LOG_ERR("Only SPI controller mode is supported"); + return -ENOTSUP; + } + + if (operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback mode is not supported"); + return -ENOTSUP; + } + + /* + * If the GPIO CS configuration is not present, return error because the hardware CS is + * not supported. + */ + if (!spi_cs_is_gpio(spi_cfg)) { + LOG_ERR("Only GPIO CS is supported"); + return -ENOTSUP; + } + + /* Get the frame length */ + frame_size = SPI_WORD_SIZE_GET(operation); + if (frame_size == 8) { + data->bytes_per_frame = 1; + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_MOD); + } else if (frame_size == 16) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_MOD); + data->bytes_per_frame = 2; + } else { + LOG_ERR("Only support word sizes either 8 or 16 bits"); + return -ENOTSUP; + } + + if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + (operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only single line mode is supported"); + return -ENOTSUP; + } + + /* Set the endianness */ + if (operation & SPI_TRANSFER_LSB) { + LOG_ERR("Shift out with LSB is not supported"); + return -ENOTSUP; + } + + /* + * Set CPOL and CPHA. + * The following is how to map npcx spip control register to CPOL and CPHA + * CPOL CPHA | SCIDL SCM + * ----------------------------- + * 0 0 | 0 0 + * 0 1 | 0 1 + * 1 0 | 1 1 + * 1 1 | 1 0 + */ + if (operation & SPI_MODE_CPOL) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SCIDL); + } else { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_SCIDL); + } + if (((operation & SPI_MODE_CPOL) == SPI_MODE_CPOL) != + ((operation & SPI_MODE_CPHA) == SPI_MODE_CPHA)) { + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SCM); + } else { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_SCM); + } + + /* Set the SPI frequency */ + prescaler_divider = data->src_clock_freq / 2 / spi_cfg->frequency; + if (prescaler_divider >= 1) { + prescaler_divider -= 1; + } + if (prescaler_divider >= SPI_NPCX_MAX_PRESCALER_DIV) { + LOG_ERR("SPI divider %d exceeds the max allowed value %d.", prescaler_divider, + SPI_NPCX_MAX_PRESCALER_DIV); + return -ENOTSUP; + } + SET_FIELD(reg_base->SPIP_CTL1, NPCX_SPIP_CTL1_SCDV, prescaler_divider); + + data->ctx.config = spi_cfg; + + return 0; +} + +static void spi_npcx_spip_process_tx_buf(struct spi_npcx_spip_data *const data, uint16_t *tx_frame) +{ + /* Get the tx_frame from tx_buf only when tx_buf != NULL */ + if (spi_context_tx_buf_on(&data->ctx)) { + if (data->bytes_per_frame == 1) { + *tx_frame = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf)); + } else { + *tx_frame = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf)); + } + } + /* + * The update is ignored if TX is off (tx_len == 0). + * Note: if tx_buf == NULL && tx_len != 0, the update still counts. + */ + spi_context_update_tx(&data->ctx, data->bytes_per_frame, 1); +} + +static void spi_npcx_spip_process_rx_buf(struct spi_npcx_spip_data *const data, uint16_t rx_frame) +{ + if (spi_context_rx_buf_on(&data->ctx)) { + if (data->bytes_per_frame == 1) { + UNALIGNED_PUT(rx_frame, (uint8_t *)data->ctx.rx_buf); + } else { + UNALIGNED_PUT(rx_frame, (uint16_t *)data->ctx.rx_buf); + } + } + spi_context_update_rx(&data->ctx, data->bytes_per_frame, 1); +} + +#ifndef CONFIG_SPI_NPCX_SPIP_INTERRUPT +static int spi_npcx_spip_xfer_frame(const struct device *dev) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + uint16_t tx_frame = SPI_NPCX_SPIP_TX_NOP; + uint16_t rx_frame; + + spi_npcx_spip_process_tx_buf(data, &tx_frame); + + if (WAIT_FOR(!IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_BSY), + SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US, NULL) == false) { + LOG_ERR("Check Status BSY Timeout"); + return -ETIMEDOUT; + } + + reg_base->SPIP_DATA = tx_frame; + + if (WAIT_FOR(IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_RBF), + SPI_NPCX_SPIP_WAIT_STATUS_TIMEOUT_US, NULL) == false) { + LOG_ERR("Check Status RBF Timeout"); + return -ETIMEDOUT; + } + + rx_frame = reg_base->SPIP_DATA; + spi_npcx_spip_process_rx_buf(data, rx_frame); + + return 0; +} +#endif + +static bool spi_npcx_spip_transfer_ongoing(struct spi_npcx_spip_data *data) +{ + return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx); +} + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT +static void spi_npcx_spip_isr(const struct device *dev) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + uint16_t tx_frame = SPI_NPCX_SPIP_TX_NOP; + uint16_t rx_frame; + uint8_t status; + + status = reg_base->SPIP_STAT; + + if (!IS_BIT_SET(status, NPCX_SPIP_STAT_BSY) && !IS_BIT_SET(status, NPCX_SPIP_STAT_RBF)) { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_EIW); + + spi_npcx_spip_process_tx_buf(data, &tx_frame); + reg_base->SPIP_DATA = tx_frame; + } else if (IS_BIT_SET(status, NPCX_SPIP_STAT_RBF)) { + rx_frame = reg_base->SPIP_DATA; + + spi_npcx_spip_process_rx_buf(data, rx_frame); + + if (!spi_npcx_spip_transfer_ongoing(data)) { + reg_base->SPIP_CTL1 &= ~BIT(NPCX_SPIP_CTL1_EIR); + /* + * The CS might not de-assert if SPI_HOLD_ON_CS is configured. + * In this case, CS de-assertion reles on the caller to explicitly call + * spi_release() API. + */ + spi_context_cs_control(ctx, false); + + spi_context_complete(ctx, dev, 0); + + } else { + spi_npcx_spip_process_tx_buf(data, &tx_frame); + reg_base->SPIP_DATA = tx_frame; + } + } +} +#endif + +static int transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, + bool asynchronous, spi_callback_t cb, void *userdata) +{ + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + int rc; + + if (!tx_bufs && !rx_bufs) { + return 0; + } + +#ifndef CONFIG_SPI_NPCX_SPIP_INTERRUPT + if (asynchronous) { + return -ENOTSUP; + } +#endif + + /* Lock the SPI Context */ + spi_context_lock(ctx, asynchronous, cb, userdata, spi_cfg); + + rc = spi_npcx_spip_configure(dev, spi_cfg); + if (rc < 0) { + spi_context_release(ctx, rc); + return rc; + } + + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, data->bytes_per_frame); + if (!spi_npcx_spip_transfer_ongoing(data)) { + spi_context_release(ctx, 0); + return 0; + } + + /* Enable SPIP module */ + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SPIEN); + + /* Cleaning junk data in the buffer */ + while (IS_BIT_SET(reg_base->SPIP_STAT, NPCX_SPIP_STAT_RBF)) { + uint8_t unused __attribute__((unused)); + + unused = reg_base->SPIP_DATA; + } + + /* Assert the CS line */ + spi_context_cs_control(ctx, true); + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_EIR) | BIT(NPCX_SPIP_CTL1_EIW); + rc = spi_context_wait_for_completion(&data->ctx); +#else + do { + rc = spi_npcx_spip_xfer_frame(dev); + if (rc < 0) { + break; + } + } while (spi_npcx_spip_transfer_ongoing(data)); + + /* + * The CS might not de-assert if SPI_HOLD_ON_CS is configured. + * In this case, CS de-assertion reles on the caller to explicitly call spi_release() API. + */ + spi_context_cs_control(ctx, false); + +#endif + spi_context_release(ctx, rc); + + return rc; +} + +static int spi_npcx_spip_transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); +} + +#ifdef CONFIG_SPI_ASYNC +static int spi_npcx_spip_transceive_async(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, spi_callback_t cb, + void *userdata) +{ + return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); +} +#endif + +static int spi_npcx_spip_release(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_npcx_spip_data *const data = dev->data; + struct spi_context *ctx = &data->ctx; + + if (!spi_context_configured(ctx, spi_cfg)) { + return -EINVAL; + } + + spi_context_unlock_unconditionally(ctx); + + return 0; +} + +static int spi_npcx_spip_init(const struct device *dev) +{ + int ret; + struct spi_npcx_spip_data *const data = dev->data; + const struct spi_npcx_spip_cfg *const config = dev->config; + struct spip_reg *const reg_base = config->reg_base; + const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); + + if (!device_is_ready(clk_dev)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + ret = clock_control_on(clk_dev, (clock_control_subsys_t)&config->clk_cfg); + if (ret < 0) { + LOG_ERR("Turn on SPIP clock fail %d", ret); + return ret; + } + + ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t)&config->clk_cfg, + &data->src_clock_freq); + if (ret < 0) { + LOG_ERR("Get SPIP clock source rate error %d", ret); + return ret; + } + + ret = spi_context_cs_configure_all(&data->ctx); + if (ret < 0) { + return ret; + } + + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + /* Make sure the context is unlocked */ + spi_context_unlock_unconditionally(&data->ctx); + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT + config->irq_cfg_func(dev); +#endif + + /* Enable SPIP module */ + reg_base->SPIP_CTL1 |= BIT(NPCX_SPIP_CTL1_SPIEN); + + return 0; +} + +static struct spi_driver_api spi_npcx_spip_api = { + .transceive = spi_npcx_spip_transceive, + .release = spi_npcx_spip_release, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = spi_npcx_spip_transceive_async, +#endif +}; + +#ifdef CONFIG_SPI_NPCX_SPIP_INTERRUPT +#define NPCX_SPIP_IRQ_HANDLER(n) \ + static void spi_npcx_spip_irq_cfg_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_npcx_spip_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +#define NPCX_SPIP_IRQ_HANDLER_FUNC(n) .irq_cfg_func = spi_npcx_spip_irq_cfg_func_##n, +#else +#define NPCX_SPIP_IRQ_HANDLER_FUNC(n) +#define NPCX_SPIP_IRQ_HANDLER(n) +#endif + +#define NPCX_SPI_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + NPCX_SPIP_IRQ_HANDLER(n) \ + \ + static struct spi_npcx_spip_data spi_npcx_spip_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(spi_npcx_spip_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_npcx_spip_data_##n, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)}; \ + \ + static struct spi_npcx_spip_cfg spi_npcx_spip_cfg_##n = { \ + .reg_base = (struct spip_reg *)DT_INST_REG_ADDR(n), \ + .clk_cfg = NPCX_DT_CLK_CFG_ITEM(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + NPCX_SPIP_IRQ_HANDLER_FUNC(n)}; \ + \ + DEVICE_DT_INST_DEFINE(n, spi_npcx_spip_init, NULL, &spi_npcx_spip_data_##n, \ + &spi_npcx_spip_cfg_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &spi_npcx_spip_api); + +DT_INST_FOREACH_STATUS_OKAY(NPCX_SPI_INIT) diff --git a/drivers/spi/spi_nrfx_common.c b/drivers/spi/spi_nrfx_common.c index 1ef233cfab3..04a11c2367a 100644 --- a/drivers/spi/spi_nrfx_common.c +++ b/drivers/spi/spi_nrfx_common.c @@ -6,40 +6,39 @@ #include "spi_nrfx_common.h" #include -#include -int spi_nrfx_wake_init(uint32_t wake_pin) +int spi_nrfx_wake_init(const nrfx_gpiote_t *gpiote, uint32_t wake_pin) { - nrfx_gpiote_input_config_t input_config = { - .pull = NRF_GPIO_PIN_PULLDOWN, - }; + nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLDOWN; uint8_t ch; nrfx_gpiote_trigger_config_t trigger_config = { .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, .p_in_channel = &ch, }; + nrfx_gpiote_input_pin_config_t input_config = { + .p_pull_config = &pull_config, + .p_trigger_config = &trigger_config, + .p_handler_config = NULL, + }; nrfx_err_t res; - res = nrfx_gpiote_channel_alloc(&ch); + res = nrfx_gpiote_channel_alloc(gpiote, &ch); if (res != NRFX_SUCCESS) { return -ENODEV; } - res = nrfx_gpiote_input_configure(wake_pin, - &input_config, - &trigger_config, - NULL); + res = nrfx_gpiote_input_configure(gpiote, wake_pin, &input_config); if (res != NRFX_SUCCESS) { - nrfx_gpiote_channel_free(ch); + nrfx_gpiote_channel_free(gpiote, ch); return -EIO; } return 0; } -int spi_nrfx_wake_request(uint32_t wake_pin) +int spi_nrfx_wake_request(const nrfx_gpiote_t *gpiote, uint32_t wake_pin) { - nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(wake_pin); + nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(gpiote, wake_pin); uint32_t start_cycles; uint32_t max_wait_cycles = DIV_ROUND_UP(CONFIG_SPI_NRFX_WAKE_TIMEOUT_US * @@ -51,7 +50,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) * The expected time to wait is quite short so it is not worth paying * the overhead of context switching to handle the interrupt. */ - nrfx_gpiote_trigger_enable(wake_pin, false); + nrfx_gpiote_trigger_enable(gpiote, wake_pin, false); /* Enable pull-up on the WAKE line. After the slave device sees the * WAKE line going high, it will force the line to go low. This will * be caught by the enabled trigger and the loop below waits for that. @@ -59,7 +58,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLUP); start_cycles = k_cycle_get_32(); - while (!nrf_gpiote_event_check(NRF_GPIOTE, trigger_event)) { + while (!nrf_gpiote_event_check(gpiote->p_reg, trigger_event)) { uint32_t elapsed_cycles = k_cycle_get_32() - start_cycles; if (elapsed_cycles >= max_wait_cycles) { @@ -68,7 +67,7 @@ int spi_nrfx_wake_request(uint32_t wake_pin) } } - nrfx_gpiote_trigger_disable(wake_pin); + nrfx_gpiote_trigger_disable(gpiote, wake_pin); nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLDOWN); return err; diff --git a/drivers/spi/spi_nrfx_common.h b/drivers/spi/spi_nrfx_common.h index 515ed5c6f1f..0cf17e2a035 100644 --- a/drivers/spi/spi_nrfx_common.h +++ b/drivers/spi/spi_nrfx_common.h @@ -8,10 +8,17 @@ #define ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ #include +#include #define WAKE_PIN_NOT_USED UINT32_MAX -int spi_nrfx_wake_init(uint32_t wake_pin); -int spi_nrfx_wake_request(uint32_t wake_pin); +#define WAKE_GPIOTE_INSTANCE(node_id) \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, wake_gpios), \ + (NRFX_GPIOTE_INSTANCE( \ + NRF_DT_GPIOTE_INST(node_id, wake_gpios))), \ + ({0})) + +int spi_nrfx_wake_init(const nrfx_gpiote_t *gpiote, uint32_t wake_pin); +int spi_nrfx_wake_request(const nrfx_gpiote_t *gpiote, uint32_t wake_pin); #endif /* ZEPHYR_DRIVERS_SPI_NRFX_COMMON_H_ */ diff --git a/drivers/spi/spi_nrfx_spi.c b/drivers/spi/spi_nrfx_spi.c index fd1dc5d933c..752132fb248 100644 --- a/drivers/spi/spi_nrfx_spi.c +++ b/drivers/spi/spi_nrfx_spi.c @@ -31,6 +31,7 @@ struct spi_nrfx_config { void (*irq_connect)(void); const struct pinctrl_dev_config *pcfg; uint32_t wake_pin; + nrfx_gpiote_t wake_gpiote; }; static void event_handler(const nrfx_spi_evt_t *p_event, void *p_context); @@ -160,8 +161,6 @@ static void finish_transaction(const struct device *dev, int error) struct spi_nrfx_data *dev_data = dev->data; struct spi_context *ctx = &dev_data->ctx; - spi_context_cs_control(ctx, false); - LOG_DBG("Transaction finished with status %d", error); spi_context_complete(ctx, dev, error); @@ -237,7 +236,8 @@ static int transceive(const struct device *dev, dev_data->busy = true; if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - error = spi_nrfx_wake_request(dev_config->wake_pin); + error = spi_nrfx_wake_request(&dev_config->wake_gpiote, + dev_config->wake_pin); if (error == -ETIMEDOUT) { LOG_WRN("Waiting for WAKE acknowledgment timed out"); /* If timeout occurs, try to perform the transfer @@ -275,6 +275,8 @@ static int transceive(const struct device *dev, /* Clean up the driver state. */ k_sem_reset(&dev_data->ctx.sync); } + + spi_context_cs_control(&dev_data->ctx, false); } spi_context_release(&dev_data->ctx, error); @@ -381,7 +383,7 @@ static int spi_nrfx_init(const struct device *dev) } if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - err = spi_nrfx_wake_init(dev_config->wake_pin); + err = spi_nrfx_wake_init(&dev_config->wake_gpiote, dev_config->wake_pin); if (err == -ENODEV) { LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); return err; @@ -444,6 +446,7 @@ static int spi_nrfx_init(const struct device *dev) .pcfg = PINCTRL_DT_DEV_CONFIG_GET(SPI(idx)), \ .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPI(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ + .wake_gpiote = WAKE_GPIOTE_INSTANCE(SPI(idx)), \ }; \ BUILD_ASSERT(!DT_NODE_HAS_PROP(SPI(idx), wake_gpios) || \ !(DT_GPIO_FLAGS(SPI(idx), wake_gpios) & GPIO_ACTIVE_LOW), \ diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c index 8b187f54c52..08012b389c5 100644 --- a/drivers/spi/spi_nrfx_spim.c +++ b/drivers/spi/spi_nrfx_spim.c @@ -9,11 +9,12 @@ #include #include #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 -#include #include #endif -#include +#ifdef CONFIG_SOC_NRF5340_CPUAPP #include +#endif +#include #include #include @@ -40,8 +41,9 @@ struct spi_nrfx_data { size_t chunk_len; bool busy; bool initialized; -#if SPI_BUFFER_IN_RAM - uint8_t *buffer; +#ifdef SPI_BUFFER_IN_RAM + uint8_t *tx_buffer; + uint8_t *rx_buffer; #endif #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 bool anomaly_58_workaround_active; @@ -61,6 +63,7 @@ struct spi_nrfx_config { bool anomaly_58_workaround; #endif uint32_t wake_pin; + nrfx_gpiote_t wake_gpiote; }; static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context); @@ -69,9 +72,9 @@ static inline uint32_t get_nrf_spim_frequency(uint32_t frequency) { /* Get the highest supported frequency not exceeding the requested one. */ - if (frequency >= MHZ(32) && NRF_SPIM_HAS_32_MHZ_FREQ) { + if (frequency >= MHZ(32) && (NRF_SPIM_HAS_32_MHZ_FREQ || NRF_SPIM_HAS_PRESCALER)) { return MHZ(32); - } else if (frequency >= MHZ(16) && NRF_SPIM_HAS_16_MHZ_FREQ) { + } else if (frequency >= MHZ(16) && (NRF_SPIM_HAS_16_MHZ_FREQ || NRF_SPIM_HAS_PRESCALER)) { return MHZ(16); } else if (frequency >= MHZ(8)) { return MHZ(8); @@ -204,6 +207,8 @@ static int configure(const struct device *dev, } #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 +static const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(0); + /* * Brief Workaround for transmitting 1 byte with SPIM. * @@ -223,15 +228,15 @@ static void anomaly_58_workaround_setup(const struct device *dev) NRF_SPIM_Type *spim = dev_config->spim.p_reg; uint32_t ppi_ch = dev_data->ppi_ch; uint32_t gpiote_ch = dev_data->gpiote_ch; - uint32_t eep = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_ch]; + uint32_t eep = (uint32_t)&gpiote.p_reg->EVENTS_IN[gpiote_ch]; uint32_t tep = (uint32_t)&spim->TASKS_STOP; dev_data->anomaly_58_workaround_active = true; /* Create an event when SCK toggles */ - nrf_gpiote_event_configure(NRF_GPIOTE, gpiote_ch, spim->PSEL.SCK, + nrf_gpiote_event_configure(gpiote.p_reg, gpiote_ch, spim->PSEL.SCK, GPIOTE_CONFIG_POLARITY_Toggle); - nrf_gpiote_event_enable(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_event_enable(gpiote.p_reg, gpiote_ch); /* Stop the spim instance when SCK toggles */ nrf_ppi_channel_endpoint_setup(NRF_PPI, ppi_ch, eep, tep); @@ -250,7 +255,7 @@ static void anomaly_58_workaround_clear(struct spi_nrfx_data *dev_data) if (dev_data->anomaly_58_workaround_active) { nrf_ppi_channel_disable(NRF_PPI, ppi_ch); - nrf_gpiote_task_disable(NRF_GPIOTE, gpiote_ch); + nrf_gpiote_task_disable(gpiote.p_reg, gpiote_ch); dev_data->anomaly_58_workaround_active = false; } @@ -271,7 +276,7 @@ static int anomaly_58_workaround_init(const struct device *dev) return -ENODEV; } - err_code = nrfx_gpiote_channel_alloc(&dev_data->gpiote_ch); + err_code = nrfx_gpiote_channel_alloc(&gpiote, &dev_data->gpiote_ch); if (err_code != NRFX_SUCCESS) { LOG_ERR("Failed to allocate GPIOTE channel"); return -ENODEV; @@ -289,8 +294,6 @@ static void finish_transaction(const struct device *dev, int error) struct spi_nrfx_data *dev_data = dev->data; struct spi_context *ctx = &dev_data->ctx; - spi_context_cs_control(ctx, false); - LOG_DBG("Transaction finished with status %d", error); spi_context_complete(ctx, dev, error); @@ -310,25 +313,40 @@ static void transfer_next_chunk(const struct device *dev) nrfx_spim_xfer_desc_t xfer; nrfx_err_t result; const uint8_t *tx_buf = ctx->tx_buf; -#if (CONFIG_SPI_NRFX_RAM_BUFFER_SIZE > 0) - if (spi_context_tx_buf_on(ctx) && !nrfx_is_in_ram(tx_buf)) { + uint8_t *rx_buf = ctx->rx_buf; + + if (chunk_len > dev_config->max_chunk_len) { + chunk_len = dev_config->max_chunk_len; + } + +#ifdef SPI_BUFFER_IN_RAM + if (spi_context_tx_buf_on(ctx) && + !nrf_dma_accessible_check(&dev_config->spim.p_reg, tx_buf)) { + if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; } - memcpy(dev_data->buffer, tx_buf, chunk_len); - tx_buf = dev_data->buffer; + memcpy(dev_data->tx_buffer, tx_buf, chunk_len); + tx_buf = dev_data->tx_buffer; } -#endif - if (chunk_len > dev_config->max_chunk_len) { - chunk_len = dev_config->max_chunk_len; + + if (spi_context_rx_buf_on(ctx) && + !nrf_dma_accessible_check(&dev_config->spim.p_reg, rx_buf)) { + + if (chunk_len > CONFIG_SPI_NRFX_RAM_BUFFER_SIZE) { + chunk_len = CONFIG_SPI_NRFX_RAM_BUFFER_SIZE; + } + + rx_buf = dev_data->rx_buffer; } +#endif dev_data->chunk_len = chunk_len; xfer.p_tx_buffer = tx_buf; xfer.tx_length = spi_context_tx_buf_on(ctx) ? chunk_len : 0; - xfer.p_rx_buffer = ctx->rx_buf; + xfer.p_rx_buffer = rx_buf; xfer.rx_length = spi_context_rx_buf_on(ctx) ? chunk_len : 0; #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 @@ -372,6 +390,15 @@ static void event_handler(const nrfx_spim_evt_t *p_event, void *p_context) #ifdef CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 anomaly_58_workaround_clear(dev_data); +#endif +#ifdef SPI_BUFFER_IN_RAM + if (spi_context_rx_buf_on(&dev_data->ctx) && + p_event->xfer_desc.p_rx_buffer != NULL && + p_event->xfer_desc.p_rx_buffer != dev_data->ctx.rx_buf) { + (void)memcpy(dev_data->ctx.rx_buf, + dev_data->rx_buffer, + dev_data->chunk_len); + } #endif spi_context_update_tx(&dev_data->ctx, 1, dev_data->chunk_len); spi_context_update_rx(&dev_data->ctx, 1, dev_data->chunk_len); @@ -399,7 +426,8 @@ static int transceive(const struct device *dev, dev_data->busy = true; if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - error = spi_nrfx_wake_request(dev_config->wake_pin); + error = spi_nrfx_wake_request(&dev_config->wake_gpiote, + dev_config->wake_pin); if (error == -ETIMEDOUT) { LOG_WRN("Waiting for WAKE acknowledgment timed out"); /* If timeout occurs, try to perform the transfer @@ -440,6 +468,8 @@ static int transceive(const struct device *dev, anomaly_58_workaround_clear(dev_data); #endif } + + spi_context_cs_control(&dev_data->ctx, false); } spi_context_release(&dev_data->ctx, error); @@ -547,7 +577,7 @@ static int spi_nrfx_init(const struct device *dev) } if (dev_config->wake_pin != WAKE_PIN_NOT_USED) { - err = spi_nrfx_wake_init(dev_config->wake_pin); + err = spi_nrfx_wake_init(&dev_config->wake_gpiote, dev_config->wake_pin); if (err == -ENODEV) { LOG_ERR("Failed to allocate GPIOTE channel for WAKE"); return err; @@ -599,7 +629,10 @@ static int spi_nrfx_init(const struct device *dev) nrfx_isr, nrfx_spim_##idx##_irq_handler, 0); \ } \ IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (static uint8_t spim_##idx##_buffer \ + (static uint8_t spim_##idx##_tx_buffer \ + [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ + SPIM_MEMORY_SECTION(idx); \ + static uint8_t spim_##idx##_rx_buffer \ [CONFIG_SPI_NRFX_RAM_BUFFER_SIZE] \ SPIM_MEMORY_SECTION(idx);)) \ static struct spi_nrfx_data spi_##idx##_data = { \ @@ -607,7 +640,8 @@ static int spi_nrfx_init(const struct device *dev) SPI_CONTEXT_INIT_SYNC(spi_##idx##_data, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(SPIM(idx), ctx) \ IF_ENABLED(SPI_BUFFER_IN_RAM, \ - (.buffer = spim_##idx##_buffer,)) \ + (.tx_buffer = spim_##idx##_tx_buffer, \ + .rx_buffer = spim_##idx##_rx_buffer,)) \ .dev = DEVICE_DT_GET(SPIM(idx)), \ .busy = false, \ }; \ @@ -634,8 +668,9 @@ static int spi_nrfx_init(const struct device *dev) ()) \ .wake_pin = NRF_DT_GPIOS_TO_PSEL_OR(SPIM(idx), wake_gpios, \ WAKE_PIN_NOT_USED), \ + .wake_gpiote = WAKE_GPIOTE_INSTANCE(SPIM(idx)), \ }; \ - BUILD_ASSERT(!DT_NODE_HAS_PROP(SPIM(idx), wake_gpios) || \ + BUILD_ASSERT(!SPIM_HAS_PROP(idx, wake_gpios) || \ !(DT_GPIO_FLAGS(SPIM(idx), wake_gpios) & GPIO_ACTIVE_LOW),\ "WAKE line must be configured as active high"); \ PM_DEVICE_DT_DEFINE(SPIM(idx), spim_nrfx_pm_action); \ diff --git a/drivers/spi/spi_numaker.c b/drivers/spi/spi_numaker.c index 372f96271ad..eda34014ebb 100644 --- a/drivers/spi/spi_numaker.c +++ b/drivers/spi/spi_numaker.c @@ -270,8 +270,10 @@ static int spi_numaker_release(const struct device *dev, const struct spi_config return 0; } -static struct spi_driver_api spi_numaker_driver_api = {.transceive = spi_numaker_transceive, - .release = spi_numaker_release}; +static const struct spi_driver_api spi_numaker_driver_api = { + .transceive = spi_numaker_transceive, + .release = spi_numaker_release +}; static int spi_numaker_init(const struct device *dev) { diff --git a/drivers/spi/spi_oc_simple.c b/drivers/spi/spi_oc_simple.c index 3b8f9c126cf..a0f7296b2a9 100644 --- a/drivers/spi/spi_oc_simple.c +++ b/drivers/spi/spi_oc_simple.c @@ -179,7 +179,7 @@ int spi_oc_simple_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_oc_simple_api = { +static const struct spi_driver_api spi_oc_simple_api = { .transceive = spi_oc_simple_transceive, .release = spi_oc_simple_release, #ifdef CONFIG_SPI_ASYNC diff --git a/drivers/spi/spi_opentitan.c b/drivers/spi/spi_opentitan.c index 3116315d929..c3ed64c4a2e 100644 --- a/drivers/spi/spi_opentitan.c +++ b/drivers/spi/spi_opentitan.c @@ -169,7 +169,7 @@ static void spi_opentitan_xfer(const struct device *dev, const bool gpio_cs_cont } /* Keep CS asserted if another Tx segment remains or if two more Rx - * segements remain (because we will handle one Rx segment after the + * segments remain (because we will handle one Rx segment after the * forthcoming transaction). */ if (ctx->tx_count > 0 || ctx->rx_count > 1) { @@ -301,7 +301,7 @@ static int spi_opentitan_release(const struct device *dev, /* Device Instantiation */ -static struct spi_driver_api spi_opentitan_api = { +static const struct spi_driver_api spi_opentitan_api = { .transceive = spi_opentitan_transceive, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_opentitan_transceive_async, diff --git a/drivers/spi/spi_pl022.c b/drivers/spi/spi_pl022.c index 29f92d3050c..ed30dddf1e1 100644 --- a/drivers/spi/spi_pl022.c +++ b/drivers/spi/spi_pl022.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -266,13 +268,20 @@ struct spi_pl022_dma_data { /* * Max frequency */ -#define MAX_FREQ_CONTROLLER_MODE(cfg) (cfg->pclk / 2) -#define MAX_FREQ_PERIPHERAL_MODE(cfg) (cfg->pclk / 12) +#define MAX_FREQ_CONTROLLER_MODE(pclk) ((pclk) / 2) +#define MAX_FREQ_PERIPHERAL_MODE(pclk) ((pclk) / 12) struct spi_pl022_cfg { const uint32_t reg; const uint32_t pclk; const bool dma_enabled; +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + const struct device *clk_dev; + const clock_control_subsys_t clk_id; +#endif +#if IS_ENABLED(CONFIG_RESET) + const struct reset_dt_spec reset; +#endif #if defined(CONFIG_PINCTRL) const struct pinctrl_dev_config *pincfg; #endif @@ -336,15 +345,25 @@ static int spi_pl022_configure(const struct device *dev, const uint16_t op = spicfg->operation; uint32_t prescale; uint32_t postdiv; + uint32_t pclk = 0; uint32_t cr0; uint32_t cr1; + int ret; if (spi_context_configured(&data->ctx, spicfg)) { return 0; } - if (spicfg->frequency > MAX_FREQ_CONTROLLER_MODE(cfg)) { - LOG_ERR("Frequency is up to %u in controller mode.", MAX_FREQ_CONTROLLER_MODE(cfg)); +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + ret = clock_control_get_rate(cfg->clk_dev, cfg->clk_id, &pclk); + if (ret < 0 || pclk == 0) { + return -EINVAL; + } +#endif + + if (spicfg->frequency > MAX_FREQ_CONTROLLER_MODE(pclk)) { + LOG_ERR("Frequency is up to %u in controller mode.", + MAX_FREQ_CONTROLLER_MODE(pclk)); return -ENOTSUP; } @@ -373,8 +392,8 @@ static int spi_pl022_configure(const struct device *dev, /* configure registers */ - prescale = spi_pl022_calc_prescale(cfg->pclk, spicfg->frequency); - postdiv = spi_pl022_calc_postdiv(cfg->pclk, spicfg->frequency, prescale); + prescale = spi_pl022_calc_prescale(pclk, spicfg->frequency); + postdiv = spi_pl022_calc_postdiv(pclk, spicfg->frequency, prescale); cr0 = 0; cr0 |= (postdiv << SSP_CR0_SCR_LSB); @@ -867,7 +886,7 @@ static int spi_pl022_release(const struct device *dev, return 0; } -static struct spi_driver_api spi_pl022_api = { +static const struct spi_driver_api spi_pl022_api = { .transceive = spi_pl022_transceive, #if defined(CONFIG_SPI_ASYNC) .transceive_async = spi_pl022_transceive_async, @@ -887,6 +906,25 @@ static int spi_pl022_init(const struct device *dev) struct spi_pl022_data *data = dev->data; int ret; +#if IS_ENABLED(CONFIG_CLOCK_CONTROL) + if (cfg->clk_dev) { + ret = clock_control_on(cfg->clk_dev, cfg->clk_id); + if (ret < 0) { + LOG_ERR("Failed to enable the clock"); + return ret; + } + } +#endif + +#if IS_ENABLED(CONFIG_RESET) + if (cfg->reset.dev) { + ret = reset_line_toggle_dt(&cfg->reset); + if (ret < 0) { + return ret; + } + } +#endif + #if defined(CONFIG_PINCTRL) ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { @@ -952,6 +990,11 @@ static int spi_pl022_init(const struct device *dev) #define DMAS_ENABLED(idx) (DT_INST_DMAS_HAS_NAME(idx, tx) && DT_INST_DMAS_HAS_NAME(idx, rx)) +#define CLOCK_ID_DECL(idx) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(0, clocks), \ + (static const clock_control_subsys_t pl022_clk_id##idx = \ + (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id);)) \ + #define SPI_PL022_INIT(idx) \ IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(idx);)) \ IF_ENABLED(CONFIG_SPI_PL022_INTERRUPT, \ @@ -961,13 +1004,18 @@ static int spi_pl022_init(const struct device *dev) spi_pl022_isr, DEVICE_DT_INST_GET(idx), 0); \ irq_enable(DT_INST_IRQN(idx)); \ })) \ + IF_ENABLED(CONFIG_CLOCK_CONTROL, (CLOCK_ID_DECL(idx))) \ static struct spi_pl022_data spi_pl022_data_##idx = { \ SPI_CONTEXT_INIT_LOCK(spi_pl022_data_##idx, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_pl022_data_##idx, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(idx), ctx)}; \ static struct spi_pl022_cfg spi_pl022_cfg_##idx = { \ .reg = DT_INST_REG_ADDR(idx), \ - .pclk = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency), \ + IF_ENABLED(CONFIG_CLOCK_CONTROL, (IF_ENABLED(DT_INST_NODE_HAS_PROP(0, clocks), \ + (.clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = pl022_clk_id##idx,)))) \ + IF_ENABLED(CONFIG_RESET, (IF_ENABLED(DT_INST_NODE_HAS_PROP(0, resets), \ + (.reset = RESET_DT_SPEC_INST_GET(idx),)))) \ IF_ENABLED(CONFIG_PINCTRL, (.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx),)) \ IF_ENABLED(CONFIG_SPI_PL022_DMA, (.dma = DMAS_DECL(idx),)) COND_CODE_1( \ CONFIG_SPI_PL022_DMA, (.dma_enabled = DMAS_ENABLED(idx),), \ diff --git a/drivers/spi/spi_pw.c b/drivers/spi/spi_pw.c index e6f4061c6e2..fa100f054e0 100644 --- a/drivers/spi/spi_pw.c +++ b/drivers/spi/spi_pw.c @@ -208,8 +208,8 @@ static void spi_pw_rx_thld_set(const struct device *dev, /* Rx threshold */ reg_data = spi_pw_reg_read(dev, PW_SPI_REG_SIRF); - reg_data = (uint32_t) ~(PW_SPI_WM_MASK); - reg_data = PW_SPI_SIRF_WM_DFLT; + reg_data &= (uint32_t) ~(PW_SPI_WM_MASK); + reg_data |= PW_SPI_SIRF_WM_DFLT; if (spi->ctx.rx_len && spi->ctx.rx_len < spi->fifo_depth) { reg_data = spi->ctx.rx_len - 1; } diff --git a/drivers/spi/spi_rpi_pico_pio.c b/drivers/spi/spi_rpi_pico_pio.c index 579c97e5cdd..ed5179e3466 100644 --- a/drivers/spi/spi_rpi_pico_pio.c +++ b/drivers/spi/spi_rpi_pico_pio.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(spi_pico_pio); #include #include +#include #include #include #include "spi_context.h" @@ -30,7 +31,8 @@ struct spi_pico_pio_config { struct gpio_dt_spec clk_gpio; struct gpio_dt_spec mosi_gpio; struct gpio_dt_spec miso_gpio; - const uint32_t clock_freq; + const struct device *clk_dev; + clock_control_subsys_t clk_id; }; struct spi_pico_pio_data { @@ -57,20 +59,19 @@ RPI_PICO_PIO_DEFINE_PROGRAM(spi_cpol_1_cpha_1, 0, 2, /* .wrap */ ); -static float spi_pico_pio_clock_divisor(const struct spi_pico_pio_config *dev_cfg, - uint32_t spi_frequency) +static float spi_pico_pio_clock_divisor(const uint32_t clock_freq, uint32_t spi_frequency) { - return (float)dev_cfg->clock_freq / (float)(PIO_CYCLES * spi_frequency); + return (float)clock_freq / (float)(PIO_CYCLES * spi_frequency); } -static uint32_t spi_pico_pio_maximum_clock_frequency(const struct spi_pico_pio_config *dev_cfg) +static uint32_t spi_pico_pio_maximum_clock_frequency(const uint32_t clock_freq) { - return dev_cfg->clock_freq / PIO_CYCLES; + return clock_freq / PIO_CYCLES; } -static uint32_t spi_pico_pio_minimum_clock_frequency(const struct spi_pico_pio_config *dev_cfg) +static uint32_t spi_pico_pio_minimum_clock_frequency(const uint32_t clock_freq) { - return dev_cfg->clock_freq / (PIO_CYCLES * 65536); + return clock_freq / (PIO_CYCLES * 65536); } static inline bool spi_pico_pio_transfer_ongoing(struct spi_pico_pio_data *data) @@ -109,10 +110,23 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, uint32_t cpol = 0; uint32_t cpha = 0; uint32_t bits; + uint32_t clock_freq; float clock_div; const pio_program_t *program; int rc; + rc = clock_control_on(dev_cfg->clk_dev, dev_cfg->clk_id); + if (rc < 0) { + LOG_ERR("Failed to enable the clock"); + return rc; + } + + rc = clock_control_get_rate(dev_cfg->clk_dev, dev_cfg->clk_id, &clock_freq); + if (rc < 0) { + LOG_ERR("Failed to get clock frequency"); + return rc; + } + if (spi_context_configured(&data->spi_ctx, spi_cfg)) { return 0; } @@ -143,13 +157,13 @@ static int spi_pico_pio_configure(const struct spi_pico_pio_config *dev_cfg, data->dfs = DIV_ROUND_UP(bits, 8); - if ((spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency(dev_cfg)) || - (spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency(dev_cfg))) { + if ((spi_cfg->frequency < spi_pico_pio_minimum_clock_frequency(clock_freq)) || + (spi_cfg->frequency > spi_pico_pio_maximum_clock_frequency(clock_freq))) { LOG_ERR("clock-frequency out of range"); return -EINVAL; } - clock_div = spi_pico_pio_clock_divisor(dev_cfg, spi_cfg->frequency); + clock_div = spi_pico_pio_clock_divisor(clock_freq, spi_cfg->frequency); /* Half-duplex mode has not been implemented */ if (spi_cfg->operation & SPI_HALF_DUPLEX) { @@ -316,7 +330,7 @@ int spi_pico_pio_release(const struct device *dev, const struct spi_config *spi_ return 0; } -static struct spi_driver_api spi_pico_pio_api = { +static const struct spi_driver_api spi_pico_pio_api = { .transceive = spi_pico_pio_transceive, .release = spi_pico_pio_release, }; @@ -352,7 +366,8 @@ int spi_pico_pio_init(const struct device *dev) .clk_gpio = GPIO_DT_SPEC_INST_GET(inst, clk_gpios), \ .mosi_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, mosi_gpios, {0}), \ .miso_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, miso_gpios, {0}), \ - .clock_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(inst, clocks, 0, clk_id), \ }; \ static struct spi_pico_pio_data spi_pico_pio_data_##inst = { \ SPI_CONTEXT_INIT_LOCK(spi_pico_pio_data_##inst, spi_ctx), \ diff --git a/drivers/spi/spi_rv32m1_lpspi.c b/drivers/spi/spi_rv32m1_lpspi.c index 33911374225..282e59b4adc 100644 --- a/drivers/spi/spi_rv32m1_lpspi.c +++ b/drivers/spi/spi_rv32m1_lpspi.c @@ -19,6 +19,8 @@ #include LOG_MODULE_REGISTER(spi_rv32m1_lpspi); +#include + #include "spi_context.h" #define CHIP_SELECT_COUNT 4 diff --git a/drivers/spi/spi_sifive.c b/drivers/spi/spi_sifive.c index c302e67ba80..1b5f178c2a6 100644 --- a/drivers/spi/spi_sifive.c +++ b/drivers/spi/spi_sifive.c @@ -272,7 +272,7 @@ static int spi_sifive_release(const struct device *dev, /* Device Instantiation */ -static struct spi_driver_api spi_sifive_api = { +static const struct spi_driver_api spi_sifive_api = { .transceive = spi_sifive_transceive, .release = spi_sifive_release, }; diff --git a/drivers/spi/spi_xec_qmspi_ldma.c b/drivers/spi/spi_xec_qmspi_ldma.c index ab48e49c095..a95a28fc176 100644 --- a/drivers/spi/spi_xec_qmspi_ldma.c +++ b/drivers/spi/spi_xec_qmspi_ldma.c @@ -215,7 +215,7 @@ static int qmspi_set_frequency(struct spi_qmspi_data *qdata, struct qmspi_regs * * SPI signalling mode: CPOL and CPHA * CPOL = 0 is clock idles low, 1 is clock idle high * CPHA = 0 Transmitter changes data on trailing of preceding clock cycle. - * Receiver samples data on leading edge of clock cyle. + * Receiver samples data on leading edge of clock cycle. * 1 Transmitter changes data on leading edge of current clock cycle. * Receiver samples data on the trailing edge of clock cycle. * SPI Mode nomenclature: @@ -475,7 +475,7 @@ static inline int qmspi_xfr_cm_init(const struct device *dev, * RX data discard for certain SPI command protocols using dual/quad I/O. * 1. Get largest contiguous data size from SPI context. * 2. If the SPI TX context has a non-zero length configure Local-DMA TX - * channel 1 for contigous data size. If TX context has valid buffer + * channel 1 for contiguous data size. If TX context has valid buffer * configure channel to use context buffer with address increment. * If the TX buffer pointer is NULL interpret byte length as the number * of clocks to generate with output line(s) tri-stated. NOTE: The controller @@ -487,7 +487,7 @@ static inline int qmspi_xfr_cm_init(const struct device *dev, * For example, if I/O lines is 4 (quad) meaning 4 bits per clock and the * user wants 7 clocks then the number of bit units is 4 * 7 = 28. * 3. If instead, the SPI RX context has a non-zero length configure Local-DMA - * RX channel 1 for the contigous data size. If RX context has a valid + * RX channel 1 for the contiguous data size. If RX context has a valid * buffer configure channel to use buffer with address increment else * configure channel for driver data temporary buffer without address * increment. @@ -696,7 +696,7 @@ static int qmspi_xfr_start_async(const struct device *dev, const struct spi_buf_ return 0; } -/* Wrapper to start asynchronous (interrupts enabled) SPI transction */ +/* Wrapper to start asynchronous (interrupts enabled) SPI transaction */ static int qmspi_xfr_async(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 47a10b358c1..36534e4716f 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_MCUX_GPT_TIMER mcux_gpt_timer.c) zephyr_library_sources_ifdef(CONFIG_MIPS_CP0_TIMER mips_cp0_timer.c) zephyr_library_sources_ifdef(CONFIG_NATIVE_POSIX_TIMER native_posix_timer.c) zephyr_library_sources_ifdef(CONFIG_NPCX_ITIM_TIMER npcx_itim_timer.c) +zephyr_library_sources_ifdef(CONFIG_NRF_GRTC_TIMER nrf_grtc_timer.c) zephyr_library_sources_ifdef(CONFIG_NRF_RTC_TIMER nrf_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_RCAR_CMT_TIMER rcar_cmt_timer.c) zephyr_library_sources_ifdef(CONFIG_RISCV_MACHINE_TIMER riscv_machine_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 8a88e731986..f20442dd2c5 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -84,6 +84,8 @@ source "drivers/timer/Kconfig.mips_cp0" source "drivers/timer/Kconfig.native_posix" source "drivers/timer/Kconfig.npcx_itim" source "drivers/timer/Kconfig.nrf_rtc" +source "drivers/timer/Kconfig.nrf_grtc" +source "drivers/timer/Kconfig.nrf_xrtc" source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" source "drivers/timer/Kconfig.rv32m1_lptmr" diff --git a/drivers/timer/Kconfig.cortex_m_systick b/drivers/timer/Kconfig.cortex_m_systick index baf1f6c817e..2a4f48832cf 100644 --- a/drivers/timer/Kconfig.cortex_m_systick +++ b/drivers/timer/Kconfig.cortex_m_systick @@ -48,6 +48,7 @@ config CORTEX_M_SYSTICK_IDLE_TIMER default $(dt_chosen_enabled,$(DT_CHOSEN_IDLE_TIMER)) depends on COUNTER depends on TICKLESS_KERNEL + depends on PM help There are chips e.g. STMFX family that use SysTick as a system timer, but SysTick is not clocked in low power mode. These chips usually have diff --git a/drivers/timer/Kconfig.native_posix b/drivers/timer/Kconfig.native_posix index 6fe1c3bde4d..278feeec2a8 100644 --- a/drivers/timer/Kconfig.native_posix +++ b/drivers/timer/Kconfig.native_posix @@ -4,12 +4,12 @@ # SPDX-License-Identifier: Apache-2.0 config NATIVE_POSIX_TIMER - bool "(POSIX) native_posix timer driver" + bool "(POSIX) native_sim/posix timer driver" default y depends on BOARD_NATIVE_POSIX select TICKLESS_CAPABLE select TIMER_HAS_64BIT_CYCLE_COUNTER select SYSTEM_TIMER_HAS_DISABLE_SUPPORT help - This module implements a kernel device driver for the native_posix HW timer + This module implements a kernel device driver for the native_sim/posix HW timer model diff --git a/drivers/timer/Kconfig.nrf_grtc b/drivers/timer/Kconfig.nrf_grtc new file mode 100644 index 00000000000..442c524fd19 --- /dev/null +++ b/drivers/timer/Kconfig.nrf_grtc @@ -0,0 +1,48 @@ +# Timer driver configuration options +# Copyright (c) 2024 Nordic Semiconductor ASA + +menuconfig NRF_GRTC_TIMER + bool "nRF GRTC Timer" + default y if DT_HAS_NORDIC_NRF_GRTC_ENABLED + select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER + select NRFX_GRTC + help + This module implements a kernel device driver for the nRF Global Real + Time Counter NRF_GRTC and provides the standard "system clock driver" + interfaces. + +if NRF_GRTC_TIMER + +config NRF_GRTC_SLEEP_ALLOWED + def_bool y + depends on POWEROFF + help + This feature allows GRTC SYSCOUNTER to go to sleep state. + +config NRF_GRTC_TIMER_APP_DEFINED_INIT + bool "Application defines GRTC initialization" + help + Application defines the initialization procedure and time of the GRTC + drivers, rather than leaving it up to SYS_INIT. + +config NRF_GRTC_START_SYSCOUNTER + bool "Start SYSCOUNTER on driver init" + select NRF_GRTC_TIMER_CLOCK_MANAGEMENT + help + Start the SYSCOUNTER when initializing the GRTC. This should only be + handled by one processor in the system. + +config NRF_GRTC_TIMER_CLOCK_MANAGEMENT + bool + help + Compile additional driver code for enabling management functionality of + the GRTC. Usually this is only needed by the processor that is starting + the SYSCOUNTER, but can be shared by multiple processors in the system. + +config NRF_GRTC_SLEEP_MINIMUM_LATENCY + int + default 1000 + depends on NRF_GRTC_SLEEP_ALLOWED + +endif # NRF_GRTC_TIMER diff --git a/drivers/timer/Kconfig.nrf_rtc b/drivers/timer/Kconfig.nrf_rtc index baa917282bc..729dc8d362a 100644 --- a/drivers/timer/Kconfig.nrf_rtc +++ b/drivers/timer/Kconfig.nrf_rtc @@ -42,36 +42,4 @@ config NRF_RTC_TIMER_TRIGGER_OVERFLOW When enabled, a function can be used to trigger RTC overflow and effectively shift time into the future. -choice - prompt "Clock startup policy" - default SYSTEM_CLOCK_WAIT_FOR_STABILITY - -config SYSTEM_CLOCK_NO_WAIT - bool "No wait" - help - System clock source is initiated but does not wait for clock readiness. - When this option is picked, system clock may not be ready when code relying - on kernel API is executed. Requested timeouts will be prolonged by the - remaining startup time. - -config SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY - bool "Wait for availability" - help - System clock source initialization waits until clock is available. In some - systems, clock initially runs from less accurate source which has faster - startup time and then seamlessly switches to the target clock source when - it is ready. When this option is picked, system clock is available after - system clock driver initialization but it may be less accurate. Option is - equivalent to waiting for stability if clock source does not have - intermediate state. - -config SYSTEM_CLOCK_WAIT_FOR_STABILITY - bool "Wait for stability" - help - System clock source initialization waits until clock is stable. When this - option is picked, system clock is available and stable after system clock - driver initialization. - -endchoice - endif # NRF_RTC_TIMER diff --git a/drivers/timer/Kconfig.nrf_xrtc b/drivers/timer/Kconfig.nrf_xrtc new file mode 100644 index 00000000000..f9fa25a1c30 --- /dev/null +++ b/drivers/timer/Kconfig.nrf_xrtc @@ -0,0 +1,38 @@ +# Common RTC configuration + +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if NRF_RTC_TIMER || NRF_GRTC_TIMER +choice + prompt "Clock startup policy" + default SYSTEM_CLOCK_WAIT_FOR_STABILITY + +config SYSTEM_CLOCK_NO_WAIT + bool "No wait" + help + System clock source is initiated but does not wait for clock readiness. + When this option is picked, system clock may not be ready when code relying + on kernel API is executed. Requested timeouts will be prolonged by the + remaining startup time. + +config SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY + bool "Wait for availability" + help + System clock source initialization waits until clock is available. In some + systems, clock initially runs from less accurate source which has faster + startup time and then seamlessly switches to the target clock source when + it is ready. When this option is picked, system clock is available after + system clock driver initialization but it may be less accurate. Option is + equivalent to waiting for stability if clock source does not have + intermediate state. + +config SYSTEM_CLOCK_WAIT_FOR_STABILITY + bool "Wait for stability" + help + System clock source initialization waits until clock is stable. When this + option is picked, system clock is available and stable after system clock + driver initialization. + +endchoice +endif # NRF_RTC_TIMER || NRF_GRTC_TIMER diff --git a/drivers/timer/Kconfig.stm32_lptim b/drivers/timer/Kconfig.stm32_lptim index d1e0d5cb81a..31bddc07409 100644 --- a/drivers/timer/Kconfig.stm32_lptim +++ b/drivers/timer/Kconfig.stm32_lptim @@ -3,6 +3,8 @@ # Copyright (c) 2019 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 +DT_CHOSEN_STDBY_TIMER := st,lptim-stdby-timer + menuconfig STM32_LPTIM_TIMER bool "STM32 Low Power Timer [EXPERIMENTAL]" default y @@ -35,7 +37,7 @@ config STM32_LPTIM_CLOCK_LSE endchoice config STM32_LPTIM_CLOCK - int "LPTIM clock value" + int default 32768 if STM32_LPTIM_CLOCK_LSE default 32000 if STM32_LPTIM_CLOCK_LSI @@ -56,4 +58,22 @@ config STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE in the driver. This options allows to override this check +config STM32_LPTIM_STDBY_TIMER + bool "Use an additional timer while entering Standby mode" + default $(dt_chosen_enabled,$(DT_CHOSEN_STDBY_TIMER)) + depends on COUNTER + depends on TICKLESS_KERNEL + select EXPERIMENTAL + help + There are chips e.g. STM32WBAX family that use LPTIM as a system timer, + but LPTIM is not clocked in standby mode. These chips usually have + another timer that is not stopped, but it has lower frequency e.g. + RTC, thus it can't be used as a main system timer. + + Use the Standby timer for timeout (wakeup) when the system is entering + Standby state. + + The chosen Standby timer node has to support setting alarm from the + counter API. + endif # STM32_LPTIM_TIMER diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c index 5db803fb12d..8a469f35907 100644 --- a/drivers/timer/ambiq_stimer.c +++ b/drivers/timer/ambiq_stimer.c @@ -80,23 +80,15 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) return; } - k_spinlock_key_t key = k_spin_lock(&g_lock); - - uint64_t now = am_hal_stimer_counter_get(); - uint32_t adj, cyc = ticks * CYC_PER_TICK; - - /* Round up to next tick boundary. */ - adj = (uint32_t)(now - g_last_count) + (CYC_PER_TICK - 1); - if (cyc <= MAX_CYCLES - adj) { - cyc += adj; - } else { - cyc = MAX_CYCLES; + if (ticks == K_TICKS_FOREVER) { + return; } - cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK; - if ((int32_t)(cyc + g_last_count - now) < MIN_DELAY) { - cyc += CYC_PER_TICK; - } + ticks = MIN(MAX_TICKS, ticks); + /* If tick is 0, set delta cyc to MIN_DELAY to trigger tick isr asap */ + uint32_t cyc = MAX(ticks * CYC_PER_TICK, MIN_DELAY); + + k_spinlock_key_t key = k_spin_lock(&g_lock); am_hal_stimer_compare_delta_set(0, cyc); @@ -142,7 +134,10 @@ static int stimer_init(void) irq_enable(TIMER_IRQ); am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREA); - + /* Start timer with period CYC_PER_TICK if tickless is not enabled */ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + am_hal_stimer_compare_delta_set(0, CYC_PER_TICK); + } return 0; } diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c index a9a762d9afa..718fecea582 100644 --- a/drivers/timer/arm_arch_timer.c +++ b/drivers/timer/arm_arch_timer.c @@ -20,6 +20,14 @@ static uint32_t cyc_per_tick; / CONFIG_SYS_CLOCK_TICKS_PER_SEC) #endif +#if defined(CONFIG_GDBSTUB) +/* When interactively debugging, the cycle diff can overflow 32-bit variable */ +#define TO_CYCLE_DIFF(x) (x) +#else +/* Convert to 32-bit for fast division */ +#define TO_CYCLE_DIFF(x) ((cycle_diff_t)(x)) +#endif + /* the unsigned long cast limits divisors to native CPU register width */ #define cycle_diff_t unsigned long @@ -58,7 +66,7 @@ static void arm_arch_timer_compare_isr(const void *arg) uint64_t curr_cycle = arm_arch_timer_count(); uint64_t delta_cycles = curr_cycle - last_cycle; - uint32_t delta_ticks = (cycle_diff_t)delta_cycles / CYC_PER_TICK; + uint32_t delta_ticks = TO_CYCLE_DIFF(delta_cycles) / CYC_PER_TICK; last_cycle += (cycle_diff_t)delta_ticks * CYC_PER_TICK; last_tick += delta_ticks; diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 13e499efec4..b5f859ae57c 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -368,14 +368,22 @@ void sys_clock_idle_exit(void) if (timeout_idle) { cycle_t systick_diff, missed_cycles; uint32_t idle_timer_diff, idle_timer_post, dcycles, dticks; - uint64_t systick_us, idle_timer_us, measurement_diff_us; + uint64_t systick_us, idle_timer_us; /* Get current values for both timers */ counter_get_value(idle_timer, &idle_timer_post); systick_diff = cycle_count + elapsed() - cycle_pre_idle; /* Calculate has much time has pasted since last measurement for both timers */ - idle_timer_diff = idle_timer_post - idle_timer_pre_idle; + /* Check IDLE timer overflow */ + if (idle_timer_pre_idle > idle_timer_post) { + idle_timer_diff = + (counter_get_top_value(idle_timer) - idle_timer_pre_idle) + + idle_timer_post + 1; + + } else { + idle_timer_diff = idle_timer_post - idle_timer_pre_idle; + } idle_timer_us = counter_ticks_to_us(idle_timer, idle_timer_diff); systick_us = ((uint64_t)systick_diff * USEC_PER_SEC) / sys_clock_hw_cycles_per_sec(); @@ -383,9 +391,20 @@ void sys_clock_idle_exit(void) /* Calculate difference in measurements to get how much time * the SysTick missed in idle state. */ - measurement_diff_us = idle_timer_us - systick_us; - missed_cycles = - (sys_clock_hw_cycles_per_sec() * measurement_diff_us) / USEC_PER_SEC; + if (idle_timer_us < systick_us) { + /* This case is possible, when the time in low power mode is + * very short or 0. SysTick usually has higher measurement + * resolution of than the IDLE timer, thus the measurement of + * passed time since the sys_clock_set_timeout call can be higher. + */ + missed_cycles = 0; + } else { + uint64_t measurement_diff_us; + + measurement_diff_us = idle_timer_us - systick_us; + missed_cycles = (sys_clock_hw_cycles_per_sec() * measurement_diff_us) / + USEC_PER_SEC; + } /* Update the cycle counter to include the cycles missed in idle */ cycle_count += missed_cycles; diff --git a/drivers/timer/ite_it8xxx2_timer.c b/drivers/timer/ite_it8xxx2_timer.c index c29c978d189..69d42790ac7 100644 --- a/drivers/timer/ite_it8xxx2_timer.c +++ b/drivers/timer/ite_it8xxx2_timer.c @@ -16,6 +16,8 @@ #include LOG_MODULE_REGISTER(timer, LOG_LEVEL_ERR); +#define COUNT_1US (EC_FREQ / USEC_PER_SEC - 1) + BUILD_ASSERT(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 32768, "ITE RTOS timer HW frequency is fixed at 32768Hz"); @@ -332,8 +334,8 @@ static int timer_init(enum ext_timer_idx ext_timer, hw_cnt = MS_TO_COUNT(1024, ms); else if (clock_source_sel == EXT_PSR_32) hw_cnt = MS_TO_COUNT(32, ms); - else if (clock_source_sel == EXT_PSR_8M) - hw_cnt = 8000 * ms; + else if (clock_source_sel == EXT_PSR_EC_CLK) + hw_cnt = MS_TO_COUNT(EC_FREQ, ms); else { LOG_ERR("Timer %d clock source error !", ext_timer); return -1; @@ -424,7 +426,7 @@ static int sys_clock_driver_init(void) IT8XXX2_EXT_CTRLX(BUSY_WAIT_L_TIMER) |= IT8XXX2_EXT_ETXCOMB; /* Set 32-bit timer6 to count-- every 1us */ - ret = timer_init(BUSY_WAIT_H_TIMER, EXT_PSR_8M, EXT_RAW_CNT, + ret = timer_init(BUSY_WAIT_H_TIMER, EXT_PSR_EC_CLK, EXT_RAW_CNT, BUSY_WAIT_TIMER_H_MAX_CNT, EXT_FIRST_TIME_ENABLE, BUSY_WAIT_H_TIMER_IRQ, BUSY_WAIT_H_TIMER_FLAG, EXT_WITHOUT_TIMER_INT, EXT_START_TIMER); @@ -438,11 +440,12 @@ static int sys_clock_driver_init(void) * NOTE: When the timer5 count down to overflow in combinational * mode, timer6 counter will automatically decrease one count * and timer5 will automatically re-start counting down - * from 0x7. Timer5 clock source is 8MHz (=0.125ns), so the - * time period from 0x7 to overflow is 0.125ns * 8 = 1us. + * from COUNT_1US. Timer5 clock source is EC_FREQ, so the + * time period from COUNT_1US to overflow is + * (1 / EC_FREQ) * (EC_FREQ / USEC_PER_SEC) = 1us. */ - ret = timer_init(BUSY_WAIT_L_TIMER, EXT_PSR_8M, EXT_RAW_CNT, - 0x7, EXT_FIRST_TIME_ENABLE, + ret = timer_init(BUSY_WAIT_L_TIMER, EXT_PSR_EC_CLK, EXT_RAW_CNT, + COUNT_1US, EXT_FIRST_TIME_ENABLE, BUSY_WAIT_L_TIMER_IRQ, BUSY_WAIT_L_TIMER_FLAG, EXT_WITHOUT_TIMER_INT, EXT_START_TIMER); if (ret < 0) { diff --git a/drivers/timer/litex_timer.c b/drivers/timer/litex_timer.c index ecc5b22a9d9..c12630eba34 100644 --- a/drivers/timer/litex_timer.c +++ b/drivers/timer/litex_timer.c @@ -13,6 +13,8 @@ #include #include +#include + #define TIMER_LOAD_ADDR DT_INST_REG_ADDR_BY_NAME(0, load) #define TIMER_RELOAD_ADDR DT_INST_REG_ADDR_BY_NAME(0, reload) #define TIMER_EN_ADDR DT_INST_REG_ADDR_BY_NAME(0, en) diff --git a/drivers/timer/native_posix_timer.c b/drivers/timer/native_posix_timer.c index 31d1fc3bc69..7376034ef62 100644 --- a/drivers/timer/native_posix_timer.c +++ b/drivers/timer/native_posix_timer.c @@ -5,7 +5,7 @@ */ /** - * Driver for the timer model of the POSIX native_posix board + * Driver for the timer model of the POSIX native_sim/posix board * It provides the interfaces required by the kernel and the sanity testcases * It also provides a custom k_busy_wait() which can be used with the * POSIX arch and InfClock SOC diff --git a/drivers/timer/nrf_grtc_timer.c b/drivers/timer/nrf_grtc_timer.c new file mode 100644 index 00000000000..8ac357864cc --- /dev/null +++ b/drivers/timer/nrf_grtc_timer.c @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#if defined(CONFIG_CLOCK_CONTROL_NRF) +#include +#endif +#include +#include +#include +#include + +#define GRTC_NODE DT_NODELABEL(grtc) + +/* Ensure that GRTC properties in devicetree are defined correctly. */ +#if !DT_NODE_HAS_PROP(GRTC_NODE, owned_channels) +#error GRTC owned-channels DT property is not defined +#endif +#define OWNED_CHANNELS_MASK NRFX_CONFIG_GRTC_MASK_DT(owned_channels) +#define CHILD_OWNED_CHANNELS_MASK NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels) +#if ((OWNED_CHANNELS_MASK | CHILD_OWNED_CHANNELS_MASK) != OWNED_CHANNELS_MASK) +#error GRTC child-owned-channels DT property must be a subset of owned-channels +#endif + +#define CHAN_COUNT NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define EXT_CHAN_COUNT (CHAN_COUNT - 1) +/* The reset value of waketime is 1, which doesn't seem to work. + * It's being looked into, but for the time being use 4. + * Timeout must always be higher than waketime, so setting that to 5. + */ +#define WAKETIME (4) +#define TIMEOUT (WAKETIME + 1) + +#ifndef GRTC_SYSCOUNTERL_VALUE_Msk +#define GRTC_SYSCOUNTERL_VALUE_Msk GRTC_SYSCOUNTER_SYSCOUNTERL_VALUE_Msk +#endif + +#ifndef GRTC_SYSCOUNTERH_VALUE_Msk +#define GRTC_SYSCOUNTERH_VALUE_Msk GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Msk +#endif + +#define MAX_CC_LATCH_WAIT_TIME_US 77 + +#define CYC_PER_TICK \ + ((uint64_t)sys_clock_hw_cycles_per_sec() / (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +#define COUNTER_SPAN (GRTC_SYSCOUNTERL_VALUE_Msk | ((uint64_t)GRTC_SYSCOUNTERH_VALUE_Msk << 32)) +#define MAX_TICKS \ + (((COUNTER_SPAN / CYC_PER_TICK) > INT_MAX) ? INT_MAX : (COUNTER_SPAN / CYC_PER_TICK)) + +#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) + +/* The maximum SYSCOUNTERVALID settling time equals 1x32k cycles + 20x1MHz cycles. */ +#define GRTC_SYSCOUNTERVALID_SETTLE_MAX_TIME_US 51 + +#if defined(CONFIG_TEST) +const int32_t z_sys_timer_irq_for_test = DT_IRQN(GRTC_NODE); +#endif + +static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_context); + +static struct k_spinlock lock; +static uint64_t last_count; +static atomic_t int_mask; +static uint8_t ext_channels_allocated; +static nrfx_grtc_channel_t system_clock_channel_data = { + .handler = sys_clock_timeout_handler, + .p_context = NULL, + .channel = (uint8_t)-1, +}; + +#define IS_CHANNEL_ALLOWED_ASSERT(chan) \ + __ASSERT_NO_MSG((NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK & (1UL << (chan))) && \ + ((chan) != system_clock_channel_data.channel)) + +static inline void grtc_active_set(void) +{ +#if defined(NRF_GRTC_HAS_SYSCOUNTER_ARRAY) && (NRF_GRTC_HAS_SYSCOUNTER_ARRAY == 1) + nrfy_grtc_sys_counter_active_set(NRF_GRTC, true); + while (!nrfy_grtc_sys_conter_ready_check(NRF_GRTC)) { + } +#else + nrfy_grtc_sys_counter_active_state_request_set(NRF_GRTC, true); + k_busy_wait(GRTC_SYSCOUNTERVALID_SETTLE_MAX_TIME_US); +#endif +} + +static inline void grtc_wakeup(void) +{ + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + grtc_active_set(); + } +} + +static inline void grtc_sleep(void) +{ + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { +#if defined(NRF_GRTC_HAS_SYSCOUNTER_ARRAY) && (NRF_GRTC_HAS_SYSCOUNTER_ARRAY == 1) + nrfy_grtc_sys_counter_active_set(NRF_GRTC, false); +#else + nrfy_grtc_sys_counter_active_state_request_set(NRF_GRTC, false); +#endif + } +} + +static inline uint64_t counter_sub(uint64_t a, uint64_t b) +{ + return (a - b); +} + +static inline uint64_t counter(void) +{ + uint64_t now; + + grtc_wakeup(); + nrfx_grtc_syscounter_get(&now); + grtc_sleep(); + return now; +} + +static inline uint64_t get_comparator(uint32_t chan) +{ + uint64_t cc; + nrfx_err_t result; + + result = nrfx_grtc_syscounter_cc_value_read(chan, &cc); + if (result != NRFX_SUCCESS) { + if (result != NRFX_ERROR_INVALID_PARAM) { + return -EAGAIN; + } + return -EPERM; + } + return cc; +} + +static void system_timeout_set(uint64_t value) +{ + if (value <= NRF_GRTC_SYSCOUNTER_CCADD_MASK) { + grtc_wakeup(); + nrfx_grtc_syscounter_cc_relative_set(&system_clock_channel_data, value, true, + NRFX_GRTC_CC_RELATIVE_SYSCOUNTER); + grtc_sleep(); + } else { + nrfx_grtc_syscounter_cc_absolute_set(&system_clock_channel_data, value + counter(), + true); + } +} + +static bool compare_int_lock(int32_t chan) +{ + atomic_val_t prev = atomic_and(&int_mask, ~BIT(chan)); + + nrfx_grtc_syscounter_cc_int_disable(chan); + + return prev & BIT(chan); +} + +static void compare_int_unlock(int32_t chan, bool key) +{ + if (key) { + atomic_or(&int_mask, BIT(chan)); + nrfx_grtc_syscounter_cc_int_enable(chan); + } +} + +static void sys_clock_timeout_handler(int32_t id, uint64_t cc_val, void *p_context) +{ + ARG_UNUSED(id); + ARG_UNUSED(p_context); + uint64_t dticks; + uint64_t now = counter(); + + if (unlikely(now < cc_val)) { + return; + } + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + /* protection is not needed because we are in the GRTC interrupt + * so it won't get preempted by the interrupt. + */ + system_timeout_set(CYC_PER_TICK); + } + + dticks = counter_sub(now, last_count) / CYC_PER_TICK; + + last_count += dticks * CYC_PER_TICK; + sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? (int32_t)dticks : (dticks > 0)); +} + +int32_t z_nrf_grtc_timer_chan_alloc(void) +{ + uint8_t chan; + nrfx_err_t err_code; + + /* Prevent allocating all available channels - one must be left for system purposes. */ + if (ext_channels_allocated >= EXT_CHAN_COUNT) { + return -ENOMEM; + } + err_code = nrfx_grtc_channel_alloc(&chan); + if (err_code != NRFX_SUCCESS) { + return -ENOMEM; + } + ext_channels_allocated++; + return (int32_t)chan; +} + +void z_nrf_grtc_timer_chan_free(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + nrfx_err_t err_code = nrfx_grtc_channel_free(chan); + + if (err_code == NRFX_SUCCESS) { + ext_channels_allocated--; + } +} + +bool z_nrf_grtc_timer_compare_evt_check(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + uint32_t event_address = nrfx_grtc_event_compare_address_get(chan); + + return *(volatile uint32_t *)event_address != 0; +} + +uint32_t z_nrf_grtc_timer_compare_evt_address_get(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return nrfx_grtc_event_compare_address_get(chan); +} + +uint32_t z_nrf_grtc_timer_capture_task_address_get(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return nrfx_grtc_capture_task_address_get(chan); +} + +uint64_t z_nrf_grtc_timer_read(void) +{ + return counter(); +} + +bool z_nrf_grtc_timer_compare_int_lock(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return compare_int_lock(chan); +} + +void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + compare_int_unlock(chan, key); +} + +uint64_t z_nrf_grtc_timer_compare_read(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return get_comparator(chan); +} + +static int compare_set_nolocks(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + nrfx_err_t result; + + __ASSERT_NO_MSG(target_time < COUNTER_SPAN); + nrfx_grtc_channel_t user_channel_data = { + .handler = handler, + .p_context = user_data, + .channel = chan, + }; + result = nrfx_grtc_syscounter_cc_absolute_set(&user_channel_data, target_time, true); + if (result != NRFX_SUCCESS) { + return -EPERM; + } + return 0; +} + +static int compare_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + bool key = compare_int_lock(chan); + int ret = compare_set_nolocks(chan, target_time, handler, user_data); + + compare_int_unlock(chan, key); + + return ret; +} + +int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + return compare_set(chan, target_time, (nrfx_grtc_cc_handler_t)handler, user_data); +} + +void z_nrf_grtc_timer_abort(int32_t chan) +{ + IS_CHANNEL_ALLOWED_ASSERT(chan); + + bool key = compare_int_lock(chan); + (void)nrfx_grtc_syscounter_cc_disable(chan); + compare_int_unlock(chan, key); +} + +uint64_t z_nrf_grtc_timer_get_ticks(k_timeout_t t) +{ + uint64_t curr_time; + int64_t curr_tick; + int64_t result; + int64_t abs_ticks; + + curr_time = counter(); + curr_tick = sys_clock_tick_get(); + + abs_ticks = Z_TICK_ABS(t.ticks); + if (abs_ticks < 0) { + /* relative timeout */ + return (t.ticks > (int64_t)COUNTER_SPAN) ? -EINVAL : (curr_time + t.ticks); + } + + /* absolute timeout */ + result = abs_ticks - curr_tick; + + if (result > (int64_t)COUNTER_SPAN) { + return -EINVAL; + } + + return curr_time + result; +} + +int z_nrf_grtc_timer_capture_prepare(int32_t chan) +{ + nrfx_grtc_channel_t user_channel_data = { + .handler = NULL, + .p_context = NULL, + .channel = chan, + }; + nrfx_err_t result; + + IS_CHANNEL_ALLOWED_ASSERT(chan); + + /* Set the CC value to mark channel as not triggered and also to enable it + * (makes CCEN=1). COUNTER_SPAN is used so as not to fire an event unnecessarily + * - it can be assumed that such a large value will never be reached. + */ + result = nrfx_grtc_syscounter_cc_absolute_set(&user_channel_data, COUNTER_SPAN, false); + + if (result != NRFX_SUCCESS) { + return -EPERM; + } + + return 0; +} + +int z_nrf_grtc_timer_capture_read(int32_t chan, uint64_t *captured_time) +{ + /* TODO: The implementation should probably go to nrfx_grtc and this + * should be just a wrapper for some nrfx_grtc_syscounter_capture_read. + */ + + uint64_t capt_time; + + IS_CHANNEL_ALLOWED_ASSERT(chan); + + /* TODO: Use `nrfy_grtc_sys_counter_enable_check` when available (NRFX-2480) */ + if (NRF_GRTC->CC[chan].CCEN == GRTC_CC_CCEN_ACTIVE_Enable) { + /* If the channel is enabled (.CCEN), it means that there was no capture + * triggering event. + */ + return -EBUSY; + } + + capt_time = nrfy_grtc_sys_counter_cc_get(NRF_GRTC, chan); + + __ASSERT_NO_MSG(capt_time < COUNTER_SPAN); + + *captured_time = capt_time; + + return 0; +} + +#if defined(CONFIG_NRF_GRTC_SLEEP_ALLOWED) +int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us) +{ + nrfx_err_t err_code; + static uint8_t systemoff_channel; + uint64_t now = counter(); + /* Minimum time that ensures valid execution of system-off procedure. */ + uint32_t minimum_latency_us = nrfy_grtc_waketime_get(NRF_GRTC) + + nrfy_grtc_timeout_get(NRF_GRTC) + + CONFIG_NRF_GRTC_SLEEP_MINIMUM_LATENCY; + uint32_t chan; + int ret; + + if (minimum_latency_us > wake_time_us) { + return -EINVAL; + } + k_spinlock_key_t key = k_spin_lock(&lock); + + err_code = nrfx_grtc_channel_alloc(&systemoff_channel); + if (err_code != NRFX_SUCCESS) { + k_spin_unlock(&lock, key); + return -ENOMEM; + } + (void)nrfx_grtc_syscounter_cc_int_disable(systemoff_channel); + ret = compare_set(systemoff_channel, now + wake_time_us, NULL, NULL); + if (ret < 0) { + k_spin_unlock(&lock, key); + return ret; + } + + for (uint32_t grtc_chan_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + grtc_chan_mask > 0; grtc_chan_mask &= ~BIT(chan)) { + /* Clear all GRTC channels except the systemoff_channel. */ + chan = u32_count_trailing_zeros(grtc_chan_mask); + if (chan != systemoff_channel) { + nrfx_grtc_syscounter_cc_disable(chan); + } + } + + /* Make sure that wake_time_us was not triggered yet. */ + if (nrfy_grtc_sys_counter_compare_event_check(NRF_GRTC, systemoff_channel)) { + k_spin_unlock(&lock, key); + return -EINVAL; + } + + /* This mechanism ensures that stored CC value is latched. */ + uint32_t wait_time = + nrfy_grtc_timeout_get(NRF_GRTC) * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 32768 + + MAX_CC_LATCH_WAIT_TIME_US; + k_busy_wait(wait_time); +#if NRF_GRTC_HAS_CLKSEL + nrfy_grtc_clksel_set(NRF_GRTC, NRF_GRTC_CLKSEL_LFXO); +#endif + k_spin_unlock(&lock, key); + return 0; +} +#endif /* CONFIG_NRF_GRTC_SLEEP_ALLOWED */ + +uint32_t sys_clock_cycle_get_32(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint32_t ret = (uint32_t)counter(); + + k_spin_unlock(&lock, key); + return ret; +} + +uint64_t sys_clock_cycle_get_64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t ret = counter(); + + k_spin_unlock(&lock, key); + return ret; +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + return (uint32_t)(counter_sub(counter(), last_count) / CYC_PER_TICK); +} + +static int sys_clock_driver_init(void) +{ + nrfx_err_t err_code; + +#if defined(CONFIG_NRF_GRTC_TIMER_CLOCK_MANAGEMENT) && \ + (defined(NRF_GRTC_HAS_CLKSEL) && (NRF_GRTC_HAS_CLKSEL == 1)) + /* Use System LFCLK as the low-frequency clock source. */ + nrfy_grtc_clksel_set(NRF_GRTC, NRF_GRTC_CLKSEL_LFCLK); +#endif + +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) + /* SYSCOUNTER needs to be turned off before initialization. */ + nrfy_grtc_sys_counter_set(NRF_GRTC, false); + nrfy_grtc_timeout_set(NRF_GRTC, TIMEOUT); + nrfy_grtc_waketime_set(NRF_GRTC, WAKETIME); +#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ + + IRQ_CONNECT(DT_IRQN(GRTC_NODE), DT_IRQ(GRTC_NODE, priority), nrfx_grtc_irq_handler, 0, 0); + + err_code = nrfx_grtc_init(0); + if (err_code != NRFX_SUCCESS) { + return -EPERM; + } + +#if defined(CONFIG_NRF_GRTC_START_SYSCOUNTER) + err_code = nrfx_grtc_syscounter_start(true, &system_clock_channel_data.channel); + if (err_code != NRFX_SUCCESS) { + return err_code == NRFX_ERROR_NO_MEM ? -ENOMEM : -EPERM; + } + if (IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + nrfy_grtc_sys_counter_auto_mode_set(NRF_GRTC, false); + } +#else + err_code = nrfx_grtc_channel_alloc(&system_clock_channel_data.channel); + if (err_code != NRFX_SUCCESS) { + return -ENOMEM; + } +#endif /* CONFIG_NRF_GRTC_START_SYSCOUNTER */ + + if (!IS_ENABLED(CONFIG_NRF_GRTC_SLEEP_ALLOWED)) { + grtc_active_set(); + } + + int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + system_timeout_set(CYC_PER_TICK); + } + +#if defined(CONFIG_CLOCK_CONTROL_NRF) + static const enum nrf_lfclk_start_mode mode = + IS_ENABLED(CONFIG_SYSTEM_CLOCK_NO_WAIT) + ? CLOCK_CONTROL_NRF_LF_START_NOWAIT + : (IS_ENABLED(CONFIG_SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY) + ? CLOCK_CONTROL_NRF_LF_START_AVAILABLE + : CLOCK_CONTROL_NRF_LF_START_STABLE); + + z_nrf_clock_control_lf_on(mode); +#endif + + return 0; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + uint64_t cyc, off, now; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; + } + + ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : MIN(MAX_TICKS, MAX(ticks - 1, 0)); + + now = counter(); + + /* Round up to the next tick boundary */ + off = (now - last_count) + (CYC_PER_TICK - 1); + off = (off / CYC_PER_TICK) * CYC_PER_TICK; + + /* Get the offset with respect to now */ + off -= (now - last_count); + + /* Add the offset to get to the next tick boundary */ + cyc = (uint64_t)ticks * CYC_PER_TICK + off; + + /* Due to elapsed time the calculation above might produce a + * duration that laps the counter. Don't let it. + */ + if (cyc > MAX_CYCLES) { + cyc = MAX_CYCLES; + } + + system_timeout_set(cyc == 0 ? 1 : cyc); +} + +#if defined(CONFIG_NRF_GRTC_TIMER_APP_DEFINED_INIT) +int nrf_grtc_timer_clock_driver_init(void) +{ + return sys_clock_driver_init(); +} +#else +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); +#endif diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index 9241c5b7a10..e0584a3c8b3 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #define RTC_PRETICK (IS_ENABLED(CONFIG_SOC_NRF53_RTC_PRETICK) && \ @@ -72,32 +72,32 @@ static uint32_t counter_sub(uint32_t a, uint32_t b) static void set_comparator(int32_t chan, uint32_t cyc) { - nrf_rtc_cc_set(RTC, chan, cyc & COUNTER_MAX); + nrfy_rtc_cc_set(RTC, chan, cyc & COUNTER_MAX); } static bool event_check(int32_t chan) { - return nrf_rtc_event_check(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); + return nrfy_rtc_event_check(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); } static void event_clear(int32_t chan) { - nrf_rtc_event_clear(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); + nrfy_rtc_event_clear(RTC, NRF_RTC_CHANNEL_EVENT_ADDR(chan)); } static void event_enable(int32_t chan) { - nrf_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } static void event_disable(int32_t chan) { - nrf_rtc_event_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_event_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } static uint32_t counter(void) { - return nrf_rtc_counter_get(RTC); + return nrfy_rtc_counter_get(RTC); } static uint32_t absolute_time_to_cc(uint64_t absolute_time) @@ -132,7 +132,7 @@ static void full_int_unlock(uint32_t mcu_critical_state) uint32_t z_nrf_rtc_timer_compare_evt_address_get(int32_t chan) { __ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT); - return nrf_rtc_event_address_get(RTC, nrf_rtc_compare_event_get(chan)); + return nrfy_rtc_event_address_get(RTC, nrfy_rtc_compare_event_get(chan)); } uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan) @@ -143,9 +143,7 @@ uint32_t z_nrf_rtc_timer_capture_task_address_get(int32_t chan) return 0; } - nrf_rtc_task_t task = offsetof(NRF_RTC_Type, TASKS_CAPTURE[chan]); - - return nrf_rtc_task_address_get(RTC, task); + return nrfy_rtc_task_address_get(RTC, nrfy_rtc_capture_task_get(chan)); #else ARG_UNUSED(chan); return 0; @@ -156,7 +154,7 @@ static bool compare_int_lock(int32_t chan) { atomic_val_t prev = atomic_and(&int_mask, ~BIT(chan)); - nrf_rtc_int_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_disable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); barrier_dmem_fence_full(); barrier_isync_fence_full(); @@ -176,7 +174,7 @@ static void compare_int_unlock(int32_t chan, bool key) { if (key) { atomic_or(&int_mask, BIT(chan)); - nrf_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); if (atomic_get(&force_isr_mask) & BIT(chan)) { NVIC_SetPendingIRQ(RTC_IRQn); } @@ -194,7 +192,7 @@ uint32_t z_nrf_rtc_timer_compare_read(int32_t chan) { __ASSERT_NO_MSG(chan >= 0 && chan < CHAN_COUNT); - return nrf_rtc_cc_get(RTC, chan); + return nrfy_rtc_cc_get(RTC, chan); } uint64_t z_nrf_rtc_timer_get_ticks(k_timeout_t t) @@ -494,7 +492,7 @@ static void sys_clock_timeout_handler(int32_t chan, static bool channel_processing_check_and_clear(int32_t chan) { - if (nrf_rtc_int_enable_check(RTC, NRF_RTC_CHANNEL_INT_MASK(chan))) { + if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_CHANNEL_INT_MASK(chan))) { /* The processing of channel can be caused by CC match * or be forced. */ @@ -568,9 +566,8 @@ void rtc_nrf_isr(const void *arg) rtc_pretick_rtc1_isr_hook(); } - if (nrf_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) && - nrf_rtc_event_check(RTC, NRF_RTC_EVENT_OVERFLOW)) { - nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_OVERFLOW); + if (nrfy_rtc_int_enable_check(RTC, NRF_RTC_INT_OVERFLOW_MASK) && + nrfy_rtc_events_process(RTC, NRF_RTC_INT_OVERFLOW_MASK)) { overflow_cnt++; } @@ -623,7 +620,7 @@ int z_nrf_rtc_timer_trigger_overflow(void) goto bail; } - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_TRIGGER_OVERFLOW); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_TRIGGER_OVERFLOW); k_busy_wait(80); uint64_t now = z_nrf_rtc_timer_read(); @@ -713,10 +710,10 @@ static void int_event_disable_rtc(void) NRF_RTC_INT_COMPARE3_MASK; /* Reset interrupt enabling to expected reset values */ - nrf_rtc_int_disable(RTC, mask); + nrfy_rtc_int_disable(RTC, mask); /* Reset event routing enabling to expected reset values */ - nrf_rtc_event_disable(RTC, mask); + nrfy_rtc_event_disable(RTC, mask); } void sys_clock_disable(void) @@ -739,13 +736,13 @@ static int sys_clock_driver_init(void) int_event_disable_rtc(); /* TODO: replace with counter driver to access RTC */ - nrf_rtc_prescaler_set(RTC, 0); + nrfy_rtc_prescaler_set(RTC, 0); for (int32_t chan = 0; chan < CHAN_COUNT; chan++) { cc_data[chan].target_time = TARGET_TIME_INVALID; - nrf_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); + nrfy_rtc_int_enable(RTC, NRF_RTC_CHANNEL_INT_MASK(chan)); } - nrf_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK); + nrfy_rtc_int_enable(RTC, NRF_RTC_INT_OVERFLOW_MASK); NVIC_ClearPendingIRQ(RTC_IRQn); @@ -753,8 +750,8 @@ static int sys_clock_driver_init(void) rtc_nrf_isr, 0, 0); irq_enable(RTC_IRQn); - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR); - nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_START); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR); + nrfy_rtc_task_trigger(RTC, NRF_RTC_TASK_START); int_mask = BIT_MASK(CHAN_COUNT); if (CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT) { diff --git a/drivers/timer/stm32_lptim_timer.c b/drivers/timer/stm32_lptim_timer.c index aaf83c30057..ba00014ad45 100644 --- a/drivers/timer/stm32_lptim_timer.c +++ b/drivers/timer/stm32_lptim_timer.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -61,11 +63,10 @@ static const struct device *const clk_ctrl = DEVICE_DT_GET(STM32_CLOCK_CONTROL_N * 0xFFFF / (LSE freq (32768Hz) / 128) */ -static uint32_t lptim_clock_freq = KHZ(32); static int32_t lptim_time_base; - +static uint32_t lptim_clock_freq = CONFIG_STM32_LPTIM_CLOCK; /* The prescaler given by the DTS and to apply to the lptim_clock_freq */ -#define LPTIM_CLOCK_RATIO DT_PROP(DT_DRV_INST(0), st_prescaler) +static uint32_t lptim_clock_presc = DT_PROP(DT_DRV_INST(0), st_prescaler); /* Minimum nb of clock cycles to have to set autoreload register correctly */ #define LPTIM_GUARD_VALUE 2 @@ -81,16 +82,31 @@ static bool autoreload_ready = true; static struct k_spinlock lock; -/* For tick accuracy, a specific tick to freq ratio is expected */ -/* This check assumes LSI@32KHz or LSE@32768Hz */ -#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE) -#if (((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSI) && \ - (CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4000)) || \ - ((DT_CLOCKS_CELL_BY_IDX(DT_DRV_INST(0), 1, bus) == STM32_SRC_LSE) && \ - (CONFIG_SYS_CLOCK_TICKS_PER_SEC != 4096))) -#warning Advised tick freq is 4096 for LSE / 4000 for LSI -#endif -#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */ +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + +#define CURRENT_CPU \ + (COND_CODE_1(CONFIG_SMP, (arch_curr_cpu()->id), (_current_cpu->id))) + +#define cycle_t uint32_t + +/* This local variable indicates that the timeout was set right before + * entering standby state. + * + * It is used for chips that has to use a separate standby timer in such + * case because the LPTIM is not clocked in some low power mode state. + */ +static bool timeout_stdby; + +/* Cycle counter before entering the standby state. */ +static cycle_t lptim_cnt_pre_stdby; + +/* Standby timer value before entering the standby state. */ +static uint32_t stdby_timer_pre_stdby; + +/* Standby timer used for timer while entering the standby state */ +static const struct device *stdby_timer = DEVICE_DT_GET(DT_CHOSEN(st_lptim_stdby_timer)); + +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ static inline bool arrm_state_get(void) { @@ -183,6 +199,41 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) ARG_UNUSED(idle); +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + const struct pm_state_info *next; + + next = pm_policy_next_state(CURRENT_CPU, ticks); + + if ((next != NULL) && (next->state == PM_STATE_SUSPEND_TO_RAM)) { + uint64_t timeout_us = + ((uint64_t)ticks * USEC_PER_SEC) / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + + struct counter_alarm_cfg cfg = { + .callback = NULL, + .ticks = counter_us_to_ticks(stdby_timer, timeout_us), + .user_data = NULL, + .flags = 0, + }; + + timeout_stdby = true; + + /* Set the alarm using timer that runs the standby. + * Needed rump-up/setting time, lower accurency etc. should be + * included in the exit-latency in the power state definition. + */ + counter_cancel_channel_alarm(stdby_timer, 0); + counter_set_channel_alarm(stdby_timer, 0, &cfg); + + /* Store current values to calculate a difference in + * measurements after exiting the standby state. + */ + counter_get_value(stdby_timer, &stdby_timer_pre_stdby); + lptim_cnt_pre_stdby = z_clock_lptim_getcounter(); + + return; + } +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { return; } @@ -387,21 +438,24 @@ static int sys_clock_driver_init(void) return -EIO; } - if (IS_ENABLED(DT_PROP(DT_DRV_INST(0), st_static_prescaler))) { - /* - * LPTIM of the stm32, like stm32U5, which has a clock source x2. - * A full 16bit LPTIM counter is counting 4s at 2 * 1/32768 (with LSE) - * Time base = (4s * freq) - 1 - */ - lptim_clock_freq = lptim_clock_freq / 2; - } +#if !defined(CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE) /* - * Else, a full 16bit LPTIM counter is counting 2s at 1/32768 (with LSE) - * Time base = (2s * freq) - 1 + * Check coherency between CONFIG_SYS_CLOCK_TICKS_PER_SEC + * and the lptim_clock_freq which is the CONFIG_STM32_LPTIM_CLOCK reduced + * by the lptim_clock_presc */ + if (lptim_clock_presc <= 8) { + __ASSERT(CONFIG_STM32_LPTIM_CLOCK / 8 >= CONFIG_SYS_CLOCK_TICKS_PER_SEC, + "It is recommended to set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/8"); + } else { + __ASSERT(CONFIG_STM32_LPTIM_CLOCK / lptim_clock_presc >= + CONFIG_SYS_CLOCK_TICKS_PER_SEC, + "Set SYS_CLOCK_TICKS_PER_SEC to CONFIG_STM32_LPTIM_CLOCK/lptim_clock_presc"); + } +#endif /* !CONFIG_STM32_LPTIM_TICK_FREQ_RATIO_OVERRIDE */ /* Actual lptim clock freq when the clock source is reduced by the prescaler */ - lptim_clock_freq = lptim_clock_freq / LPTIM_CLOCK_RATIO; + lptim_clock_freq = lptim_clock_freq / lptim_clock_presc; /* Clear the event flag and possible pending interrupt */ IRQ_CONNECT(DT_INST_IRQN(0), @@ -417,7 +471,8 @@ static int sys_clock_driver_init(void) /* configure the LPTIM counter */ LL_LPTIM_SetClockSource(LPTIM, LL_LPTIM_CLK_SOURCE_INTERNAL); /* the LPTIM clock freq is affected by the prescaler */ - LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(LPTIM_CLOCK_RATIO)) << LPTIM_CFGR_PRESC_Pos)); + LL_LPTIM_SetPrescaler(LPTIM, (__CLZ(__RBIT(lptim_clock_presc)) << LPTIM_CFGR_PRESC_Pos)); + #if defined(CONFIG_SOC_SERIES_STM32U5X) || \ defined(CONFIG_SOC_SERIES_STM32WBAX) LL_LPTIM_OC_SetPolarity(LPTIM, LL_LPTIM_CHANNEL_CH1, @@ -456,8 +511,6 @@ static int sys_clock_driver_init(void) stm32_lptim_wait_ready(); LL_LPTIM_ClearFlag_ARROK(LPTIM); - accumulated_lptim_cnt = 0; - #if !defined(CONFIG_SOC_SERIES_STM32U5X) && \ !defined(CONFIG_SOC_SERIES_STM32WBAX) /* Enable the LPTIM counter */ @@ -490,5 +543,55 @@ static int sys_clock_driver_init(void) return 0; } +void sys_clock_idle_exit(void) +{ +#ifdef CONFIG_STM32_LPTIM_STDBY_TIMER + if (clock_control_get_status(clk_ctrl, + (clock_control_subsys_t) &lptim_clk[0]) + != CLOCK_CONTROL_STATUS_ON) { + sys_clock_driver_init(); + } else if (timeout_stdby) { + cycle_t missed_lptim_cnt; + uint32_t stdby_timer_diff, stdby_timer_post, dticks; + uint64_t stdby_timer_us; + + /* Get current value for standby timer and reset LPTIM counter value + * to start anew. + */ + LL_LPTIM_ResetCounter(LPTIM); + counter_get_value(stdby_timer, &stdby_timer_post); + + /* Calculate how much time has passed since last measurement for standby timer */ + /* Check IDLE timer overflow */ + if (stdby_timer_pre_stdby > stdby_timer_post) { + stdby_timer_diff = + (counter_get_top_value(stdby_timer) - stdby_timer_pre_stdby) + + stdby_timer_post + 1; + + } else { + stdby_timer_diff = stdby_timer_post - stdby_timer_pre_stdby; + } + stdby_timer_us = counter_ticks_to_us(stdby_timer, stdby_timer_diff); + + /* Convert standby time in LPTIM cnt */ + missed_lptim_cnt = (sys_clock_hw_cycles_per_sec() * stdby_timer_us) / + USEC_PER_SEC; + /* Add the LPTIM cnt pre standby */ + missed_lptim_cnt += lptim_cnt_pre_stdby; + + /* Update the cycle counter to include the cycles missed in standby */ + accumulated_lptim_cnt += missed_lptim_cnt; + + /* Announce the passed ticks to the kernel */ + dticks = (missed_lptim_cnt * CONFIG_SYS_CLOCK_TICKS_PER_SEC) + / lptim_clock_freq; + sys_clock_announce(dticks); + + /* We've already performed all needed operations */ + timeout_stdby = false; + } +#endif /* CONFIG_STM32_LPTIM_STDBY_TIMER */ +} + SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/drivers/usb/common/usb_dwc2_hw.h b/drivers/usb/common/usb_dwc2_hw.h new file mode 100644 index 00000000000..edcab56b50f --- /dev/null +++ b/drivers/usb/common/usb_dwc2_hw.h @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW +#define ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* This file describes register set for the DesignWare USB 2.0 controller IP */ + +/* IN endpoint register block */ +struct usb_dwc2_in_ep { + volatile uint32_t diepctl; + uint32_t reserved; + volatile uint32_t diepint; + uint32_t reserved1; + volatile uint32_t dieptsiz; + volatile uint32_t diepdma; + volatile uint32_t dtxfsts; + volatile uint32_t diepdmab; +}; + +/* OUT endpoint register block */ +struct usb_dwc2_out_ep { + volatile uint32_t doepctl; + uint32_t reserved; + volatile uint32_t doepint; + uint32_t reserved1; + volatile uint32_t doeptsiz; + volatile uint32_t doepdma; + uint32_t reserved2; + volatile uint32_t doepdmab; +}; + +/* DWC2 register map + * TODO: This should probably be split into global, host, and device register + * blocks + */ +struct usb_dwc2_reg { + volatile uint32_t gotgctl; + volatile uint32_t gotgint; + volatile uint32_t gahbcfg; + volatile uint32_t gusbcfg; + volatile uint32_t grstctl; + volatile uint32_t gintsts; + volatile uint32_t gintmsk; + volatile uint32_t grxstsr; + volatile uint32_t grxstsp; + volatile uint32_t grxfsiz; + volatile uint32_t gnptxfsiz; + volatile uint32_t gnptxsts; + volatile uint32_t gi2cctl; + volatile uint32_t gpvndctl; + volatile uint32_t ggpio; + volatile uint32_t guid; + volatile uint32_t gsnpsid; + volatile uint32_t ghwcfg1; + volatile uint32_t ghwcfg2; + volatile uint32_t ghwcfg3; + volatile uint32_t ghwcfg4; + volatile uint32_t glpmcfg; + volatile uint32_t gpwrdn; + volatile uint32_t gdfifocfg; + volatile uint32_t gadpctl; + volatile uint32_t grefclk; + volatile uint32_t gintmsk2; + volatile uint32_t gintsts2; + volatile uint32_t reserved1[36]; + volatile uint32_t hptxfsiz; + union { + volatile uint32_t dptxfsiz[15]; + volatile uint32_t dieptxf[15]; + }; + volatile uint32_t reserved2[176]; + /* Host mode register 0x0400 .. 0x0670 */ + uint32_t reserved3[256]; + /* Device mode register 0x0800 .. 0x0D00 */ + volatile uint32_t dcfg; + volatile uint32_t dctl; + volatile uint32_t dsts; + uint32_t reserved4; + volatile uint32_t diepmsk; + volatile uint32_t doepmsk; + volatile uint32_t daint; + volatile uint32_t daintmsk; + volatile uint32_t dtknqr1; + volatile uint32_t dtknqr2; + volatile uint32_t dvbusdis; + volatile uint32_t dvbuspulse; + union { + volatile uint32_t dtknqr3; + volatile uint32_t dthrctl; + }; + union { + volatile uint32_t dtknqr4; + volatile uint32_t diepempmsk; + }; + volatile uint32_t deachint; + volatile uint32_t deachintmsk; + volatile uint32_t diepeachmsk[16]; + volatile uint32_t doepeachmsk[16]; + volatile uint32_t reserved5[16]; + struct usb_dwc2_in_ep in_ep[16]; + struct usb_dwc2_out_ep out_ep[16]; +}; + +/* + * With the maximum number of supported endpoints, register map + * of the controller must be equal to 0x0D00. + */ +BUILD_ASSERT(sizeof(struct usb_dwc2_reg) == 0x0D00); + +/* + * GET_FIELD/SET_FIELD macros below are intended to be used to define functions + * to get/set a bitfield of a register from/into a value. They should not be + * used to get/set a bitfield consisting of only one bit. + */ +#define USB_DWC2_GET_FIELD_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_get_##name(const uint32_t value) \ + { \ + return (value & USB_DWC2_##reg_name_and_field##_MASK) >> \ + USB_DWC2_##reg_name_and_field##_POS; \ + } + +#define USB_DWC2_SET_FIELD_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_set_##name(const uint32_t value) \ + { \ + return (value << USB_DWC2_##reg_name_and_field##_POS) & \ + USB_DWC2_##reg_name_and_field##_MASK; \ + } + +#define USB_DWC2_GET_FIELD_AND_IDX_DEFINE(name, reg_name_and_field) \ + static inline uint32_t usb_dwc2_get_##name(const uint32_t value, \ + const uint32_t idx) \ + { \ + return (value & USB_DWC2_##reg_name_and_field##_MASK(idx)) >> \ + USB_DWC2_##reg_name_and_field##_POS(idx); \ + } + +/* AHB configuration register */ +#define USB_DWC2_GAHBCFG 0x0008UL +#define USB_DWC2_GAHBCFG_DMAEN_POS 5UL +#define USB_DWC2_GAHBCFG_DMAEN BIT(USB_DWC2_GAHBCFG_DMAEN_POS) +#define USB_DWC2_GAHBCFG_GLBINTRMASK_POS 0UL +#define USB_DWC2_GAHBCFG_GLBINTRMASK BIT(USB_DWC2_GAHBCFG_GLBINTRMASK_POS) + +/* USB configuration register */ +#define USB_DWC2_GUSBCFG 0x000CUL +#define USB_DWC2_GUSBCFG_FORCEDEVMODE_POS 30UL +#define USB_DWC2_GUSBCFG_FORCEDEVMODE BIT(USB_DWC2_GUSBCFG_FORCEDEVMODE_POS) +#define USB_DWC2_GUSBCFG_FORCEHSTMODE_POS 29UL +#define USB_DWC2_GUSBCFG_FORCEHSTMODE BIT(USB_DWC2_GUSBCFG_FORCEHSTMODE_POS) +#define USB_DWC2_GUSBCFG_PHYSEL_POS 6UL +#define USB_DWC2_GUSBCFG_PHYSEL_USB11 BIT(USB_DWC2_GUSBCFG_PHYSEL_POS) +#define USB_DWC2_GUSBCFG_PHYSEL_USB20 0UL +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_POS 4UL +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_ULPI BIT(USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_POS) +#define USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_UTMI 0UL +#define USB_DWC2_GUSBCFG_PHYIF_POS 3UL +#define USB_DWC2_GUSBCFG_PHYIF_16_BIT BIT(USB_DWC2_GUSBCFG_PHYIF_POS) +#define USB_DWC2_GUSBCFG_PHYIF_8_BIT 0UL + +/* Reset register */ +#define USB_DWC2_GRSTCTL 0x0010UL +#define USB_DWC2_GRSTCTL_AHBIDLE_POS 31UL +#define USB_DWC2_GRSTCTL_AHBIDLE BIT(USB_DWC2_GRSTCTL_AHBIDLE_POS) +#define USB_DWC2_GRSTCTL_CSFTRSTDONE_POS 29UL +#define USB_DWC2_GRSTCTL_CSFTRSTDONE BIT(USB_DWC2_GRSTCTL_CSFTRSTDONE_POS) +#define USB_DWC2_GRSTCTL_TXFNUM_POS 6UL +#define USB_DWC2_GRSTCTL_TXFNUM_MASK (0x1FUL << USB_DWC2_GRSTCTL_TXFNUM_POS) +#define USB_DWC2_GRSTCTL_TXFFLSH_POS 5UL +#define USB_DWC2_GRSTCTL_TXFFLSH BIT(USB_DWC2_GRSTCTL_TXFFLSH_POS) +#define USB_DWC2_GRSTCTL_RXFFLSH_POS 4UL +#define USB_DWC2_GRSTCTL_RXFFLSH BIT(USB_DWC2_GRSTCTL_RXFFLSH_POS) +#define USB_DWC2_GRSTCTL_CSFTRST_POS 0UL +#define USB_DWC2_GRSTCTL_CSFTRST BIT(USB_DWC2_GRSTCTL_CSFTRST_POS) + +USB_DWC2_SET_FIELD_DEFINE(grstctl_txfnum, GRSTCTL_TXFNUM) + +/* Core interrupt registers */ +#define USB_DWC2_GINTSTS 0x0014UL +#define USB_DWC2_GINTMSK 0x0018UL +#define USB_DWC2_GINTSTS_WKUPINT_POS 31UL +#define USB_DWC2_GINTSTS_WKUPINT BIT(USB_DWC2_GINTSTS_WKUPINT_POS) +#define USB_DWC2_GINTSTS_OEPINT_POS 19UL +#define USB_DWC2_GINTSTS_OEPINT BIT(USB_DWC2_GINTSTS_OEPINT_POS) +#define USB_DWC2_GINTSTS_IEPINT_POS 18UL +#define USB_DWC2_GINTSTS_IEPINT BIT(USB_DWC2_GINTSTS_IEPINT_POS) +#define USB_DWC2_GINTSTS_ENUMDONE_POS 13UL +#define USB_DWC2_GINTSTS_ENUMDONE BIT(USB_DWC2_GINTSTS_ENUMDONE_POS) +#define USB_DWC2_GINTSTS_USBRST_POS 12UL +#define USB_DWC2_GINTSTS_USBRST BIT(USB_DWC2_GINTSTS_USBRST_POS) +#define USB_DWC2_GINTSTS_USBSUSP_POS 11UL +#define USB_DWC2_GINTSTS_USBSUSP BIT(USB_DWC2_GINTSTS_USBSUSP_POS) +#define USB_DWC2_GINTSTS_RXFLVL_POS 4UL +#define USB_DWC2_GINTSTS_RXFLVL BIT(USB_DWC2_GINTSTS_RXFLVL_POS) +#define USB_DWC2_GINTSTS_OTGINT_POS 2UL +#define USB_DWC2_GINTSTS_OTGINT BIT(USB_DWC2_GINTSTS_OTGINT_POS) + +/* Status read and pop registers */ +#define USB_DWC2_GRXSTSR 0x001CUL +#define USB_DWC2_GRXSTSP 0x0020UL +#define USB_DWC2_GRXSTSR_PKTSTS_POS 17UL +#define USB_DWC2_GRXSTSR_PKTSTS_MASK (0xFUL << USB_DWC2_GRXSTSR_PKTSTS_POS) +#define USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA 2 +#define USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE 3 +#define USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE 4 +#define USB_DWC2_GRXSTSR_PKTSTS_SETUP 6 +#define USB_DWC2_GRXSTSR_BCNT_POS 4UL +#define USB_DWC2_GRXSTSR_BCNT_MASK (0x000007FFUL << USB_DWC2_GRXSTSR_BCNT_POS) +#define USB_DWC2_GRXSTSR_EPNUM_POS 0UL +#define USB_DWC2_GRXSTSR_EPNUM_MASK 0x0000000FUL +#define USB_DWC2_GRXSTSR_CHNUM_POS 0UL +#define USB_DWC2_GRXSTSR_CHNUM_MASK 0x0000000FUL + +USB_DWC2_GET_FIELD_DEFINE(grxstsp_pktsts, GRXSTSR_PKTSTS) +USB_DWC2_GET_FIELD_DEFINE(grxstsp_bcnt, GRXSTSR_BCNT) +USB_DWC2_GET_FIELD_DEFINE(grxstsp_epnum, GRXSTSR_EPNUM) + +/* Receive FIFO size register (device mode) */ +#define USB_DWC2_GRXFSIZ 0x0024UL +#define USB_DWC2_GRXFSIZ_RXFDEP_POS 0UL +#define USB_DWC2_GRXFSIZ_RXFDEP_MASK (0xFFFFUL << USB_DWC2_GRXFSIZ_RXFDEP_POS) + +USB_DWC2_GET_FIELD_DEFINE(grxfsiz, GRXFSIZ_RXFDEP) +USB_DWC2_SET_FIELD_DEFINE(grxfsiz, GRXFSIZ_RXFDEP) + +/* Non-periodic transmit FIFO size register (device mode) */ +#define USB_DWC2_GNPTXFSIZ 0x0028UL +#define USB_DWC2_GNPTXFSIZ_NPTXFDEP_POS 16UL +#define USB_DWC2_GNPTXFSIZ_NPTXFDEP_MASK (0xFFFFUL << USB_DWC2_GNPTXFSIZ_NPTXFDEP_POS) +#define USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_POS 0UL +#define USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_MASK (0xFFFFUL << USB_DWC2_GNPTXFSIZ_NPTXFSTADDR_POS) + +USB_DWC2_GET_FIELD_DEFINE(gnptxfsiz_nptxfdep, GNPTXFSIZ_NPTXFDEP) +USB_DWC2_GET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR) +USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfdep, GNPTXFSIZ_NPTXFDEP) +USB_DWC2_SET_FIELD_DEFINE(gnptxfsiz_nptxfstaddr, GNPTXFSIZ_NPTXFSTADDR) + +/* Application (vendor) general purpose registers */ +#define USB_DWC2_GGPIO 0x0038UL +#define USB_DWC2_GGPIO_STM32_VBDEN_POS 21UL +#define USB_DWC2_GGPIO_STM32_VBDEN BIT(USB_DWC2_GGPIO_STM32_VBDEN_POS) +#define USB_DWC2_GGPIO_STM32_PWRDWN_POS 16UL +#define USB_DWC2_GGPIO_STM32_PWRDWN BIT(USB_DWC2_GGPIO_STM32_PWRDWN_POS) + +/* GHWCFG1 register */ +#define USB_DWC2_GHWCFG1 0x0044UL +#define USB_DWC2_GHWCFG1_EPDIR_POS(i) (i * 2) +#define USB_DWC2_GHWCFG1_EPDIR_MASK(i) (0x3UL << USB_DWC2_GHWCFG1_EPDIR_POS(i)) +#define USB_DWC2_GHWCFG1_EPDIR_OUT 2 +#define USB_DWC2_GHWCFG1_EPDIR_IN 1 +#define USB_DWC2_GHWCFG1_EPDIR_BDIR 0 + +USB_DWC2_GET_FIELD_AND_IDX_DEFINE(ghwcfg1_epdir, GHWCFG1_EPDIR) + +/* GHWCFG2 register */ +#define USB_DWC2_GHWCFG2 0x0048UL +#define USB_DWC2_GHWCFG2_DYNFIFOSIZING_POS 19UL +#define USB_DWC2_GHWCFG2_DYNFIFOSIZING BIT(USB_DWC2_GHWCFG2_DYNFIFOSIZING_POS) +#define USB_DWC2_GHWCFG2_NUMDEVEPS_POS 10UL +#define USB_DWC2_GHWCFG2_NUMDEVEPS_MASK (0xFUL << USB_DWC2_GHWCFG2_NUMDEVEPS_POS) +#define USB_DWC2_GHWCFG2_FSPHYTYPE_POS 8UL +#define USB_DWC2_GHWCFG2_FSPHYTYPE_MASK (0x3UL << USB_DWC2_GHWCFG2_FSPHYTYPE_POS) +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FSPLUSULPI 3 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FSPLUSUTMI 2 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_FS 1 +#define USB_DWC2_GHWCFG2_FSPHYTYPE_NO_FS 0 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_POS 6UL +#define USB_DWC2_GHWCFG2_HSPHYTYPE_MASK (0x3UL << USB_DWC2_GHWCFG2_HSPHYTYPE_POS) +#define USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI 3 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_ULPI 2 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUS 1 +#define USB_DWC2_GHWCFG2_HSPHYTYPE_NO_HS 0 +#define USB_DWC2_GHWCFG2_OTGARCH_POS 3UL +#define USB_DWC2_GHWCFG2_OTGARCH_MASK (0x3UL << USB_DWC2_GHWCFG2_OTGARCH_POS) +#define USB_DWC2_GHWCFG2_OTGARCH_INTERNALDMA 2 +#define USB_DWC2_GHWCFG2_OTGARCH_EXTERNALDMA 1 +#define USB_DWC2_GHWCFG2_OTGARCH_SLAVEMODE 0 +#define USB_DWC2_GHWCFG2_OTGMODE_POS 0UL +#define USB_DWC2_GHWCFG2_OTGMODE_MASK (0x7UL << USB_DWC2_GHWCFG2_OTGMODE_POS) +#define USB_DWC2_GHWCFG2_OTGMODE_NONOTGH 6 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPCAPH 5 +#define USB_DWC2_GHWCFG2_OTGMODE_NONOTGD 4 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPCAPD 3 +#define USB_DWC2_GHWCFG2_OTGMODE_NHNPNSRP 2 +#define USB_DWC2_GHWCFG2_OTGMODE_SRPOTG 1 +#define USB_DWC2_GHWCFG2_OTGMODE_HNPSRP 0 + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_numdeveps, GHWCFG2_NUMDEVEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_fsphytype, GHWCFG2_FSPHYTYPE) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_hsphytype, GHWCFG2_HSPHYTYPE) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_otgarch, GHWCFG2_OTGARCH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg2_otgmode, GHWCFG2_OTGMODE) + +/* GHWCFG3 register */ +#define USB_DWC2_GHWCFG3 0x004CUL +#define USB_DWC2_GHWCFG3_DFIFODEPTH_POS 16UL +#define USB_DWC2_GHWCFG3_DFIFODEPTH_MASK (0xFFFFUL << USB_DWC2_GHWCFG3_DFIFODEPTH_POS) +#define USB_DWC2_GHWCFG3_LPMMODE_POS 15UL +#define USB_DWC2_GHWCFG3_LPMMODE BIT(USB_DWC2_GHWCFG3_LPMMODE_POS) +#define USB_DWC2_GHWCFG3_OPTFEATURE_POS 10UL +#define USB_DWC2_GHWCFG3_OPTFEATURE BIT(USB_DWC2_GHWCFG3_OPTFEATURE_POS) +#define USB_DWC2_GHWCFG3_VNDCTLSUPT_POS 9UL +#define USB_DWC2_GHWCFG3_VNDCTLSUPT BIT(USB_DWC2_GHWCFG3_VNDCTLSUPT_POS) +#define USB_DWC2_GHWCFG3_OTGEN_POS 7UL +#define USB_DWC2_GHWCFG3_OTGEN BIT(USB_DWC2_GHWCFG3_OTGEN_POS) +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_POS 4UL +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_MASK (0x7UL << USB_DWC2_GHWCFG3_PKTSIZEWIDTH_POS) +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS10 6U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS9 5U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS8 4U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS7 3U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS6 2U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS5 1U +#define USB_DWC2_GHWCFG3_PKTSIZEWIDTH_BITS4 0U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_POS 0UL +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_MASK (0xFUL << USB_DWC2_GHWCFG3_XFERSIZEWIDTH_POS) +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH19 8U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH18 7U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH17 6U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH16 5U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH15 4U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH14 3U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH13 2U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH12 1U +#define USB_DWC2_GHWCFG3_XFERSIZEWIDTH_WIDTH11 0U + +#define GHWCFG3_PKTCOUNT(pktsizewidth) BIT_MASK(pktsizewidth + 4) +#define GHWCFG3_XFERSIZE(xfersizewidth) BIT_MASK(xfersizewidth + 11) + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_dfifodepth, GHWCFG3_DFIFODEPTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_pktsizewidth, GHWCFG3_PKTSIZEWIDTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg3_xfersizewidth, GHWCFG3_XFERSIZEWIDTH) + +/* GHWCFG4 register */ +#define USB_DWC2_GHWCFG4 0x0050UL +#define USB_DWC2_GHWCFG4_INEPS_POS 26UL +#define USB_DWC2_GHWCFG4_INEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_INEPS_POS) +#define USB_DWC2_GHWCFG4_DEDFIFOMODE_POS 25UL +#define USB_DWC2_GHWCFG4_DEDFIFOMODE BIT(USB_DWC2_GHWCFG4_DEDFIFOMODE_POS) +#define USB_DWC2_GHWCFG4_NUMCTLEPS_POS 16UL +#define USB_DWC2_GHWCFG4_NUMCTLEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_NUMCTLEPS_POS) +#define USB_DWC2_GHWCFG4_PHYDATAWIDTH_POS 14UL +#define USB_DWC2_GHWCFG4_PHYDATAWIDTH_MASK (0x3UL << USB_DWC2_GHWCFG4_PHYDATAWIDTH_POS) +#define USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_POS 0UL +#define USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_MASK (0xFUL << USB_DWC2_GHWCFG4_NUMDEVPERIOEPS_POS) + +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_ineps, GHWCFG4_INEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_numctleps, GHWCFG4_NUMCTLEPS) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_phydatawidth, GHWCFG4_PHYDATAWIDTH) +USB_DWC2_GET_FIELD_DEFINE(ghwcfg4_numdevperioeps, GHWCFG4_NUMDEVPERIOEPS) + +/* Device IN endpoint transmit FIFO size register */ +#define USB_DWC2_DIEPTXF1 0x0104UL +#define USB_DWC2_DIEPTXF_INEPNTXFDEP_POS 16UL +#define USB_DWC2_DIEPTXF_INEPNTXFDEP_MASK (0xFFFFUL << USB_DWC2_DIEPTXF_INEPNTXFDEP_POS) +#define USB_DWC2_DIEPTXF_INEPNTXFSTADDR_POS 0UL +#define USB_DWC2_DIEPTXF_INEPNTXFSTADDR_MASK (0xFFFFUL << USB_DWC2_DIEPTXF_INEPNTXFSTADDR_POS) + +USB_DWC2_GET_FIELD_DEFINE(dieptxf_inepntxfdep, DIEPTXF_INEPNTXFDEP) +USB_DWC2_GET_FIELD_DEFINE(dieptxf_inepntxfstaddr, DIEPTXF_INEPNTXFSTADDR) +USB_DWC2_SET_FIELD_DEFINE(dieptxf_inepntxfdep, DIEPTXF_INEPNTXFDEP) +USB_DWC2_SET_FIELD_DEFINE(dieptxf_inepntxfstaddr, DIEPTXF_INEPNTXFSTADDR) + +/* Device configuration registers */ +#define USB_DWC2_DCFG 0x0800UL +#define USB_DWC2_DCFG_DEVADDR_POS 4UL +#define USB_DWC2_DCFG_DEVADDR_MASK (0x7FUL << USB_DWC2_DCFG_DEVADDR_POS) +#define USB_DWC2_DCFG_DEVSPD_POS 0UL +#define USB_DWC2_DCFG_DEVSPD_MASK (0x03UL << USB_DWC2_DCFG_DEVSPD_POS) +#define USB_DWC2_DCFG_DEVSPD_USBHS20 0 +#define USB_DWC2_DCFG_DEVSPD_USBFS20 1 +#define USB_DWC2_DCFG_DEVSPD_USBLS116 2 +#define USB_DWC2_DCFG_DEVSPD_USBFS1148 3 + +USB_DWC2_SET_FIELD_DEFINE(dcfg_devaddr, DCFG_DEVADDR) +USB_DWC2_GET_FIELD_DEFINE(dcfg_devspd, DCFG_DEVSPD) + +/* Device control register */ +#define USB_DWC2_DCTL 0x0804UL +#define USB_DWC2_DCTL_SERVINT_POS 19UL +#define USB_DWC2_DCTL_SERVINT BIT(USB_DWC2_DCTL_SERVINT_POS) +#define USB_DWC2_DCTL_DEEPSLEEPBESLREJECT_POS 18UL +#define USB_DWC2_DCTL_DEEPSLEEPBESLREJECT BIT(USB_DWC2_DCTL_DEEPSLEEPBESLREJECT_POS) +#define USB_DWC2_DCTL_NAKONBBLE_POS 16UL +#define USB_DWC2_DCTL_NAKONBBLE BIT(USB_DWC2_DCTL_NAKONBBLE_POS) +#define USB_DWC2_DCTL_IGNRFRMNUM_POS 15UL +#define USB_DWC2_DCTL_IGNRFRMNUM BIT(USB_DWC2_DCTL_IGNRFRMNUM_POS) +#define USB_DWC2_DCTL_PWRONPRGDONE_POS 11UL +#define USB_DWC2_DCTL_PWRONPRGDONE BIT(USB_DWC2_DCTL_PWRONPRGDONE_POS) +#define USB_DWC2_DCTL_CGOUTNAK_POS 10UL +#define USB_DWC2_DCTL_CGOUTNAK BIT(USB_DWC2_DCTL_CGOUTNAK_POS) +#define USB_DWC2_DCTL_SGOUTNAK_POS 9UL +#define USB_DWC2_DCTL_SGOUTNAK BIT(USB_DWC2_DCTL_SGOUTNAK_POS) +#define USB_DWC2_DCTL_CGNPINNAK_POS 8UL +#define USB_DWC2_DCTL_CGNPINNAK BIT(USB_DWC2_DCTL_CGNPINNAK_POS) +#define USB_DWC2_DCTL_SGNPINNAK_POS 7UL +#define USB_DWC2_DCTL_SGNPINNAK BIT(USB_DWC2_DCTL_SGNPINNAK_POS) +#define USB_DWC2_DCTL_TSTCTL_POS 4UL +#define USB_DWC2_DCTL_TSTCTL_MASK (0x7UL << USB_DWC2_DCTL_TSTCTL_POS) +#define USB_DWC2_DCTL_TSTCTL_TESTFE 5UL +#define USB_DWC2_DCTL_TSTCTL_TESTPM 4UL +#define USB_DWC2_DCTL_TSTCTL_TESTSN 3UL +#define USB_DWC2_DCTL_TSTCTL_TESTK 2UL +#define USB_DWC2_DCTL_TSTCTL_TESTJ 1UL +#define USB_DWC2_DCTL_TSTCTL_DISABLED 0UL +#define USB_DWC2_DCTL_GOUTNAKSTS_POS 3UL +#define USB_DWC2_DCTL_GOUTNAKSTS BIT(USB_DWC2_DCTL_GOUTNAKSTS_POS) +#define USB_DWC2_DCTL_GNPINNAKSTS_POS 2UL +#define USB_DWC2_DCTL_GNPINNAKSTS BIT(USB_DWC2_DCTL_GNPINNAKSTS_POS) +#define USB_DWC2_DCTL_SFTDISCON_POS 1UL +#define USB_DWC2_DCTL_SFTDISCON BIT(USB_DWC2_DCTL_SFTDISCON_POS) +#define USB_DWC2_DCTL_RMTWKUPSIG_POS 0UL +#define USB_DWC2_DCTL_RMTWKUPSIG BIT(USB_DWC2_DCTL_RMTWKUPSIG_POS) + +USB_DWC2_GET_FIELD_DEFINE(dctl_tstctl, DCTL_TSTCTL) +USB_DWC2_SET_FIELD_DEFINE(dctl_tstctl, DCTL_TSTCTL) + +/* Device status register */ +#define USB_DWC2_DSTS 0x0808UL +#define USB_DWC2_DSTS_ENUMSPD_POS 1UL +#define USB_DWC2_DSTS_ENUMSPD_MASK (0x3UL << USB_DWC2_DSTS_ENUMSPD_POS) +#define USB_DWC2_DSTS_ENUMSPD_HS3060 0 +#define USB_DWC2_DSTS_ENUMSPD_FS3060 1 +#define USB_DWC2_DSTS_ENUMSPD_LS6 2 +#define USB_DWC2_DSTS_ENUMSPD_FS48 3 + +USB_DWC2_GET_FIELD_DEFINE(dsts_enumspd, DSTS_ENUMSPD) + +/* Device all endpoints interrupt registers */ +#define USB_DWC2_DAINT 0x0818UL +#define USB_DWC2_DAINTMSK 0x081CUL +#define USB_DWC2_DAINT_OUTEPINT(ep_num) BIT(16UL + ep_num) +#define USB_DWC2_DAINT_INEPINT(ep_num) BIT(ep_num) + +/* + * Device IN/OUT endpoint control register + * IN endpoint offsets 0x0900 + (0x20 * n), n = 0 .. x, + * OUT endpoint offsets 0x0B00 + (0x20 * n), n = 0 .. x, + * + */ +#define USB_DWC2_DIEPCTL0 0x0900UL +#define USB_DWC2_DOEPCTL0 0x0B00UL +#define USB_DWC2_DEPCTL_EPENA_POS 31UL +#define USB_DWC2_DEPCTL_EPENA BIT(USB_DWC2_DEPCTL_EPENA_POS) +#define USB_DWC2_DEPCTL_EPDIS_POS 30UL +#define USB_DWC2_DEPCTL_EPDIS BIT(USB_DWC2_DEPCTL_EPDIS_POS) +#define USB_DWC2_DEPCTL_SETD0PID_POS 28UL +#define USB_DWC2_DEPCTL_SETD0PID BIT(USB_DWC2_DEPCTL_SETD0PID_POS) +#define USB_DWC2_DEPCTL_SNAK_POS 27UL +#define USB_DWC2_DEPCTL_SNAK BIT(USB_DWC2_DEPCTL_SNAK_POS) +#define USB_DWC2_DEPCTL_CNAK_POS 26UL +#define USB_DWC2_DEPCTL_CNAK BIT(USB_DWC2_DEPCTL_CNAK_POS) +#define USB_DWC2_DEPCTL_TXFNUM_POS 22UL +#define USB_DWC2_DEPCTL_TXFNUM_MASK (0xFUL << USB_DWC2_DEPCTL_TXFNUM_POS) +#define USB_DWC2_DEPCTL_STALL_POS 21UL +#define USB_DWC2_DEPCTL_STALL BIT(USB_DWC2_DEPCTL_STALL_POS) +#define USB_DWC2_DEPCTL_EPTYPE_POS 18UL +#define USB_DWC2_DEPCTL_EPTYPE_MASK (0x3UL << USB_DWC2_DEPCTL_EPTYPE_POS) +#define USB_DWC2_DEPCTL_EPTYPE_INTERRUPT 3 +#define USB_DWC2_DEPCTL_EPTYPE_BULK 2 +#define USB_DWC2_DEPCTL_EPTYPE_ISO 1 +#define USB_DWC2_DEPCTL_EPTYPE_CONTROL 0 +#define USB_DWC2_DEPCTL_USBACTEP_POS 15UL +#define USB_DWC2_DEPCTL_USBACTEP BIT(USB_DWC2_DEPCTL_USBACTEP_POS) +#define USB_DWC2_DEPCTL0_MPS_POS 0UL +#define USB_DWC2_DEPCTL0_MPS_MASK (0x3UL << USB_DWC2_DEPCTL0_MPS_POS) +#define USB_DWC2_DEPCTL0_MPS_8 3 +#define USB_DWC2_DEPCTL0_MPS_16 2 +#define USB_DWC2_DEPCTL0_MPS_32 1 +#define USB_DWC2_DEPCTL0_MPS_64 0 +#define USB_DWC2_DEPCTL_MPS_POS 0UL +#define USB_DWC2_DEPCTL_MPS_MASK (0x7FF << USB_DWC2_DEPCTL_MPS_POS) + +USB_DWC2_GET_FIELD_DEFINE(depctl_txfnum, DEPCTL_TXFNUM) +USB_DWC2_SET_FIELD_DEFINE(depctl_txfnum, DEPCTL_TXFNUM) +USB_DWC2_GET_FIELD_DEFINE(depctl_eptype, DEPCTL_EPTYPE) +USB_DWC2_SET_FIELD_DEFINE(depctl_eptype, DEPCTL_EPTYPE) +USB_DWC2_GET_FIELD_DEFINE(depctl0_mps, DEPCTL0_MPS) +USB_DWC2_SET_FIELD_DEFINE(depctl0_mps, DEPCTL0_MPS) +USB_DWC2_GET_FIELD_DEFINE(depctl_mps, DEPCTL_MPS) +USB_DWC2_SET_FIELD_DEFINE(depctl_mps, DEPCTL_MPS) + +/* + * Device IN endpoint interrupt register + * offsets 0x0908 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DIEPINT0 0x0908UL +#define USB_DWC2_DIEPINT_NYETINTRPT_POS 14UL +#define USB_DWC2_DIEPINT_NYETINTRPT BIT(USB_DWC2_DIEPINT_NYETINTRPT_POS) +#define USB_DWC2_DIEPINT_NAKINTRPT_POS 13UL +#define USB_DWC2_DIEPINT_NAKINTRPT BIT(USB_DWC2_DIEPINT_NAKINTRPT_POS) +#define USB_DWC2_DIEPINT_BBLEERR_POS 12UL +#define USB_DWC2_DIEPINT_BBLEERR BIT(USB_DWC2_DIEPINT_BBLEERR_POS) +#define USB_DWC2_DIEPINT_PKTDRPSTS_POS 11UL +#define USB_DWC2_DIEPINT_PKTDRPSTS BIT(USB_DWC2_DIEPINT_PKTDRPSTS_POS) +#define USB_DWC2_DIEPINT_BNAINTR_POS 9UL +#define USB_DWC2_DIEPINT_BNAINTR BIT(USB_DWC2_DIEPINT_BNAINTR_POS) +#define USB_DWC2_DIEPINT_TXFIFOUNDRN_POS 8UL +#define USB_DWC2_DIEPINT_TXFIFOUNDRN BIT(USB_DWC2_DIEPINT_TXFIFOUNDRN_POS) +#define USB_DWC2_DIEPINT_TXFEMP_POS 7UL +#define USB_DWC2_DIEPINT_TXFEMP BIT(USB_DWC2_DIEPINT_TXFEMP_POS) +#define USB_DWC2_DIEPINT_INEPNAKEFF_POS 6UL +#define USB_DWC2_DIEPINT_INEPNAKEFF BIT(USB_DWC2_DIEPINT_INEPNAKEFF_POS) +#define USB_DWC2_DIEPINT_INTKNEPMIS_POS 5UL +#define USB_DWC2_DIEPINT_INTKNEPMIS BIT(USB_DWC2_DIEPINT_INTKNEPMIS_POS) +#define USB_DWC2_DIEPINT_INTKNTXFEMP_POS 4UL +#define USB_DWC2_DIEPINT_INTKNTXFEMP BIT(USB_DWC2_DIEPINT_INTKNTXFEMP_POS) +#define USB_DWC2_DIEPINT_TIMEOUT_POS 3UL +#define USB_DWC2_DIEPINT_TIMEOUT BIT(USB_DWC2_DIEPINT_TIMEOUT_POS) +#define USB_DWC2_DIEPINT_AHBERR_POS 2UL +#define USB_DWC2_DIEPINT_AHBERR BIT(USB_DWC2_DIEPINT_AHBERR_POS) +#define USB_DWC2_DIEPINT_EPDISBLD_POS 1UL +#define USB_DWC2_DIEPINT_EPDISBLD BIT(USB_DWC2_DIEPINT_EPDISBLD_POS) +#define USB_DWC2_DIEPINT_XFERCOMPL_POS 0UL +#define USB_DWC2_DIEPINT_XFERCOMPL BIT(USB_DWC2_DIEPINT_XFERCOMPL_POS) + +/* + * Device OUT endpoint interrupt register + * offsets 0x0B08 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DOEPINT0 0x0B08UL +#define USB_DWC2_DOEPINT_STUPPKTRCVD_POS 15UL +#define USB_DWC2_DOEPINT_STUPPKTRCVD BIT(USB_DWC2_DOEPINT_STUPPKTRCVD_POS) +#define USB_DWC2_DOEPINT_NYETINTRPT_POS 14UL +#define USB_DWC2_DOEPINT_NYETINTRPT BIT(USB_DWC2_DOEPINT_NYETINTRPT_POS) +#define USB_DWC2_DOEPINT_NAKINTRPT_POS 13UL +#define USB_DWC2_DOEPINT_NAKINTRPT BIT(USB_DWC2_DOEPINT_NAKINTRPT_POS) +#define USB_DWC2_DOEPINT_BBLEERR_POS 12UL +#define USB_DWC2_DOEPINT_BBLEERR BIT(USB_DWC2_DOEPINT_BBLEERR_POS) +#define USB_DWC2_DOEPINT_PKTDRPSTS_POS 11UL +#define USB_DWC2_DOEPINT_PKTDRPSTS BIT(USB_DWC2_DOEPINT_PKTDRPSTS_POS) +#define USB_DWC2_DOEPINT_BNAINTR_POS 9UL +#define USB_DWC2_DOEPINT_BNAINTR BIT(USB_DWC2_DOEPINT_BNAINTR_POS) +#define USB_DWC2_DOEPINT_OUTPKTERR_POS 8UL +#define USB_DWC2_DOEPINT_OUTPKTERR BIT(USB_DWC2_DOEPINT_OUTPKTERR_POS) +#define USB_DWC2_DOEPINT_BACK2BACKSETUP_POS 6UL +#define USB_DWC2_DOEPINT_BACK2BACKSETUP BIT(USB_DWC2_DOEPINT_BACK2BACKSETUP_POS) +#define USB_DWC2_DOEPINT_STSPHSERCVD_POS 5UL +#define USB_DWC2_DOEPINT_STSPHSERCVD BIT(USB_DWC2_DOEPINT_STSPHSERCVD_POS) +#define USB_DWC2_DOEPINT_OUTTKNEPDIS_POS 4UL +#define USB_DWC2_DOEPINT_OUTTKNEPDIS BIT(USB_DWC2_DOEPINT_OUTTKNEPDIS_POS) +#define USB_DWC2_DOEPINT_SETUP_POS 3UL +#define USB_DWC2_DOEPINT_SETUP BIT(USB_DWC2_DOEPINT_SETUP_POS) +#define USB_DWC2_DOEPINT_AHBERR_POS 2UL +#define USB_DWC2_DOEPINT_AHBERR BIT(USB_DWC2_DOEPINT_AHBERR_POS) +#define USB_DWC2_DOEPINT_EPDISBLD_POS 1UL +#define USB_DWC2_DOEPINT_EPDISBLD BIT(USB_DWC2_DOEPINT_EPDISBLD_POS) +#define USB_DWC2_DOEPINT_XFERCOMPL_POS 0UL +#define USB_DWC2_DOEPINT_XFERCOMPL BIT(USB_DWC2_DOEPINT_XFERCOMPL_POS) + +/* + * Device IN/OUT control endpoint transfer size register + */ +#define USB_DWC2_DIEPTSIZ0 0x0910UL +#define USB_DWC2_DOEPTSIZ0 0x0B10UL +#define USB_DWC2_DOEPTSIZ0_SUPCNT_POS 29UL +#define USB_DWC2_DOEPTSIZ0_SUPCNT_MASK (0x3UL << USB_DWC2_DOEPTSIZ0_SUPCNT_POS) +#define USB_DWC2_DOEPTSIZ0_PKTCNT_POS 19UL +#define USB_DWC2_DOEPTSIZ0_PKTCNT_MASK (0x1UL << USB_DWC2_DOEPTSIZ0_PKTCNT_POS) +#define USB_DWC2_DIEPTSIZ0_PKTCNT_POS 19UL +#define USB_DWC2_DIEPTSIZ0_PKTCNT_MASK (0x3UL << USB_DWC2_DIEPTSIZ0_PKTCNT_POS) +#define USB_DWC2_DEPTSIZ0_XFERSIZE_POS 0UL +#define USB_DWC2_DEPTSIZ0_XFERSIZE_MASK 0x7FUL + +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_supcnt, DOEPTSIZ0_SUPCNT) +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_pktcnt, DOEPTSIZ0_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(doeptsiz0_xfersize, DEPTSIZ0_XFERSIZE) +USB_DWC2_GET_FIELD_DEFINE(dieptsiz0_pktcnt, DIEPTSIZ0_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(dieptsiz0_xfersize, DEPTSIZ0_XFERSIZE) + +/* + * Device IN/OUT endpoint transfer size register + * IN at offsets 0x0910 + (0x20 * n), n = 1 .. x, + * OUT at offsets 0x0B10 + (0x20 * n), n = 1 .. x + */ +#define USB_DWC2_DEPTSIZN_PKTCNT_POS 19UL +#define USB_DWC2_DEPTSIZN_PKTCNT_MASK (0x3FFUL << USB_DWC2_DEPTSIZN_PKTCNT_POS) +#define USB_DWC2_DEPTSIZN_XFERSIZE_POS 0UL +#define USB_DWC2_DEPTSIZN_XFERSIZE_MASK 0x7FFFFUL + +USB_DWC2_GET_FIELD_DEFINE(deptsizn_pktcnt, DEPTSIZN_PKTCNT) +USB_DWC2_GET_FIELD_DEFINE(deptsizn_xfersize, DEPTSIZN_XFERSIZE) + +/* + * Device IN/OUT endpoint transfer size register + * IN at offsets 0x0910 + (0x20 * n), n = 0 .. x, + * OUT at offsets 0x0B10 + (0x20 * n), n = 0 .. x + * + * Note: Legacy definitions for the usb_dc_dw.c driver only. + */ +#define USB_DWC2_DEPTSIZ_PKT_CNT_POS 19UL +#define USB_DWC2_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19) +#define USB_DWC2_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19) +#define USB_DWC2_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19) +#define USB_DWC2_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19) +#define USB_DWC2_DOEPTSIZ_SUP_CNT_POS 29UL +#define USB_DWC2_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29) +#define USB_DWC2_DEPTSIZ_XFER_SIZE_POS 0UL +#define USB_DWC2_DEPTSIZ0_XFER_SIZE_MASK 0x7F +#define USB_DWC2_DEPTSIZn_XFER_SIZE_MASK 0x7FFFF + +/* + * Device IN endpoint transmit FIFO status register, + * offsets 0x0918 + (0x20 * n), n = 0 .. x + */ +#define USB_DWC2_DTXFSTS0 0x0918UL +#define USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_POS 0UL +#define USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_MASK 0xFFFFUL + +USB_DWC2_GET_FIELD_DEFINE(dtxfsts_ineptxfspcavail, DTXFSTS_INEPTXFSPCAVAIL) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_USB_COMMON_USB_DWC2_HW */ diff --git a/drivers/usb/device/CMakeLists.txt b/drivers/usb/device/CMakeLists.txt index 534195e4a07..6763b3c7f88 100644 --- a/drivers/usb/device/CMakeLists.txt +++ b/drivers/usb/device/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_USB_DEVICE_DRIVER) zephyr_library() +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/usb/common/) zephyr_library_sources_ifdef(CONFIG_USB_DW usb_dc_dw.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_RPI_PICO usb_dc_rpi_pico.c) @@ -19,5 +20,6 @@ zephyr_library_sources_ifdef(CONFIG_USB_NRFX usb_dc_nrfx.c) zephyr_library_sources_ifdef(CONFIG_USB_MCUX usb_dc_mcux.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_SMARTBOND usb_dc_smartbond.c) zephyr_library_sources_ifdef(CONFIG_USB_DC_IT82XX2 usb_dc_it82xx2.c) +zephyr_library_sources_ifdef(CONFIG_USB_DC_NUMAKER usb_dc_numaker.c) endif() diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index 91db896eede..3dc1a365bea 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -197,6 +197,31 @@ config USB_DC_IT82XX2 help ITE IT82XX2 USB Device Controller Driver +config USB_DC_NUMAKER + bool "Nuvoton NuMaker USB 1.1 device controller" + default y + depends on DT_HAS_NUVOTON_NUMAKER_USBD_ENABLED + help + Enable Nuvoton NuMaker USB 1.1 device controller driver + +if USB_DC_NUMAKER + +config USB_DC_NUMAKER_MSG_QUEUE_SIZE + int "USB DC message queue size" + default 32 + help + Maximum number of messages the driver can queue for interrupt bottom half processing + +config USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE + int "USB DC message handler thread stack size" + default 1536 + help + Size of the stack for the message handler thread that is used in the driver + for handling messages from the USB DC ISR, i.e. interrupt bottom half processing, + including callbacks to the USB device stack. + +endif # USB_DC_NUMAKER + config USB_NATIVE_POSIX bool "Native Posix USB Device Controller Driver" depends on ARCH_POSIX && EXTERNAL_LIBC diff --git a/drivers/usb/device/usb_dc_dw.c b/drivers/usb/device/usb_dc_dw.c index 252e4f6d639..b2f6a8f0e3c 100644 --- a/drivers/usb/device/usb_dc_dw.c +++ b/drivers/usb/device/usb_dc_dw.c @@ -25,7 +25,7 @@ #include #include -#include "usb_dw_registers.h" +#include #include "usb_dc_dw_stm32.h" #include @@ -64,11 +64,11 @@ enum usb_dw_out_ep_idx { (*(uint32_t *)(POINTER_TO_UINT(base) + 0x1000 * (idx + 1))) struct usb_dw_config { - struct usb_dw_reg *const base; + struct usb_dwc2_reg *const base; struct pinctrl_dev_config *const pcfg; void (*irq_enable_func)(const struct device *dev); int (*clk_enable_func)(void); - int (*pwr_on_func)(struct usb_dw_reg *const base); + int (*pwr_on_func)(struct usb_dwc2_reg *const base); }; /* @@ -166,7 +166,7 @@ static int usb_dw_init_pinctrl(const struct usb_dw_config *const config) } \ \ static const struct usb_dw_config usb_dw_cfg_##n = { \ - .base = (struct usb_dw_reg *)DT_INST_REG_ADDR(n), \ + .base = (struct usb_dwc2_reg *)DT_INST_REG_ADDR(n), \ .pcfg = USB_DW_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .irq_enable_func = usb_dw_irq_enable_func_##n, \ .clk_enable_func = USB_DW_GET_COMPAT_CLK_QUIRK_0(n), \ @@ -182,7 +182,7 @@ USB_DW_DEVICE_DEFINE(0) static void usb_dw_reg_dump(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t i; LOG_DBG("USB registers: GOTGCTL : 0x%x GOTGINT : 0x%x GAHBCFG : " @@ -200,16 +200,16 @@ static void usb_dw_reg_dump(void) for (i = 0U; i < USB_DW_OUT_EP_NUM; i++) { LOG_DBG("\n EP %d registers: DIEPCTL : 0x%x DIEPINT : " - "0x%x", i, base->in_ep_reg[i].diepctl, - base->in_ep_reg[i].diepint); + "0x%x", i, base->in_ep[i].diepctl, + base->in_ep[i].diepint); LOG_DBG(" DIEPTSIZ: 0x%x DIEPDMA : 0x%x DOEPCTL : " - "0x%x", base->in_ep_reg[i].dieptsiz, - base->in_ep_reg[i].diepdma, - base->out_ep_reg[i].doepctl); + "0x%x", base->in_ep[i].dieptsiz, + base->in_ep[i].diepdma, + base->out_ep[i].doepctl); LOG_DBG(" DOEPINT : 0x%x DOEPTSIZ: 0x%x DOEPDMA : " - "0x%x", base->out_ep_reg[i].doepint, - base->out_ep_reg[i].doeptsiz, - base->out_ep_reg[i].doepdma); + "0x%x", base->out_ep[i].doepint, + base->out_ep[i].doeptsiz, + base->out_ep[i].doepdma); } } @@ -250,11 +250,11 @@ static inline void usb_dw_udelay(uint32_t us) static int usb_dw_reset(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t cnt = 0U; /* Wait for AHB master idle state. */ - while (!(base->grstctl & USB_DW_GRSTCTL_AHB_IDLE)) { + while (!(base->grstctl & USB_DWC2_GRSTCTL_AHBIDLE)) { usb_dw_udelay(1); if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) { @@ -266,7 +266,7 @@ static int usb_dw_reset(void) /* Core Soft Reset */ cnt = 0U; - base->grstctl |= USB_DW_GRSTCTL_C_SFT_RST; + base->grstctl |= USB_DWC2_GRSTCTL_CSFTRST; do { if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) { @@ -275,7 +275,7 @@ static int usb_dw_reset(void) return -EIO; } usb_dw_udelay(1); - } while (base->grstctl & USB_DW_GRSTCTL_C_SFT_RST); + } while (base->grstctl & USB_DWC2_GRSTCTL_CSFTRST); /* Wait for 3 PHY Clocks */ usb_dw_udelay(100); @@ -285,14 +285,14 @@ static int usb_dw_reset(void) static int usb_dw_num_dev_eps(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; return (base->ghwcfg2 >> 10) & 0xf; } static void usb_dw_flush_tx_fifo(int ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; int fnum = usb_dw_ctrl.in_ep_ctrl[ep].fifo_num; base->grstctl = (fnum << 6) | (1<<5); @@ -302,20 +302,20 @@ static void usb_dw_flush_tx_fifo(int ep) static int usb_dw_tx_fifo_avail(int ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; - return base->in_ep_reg[ep].dtxfsts & USB_DW_DTXFSTS_TXF_SPC_AVAIL_MASK; + return base->in_ep[ep].dtxfsts & USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_MASK; } /* Choose a FIFO number for an IN endpoint */ static int usb_dw_set_fifo(uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; int ep_idx = USB_EP_GET_IDX(ep); - volatile uint32_t *reg = &base->in_ep_reg[ep_idx].diepctl; + volatile uint32_t *reg = &base->in_ep[ep_idx].diepctl; uint32_t val; int fifo = 0; - int ded_fifo = !!(base->ghwcfg4 & USB_DW_GHWCFG4_DEDFIFOMODE); + int ded_fifo = !!(base->ghwcfg4 & USB_DWC2_GHWCFG4_DEDFIFOMODE); if (!ded_fifo) { /* No support for shared-FIFO mode yet, existing @@ -340,9 +340,9 @@ static int usb_dw_set_fifo(uint8_t ep) return -EINVAL; } - reg = &base->in_ep_reg[ep_idx].diepctl; - val = *reg & ~USB_DW_DEPCTL_TXFNUM_MASK; - val |= fifo << USB_DW_DEPCTL_TXFNUM_OFFSET; + reg = &base->in_ep[ep_idx].diepctl; + val = *reg & ~USB_DWC2_DEPCTL_TXFNUM_MASK; + val |= fifo << USB_DWC2_DEPCTL_TXFNUM_POS; *reg = val; } @@ -359,40 +359,40 @@ static int usb_dw_set_fifo(uint8_t ep) static int usb_dw_ep_set(uint8_t ep, uint32_t ep_mps, enum usb_dc_ep_transfer_type ep_type) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; volatile uint32_t *p_depctl; uint8_t ep_idx = USB_EP_GET_IDX(ep); LOG_DBG("%s ep %x, mps %d, type %d", __func__, ep, ep_mps, ep_type); if (USB_EP_DIR_IS_OUT(ep)) { - p_depctl = &base->out_ep_reg[ep_idx].doepctl; + p_depctl = &base->out_ep[ep_idx].doepctl; usb_dw_ctrl.out_ep_ctrl[ep_idx].mps = ep_mps; } else { - p_depctl = &base->in_ep_reg[ep_idx].diepctl; + p_depctl = &base->in_ep[ep_idx].diepctl; usb_dw_ctrl.in_ep_ctrl[ep_idx].mps = ep_mps; } if (!ep_idx) { /* Set max packet size for EP0 */ - *p_depctl &= ~USB_DW_DEPCTL0_MSP_MASK; + *p_depctl &= ~USB_DWC2_DEPCTL0_MPS_MASK; switch (ep_mps) { case 8: - *p_depctl |= USB_DW_DEPCTL0_MSP_8 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_8 << + USB_DWC2_DEPCTL_MPS_POS; break; case 16: - *p_depctl |= USB_DW_DEPCTL0_MSP_16 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_16 << + USB_DWC2_DEPCTL_MPS_POS; break; case 32: - *p_depctl |= USB_DW_DEPCTL0_MSP_32 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_32 << + USB_DWC2_DEPCTL_MPS_POS; break; case 64: - *p_depctl |= USB_DW_DEPCTL0_MSP_64 << - USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL0_MPS_64 << + USB_DWC2_DEPCTL_MPS_POS; break; default: return -EINVAL; @@ -400,36 +400,36 @@ static int usb_dw_ep_set(uint8_t ep, /* No need to set EP0 type */ } else { /* Set max packet size for EP */ - if (ep_mps > (USB_DW_DEPCTLn_MSP_MASK >> - USB_DW_DEPCTL_MSP_OFFSET)) { + if (ep_mps > (USB_DWC2_DEPCTL_MPS_MASK >> + USB_DWC2_DEPCTL_MPS_POS)) { return -EINVAL; } - *p_depctl &= ~USB_DW_DEPCTLn_MSP_MASK; - *p_depctl |= ep_mps << USB_DW_DEPCTL_MSP_OFFSET; + *p_depctl &= ~USB_DWC2_DEPCTL_MPS_MASK; + *p_depctl |= ep_mps << USB_DWC2_DEPCTL_MPS_POS; /* Set endpoint type */ - *p_depctl &= ~USB_DW_DEPCTL_EP_TYPE_MASK; + *p_depctl &= ~USB_DWC2_DEPCTL_EPTYPE_MASK; switch (ep_type) { case USB_DC_EP_CONTROL: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_CONTROL << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_CONTROL << + USB_DWC2_DEPCTL_EPTYPE_POS; break; case USB_DC_EP_BULK: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_BULK << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_BULK << + USB_DWC2_DEPCTL_EPTYPE_POS; break; case USB_DC_EP_INTERRUPT: - *p_depctl |= USB_DW_DEPCTL_EP_TYPE_INTERRUPT << - USB_DW_DEPCTL_EP_TYPE_OFFSET; + *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_INTERRUPT << + USB_DWC2_DEPCTL_EPTYPE_POS; break; default: return -EINVAL; } /* sets the Endpoint Data PID to DATA0 */ - *p_depctl |= USB_DW_DEPCTL_SETDOPID; + *p_depctl |= USB_DWC2_DEPCTL_SETD0PID; } if (USB_EP_DIR_IS_IN(ep)) { @@ -445,7 +445,7 @@ static int usb_dw_ep_set(uint8_t ep, static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep); uint32_t ep_mps = usb_dw_ctrl.out_ep_ctrl[ep_idx].mps; @@ -453,16 +453,16 @@ static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) * each time a packet is received */ - base->out_ep_reg[ep_idx].doeptsiz = - (USB_DW_SUP_CNT << USB_DW_DOEPTSIZ_SUP_CNT_OFFSET) | - (1 << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | ep_mps; + base->out_ep[ep_idx].doeptsiz = + (USB_DW_SUP_CNT << USB_DWC2_DOEPTSIZ_SUP_CNT_POS) | + (1 << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | ep_mps; /* Clear NAK and enable ep */ if (!setup) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_CNAK; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_CNAK; } - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_EP_ENA; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_EPENA; LOG_DBG("USB OUT EP%d armed", ep_idx); } @@ -470,7 +470,7 @@ static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup) static int usb_dw_tx(uint8_t ep, const uint8_t *const data, uint32_t data_len) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; enum usb_dw_in_ep_idx ep_idx = USB_EP_GET_IDX(ep); uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space; uint32_t ep_mps = usb_dw_ctrl.in_ep_ctrl[ep_idx].mps; @@ -492,7 +492,7 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, avail_space *= 4U; if (!avail_space) { LOG_ERR("USB IN EP%d no space available, DTXFSTS %x", ep_idx, - base->in_ep_reg[ep_idx].dtxfsts); + base->in_ep[ep_idx].dtxfsts); irq_unlock(key); return -EAGAIN; } @@ -510,18 +510,18 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, /* Get max packet size and packet count for ep */ if (ep_idx == USB_DW_IN_EP_0) { max_pkt_cnt = - USB_DW_DIEPTSIZ0_PKT_CNT_MASK >> - USB_DW_DEPTSIZ_PKT_CNT_OFFSET; + USB_DWC2_DIEPTSIZ0_PKT_CNT_MASK >> + USB_DWC2_DEPTSIZ_PKT_CNT_POS; max_xfer_size = - USB_DW_DEPTSIZ0_XFER_SIZE_MASK >> - USB_DW_DEPTSIZ_XFER_SIZE_OFFSET; + USB_DWC2_DEPTSIZ0_XFER_SIZE_MASK >> + USB_DWC2_DEPTSIZ_XFER_SIZE_POS; } else { max_pkt_cnt = - USB_DW_DIEPTSIZn_PKT_CNT_MASK >> - USB_DW_DEPTSIZ_PKT_CNT_OFFSET; + USB_DWC2_DIEPTSIZn_PKT_CNT_MASK >> + USB_DWC2_DEPTSIZ_PKT_CNT_POS; max_xfer_size = - USB_DW_DEPTSIZn_XFER_SIZE_MASK >> - USB_DW_DEPTSIZ_XFER_SIZE_OFFSET; + USB_DWC2_DEPTSIZn_XFER_SIZE_MASK >> + USB_DWC2_DEPTSIZ_XFER_SIZE_POS; } /* Check if transfer len is too big */ @@ -551,12 +551,12 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, } /* Set number of packets and transfer size */ - base->in_ep_reg[ep_idx].dieptsiz = - (pkt_cnt << USB_DW_DEPTSIZ_PKT_CNT_OFFSET) | data_len; + base->in_ep[ep_idx].dieptsiz = + (pkt_cnt << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | data_len; /* Clear NAK and enable ep */ - base->in_ep_reg[ep_idx].diepctl |= (USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_CNAK); + base->in_ep[ep_idx].diepctl |= (USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_CNAK); /* * Write data to FIFO, make sure that we are protected against @@ -592,7 +592,7 @@ static int usb_dw_tx(uint8_t ep, const uint8_t *const data, static int usb_dw_init(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep; int ret; @@ -605,36 +605,36 @@ static int usb_dw_init(void) * Force device mode as we do no support other roles or role changes. * Wait 25ms for the change to take effect. */ - base->gusbcfg |= USB_DW_GUSBCFG_FORCEDEVMODE; + base->gusbcfg |= USB_DWC2_GUSBCFG_FORCEDEVMODE; k_msleep(25); #ifdef CONFIG_USB_DW_USB_2_0 /* set the PHY interface to be 16-bit UTMI */ - base->gusbcfg = (base->gusbcfg & ~USB_DW_GUSBCFG_PHY_IF_MASK) | - USB_DW_GUSBCFG_PHY_IF_16_BIT; + base->gusbcfg = (base->gusbcfg & ~USB_DWC2_GUSBCFG_PHYIF_16_BIT) | + USB_DWC2_GUSBCFG_PHYIF_16_BIT; /* Set USB2.0 High Speed */ - base->dcfg |= USB_DW_DCFG_DEV_SPD_USB2_HS; + base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBHS20; #else /* Set device speed to Full Speed */ - base->dcfg |= USB_DW_DCFG_DEV_SPD_FS; + base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBFS1148; #endif /* Set NAK for all OUT EPs */ for (ep = 0U; ep < USB_DW_OUT_EP_NUM; ep++) { - base->out_ep_reg[ep].doepctl = USB_DW_DEPCTL_SNAK; + base->out_ep[ep].doepctl = USB_DWC2_DEPCTL_SNAK; } /* Enable global interrupts */ - base->gintmsk = USB_DW_GINTSTS_OEP_INT | - USB_DW_GINTSTS_IEP_INT | - USB_DW_GINTSTS_ENUM_DONE | - USB_DW_GINTSTS_USB_RST | - USB_DW_GINTSTS_WK_UP_INT | - USB_DW_GINTSTS_USB_SUSP; + base->gintmsk = USB_DWC2_GINTSTS_OEPINT | + USB_DWC2_GINTSTS_IEPINT | + USB_DWC2_GINTSTS_ENUMDONE | + USB_DWC2_GINTSTS_USBRST | + USB_DWC2_GINTSTS_WKUPINT | + USB_DWC2_GINTSTS_USBSUSP; /* Enable global interrupt */ - base->gahbcfg |= USB_DW_GAHBCFG_GLB_INTR_MASK; + base->gahbcfg |= USB_DWC2_GAHBCFG_GLBINTRMASK; /* Call vendor-specific function to enable peripheral */ if (usb_dw_cfg.pwr_on_func != NULL) { @@ -645,7 +645,7 @@ static int usb_dw_init(void) } /* Disable soft disconnect */ - base->dctl &= ~USB_DW_DCTL_SFT_DISCON; + base->dctl &= ~USB_DWC2_DCTL_SFTDISCON; usb_dw_reg_dump(); @@ -654,7 +654,7 @@ static int usb_dw_init(void) static void usb_dw_handle_reset(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; LOG_DBG("USB RESET event"); @@ -664,24 +664,24 @@ static void usb_dw_handle_reset(void) } /* Clear device address during reset. */ - base->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK; + base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK; /* enable global EP interrupts */ base->doepmsk = 0U; - base->gintmsk |= USB_DW_GINTSTS_RX_FLVL; - base->diepmsk |= USB_DW_DIEPINT_XFER_COMPL; + base->gintmsk |= USB_DWC2_GINTSTS_RXFLVL; + base->diepmsk |= USB_DWC2_DIEPINT_XFERCOMPL; } static void usb_dw_handle_enum_done(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t speed; - speed = (base->dsts & ~USB_DW_DSTS_ENUM_SPD_MASK) >> - USB_DW_DSTS_ENUM_SPD_OFFSET; + speed = (base->dsts & ~USB_DWC2_DSTS_ENUMSPD_MASK) >> + USB_DWC2_DSTS_ENUMSPD_POS; LOG_DBG("USB ENUM DONE event, %s speed detected", - speed == USB_DW_DSTS_ENUM_LS ? "Low" : "Full"); + speed == USB_DWC2_DSTS_ENUMSPD_LS6 ? "Low" : "Full"); /* Inform upper layers */ if (usb_dw_ctrl.status_cb) { @@ -692,7 +692,7 @@ static void usb_dw_handle_enum_done(void) /* USB ISR handler */ static inline void usb_dw_int_rx_flvl_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t grxstsp = base->grxstsp; uint32_t status, xfer_size; uint8_t ep_idx; @@ -700,11 +700,11 @@ static inline void usb_dw_int_rx_flvl_handler(void) /* Packet in RX FIFO */ - ep_idx = grxstsp & USB_DW_GRXSTSR_EP_NUM_MASK; - status = (grxstsp & USB_DW_GRXSTSR_PKT_STS_MASK) >> - USB_DW_GRXSTSR_PKT_STS_OFFSET; - xfer_size = (grxstsp & USB_DW_GRXSTSR_PKT_CNT_MASK) >> - USB_DW_GRXSTSR_PKT_CNT_OFFSET; + ep_idx = grxstsp & USB_DWC2_GRXSTSR_EPNUM_MASK; + status = (grxstsp & USB_DWC2_GRXSTSR_PKTSTS_MASK) >> + USB_DWC2_GRXSTSR_PKTSTS_POS; + xfer_size = (grxstsp & USB_DWC2_GRXSTSR_BCNT_MASK) >> + USB_DWC2_GRXSTSR_BCNT_POS; LOG_DBG("USB OUT EP%u: RX_FLVL status %u, size %u", ep_idx, status, xfer_size); @@ -713,7 +713,7 @@ static inline void usb_dw_int_rx_flvl_handler(void) ep_cb = usb_dw_ctrl.out_ep_ctrl[ep_idx].cb; switch (status) { - case USB_DW_GRXSTSR_PKT_STS_SETUP: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP: /* Call the registered callback if any */ if (ep_cb) { ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT), @@ -721,15 +721,15 @@ static inline void usb_dw_int_rx_flvl_handler(void) } break; - case USB_DW_GRXSTSR_PKT_STS_OUT_DATA: + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA: if (ep_cb) { ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT), USB_DC_EP_DATA_OUT); } break; - case USB_DW_GRXSTSR_PKT_STS_OUT_DATA_DONE: - case USB_DW_GRXSTSR_PKT_STS_SETUP_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: break; default: break; @@ -738,26 +738,26 @@ static inline void usb_dw_int_rx_flvl_handler(void) static inline void usb_dw_int_iep_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t ep_int_status; uint8_t ep_idx; usb_dc_ep_callback ep_cb; for (ep_idx = 0U; ep_idx < USB_DW_IN_EP_NUM; ep_idx++) { - if (base->daint & USB_DW_DAINT_IN_EP_INT(ep_idx)) { + if (base->daint & USB_DWC2_DAINT_INEPINT(ep_idx)) { /* Read IN EP interrupt status */ - ep_int_status = base->in_ep_reg[ep_idx].diepint & + ep_int_status = base->in_ep[ep_idx].diepint & base->diepmsk; /* Clear IN EP interrupts */ - base->in_ep_reg[ep_idx].diepint = ep_int_status; + base->in_ep[ep_idx].diepint = ep_int_status; LOG_DBG("USB IN EP%u interrupt status: 0x%x", ep_idx, ep_int_status); ep_cb = usb_dw_ctrl.in_ep_ctrl[ep_idx].cb; if (ep_cb && - (ep_int_status & USB_DW_DIEPINT_XFER_COMPL)) { + (ep_int_status & USB_DWC2_DIEPINT_XFERCOMPL)) { /* Call the registered callback */ ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_IN), @@ -767,23 +767,23 @@ static inline void usb_dw_int_iep_handler(void) } /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_IEP_INT; + base->gintsts = USB_DWC2_GINTSTS_IEPINT; } static inline void usb_dw_int_oep_handler(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t ep_int_status; uint8_t ep_idx; for (ep_idx = 0U; ep_idx < USB_DW_OUT_EP_NUM; ep_idx++) { - if (base->daint & USB_DW_DAINT_OUT_EP_INT(ep_idx)) { + if (base->daint & USB_DWC2_DAINT_OUTEPINT(ep_idx)) { /* Read OUT EP interrupt status */ - ep_int_status = base->out_ep_reg[ep_idx].doepint & + ep_int_status = base->out_ep[ep_idx].doepint & base->doepmsk; /* Clear OUT EP interrupts */ - base->out_ep_reg[ep_idx].doepint = ep_int_status; + base->out_ep[ep_idx].doepint = ep_int_status; LOG_DBG("USB OUT EP%u interrupt status: 0x%x\n", ep_idx, ep_int_status); @@ -791,12 +791,12 @@ static inline void usb_dw_int_oep_handler(void) } /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_OEP_INT; + base->gintsts = USB_DWC2_GINTSTS_OEPINT; } static void usb_dw_isr_handler(const void *unused) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint32_t int_status; ARG_UNUSED(unused); @@ -806,51 +806,51 @@ static void usb_dw_isr_handler(const void *unused) LOG_DBG("USB GINTSTS 0x%x", int_status); - if (int_status & USB_DW_GINTSTS_USB_RST) { + if (int_status & USB_DWC2_GINTSTS_USBRST) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_USB_RST; + base->gintsts = USB_DWC2_GINTSTS_USBRST; /* Reset detected */ usb_dw_handle_reset(); } - if (int_status & USB_DW_GINTSTS_ENUM_DONE) { + if (int_status & USB_DWC2_GINTSTS_ENUMDONE) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_ENUM_DONE; + base->gintsts = USB_DWC2_GINTSTS_ENUMDONE; /* Enumeration done detected */ usb_dw_handle_enum_done(); } - if (int_status & USB_DW_GINTSTS_USB_SUSP) { + if (int_status & USB_DWC2_GINTSTS_USBSUSP) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_USB_SUSP; + base->gintsts = USB_DWC2_GINTSTS_USBSUSP; if (usb_dw_ctrl.status_cb) { usb_dw_ctrl.status_cb(USB_DC_SUSPEND, NULL); } } - if (int_status & USB_DW_GINTSTS_WK_UP_INT) { + if (int_status & USB_DWC2_GINTSTS_WKUPINT) { /* Clear interrupt. */ - base->gintsts = USB_DW_GINTSTS_WK_UP_INT; + base->gintsts = USB_DWC2_GINTSTS_WKUPINT; if (usb_dw_ctrl.status_cb) { usb_dw_ctrl.status_cb(USB_DC_RESUME, NULL); } } - if (int_status & USB_DW_GINTSTS_RX_FLVL) { + if (int_status & USB_DWC2_GINTSTS_RXFLVL) { /* Packet in RX FIFO */ usb_dw_int_rx_flvl_handler(); } - if (int_status & USB_DW_GINTSTS_IEP_INT) { + if (int_status & USB_DWC2_GINTSTS_IEPINT) { /* IN EP interrupt */ usb_dw_int_iep_handler(); } - if (int_status & USB_DW_GINTSTS_OEP_INT) { + if (int_status & USB_DWC2_GINTSTS_OEPINT) { /* No OUT interrupt expected in FIFO mode, * just clear interrupt */ @@ -894,7 +894,7 @@ int usb_dc_attach(void) int usb_dc_detach(void) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; if (!usb_dw_ctrl.attached) { return 0; @@ -903,7 +903,7 @@ int usb_dc_detach(void) irq_disable(DT_INST_IRQN(0)); /* Enable soft disconnect */ - base->dctl |= USB_DW_DCTL_SFT_DISCON; + base->dctl |= USB_DWC2_DCTL_SFTDISCON; usb_dw_ctrl.attached = 0U; @@ -924,14 +924,14 @@ int usb_dc_reset(void) int usb_dc_set_address(const uint8_t addr) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; - if (addr > (USB_DW_DCFG_DEV_ADDR_MASK >> USB_DW_DCFG_DEV_ADDR_OFFSET)) { + if (addr > (USB_DWC2_DCFG_DEVADDR_MASK >> USB_DWC2_DCFG_DEVADDR_POS)) { return -EINVAL; } - base->dcfg &= ~USB_DW_DCFG_DEV_ADDR_MASK; - base->dcfg |= addr << USB_DW_DCFG_DEV_ADDR_OFFSET; + base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK; + base->dcfg |= addr << USB_DWC2_DCFG_DEVADDR_POS; return 0; } @@ -988,7 +988,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg) int usb_dc_ep_set_stall(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -997,9 +997,9 @@ int usb_dc_ep_set_stall(const uint8_t ep) } if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_STALL; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_STALL; } else { - base->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_STALL; + base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_STALL; } return 0; @@ -1007,7 +1007,7 @@ int usb_dc_ep_set_stall(const uint8_t ep) int usb_dc_ep_clear_stall(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1021,9 +1021,9 @@ int usb_dc_ep_clear_stall(const uint8_t ep) } if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl &= ~USB_DW_DEPCTL_STALL; + base->out_ep[ep_idx].doepctl &= ~USB_DWC2_DEPCTL_STALL; } else { - base->in_ep_reg[ep_idx].diepctl &= ~USB_DW_DEPCTL_STALL; + base->in_ep[ep_idx].diepctl &= ~USB_DWC2_DEPCTL_STALL; } return 0; @@ -1031,7 +1031,7 @@ int usb_dc_ep_clear_stall(const uint8_t ep) int usb_dc_ep_halt(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); volatile uint32_t *p_depctl; @@ -1045,16 +1045,16 @@ int usb_dc_ep_halt(const uint8_t ep) usb_dc_ep_set_stall(ep); } else { if (USB_EP_DIR_IS_OUT(ep)) { - p_depctl = &base->out_ep_reg[ep_idx].doepctl; + p_depctl = &base->out_ep[ep_idx].doepctl; } else { - p_depctl = &base->in_ep_reg[ep_idx].diepctl; + p_depctl = &base->in_ep[ep_idx].diepctl; } /* Set STALL and disable endpoint if enabled */ - if (*p_depctl & USB_DW_DEPCTL_EP_ENA) { - *p_depctl |= USB_DW_DEPCTL_EP_DIS | USB_DW_DEPCTL_STALL; + if (*p_depctl & USB_DWC2_DEPCTL_EPENA) { + *p_depctl |= USB_DWC2_DEPCTL_EPDIS | USB_DWC2_DEPCTL_STALL; } else { - *p_depctl |= USB_DW_DEPCTL_STALL; + *p_depctl |= USB_DWC2_DEPCTL_STALL; } } @@ -1063,7 +1063,7 @@ int usb_dc_ep_halt(const uint8_t ep) int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1077,11 +1077,11 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) *stalled = 0U; if (USB_EP_DIR_IS_OUT(ep)) { - if (base->out_ep_reg[ep_idx].doepctl & USB_DW_DEPCTL_STALL) { + if (base->out_ep[ep_idx].doepctl & USB_DWC2_DEPCTL_STALL) { *stalled = 1U; } } else { - if (base->in_ep_reg[ep_idx].diepctl & USB_DW_DEPCTL_STALL) { + if (base->in_ep[ep_idx].diepctl & USB_DWC2_DEPCTL_STALL) { *stalled = 1U; } } @@ -1091,7 +1091,7 @@ int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) int usb_dc_ep_enable(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1101,17 +1101,17 @@ int usb_dc_ep_enable(const uint8_t ep) /* enable EP interrupts */ if (USB_EP_DIR_IS_OUT(ep)) { - base->daintmsk |= USB_DW_DAINT_OUT_EP_INT(ep_idx); + base->daintmsk |= USB_DWC2_DAINT_OUTEPINT(ep_idx); } else { - base->daintmsk |= USB_DW_DAINT_IN_EP_INT(ep_idx); + base->daintmsk |= USB_DWC2_DAINT_INEPINT(ep_idx); } /* Activate Ep */ if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl |= USB_DW_DEPCTL_USB_ACT_EP; + base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_USBACTEP; usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1U; } else { - base->in_ep_reg[ep_idx].diepctl |= USB_DW_DEPCTL_USB_ACT_EP; + base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_USBACTEP; usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1U; } @@ -1126,7 +1126,7 @@ int usb_dc_ep_enable(const uint8_t ep) int usb_dc_ep_disable(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) { @@ -1136,26 +1136,26 @@ int usb_dc_ep_disable(const uint8_t ep) /* Disable EP interrupts */ if (USB_EP_DIR_IS_OUT(ep)) { - base->daintmsk &= ~USB_DW_DAINT_OUT_EP_INT(ep_idx); - base->doepmsk &= ~USB_DW_DOEPINT_SET_UP; + base->daintmsk &= ~USB_DWC2_DAINT_OUTEPINT(ep_idx); + base->doepmsk &= ~USB_DWC2_DOEPINT_SETUP; } else { - base->daintmsk &= ~USB_DW_DAINT_IN_EP_INT(ep_idx); - base->diepmsk &= ~USB_DW_DIEPINT_XFER_COMPL; - base->gintmsk &= ~USB_DW_GINTSTS_RX_FLVL; + base->daintmsk &= ~USB_DWC2_DAINT_INEPINT(ep_idx); + base->diepmsk &= ~USB_DWC2_DIEPINT_XFERCOMPL; + base->gintmsk &= ~USB_DWC2_GINTSTS_RXFLVL; } /* De-activate, disable and set NAK for Ep */ if (USB_EP_DIR_IS_OUT(ep)) { - base->out_ep_reg[ep_idx].doepctl &= - ~(USB_DW_DEPCTL_USB_ACT_EP | - USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_SNAK); + base->out_ep[ep_idx].doepctl &= + ~(USB_DWC2_DEPCTL_USBACTEP | + USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_SNAK); usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 0U; } else { - base->in_ep_reg[ep_idx].diepctl &= - ~(USB_DW_DEPCTL_USB_ACT_EP | - USB_DW_DEPCTL_EP_ENA | - USB_DW_DEPCTL_SNAK); + base->in_ep[ep_idx].diepctl &= + ~(USB_DWC2_DEPCTL_USBACTEP | + USB_DWC2_DEPCTL_EPENA | + USB_DWC2_DEPCTL_SNAK); usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 0U; } @@ -1164,7 +1164,7 @@ int usb_dc_ep_disable(const uint8_t ep) int usb_dc_ep_flush(const uint8_t ep) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t cnt; @@ -1179,8 +1179,8 @@ int usb_dc_ep_flush(const uint8_t ep) } /* Each endpoint has dedicated Tx FIFO */ - base->grstctl |= ep_idx << USB_DW_GRSTCTL_TX_FNUM_OFFSET; - base->grstctl |= USB_DW_GRSTCTL_TX_FFLSH; + base->grstctl |= ep_idx << USB_DWC2_GRSTCTL_TXFNUM_POS; + base->grstctl |= USB_DWC2_GRSTCTL_TXFFLSH; cnt = 0U; @@ -1190,7 +1190,7 @@ int usb_dc_ep_flush(const uint8_t ep) return -EIO; } usb_dw_udelay(1); - } while (base->grstctl & USB_DW_GRSTCTL_TX_FFLSH); + } while (base->grstctl & USB_DWC2_GRSTCTL_TXFFLSH); return 0; } @@ -1230,7 +1230,7 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, uint32_t *read_bytes) { - struct usb_dw_reg *const base = usb_dw_cfg.base; + struct usb_dwc2_reg *const base = usb_dw_cfg.base; uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t i, j, data_len, bytes_to_copy; diff --git a/drivers/usb/device/usb_dc_dw_stm32.h b/drivers/usb/device/usb_dc_dw_stm32.h index 282ae41ab99..e2cd5208459 100644 --- a/drivers/usb/device/usb_dc_dw_stm32.h +++ b/drivers/usb/device/usb_dc_dw_stm32.h @@ -11,7 +11,7 @@ #include #include -#include "usb_dw_registers.h" +#include struct usb_dw_stm32_clk { const struct device *const dev; @@ -52,9 +52,9 @@ static inline int clk_enable_st_stm32f4_fsotg(const struct usb_dw_stm32_clk *con return clock_control_on(clk->dev, (void *)&clk->pclken[0]); } -static inline int pwr_on_st_stm32f4_fsotg(struct usb_dw_reg *const base) +static inline int pwr_on_st_stm32f4_fsotg(struct usb_dwc2_reg *const base) { - base->ggpio |= USB_DW_GGPIO_STM32_PWRDWN | USB_DW_GGPIO_STM32_VBDEN; + base->ggpio |= USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN; return 0; } diff --git a/drivers/usb/device/usb_dc_it82xx2.c b/drivers/usb/device/usb_dc_it82xx2.c index b5307252325..e453144473c 100644 --- a/drivers/usb/device/usb_dc_it82xx2.c +++ b/drivers/usb/device/usb_dc_it82xx2.c @@ -20,11 +20,12 @@ #include LOG_MODULE_REGISTER(usb_dc_it82xx2, CONFIG_USB_DRIVER_LOG_LEVEL); +#define IT8XXX2_IS_EXTEND_ENDPOINT(n) (USB_EP_GET_IDX(n) >= 4) + /* USB Device Controller Registers Bits & Constants */ #define IT8XXX2_USB_IRQ DT_INST_IRQ_BY_IDX(0, 0, irq) #define IT8XXX2_WU90_IRQ DT_INST_IRQ_BY_IDX(0, 1, irq) -#define MAX_NUM_ENDPOINTS 16 #define FIFO_NUM 3 #define SETUP_DATA_CNT 8 #define DC_ADDR_NULL 0x00 @@ -42,13 +43,8 @@ LOG_MODULE_REGISTER(usb_dc_it82xx2, CONFIG_USB_DRIVER_LOG_LEVEL); #define RX_LINE_RESET 0x00 /* EPN Extend Control 2 Register Mask Definition */ -#define READY_BITS 0x0F #define COMPLETED_TRANS 0xF0 -/* EP Definitions */ -#define EP_VALID_MASK 0x0F -#define EP_INVALID_MASK ~(USB_EP_DIR_MASK | EP_VALID_MASK) - /* Bit [1:0] represents the TRANSACTION_TYPE as follows: */ enum it82xx2_transaction_types { DC_SETUP_TRANS, @@ -66,15 +62,6 @@ enum it82xx2_transaction_types { /* The bit definitions of the register Host/Device Control: 0XE0 */ #define RESET_CORE BIT(1) -/* Bit definitions of the register Port0/Port1 MISC Control: 0XE4/0xE8 */ -#define PULL_DOWN_EN BIT(4) - -/* Bit definitions of the register EPN0N1_EXTEND_CONTROL_REG: 0X98 ~ 0X9D */ -#define EPN1_OUTDATA_SEQ BIT(4) -#define EPN0_ISO_ENABLE BIT(2) -#define EPN0_SEND_STALL BIT(1) -#define EPN0_OUTDATA_SEQ BIT(0) - /* ENDPOINT[3..0]_STATUS_REG */ #define DC_STALL_SENT BIT(5) @@ -96,13 +83,10 @@ enum it82xx2_transaction_types { /* ENDPOINT[3..0]_CONTROL_REG */ #define ENDPOINT_EN BIT(0) #define ENDPOINT_RDY BIT(1) -#define EP_OUTDATA_SEQ BIT(2) #define EP_SEND_STALL BIT(3) -#define EP_ISO_ENABLE BIT(4) -#define EP_DIRECTION BIT(5) enum it82xx2_ep_status { - EP_INIT, + EP_INIT = 0, EP_CHECK, EP_CONFIG, EP_CONFIG_IN, @@ -124,23 +108,15 @@ enum it82xx2_setup_stage { STALL_SEND, }; -enum it82xx2_extend_ep_ctrl { - /* EPN0N1_EXTEND_CONTROL_REG */ - EXT_EP_ISO_DISABLE, - EXT_EP_ISO_ENABLE, - EXT_EP_SEND_STALL, - EXT_EP_CLEAR_STALL, - EXT_EP_CHECK_STALL, - EXT_EP_DATA_SEQ_1, - EXT_EP_DATA_SEQ_0, - EXT_EP_DATA_SEQ_INV, - /* EPN_EXTEND_CONTROL1_REG */ - EXT_EP_DIR_IN, - EXT_EP_DIR_OUT, - EXT_EP_ENABLE, - EXT_EP_DISABLE, - /* EPN_EXTEND_CONTROL2_REG */ - EXT_EP_READY, +enum it82xx2_ep_ctrl { + EP_IN_DIRECTION_SET, + EP_STALL_SEND, + EP_STALL_CHECK, + EP_IOS_ENABLE, + EP_ENABLE, + EP_DATA_SEQ_1, + EP_DATA_SEQ_TOGGLE, + EP_READY_ENABLE, }; struct usb_it8xxx2_wuc { @@ -193,43 +169,19 @@ struct usb_it82xx2_data { bool suspended; usb_dc_status_callback usb_status_cb; - /* Check the EP interrupt status for (ep > 0) */ - bool ep_ready[3]; + /* FIFO_1/2/3 ready status */ + bool fifo_ready[3]; - struct k_sem ep_sem[3]; + struct k_sem fifo_sem[3]; struct k_sem suspended_sem; struct k_work_delayable check_suspended_work; }; -/* Mapped to the bit definitions in the EPN_EXTEND_CONTROL1 Register - * (D6h to DDh) for configuring the FIFO direction and for enabling/disabling - * the endpoints. - */ -static uint8_t ext_ep_bit_shift[12] = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}; - /* The ep_fifo_res[ep_idx % FIFO_NUM] where the FIFO_NUM is 3 represents the * EP mapping because when (ep_idx % FIFO_NUM) is 3, it actually means the EP0. */ static const uint8_t ep_fifo_res[3] = {3, 1, 2}; -/* Mapping the enum it82xx2_extend_ep_ctrl code to their corresponding bit in - * the EP45/67/89/1011/1213/1415 Extended Control Registers. - */ -static const uint8_t ext_ctrl_tbl[7] = { - EPN0_ISO_ENABLE, - EPN0_ISO_ENABLE, - EPN0_SEND_STALL, - EPN0_SEND_STALL, - EPN0_SEND_STALL, - EPN0_OUTDATA_SEQ, - EPN0_OUTDATA_SEQ, -}; - -/* Indexing of the following control codes: - * EXT_EP_DIR_IN, EXT_EP_DIR_OUT, EXT_EP_ENABLE, EXT_EP_DISABLE - */ -static const uint8_t epn_ext_ctrl_tbl[4] = {1, 0, 1, 0}; - static struct usb_it82xx2_data udata0; static struct usb_it82xx2_regs *it82xx2_get_usb_regs(void) @@ -305,185 +257,244 @@ static void it8xxx2_usb_dc_wuc_init(const struct device *dev) IRQ_CONNECT(IT8XXX2_WU90_IRQ, 0, it82xx2_wu90_isr, 0, 0); } -/* Function it82xx2_get_ep_fifo_ctrl_reg_idx(uint8_t ep_idx): - * - * Calculate the register offset index which determines the corresponding - * EP FIFO Ctrl Registers which is defined as ep_fifo_ctrl[reg_idx] here - * - * The ep_fifo_res[ep_idx % FIFO_NUM] represents the EP mapping because when - * (ep_idx % FIFO_NUM) is 3, it actually means the EP0. - */ -static uint8_t it82xx2_get_ep_fifo_ctrl_reg_idx(uint8_t ep_idx) +static int it82xx2_usb_fifo_ctrl(uint8_t ep) { + struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + volatile uint8_t *ep_fifo_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t fifon_ctrl = (ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2; + int ret = 0; - uint8_t reg_idx = (ep_idx < EP8) ? - ((ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2) : - ((ep_fifo_res[ep_idx % FIFO_NUM] - 1) * 2 + 1); - - return reg_idx; -} + if (ep_idx == 0) { + LOG_ERR("Invalid endpoint 0x%x", ep); + return -EINVAL; + } -/* Function it82xx2_get_ep_fifo_ctrl_reg_val(uint8_t ep_idx): - * - * Calculate the register value written to the ep_fifo_ctrl which is defined as - * ep_fifo_ctrl[reg_idx] here for selecting the corresponding control bit. - */ -static uint8_t it82xx2_get_ep_fifo_ctrl_reg_val(uint8_t ep_idx) -{ - uint8_t reg_val = (ep_idx < EP8) ? - (1 << ep_idx) : (1 << (ep_idx - EP8)); + if (USB_EP_DIR_IS_IN(ep) && udata0.ep_data[ep_idx].ep_status == EP_CONFIG_IN) { + if (ep_idx < 8) { + ep_fifo_ctrl[fifon_ctrl] = BIT(ep_idx); + ep_fifo_ctrl[fifon_ctrl + 1] = 0x0; + } else { + ep_fifo_ctrl[fifon_ctrl] = 0x0; + ep_fifo_ctrl[fifon_ctrl + 1] = BIT(ep_idx - 8); + } + } else if (USB_EP_DIR_IS_OUT(ep) && + udata0.ep_data[ep_idx].ep_status == EP_CONFIG_OUT) { + if (ep_idx < 8) { + ep_fifo_ctrl[fifon_ctrl] |= BIT(ep_idx); + } else { + ep_fifo_ctrl[fifon_ctrl + 1] |= BIT(ep_idx - 8); + } + } else { + LOG_ERR("Failed to set fifo control register for ep 0x%x", ep); + ret = -EINVAL; + } - return reg_val; + return ret; } -/* - * Functions it82xx2_epn0n1_ext_ctrl_cfg() and epn0n1_ext_ctrl_cfg_seq_inv() - * provide the entrance of configuring the EPN0N1 Extended Ctrl Registers. - * - * The variable set_clr determines if we set/clear the corresponding bit. - */ -static void it82xx2_epn0n1_ext_ctrl_cfg(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) +static volatile void *it82xx2_get_ext_ctrl(int ep_idx, enum it82xx2_ep_ctrl ctrl) { + uint8_t idx; struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = + union epn0n1_extend_ctrl_reg *epn0n1_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; + struct epn_ext_ctrl_regs *ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - (set_clr) ? (epn0n1_ext_ctrl[reg_idx] |= bit_mask) : - (epn0n1_ext_ctrl[reg_idx] &= ~(bit_mask)); + if ((ctrl == EP_IN_DIRECTION_SET) || (ctrl == EP_ENABLE)) { + idx = ((ep_idx - 4) % 3) + 1; + return &ext_ctrl[idx].epn_ext_ctrl1; + } + + idx = (ep_idx - 4) / 2; + return &epn0n1_ext_ctrl[idx]; } -static void it82xx2_epn0n1_ext_ctrl_cfg_seq_inv(uint8_t reg_idx, - uint8_t bit_mask, bool set_clr) +static int it82xx2_usb_extend_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; - - bool check = (set_clr) ? - (epn0n1_ext_ctrl[reg_idx] & EPN0_OUTDATA_SEQ) : - (epn0n1_ext_ctrl[reg_idx] & EPN1_OUTDATA_SEQ); + struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); + struct epn_ext_ctrl_regs *ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + union epn_extend_ctrl1_reg *epn_ext_ctrl1 = NULL; + union epn0n1_extend_ctrl_reg *epn0n1_ext_ctrl = NULL; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - (check) ? (epn0n1_ext_ctrl[reg_idx] &= ~(bit_mask)) : - (epn0n1_ext_ctrl[reg_idx] |= bit_mask); -} + if (!IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + return -EINVAL; + } -/* Return the status of STALL bit in the EPN0N1 Extend Control Registers */ -static bool it82xx2_epn01n1_check_stall(uint8_t reg_idx, uint8_t bit_mask) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - volatile uint8_t *epn0n1_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_9X].ext_4_15.epn0n1_ext_ctrl; + if ((ctrl == EP_IN_DIRECTION_SET) || (ctrl == EP_ENABLE)) { + epn_ext_ctrl1 = (union epn_extend_ctrl1_reg *)it82xx2_get_ext_ctrl(ep_idx, ctrl); + } else { + epn0n1_ext_ctrl = + (union epn0n1_extend_ctrl_reg *)it82xx2_get_ext_ctrl(ep_idx, ctrl); + } - return !!(epn0n1_ext_ctrl[reg_idx] & bit_mask); -} + switch (ctrl) { + case EP_STALL_SEND: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_send_stall_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_send_stall_bit = enable; + } + break; + case EP_STALL_CHECK: + if (ep_idx % 2) { + return epn0n1_ext_ctrl->fields.epn1_send_stall_bit; + } else { + return epn0n1_ext_ctrl->fields.epn0_send_stall_bit; + } + break; + case EP_IOS_ENABLE: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_iso_enable_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_iso_enable_bit = enable; + } + break; + case EP_DATA_SEQ_1: + if (ep_idx % 2) { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = enable; + } else { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = enable; + } + break; + case EP_DATA_SEQ_TOGGLE: + if (!enable) { + break; + } + if (ep_idx % 2) { + if (epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit) { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = 0; + } else { + epn0n1_ext_ctrl->fields.epn1_outdata_sequence_bit = 1; + } + } else { + if (epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit) { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = 0; + } else { + epn0n1_ext_ctrl->fields.epn0_outdata_sequence_bit = 1; + } + } + break; + case EP_IN_DIRECTION_SET: + if (((ep_idx - 4) / 3 == 0)) { + epn_ext_ctrl1->fields.epn0_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 1)) { + epn_ext_ctrl1->fields.epn3_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 2)) { + epn_ext_ctrl1->fields.epn6_direction_bit = enable; + } else if (((ep_idx - 4) / 3 == 3)) { + epn_ext_ctrl1->fields.epn9_direction_bit = enable; + } else { + LOG_ERR("Invalid endpoint 0x%x for control type 0x%x", ep, ctrl); + return -EINVAL; + } + break; + case EP_ENABLE: + if (((ep_idx - 4) / 3 == 0)) { + epn_ext_ctrl1->fields.epn0_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 1)) { + epn_ext_ctrl1->fields.epn3_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 2)) { + epn_ext_ctrl1->fields.epn6_enable_bit = enable; + } else if (((ep_idx - 4) / 3 == 3)) { + epn_ext_ctrl1->fields.epn9_enable_bit = enable; + } else { + LOG_ERR("Invalid endpoint 0x%x for control type 0x%x", ep, ctrl); + return -EINVAL; + } + break; + case EP_READY_ENABLE: + int idx = ((ep_idx - 4) % 3) + 1; -/* Configuring the EPN Extended Ctrl Registers. */ -static void it82xx2_epn_ext_ctrl_cfg1(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + (enable) ? (ext_ctrl[idx].epn_ext_ctrl2 |= BIT((ep_idx - 4) / 3)) + : (ext_ctrl[idx].epn_ext_ctrl2 &= ~BIT((ep_idx - 4) / 3)); + break; + default: + LOG_ERR("Unknown control type 0x%x", ctrl); + return -EINVAL; + } - (set_clr) ? (epn_ext_ctrl[reg_idx].epn_ext_ctrl1 |= bit_mask) : - (epn_ext_ctrl[reg_idx].epn_ext_ctrl1 &= ~(bit_mask)); + return 0; } -static void it82xx2_epn_ext_ctrl_cfg2(uint8_t reg_idx, uint8_t bit_mask, - bool set_clr) +static int it82xx2_usb_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - - (set_clr) ? (epn_ext_ctrl[reg_idx].epn_ext_ctrl2 |= bit_mask) : - (epn_ext_ctrl[reg_idx].epn_ext_ctrl2 &= ~(bit_mask)); -} - -/* From 98h to 9Dh, the EP45/67/89/1011/1213/1415 Extended Control Registers - * are defined, and their bits definitions are as follows: - * - * Bit Description - * 7 Reserved - * 6 EPPOINT5_ISO_ENABLE - * 5 EPPOINT5_SEND_STALL - * 4 EPPOINT5_OUT_DATA_SEQUENCE - * 3 Reserved - * 2 EPPOINT4_ISO_ENABLE - * 1 EPPOINT4_SEND_STALL - * 0 EPPOINT4_OUT_DATA_SEQUENCE - * - * Apparently, we can tell that the EP4 and EP5 share the same register, and - * the EP6 and EP7 share the same one, and the other EPs are defined in the - * same way. - * - * In the function it82xx2_usb_extend_ep_ctrl() we will obtain the mask/flag - * according to the bits definitions mentioned above. As for the control code, - * please refer to the definition of enum it82xx2_extend_ep_ctrl. - */ -static int it82xx2_usb_extend_ep_ctrl(uint8_t ep_idx, - enum it82xx2_extend_ep_ctrl ctrl) -{ - uint8_t reg_idx, mask; - bool flag; + struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - if (ep_idx < EP4) { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { return -EINVAL; } - if ((ctrl >= EXT_EP_DIR_IN) && (ctrl < EXT_EP_READY)) { - /* From EXT_EP_DIR_IN to EXT_EP_DISABLE */ - reg_idx = ep_fifo_res[ep_idx % FIFO_NUM]; - mask = 1 << (ext_ep_bit_shift[ep_idx - 4] * 2 + 1); - flag = epn_ext_ctrl_tbl[ctrl - EXT_EP_DIR_IN]; - it82xx2_epn_ext_ctrl_cfg1(reg_idx, mask, flag); - - } else if ((ctrl >= EXT_EP_ISO_DISABLE) && (ctrl < EXT_EP_DIR_IN)) { - /* From EXT_EP_ISO_DISABLE to EXT_EP_DATA_SEQ_0 */ - reg_idx = (ep_idx - 4) >> 1; - flag = !!(ep_idx & 1); - mask = flag ? (ext_ctrl_tbl[ctrl] << 4) : (ext_ctrl_tbl[ctrl]); - - if (ctrl == EXT_EP_CHECK_STALL) { - return it82xx2_epn01n1_check_stall(reg_idx, mask); - } else if (ctrl == EXT_EP_DATA_SEQ_INV) { - it82xx2_epn0n1_ext_ctrl_cfg_seq_inv( - reg_idx, mask, flag); + switch (ctrl) { + case EP_IN_DIRECTION_SET: + ep_regs[ep_idx].ep_ctrl.fields.direction_bit = enable; + break; + case EP_STALL_SEND: + ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit = enable; + break; + case EP_STALL_CHECK: + return ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit; + case EP_IOS_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.iso_enable_bit = enable; + break; + case EP_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.enable_bit = enable; + break; + case EP_READY_ENABLE: + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = enable; + break; + case EP_DATA_SEQ_1: + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = enable; + break; + case EP_DATA_SEQ_TOGGLE: + if (!enable) { + break; + } + if (ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit) { + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = 0; } else { - it82xx2_epn0n1_ext_ctrl_cfg(reg_idx, mask, flag); + ep_regs[ep_idx].ep_ctrl.fields.outdata_sequence_bit = 1; } - } else if (ctrl == EXT_EP_READY) { - reg_idx = (ep_idx - 4) >> 1; - mask = 1 << (ext_ep_bit_shift[ep_idx - 4]); - it82xx2_epn_ext_ctrl_cfg2(reg_idx, mask, true); - } else { - LOG_ERR("Invalid Control Code of Endpoint"); + break; + default: + LOG_ERR("Unknown control type 0x%x", ctrl); return -EINVAL; } - return 0; } -static int it82xx2_usb_dc_ip_init(uint8_t p_action) +static int it82xx2_usb_set_ep_ctrl(uint8_t ep, enum it82xx2_ep_ctrl ctrl, bool enable) +{ + uint8_t ep_idx = USB_EP_GET_IDX(ep); + int ret = 0; + + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + ret = it82xx2_usb_extend_ep_ctrl(ep, ctrl, enable); + } else { + ret = it82xx2_usb_ep_ctrl(ep, ctrl, enable); + } + return ret; +} + +static int it82xx2_usb_dc_ip_init(void) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - if (p_action == 0) { - /* Reset Device Controller */ - usb_regs->host_device_control = RESET_CORE; - k_msleep(1); - usb_regs->port0_misc_control &= ~(PULL_DOWN_EN); - usb_regs->port1_misc_control &= ~(PULL_DOWN_EN); - /* clear reset bit */ - usb_regs->host_device_control = 0; - } + /* Reset Device Controller */ + usb_regs->host_device_control = RESET_CORE; + k_msleep(1); + usb_regs->port0_misc_control &= ~(PULL_DOWN_EN); + usb_regs->port1_misc_control &= ~(PULL_DOWN_EN); + /* clear reset bit */ + usb_regs->host_device_control = 0; usb_regs->dc_interrupt_status = DC_TRANS_DONE | DC_RESET_EVENT | DC_SOF_RECEIVED; @@ -507,7 +518,7 @@ static int it82xx2_usb_dc_attach_init(void) gctrl_regs->GCTRL_MCCR &= ~(IT8XXX2_GCTRL_MCCR_USB_EN); gctrl_regs->gctrl_pmer2 |= IT8XXX2_GCTRL_PMER2_USB_PAD_EN; - return it82xx2_usb_dc_ip_init(0); + return it82xx2_usb_dc_ip_init(); } /* Check the condition that SETUP_TOKEN following OUT_TOKEN and return it */ @@ -523,198 +534,180 @@ static bool it82xx2_check_setup_following_out(void) ff_regs[EP0].ep_rx_fifo_dcnt_lsb == SETUP_DATA_CNT)); } -static int it82xx2_setup_done(uint8_t ep_ctrl, uint8_t idx) +static inline void it82xx2_handler_setup(uint8_t fifo_idx, uint8_t ep_ctrl) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; + uint8_t ep_idx = fifo_idx; - LOG_DBG("SETUP(%d)", idx); - /* wrong trans*/ + /* wrong trans */ if (ep_ctrl & EP_SEND_STALL) { - ep_regs[idx].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[fifo_idx].ep_ctrl.fields.send_stall_bit = 0; udata0.st_state = STALL_SEND; - ff_regs[idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + ff_regs[fifo_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; LOG_DBG("Clear Stall Bit & RX FIFO"); - return -EINVAL; + return; } - /* handle status interrupt */ - /* status out */ + if (udata0.st_state == DIN_ST) { - LOG_DBG("Status OUT"); + /* setup -> in(data) -> out(status) */ udata0.last_token = udata0.now_token; udata0.now_token = OUT_TOKEN; udata0.st_state = STATUS_ST; - udata0.ep_data[idx].cb_out(idx, USB_DC_EP_DATA_OUT); + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_DATA_OUT); } else if (udata0.st_state == DOUT_ST || udata0.st_state == SETUP_ST) { - /* Status IN*/ - LOG_DBG("Status IN"); + /* setup -> out(data) -> in(status) + * or + * setup -> in(status) + */ udata0.last_token = udata0.now_token; udata0.now_token = IN_TOKEN; udata0.st_state = STATUS_ST; - udata0.ep_data[idx].cb_in(idx | 0x80, USB_DC_EP_DATA_IN); + udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } udata0.last_token = udata0.now_token; udata0.now_token = SETUP_TOKEN; udata0.st_state = SETUP_ST; - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - udata0.ep_data[idx].cb_out(USB_EP_DIR_OUT, USB_DC_EP_SETUP); + ep_regs[fifo_idx].ep_ctrl.fields.outdata_sequence_bit = 1; + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); /* Set ready bit to no-data control in */ if (udata0.no_data_ctrl) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("(%d): Set Ready Bit for no-data control", __LINE__); - + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; udata0.no_data_ctrl = false; } - - return 0; } -static int it82xx2_in_done(uint8_t ep_ctrl, uint8_t idx) +static inline void it82xx2_handler_in(uint8_t fifo_idx, uint8_t ep_ctrl) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; + volatile struct epn_ext_ctrl_regs *epn_ext_ctrl = + usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + uint8_t ep_idx; - /* stall send check */ - if (ep_ctrl & EP_SEND_STALL) { - ep_regs[EP0].ep_ctrl &= ~EP_SEND_STALL; - udata0.st_state = STALL_SEND; - LOG_DBG("Clear Stall Bit"); - return -EINVAL; - } - - if (udata0.st_state >= STATUS_ST) { - return -EINVAL; - } - - LOG_DBG("IN(%d)(%d)", idx, !!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)); - - udata0.last_token = udata0.now_token; - udata0.now_token = IN_TOKEN; - - if (udata0.addr != DC_ADDR_NULL && - udata0.addr != usb_regs->dc_address) { - usb_regs->dc_address = udata0.addr; - LOG_DBG("Address Is Set Successfully"); - } - - /* set setup stage */ - if (udata0.st_state == DOUT_ST) { - udata0.st_state = STATUS_ST; - /* no data status in */ - } else if (udata0.ep_data[EP0].remaining == 0 && - udata0.st_state == SETUP_ST) { - udata0.st_state = STATUS_ST; - } else { - udata0.st_state = DIN_ST; - } + if (fifo_idx != 0) { + if (!udata0.fifo_ready[fifo_idx - 1]) { + return; + } - if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { - ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; + ep_idx = (epn_ext_ctrl[fifo_idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; + if (ep_idx == 0 || udata0.ep_data[ep_idx].ep_status != EP_CONFIG_IN) { + return; + } + udata0.fifo_ready[fifo_idx - 1] = false; } else { - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - } - udata0.ep_data[idx].cb_in(idx | 0x80, USB_DC_EP_DATA_IN); + ep_idx = 0; + if (ep_ctrl & EP_SEND_STALL) { + ep_regs[fifo_idx].ep_ctrl.fields.send_stall_bit = 0; + udata0.st_state = STALL_SEND; + LOG_DBG("Clear Stall Bit"); + return; + } - /* set ready bit for status out */ - LOG_DBG("Remaining Bytes: %d, Stage: %d", - udata0.ep_data[EP0].remaining, udata0.st_state); + if (udata0.st_state >= STATUS_ST) { + return; + } - if (udata0.st_state == DIN_ST && udata0.ep_data[EP0].remaining == 0) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set EP%d Ready (%d)", idx, __LINE__); - } + udata0.last_token = udata0.now_token; + udata0.now_token = IN_TOKEN; - return 0; -} + if (udata0.addr != DC_ADDR_NULL && + udata0.addr != usb_regs->dc_address) { + usb_regs->dc_address = udata0.addr; + LOG_DBG("Address Is Set Successfully"); + } -static int it82xx2_out_done(uint8_t idx) -{ - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; + if (udata0.st_state == DOUT_ST) { + /* setup -> out(data) -> in(status) */ + udata0.st_state = STATUS_ST; - /* ep0 wrong enter check */ - if (udata0.st_state >= STATUS_ST) { - return -EINVAL; + } else if (udata0.ep_data[ep_idx].remaining == 0 && + udata0.st_state == SETUP_ST) { + /* setup -> in(status) */ + udata0.st_state = STATUS_ST; + } else { + /* setup -> in(data) */ + udata0.st_state = DIN_ST; + } } - LOG_DBG("OUT(%d)", idx); - - udata0.last_token = udata0.now_token; - udata0.now_token = OUT_TOKEN; + it82xx2_usb_set_ep_ctrl(ep_idx, EP_DATA_SEQ_TOGGLE, true); - if (udata0.st_state == SETUP_ST) { - udata0.st_state = DOUT_ST; - } else { - udata0.st_state = STATUS_ST; + if (udata0.ep_data[ep_idx].cb_in) { + udata0.ep_data[ep_idx].cb_in(ep_idx | USB_EP_DIR_IN, USB_DC_EP_DATA_IN); } - udata0.ep_data[idx].cb_out(idx, USB_DC_EP_DATA_OUT); - - /* SETUP_TOKEN follow OUT_TOKEN */ - if (it82xx2_check_setup_following_out()) { - LOG_WRN("[%s] OUT => SETUP", __func__); - udata0.last_token = udata0.now_token; - udata0.now_token = SETUP_TOKEN; - udata0.st_state = SETUP_ST; - ep_regs[EP0].ep_ctrl |= EP_OUTDATA_SEQ; - udata0.ep_data[EP0].cb_out(USB_EP_DIR_OUT, USB_DC_EP_SETUP); - - /* NOTE: set ready bit to no-data control in */ - if (udata0.no_data_ctrl) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set Ready Bit for no-data control"); - udata0.no_data_ctrl = false; + if (fifo_idx != 0) { + k_sem_give(&udata0.fifo_sem[fifo_idx - 1]); + } else { + if (udata0.st_state == DIN_ST && udata0.ep_data[ep_idx].remaining == 0) { + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; } } - - return 0; } -/* Functions it82xx2_ep_in_out_config(): - * Dealing with the ep_ctrl configurations in this subroutine when it's - * invoked in the it82xx2_usb_dc_trans_done(). - */ -static void it82xx2_ep_in_out_config(uint8_t idx) +static inline void it82xx2_handler_out(uint8_t fifo_idx) { struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - struct epn_ext_ctrl_regs *epn_ext_ctrl = + volatile struct epn_ext_ctrl_regs *epn_ext_ctrl = usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; + uint8_t ep_idx; - uint8_t ep_trans = (epn_ext_ctrl[idx].epn_ext_ctrl2 >> 4) & READY_BITS; + if (fifo_idx != 0) { + if (!udata0.fifo_ready[fifo_idx - 1]) { + return; + } - if (udata0.ep_data[ep_trans].ep_status == EP_CONFIG_IN) { - if (ep_trans < 4) { - if (!!(ep_regs[idx].ep_ctrl & EP_OUTDATA_SEQ)) { - ep_regs[idx].ep_ctrl &= ~EP_OUTDATA_SEQ; - } else { - ep_regs[idx].ep_ctrl |= EP_OUTDATA_SEQ; - } - } else { - it82xx2_usb_extend_ep_ctrl(ep_trans, - EXT_EP_DATA_SEQ_INV); + ep_idx = (epn_ext_ctrl[fifo_idx].epn_ext_ctrl2 & COMPLETED_TRANS) >> 4; + if (ep_idx == 0 || udata0.ep_data[ep_idx].ep_status != EP_CONFIG_OUT) { + return; + } + udata0.fifo_ready[fifo_idx - 1] = false; + } else { + ep_idx = 0; + /* ep0 wrong enter check */ + if (udata0.st_state >= STATUS_ST) { + return; } - if (udata0.ep_data[ep_trans].cb_in) { - udata0.ep_data[ep_trans].cb_in(ep_trans | 0x80, - USB_DC_EP_DATA_IN); + udata0.last_token = udata0.now_token; + udata0.now_token = OUT_TOKEN; + + if (udata0.st_state == SETUP_ST) { + /* setup -> out(data) */ + udata0.st_state = DOUT_ST; + } else { + /* setup -> in(data) -> out(status) */ + udata0.st_state = STATUS_ST; } + } - k_sem_give(&udata0.ep_sem[idx - 1]); + if (udata0.ep_data[ep_idx].cb_out) { + udata0.ep_data[ep_idx].cb_out(ep_idx, USB_DC_EP_DATA_OUT); + } - } else { - if (udata0.ep_data[ep_trans].cb_out) { - udata0.ep_data[ep_trans].cb_out(ep_trans, - USB_DC_EP_DATA_OUT); + if (fifo_idx == 0) { + /* SETUP_TOKEN follow OUT_TOKEN */ + if (it82xx2_check_setup_following_out()) { + udata0.last_token = udata0.now_token; + udata0.now_token = SETUP_TOKEN; + udata0.st_state = SETUP_ST; + ep_regs[fifo_idx].ep_ctrl.fields.outdata_sequence_bit = 1; + udata0.ep_data[ep_idx].cb_out(ep_idx | USB_EP_DIR_OUT, USB_DC_EP_SETUP); + + if (udata0.no_data_ctrl) { + ep_regs[fifo_idx].ep_ctrl.fields.ready_bit = 1; + udata0.no_data_ctrl = false; + } } } } @@ -724,55 +717,26 @@ static void it82xx2_usb_dc_trans_done(void) struct usb_it82xx2_regs *const usb_regs = (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - struct epn_ext_ctrl_regs *epn_ext_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_DX].ext_0_3.epn_ext_ctrl; - - int ret; - for (uint8_t idx = 0 ; idx < EP4 ; idx++) { - uint8_t ep_ctrl = ep_regs[idx].ep_ctrl; + for (uint8_t fifo_idx = 0; fifo_idx < 4; fifo_idx++) { + uint8_t ep_ctrl = ep_regs[fifo_idx].ep_ctrl.value; /* check ready bit ,will be 0 when trans done */ if ((ep_ctrl & ENDPOINT_EN) && !(ep_ctrl & ENDPOINT_RDY)) { - if (idx == EP0) { - uint8_t ep_trans_type = ep_regs[idx].ep_transtype_sts & - DC_ALL_TRANS; - - /* set up*/ - if (ep_trans_type == DC_SETUP_TRANS) { - ret = it82xx2_setup_done(ep_ctrl, idx); - - if (ret != 0) { - continue; - } - } else if (ep_trans_type == DC_IN_TRANS) { - /* in */ - ret = it82xx2_in_done(ep_ctrl, idx); - - if (ret != 0) { - continue; - } - } else if (ep_trans_type == DC_OUTDATA_TRANS) { - /* out */ - ret = it82xx2_out_done(idx); - - if (ret != 0) { - continue; - } + switch (ep_regs[fifo_idx].ep_transtype_sts & DC_ALL_TRANS) { + case DC_SETUP_TRANS: + if (fifo_idx == 0) { + it82xx2_handler_setup(fifo_idx, ep_ctrl); } - } else { - /* prevent wrong entry */ - if (!udata0.ep_ready[idx - 1]) { - continue; - } - - if ((epn_ext_ctrl[idx].epn_ext_ctrl2 & - COMPLETED_TRANS) == 0) { - continue; - } - - udata0.ep_ready[idx - 1] = false; - it82xx2_ep_in_out_config(idx); + break; + case DC_IN_TRANS: + it82xx2_handler_in(fifo_idx, ep_ctrl); + break; + case DC_OUTDATA_TRANS: + it82xx2_handler_out(fifo_idx); + break; + default: + break; } } } @@ -792,13 +756,7 @@ static void it82xx2_usb_dc_isr(void) RX_LINE_RESET) { usb_dc_reset(); usb_regs->dc_interrupt_status = DC_RESET_EVENT; - - if (udata0.usb_status_cb) { - (*(udata0.usb_status_cb))(USB_DC_RESET, NULL); - } - return; - } else { usb_regs->dc_interrupt_status = DC_RESET_EVENT; } @@ -875,20 +833,20 @@ int usb_dc_attach(void) return ret; } - for (int idx = 0 ; idx < MAX_NUM_ENDPOINTS ; idx++) { + for (uint8_t idx = 0; idx < MAX_NUM_ENDPOINTS; idx++) { udata0.ep_data[idx].ep_status = EP_INIT; } udata0.attached = 1U; - /* init ep ready status */ - udata0.ep_ready[0] = false; - udata0.ep_ready[1] = false; - udata0.ep_ready[2] = false; + /* init fifo ready status */ + udata0.fifo_ready[0] = false; + udata0.fifo_ready[1] = false; + udata0.fifo_ready[2] = false; - k_sem_init(&udata0.ep_sem[0], 1, 1); - k_sem_init(&udata0.ep_sem[1], 1, 1); - k_sem_init(&udata0.ep_sem[2], 1, 1); + k_sem_init(&udata0.fifo_sem[0], 1, 1); + k_sem_init(&udata0.fifo_sem[1], 1, 1); + k_sem_init(&udata0.fifo_sem[2], 1, 1); k_sem_init(&udata0.suspended_sem, 0, 1); k_work_init_delayable(&udata0.check_suspended_work, suspended_check_handler); @@ -934,21 +892,19 @@ int usb_dc_reset(void) struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - int idx; - LOG_DBG("USB Device Reset"); ff_regs[EP0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; ff_regs[EP0].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; - for (idx = 1 ; idx < EP4 ; idx++) { + for (uint8_t idx = 1; idx < 4; idx++) { if (udata0.ep_data[idx].ep_status > EP_CHECK) { ff_regs[idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; ff_regs[idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; } } - ep_regs[EP0].ep_ctrl = ENDPOINT_EN; + ep_regs[0].ep_ctrl.value = ENDPOINT_EN; usb_regs->dc_address = DC_ADDR_NULL; udata0.addr = DC_ADDR_NULL; usb_regs->dc_interrupt_status = DC_NAK_SENT_INT | DC_SOF_RECEIVED; @@ -974,12 +930,8 @@ void usb_dc_set_status_callback(const usb_dc_status_callback cb) int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) { - uint8_t ep_idx = cfg->ep_addr & EP_VALID_MASK; - bool in = !!((cfg->ep_addr) & USB_EP_DIR_MASK); - - if ((cfg->ep_addr & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); + bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx > EP0) { LOG_ERR("Invalid Endpoint Configuration"); @@ -1001,7 +953,7 @@ int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) return -EINVAL; } - if (udata0.ep_data[ep_idx].ep_status > 0) { + if (udata0.ep_data[ep_idx].ep_status > EP_INIT) { LOG_WRN("EP%d have been used", ep_idx); return -EINVAL; } @@ -1018,21 +970,8 @@ int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - volatile uint8_t *ep_fifo_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; - - uint8_t ep_idx = (cfg->ep_addr) & EP_VALID_MASK; - uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); - uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); - bool in = !!((cfg->ep_addr) & USB_EP_DIR_MASK); - - if ((cfg->ep_addr & EP_INVALID_MASK) != 0) { - LOG_DBG("Invalid Address"); - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr); + bool in = USB_EP_DIR_IS_IN(cfg->ep_addr); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_DBG("Not attached / Invalid Endpoint: 0x%X", cfg->ep_addr); @@ -1054,52 +993,31 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) return 0; } - if (ep_idx < EP4) { - (in) ? (ep_regs[ep_idx].ep_ctrl |= EP_DIRECTION) : - (ep_regs[ep_idx].ep_ctrl &= ~EP_DIRECTION); - - } else { - - (in) ? (it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DIR_IN)) : - (it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DIR_OUT)); + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IN_DIRECTION_SET, in); - if (in) { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DATA_SEQ_0); + if (in) { + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_DATA_SEQ_1, false); } - - LOG_DBG("ep_status %d", udata0.ep_data[ep_idx].ep_status); + udata0.ep_data[ep_idx].ep_status = EP_CONFIG_IN; + } else { + udata0.ep_data[ep_idx].ep_status = EP_CONFIG_OUT; + it82xx2_usb_fifo_ctrl(cfg->ep_addr); } - (in) ? (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_IN) : - (udata0.ep_data[ep_idx].ep_status = EP_CONFIG_OUT); - - ep_fifo_ctrl[reg_idx] |= reg_val; - switch (cfg->ep_type) { - case USB_DC_EP_CONTROL: return -EINVAL; - case USB_DC_EP_ISOCHRONOUS: - if (ep_idx < EP4) { - ep_regs[ep_idx].ep_ctrl |= EP_ISO_ENABLE; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_ENABLE); - } - + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IOS_ENABLE, true); break; - case USB_DC_EP_BULK: + __fallthrough; case USB_DC_EP_INTERRUPT: + __fallthrough; default: - if (ep_idx < EP4) { - ep_regs[ep_idx].ep_ctrl &= ~EP_ISO_ENABLE; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ISO_DISABLE); - } - + it82xx2_usb_set_ep_ctrl(ep_idx, EP_IOS_ENABLE, false); break; - } udata0.ep_data[ep_idx].ep_type = cfg->ep_type; @@ -1110,11 +1028,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg) int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) { - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d)Not attached / Invalid endpoint: EP 0x%x", @@ -1129,67 +1043,51 @@ int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) LOG_DBG("EP%d set callback: %d", ep_idx, !!(ep & USB_EP_DIR_IN)); - (ep & USB_EP_DIR_IN) ? - (udata0.ep_data[ep_idx].cb_in = cb) : - (udata0.ep_data[ep_idx].cb_out = cb); + if (USB_EP_DIR_IS_IN(ep)) { + udata0.ep_data[ep_idx].cb_in = cb; + } else { + udata0.ep_data[ep_idx].cb_out = cb; + } return 0; } int usb_dc_ep_enable(const uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - LOG_DBG("Bit[6:4] has something invalid"); - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); + int ret = 0; if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep_idx); return -EINVAL; } - if (ep_idx < EP4) { - LOG_DBG("ep_idx < 4"); - ep_regs[ep_idx].ep_ctrl |= ENDPOINT_EN; - LOG_DBG("EP%d Enabled %02x", ep_idx, ep_regs[ep_idx].ep_ctrl); - } else { - LOG_DBG("ep_idx >= 4"); - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_ENABLE); + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + uint8_t ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; + + it82xx2_usb_set_ep_ctrl(ep_fifo, EP_ENABLE, true); + } + + ret = it82xx2_usb_set_ep_ctrl(ep_idx, EP_ENABLE, true); + if (ret < 0) { + return ret; } + LOG_DBG("Endpoint 0x%02x is enabled", ep); + return 0; } int usb_dc_ep_disable(uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (!udata0.attached || ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep_idx); return -EINVAL; } - if (ep_idx < EP4) { - ep_regs[ep_idx].ep_ctrl &= ~ENDPOINT_EN; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_DISABLE); - } - - return 0; + return it82xx2_usb_set_ep_ctrl(ep_idx, EP_ENABLE, false); } @@ -1199,39 +1097,36 @@ int usb_dc_ep_set_stall(const uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; - if (((ep & EP_INVALID_MASK) != 0) || (ep_idx >= MAX_NUM_ENDPOINTS)) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_idx < EP4) { - ep_regs[ep_idx].ep_ctrl |= EP_SEND_STALL; - } else { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_SEND_STALL); - } + it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_SEND, true); - if (ep_idx == EP0) { - ep_regs[EP0].ep_ctrl |= ENDPOINT_RDY; + if (ep_idx == 0) { uint32_t idx = 0; + + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = 1; /* polling if stall send for 3ms */ while (idx < 198 && - !(ep_regs[EP0].ep_status & DC_STALL_SENT)) { + !(ep_regs[ep_idx].ep_status & DC_STALL_SENT)) { /* wait 15.15us */ gctrl_regs->GCTRL_WNCKR = 0; idx++; } if (idx < 198) { - ep_regs[EP0].ep_ctrl &= ~EP_SEND_STALL; + ep_regs[ep_idx].ep_ctrl.fields.send_stall_bit = 0; } udata0.no_data_ctrl = false; udata0.st_state = STALL_SEND; } - LOG_DBG("EP(%d) ctrl: 0x%02x", ep_idx, ep_regs[ep_idx].ep_ctrl); + LOG_DBG("EP(%d) ctrl: 0x%02x", ep_idx, ep_regs[ep_idx].ep_ctrl.value); LOG_DBG("EP(%d) Set Stall", ep_idx); return 0; @@ -1239,21 +1134,13 @@ int usb_dc_ep_set_stall(const uint8_t ep) int usb_dc_ep_clear_stall(const uint8_t ep) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - ep_regs[ep_idx].ep_ctrl &= ~EP_SEND_STALL; + it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_SEND, false); LOG_DBG("EP(%d) clear stall", ep_idx); return 0; @@ -1261,24 +1148,13 @@ int usb_dc_ep_clear_stall(const uint8_t ep) int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *stalled) { - struct usb_it82xx2_regs *const usb_regs = - (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); - struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - - uint8_t ep_idx = ep & EP_VALID_MASK; + uint8_t ep_idx = USB_EP_GET_IDX(ep); - if ((!stalled) || ((ep & EP_INVALID_MASK) != 0) || - (ep_idx >= MAX_NUM_ENDPOINTS)) { + if ((!stalled) || (ep_idx >= MAX_NUM_ENDPOINTS)) { return -EINVAL; } - if (ep_idx < EP4) { - *stalled = - (0 != (ep_regs[ep_idx].ep_ctrl & EP_SEND_STALL)); - } else { - *stalled = it82xx2_usb_extend_ep_ctrl(ep_idx, - EXT_EP_CHECK_STALL); - } + *stalled = it82xx2_usb_set_ep_ctrl(ep_idx, EP_STALL_CHECK, true); return 0; } @@ -1294,20 +1170,19 @@ int usb_dc_ep_flush(uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - bool in = !!(ep & USB_EP_DIR_MASK); + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; - if (((ep & EP_INVALID_MASK) != 0) || (ep_idx >= MAX_NUM_ENDPOINTS)) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_idx > FIFO_NUM) { - ep_idx = ep_fifo_res[ep_idx % FIFO_NUM]; + if (USB_EP_DIR_IS_IN(ep)) { + ff_regs[ep_fifo].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; + } else { + ff_regs[ep_fifo].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; } - in ? (ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY) : - (ff_regs[ep_idx].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY); - return 0; } @@ -1318,50 +1193,32 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - volatile uint8_t *ep_fifo_ctrl = - usb_regs->fifo_regs[EP_EXT_REGS_BX].fifo_ctrl.ep_fifo_ctrl; - - uint8_t ep_idx = ep & EP_VALID_MASK; - uint8_t reg_idx = it82xx2_get_ep_fifo_ctrl_reg_idx(ep_idx); - uint8_t reg_val = it82xx2_get_ep_fifo_ctrl_reg_val(ep_idx); - uint8_t ep_fifo = (ep_idx > EP0) ? - (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; - uint32_t idx; - - if ((ep & EP_INVALID_MASK) != 0) - return -EINVAL; - /* status IN */ - if ((ep_idx == EP0) && (data_len == 0) && - (udata0.now_token == SETUP_TOKEN)) { - return 0; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - /* clear fifo before write*/ if (ep_idx == EP0) { + if ((udata0.now_token == SETUP_TOKEN) && (data_len == 0)) { + return 0; + } + /* clear fifo before write*/ ff_regs[ep_idx].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; - } - - if ((ep_idx == EP0) && (udata0.st_state == SETUP_ST)) { - udata0.st_state = DIN_ST; - } - - /* select FIFO */ - if (ep_idx > EP0) { - k_sem_take(&udata0.ep_sem[ep_fifo-1], K_FOREVER); - - /* select FIFO */ - ep_fifo_ctrl[reg_idx] |= reg_val; + if (udata0.st_state == SETUP_ST) { + udata0.st_state = DIN_ST; + } + } else { + k_sem_take(&udata0.fifo_sem[ep_fifo - 1], K_FOREVER); + it82xx2_usb_fifo_ctrl(ep); } if (data_len > udata0.ep_data[ep_idx].mps) { - for (idx = 0 ; idx < udata0.ep_data[ep_idx].mps ; idx++) { + for (uint32_t idx = 0; idx < udata0.ep_data[ep_idx].mps; idx++) { ff_regs[ep_fifo].ep_tx_fifo_data = buf[idx]; } @@ -1372,7 +1229,7 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, LOG_DBG("data_len: %d, Write Max Packets to TX FIFO(%d)", data_len, ep_idx); } else { - for (idx = 0 ; idx < data_len ; idx++) { + for (uint32_t idx = 0; idx < data_len; idx++) { ff_regs[ep_fifo].ep_tx_fifo_data = buf[idx]; } @@ -1381,14 +1238,14 @@ int usb_dc_ep_write(uint8_t ep, const uint8_t *buf, LOG_DBG("Write %d Packets to TX FIFO(%d)", data_len, ep_idx); } - if (ep_idx > FIFO_NUM) { - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); } - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; if (ep_fifo > EP0) { - udata0.ep_ready[ep_fifo - 1] = true; + udata0.fifo_ready[ep_fifo - 1] = true; } LOG_DBG("Set EP%d Ready(%d)", ep_idx, __LINE__); @@ -1405,79 +1262,55 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - uint8_t ep_fifo = 0; + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint16_t rx_fifo_len; - if ((ep & EP_INVALID_MASK) != 0) { + if (ep_idx >= MAX_NUM_ENDPOINTS) { return -EINVAL; } - if (ep_regs[ep_idx].ep_status & EP_STATUS_ERROR) { - LOG_WRN("EP Error Flag: 0x%02x", ep_regs[ep_idx].ep_status); + if (ep_regs[ep_fifo].ep_status & EP_STATUS_ERROR) { + LOG_WRN("fifo_%d error status: 0x%02x", ep_fifo, ep_regs[ep_fifo].ep_status); } if (max_data_len == 0) { *read_bytes = 0; - if (ep_idx > EP0) { - ep_regs[ep_idx].ep_ctrl |= ENDPOINT_RDY; - LOG_DBG("Set EP%d Ready(%d)", ep_idx, __LINE__); + if (ep_idx > 0) { + ep_regs[ep_idx].ep_ctrl.fields.ready_bit = 1; } return 0; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - } - rx_fifo_len = (uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_lsb + (((uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_msb) << 8); if (ep_idx == 0) { - /* if ep0 check trans_type in OUT_TOKEN to - * prevent wrong read_bytes cause memory error - */ - if (udata0.st_state == STATUS_ST && - (ep_regs[EP0].ep_transtype_sts & DC_ALL_TRANS) == 0) { - + /* Prevent wrong read_bytes cause memory error + * if EP0 is in OUT status stage + */ + if (udata0.st_state == STATUS_ST) { *read_bytes = 0; return 0; - - } else if (udata0.st_state == STATUS_ST) { - /* status out but rx_fifo_len not zero */ - if (rx_fifo_len != 0) { - LOG_ERR("Status OUT length not 0 (%d)", - rx_fifo_len); + } else if (udata0.now_token == SETUP_TOKEN) { + if (rx_fifo_len == 0) { + LOG_ERR("Setup length 0, reset to 8"); + rx_fifo_len = 8; + } + if (rx_fifo_len != 8) { + LOG_ERR("Setup length: %d", rx_fifo_len); + ff_regs[0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; + return -EIO; } - /* rx_fifo_len = 0; */ - *read_bytes = 0; - - return 0; - } else if (rx_fifo_len == 0 && - udata0.now_token == SETUP_TOKEN) { - /* RX fifo error workaround */ - - /* wrong length(like 7), - * may read wrong packet so clear fifo then return -1 - */ - LOG_ERR("Setup length 0, reset to 8"); - rx_fifo_len = 8; - } else if (rx_fifo_len != 8 && - udata0.now_token == SETUP_TOKEN) { - LOG_ERR("Setup length: %d", rx_fifo_len); - /* clear rx fifo */ - ff_regs[EP0].ep_rx_fifo_ctrl = FIFO_FORCE_EMPTY; - - return -EIO; } } if (rx_fifo_len > max_data_len) { *read_bytes = max_data_len; - for (int idx = 0 ; idx < max_data_len ; idx++) { + for (uint32_t idx = 0; idx < max_data_len; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } @@ -1486,7 +1319,7 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = rx_fifo_len; - for (int idx = 0 ; idx < rx_fifo_len ; idx++) { + for (uint32_t idx = 0; idx < rx_fifo_len; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } @@ -1498,34 +1331,25 @@ int usb_dc_ep_read(uint8_t ep, uint8_t *buf, uint32_t max_data_len, } if (ep_fifo > EP0) { - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); - LOG_DBG("(%d): Set EP%d Ready", __LINE__, ep_idx); - udata0.ep_ready[ep_fifo - 1] = true; + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); + } + udata0.fifo_ready[ep_fifo - 1] = true; } else if (udata0.now_token == SETUP_TOKEN) { - if (!(buf[0] & USB_EP_DIR_MASK)) { - /* Host to device transfer check */ + /* request type: host-to-device transfer direction */ + ff_regs[0].ep_tx_fifo_ctrl = FIFO_FORCE_EMPTY; if (buf[6] != 0 || buf[7] != 0) { - /* clear tx fifo */ - ff_regs[EP0].ep_tx_fifo_ctrl = - FIFO_FORCE_EMPTY; /* set status IN after data OUT */ - ep_regs[EP0].ep_ctrl |= - ENDPOINT_RDY | EP_OUTDATA_SEQ; - LOG_DBG("Set EP%d Ready(%d)", - ep_idx, __LINE__); + ep_regs[0].ep_ctrl.fields.outdata_sequence_bit = 1; + ep_regs[0].ep_ctrl.fields.ready_bit = 1; } else { /* no_data_ctrl status */ - - /* clear tx fifo */ - ff_regs[EP0].ep_tx_fifo_ctrl = - FIFO_FORCE_EMPTY; udata0.no_data_ctrl = true; } } } - } return 0; @@ -1539,30 +1363,22 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; struct it82xx2_usb_ep_fifo_regs *ff_regs = usb_regs->fifo_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - uint8_t ep_fifo = 0; + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; uint16_t rx_fifo_len; - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } - if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); return -EINVAL; } - /* Check if OUT ep */ - if (!!(ep & USB_EP_DIR_MASK)) { + + if (USB_EP_DIR_IS_IN(ep)) { LOG_ERR("Wrong Endpoint Direction"); return -EINVAL; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; - } - if (ep_regs[ep_fifo].ep_status & EP_STATUS_ERROR) { - LOG_WRN("EP error flag(%02x)", ep_regs[ep_fifo].ep_status); + LOG_WRN("fifo_%d error status(%02x)", ep_fifo, ep_regs[ep_fifo].ep_status); } rx_fifo_len = (uint16_t)ff_regs[ep_fifo].ep_rx_fifo_dcnt_lsb + @@ -1573,16 +1389,12 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *buf, uint32_t max_data_len, *read_bytes = (rx_fifo_len > max_data_len) ? max_data_len : rx_fifo_len; - for (int idx = 0 ; idx < *read_bytes ; idx++) { + for (uint32_t idx = 0; idx < *read_bytes; idx++) { buf[idx] = ff_regs[ep_fifo].ep_rx_fifo_data; } LOG_DBG("Read %d packets", *read_bytes); - if (ep_idx > EP0) { - LOG_DBG("RX buf[0]: 0x%02X", buf[0]); - } - return 0; } @@ -1592,31 +1404,24 @@ int usb_dc_ep_read_continue(uint8_t ep) (struct usb_it82xx2_regs *)it82xx2_get_usb_regs(); struct it82xx2_usb_ep_regs *ep_regs = usb_regs->usb_ep_regs; - uint8_t ep_idx = ep & EP_VALID_MASK; - uint8_t ep_fifo = 2; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); + uint8_t ep_fifo = (ep_idx > 0) ? (ep_fifo_res[ep_idx % FIFO_NUM]) : 0; if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); return -EINVAL; } - /* Check if OUT ep */ - if (!!(ep & USB_EP_DIR_MASK)) { + if (USB_EP_DIR_IS_IN(ep)) { LOG_ERR("Wrong Endpoint Direction"); return -EINVAL; } - if (ep_idx > EP0) { - ep_fifo = ep_fifo_res[ep_idx % FIFO_NUM]; + if (IT8XXX2_IS_EXTEND_ENDPOINT(ep_idx)) { + it82xx2_usb_extend_ep_ctrl(ep_idx, EP_READY_ENABLE, true); } - - it82xx2_usb_extend_ep_ctrl(ep_idx, EXT_EP_READY); - ep_regs[ep_fifo].ep_ctrl |= ENDPOINT_RDY; - udata0.ep_ready[ep_fifo - 1] = true; + ep_regs[ep_fifo].ep_ctrl.fields.ready_bit = 1; + udata0.fifo_ready[ep_fifo - 1] = true; LOG_DBG("EP(%d) Read Continue", ep_idx); return 0; } @@ -1624,11 +1429,7 @@ int usb_dc_ep_read_continue(uint8_t ep) int usb_dc_ep_mps(const uint8_t ep) { - uint8_t ep_idx = ep & EP_VALID_MASK; - - if ((ep & EP_INVALID_MASK) != 0) { - return -EINVAL; - } + uint8_t ep_idx = USB_EP_GET_IDX(ep); if (ep_idx >= MAX_NUM_ENDPOINTS) { LOG_ERR("(%d): Wrong Endpoint Index/Address", __LINE__); diff --git a/drivers/usb/device/usb_dc_kinetis.c b/drivers/usb/device/usb_dc_kinetis.c index 903b1a9dc33..36734580e6c 100644 --- a/drivers/usb/device/usb_dc_kinetis.c +++ b/drivers/usb/device/usb_dc_kinetis.c @@ -354,7 +354,7 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg) (void)memset(&bdt[idx_even], 0, sizeof(struct buf_descriptor)); (void)memset(&bdt[idx_odd], 0, sizeof(struct buf_descriptor)); - block->data = k_heap_alloc(&ep_buf_pool, cfg->ep_mps * 2U, K_MSEC(10)); + block->data = k_heap_alloc(&ep_buf_pool, cfg->ep_mps * 2U, K_NO_WAIT); if (block->data != NULL) { (void)memset(block->data, 0, cfg->ep_mps * 2U); } else { diff --git a/drivers/usb/device/usb_dc_native_posix.c b/drivers/usb/device/usb_dc_native_posix.c index 70410db2440..c74dad9b35d 100644 --- a/drivers/usb/device/usb_dc_native_posix.c +++ b/drivers/usb/device/usb_dc_native_posix.c @@ -605,14 +605,8 @@ int handle_usb_data(struct usbip_header *hdr) LOG_HEXDUMP_DBG(ep_ctrl->buf, ep_ctrl->buf_len, ">"); - /* - * Call the callback only if data in usb_dc_ep_write() - * is actually written to the intermediate buffer and sent. - */ - if (ep_ctrl->buf_len != 0) { - ep_ctrl->cb(ep, USB_DC_EP_DATA_IN); - usbip_ctrl.in_ep_ctrl[ep_idx].buf_len = 0; - } + ep_ctrl->cb(ep, USB_DC_EP_DATA_IN); + ep_ctrl->buf_len = 0; } return 0; diff --git a/drivers/usb/device/usb_dc_numaker.c b/drivers/usb/device/usb_dc_numaker.c new file mode 100644 index 00000000000..0f52b165a13 --- /dev/null +++ b/drivers/usb/device/usb_dc_numaker.c @@ -0,0 +1,2007 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_numaker_usbd + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usb_dc_numaker, CONFIG_USB_DRIVER_LOG_LEVEL); + +#include +#include + +/* USBD notes + * + * 1. Require 48MHz clock source + * (1) Not support HIRC48 as clock source. It involves trim with USB SOF packets + * and isn't suitable in HAL. + * (2) Instead of HICR48, core clock is required to be multiple of 48MHz e.g. 192MHz, + * to generate necessary 48MHz. + */ + +/* For bus reset, keep 'SE0' (USB spec: SE0 >= 2.5 ms) */ +#define NUMAKER_USBD_BUS_RESET_DRV_SE0_US 3000 + +/* For bus resume, generate 'K' (USB spec: 'K' >= 1 ms) */ +#define NUMAKER_USBD_BUS_RESUME_DRV_K_US 1500 + +/* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, required to be 8-byte aligned */ +#define NUMAKER_USBD_DMABUF_SIZE_SETUP 8 +#define NUMAKER_USBD_DMABUF_SIZE_CTRLOUT 64 +#define NUMAKER_USBD_DMABUF_SIZE_CTRLIN 64 + +/* Maximum number of EP contexts across all instances + * This is to static-allocate EP contexts which can accommodate all instances. + * The number of effective EP contexts per instance is passed on through its + * num_bidir_endpoints, which must not be larger than this. + */ +#define NUMAKER_USBD_EP_MAXNUM 25ul + +/* Message type */ +#define NUMAKER_USBD_MSG_TYPE_SW_RECONN 0 /* S/W reconnect */ +#define NUMAKER_USBD_MSG_TYPE_CB_STATE 1 /* Callback for usb_dc_status_code */ +#define NUMAKER_USBD_MSG_TYPE_CB_EP 2 /* Callback for usb_dc_ep_cb_status_code */ + +/* Message structure */ +struct numaker_usbd_msg { + uint32_t type; + union { + struct { + enum usb_dc_status_code status_code; + } cb_device; + struct { + uint8_t ep; + enum usb_dc_ep_cb_status_code status_code; + } cb_ep; + }; +}; + +/* Immutable device context */ +struct numaker_usbd_config { + USBD_T *base; + const struct reset_dt_spec reset; + uint32_t clk_modidx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clkctrl_dev; + void (*irq_config_func)(const struct device *dev); + void (*irq_unconfig_func)(const struct device *dev); + const struct pinctrl_dev_config *pincfg; + uint32_t num_bidir_endpoints; + uint32_t dmabuf_size; + bool disallow_iso_inout_same; +}; + +/* EP context */ +struct numaker_usbd_ep { + bool valid; + + bool nak_clr; /* NAK cleared (ACK next transaction) */ + + const struct device *dev; /* Pointer to the containing device */ + + uint8_t ep_hw_idx; /* BSP USBD driver EP index EP0, EP1, EP2, etc */ + uint32_t ep_hw_cfg; /* BSP USBD driver EP configuration */ + + /* EP DMA buffer */ + bool dmabuf_valid; + uint32_t dmabuf_base; + uint32_t dmabuf_size; + + /* On USBD, no H/W FIFO. Simulate based on above DMA buffer with + * one-shot implementation + */ + uint32_t read_fifo_pos; + uint32_t read_fifo_used; + uint32_t write_fifo_pos; + uint32_t write_fifo_free; + + /* NOTE: On USBD, Setup and CTRL OUT are not completely separated. CTRL OUT MXPLD + * can be overridden to 8 by next Setup. To overcome it, we make one copy of CTRL + * OUT MXPLD immediately on its interrupt. + */ + uint32_t mxpld_ctrlout; + + /* EP address */ + bool addr_valid; + uint8_t addr; + + /* EP MPS */ + bool mps_valid; + uint16_t mps; + + usb_dc_ep_callback cb; /* EP callback function */ +}; + +/* EP context manager */ +struct numaker_usbd_ep_mgmt { + /* EP context management + * + * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach(). + */ + uint8_t ep_idx; + + /* DMA buffer management + * + * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach(). + */ + uint32_t dmabuf_pos; + + /* Pass Setup packet from ISR to thread */ + bool new_setup; + struct usb_setup_packet setup_packet; + + struct numaker_usbd_ep ep_pool[NUMAKER_USBD_EP_MAXNUM]; +}; + +/* Mutable device context */ +struct numaker_usbd_data { + uint8_t addr; /* Host assigned USB device address */ + + struct k_mutex sync_mutex; + + /* Enable interrupt top/bottom halves processing + * + * Registered callbacks may use mutex or other kernel functions which are not supported + * in interrupt context + */ + struct k_msgq msgq; + struct numaker_usbd_msg msgq_buf[CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE]; + + K_KERNEL_STACK_MEMBER(msg_hdlr_thread_stack, + CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE); + struct k_thread msg_hdlr_thread; + + usb_dc_status_callback status_cb; /* Status callback function */ + + struct numaker_usbd_ep_mgmt ep_mgmt; /* EP management */ +}; + +static inline const struct device *numaker_usbd_device_get(void); + +static inline void numaker_usbd_lock(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + + k_mutex_lock(&data->sync_mutex, K_FOREVER); +} + +static inline void numaker_usbd_unlock(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + + k_mutex_unlock(&data->sync_mutex); +} + +static inline void numaker_usbd_sw_connect(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Clear all interrupts first for clean */ + base->INTSTS = base->INTSTS; + + /* Enable relevant interrupts */ + base->INTEN = USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP | USBD_INT_SOF; + + /* Clear SE0 for connect */ + base->SE0 &= ~USBD_DRVSE0; +} + +static inline void numaker_usbd_sw_disconnect(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Set SE0 for disconnect */ + base->SE0 |= USBD_DRVSE0; +} + +static inline void numaker_usbd_sw_reconnect(const struct device *dev) +{ + /* Keep SE0 to trigger bus reset */ + numaker_usbd_sw_disconnect(dev); + k_sleep(K_USEC(NUMAKER_USBD_BUS_RESET_DRV_SE0_US)); + numaker_usbd_sw_connect(dev); +} + +static inline void numaker_usbd_reset_addr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + + base->FADDR = 0; + data->addr = 0; +} + +static inline void numaker_usbd_set_addr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + + if (base->FADDR != data->addr) { + base->FADDR = data->addr; + } +} + +/* USBD EP base by e.g. EP0, EP1, ... */ +static inline USBD_EP_T *numaker_usbd_ep_base(const struct device *dev, uint32_t ep_hw_idx) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + return base->EP + ep_hw_idx; +} + +static inline uint32_t numaker_usbd_ep_fifo_max(struct numaker_usbd_ep *ep_cur) +{ + /* NOTE: For one-shot implementation, effective size of EP FIFO is limited to EP MPS */ + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + __ASSERT_NO_MSG(ep_cur->mps_valid); + __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); + return ep_cur->mps; +} + +static inline uint32_t numaker_usbd_ep_fifo_used(struct numaker_usbd_ep *ep_cur) +{ + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + return USB_EP_DIR_IS_OUT(ep_cur->addr) + ? ep_cur->read_fifo_used + : numaker_usbd_ep_fifo_max(ep_cur) - ep_cur->write_fifo_free; +} + +/* Reset EP FIFO + * + * NOTE: EP FIFO is based on EP DMA buffer, which may not be configured yet. + */ +static void numaker_usbd_ep_fifo_reset(struct numaker_usbd_ep *ep_cur) +{ + if (ep_cur->dmabuf_valid && ep_cur->mps_valid) { + if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { + /* Read FIFO */ + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + ep_cur->read_fifo_used = 0; + } else { + /* Write FIFO */ + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); + } + } +} + +static inline void numaker_usbd_ep_set_stall(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Set EP to stalled */ + ep_base->CFGP |= USBD_CFGP_SSTALL_Msk; +} + +/* Reset EP to unstalled and data toggle bit to 0 */ +static inline void numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Reset EP to unstalled */ + ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; + + /* Reset EP data toggle bit to 0 */ + ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; +} + +static inline bool numaker_usbd_ep_is_stalled(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + return ep_base->CFGP & USBD_CFGP_SSTALL_Msk; +} + +static int numaker_usbd_send_msg(const struct device *dev, const struct numaker_usbd_msg *msg) +{ + struct numaker_usbd_data *data = dev->data; + int rc; + + rc = k_msgq_put(&data->msgq, msg, K_NO_WAIT); + if (rc < 0) { + /* Try to recover by S/W reconnect */ + struct numaker_usbd_msg msg_reconn = { + .type = NUMAKER_USBD_MSG_TYPE_SW_RECONN, + }; + + LOG_ERR("Message queue overflow"); + + /* Discard all not yet received messages for error recovery below */ + k_msgq_purge(&data->msgq); + + rc = k_msgq_put(&data->msgq, &msg_reconn, K_NO_WAIT); + if (rc < 0) { + LOG_ERR("Message queue overflow again"); + } + } + + return rc; +} + +static int numaker_usbd_hw_setup(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + int rc; + struct numaker_scc_subsys scc_subsys; + + /* Reset controller ready? */ + if (!device_is_ready(config->reset.dev)) { + LOG_ERR("Reset controller not ready"); + return -ENODEV; + } + + SYS_UnlockReg(); + + /* Configure USB PHY for USBD */ + SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | + (SYS_USBPHY_USBROLE_STD_USBD | SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk); + + /* Invoke Clock controller to enable module clock */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + scc_subsys.pcc.clk_src = config->clk_src; + scc_subsys.pcc.clk_div = config->clk_div; + + /* Equivalent to CLK_EnableModuleClock() */ + rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); + if (rc < 0) { + goto cleanup; + } + /* Equivalent to CLK_SetModuleClock() */ + rc = clock_control_configure(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys, + NULL); + if (rc < 0) { + goto cleanup; + } + + /* Configure pinmux (NuMaker's SYS MFP) */ + rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + goto cleanup; + } + + /* Invoke Reset controller to reset module to default state */ + /* Equivalent to SYS_ResetModule() + */ + reset_line_toggle_dt(&config->reset); + + /* Initialize USBD engine */ + /* NOTE: BSP USBD driver: ATTR = 0x7D0 */ + base->ATTR = USBD_ATTR_BYTEM_Msk | BIT(9) | USBD_ATTR_DPPUEN_Msk | USBD_ATTR_USBEN_Msk | + BIT(6) | USBD_ATTR_PHYEN_Msk; + + /* Set SE0 for S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* NOTE: Ignore DT maximum-speed with USBD fixed to full-speed */ + + /* Initialize IRQ */ + config->irq_config_func(dev); + +cleanup: + + SYS_LockReg(); + + return rc; +} + +static void numaker_usbd_hw_shutdown(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + struct numaker_scc_subsys scc_subsys; + + SYS_UnlockReg(); + + /* Uninitialize IRQ */ + config->irq_unconfig_func(dev); + + /* Set SE0 for S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* Disable USB PHY */ + base->ATTR &= ~USBD_PHY_EN; + + /* Invoke Clock controller to disable module clock */ + memset(&scc_subsys, 0x00, sizeof(scc_subsys)); + scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC; + scc_subsys.pcc.clk_modidx = config->clk_modidx; + + /* Equivalent to CLK_DisableModuleClock() */ + clock_control_off(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); + + /* Invoke Reset controller to reset module to default state */ + /* Equivalent to SYS_ResetModule() */ + reset_line_toggle_dt(&config->reset); + + SYS_LockReg(); +} + +/* Interrupt top half processing for bus reset */ +static void numaker_usbd_bus_reset_th(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_EP_T *ep_base; + + for (uint32_t i = 0ul; i < config->num_bidir_endpoints; i++) { + ep_base = numaker_usbd_ep_base(dev, EP0 + i); + + /* Cancel EP on-going transaction */ + ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* Reset EP to unstalled */ + ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; + + /* Reset EP data toggle bit to 0 */ + ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; + + /* Except EP0/EP1 kept resident for CTRL OUT/IN, disable all other EPs */ + if (i >= 2) { + ep_base->CFG = 0; + } + } + + numaker_usbd_reset_addr(dev); +} + +static void numaker_usbd_remote_wakeup(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + /* Enable back USB/PHY first */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Then generate 'K' */ + base->ATTR |= USBD_ATTR_RWAKEUP_Msk; + k_sleep(K_USEC(NUMAKER_USBD_BUS_RESUME_DRV_K_US)); + base->ATTR ^= USBD_ATTR_RWAKEUP_Msk; +} + +/* USBD SRAM base for DMA */ +static inline uint32_t numaker_usbd_buf_base(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + + return ((uint32_t)base + 0x800ul); +} + +/* Copy to user buffer from Setup FIFO */ +static void numaker_usbd_setup_fifo_copy_to_user(const struct device *dev, uint8_t *usrbuf) +{ + const struct numaker_usbd_config *config = dev->config; + USBD_T *const base = config->base; + uint32_t dmabuf_addr; + + dmabuf_addr = numaker_usbd_buf_base(dev) + (base->STBUFSEG & USBD_STBUFSEG_STBUFSEG_Msk); + + bytecpy(usrbuf, (uint8_t *)dmabuf_addr, 8ul); +} + +/* Copy data to user buffer from EP FIFO + * + * size_p holds size to copy/copied on input/output + */ +static int numaker_usbd_ep_fifo_copy_to_user(struct numaker_usbd_ep *ep_cur, uint8_t *usrbuf, + uint32_t *size_p) +{ + const struct device *dev = ep_cur->dev; + uint32_t dmabuf_addr; + + __ASSERT_NO_MSG(size_p); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + dmabuf_addr = numaker_usbd_buf_base(dev) + ep_cur->read_fifo_pos; + + /* Clamp to read FIFO used count */ + *size_p = MIN(*size_p, numaker_usbd_ep_fifo_used(ep_cur)); + + bytecpy(usrbuf, (uint8_t *)dmabuf_addr, *size_p); + + /* Advance read FIFO */ + ep_cur->read_fifo_pos += *size_p; + ep_cur->read_fifo_used -= *size_p; + if (ep_cur->read_fifo_used == 0) { + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + } + + return 0; +} + +/* Copy data from user buffer to EP FIFO + * + * size_p holds size to copy/copied on input/output + */ +static int numaker_usbd_ep_fifo_copy_from_user(struct numaker_usbd_ep *ep_cur, + const uint8_t *usrbuf, uint32_t *size_p) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + uint32_t dmabuf_addr; + uint32_t fifo_free; + + __ASSERT_NO_MSG(size_p); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + __ASSERT_NO_MSG(ep_cur->mps_valid); + __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); + + dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG; + fifo_free = numaker_usbd_ep_fifo_max(ep_cur) - numaker_usbd_ep_fifo_used(ep_cur); + + *size_p = MIN(*size_p, fifo_free); + + bytecpy((uint8_t *)dmabuf_addr, (uint8_t *)usrbuf, *size_p); + + /* Advance write FIFO */ + ep_cur->write_fifo_pos += *size_p; + ep_cur->write_fifo_free -= *size_p; + if (ep_cur->write_fifo_free == 0) { + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + } + + return 0; +} + +/* Update EP read/write FIFO on DATA OUT/IN completed */ +static void numaker_usbd_ep_fifo_update(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + __ASSERT_NO_MSG(ep_cur->addr_valid); + __ASSERT_NO_MSG(ep_cur->dmabuf_valid); + + if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { + /* Read FIFO */ + /* NOTE: For one-shot implementation, FIFO gets updated from empty. */ + ep_cur->read_fifo_pos = ep_cur->dmabuf_base; + /* NOTE: See comment on mxpld_ctrlout for why make one copy of CTRL OUT's MXPLD */ + if (USB_EP_GET_IDX(ep_cur->addr) == 0) { + ep_cur->read_fifo_used = ep_cur->mxpld_ctrlout; + } else { + ep_cur->read_fifo_used = ep_base->MXPLD; + } + } else { + /* Write FIFO */ + /* NOTE: For one-shot implementation, FIFO gets to empty. */ + ep_cur->write_fifo_pos = ep_cur->dmabuf_base; + ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); + } +} + +static void numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep *ep_cur, uint32_t dmabuf_base, + uint32_t dmabuf_size) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_base->BUFSEG = dmabuf_base; + + ep_cur->dmabuf_valid = true; + ep_cur->dmabuf_base = dmabuf_base; + ep_cur->dmabuf_size = dmabuf_size; +} + +static void numaker_usbd_ep_abort(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* Abort EP on-going transaction */ + ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; +} + +/* Configure EP major common parts */ +static void numaker_usbd_ep_config_major(struct numaker_usbd_ep *ep_cur, + const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_cur->mps_valid = true; + ep_cur->mps = ep_cfg->ep_mps; + + /* Configure EP transfer type, DATA0/1 toggle, direction, number, etc. */ + ep_cur->ep_hw_cfg = 0; + + /* Clear STALL Response in Setup stage */ + if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { + ep_cur->ep_hw_cfg |= USBD_CFG_CSTALL; + } + + /* Default to DATA0 */ + ep_cur->ep_hw_cfg &= ~USBD_CFG_DSQSYNC_Msk; + + /* Endpoint IN/OUT, though, default to disabled */ + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_DISABLE; + + /* Isochronous or not */ + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + ep_cur->ep_hw_cfg |= USBD_CFG_TYPE_ISO; + } + + /* Endpoint index */ + ep_cur->ep_hw_cfg |= + (USB_EP_GET_IDX(ep_cfg->ep_addr) << USBD_CFG_EPNUM_Pos) & USBD_CFG_EPNUM_Msk; + + ep_base->CFG = ep_cur->ep_hw_cfg; +} + +static void numaker_usbd_ep_enable(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* For safe, EP (re-)enable from clean state */ + numaker_usbd_ep_abort(ep_cur); + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + numaker_usbd_ep_fifo_reset(ep_cur); + + /* Enable EP to IN/OUT */ + ep_cur->ep_hw_cfg &= ~USBD_CFG_STATE_Msk; + if (USB_EP_DIR_IS_IN(ep_cur->addr)) { + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_IN; + } else { + ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_OUT; + } + + ep_base->CFG = ep_cur->ep_hw_cfg; + + /* For USBD, no separate EP interrupt control */ +} + +static void numaker_usbd_ep_disable(struct numaker_usbd_ep *ep_cur) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + /* For USBD, no separate EP interrupt control */ + + /* Disable EP */ + ep_cur->ep_hw_cfg = (ep_cur->ep_hw_cfg & ~USBD_CFG_STATE_Msk) | USBD_CFG_EPMODE_DISABLE; + ep_base->CFG = ep_cur->ep_hw_cfg; +} + +/* Start EP data transaction */ +static void numaker_usbd_ep_trigger(struct numaker_usbd_ep *ep_cur, uint32_t len) +{ + const struct device *dev = ep_cur->dev; + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); + + ep_base->MXPLD = len; +} + +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_alloc_ep(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur = NULL; + + if (ep_mgmt->ep_idx < config->num_bidir_endpoints) { + ep_cur = ep_mgmt->ep_pool + ep_mgmt->ep_idx; + ep_mgmt->ep_idx++; + + __ASSERT_NO_MSG(!ep_cur->valid); + + /* Indicate this EP context is allocated */ + ep_cur->valid = true; + } + + return ep_cur; +} + +/* Allocate DMA buffer + * + * Return -ENOMEM on OOM error, or 0 on success with DMA buffer base/size (rounded up) allocated + */ +static int numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device *dev, uint32_t size, + uint32_t *dmabuf_base_p, uint32_t *dmabuf_size_p) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + __ASSERT_NO_MSG(dmabuf_base_p); + __ASSERT_NO_MSG(dmabuf_size_p); + + /* Required to be 8-byte aligned */ + size = ROUND_UP(size, 8); + + ep_mgmt->dmabuf_pos += size; + if (ep_mgmt->dmabuf_pos > config->dmabuf_size) { + ep_mgmt->dmabuf_pos -= size; + return -ENOMEM; + } + + *dmabuf_base_p = ep_mgmt->dmabuf_pos - size; + *dmabuf_size_p = size; + return 0; +} + +/* Initialize all endpoint-related */ +static void numaker_usbd_ep_mgmt_init(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_ep *ep_cur; + struct numaker_usbd_ep *ep_end; + + /* Initialize all fields to zero except persistent */ + memset(ep_mgmt, 0x00, sizeof(*ep_mgmt)); + + ep_cur = ep_mgmt->ep_pool; + ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + /* Initialize all EP contexts */ + for (; ep_cur != ep_end; ep_cur++) { + /* Pointer to the containing device */ + ep_cur->dev = dev; + + /* BSP USBD driver EP handle */ + ep_cur->ep_hw_idx = EP0 + (ep_cur - ep_mgmt->ep_pool); + } + + /* Reserve 1st/2nd EP contexts (BSP USBD driver EP0/EP1) for CTRL OUT/IN */ + ep_mgmt->ep_idx = 2; + + /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, starting from 0 */ + ep_mgmt->dmabuf_pos = 0; + + /* Configure DMA buffer for Setup packet */ + base->STBUFSEG = ep_mgmt->dmabuf_pos; + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_SETUP; + + /* Reserve 1st EP context (BSP USBD driver EP0) for CTRL OUT */ + ep_cur = ep_mgmt->ep_pool + 0; + ep_cur->valid = true; + ep_cur->addr_valid = true; + ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT); + numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, + NUMAKER_USBD_DMABUF_SIZE_CTRLOUT); + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; + ep_cur->mps_valid = true; + ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; + + /* Reserve 2nd EP context (BSP USBD driver EP1) for CTRL IN */ + ep_cur = ep_mgmt->ep_pool + 1; + ep_cur->valid = true; + ep_cur->addr_valid = true; + ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_IN); + numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, NUMAKER_USBD_DMABUF_SIZE_CTRLIN); + ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLIN; + ep_cur->mps_valid = true; + ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLIN; +} + +/* Find EP context by EP address */ +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_find_ep(const struct device *dev, + const uint8_t ep) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; + struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + for (; ep_cur != ep_end; ep_cur++) { + if (!ep_cur->valid) { + continue; + } + + if (!ep_cur->addr_valid) { + continue; + } + + if (ep == ep_cur->addr) { + return ep_cur; + } + } + + return NULL; +} + +/* Bind EP context to EP address */ +static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_bind_ep(const struct device *dev, + const uint8_t ep) +{ + struct numaker_usbd_ep *ep_cur = numaker_usbd_ep_mgmt_find_ep(dev, ep); + + if (!ep_cur) { + ep_cur = numaker_usbd_ep_mgmt_alloc_ep(dev); + + if (!ep_cur) { + return NULL; + } + + /* Bind EP context to EP address */ + ep_cur->addr = ep; + ep_cur->addr_valid = true; + } + + /* Assert EP context bound to EP address */ + __ASSERT_NO_MSG(ep_cur->valid); + __ASSERT_NO_MSG(ep_cur->addr_valid); + __ASSERT_NO_MSG(ep_cur->addr == ep); + + return ep_cur; +} + +/* Interrupt bottom half processing for bus reset */ +static void numaker_usbd_bus_reset_bh(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; + struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; + + for (; ep_cur != ep_end; ep_cur++) { + /* Reset EP FIFO */ + numaker_usbd_ep_fifo_reset(ep_cur); + + /* Abort EP on-going transaction and signal H/W relinquishes DMA buffer ownership */ + numaker_usbd_ep_abort(ep_cur); + + /* Reset EP to unstalled and data toggle bit to 0 */ + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + } + + numaker_usbd_reset_addr(dev); +} + +/* Interrupt bottom half processing for Setup/EP data transaction */ +static void numaker_usbd_ep_bh(struct numaker_usbd_ep *ep_cur, + enum usb_dc_ep_cb_status_code status_code) +{ + const struct device *dev = ep_cur->dev; + struct numaker_usbd_data *data = dev->data; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + if (status_code == USB_DC_EP_SETUP) { + /* Zephyr USB device stack passes Setup packet via CTRL OUT EP. */ + __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); + + if (numaker_usbd_ep_fifo_used(ep_cur)) { + LOG_WRN("New Setup will override previous Control OUT data"); + } + + /* We should have reserved 1st/2nd EP contexts for CTRL OUT/IN */ + __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); + __ASSERT_NO_MSG((ep_cur + 1)->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)); + + /* Reset CTRL OUT/IN FIFO due to new Setup packet */ + numaker_usbd_ep_fifo_reset(ep_cur); + numaker_usbd_ep_fifo_reset(ep_cur + 1); + + /* Relinquish CTRL OUT/IN DMA buffer ownership on behalf of H/W */ + numaker_usbd_ep_abort(ep_cur); + numaker_usbd_ep_abort(ep_cur + 1); + + /* Mark new Setup packet for read */ + numaker_usbd_setup_fifo_copy_to_user(dev, (uint8_t *)&ep_mgmt->setup_packet); + ep_mgmt->new_setup = true; + } else if (status_code == USB_DC_EP_DATA_OUT) { + __ASSERT_NO_MSG(USB_EP_DIR_IS_OUT(ep_cur->addr)); + + /* Update EP read FIFO */ + numaker_usbd_ep_fifo_update(ep_cur); + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; + } else if (status_code == USB_DC_EP_DATA_IN) { + __ASSERT_NO_MSG(USB_EP_DIR_IS_IN(ep_cur->addr)); + + /* Update EP write FIFO */ + numaker_usbd_ep_fifo_update(ep_cur); + + /* Need to clear NAK for next transaction */ + ep_cur->nak_clr = false; + } +} + +/* Message handler for S/W reconnect */ +static void numaker_usbd_msg_sw_reconn(const struct device *dev, struct numaker_usbd_msg *msg) +{ + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SW_RECONN); + + /* S/W reconnect for error recovery */ + numaker_usbd_lock(dev); + numaker_usbd_sw_reconnect(dev); + numaker_usbd_unlock(dev); +} + +/* Message handler for callback for usb_dc_status_code */ +static void numaker_usbd_msg_cb_state(const struct device *dev, struct numaker_usbd_msg *msg) +{ + struct numaker_usbd_data *data = dev->data; + + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_STATE); + + /* Interrupt bottom half processing for bus reset */ + if (msg->cb_device.status_code == USB_DC_RESET) { + numaker_usbd_lock(dev); + numaker_usbd_bus_reset_bh(dev); + numaker_usbd_unlock(dev); + } + + /* NOTE: Don't run callback with our mutex locked, or we may encounter + * deadlock because the Zephyr USB device stack can have its own + * synchronization. + */ + if (data->status_cb) { + data->status_cb(msg->cb_device.status_code, NULL); + } else { + LOG_WRN("No status callback: status_code=%d", msg->cb_device.status_code); + } +} + +/* Message handler for callback for usb_dc_ep_cb_status_code */ +static void numaker_usbd_msg_cb_ep(const struct device *dev, struct numaker_usbd_msg *msg) +{ + uint8_t ep; + struct numaker_usbd_ep *ep_cur; + + __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_EP); + + ep = msg->cb_ep.ep; + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + return; + } + + /* Interrupt bottom half processing for EP */ + numaker_usbd_lock(dev); + numaker_usbd_ep_bh(ep_cur, msg->cb_ep.status_code); + numaker_usbd_unlock(dev); + + /* NOTE: Same as above, don't run callback with our mutex locked */ + if (ep_cur->cb) { + ep_cur->cb(ep, msg->cb_ep.status_code); + } else { + LOG_WRN("No EP callback: ep=0x%02x, status_code=%d", ep, msg->cb_ep.status_code); + } +} + +/* Interrupt bottom half processing + * + * This thread is used to not run Zephyr USB device stack and callbacks in interrupt + * context. This is because callbacks from this stack may use mutex or other kernel functions + * which are not supported in interrupt context. + */ +static void numaker_usbd_msg_hdlr_thread_main(void *arg1, void *arg2, void *arg3) +{ + const struct device *dev = (const struct device *)arg1; + struct numaker_usbd_data *data = dev->data; + + struct numaker_usbd_msg msg; + + __ASSERT_NO_MSG(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + while (true) { + if (k_msgq_get(&data->msgq, &msg, K_FOREVER)) { + continue; + } + + switch (msg.type) { + case NUMAKER_USBD_MSG_TYPE_SW_RECONN: + numaker_usbd_msg_sw_reconn(dev, &msg); + break; + + case NUMAKER_USBD_MSG_TYPE_CB_STATE: + numaker_usbd_msg_cb_state(dev, &msg); + break; + + case NUMAKER_USBD_MSG_TYPE_CB_EP: + numaker_usbd_msg_cb_ep(dev, &msg); + break; + + default: + __ASSERT_NO_MSG(false); + } + } +} + +static void numaker_udbd_isr(const struct device *dev) +{ + const struct numaker_usbd_config *config = dev->config; + struct numaker_usbd_data *data = dev->data; + USBD_T *const base = config->base; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + + struct numaker_usbd_msg msg = {0}; + + uint32_t volatile usbd_intsts = base->INTSTS; + uint32_t volatile usbd_bus_state = base->ATTR; + + /* USB plug-in/unplug */ + if (usbd_intsts & USBD_INTSTS_FLDET) { + /* Floating detect */ + base->INTSTS = USBD_INTSTS_FLDET; + + if (base->VBUSDET & USBD_VBUSDET_VBUSDET_Msk) { + /* USB plug-in */ + + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_CONNECTED; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB plug-in"); + } else { + /* USB unplug */ + + /* Disable USB */ + base->ATTR &= ~USBD_USB_EN; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_DISCONNECTED; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB unplug"); + } + } + + /* USB wake-up */ + if (usbd_intsts & USBD_INTSTS_WAKEUP) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_WAKEUP; + + LOG_DBG("USB wake-up"); + } + + /* USB reset/suspend/resume */ + if (usbd_intsts & USBD_INTSTS_BUS) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_BUS; + + if (usbd_bus_state & USBD_STATE_USBRST) { + /* Bus reset */ + + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Bus reset top half */ + numaker_usbd_bus_reset_th(dev); + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_RESET; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB reset"); + } + if (usbd_bus_state & USBD_STATE_SUSPEND) { + /* Enable USB but disable PHY */ + base->ATTR &= ~USBD_PHY_EN; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_SUSPEND; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB suspend"); + } + if (usbd_bus_state & USBD_STATE_RESUME) { + /* Enable back USB/PHY */ + base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_RESUME; + numaker_usbd_send_msg(dev, &msg); + + LOG_DBG("USB resume"); + } + } + + /* USB SOF */ + if (usbd_intsts & USBD_INTSTS_SOFIF_Msk) { + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_SOFIF_Msk; + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE; + msg.cb_device.status_code = USB_DC_SOF; + numaker_usbd_send_msg(dev, &msg); + } + + /* USB Setup/EP */ + if (usbd_intsts & USBD_INTSTS_USB) { + uint32_t epintsts; + + /* Setup event */ + if (usbd_intsts & USBD_INTSTS_SETUP) { + USBD_EP_T *ep0_base = numaker_usbd_ep_base(dev, EP0); + USBD_EP_T *ep1_base = numaker_usbd_ep_base(dev, EP1); + + /* Clear event flag */ + base->INTSTS = USBD_INTSTS_SETUP; + + /* Clear the data IN/OUT ready flag of control endpoints */ + ep0_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + ep1_base->CFGP |= USBD_CFGP_CLRRDY_Msk; + + /* By USB spec, following transactions, regardless of Data/Status stage, + * will always be DATA1 + */ + ep0_base->CFG |= USBD_CFG_DSQSYNC_Msk; + ep1_base->CFG |= USBD_CFG_DSQSYNC_Msk; + + /* Message for bottom-half processing */ + /* NOTE: In Zephyr USB device stack, Setup packet is passed via + * CTRL OUT EP + */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP; + msg.cb_ep.ep = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT); + msg.cb_ep.status_code = USB_DC_EP_SETUP; + numaker_usbd_send_msg(dev, &msg); + } + + /* EP events */ + epintsts = base->EPINTSTS; + + base->EPINTSTS = epintsts; + + while (epintsts) { + uint32_t ep_hw_idx = u32_count_trailing_zeros(epintsts); + USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_hw_idx); + uint8_t ep_dir; + uint8_t ep_idx; + uint8_t ep; + + /* We don't enable INNAKEN interrupt, so as long as EP event occurs, + * we can just regard one data transaction has completed (ACK for + * CTRL/BULK/INT or no-ACK for Iso), that is, no need to check EPSTS0, + * EPSTS1, etc. + */ + + /* EP direction, number, and address */ + ep_dir = ((ep_base->CFG & USBD_CFG_STATE_Msk) == USBD_CFG_EPMODE_IN) + ? USB_EP_DIR_IN + : USB_EP_DIR_OUT; + ep_idx = (ep_base->CFG & USBD_CFG_EPNUM_Msk) >> USBD_CFG_EPNUM_Pos; + ep = USB_EP_GET_ADDR(ep_idx, ep_dir); + + /* NOTE: See comment in usb_dc_set_address()'s implementation + * for safe place to change USB device address + */ + if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)) { + numaker_usbd_set_addr(dev); + } + + /* NOTE: See comment on mxpld_ctrlout for why make one copy of + * CTRL OUT's MXPLD + */ + if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)) { + struct numaker_usbd_ep *ep_ctrlout = ep_mgmt->ep_pool + 0; + USBD_EP_T *ep_ctrlout_base = + numaker_usbd_ep_base(dev, ep_ctrlout->ep_hw_idx); + + ep_ctrlout->mxpld_ctrlout = ep_ctrlout_base->MXPLD; + } + + /* Message for bottom-half processing */ + msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP; + msg.cb_ep.ep = ep; + msg.cb_ep.status_code = + USB_EP_DIR_IS_IN(ep) ? USB_DC_EP_DATA_IN : USB_DC_EP_DATA_OUT; + numaker_usbd_send_msg(dev, &msg); + + /* Have handled this EP and go next */ + epintsts &= ~BIT(ep_hw_idx); + } + } +} + +/* Zephyr USB device controller API implementation */ + +int usb_dc_attach(void) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc; + + numaker_usbd_lock(dev); + + /* Initialize USB DC H/W */ + rc = numaker_usbd_hw_setup(dev); + if (rc < 0) { + LOG_ERR("Set up H/W"); + goto cleanup; + } + + /* USB device address defaults to 0 */ + numaker_usbd_reset_addr(dev); + + /* Initialize all EPs */ + numaker_usbd_ep_mgmt_init(dev); + + /* S/W connect */ + numaker_usbd_sw_connect(dev); + + LOG_DBG("attached"); + +cleanup: + + if (rc < 0) { + usb_dc_detach(); + } + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_detach(void) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + LOG_DBG("detached"); + + numaker_usbd_lock(dev); + + /* S/W disconnect */ + numaker_usbd_sw_disconnect(dev); + + /* Uninitialize USB DC H/W */ + numaker_usbd_hw_shutdown(numaker_usbd_device_get()); + + /* Purge message queue */ + k_msgq_purge(&data->msgq); + + numaker_usbd_unlock(dev); + + return 0; +} + +int usb_dc_reset(void) +{ + const struct device *dev = numaker_usbd_device_get(); + + LOG_DBG("usb_dc_reset"); + + numaker_usbd_lock(dev); + + usb_dc_detach(); + usb_dc_attach(); + + numaker_usbd_unlock(dev); + + return 0; +} + +int usb_dc_set_address(const uint8_t addr) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + LOG_DBG("USB device address=%u (0x%02x)", addr, addr); + + numaker_usbd_lock(dev); + + /* NOTE: Timing for configuring USB device address into H/W is critical. It must be done + * in-between SET_ADDRESS control transfer and next transfer. For this, it is done in + * IN ACK ISR of SET_ADDRESS control transfer. + */ + data->addr = addr; + + numaker_usbd_unlock(dev); + + return 0; +} + +void usb_dc_set_status_callback(const usb_dc_status_callback cb) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + + numaker_usbd_lock(dev); + + data->status_cb = cb; + + numaker_usbd_unlock(dev); +} + +int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = numaker_usbd_device_get(); + const struct numaker_usbd_config *config = dev->config; + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* For safe, require EP number for control transfer to be 0 */ + if ((ep_cfg->ep_type == USB_DC_EP_CONTROL) && USB_EP_GET_IDX(ep_cfg->ep_addr) != 0) { + LOG_ERR("EP number for control transfer must be 0"); + rc = -ENOTSUP; + goto cleanup; + } + + /* Some soc series don't allow ISO IN/OUT to be assigned the same EP number. + * This is addressed by limiting all OUT/IN EP addresses in top/bottom halves, + * except CTRL OUT/IN. + */ + if (config->disallow_iso_inout_same && ep_cfg->ep_type != USB_DC_EP_CONTROL) { + /* Limit all OUT EP addresses in top-half, except CTRL OUT */ + if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) >= 8) { + LOG_DBG("Support only ISO OUT EP address 0x01~0x07: 0x%02x", + ep_cfg->ep_addr); + rc = -ENOTSUP; + goto cleanup; + } + + /* Limit all IN EP addresses in bottom-half , except CTRL IN */ + if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) < 8) { + LOG_DBG("Support only ISO IN EP address 0x88~0x8F: 0x%02x", + ep_cfg->ep_addr); + rc = -ENOTSUP; + goto cleanup; + } + } + + /* To respect this capability check, pre-bind EP context to EP address, + * and pre-determined its type + */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); + rc = -ENOMEM; + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + ep_cur->cb = cb; + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + uint32_t dmabuf_base; + uint32_t dmabuf_size; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("EP=0x%02x, MPS=%d, Type=%d", ep_cfg->ep_addr, ep_cfg->ep_mps, ep_cfg->ep_type); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); + rc = -ENOMEM; + goto cleanup; + } + + /* Configure EP DMA buffer */ + if (!ep_cur->dmabuf_valid || ep_cur->dmabuf_size < ep_cfg->ep_mps) { + /* Allocate DMA buffer */ + rc = numaker_usbd_ep_mgmt_alloc_dmabuf(dev, ep_cfg->ep_mps, &dmabuf_base, + &dmabuf_size); + if (rc < 0) { + LOG_ERR("Allocate DMA buffer failed"); + goto cleanup; + } + + /* Configure EP DMA buffer */ + numaker_usbd_ep_config_dmabuf(ep_cur, dmabuf_base, dmabuf_size); + } + + /* Configure EP majorly */ + numaker_usbd_ep_config_major(ep_cur, ep_cfg); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_set_stall(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Set stall: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + /* Set EP to stalled */ + numaker_usbd_ep_set_stall(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_clear_stall(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Clear stall: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + /* Reset EP to unstalled and data toggle bit to 0 */ + numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + if (!stalled) { + return -EINVAL; + } + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + *stalled = numaker_usbd_ep_is_stalled(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_halt(const uint8_t ep) +{ + return usb_dc_ep_set_stall(ep); +} + +int usb_dc_ep_enable(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Enable: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_enable(ep_cur); + + /* Trigger OUT transaction manually, or H/W will continue to reply NAK because + * Zephyr USB device stack is unclear on kicking off by invoking usb_dc_ep_read() + * or friends. We needn't do this for CTRL OUT because Setup sequence will involve + * this. + */ + if (USB_EP_DIR_IS_OUT(ep) && USB_EP_GET_IDX(ep) != 0) { + rc = usb_dc_ep_read_continue(ep); + if (rc < 0) { + goto cleanup; + } + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_disable(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("Disable: ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_disable(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_flush(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + LOG_DBG("ep=0x%02x", ep); + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + numaker_usbd_ep_fifo_reset(ep_cur); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data_buf, const uint32_t data_len, + uint32_t *const ret_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + uint32_t data_len_act; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_IN(ep)) { + LOG_ERR("Invalid EP address 0x%02x for write", ep); + rc = -EINVAL; + goto cleanup; + } + + /* For USBD, avoid duplicate NAK clear */ + if (ep_cur->nak_clr) { + LOG_WRN("ep 0x%02x busy", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* For one-shot implementation, don't trigger next DATA IN with write FIFO not empty. */ + if (numaker_usbd_ep_fifo_used(ep_cur)) { + LOG_WRN("ep 0x%02x: Write FIFO not empty for one-shot implementation", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* NOTE: Null data or zero data length are valid, used for ZLP */ + if (data_buf && data_len) { + data_len_act = data_len; + rc = numaker_usbd_ep_fifo_copy_from_user(ep_cur, data_buf, &data_len_act); + if (rc < 0) { + LOG_ERR("Copy to FIFO from user buffer"); + goto cleanup; + } + } else { + data_len_act = 0; + } + + /* Now H/W actually owns EP DMA buffer */ + numaker_usbd_ep_trigger(ep_cur, data_len_act); + + /* NOTE: For one-shot implementation, at most MPS size can be written, though, + * null 'ret_bytes' requires all data written. + */ + if (ret_bytes) { + *ret_bytes = data_len_act; + } else if (data_len_act != data_len) { + LOG_ERR("Expected write all %d bytes, but actual %d bytes written", data_len, + data_len_act); + rc = -EIO; + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, const uint32_t max_data_len, + uint32_t *const read_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + + numaker_usbd_lock(dev); + + rc = usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes); + if (rc < 0) { + goto cleanup; + } + + rc = usb_dc_ep_read_continue(ep); + if (rc < 0) { + goto cleanup; + } + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data_buf, uint32_t max_data_len, uint32_t *read_bytes) +{ + const struct device *dev = numaker_usbd_device_get(); + struct numaker_usbd_data *data = dev->data; + int rc = 0; + struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; + struct numaker_usbd_ep *ep_cur; + uint32_t data_len_act = 0; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_OUT(ep)) { + LOG_ERR("Invalid EP address 0x%02x for read", ep); + rc = -EINVAL; + goto cleanup; + } + + /* Special handling for USB_CONTROL_EP_OUT on Setup packet */ + if (ep == USB_CONTROL_EP_OUT && ep_mgmt->new_setup) { + if (!data_buf || max_data_len != 8) { + LOG_ERR("Invalid parameter for reading Setup packet"); + rc = -EINVAL; + goto cleanup; + } + + memcpy(data_buf, &ep_mgmt->setup_packet, 8); + ep_mgmt->new_setup = false; + + if (read_bytes) { + *read_bytes = 8; + } + + goto cleanup; + } + + /* For one-shot implementation, don't read FIFO with EP busy. */ + if (ep_cur->nak_clr) { + LOG_WRN("ep 0x%02x busy", ep); + rc = -EAGAIN; + goto cleanup; + } + + /* NOTE: Null data and zero data length is valid, used for returning number of + * available bytes for read + */ + if (data_buf) { + data_len_act = max_data_len; + rc = numaker_usbd_ep_fifo_copy_to_user(ep_cur, data_buf, &data_len_act); + if (rc < 0) { + LOG_ERR("Copy from FIFO to user buffer"); + goto cleanup; + } + + if (read_bytes) { + *read_bytes = data_len_act; + } + } else if (max_data_len) { + LOG_ERR("Null data but non-zero data length"); + rc = -EINVAL; + goto cleanup; + } else { + if (read_bytes) { + *read_bytes = numaker_usbd_ep_fifo_used(ep_cur); + } + } + + /* Suppress further USB_DC_EP_DATA_OUT events by replying NAK or disabling interrupt + * + * For USBD, further control is unnecessary because NAK is automatically replied until + * next USBD_SET_PAYLOAD_LEN(). + */ + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_read_continue(uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + if (!USB_EP_DIR_IS_OUT(ep)) { + LOG_ERR("Invalid EP address 0x%02x for read", ep); + rc = -EINVAL; + goto cleanup; + } + + /* Avoid duplicate NAK clear */ + if (ep_cur->nak_clr) { + rc = 0; + goto cleanup; + } + + /* For one-shot implementation, don't trigger next DATA OUT, or overwrite. */ + if (numaker_usbd_ep_fifo_used(ep_cur)) { + goto cleanup; + } + + __ASSERT_NO_MSG(ep_cur->mps_valid); + numaker_usbd_ep_trigger(ep_cur, ep_cur->mps); + +cleanup: + + numaker_usbd_unlock(dev); + + return rc; +} + +int usb_dc_ep_mps(const uint8_t ep) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + struct numaker_usbd_ep *ep_cur; + uint16_t ep_mps = 0; + + numaker_usbd_lock(dev); + + /* Bind EP context to EP address */ + ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep); + + if (!ep_cur) { + LOG_ERR("Bind EP context: ep=0x%02x", ep); + rc = -ENOMEM; + goto cleanup; + } + + __ASSERT_NO_MSG(ep_cur->mps_valid); + ep_mps = ep_cur->mps; + +cleanup: + + numaker_usbd_unlock(dev); + + return rc == 0 ? ep_mps : rc; +} + +int usb_dc_wakeup_request(void) +{ + const struct device *dev = numaker_usbd_device_get(); + int rc = 0; + + LOG_DBG("Remote wakeup"); + + numaker_usbd_lock(dev); + + numaker_usbd_remote_wakeup(dev); + + numaker_usbd_unlock(dev); + + return rc; +} + +static int numaker_udbd_init(const struct device *dev) +{ + struct numaker_usbd_data *data = dev->data; + int rc = 0; + + /* Initialize all fields to zero */ + memset(data, 0x00, sizeof(*data)); + + k_mutex_init(&data->sync_mutex); + + /* Set up interrupt top/bottom halves processing */ + + k_msgq_init(&data->msgq, (char *)data->msgq_buf, sizeof(struct numaker_usbd_msg), + CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE); + + k_thread_create(&data->msg_hdlr_thread, data->msg_hdlr_thread_stack, + CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE, + numaker_usbd_msg_hdlr_thread_main, (void *)dev, NULL, NULL, K_PRIO_COOP(2), + 0, K_NO_WAIT); + + k_thread_name_set(&data->msg_hdlr_thread, "numaker_usbd"); + + return rc; +} + +#define USB_DC_NUMAKER_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static void numaker_usbd_irq_config_func_##inst(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), numaker_udbd_isr, \ + DEVICE_DT_INST_GET(inst), 0); \ + \ + irq_enable(DT_INST_IRQN(inst)); \ + } \ + \ + static void numaker_uusbd_irq_unconfig_func_##inst(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(inst)); \ + } \ + \ + static const struct numaker_usbd_config numaker_usbd_config_##inst = { \ + .base = (USBD_T *)DT_INST_REG_ADDR(inst), \ + .reset = RESET_DT_SPEC_INST_GET(inst), \ + .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \ + .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \ + .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \ + .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \ + .irq_config_func = numaker_usbd_irq_config_func_##inst, \ + .irq_unconfig_func = numaker_uusbd_irq_unconfig_func_##inst, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .num_bidir_endpoints = DT_INST_PROP(inst, num_bidir_endpoints), \ + .dmabuf_size = DT_INST_PROP(inst, dma_buffer_size), \ + .disallow_iso_inout_same = DT_INST_PROP(inst, disallow_iso_in_out_same_number), \ + }; \ + \ + static struct numaker_usbd_data numaker_usbd_data_##inst; \ + \ + BUILD_ASSERT(DT_INST_PROP(inst, num_bidir_endpoints) <= NUMAKER_USBD_EP_MAXNUM, \ + "num_bidir_endpoints exceeds support limit by USBD driver"); \ + \ + DEVICE_DT_INST_DEFINE(inst, numaker_udbd_init, NULL, &numaker_usbd_data_##inst, \ + &numaker_usbd_config_##inst, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL); + +USB_DC_NUMAKER_INIT(0); + +/* Get USB DC device context instance 0 */ +static inline const struct device *numaker_usbd_device_get(void) +{ + return DEVICE_DT_INST_GET(0); +} diff --git a/drivers/usb/device/usb_dc_rpi_pico.c b/drivers/usb/device/usb_dc_rpi_pico.c index bcc5e93151b..bb99fa365b2 100644 --- a/drivers/usb/device/usb_dc_rpi_pico.c +++ b/drivers/usb/device/usb_dc_rpi_pico.c @@ -17,6 +17,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(udc_rpi, CONFIG_USB_DRIVER_LOG_LEVEL); @@ -26,6 +27,8 @@ LOG_MODULE_REGISTER(udc_rpi, CONFIG_USB_DRIVER_LOG_LEVEL); #define USB_IRQ DT_INST_IRQ_BY_NAME(0, usbctrl, irq) #define USB_IRQ_PRI DT_INST_IRQ_BY_NAME(0, usbctrl, priority) #define USB_NUM_BIDIR_ENDPOINTS DT_INST_PROP(0, num_bidir_endpoints) +#define CLK_DRV DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)) +#define CLK_ID (clock_control_subsys_t)DT_INST_PHA_BY_IDX(0, clocks, 0, clk_id) #define DATA_BUFFER_SIZE 64U @@ -637,9 +640,9 @@ int usb_dc_ep_enable(const uint8_t ep) LOG_DBG("ep 0x%02x (id: %d) -> type %d", ep, USB_EP_GET_IDX(ep), ep_state->type); - /* clear buffer state (EP0 starts with PID=1 for setup phase) */ - - *ep_state->buf_ctl = (USB_EP_GET_IDX(ep) == 0 ? USB_BUF_CTRL_DATA1_PID : 0); + /* clear buffer state */ + *ep_state->buf_ctl = USB_BUF_CTRL_DATA0_PID; + ep_state->next_pid = 0; /* EP0 doesn't have an ep_ctl */ if (ep_state->ep_ctl) { @@ -674,6 +677,13 @@ int usb_dc_ep_disable(const uint8_t ep) return 0; } + /* If this endpoint has previously been used and e.g. the host application + * crashed, the endpoint may remain locked even after reconfiguration + * because the write semaphore is never given back. + * udc_rpi_cancel_endpoint() handles this so the endpoint can be written again. + */ + udc_rpi_cancel_endpoint(ep); + uint8_t val = *ep_state->ep_ctl & ~EP_CTRL_ENABLE_BITS; *ep_state->ep_ctl = val; @@ -985,6 +995,7 @@ static void udc_rpi_thread_main(void *arg1, void *unused1, void *unused2) static int usb_rpi_init(void) { + int ret; k_thread_create(&thread, thread_stack, USBD_THREAD_STACK_SIZE, @@ -992,6 +1003,11 @@ static int usb_rpi_init(void) K_PRIO_COOP(2), 0, K_NO_WAIT); k_thread_name_set(&thread, "usb_rpi"); + ret = clock_control_on(CLK_DRV, CLK_ID); + if (ret < 0) { + return ret; + } + IRQ_CONNECT(USB_IRQ, USB_IRQ_PRI, udc_rpi_isr, 0, 0); irq_enable(USB_IRQ); diff --git a/drivers/usb/device/usb_dc_stm32.c b/drivers/usb/device/usb_dc_stm32.c index c5516b73aef..13131061610 100644 --- a/drivers/usb/device/usb_dc_stm32.c +++ b/drivers/usb/device/usb_dc_stm32.c @@ -127,14 +127,18 @@ static const struct gpio_dt_spec ulpi_reset = #define EP_MPS USB_OTG_FS_MAX_PACKET_SIZE #endif -/* We need one RX FIFO and n TX-IN FIFOs */ -#define FIFO_NUM (1 + USB_NUM_BIDIR_ENDPOINTS) +/* We need n TX IN FIFOs */ +#define TX_FIFO_NUM USB_NUM_BIDIR_ENDPOINTS -/* 4-byte words FIFO */ -#define FIFO_WORDS (USB_RAM_SIZE / 4) +/* We need a minimum size for RX FIFO */ +#define USB_FIFO_RX_MIN 160 -/* Allocate FIFO memory evenly between the FIFOs */ -#define FIFO_EP_WORDS (FIFO_WORDS / FIFO_NUM) +/* 4-byte words TX FIFO */ +#define TX_FIFO_WORDS ((USB_RAM_SIZE - USB_FIFO_RX_MIN - 64) / 4) + +/* Allocate FIFO memory evenly between the TX FIFOs */ +/* except the first TX endpoint need only 64 bytes */ +#define TX_FIFO_EP_WORDS (TX_FIFO_WORDS / (TX_FIFO_NUM - 1)) #endif /* USB */ @@ -213,10 +217,14 @@ static int usb_dc_stm32_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) + + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ if (DT_INST_NUM_CLOCKS(0) > 1) { if (clock_control_configure(clk, (clock_control_subsys_t)&pclken[1], @@ -436,11 +444,17 @@ static int usb_dc_stm32_init(void) k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1); } #else /* USB_OTG_FS */ + /* TODO: make this dynamic (depending usage) */ - HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, FIFO_EP_WORDS); + HAL_PCDEx_SetRxFiFo(&usb_dc_stm32_state.pcd, USB_FIFO_RX_MIN); for (i = 0U; i < USB_NUM_BIDIR_ENDPOINTS; i++) { - HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, - FIFO_EP_WORDS); + if (i == 0) { + /* first endpoint need only 64 byte for EP_TYPE_CTRL */ + HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, 16); + } else { + HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i, + TX_FIFO_EP_WORDS); + } k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1); } #endif /* USB */ @@ -498,7 +512,7 @@ int usb_dc_attach(void) /* * Required for at least STM32L4 devices as they electrically - * isolate USB features from VDDUSB. It must be enabled before + * isolate USB features from VddUSB. It must be enabled before * USB can function. Refer to section 5.1.3 in DM00083560 or * DM00310109. */ @@ -629,20 +643,39 @@ int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg) LOG_DBG("ep 0x%02x, previous ep_mps %u, ep_mps %u, ep_type %u", ep_cfg->ep_addr, ep_state->ep_mps, ep_cfg->ep_mps, ep_cfg->ep_type); - #if defined(USB) || defined(USB_DRD_FS) if (ep_cfg->ep_mps > ep_state->ep_pma_buf_len) { - if (USB_RAM_SIZE <= - (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps*2)) { + return -EINVAL; + } + } else if (USB_RAM_SIZE <= + (usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps)) { return -EINVAL; } - HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, - usb_dc_stm32_state.pma_offset); - ep_state->ep_pma_buf_len = ep_cfg->ep_mps; - usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_DBL_BUF, + usb_dc_stm32_state.pma_offset + + ((usb_dc_stm32_state.pma_offset + ep_cfg->ep_mps) << 16)); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps*2; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps*2; + } else { + HAL_PCDEx_PMAConfig(&usb_dc_stm32_state.pcd, ep, PCD_SNG_BUF, + usb_dc_stm32_state.pma_offset); + ep_state->ep_pma_buf_len = ep_cfg->ep_mps; + usb_dc_stm32_state.pma_offset += ep_cfg->ep_mps; + } } -#endif + if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { + ep_state->ep_mps = ep_cfg->ep_mps*2; + } else { + ep_state->ep_mps = ep_cfg->ep_mps; + } +#else ep_state->ep_mps = ep_cfg->ep_mps; +#endif switch (ep_cfg->ep_type) { case USB_DC_EP_CONTROL: @@ -751,7 +784,7 @@ int usb_dc_ep_enable(const uint8_t ep) if (USB_EP_DIR_IS_OUT(ep) && ep != EP0_OUT) { return usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; @@ -890,7 +923,7 @@ int usb_dc_ep_read_continue(uint8_t ep) */ if (!ep_state->read_count) { usb_dc_ep_start_read(ep, usb_dc_stm32_state.ep_buf[USB_EP_GET_IDX(ep)], - EP_MPS); + ep_state->ep_mps); } return 0; diff --git a/drivers/usb/device/usb_dw_registers.h b/drivers/usb/device/usb_dw_registers.h deleted file mode 100644 index 83e67c157ce..00000000000 --- a/drivers/usb/device/usb_dw_registers.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ -#define ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This file describes register set for the DesignWare USB 2.0 controller IP, - * other known names are OTG_FS, OTG_HS. - */ - -/* USB IN EP Register block type */ -struct usb_dw_in_ep_reg { - volatile uint32_t diepctl; - uint32_t reserved; - volatile uint32_t diepint; - uint32_t reserved1; - volatile uint32_t dieptsiz; - volatile uint32_t diepdma; - volatile uint32_t dtxfsts; - uint32_t reserved2; -}; - -/* USB OUT EP Register block type */ -struct usb_dw_out_ep_reg { - volatile uint32_t doepctl; - uint32_t reserved; - volatile uint32_t doepint; - uint32_t reserved1; - volatile uint32_t doeptsiz; - volatile uint32_t doepdma; - uint32_t reserved2; - uint32_t reserved3; -}; - -/* USB Register block type */ -struct usb_dw_reg { - volatile uint32_t gotgctl; - volatile uint32_t gotgint; - volatile uint32_t gahbcfg; - volatile uint32_t gusbcfg; - volatile uint32_t grstctl; - volatile uint32_t gintsts; - volatile uint32_t gintmsk; - volatile uint32_t grxstsr; - volatile uint32_t grxstsp; - volatile uint32_t grxfsiz; - volatile uint32_t gnptxfsiz; - uint32_t reserved[3]; - volatile uint32_t ggpio; - volatile uint32_t guid; - volatile uint32_t gsnpsid; - volatile uint32_t ghwcfg1; - volatile uint32_t ghwcfg2; - volatile uint32_t ghwcfg3; - volatile uint32_t ghwcfg4; - volatile uint32_t gdfifocfg; - uint32_t reserved1[43]; - volatile uint32_t dieptxf1; - volatile uint32_t dieptxf2; - volatile uint32_t dieptxf3; - volatile uint32_t dieptxf4; - volatile uint32_t dieptxf5; - /* Host mode register 0x0400 .. 0x0670 */ - uint32_t reserved2[442]; - /* Device mode register 0x0800 .. 0x0D00 */ - volatile uint32_t dcfg; - volatile uint32_t dctl; - volatile uint32_t dsts; - uint32_t reserved3; - volatile uint32_t diepmsk; - volatile uint32_t doepmsk; - volatile uint32_t daint; - volatile uint32_t daintmsk; - uint32_t reserved4[2]; - volatile uint32_t dvbusdis; - volatile uint32_t dvbuspulse; - volatile uint32_t dthrctl; - volatile uint32_t diepempmsk; - uint32_t reserved5[50]; - struct usb_dw_in_ep_reg in_ep_reg[16]; - struct usb_dw_out_ep_reg out_ep_reg[16]; -}; - -/* - * With the maximum number of supported endpoints, register set - * of the controller can occupy the region up to 0x0D00. - */ -BUILD_ASSERT(sizeof(struct usb_dw_reg) <= 0x0D00); - -/* AHB configuration register, offset: 0x0008 */ -#define USB_DW_GAHBCFG_DMA_EN BIT(5) -#define USB_DW_GAHBCFG_GLB_INTR_MASK BIT(0) - -/* USB configuration register, offset: 0x000C */ -#define USB_DW_GUSBCFG_FORCEDEVMODE BIT(30) -#define USB_DW_GUSBCFG_FORCEHSTMODE BIT(29) -#define USB_DW_GUSBCFG_PHY_IF_MASK BIT(3) -#define USB_DW_GUSBCFG_PHY_IF_8_BIT 0 -#define USB_DW_GUSBCFG_PHY_IF_16_BIT BIT(3) - -/* Reset register, offset: 0x0010 */ -#define USB_DW_GRSTCTL_AHB_IDLE BIT(31) -#define USB_DW_GRSTCTL_TX_FNUM_OFFSET 6 -#define USB_DW_GRSTCTL_TX_FFLSH BIT(5) -#define USB_DW_GRSTCTL_C_SFT_RST BIT(0) - -/* Core interrupt register, offset: 0x0014 */ -#define USB_DW_GINTSTS_WK_UP_INT BIT(31) -#define USB_DW_GINTSTS_OEP_INT BIT(19) -#define USB_DW_GINTSTS_IEP_INT BIT(18) -#define USB_DW_GINTSTS_ENUM_DONE BIT(13) -#define USB_DW_GINTSTS_USB_RST BIT(12) -#define USB_DW_GINTSTS_USB_SUSP BIT(11) -#define USB_DW_GINTSTS_RX_FLVL BIT(4) -#define USB_DW_GINTSTS_OTG_INT BIT(2) - -/* Status read and pop registers (device mode), offset: 0x001C 0x0020 */ -#define USB_DW_GRXSTSR_PKT_STS_MASK (0xF << 17) -#define USB_DW_GRXSTSR_PKT_STS_OFFSET 17 -#define USB_DW_GRXSTSR_PKT_STS_OUT_DATA 2 -#define USB_DW_GRXSTSR_PKT_STS_OUT_DATA_DONE 3 -#define USB_DW_GRXSTSR_PKT_STS_SETUP_DONE 4 -#define USB_DW_GRXSTSR_PKT_STS_SETUP 6 -#define USB_DW_GRXSTSR_PKT_CNT_MASK (0x7FF << 4) -#define USB_DW_GRXSTSR_PKT_CNT_OFFSET 4 -#define USB_DW_GRXSTSR_EP_NUM_MASK (0xF << 0) - -/* Application (vendor) general purpose registers, offset: 0x0038 */ -#define USB_DW_GGPIO_STM32_VBDEN BIT(21) -#define USB_DW_GGPIO_STM32_PWRDWN BIT(16) - -/* GHWCFG1 register, offset: 0x0044 */ -#define USB_DW_GHWCFG1_EPDIR_MASK(i) (0x3 << (i * 2)) -#define USB_DW_GHWCFG1_EPDIR_SHIFT(i) (i * 2) -#define USB_DW_GHWCFG1_OUTENDPT 2 -#define USB_DW_GHWCFG1_INENDPT 1 -#define USB_DW_GHWCFG1_BDIR 0 - -/* GHWCFG2 register, offset: 0x0048 */ -#define USB_DW_GHWCFG2_NUMDEVEPS_MASK (0xF << 10) -#define USB_DW_GHWCFG2_NUMDEVEPS_SHIFT 10 -#define USB_DW_GHWCFG2_FSPHYTYPE_MASK (0x3 << 8) -#define USB_DW_GHWCFG2_FSPHYTYPE_SHIFT 8 -#define USB_DW_GHWCFG2_FSPHYTYPE_FSPLUSULPI 3 -#define USB_DW_GHWCFG2_FSPHYTYPE_FSPLUSUTMI 2 -#define USB_DW_GHWCFG2_FSPHYTYPE_FS 1 -#define USB_DW_GHWCFG2_FSPHYTYPE_NO_FS 0 -#define USB_DW_GHWCFG2_HSPHYTYPE_MASK (0x3 << 6) -#define USB_DW_GHWCFG2_HSPHYTYPE_SHIFT 6 -#define USB_DW_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI 3 -#define USB_DW_GHWCFG2_HSPHYTYPE_ULPI 2 -#define USB_DW_GHWCFG2_HSPHYTYPE_UTMIPLUS 1 -#define USB_DW_GHWCFG2_HSPHYTYPE_NO_HS 0 - -/* GHWCFG3 register, offset: 0x004C */ -#define USB_DW_GHWCFG3_DFIFODEPTH_MASK (0xFFFFU << 16) -#define USB_DW_GHWCFG3_DFIFODEPTH_SHIFT 16 - -/* GHWCFG4 register, offset: 0x0050 */ -#define USB_DW_GHWCFG4_INEPS_MASK (0xF << 26) -#define USB_DW_GHWCFG4_INEPS_SHIFT 26 -#define USB_DW_GHWCFG4_DEDFIFOMODE BIT(25) - -/* Device configuration registers, offset: 0x0800 */ -#define USB_DW_DCFG_DEV_ADDR_MASK (0x7F << 4) -#define USB_DW_DCFG_DEV_ADDR_OFFSET 4 -#define USB_DW_DCFG_DEV_SPD_USB2_HS 0 -#define USB_DW_DCFG_DEV_SPD_USB2_FS 1 -#define USB_DW_DCFG_DEV_SPD_LS 2 -#define USB_DW_DCFG_DEV_SPD_FS 3 - -/* Device control register, offset 0x0804 */ -#define USB_DW_DCTL_SFT_DISCON BIT(1) - -/* Device status register, offset 0x0808 */ -#define USB_DW_DSTS_ENUM_SPD_MASK (0x3 << 1) -#define USB_DW_DSTS_ENUM_SPD_OFFSET 1 -#define USB_DW_DSTS_ENUM_LS 2 -#define USB_DW_DSTS_ENUM_FS 3 - -/* Device all endpoints interrupt register, offset 0x0818 */ -#define USB_DW_DAINT_OUT_EP_INT(ep) (0x10000 << (ep)) -#define USB_DW_DAINT_IN_EP_INT(ep) (1 << (ep)) - -/* - * Device IN/OUT endpoint control register - * IN endpoint offsets 0x0900 + (0x20 * n), n = 0 .. x, - * offset 0x0900 and 0x0B00 are hardcoded to control type. - * - * REVISE: Better own definitions for DIEPTCTL0, DOEPTCTL0... - */ -#define USB_DW_DEPCTL_EP_ENA BIT(31) -#define USB_DW_DEPCTL_EP_DIS BIT(30) -#define USB_DW_DEPCTL_SETDOPID BIT(28) -#define USB_DW_DEPCTL_SNAK BIT(27) -#define USB_DW_DEPCTL_CNAK BIT(26) -#define USB_DW_DEPCTL_STALL BIT(21) -#define USB_DW_DEPCTL_TXFNUM_OFFSET 22 -#define USB_DW_DEPCTL_TXFNUM_MASK (0xF << 22) -#define USB_DW_DEPCTL_EP_TYPE_MASK (0x3 << 18) -#define USB_DW_DEPCTL_EP_TYPE_OFFSET 18 -#define USB_DW_DEPCTL_EP_TYPE_INTERRUPT 3 -#define USB_DW_DEPCTL_EP_TYPE_BULK 2 -#define USB_DW_DEPCTL_EP_TYPE_ISO 1 -#define USB_DW_DEPCTL_EP_TYPE_CONTROL 0 -#define USB_DW_DEPCTL_USB_ACT_EP BIT(15) -#define USB_DW_DEPCTL0_MSP_MASK 0x3 -#define USB_DW_DEPCTL0_MSP_8 3 -#define USB_DW_DEPCTL0_MSP_16 2 -#define USB_DW_DEPCTL0_MSP_32 1 -#define USB_DW_DEPCTL0_MSP_64 0 -#define USB_DW_DEPCTLn_MSP_MASK 0x3FF -#define USB_DW_DEPCTL_MSP_OFFSET 0 - -/* - * Device IN endpoint interrupt register - * offsets 0x0908 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DIEPINT_TX_FEMP BIT(7) -#define USB_DW_DIEPINT_XFER_COMPL BIT(0) - -/* - * Device OUT endpoint interrupt register - * offsets 0x0B08 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DOEPINT_SET_UP BIT(3) -#define USB_DW_DOEPINT_XFER_COMPL BIT(0) - -/* - * Device IN/OUT endpoint transfer size register - * IN at offsets 0x0910 + (0x20 * n), n = 0 .. x, - * OUT at offsets 0x0B10 + (0x20 * n), n = 0 .. x - * - * REVISE: Better own definitions for DIEPTSIZ0, DOEPTSIZ0... - */ -#define USB_DW_DEPTSIZ_PKT_CNT_OFFSET 19 -#define USB_DW_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19) -#define USB_DW_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19) -#define USB_DW_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19) -#define USB_DW_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19) -#define USB_DW_DOEPTSIZ_SUP_CNT_OFFSET 29 -#define USB_DW_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29) -#define USB_DW_DEPTSIZ_XFER_SIZE_OFFSET 0 -#define USB_DW_DEPTSIZ0_XFER_SIZE_MASK 0x7F -#define USB_DW_DEPTSIZn_XFER_SIZE_MASK 0x7FFFF - -/* - * Device IN endpoint transmit FIFO status register, - * offsets 0x0918 + (0x20 * n), n = 0 .. x - */ -#define USB_DW_DTXFSTS_TXF_SPC_AVAIL_MASK 0xFFFF - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_DRIVERS_USB_DEVICE_USB_DW_REGISTERS_H_ */ diff --git a/drivers/usb/udc/CMakeLists.txt b/drivers/usb/udc/CMakeLists.txt index f4f729cb181..ebca5f64277 100644 --- a/drivers/usb/udc/CMakeLists.txt +++ b/drivers/usb/udc/CMakeLists.txt @@ -4,6 +4,9 @@ zephyr_library() zephyr_library_sources(udc_common.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/usb/common/) + +zephyr_library_sources_ifdef(CONFIG_UDC_DWC2 udc_dwc2.c) zephyr_library_sources_ifdef(CONFIG_UDC_NRF udc_nrf.c) zephyr_library_sources_ifdef(CONFIG_UDC_KINETIS udc_kinetis.c) zephyr_library_sources_ifdef(CONFIG_UDC_SKELETON udc_skeleton.c) diff --git a/drivers/usb/udc/Kconfig b/drivers/usb/udc/Kconfig index ef1e01d82d2..5b19a3385ad 100644 --- a/drivers/usb/udc/Kconfig +++ b/drivers/usb/udc/Kconfig @@ -47,6 +47,7 @@ module = UDC_DRIVER module-str = usb drv source "subsys/logging/Kconfig.template.log_config" +source "drivers/usb/udc/Kconfig.dwc2" source "drivers/usb/udc/Kconfig.nrf" source "drivers/usb/udc/Kconfig.kinetis" source "drivers/usb/udc/Kconfig.skeleton" diff --git a/drivers/usb/udc/Kconfig.dwc2 b/drivers/usb/udc/Kconfig.dwc2 new file mode 100644 index 00000000000..e7f7e782325 --- /dev/null +++ b/drivers/usb/udc/Kconfig.dwc2 @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UDC_DWC2 + bool "DWC2 USB device controller driver" + default y + depends on DT_HAS_SNPS_DWC2_ENABLED + help + DWC2 USB device controller driver. + +config UDC_DWC2_STACK_SIZE + int "UDC DWC2 driver internal thread stack size" + depends on UDC_DWC2 + default 512 + help + DWC2 driver internal thread stack size. + +config UDC_DWC2_THREAD_PRIORITY + int "UDC DWC2 driver thread priority" + depends on UDC_DWC2 + default 8 + help + DWC2 driver thread priority. + +config UDC_DWC2_MAX_QMESSAGES + int "UDC DWC2 maximum number of ISR event messages" + range 4 64 + default 8 + help + DWC2 maximum number of ISR event messages. diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c new file mode 100644 index 00000000000..c38e03157b6 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2.c @@ -0,0 +1,1775 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "udc_common.h" +#include "udc_dwc2.h" +#include "udc_dwc2_vendor_quirks.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(udc_dwc2, CONFIG_UDC_DRIVER_LOG_LEVEL); + +enum dwc2_drv_event_type { + /* Trigger next transfer, must not be used for control OUT */ + DWC2_DRV_EVT_XFER, + /* Setup packet received */ + DWC2_DRV_EVT_SETUP, + /* OUT transaction for specific endpoint is finished */ + DWC2_DRV_EVT_DOUT, + /* IN transaction for specific endpoint is finished */ + DWC2_DRV_EVT_DIN, +}; + +struct dwc2_drv_event { + const struct device *dev; + enum dwc2_drv_event_type type; + uint32_t bcnt; + uint8_t ep; +}; + +K_MSGQ_DEFINE(drv_msgq, sizeof(struct dwc2_drv_event), + CONFIG_UDC_DWC2_MAX_QMESSAGES, sizeof(void *)); + + +/* Minimum RX FIFO size in 32-bit words considering the largest used OUT packet + * of 512 bytes. The value must be adjusted according to the number of OUT + * endpoints. + */ +#define UDC_DWC2_GRXFSIZ_DEFAULT (15U + 512U/4U) + +/* TX FIFO0 depth in 32-bit words (used by control IN endpoint) */ +#define UDC_DWC2_FIFO0_DEPTH 16U + +/* Number of endpoints supported by the driver. + * This must be equal to or greater than the number supported by the hardware. + * (FIXME) + */ +#define UDC_DWC2_DRV_EP_NUM 8 + +/* Get Data FIFO access register */ +#define UDC_DWC2_EP_FIFO(base, idx) ((mem_addr_t)base + 0x1000 * (idx + 1)) + +/* Driver private data per instance */ +struct udc_dwc2_data { + struct k_thread thread_data; + uint32_t ghwcfg1; + uint32_t enumspd; + uint32_t txf_set; + uint32_t grxfsiz; + uint32_t dfifodepth; + uint32_t max_xfersize; + uint32_t max_pktcnt; + uint32_t tx_len[16]; + unsigned int dynfifosizing : 1; + /* Number of endpoints in addition to control endpoint */ + uint8_t numdeveps; + /* Number of IN endpoints including control endpoint */ + uint8_t ineps; + /* Number of OUT endpoints including control endpoint */ + uint8_t outeps; + uint8_t setup[8]; +}; + +#if defined(CONFIG_PINCTRL) +#include + +static int dwc2_init_pinctrl(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + const struct pinctrl_dev_config *const pcfg = config->pcfg; + int ret = 0; + + if (pcfg == NULL) { + LOG_INF("Skip pinctrl configuration"); + return 0; + } + + ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT); + if (ret) { + LOG_ERR("Failed to apply default pinctrl state (%d)", ret); + } + + LOG_DBG("Apply pinctrl"); + + return ret; +} +#else +static int dwc2_init_pinctrl(const struct device *dev) +{ + ARG_UNUSED(dev); + + return 0; +} +#endif + +static inline struct usb_dwc2_reg *dwc2_get_base(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + + return config->base; +} + +/* Get DOEPCTLn or DIEPCTLn register address */ +static mem_addr_t dwc2_get_dxepctl_reg(const struct device *dev, const uint8_t ep) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint8_t ep_idx = USB_EP_GET_IDX(ep); + + if (USB_EP_DIR_IS_OUT(ep)) { + return (mem_addr_t)&base->out_ep[ep_idx].doepctl; + } else { + return (mem_addr_t)&base->in_ep[ep_idx].diepctl; + } +} + +/* Get available FIFO space in bytes */ +static uint32_t dwc2_ftx_avail(const struct device *dev, const uint32_t idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t reg = (mem_addr_t)&base->in_ep[idx].dtxfsts; + uint32_t dtxfsts; + + dtxfsts = sys_read32(reg); + + return usb_dwc2_get_dtxfsts_ineptxfspcavail(dtxfsts) * 4; +} + +static uint32_t dwc2_get_iept_pktctn(const struct device *dev, const uint32_t idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + if (idx == 0) { + return usb_dwc2_get_dieptsiz0_pktcnt(UINT32_MAX); + } else { + return priv->max_pktcnt; + } +} + +static uint32_t dwc2_get_iept_xfersize(const struct device *dev, const uint32_t idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + if (idx == 0) { + return usb_dwc2_get_dieptsiz0_xfersize(UINT32_MAX); + } else { + return priv->max_xfersize; + } +} + +static void dwc2_flush_rx_fifo(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + + sys_write32(USB_DWC2_GRSTCTL_RXFFLSH, grstctl_reg); + while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_RXFFLSH) { + } +} + +static void dwc2_flush_tx_fifo(const struct device *dev, const uint8_t idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + /* TODO: use dwc2_get_dxepctl_reg() */ + mem_addr_t diepctl_reg = (mem_addr_t)&base->in_ep[idx].diepctl; + uint32_t grstctl; + uint32_t fnum; + + fnum = usb_dwc2_get_depctl_txfnum(sys_read32(diepctl_reg)); + grstctl = usb_dwc2_set_grstctl_txfnum(fnum) | USB_DWC2_GRSTCTL_TXFFLSH; + + sys_write32(grstctl, grstctl_reg); + while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_TXFFLSH) { + } +} + +/* Return TX FIFOi depth in 32-bit words (i = f_idx + 1) */ +static uint32_t dwc2_get_txfdep(const struct device *dev, const uint32_t f_idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = sys_read32((mem_addr_t)&base->dieptxf[f_idx]); + + return usb_dwc2_get_dieptxf_inepntxfdep(dieptxf); +} + +/* Return TX FIFOi address (i = f_idx + 1) */ +static uint32_t dwc2_get_txfaddr(const struct device *dev, const uint32_t f_idx) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = sys_read32((mem_addr_t)&base->dieptxf[f_idx]); + + return usb_dwc2_get_dieptxf_inepntxfstaddr(dieptxf); +} + +/* Set TX FIFOi address and depth (i = f_idx + 1) */ +static void dwc2_set_txf(const struct device *dev, const uint32_t f_idx, + const uint32_t dep, const uint32_t addr) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint32_t dieptxf; + + dieptxf = usb_dwc2_set_dieptxf_inepntxfdep(dep) | + usb_dwc2_set_dieptxf_inepntxfstaddr(addr); + + sys_write32(dieptxf, (mem_addr_t)&base->dieptxf[f_idx]); +} + +/* Enable/disable endpoint interrupt */ +static void dwc2_set_epint(const struct device *dev, + struct udc_ep_config *const cfg, const bool enabled) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t reg = (mem_addr_t)&base->daintmsk; + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + uint32_t epmsk; + + if (USB_EP_DIR_IS_IN(cfg->addr)) { + epmsk = USB_DWC2_DAINT_INEPINT(ep_idx); + } else { + epmsk = USB_DWC2_DAINT_OUTEPINT(ep_idx); + } + + if (enabled) { + sys_set_bits(reg, epmsk); + } else { + sys_clear_bits(reg, epmsk); + } +} + +/* Can be called from ISR context */ +static int dwc2_tx_fifo_write(const struct device *dev, + struct udc_ep_config *const cfg, struct net_buf *const buf) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + mem_addr_t dieptsiz_reg = (mem_addr_t)&base->in_ep[ep_idx].dieptsiz; + /* TODO: use dwc2_get_dxepctl_reg() */ + mem_addr_t diepctl_reg = (mem_addr_t)&base->in_ep[ep_idx].diepctl; + + uint32_t max_xfersize, max_pktcnt, pktcnt, spcavail; + const size_t d = sizeof(uint32_t); + unsigned int key; + uint32_t len; + + spcavail = dwc2_ftx_avail(dev, ep_idx); + /* Round down to multiple of endpoint MPS */ + spcavail -= spcavail % cfg->mps; + /* + * Here, the available space should be equal to the FIFO space + * assigned/configured for that endpoint because we do not schedule another + * transfer until the previous one has not finished. For simplicity, + * we only check that the available space is not less than the endpoint + * MPS. + */ + if (spcavail < cfg->mps) { + LOG_ERR("ep 0x%02x FIFO space is too low, %u (%u)", + cfg->addr, spcavail, dwc2_ftx_avail(dev, ep_idx)); + return -EAGAIN; + } + + len = MIN(buf->len, spcavail); + + if (len != 0U) { + max_pktcnt = dwc2_get_iept_pktctn(dev, ep_idx); + max_xfersize = dwc2_get_iept_xfersize(dev, ep_idx); + + if (len > max_xfersize) { + /* + * Avoid short packets if the transfer size cannot be + * handled in one set. + */ + len = ROUND_DOWN(max_xfersize, cfg->mps); + } + + /* + * Determine the number of packets for the current transfer; + * if the pktcnt is too large, truncate the actual transfer length. + */ + pktcnt = DIV_ROUND_UP(len, cfg->mps); + if (pktcnt > max_pktcnt) { + pktcnt = max_pktcnt; + len = pktcnt * cfg->mps; + } + } else { + /* ZLP */ + pktcnt = 1U; + } + + LOG_DBG("Prepare ep 0x%02x xfer len %u pktcnt %u spcavail %u", + cfg->addr, len, pktcnt, spcavail); + priv->tx_len[ep_idx] = len; + + /* Lock and write to endpoint FIFO */ + key = irq_lock(); + + /* Set number of packets and transfer size */ + sys_write32((pktcnt << USB_DWC2_DEPTSIZN_PKTCNT_POS) | len, dieptsiz_reg); + + /* Clear NAK and set endpoint enable */ + sys_set_bits(diepctl_reg, USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_CNAK); + + /* FIFO access is always in 32-bit words */ + + for (uint32_t i = 0UL; i < len; i += d) { + uint32_t val = buf->data[i]; + + if (i + 1 < len) { + val |= ((uint32_t)buf->data[i + 1UL]) << 8; + } + if (i + 2 < len) { + val |= ((uint32_t)buf->data[i + 2UL]) << 16; + } + if (i + 3 < len) { + val |= ((uint32_t)buf->data[i + 3UL]) << 24; + } + + sys_write32(val, UDC_DWC2_EP_FIFO(base, ep_idx)); + } + + irq_unlock(key); + + return 0; +} + +static inline int dwc2_read_fifo(const struct device *dev, const uint8_t ep, + struct net_buf *const buf, const size_t size) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + size_t len = MIN(size, net_buf_tailroom(buf)); + const size_t d = sizeof(uint32_t); + + /* FIFO access is always in 32-bit words */ + + for (uint32_t n = 0; n < (len / d); n++) { + net_buf_add_le32(buf, sys_read32(UDC_DWC2_EP_FIFO(base, ep))); + } + + if (len % d) { + uint8_t r[4]; + + /* Get the remaining */ + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, ep)), r); + for (uint32_t i = 0U; i < (len % d); i++) { + net_buf_add_u8(buf, r[i]); + } + } + + if (unlikely(size > len)) { + for (uint32_t n = 0; n < DIV_ROUND_UP(size - len, d); n++) { + (void)sys_read32(UDC_DWC2_EP_FIFO(base, ep)); + } + } + + return 0; +} + +/* Can be called from ISR and we call it only when there is a buffer in the queue */ +static void dwc2_prep_rx(const struct device *dev, + struct udc_ep_config *const cfg, const bool ncnak) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t doeptsiz_reg = (mem_addr_t)&base->out_ep[ep_idx].doeptsiz; + mem_addr_t doepctl_reg = dwc2_get_dxepctl_reg(dev, ep_idx); + uint32_t doeptsiz; + + doeptsiz = (1 << USB_DWC2_DOEPTSIZ0_PKTCNT_POS) | cfg->mps; + if (cfg->addr == USB_CONTROL_EP_OUT) { + doeptsiz |= (1 << USB_DWC2_DOEPTSIZ0_SUPCNT_POS); + } + + sys_write32(doeptsiz, doeptsiz_reg); + + if (ncnak) { + sys_set_bits(doepctl_reg, USB_DWC2_DEPCTL_EPENA); + } else { + sys_set_bits(doepctl_reg, USB_DWC2_DEPCTL_EPENA | USB_DWC2_DEPCTL_CNAK); + } + + LOG_INF("Prepare RX 0x%02x doeptsiz 0x%x", cfg->addr, doeptsiz); +} + +static void dwc2_handle_xfer_next(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + + buf = udc_buf_peek(dev, cfg->addr); + if (buf == NULL) { + return; + } + + if (USB_EP_DIR_IS_OUT(cfg->addr)) { + dwc2_prep_rx(dev, cfg, 0); + } else { + if (dwc2_tx_fifo_write(dev, cfg, buf)) { + LOG_ERR("Failed to start write to TX FIFO, ep 0x%02x", + cfg->addr); + } + } + + udc_ep_set_busy(dev, cfg->addr, true); +} + +static int dwc2_ctrl_feed_dout(const struct device *dev, const size_t length) +{ + struct net_buf *buf; + + buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, length); + if (buf == NULL) { + return -ENOMEM; + } + + udc_buf_put(udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT), buf); + dwc2_prep_rx(dev, udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT), 0); + LOG_DBG("feed buf %p", buf); + + return 0; +} + +static int dwc2_handle_evt_setup(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct net_buf *buf; + int err; + + buf = udc_buf_get(dev, USB_CONTROL_EP_OUT); + if (buf == NULL) { + LOG_ERR("No buffer queued for control ep"); + return -ENODATA; + } + + net_buf_add_mem(buf, priv->setup, sizeof(priv->setup)); + udc_ep_buf_set_setup(buf); + LOG_HEXDUMP_DBG(buf->data, buf->len, "setup"); + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + /* We always allocate and feed buffer large enough for a setup packet. */ + + if (udc_ctrl_stage_is_data_out(dev)) { + /* Allocate and feed buffer for data OUT stage */ + LOG_DBG("s:%p|feed for -out-", buf); + + err = dwc2_ctrl_feed_dout(dev, udc_data_stage_length(buf)); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + } else if (udc_ctrl_stage_is_data_in(dev)) { + LOG_DBG("s:%p|feed for -in-status", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + err = udc_ctrl_submit_s_in_status(dev); + } else { + LOG_DBG("s:%p|feed >setup", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + err = udc_ctrl_submit_s_status(dev); + } + + return err; +} + +static inline int dwc2_handle_evt_dout(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + int err = 0; + + buf = udc_buf_get(dev, cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer queued for control ep"); + return -ENODATA; + } + + udc_ep_set_busy(dev, cfg->addr, false); + + if (cfg->addr == USB_CONTROL_EP_OUT) { + if (udc_ctrl_stage_is_status_out(dev)) { + /* s-in-status finished */ + LOG_DBG("dout:%p| status, feed >s", buf); + + /* Feed a buffer for the next setup packet */ + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + + /* Status stage finished, notify upper layer */ + udc_ctrl_submit_status(dev, buf); + } else { + /* + * For all other cases we feed with a buffer + * large enough for setup packet. + */ + LOG_DBG("dout:%p| data, feed >s", buf); + + err = dwc2_ctrl_feed_dout(dev, 8); + if (err == -ENOMEM) { + err = udc_submit_ep_event(dev, buf, err); + } + } + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + if (udc_ctrl_stage_is_status_in(dev)) { + err = udc_ctrl_submit_s_out_status(dev, buf); + } + } else { + err = udc_submit_ep_event(dev, buf, 0); + } + + return err; +} + +static int dwc2_handle_evt_din(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct net_buf *buf; + + buf = udc_buf_peek(dev, cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer for ep 0x%02x", cfg->addr); + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + return -ENOBUFS; + } + + if (buf->len) { + /* Looks like we failed to continue in ISR, retry */ + return dwc2_tx_fifo_write(dev, cfg, buf); + } + + if (cfg->addr == USB_CONTROL_EP_IN && udc_ep_buf_has_zlp(buf)) { + udc_ep_buf_clear_zlp(buf); + return dwc2_tx_fifo_write(dev, cfg, buf); + } + + buf = udc_buf_get(dev, cfg->addr); + udc_ep_set_busy(dev, cfg->addr, false); + + if (cfg->addr == USB_CONTROL_EP_IN) { + if (udc_ctrl_stage_is_status_in(dev) || + udc_ctrl_stage_is_no_data(dev)) { + /* Status stage finished, notify upper layer */ + udc_ctrl_submit_status(dev, buf); + } + + /* Update to next stage of control transfer */ + udc_ctrl_update_stage(dev, buf); + + if (udc_ctrl_stage_is_status_out(dev)) { + /* + * IN transfer finished, release buffer, + * control OUT buffer should be already fed. + */ + net_buf_unref(buf); + } + + return 0; + } + + return udc_submit_ep_event(dev, buf, 0); +} + +static ALWAYS_INLINE void dwc2_thread_handler(void *const arg) +{ + const struct device *dev = (const struct device *)arg; + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + + /* This is the bottom-half of the ISR handler and the place where + * a new transfer can be fed. + */ + k_msgq_get(&drv_msgq, &evt, K_FOREVER); + ep_cfg = udc_get_ep_cfg(dev, evt.ep); + + switch (evt.type) { + case DWC2_DRV_EVT_XFER: + LOG_DBG("New transfer in the queue"); + break; + case DWC2_DRV_EVT_SETUP: + LOG_DBG("SETUP event"); + dwc2_handle_evt_setup(dev); + break; + case DWC2_DRV_EVT_DOUT: + LOG_DBG("DOUT event ep 0x%02x", ep_cfg->addr); + dwc2_handle_evt_dout(dev, ep_cfg); + break; + case DWC2_DRV_EVT_DIN: + LOG_DBG("DIN event"); + dwc2_handle_evt_din(dev, ep_cfg); + break; + } + + if (ep_cfg->addr != USB_CONTROL_EP_OUT && !udc_ep_is_busy(dev, ep_cfg->addr)) { + dwc2_handle_xfer_next(dev, ep_cfg); + } else { + LOG_DBG("ep 0x%02x busy", ep_cfg->addr); + } +} + +static void dwc2_on_bus_reset(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + + /* Set the NAK bit for all OUT endpoints */ + for (uint8_t i = 0U; i < priv->numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(priv->ghwcfg1, i); + mem_addr_t doepctl_reg; + + LOG_DBG("ep 0x%02x EPDIR %u", i, epdir); + if (epdir == USB_DWC2_GHWCFG1_EPDIR_OUT || + epdir == USB_DWC2_GHWCFG1_EPDIR_BDIR) { + doepctl_reg = dwc2_get_dxepctl_reg(dev, i); + sys_write32(USB_DWC2_DEPCTL_SNAK, doepctl_reg); + } + } + + sys_write32(0UL, (mem_addr_t)&base->doepmsk); + sys_set_bits((mem_addr_t)&base->gintmsk, USB_DWC2_GINTSTS_RXFLVL); + sys_set_bits((mem_addr_t)&base->diepmsk, USB_DWC2_DIEPINT_XFERCOMPL); + + /* Clear device address during reset. */ + sys_clear_bits((mem_addr_t)&base->dcfg, USB_DWC2_DCFG_DEVADDR_MASK); +} + +static void dwc2_handle_enumdone(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint32_t dsts; + + dsts = sys_read32((mem_addr_t)&base->dsts); + priv->enumspd = usb_dwc2_get_dsts_enumspd(dsts); +} + +static inline int dwc2_read_fifo_setup(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + + /* FIFO access is always in 32-bit words */ + + /* + * We store the setup packet temporarily in the driver's private data + * because there is always a race risk after the status stage OUT + * packet from the host and the new setup packet. This is fine in + * bottom-half processing because the events arrive in a queue and + * there will be a next net_buf for the setup packet. + */ + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, 0)), priv->setup); + sys_put_le32(sys_read32(UDC_DWC2_EP_FIFO(base, 0)), &priv->setup[4]); + + return 0; +} + +static inline void dwc2_handle_rxflvl(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + struct net_buf *buf; + uint32_t grxstsp; + uint32_t pktsts; + + grxstsp = sys_read32((mem_addr_t)&base->grxstsp); + evt.ep = usb_dwc2_get_grxstsp_epnum(grxstsp); + evt.bcnt = usb_dwc2_get_grxstsp_bcnt(grxstsp); + pktsts = usb_dwc2_get_grxstsp_pktsts(grxstsp); + + LOG_DBG("ep 0x%02x: pktsts %u, bcnt %u", evt.ep, pktsts, evt.bcnt); + + switch (pktsts) { + case USB_DWC2_GRXSTSR_PKTSTS_SETUP: + evt.type = DWC2_DRV_EVT_SETUP; + + __ASSERT(evt.bcnt == 8, "Incorrect setup packet length"); + dwc2_read_fifo_setup(dev); + + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + break; + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA: + evt.type = DWC2_DRV_EVT_DOUT; + ep_cfg = udc_get_ep_cfg(dev, evt.ep); + + buf = udc_buf_peek(dev, ep_cfg->addr); + if (buf == NULL) { + LOG_ERR("No buffer for ep 0x%02x", ep_cfg->addr); + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + break; + } + + dwc2_read_fifo(dev, USB_CONTROL_EP_OUT, buf, evt.bcnt); + + if (net_buf_tailroom(buf) && evt.bcnt == ep_cfg->mps) { + dwc2_prep_rx(dev, ep_cfg, 0); + } else { + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } + + break; + case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE: + case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE: + LOG_DBG("RX pktsts DONE"); + break; + default: + break; + } +} + +static inline void dwc2_handle_xfercompl(const struct device *dev, + const uint8_t ep_idx) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct udc_ep_config *ep_cfg; + struct dwc2_drv_event evt; + struct net_buf *buf; + + ep_cfg = udc_get_ep_cfg(dev, ep_idx | USB_EP_DIR_IN); + buf = udc_buf_peek(dev, ep_cfg->addr); + if (buf == NULL) { + udc_submit_event(dev, UDC_EVT_ERROR, -ENOBUFS); + return; + } + + net_buf_pull(buf, priv->tx_len[ep_idx]); + if (buf->len && dwc2_tx_fifo_write(dev, ep_cfg, buf) == 0) { + return; + } + + evt.dev = dev; + evt.ep = ep_cfg->addr; + evt.type = DWC2_DRV_EVT_DIN; + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); +} + +static inline void dwc2_handle_iepint(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + const uint8_t n_max = 16; + uint32_t diepmsk; + uint32_t daint; + + diepmsk = sys_read32((mem_addr_t)&base->diepmsk); + daint = sys_read32((mem_addr_t)&base->daint); + + for (uint8_t n = 0U; n < n_max; n++) { + mem_addr_t diepint_reg = (mem_addr_t)&base->in_ep[n].diepint; + uint32_t diepint; + uint32_t status; + + if (daint & USB_DWC2_DAINT_INEPINT(n)) { + /* Read and clear interrupt status */ + diepint = sys_read32(diepint_reg); + status = diepint & diepmsk; + sys_write32(status, diepint_reg); + + LOG_DBG("ep 0x%02x interrupt status: 0x%x", + n | USB_EP_DIR_IN, status); + + if (status & USB_DWC2_DIEPINT_XFERCOMPL) { + dwc2_handle_xfercompl(dev, n); + } + + } + } + + /* Clear IEPINT interrupt */ + sys_write32(USB_DWC2_GINTSTS_IEPINT, (mem_addr_t)&base->gintsts); +} + +static inline void dwc2_handle_oepint(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + const uint8_t n_max = 16; + uint32_t doepmsk; + uint32_t daint; + + doepmsk = sys_read32((mem_addr_t)&base->doepmsk); + daint = sys_read32((mem_addr_t)&base->daint); + + /* No OUT interrupt expected in FIFO mode, just clear interrupt */ + for (uint8_t n = 0U; n < n_max; n++) { + mem_addr_t doepint_reg = (mem_addr_t)&base->out_ep[n].doepint; + uint32_t doepint; + uint32_t status; + + if (daint & USB_DWC2_DAINT_OUTEPINT(n)) { + /* Read and clear interrupt status */ + doepint = sys_read32(doepint_reg); + status = doepint & doepmsk; + sys_write32(status, doepint_reg); + + LOG_DBG("ep 0x%02x interrupt status: 0x%x", n, status); + } + } + + /* Clear OEPINT interrupt */ + sys_write32(USB_DWC2_GINTSTS_OEPINT, (mem_addr_t)&base->gintsts); +} + +static void udc_dwc2_isr_handler(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct usb_dwc2_reg *const base = config->base; + mem_addr_t gintsts_reg = (mem_addr_t)&base->gintsts; + uint32_t int_status; + uint32_t gintmsk; + + gintmsk = sys_read32((mem_addr_t)&base->gintmsk); + + /* Read and handle interrupt status register */ + while ((int_status = sys_read32(gintsts_reg) & gintmsk)) { + + LOG_DBG("GINTSTS 0x%x", int_status); + + if (int_status & USB_DWC2_GINTSTS_USBRST) { + /* Clear and handle USB Reset interrupt. */ + sys_write32(USB_DWC2_GINTSTS_USBRST, gintsts_reg); + dwc2_on_bus_reset(dev); + LOG_DBG("USB Reset interrupt"); + udc_submit_event(dev, UDC_EVT_RESET, 0); + } + + if (int_status & USB_DWC2_GINTSTS_ENUMDONE) { + /* Clear and handle Enumeration Done interrupt. */ + sys_write32(USB_DWC2_GINTSTS_ENUMDONE, gintsts_reg); + dwc2_handle_enumdone(dev); + } + + if (int_status & USB_DWC2_GINTSTS_USBSUSP) { + /* Clear USB Suspend interrupt. */ + sys_write32(USB_DWC2_GINTSTS_USBSUSP, gintsts_reg); + udc_set_suspended(dev, true); + udc_submit_event(dev, UDC_EVT_SUSPEND, 0); + } + + if (int_status & USB_DWC2_GINTSTS_WKUPINT) { + /* Clear Resume/Remote Wakeup Detected interrupt. */ + sys_write32(USB_DWC2_GINTSTS_WKUPINT, gintsts_reg); + udc_set_suspended(dev, false); + udc_submit_event(dev, UDC_EVT_RESUME, 0); + } + + if (int_status & USB_DWC2_GINTSTS_RXFLVL) { + /* Handle RxFIFO Non-Empty interrupt */ + dwc2_handle_rxflvl(dev); + } + + if (int_status & USB_DWC2_GINTSTS_IEPINT) { + /* Handle IN Endpoints interrupt */ + dwc2_handle_iepint(dev); + } + + if (int_status & USB_DWC2_GINTSTS_OEPINT) { + /* Handle OUT Endpoints interrupt */ + dwc2_handle_oepint(dev); + } + } + + if (config->quirks != NULL && config->quirks->irq_clear != NULL) { + config->quirks->irq_clear(dev); + } +} + +static int udc_dwc2_ep_enqueue(const struct device *dev, + struct udc_ep_config *const cfg, + struct net_buf *const buf) +{ + struct dwc2_drv_event evt = { + .ep = cfg->addr, + .type = DWC2_DRV_EVT_XFER, + }; + + LOG_DBG("%p enqueue %x %p", dev, cfg->addr, buf); + udc_buf_put(cfg, buf); + + if (!cfg->stat.halted) { + k_msgq_put(&drv_msgq, &evt, K_NO_WAIT); + } + + return 0; +} + +static int udc_dwc2_ep_dequeue(const struct device *dev, + struct udc_ep_config *const cfg) +{ + unsigned int lock_key; + struct net_buf *buf; + + lock_key = irq_lock(); + + if (USB_EP_DIR_IS_IN(cfg->addr)) { + dwc2_flush_tx_fifo(dev, USB_EP_GET_IDX(cfg->addr)); + } + + buf = udc_buf_get_all(dev, cfg->addr); + if (buf) { + udc_submit_ep_event(dev, buf, -ECONNABORTED); + } + + irq_unlock(lock_key); + LOG_DBG("dequeue ep 0x%02x", cfg->addr); + + return 0; +} + +static void dwc2_unset_unused_fifo(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct udc_ep_config *tmp; + + for (uint8_t i = priv->ineps; i > 0; i--) { + tmp = udc_get_ep_cfg(dev, i | USB_EP_DIR_IN); + + if (tmp->stat.enabled && (priv->txf_set & BIT(i))) { + return; + } + + if (!tmp->stat.enabled && (priv->txf_set & BIT(i))) { + priv->txf_set &= ~BIT(i); + } + } +} + +/* + * In dedicated FIFO mode there are i (i = 1 ... ineps - 1) FIFO size registers, + * e.g. DIEPTXF1, DIEPTXF2, ... DIEPTXF4. When dynfifosizing is enabled, + * the size register is mutable. The offset of DIEPTXF1 registers is 0. + */ +static int dwc2_set_dedicated_fifo(const struct device *dev, + struct udc_ep_config *const cfg, + uint32_t *const diepctl) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + uint32_t txfaddr; + uint32_t txfdep; + uint32_t tmp; + + /* Keep everything but FIFO number */ + tmp = *diepctl & ~USB_DWC2_DEPCTL_TXFNUM_MASK; + + if (priv->dynfifosizing) { + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + dwc2_unset_unused_fifo(dev); + } + + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + LOG_WRN("Some of the FIFOs higher than %u are set, %lx", + ep_idx, priv->txf_set & ~BIT_MASK(ep_idx)); + return -EIO; + } + + if ((ep_idx - 1) != 0U) { + txfaddr = dwc2_get_txfdep(dev, ep_idx - 2) + + dwc2_get_txfaddr(dev, ep_idx - 2); + } else { + txfaddr = UDC_DWC2_FIFO0_DEPTH + priv->grxfsiz; + } + + /* Set FIFO depth (32-bit words) and address */ + txfdep = cfg->mps / 4U; + dwc2_set_txf(dev, ep_idx - 1, txfdep, txfaddr); + } else { + txfdep = dwc2_get_txfdep(dev, ep_idx - 1); + txfaddr = dwc2_get_txfaddr(dev, ep_idx - 1); + + if (cfg->mps < txfdep * 4U) { + return -ENOMEM; + } + + LOG_DBG("Reuse FIFO%u addr 0x%08x depth %u", ep_idx, txfaddr, txfdep); + } + + /* Assign FIFO to the IN endpoint */ + *diepctl = tmp | usb_dwc2_set_depctl_txfnum(ep_idx); + priv->txf_set |= BIT(ep_idx); + dwc2_flush_tx_fifo(dev, ep_idx); + + LOG_INF("Set FIFO%u (ep 0x%02x) addr 0x%04x depth %u size %u", + ep_idx, cfg->addr, txfaddr, txfdep, dwc2_ftx_avail(dev, ep_idx)); + + return 0; +} + +static int dwc2_ep_control_enable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + mem_addr_t dxepctl0_reg; + uint32_t dxepctl0; + + dxepctl0_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); + dxepctl0 = sys_read32(dxepctl0_reg); + + dxepctl0 &= ~USB_DWC2_DEPCTL0_MPS_MASK; + switch (cfg->mps) { + case 8: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_8 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 16: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_16 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 32: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_32 << USB_DWC2_DEPCTL_MPS_POS; + break; + case 64: + dxepctl0 |= USB_DWC2_DEPCTL0_MPS_64 << USB_DWC2_DEPCTL_MPS_POS; + break; + default: + return -EINVAL; + } + + dxepctl0 |= USB_DWC2_DEPCTL_USBACTEP; + + /* + * The following applies to the Control IN endpoint only. + * + * Set endpoint 0 TxFIFO depth when dynfifosizing is enabled. + * Note that only dedicated mode is supported at this time. + */ + if (cfg->addr == USB_CONTROL_EP_IN && priv->dynfifosizing) { + uint32_t gnptxfsiz; + + gnptxfsiz = usb_dwc2_set_gnptxfsiz_nptxfdep(UDC_DWC2_FIFO0_DEPTH) | + usb_dwc2_set_gnptxfsiz_nptxfstaddr(priv->grxfsiz); + + sys_write32(gnptxfsiz, (mem_addr_t)&base->gnptxfsiz); + } + + if (cfg->addr == USB_CONTROL_EP_OUT) { + int ret; + + dwc2_flush_rx_fifo(dev); + ret = dwc2_ctrl_feed_dout(dev, 8); + if (ret) { + return ret; + } + } else { + dwc2_flush_tx_fifo(dev, 0); + } + + sys_write32(dxepctl0, dxepctl0_reg); + dwc2_set_epint(dev, cfg, true); + + return 0; +} + +static int udc_dwc2_ep_enable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t dxepctl_reg; + uint32_t dxepctl; + + LOG_DBG("Enable ep 0x%02x", cfg->addr); + + if (ep_idx == 0U) { + return dwc2_ep_control_enable(dev, cfg); + } + + if (USB_EP_DIR_IS_OUT(cfg->addr)) { + /* TODO: use dwc2_get_dxepctl_reg() */ + dxepctl_reg = (mem_addr_t)&base->out_ep[ep_idx].doepctl; + } else { + if (priv->ineps > 0U && ep_idx > (priv->ineps - 1U)) { + LOG_ERR("No resources available for ep 0x%02x", cfg->addr); + return -EINVAL; + } + + dxepctl_reg = (mem_addr_t)&base->in_ep[ep_idx].diepctl; + } + + if (cfg->mps > usb_dwc2_get_depctl_mps(UINT16_MAX)) { + return -EINVAL; + } + + dxepctl = sys_read32(dxepctl_reg); + /* Set max packet size */ + dxepctl &= ~USB_DWC2_DEPCTL_MPS_MASK; + dxepctl |= cfg->mps << USB_DWC2_DEPCTL_MPS_POS; + + /* Set endpoint type */ + dxepctl &= ~USB_DWC2_DEPCTL_EPTYPE_MASK; + + switch (cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) { + case USB_EP_TYPE_BULK: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_BULK << + USB_DWC2_DEPCTL_EPTYPE_POS; + dxepctl |= USB_DWC2_DEPCTL_SETD0PID; + break; + case USB_EP_TYPE_INTERRUPT: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_INTERRUPT << + USB_DWC2_DEPCTL_EPTYPE_POS; + dxepctl |= USB_DWC2_DEPCTL_SETD0PID; + break; + case USB_EP_TYPE_ISO: + dxepctl |= USB_DWC2_DEPCTL_EPTYPE_ISO << + USB_DWC2_DEPCTL_EPTYPE_POS; + break; + default: + return -EINVAL; + } + + if (USB_EP_DIR_IS_IN(cfg->addr) && cfg->mps != 0U) { + int ret = dwc2_set_dedicated_fifo(dev, cfg, &dxepctl); + + if (ret) { + return ret; + } + } + + dxepctl |= USB_DWC2_DEPCTL_USBACTEP; + + /* Enable endpoint interrupts */ + dwc2_set_epint(dev, cfg, true); + sys_write32(dxepctl, dxepctl_reg); + + for (uint8_t i = 1U; i < priv->ineps; i++) { + LOG_DBG("DIEPTXF%u %08x DIEPCTL%u %08x", + i, sys_read32((mem_addr_t)base->dieptxf[i - 1U]), i, dxepctl); + } + + return 0; +} + +static int dwc2_unset_dedicated_fifo(const struct device *dev, + struct udc_ep_config *const cfg, + uint32_t *const diepctl) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + /* Clear FIFO number field */ + *diepctl &= ~USB_DWC2_DEPCTL_TXFNUM_MASK; + + if (priv->dynfifosizing) { + if (priv->txf_set & ~BIT_MASK(ep_idx)) { + LOG_WRN("Some of the FIFOs higher than %u are set, %lx", + ep_idx, priv->txf_set & ~BIT_MASK(ep_idx)); + return 0; + } + + dwc2_set_txf(dev, ep_idx - 1, 0, 0); + } + + priv->txf_set &= ~BIT(ep_idx); + + return 0; +} + +static int udc_dwc2_ep_disable(const struct device *dev, + struct udc_ep_config *const cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + mem_addr_t dxepctl_reg; + uint32_t dxepctl; + + dxepctl_reg = dwc2_get_dxepctl_reg(dev, cfg->addr); + dxepctl = sys_read32(dxepctl_reg); + + if (dxepctl & USB_DWC2_DEPCTL_USBACTEP) { + LOG_DBG("Disable ep 0x%02x DxEPCTL%u %x", + cfg->addr, ep_idx, dxepctl); + dxepctl |= USB_DWC2_DEPCTL_EPDIS | USB_DWC2_DEPCTL_SNAK; + } else { + LOG_WRN("ep 0x%02x is not active DxEPCTL%u %x", + cfg->addr, ep_idx, dxepctl); + } + + if (USB_EP_DIR_IS_IN(cfg->addr) && cfg->mps != 0U && ep_idx != 0U) { + dwc2_unset_dedicated_fifo(dev, cfg, &dxepctl); + } + + sys_write32(dxepctl, dxepctl_reg); + dwc2_set_epint(dev, cfg, false); + + return 0; +} + +static int udc_dwc2_ep_set_halt(const struct device *dev, + struct udc_ep_config *const cfg) +{ + uint8_t ep_idx = USB_EP_GET_IDX(cfg->addr); + + sys_set_bits(dwc2_get_dxepctl_reg(dev, cfg->addr), USB_DWC2_DEPCTL_STALL); + + LOG_DBG("Set halt ep 0x%02x", cfg->addr); + if (ep_idx != 0) { + cfg->stat.halted = true; + } + + return 0; +} + +static int udc_dwc2_ep_clear_halt(const struct device *dev, + struct udc_ep_config *const cfg) +{ + sys_clear_bits(dwc2_get_dxepctl_reg(dev, cfg->addr), USB_DWC2_DEPCTL_STALL); + + LOG_DBG("Clear halt ep 0x%02x", cfg->addr); + cfg->stat.halted = false; + + return 0; +} + +static int udc_dwc2_set_address(const struct device *dev, const uint8_t addr) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg; + + if (addr > (USB_DWC2_DCFG_DEVADDR_MASK >> USB_DWC2_DCFG_DEVADDR_POS)) { + return -EINVAL; + } + + sys_clear_bits(dcfg_reg, USB_DWC2_DCFG_DEVADDR_MASK); + sys_set_bits(dcfg_reg, usb_dwc2_set_dcfg_devaddr(addr)); + LOG_DBG("Set new address %u for %p", addr, dev); + + return 0; +} + +static int udc_dwc2_test_mode(const struct device *dev, + const uint8_t mode, const bool dryrun) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + uint32_t tstctl; + + if (mode == 0U || mode > USB_DWC2_DCTL_TSTCTL_TESTFE) { + return -EINVAL; + } + + tstctl = usb_dwc2_get_dctl_tstctl(sys_read32(dctl_reg)); + if (tstctl != USB_DWC2_DCTL_TSTCTL_DISABLED) { + return -EALREADY; + } + + if (dryrun) { + LOG_DBG("Test Mode %u supported", mode); + return 0; + } + + sys_set_bits(dctl_reg, usb_dwc2_set_dctl_tstctl(mode)); + LOG_DBG("Enable Test Mode %u", mode); + + return 0; +} + +static int udc_dwc2_host_wakeup(const struct device *dev) +{ + LOG_DBG("Remote wakeup from %p", dev); + + return -ENOTSUP; +} + +/* Return actual USB device speed */ +static enum udc_bus_speed udc_dwc2_device_speed(const struct device *dev) +{ + struct udc_dwc2_data *const priv = udc_get_private(dev); + + switch (priv->enumspd) { + case USB_DWC2_DSTS_ENUMSPD_HS3060: + return UDC_BUS_SPEED_HS; + case USB_DWC2_DSTS_ENUMSPD_LS6: + __ASSERT(false, "Low speed mode not supported"); + __fallthrough; + case USB_DWC2_DSTS_ENUMSPD_FS48: + __fallthrough; + case USB_DWC2_DSTS_ENUMSPD_FS3060: + __fallthrough; + default: + return UDC_BUS_SPEED_FS; + } +} + +static int udc_dwc2_enable(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + + /* Disable soft disconnect */ + sys_clear_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Enable device %p", base); + + return 0; +} + +static int udc_dwc2_disable(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t dctl_reg = (mem_addr_t)&base->dctl; + + /* Enable soft disconnect */ + sys_set_bits(dctl_reg, USB_DWC2_DCTL_SFTDISCON); + LOG_DBG("Disable device %p", dev); + + return 0; +} + +static int dwc2_core_soft_reset(const struct device *dev) +{ + struct usb_dwc2_reg *const base = dwc2_get_base(dev); + mem_addr_t grstctl_reg = (mem_addr_t)&base->grstctl; + const unsigned int csr_timeout_us = 10000UL; + uint32_t cnt = 0UL; + + /* Check AHB master idle state */ + while (!(sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_AHBIDLE)) { + k_busy_wait(1); + + if (++cnt > csr_timeout_us) { + LOG_ERR("Wait for AHB idle timeout, GRSTCTL 0x%08x", + sys_read32(grstctl_reg)); + return -EIO; + } + } + + /* Apply Core Soft Reset */ + sys_write32(USB_DWC2_GRSTCTL_CSFTRST, grstctl_reg); + + cnt = 0UL; + do { + if (++cnt > csr_timeout_us) { + LOG_ERR("Wait for CSR done timeout, GRSTCTL 0x%08x", + sys_read32(grstctl_reg)); + return -EIO; + } + + k_busy_wait(1); + } while (sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRST && + !(sys_read32(grstctl_reg) & USB_DWC2_GRSTCTL_CSFTRSTDONE)); + + sys_clear_bits(grstctl_reg, USB_DWC2_GRSTCTL_CSFTRST | USB_DWC2_GRSTCTL_CSFTRSTDONE); + + return 0; +} + +static int udc_dwc2_init(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct udc_dwc2_data *const priv = udc_get_private(dev); + struct usb_dwc2_reg *const base = config->base; + mem_addr_t gusbcfg_reg = (mem_addr_t)&base->gusbcfg; + mem_addr_t dcfg_reg = (mem_addr_t)&base->dcfg; + uint32_t gusbcfg; + uint32_t ghwcfg2; + uint32_t ghwcfg3; + uint32_t ghwcfg4; + int ret; + + if (config->quirks != NULL && config->quirks->clk_enable != NULL) { + LOG_DBG("Enable vendor clock"); + ret = config->quirks->clk_enable(dev); + if (ret) { + return ret; + } + } + + ret = dwc2_init_pinctrl(dev); + if (ret) { + return ret; + } + + ret = dwc2_core_soft_reset(dev); + if (ret) { + return ret; + } + + priv->ghwcfg1 = sys_read32((mem_addr_t)&base->ghwcfg1); + ghwcfg2 = sys_read32((mem_addr_t)&base->ghwcfg2); + ghwcfg3 = sys_read32((mem_addr_t)&base->ghwcfg3); + ghwcfg4 = sys_read32((mem_addr_t)&base->ghwcfg4); + + if (!(ghwcfg4 & USB_DWC2_GHWCFG4_DEDFIFOMODE)) { + LOG_ERR("Only dedicated TX FIFO mode is supported"); + return -ENOTSUP; + } + + /* + * Force device mode as we do no support role changes. + * Wait 25ms for the change to take effect. + */ + gusbcfg = USB_DWC2_GUSBCFG_FORCEDEVMODE; + sys_write32(gusbcfg, gusbcfg_reg); + k_msleep(25); + + if (ghwcfg2 & USB_DWC2_GHWCFG2_DYNFIFOSIZING) { + LOG_DBG("Dynamic FIFO Sizing is enabled"); + priv->dynfifosizing = true; + } + + /* Get the number or endpoints and IN endpoints we can use later */ + priv->numdeveps = usb_dwc2_get_ghwcfg2_numdeveps(ghwcfg2); + priv->ineps = usb_dwc2_get_ghwcfg4_ineps(ghwcfg4); + LOG_DBG("Number of endpoints (NUMDEVEPS) %u", priv->numdeveps); + LOG_DBG("Number of IN endpoints (INEPS) %u", priv->ineps); + + LOG_DBG("Number of periodic IN endpoints (NUMDEVPERIOEPS) %u", + usb_dwc2_get_ghwcfg4_numdevperioeps(ghwcfg4)); + LOG_DBG("Number of additional control endpoints (NUMCTLEPS) %u", + usb_dwc2_get_ghwcfg4_numctleps(ghwcfg4)); + + LOG_DBG("OTG architecture (OTGARCH) %u, mode (OTGMODE) %u", + usb_dwc2_get_ghwcfg2_otgarch(ghwcfg2), + usb_dwc2_get_ghwcfg2_otgmode(ghwcfg2)); + + priv->dfifodepth = usb_dwc2_get_ghwcfg3_dfifodepth(ghwcfg3); + LOG_DBG("DFIFO depth (DFIFODEPTH) %u bytes", priv->dfifodepth * 4); + + priv->max_pktcnt = GHWCFG3_PKTCOUNT(usb_dwc2_get_ghwcfg3_pktsizewidth(ghwcfg3)); + priv->max_xfersize = GHWCFG3_XFERSIZE(usb_dwc2_get_ghwcfg3_xfersizewidth(ghwcfg3)); + LOG_DBG("Max packet count %u, Max transfer size %u", + priv->max_pktcnt, priv->max_xfersize); + + LOG_DBG("Vendor Control interface support enabled: %s", + (ghwcfg3 & USB_DWC2_GHWCFG3_VNDCTLSUPT) ? "true" : "false"); + + LOG_DBG("PHY interface type: FSPHYTYPE %u, HSPHYTYPE %u, DATAWIDTH %u", + usb_dwc2_get_ghwcfg2_fsphytype(ghwcfg2), + usb_dwc2_get_ghwcfg2_hsphytype(ghwcfg2), + usb_dwc2_get_ghwcfg4_phydatawidth(ghwcfg4)); + + LOG_DBG("LPM mode is %s", + (ghwcfg3 & USB_DWC2_GHWCFG3_LPMMODE) ? "enabled" : "disabled"); + + /* Configure PHY and device speed */ + switch (usb_dwc2_get_ghwcfg2_hsphytype(ghwcfg2)) { + case USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUSULPI: + __fallthrough; + case USB_DWC2_GHWCFG2_HSPHYTYPE_ULPI: + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB20 | + USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_ULPI; + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBHS20); + break; + case USB_DWC2_GHWCFG2_HSPHYTYPE_UTMIPLUS: + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB20 | + USB_DWC2_GUSBCFG_ULPI_UTMI_SEL_UTMI; + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBHS20); + break; + case USB_DWC2_GHWCFG2_HSPHYTYPE_NO_HS: + __fallthrough; + default: + if (usb_dwc2_get_ghwcfg2_fsphytype(ghwcfg2) != + USB_DWC2_GHWCFG2_FSPHYTYPE_NO_FS) { + gusbcfg |= USB_DWC2_GUSBCFG_PHYSEL_USB11; + } + + sys_set_bits(dcfg_reg, USB_DWC2_DCFG_DEVSPD_USBFS1148); + } + + if (usb_dwc2_get_ghwcfg4_phydatawidth(ghwcfg4)) { + gusbcfg |= USB_DWC2_GUSBCFG_PHYIF_16_BIT; + } + + /* Update PHY configuration */ + sys_set_bits(gusbcfg_reg, gusbcfg); + + priv->outeps = 0U; + for (uint8_t i = 0U; i < priv->numdeveps; i++) { + uint32_t epdir = usb_dwc2_get_ghwcfg1_epdir(priv->ghwcfg1, i); + + if (epdir == USB_DWC2_GHWCFG1_EPDIR_OUT || + epdir == USB_DWC2_GHWCFG1_EPDIR_BDIR) { + mem_addr_t doepctl_reg = dwc2_get_dxepctl_reg(dev, i); + + sys_write32(USB_DWC2_DEPCTL_SNAK, doepctl_reg); + priv->outeps++; + } + } + + LOG_DBG("Number of OUT endpoints %u", priv->outeps); + + if (priv->dynfifosizing) { + priv->grxfsiz = UDC_DWC2_GRXFSIZ_DEFAULT + priv->outeps * 2U; + sys_write32(usb_dwc2_set_grxfsiz(priv->grxfsiz), (mem_addr_t)&base->grxfsiz); + } + + LOG_DBG("RX FIFO size %u bytes", priv->grxfsiz * 4); + for (uint8_t i = 1U; i < priv->ineps; i++) { + LOG_DBG("TX FIFO%u depth %u addr %u", + i, dwc2_get_txfdep(dev, i), dwc2_get_txfaddr(dev, i)); + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, + USB_EP_TYPE_CONTROL, 64, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } + + if (udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, + USB_EP_TYPE_CONTROL, 64, 0)) { + LOG_ERR("Failed to enable control endpoint"); + return -EIO; + } + + /* Unmask interrupts */ + sys_write32(USB_DWC2_GINTSTS_OEPINT | USB_DWC2_GINTSTS_IEPINT | + USB_DWC2_GINTSTS_ENUMDONE | USB_DWC2_GINTSTS_USBRST | + USB_DWC2_GINTSTS_WKUPINT | USB_DWC2_GINTSTS_USBSUSP, + (mem_addr_t)&base->gintmsk); + + + /* Call vendor-specific function to enable peripheral */ + if (config->quirks != NULL && config->quirks->pwr_on != NULL) { + LOG_DBG("Enable vendor power"); + ret = config->quirks->pwr_on(dev); + if (ret) { + return ret; + } + } + + /* Enable global interrupt */ + sys_set_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); + config->irq_enable_func(dev); + + return 0; +} + +static int udc_dwc2_shutdown(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + struct usb_dwc2_reg *const base = config->base; + + config->irq_disable_func(dev); + sys_clear_bits((mem_addr_t)&base->gahbcfg, USB_DWC2_GAHBCFG_GLBINTRMASK); + + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) { + LOG_DBG("Failed to disable control endpoint"); + return -EIO; + } + + if (udc_ep_disable_internal(dev, USB_CONTROL_EP_IN)) { + LOG_DBG("Failed to disable control endpoint"); + return -EIO; + } + + return 0; +} + +static int dwc2_driver_preinit(const struct device *dev) +{ + const struct udc_dwc2_config *config = dev->config; + struct udc_data *data = dev->data; + uint16_t mps = 1023; + int err; + + k_mutex_init(&data->mutex); + + data->caps.rwup = true; + data->caps.addr_before_status = true; + data->caps.mps0 = UDC_MPS0_64; + if (config->speed_idx == 2) { + data->caps.hs = true; + mps = 1024; + } + + for (int i = 0; i < config->num_of_eps; i++) { + config->ep_cfg_out[i].caps.out = 1; + if (i == 0) { + config->ep_cfg_out[i].caps.control = 1; + config->ep_cfg_out[i].caps.mps = 64; + } else { + config->ep_cfg_out[i].caps.bulk = 1; + config->ep_cfg_out[i].caps.interrupt = 1; + config->ep_cfg_out[i].caps.iso = 1; + config->ep_cfg_out[i].caps.mps = mps; + } + + config->ep_cfg_out[i].addr = USB_EP_DIR_OUT | i; + err = udc_register_ep(dev, &config->ep_cfg_out[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + for (int i = 0; i < config->num_of_eps; i++) { + config->ep_cfg_in[i].caps.in = 1; + if (i == 0) { + config->ep_cfg_in[i].caps.control = 1; + config->ep_cfg_in[i].caps.mps = 64; + } else { + config->ep_cfg_in[i].caps.bulk = 1; + config->ep_cfg_in[i].caps.interrupt = 1; + config->ep_cfg_in[i].caps.iso = 1; + config->ep_cfg_in[i].caps.mps = mps; + } + + config->ep_cfg_in[i].addr = USB_EP_DIR_IN | i; + err = udc_register_ep(dev, &config->ep_cfg_in[i]); + if (err != 0) { + LOG_ERR("Failed to register endpoint"); + return err; + } + } + + config->make_thread(dev); + + return 0; +} + +static int udc_dwc2_lock(const struct device *dev) +{ + return udc_lock_internal(dev, K_FOREVER); +} + +static int udc_dwc2_unlock(const struct device *dev) +{ + return udc_unlock_internal(dev); +} + +static const struct udc_api udc_dwc2_api = { + .lock = udc_dwc2_lock, + .unlock = udc_dwc2_unlock, + .device_speed = udc_dwc2_device_speed, + .init = udc_dwc2_init, + .enable = udc_dwc2_enable, + .disable = udc_dwc2_disable, + .shutdown = udc_dwc2_shutdown, + .set_address = udc_dwc2_set_address, + .test_mode = udc_dwc2_test_mode, + .host_wakeup = udc_dwc2_host_wakeup, + .ep_enable = udc_dwc2_ep_enable, + .ep_disable = udc_dwc2_ep_disable, + .ep_set_halt = udc_dwc2_ep_set_halt, + .ep_clear_halt = udc_dwc2_ep_clear_halt, + .ep_enqueue = udc_dwc2_ep_enqueue, + .ep_dequeue = udc_dwc2_ep_dequeue, +}; + +#define DT_DRV_COMPAT snps_dwc2 + +#define UDC_DWC2_VENDOR_QUIRK_GET(n) \ + COND_CODE_1(DT_NODE_VENDOR_HAS_IDX(DT_DRV_INST(n), 1), \ + (&dwc2_vendor_quirks_##n), \ + (NULL)) + +#define UDC_DWC2_DT_INST_REG_ADDR(n) \ + COND_CODE_1(DT_NUM_REGS(DT_DRV_INST(n)), (DT_INST_REG_ADDR(n)), \ + (DT_INST_REG_ADDR_BY_NAME(n, core))) + +#define UDC_DWC2_PINCTRL_DT_INST_DEFINE(n) \ + COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \ + (PINCTRL_DT_INST_DEFINE(n)), ()) + +#define UDC_DWC2_PINCTRL_DT_INST_DEV_CONFIG_GET(n) \ + COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \ + ((void *)PINCTRL_DT_INST_DEV_CONFIG_GET(n)), (NULL)) + +#define UDC_DWC2_IRQ_FLAGS_TYPE0(n) 0 +#define UDC_DWC2_IRQ_FLAGS_TYPE1(n) DT_INST_IRQ(n, type) +#define DW_IRQ_FLAGS(n) \ + _CONCAT(UDC_DWC2_IRQ_FLAGS_TYPE, DT_INST_IRQ_HAS_CELL(n, type))(n) + +/* + * A UDC driver should always be implemented as a multi-instance + * driver, even if your platform does not require it. + */ +#define UDC_DWC2_DEVICE_DEFINE(n) \ + UDC_DWC2_PINCTRL_DT_INST_DEFINE(n); \ + \ + K_THREAD_STACK_DEFINE(udc_dwc2_stack_##n, CONFIG_UDC_DWC2_STACK_SIZE); \ + \ + static void udc_dwc2_thread_##n(void *dev, void *arg1, void *arg2) \ + { \ + while (true) { \ + dwc2_thread_handler(dev); \ + } \ + } \ + \ + static void udc_dwc2_make_thread_##n(const struct device *dev) \ + { \ + struct udc_dwc2_data *priv = udc_get_private(dev); \ + \ + k_thread_create(&priv->thread_data, \ + udc_dwc2_stack_##n, \ + K_THREAD_STACK_SIZEOF(udc_dwc2_stack_##n), \ + udc_dwc2_thread_##n, \ + (void *)dev, NULL, NULL, \ + K_PRIO_COOP(CONFIG_UDC_DWC2_THREAD_PRIORITY), \ + K_ESSENTIAL, \ + K_NO_WAIT); \ + k_thread_name_set(&priv->thread_data, dev->name); \ + } \ + \ + static void udc_dwc2_irq_enable_func_##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + udc_dwc2_isr_handler, \ + DEVICE_DT_INST_GET(n), \ + DW_IRQ_FLAGS(n)); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static void udc_dwc2_irq_disable_func_##n(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(n)); \ + } \ + \ + static struct udc_ep_config ep_cfg_out[UDC_DWC2_DRV_EP_NUM]; \ + static struct udc_ep_config ep_cfg_in[UDC_DWC2_DRV_EP_NUM]; \ + \ + static const struct udc_dwc2_config udc_dwc2_config_##n = { \ + .num_of_eps = UDC_DWC2_DRV_EP_NUM, \ + .ep_cfg_in = ep_cfg_out, \ + .ep_cfg_out = ep_cfg_in, \ + .make_thread = udc_dwc2_make_thread_##n, \ + .base = (struct usb_dwc2_reg *)UDC_DWC2_DT_INST_REG_ADDR(n), \ + .pcfg = UDC_DWC2_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .irq_enable_func = udc_dwc2_irq_enable_func_##n, \ + .irq_disable_func = udc_dwc2_irq_disable_func_##n, \ + .quirks = UDC_DWC2_VENDOR_QUIRK_GET(n), \ + }; \ + \ + static struct udc_dwc2_data udc_priv_##n = { \ + }; \ + \ + static struct udc_data udc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(udc_data_##n.mutex), \ + .priv = &udc_priv_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, dwc2_driver_preinit, NULL, \ + &udc_data_##n, &udc_dwc2_config_##n, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &udc_dwc2_api); + +DT_INST_FOREACH_STATUS_OKAY(UDC_DWC2_DEVICE_DEFINE) diff --git a/drivers/usb/udc/udc_dwc2.h b/drivers/usb/udc/udc_dwc2.h new file mode 100644 index 00000000000..11d8178c135 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_UDC_DWC2_H +#define ZEPHYR_DRIVERS_USB_UDC_DWC2_H + +#include +#include +#include +#include + +/* Vendor quirks per driver instance */ +struct dwc2_vendor_quirks { + int (*clk_enable)(const struct device *dev); + int (*clk_disable)(const struct device *dev); + int (*pwr_on)(const struct device *dev); + int (*pwr_off)(const struct device *dev); + int (*irq_clear)(const struct device *dev); +}; + +/* Driver configuration per instance */ +struct udc_dwc2_config { + size_t num_of_eps; + struct udc_ep_config *ep_cfg_in; + struct udc_ep_config *ep_cfg_out; + int speed_idx; + struct usb_dwc2_reg *const base; + /* Pointer to pin control configuration or NULL */ + struct pinctrl_dev_config *const pcfg; + /* Pointer to vendor quirks or NULL */ + struct dwc2_vendor_quirks *const quirks; + void (*make_thread)(const struct device *dev); + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); +}; + +#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_H */ diff --git a/drivers/usb/udc/udc_dwc2_vendor_quirks.h b/drivers/usb/udc/udc_dwc2_vendor_quirks.h new file mode 100644 index 00000000000..104cb5cb847 --- /dev/null +++ b/drivers/usb/udc/udc_dwc2_vendor_quirks.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H +#define ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H + +#include "udc_dwc2.h" + +#include +#include +#include +#include + +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) + +struct usb_dw_stm32_clk { + const struct device *const dev; + const struct stm32_pclken *const pclken; + size_t pclken_len; +}; + +#define DT_DRV_COMPAT snps_dwc2 + +static inline int clk_enable_stm32f4_fsotg(const struct usb_dw_stm32_clk *const clk) +{ + int ret; + + if (!device_is_ready(clk->dev)) { + return -ENODEV; + } + + if (clk->pclken_len > 1) { + uint32_t clk_rate; + + ret = clock_control_configure(clk->dev, + (void *)&clk->pclken[1], + NULL); + if (ret) { + return ret; + } + + ret = clock_control_get_rate(clk->dev, + (void *)&clk->pclken[1], + &clk_rate); + if (ret) { + return ret; + } + + if (clk_rate != MHZ(48)) { + return -ENOTSUP; + } + } + + return clock_control_on(clk->dev, (void *)&clk->pclken[0]); +} + +static inline int pwr_on_stm32f4_fsotg(const struct device *dev) +{ + const struct udc_dwc2_config *const config = dev->config; + mem_addr_t ggpio_reg = (mem_addr_t)&config->base->ggpio; + + sys_set_bits(ggpio_reg, USB_DWC2_GGPIO_STM32_PWRDWN | USB_DWC2_GGPIO_STM32_VBDEN); + + return 0; +} + +#define QUIRK_STM32F4_FSOTG_DEFINE(n) \ + static const struct stm32_pclken pclken_##n[] = STM32_DT_INST_CLOCKS(n);\ + \ + static const struct usb_dw_stm32_clk stm32f4_clk_##n = { \ + .dev = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE), \ + .pclken = pclken_##n, \ + .pclken_len = DT_INST_NUM_CLOCKS(n), \ + }; \ + \ + static int clk_enable_stm32f4_fsotg_##n(const struct device *dev) \ + { \ + return clk_enable_stm32f4_fsotg(&stm32f4_clk_##n); \ + } \ + \ + struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \ + .clk_enable = clk_enable_stm32f4_fsotg_##n, \ + .pwr_on = pwr_on_stm32f4_fsotg, \ + .irq_clear = NULL, \ + }; + + +DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE) + +#undef DT_DRV_COMPAT + +#endif /*DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) */ + +/* Add next vendor quirks definition above this line */ + +#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ diff --git a/drivers/usb/udc/udc_nrf.c b/drivers/usb/udc/udc_nrf.c index bca098347d8..d4ecc130587 100644 --- a/drivers/usb/udc/udc_nrf.c +++ b/drivers/usb/udc/udc_nrf.c @@ -436,6 +436,8 @@ static void usbd_event_handler(nrf_usbd_common_evt_t const *const hal_evt) break; case NRF_USBD_COMMON_EVT_WUREQ: LOG_INF("Remote wakeup initiated"); + udc_set_suspended(udc_nrf_dev, false); + udc_submit_event(udc_nrf_dev, UDC_EVT_RESUME, 0); break; case NRF_USBD_COMMON_EVT_RESET: LOG_INF("Reset"); diff --git a/drivers/usb/udc/udc_stm32.c b/drivers/usb/udc/udc_stm32.c index 88070329cc3..e11228619b8 100644 --- a/drivers/usb/udc/udc_stm32.c +++ b/drivers/usb/udc/udc_stm32.c @@ -914,10 +914,13 @@ static int priv_clock_enable(void) return -ENODEV; } -#ifdef CONFIG_SOC_SERIES_STM32U5X - /* VDDUSB independent USB supply (PWR clock is on) */ +#if defined(PWR_USBSCR_USB33SV) || defined(PWR_SVMCR_USV) + /* + * VDDUSB independent USB supply (PWR clock is on) + * with LL_PWR_EnableVDDUSB function (higher case) + */ LL_PWR_EnableVDDUSB(); -#endif /* CONFIG_SOC_SERIES_STM32U5X */ +#endif /* PWR_USBSCR_USB33SV or PWR_SVMCR_USV */ #if defined(CONFIG_SOC_SERIES_STM32H7X) LL_PWR_EnableUSBVoltageDetector(); diff --git a/drivers/usb_c/CMakeLists.txt b/drivers/usb_c/CMakeLists.txt index d576f955cec..9629bbad2f6 100644 --- a/drivers/usb_c/CMakeLists.txt +++ b/drivers/usb_c/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory_ifdef(CONFIG_USBC_TCPC_DRIVER tcpc) add_subdirectory_ifdef(CONFIG_USBC_VBUS_DRIVER vbus) +add_subdirectory_ifdef(CONFIG_USBC_PPC_DRIVER ppc) diff --git a/drivers/usb_c/Kconfig b/drivers/usb_c/Kconfig index f62da2a67c7..b30259c80b4 100644 --- a/drivers/usb_c/Kconfig +++ b/drivers/usb_c/Kconfig @@ -5,3 +5,4 @@ source "drivers/usb_c/tcpc/Kconfig" source "drivers/usb_c/vbus/Kconfig" +source "drivers/usb_c/ppc/Kconfig" diff --git a/drivers/usb_c/ppc/CMakeLists.txt b/drivers/usb_c/ppc/CMakeLists.txt new file mode 100644 index 00000000000..dc3fc83988c --- /dev/null +++ b/drivers/usb_c/ppc/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_USBC_PPC_SHELL shell.c) +zephyr_library_sources_ifdef(CONFIG_USBC_PPC_NX20P3483 nxp_nx20p3483.c) diff --git a/drivers/usb_c/ppc/Kconfig b/drivers/usb_c/ppc/Kconfig new file mode 100644 index 00000000000..c3fc93e1f4e --- /dev/null +++ b/drivers/usb_c/ppc/Kconfig @@ -0,0 +1,30 @@ +# Power path controllers configuration options + +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +menuconfig USBC_PPC_DRIVER + bool "USB-C PPC drivers" + help + Enable USB-C Power Path Controllers support + +if USBC_PPC_DRIVER + +config USBC_PPC_INIT_PRIORITY + int "USBC PPC driver init priority" + default 82 + help + Initialization priority of the USB-C PPC drivers in POST_KERNEL. + +config USBC_PPC_SHELL + bool "Shell commands for PPC" + help + Add useful shell commands to manipulate and debug the PPCs + +source "drivers/usb_c/ppc/Kconfig.nxp" + +module = USBC_PPC +module-str = usbc-ppc +source "subsys/logging/Kconfig.template.log_config" + +endif # USBC_PPC_DRIVER diff --git a/drivers/usb_c/ppc/Kconfig.nxp b/drivers/usb_c/ppc/Kconfig.nxp new file mode 100644 index 00000000000..1d1de6a49e9 --- /dev/null +++ b/drivers/usb_c/ppc/Kconfig.nxp @@ -0,0 +1,20 @@ +# NXP NX20P3483 Configuration menu + +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +config USBC_PPC_NX20P3483 + bool "NXP NX20P3483 support" + default y + depends on DT_HAS_NXP_NX20P3483_ENABLED + help + Enable USB-C PPC support for NXP nx20p3483 chip + +if USBC_PPC_NX20P3483 + +config USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES + bool "Dump full register names" + help + Dump human-readable names instead of offsets of registers + +endif diff --git a/drivers/usb_c/ppc/nxp_nx20p3483.c b/drivers/usb_c/ppc/nxp_nx20p3483.c new file mode 100644 index 00000000000..8b6a2fe914d --- /dev/null +++ b/drivers/usb_c/ppc/nxp_nx20p3483.c @@ -0,0 +1,457 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "nxp_nx20p3483_priv.h" + +#define DT_DRV_COMPAT nxp_nx20p3483 +LOG_MODULE_REGISTER(nxp_nx20p3483, CONFIG_USBC_PPC_LOG_LEVEL); + +#ifdef CONFIG_USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES +static const char *const nx20p3483_reg_names[] = { + "Device ID ", "Device Status ", "Switch Control ", + "Switch Status ", "Interrupt 1 ", "Interrupt 2 ", + "Interrupt 1 Mask ", "Interrupt 2 Mask ", "OVLO Threshold ", + "HV SRC OCP Threshold", "5V SRC OCP Threshold", "Device Control ", +}; +#endif + +/* Driver structures */ + +struct nx20p3483_cfg { + /** Device address on I2C bus */ + const struct i2c_dt_spec bus; + /** GPIO used as interrupt request */ + const struct gpio_dt_spec irq_gpio; + + /** Overvoltage protection threshold for sink role */ + int snk_ovp_thresh; + /** Boolean value whether to use high-voltage source if true or 5V source if false */ + bool src_use_hv; + /** Overcurrent protection threshold for 5V source role */ + int src_5v_ocp_thresh; + /** Overcurrent protection threshold for HV source role */ + int src_hv_ocp_thresh; +}; + +struct nx20p3483_data { + /** Device structure to get from data structure */ + const struct device *dev; + /** Interrupt request callback object */ + struct gpio_callback irq_cb; + /** Workqueue object for handling interrupts */ + struct k_work irq_work; + + /** Callback used to notify about PPC events, like overcurrent or short */ + usbc_ppc_event_cb_t event_cb; + /** Data sent as parameter to the callback */ + void *event_cb_data; +}; + +/* Helper functions */ + +static int read_reg(const struct device *dev, uint8_t reg, uint8_t *value) +{ + const struct nx20p3483_cfg *cfg = dev->config; + int ret; + + ret = i2c_reg_read_byte(cfg->bus.bus, cfg->bus.addr, reg, value); + if (ret != 0) { + LOG_ERR("Error reading reg %02x: %d", reg, ret); + return ret; + } + + return 0; +} + +static int write_reg(const struct device *dev, uint8_t reg, uint8_t value) +{ + const struct nx20p3483_cfg *cfg = dev->config; + int ret; + + ret = i2c_reg_write_byte(cfg->bus.bus, cfg->bus.addr, reg, value); + if (ret != 0) { + LOG_ERR("Error writing reg %02x: %d", reg, ret); + return ret; + } + + return 0; +} + +static int nx20p3483_set_snk_ovp_limit(const struct device *dev, uint8_t u_thresh) +{ + int ret; + + if (u_thresh < NX20P3483_I_THRESHOLD_0_400 || u_thresh > NX20P3483_I_THRESHOLD_3_400) { + return -EINVAL; + } + + ret = write_reg(dev, NX20P3483_REG_OVLO_THRESHOLD, u_thresh); + if (ret != 0) { + LOG_ERR("Couldn't set SNK OVP: %d", ret); + return ret; + } + + LOG_DBG("Set SNK OVP: %d", u_thresh); + return 0; +} + +/* API functions */ + +int nx20p3483_is_dead_battery_mode(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return ((sts_reg & NX20P3483_REG_DEVICE_STATUS_MODE_MASK) == NX20P3483_MODE_DEAD_BATTERY); +} + +int nx20p3483_exit_dead_battery_mode(const struct device *dev) +{ + uint8_t ctrl_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_CTRL, &ctrl_reg); + if (ret != 0) { + return ret; + } + + ctrl_reg |= NX20P3483_REG_DEVICE_CTRL_DB_EXIT; + ret = write_reg(dev, NX20P3483_REG_DEVICE_CTRL, ctrl_reg); + if (ret != 0) { + return ret; + } + + return 0; +} + +static int nx20p3483_is_vbus_source(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_SWITCH_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return !!(sts_reg & + (NX20P3483_REG_SWITCH_STATUS_5VSRC | NX20P3483_REG_SWITCH_STATUS_HVSRC)); +} + +static int nx20p3483_is_vbus_sink(const struct device *dev) +{ + uint8_t sts_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_SWITCH_STATUS, &sts_reg); + if (ret != 0) { + return ret; + } + + return !!(sts_reg & NX20P3483_REG_SWITCH_STATUS_HVSNK); +} + +static int nx20p3483_set_vbus_sink(const struct device *dev, bool enable) +{ + const struct nx20p3483_cfg *cfg = dev->config; + + /* + * The nx20p3483 is enabled by external GPIO signal, however enabling it sets the + * overvoltage threshold to the highest possible value. Due to that, the threshold has + * to be set here again. Must be called after enabling the path by the external signal. + */ + return nx20p3483_set_snk_ovp_limit(dev, cfg->snk_ovp_thresh); +} + +static int nx20p3483_set_vbus_discharge(const struct device *dev, bool enable) +{ + uint8_t ctrl_reg; + int ret; + + ret = read_reg(dev, NX20P3483_REG_DEVICE_CTRL, &ctrl_reg); + if (ret != 0) { + return ret; + } + + if (enable) { + ctrl_reg |= NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN; + } else { + ctrl_reg &= ~NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN; + } + + ret = write_reg(dev, NX20P3483_REG_DEVICE_CTRL, ctrl_reg); + + return ret; +} + +static int nx20p3483_set_event_handler(const struct device *dev, usbc_ppc_event_cb_t handler, + void *handler_data) +{ + struct nx20p3483_data *data = dev->data; + + data->event_cb = handler; + data->event_cb_data = handler_data; + + return 0; +} + +static int nx20p3483_dump_regs(const struct device *dev) +{ + const struct nx20p3483_cfg *cfg = dev->config; + uint8_t val; + + LOG_INF("NX20P alert: %d", gpio_pin_get(cfg->irq_gpio.port, cfg->irq_gpio.pin)); + LOG_INF("PPC %s:%s registers:", cfg->bus.bus->name, dev->name); + for (int a = 0; a <= NX20P3483_REG_DEVICE_CTRL; a++) { + i2c_reg_read_byte(cfg->bus.bus, cfg->bus.addr, a, &val); + +#ifdef CONFIG_USBC_PPC_NX20P3483_DUMP_FULL_REG_NAMES + LOG_INF("- [%s] = 0x%02x", nx20p3483_reg_names[a], val); +#else + LOG_INF("- [%02x] = 0x%02x", a, val); +#endif + } + + return 0; +} + +static struct usbc_ppc_drv nx20p3483_driver_api = { + .is_dead_battery_mode = nx20p3483_is_dead_battery_mode, + .exit_dead_battery_mode = nx20p3483_exit_dead_battery_mode, + .is_vbus_source = nx20p3483_is_vbus_source, + .is_vbus_sink = nx20p3483_is_vbus_sink, + .set_snk_ctrl = nx20p3483_set_vbus_sink, + .set_vbus_discharge = nx20p3483_set_vbus_discharge, + .set_event_handler = nx20p3483_set_event_handler, + .dump_regs = nx20p3483_dump_regs, +}; + +static int nx20p3483_set_src_ovc_limit(const struct device *dev, uint8_t i_thresh_5v, + uint8_t i_thresh_hv) +{ + int ret; + + if (i_thresh_5v < NX20P3483_I_THRESHOLD_0_400 || + i_thresh_5v > NX20P3483_I_THRESHOLD_3_400) { + LOG_ERR("Invalid SRC 5V ovc threshold: %d", i_thresh_5v); + return -EINVAL; + } + + if (i_thresh_hv < NX20P3483_I_THRESHOLD_0_400 || + i_thresh_hv > NX20P3483_I_THRESHOLD_3_400) { + LOG_ERR("Invalid SRC HV ovc threshold: %d", i_thresh_hv); + return -EINVAL; + } + + ret = write_reg(dev, NX20P3483_REG_5V_SRC_OCP_THRESHOLD, i_thresh_5v); + if (ret != 0) { + return ret; + } + + ret = write_reg(dev, NX20P3483_REG_HV_SRC_OCP_THRESHOLD, i_thresh_hv); + if (ret != 0) { + return ret; + } + + LOG_DBG("Set SRC OVC 5V: %d, HV: %d", i_thresh_5v, i_thresh_hv); + return 0; +} + +static void nx20p3483_send_event(const struct device *dev, enum usbc_ppc_event ev) +{ + struct nx20p3483_data *data = dev->data; + + if (data->event_cb != NULL) { + data->event_cb(dev, data->event_cb_data, ev); + } +} + +static void nx20p3483_irq_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ + struct nx20p3483_data *data = CONTAINER_OF(cb, struct nx20p3483_data, irq_cb); + + k_work_submit(&data->irq_work); +} + +static void nx20p3483_irq_worker(struct k_work *work) +{ + struct nx20p3483_data *data = CONTAINER_OF(work, struct nx20p3483_data, irq_work); + const struct device *dev = data->dev; + uint8_t irq1, irq2; + int ret; + + ret = read_reg(dev, NX20P3483_REG_INT1, &irq1); + if (ret != 0) { + LOG_ERR("Couldn't read irq1"); + return; + } + + ret = read_reg(dev, NX20P3483_REG_INT2, &irq2); + if (ret != 0) { + LOG_ERR("Couldn't read irq2"); + return; + } + + if (data->event_cb == NULL) { + LOG_DBG("No callback set: %02x %02x", irq1, irq1); + } + + /* Generic alerts */ + if (irq1 & NX20P3483_REG_INT1_DBEXIT_ERR) { + LOG_INF("PPC dead battery exit failed"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_DEAD_BATTERY_ERROR); + } + + if (irq1 & NX20P3483_REG_INT1_OTP) { + LOG_INF("PPC over temperature"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_OVER_TEMPERATURE); + } + + if (irq1 & NX20P3483_REG_INT2_EN_ERR) { + LOG_INF("PPC source and sink enabled"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_BOTH_SNKSRC_ENABLED); + } + + /* Source */ + if (irq1 & NX20P3483_REG_INT1_OV_5VSRC || irq2 & NX20P3483_REG_INT2_OV_HVSRC) { + LOG_INF("PPC source overvoltage"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_OVERVOLTAGE); + } + + if (irq1 & NX20P3483_REG_INT1_RCP_5VSRC || irq2 & NX20P3483_REG_INT2_RCP_HVSRC) { + LOG_INF("PPC source reverse current"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_REVERSE_CURRENT); + } + + if (irq1 & NX20P3483_REG_INT1_OC_5VSRC || irq2 & NX20P3483_REG_INT2_OC_HVSRC) { + LOG_INF("PPC source overcurrent"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_OVERCURRENT); + } + + if (irq1 & NX20P3483_REG_INT1_SC_5VSRC || irq2 & NX20P3483_REG_INT2_SC_HVSRC) { + LOG_INF("PPC source short"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SRC_SHORT); + } + + /* Sink */ + if (irq2 & NX20P3483_REG_INT2_RCP_HVSNK) { + LOG_INF("PPC sink reverse current"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_REVERSE_CURRENT); + } + + if (irq2 & NX20P3483_REG_INT2_SC_HVSNK) { + LOG_INF("PPC sink short"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_SHORT); + } + + if (irq2 & NX20P3483_REG_INT2_OV_HVSNK) { + LOG_INF("PPC sink overvoltage"); + nx20p3483_send_event(dev, USBC_PPC_EVENT_SNK_OVERVOLTAGE); + } +} + +static int nx20p3483_dev_init(const struct device *dev) +{ + const struct nx20p3483_cfg *cfg = dev->config; + struct nx20p3483_data *data = dev->data; + uint8_t reg; + int ret; + + LOG_INF("Initializing PPC"); + + /* Initialize irq */ + ret = gpio_pin_configure(cfg->irq_gpio.port, cfg->irq_gpio.pin, GPIO_INPUT | GPIO_PULL_UP); + if (ret != 0) { + return ret; + } + + ret = gpio_pin_interrupt_configure(cfg->irq_gpio.port, cfg->irq_gpio.pin, + GPIO_INT_EDGE_FALLING); + if (ret != 0) { + return ret; + } + + gpio_init_callback(&data->irq_cb, nx20p3483_irq_handler, BIT(cfg->irq_gpio.pin)); + ret = gpio_add_callback(cfg->irq_gpio.port, &data->irq_cb); + if (ret != 0) { + return ret; + } + + /* Initialize work_q */ + k_work_init(&data->irq_work, nx20p3483_irq_worker); + k_work_submit(&data->irq_work); + + /* If src_use_hv, select the HV src path but do not enable it yet */ + read_reg(dev, NX20P3483_REG_SWITCH_CTRL, ®); + if (cfg->src_use_hv) { + reg |= NX20P3483_REG_SWITCH_CTRL_SRC; + } else { + reg &= ~NX20P3483_REG_SWITCH_CTRL_SRC; + } + + write_reg(dev, NX20P3483_REG_SWITCH_CTRL, reg); + + /* Set limits */ + ret = nx20p3483_set_snk_ovp_limit(dev, cfg->snk_ovp_thresh); + if (ret != 0) { + return ret; + } + + ret = nx20p3483_set_src_ovc_limit(dev, cfg->src_5v_ocp_thresh, cfg->src_hv_ocp_thresh); + if (ret != 0) { + return ret; + } + + return 0; +} + +#define NX20P3483_DRIVER_CFG_INIT(node) \ + { \ + .bus = I2C_DT_SPEC_GET(node), .irq_gpio = GPIO_DT_SPEC_GET(node, irq_gpios), \ + .snk_ovp_thresh = DT_PROP(node, snk_ovp), .src_use_hv = DT_PROP(node, src_hv), \ + .src_5v_ocp_thresh = DT_PROP(node, src_5v_ocp), \ + .src_hv_ocp_thresh = DT_PROP(node, src_hv_ocp), \ + } + +#define NX20P3483_DRIVER_CFG_ASSERTS(node) \ + BUILD_ASSERT(DT_PROP(node, snk_ovp) >= NX20P3483_U_THRESHOLD_6_0 && \ + DT_PROP(node, snk_ovp) <= NX20P3483_U_THRESHOLD_23_0, \ + "Invalid overvoltage threshold"); \ + BUILD_ASSERT(DT_PROP(node, src_5v_ocp) >= NX20P3483_I_THRESHOLD_0_400 && \ + DT_PROP(node, src_5v_ocp) <= NX20P3483_I_THRESHOLD_3_400, \ + "Invalid overcurrent threshold"); \ + BUILD_ASSERT(DT_PROP(node, src_hv_ocp) >= NX20P3483_I_THRESHOLD_0_400 && \ + DT_PROP(node, src_hv_ocp) <= NX20P3483_I_THRESHOLD_3_400, \ + "Invalid overcurrent threshold"); + +#define NX20P3483_DRIVER_DATA_INIT(node) \ + { \ + .dev = DEVICE_DT_GET(node), \ + } + +#define NX20P3483_DRIVER_INIT(inst) \ + static struct nx20p3483_data drv_data_nx20p3483##inst = \ + NX20P3483_DRIVER_DATA_INIT(DT_DRV_INST(inst)); \ + NX20P3483_DRIVER_CFG_ASSERTS(DT_DRV_INST(inst)); \ + static struct nx20p3483_cfg drv_cfg_nx20p3483##inst = \ + NX20P3483_DRIVER_CFG_INIT(DT_DRV_INST(inst)); \ + DEVICE_DT_INST_DEFINE(inst, &nx20p3483_dev_init, NULL, &drv_data_nx20p3483##inst, \ + &drv_cfg_nx20p3483##inst, POST_KERNEL, \ + CONFIG_USBC_PPC_INIT_PRIORITY, &nx20p3483_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(NX20P3483_DRIVER_INIT) diff --git a/drivers/usb_c/ppc/nxp_nx20p3483_priv.h b/drivers/usb_c/ppc/nxp_nx20p3483_priv.h new file mode 100644 index 00000000000..b033be4a730 --- /dev/null +++ b/drivers/usb_c/ppc/nxp_nx20p3483_priv.h @@ -0,0 +1,127 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief NX20P3483 PPC registers definitions + */ + +#ifndef ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ +#define ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ + +#include + +/** Register address - device id */ +#define NX20P3483_REG_DEVICE_ID 0x00 +/** Bit mask for vendor id */ +#define NX20P3483_REG_DEVICE_ID_VENDOR_MASK GENMASK(7, 3) +/** Bit mask for version id */ +#define NX20P3483_REG_DEVICE_ID_REVISION_MASK GENMASK(2, 0) + +/** Register address - device status */ +#define NX20P3483_REG_DEVICE_STATUS 0x01 +/** Bit mask for device mode */ +#define NX20P3483_REG_DEVICE_STATUS_MODE_MASK GENMASK(2, 0) + +/** Value for dead battery mode */ +#define NX20P3483_MODE_DEAD_BATTERY 0 +/** Value for high-voltage sink mode */ +#define NX20P3483_MODE_HV_SNK 1 +/** Value for 5V source mode */ +#define NX20P3483_MODE_5V_SRC 2 +/** Value for high-voltage source mode */ +#define NX20P3483_MODE_HV_SRC 3 +/** Value for standby mode */ +#define NX20P3483_MODE_STANDBY 4 + +/** Register address - switch control */ +#define NX20P3483_REG_SWITCH_CTRL 0x02 +/** Bit field for source path selection. If set, HV source path is selected, 5V otherwise. */ +#define NX20P3483_REG_SWITCH_CTRL_SRC BIT(7) + +/** Register address - switch status */ +#define NX20P3483_REG_SWITCH_STATUS 0x03 +/** Bit field for 5V source switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_5VSRC BIT(2) +/** Bit field for HV source switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_HVSRC BIT(1) +/** Bit field for HV sink switch enabled */ +#define NX20P3483_REG_SWITCH_STATUS_HVSNK BIT(0) + +/** Register address - interrupt1 */ +#define NX20P3483_REG_INT1 0x04 +/** Bit field for exit dead battery error */ +#define NX20P3483_REG_INT1_DBEXIT_ERR BIT(7) +/** Bit field for overvoltage fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_OV_5VSRC BIT(4) +/** Bit field for reverse current fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_RCP_5VSRC BIT(3) +/** Bit field for short circuit fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_SC_5VSRC BIT(2) +/** Bit field for overcurrent fault triggered on 5V source path */ +#define NX20P3483_REG_INT1_OC_5VSRC BIT(1) +/** Bit field for over temperature protection fault triggered */ +#define NX20P3483_REG_INT1_OTP BIT(0) + +/** Register address - interrupt2*/ +#define NX20P3483_REG_INT2 0x05 +/** Bit field for sink and source routes enabled fault */ +#define NX20P3483_REG_INT2_EN_ERR BIT(7) +/** Bit field for reverse current fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_RCP_HVSNK BIT(6) +/** Bit field for short circuit fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_SC_HVSNK BIT(5) +/** Bit field for overvoltage fault triggered on HV sink path */ +#define NX20P3483_REG_INT2_OV_HVSNK BIT(4) +/** Bit field for reverse current fault triggered on HV source path */ +#define NX20P3483_REG_INT2_RCP_HVSRC BIT(3) +/** Bit field for short circuit fault triggered on HV source path */ +#define NX20P3483_REG_INT2_SC_HVSRC BIT(2) +/** Bit field for overcurrent fault triggered on HV source path */ +#define NX20P3483_REG_INT2_OC_HVSRC BIT(1) +/** Bit field for overvoltage fault triggered on HV source path */ +#define NX20P3483_REG_INT2_OV_HVSRC BIT(0) + +/** Register address - interrupt1 mask */ +#define NX20P3483_REG_INT1_MASK 0x06 + +/** Register address - interrupt2 mask*/ +#define NX20P3483_REG_INT2_MASK 0x07 + +/** Register address - OVLO threshold (overvoltage threshold) */ +#define NX20P3483_REG_OVLO_THRESHOLD 0x08 +/** + * Bit mask for overvoltage threshold value + * Values used in this register are defined as NX20P3483_U_THRESHOLD_* + */ +#define NX20P3483_REG_OVLO_THRESHOLD_MASK GENMASK(2, 0) + +/* Internal 5V VBUS Switch Current Limit Settings (min) */ +#define NX20P3483_ILIM_MASK 0xF + +/** + * Register address - HV source switch OCP threshold + * Values used in this register are defined as NX20P3483_I_THRESHOLD_* + */ +#define NX20P3483_REG_HV_SRC_OCP_THRESHOLD 0x09 + +/** + * Register address - 5V source switch OCP threshold + * Values used in this register are defined as NX20P3483_I_THRESHOLD_* + */ +#define NX20P3483_REG_5V_SRC_OCP_THRESHOLD 0x0A + +/** Register address - device control */ +#define NX20P3483_REG_DEVICE_CTRL 0x0B +/** Bit field for fast role swap capability activated */ +#define NX20P3483_REG_DEVICE_CTRL_FRS_AT BIT(3) +/** Bit field for exit dead battery mode */ +#define NX20P3483_REG_DEVICE_CTRL_DB_EXIT BIT(2) +/** Bit field for VBUS discharge circuit enabled */ +#define NX20P3483_REG_DEVICE_CTRL_VBUSDIS_EN BIT(1) +/** Bit field for LDO shutdown */ +#define NX20P3483_REG_DEVICE_CTRL_LDO_SD BIT(0) + +#endif /* ZEPHYR_DRIVERS_USBC_PPC_NXP_NX20P3483_PRIV_H_ */ diff --git a/drivers/usb_c/ppc/shell.c b/drivers/usb_c/ppc/shell.c new file mode 100644 index 00000000000..a69db474ce8 --- /dev/null +++ b/drivers/usb_c/ppc/shell.c @@ -0,0 +1,134 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/** Macro used to iterate over USB-C connector and call a function if the node has PPC property */ +#define CALL_IF_HAS_PPC(usb_node, func) \ + COND_CODE_1(DT_NODE_HAS_PROP(usb_node, ppc), \ + (ret |= func(DEVICE_DT_GET(DT_PHANDLE_BY_IDX(usb_node, ppc, 0)));), ()) + +/** + * @brief Command that dumps registers of one or all of the PPCs + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_dump(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, ppc_dump_regs); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = ppc_dump_regs(dev); + } + + return ret; +} + +/** + * @brief Function used to pretty print status of the PPC + * + * @param dev Pointer to the PPC device structure + */ +static int print_status(const struct device *dev) +{ + printk("PPC %s:\n", dev->name); + printk(" Dead battery: %d\n", ppc_is_dead_battery_mode(dev)); + printk(" Is sourcing: %d\n", ppc_is_vbus_source(dev)); + printk(" Is sinking: %d\n", ppc_is_vbus_sink(dev)); + printk(" Is VBUS present: %d\n", ppc_is_vbus_present(dev)); + + return 0; +} + +/** + * @brief Command that prints the status of one or all of the PPCs + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_status(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, print_status); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = print_status(dev); + } + + return ret; +} + +/** + * @brief Command that requests one or all of the PPCs to try exiting the dead battery mode + * + * @param sh Shell structure + * @param argc Arguments count + * @param argv Device name + * @return int ORed return values of all the functions executed, 0 in case of success + */ +static int cmd_ppc_exit_db(const struct shell *sh, size_t argc, char **argv) +{ + int ret = 0; + + if (argc <= 1) { + DT_FOREACH_STATUS_OKAY_VARGS(usb_c_connector, CALL_IF_HAS_PPC, + ppc_exit_dead_battery_mode); + } else { + const struct device *dev = device_get_binding(argv[1]); + + ret = ppc_exit_dead_battery_mode(dev); + } + + return ret; +} + +/** + * @brief Function used to create subcommands with devices names + * + * @param idx counter of devices + * @param entry shell structure that will be filled + */ +static void device_name_get(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_lookup(idx, NULL); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = NULL; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(list_device_names, device_name_get); + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_ppc_cmds, + SHELL_CMD_ARG(dump, &list_device_names, + "Dump PPC registers\n" + "Usage: ppc dump []", + cmd_ppc_dump, 1, 1), + SHELL_CMD_ARG(status, &list_device_names, + "Write PPC power status\n" + "Usage: ppc statuc []", + cmd_ppc_status, 1, 1), + SHELL_CMD_ARG(exitdb, &list_device_names, + "Exit from the dead battery mode\n" + "Usage: ppc exitdb []", + cmd_ppc_exit_db, 1, 1), + SHELL_SUBCMD_SET_END); + +SHELL_CMD_REGISTER(ppc, &sub_ppc_cmds, "PPC (USB-C PD) diagnostics", NULL); diff --git a/drivers/virtualization/Kconfig b/drivers/virtualization/Kconfig index 4f32552f09a..f439f5ba97d 100644 --- a/drivers/virtualization/Kconfig +++ b/drivers/virtualization/Kconfig @@ -66,4 +66,10 @@ config IVSHMEM_V2 Enable ivshmem-v2 support. ivshmem-v2 is primarily used for IPC in the Jailhouse hypervisor. +config IVSHMEM_V2_MAX_PEERS + int "Maximum number of ivshmem-v2 peers" + depends on IVSHMEM_V2 + default 2 + range 2 65536 + endif # VIRTUALIZATION diff --git a/drivers/virtualization/virt_ivshmem.c b/drivers/virtualization/virt_ivshmem.c index 6e8258f1dad..f620ab473f9 100644 --- a/drivers/virtualization/virt_ivshmem.c +++ b/drivers/virtualization/virt_ivshmem.c @@ -198,7 +198,7 @@ static bool ivshmem_configure(const struct device *dev) (volatile struct ivshmem_v2_reg *)DEVICE_MMIO_GET(dev); data->max_peers = regs->max_peers; - if (!IN_RANGE(data->max_peers, 2, 0x10000)) { + if (!IN_RANGE(data->max_peers, 2, CONFIG_IVSHMEM_V2_MAX_PEERS)) { LOG_ERR("Invalid max peers %u", data->max_peers); return false; } @@ -211,26 +211,49 @@ static bool ivshmem_configure(const struct device *dev) shmem_phys_addr = pcie_conf_read_u64(data->pcie->bdf, cap_pos); } + /* State table R/O */ cap_pos = vendor_cap + IVSHMEM_CFG_STATE_TAB_SZ / 4; size_t state_table_size = pcie_conf_read(data->pcie->bdf, cap_pos); - LOG_INF("State table size 0x%zX", state_table_size); if (state_table_size < sizeof(uint32_t) * data->max_peers) { LOG_ERR("Invalid state table size %zu", state_table_size); return false; } + z_phys_map((uint8_t **)&data->state_table_shmem, + shmem_phys_addr, state_table_size, + K_MEM_CACHE_WB | K_MEM_PERM_USER); + /* R/W section (optional) */ cap_pos = vendor_cap + IVSHMEM_CFG_RW_SECTION_SZ / 4; data->rw_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->rw_section_offset = state_table_size; + size_t rw_section_offset = state_table_size; LOG_INF("RW section size 0x%zX", data->rw_section_size); + if (data->rw_section_size > 0) { + z_phys_map((uint8_t **)&data->rw_section_shmem, + shmem_phys_addr + rw_section_offset, data->rw_section_size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } + /* Output sections */ cap_pos = vendor_cap + IVSHMEM_CFG_OUTPUT_SECTION_SZ / 4; data->output_section_size = pcie_conf_read_u64(data->pcie->bdf, cap_pos); - data->output_section_offset = data->rw_section_offset + data->rw_section_size; + size_t output_section_offset = rw_section_offset + data->rw_section_size; LOG_INF("Output section size 0x%zX", data->output_section_size); + for (uint32_t i = 0; i < data->max_peers; i++) { + uintptr_t phys_addr = shmem_phys_addr + + output_section_offset + + (data->output_section_size * i); + uint32_t flags = K_MEM_CACHE_WB | K_MEM_PERM_USER; + + /* Only your own output section is R/W */ + if (i == regs->id) { + flags |= K_MEM_PERM_RW; + } + z_phys_map((uint8_t **)&data->output_section_shmem[i], + phys_addr, data->output_section_size, flags); + } - data->size = data->output_section_offset + + data->size = output_section_offset + data->output_section_size * data->max_peers; /* Ensure one-shot ISR mode is disabled */ @@ -249,11 +272,11 @@ static bool ivshmem_configure(const struct device *dev) } data->size = mbar_shmem.size; - } - z_phys_map((uint8_t **)&data->shmem, - shmem_phys_addr, data->size, - K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + z_phys_map((uint8_t **)&data->shmem, + shmem_phys_addr, data->size, + K_MEM_CACHE_WB | K_MEM_PERM_RW | K_MEM_PERM_USER); + } if (msi_x_bar_present) { if (!ivshmem_configure_msi_x_interrupts(dev)) { @@ -284,6 +307,13 @@ static size_t ivshmem_api_get_mem(const struct device *dev, { struct ivshmem *data = dev->data; +#ifdef CONFIG_IVSHMEM_V2 + if (data->ivshmem_v2) { + *memmap = 0; + return 0; + } +#endif + *memmap = data->shmem; return data->size; @@ -389,11 +419,11 @@ static size_t ivshmem_api_get_rw_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->rw_section_offset; + *memmap = data->rw_section_shmem; return data->rw_section_size; } @@ -405,12 +435,11 @@ static size_t ivshmem_api_get_output_mem_section(const struct device *dev, struct ivshmem *data = dev->data; if (!data->ivshmem_v2 || peer_id >= data->max_peers) { - memmap = NULL; + *memmap = 0; return 0; } - *memmap = data->shmem + data->output_section_offset + - data->output_section_size * peer_id; + *memmap = data->output_section_shmem[peer_id]; return data->output_section_size; } @@ -425,7 +454,7 @@ static uint32_t ivshmem_api_get_state(const struct device *dev, } const volatile uint32_t *state_table = - (const volatile uint32_t *)data->shmem; + (const volatile uint32_t *)data->state_table_shmem; return state_table[peer_id]; } diff --git a/drivers/virtualization/virt_ivshmem.h b/drivers/virtualization/virt_ivshmem.h index e6439408787..8a7ae11c364 100644 --- a/drivers/virtualization/virt_ivshmem.h +++ b/drivers/virtualization/virt_ivshmem.h @@ -57,9 +57,10 @@ struct ivshmem { bool ivshmem_v2; uint32_t max_peers; size_t rw_section_size; - size_t rw_section_offset; size_t output_section_size; - size_t output_section_offset; + uintptr_t state_table_shmem; + uintptr_t rw_section_shmem; + uintptr_t output_section_shmem[CONFIG_IVSHMEM_V2_MAX_PEERS]; #endif }; diff --git a/drivers/w1/CMakeLists.txt b/drivers/w1/CMakeLists.txt index 57d010f4e4d..58fa21ab84a 100644 --- a/drivers/w1/CMakeLists.txt +++ b/drivers/w1/CMakeLists.txt @@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_W1_DS2484 w1_ds2484.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2485 w1_ds2485.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2477_85_COMMON w1_ds2477_85_common.c) zephyr_library_sources_ifdef(CONFIG_W1_TEST w1_test.c) +zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_GPIO w1_zephyr_gpio.c) zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_SERIAL w1_zephyr_serial.c) # network functions: diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index a63a5741981..d33503c2684 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -44,6 +44,7 @@ rsource "Kconfig.ds2484" rsource "Kconfig.ds2477_85" rsource "Kconfig.ds2485" rsource "Kconfig.test" +rsource "Kconfig.zephyr_gpio" rsource "Kconfig.zephyr_serial" config W1_NET diff --git a/drivers/w1/Kconfig.zephyr_gpio b/drivers/w1/Kconfig.zephyr_gpio new file mode 100644 index 00000000000..57bccfabd91 --- /dev/null +++ b/drivers/w1/Kconfig.zephyr_gpio @@ -0,0 +1,28 @@ +# Configuration options for the Zephyr GPIO 1-Wire Master driver + +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +config W1_ZEPHYR_GPIO + bool "1-wire GPIO" + default y + depends on DT_HAS_ZEPHYR_W1_GPIO_ENABLED + help + This option enables the Zephyr GPIO 1-Wire master driver. + + The bus reset, and bit read and write operations are executed + via byte read and write operations on top of the Zephyr + GPIO driver interface. + +if W1_ZEPHYR_GPIO + +config W1_ZEPHYR_GPIO_TIME_CRITICAL + bool "Force time critical operations" + default y + help + This option forces the 1-Wire GPIO driver to use time critical + operations for bus reset, and bit read and write operations. + Time critical communications operations are not interrupted while + being generated. + +endif # W1_ZEPHYR_GPIO diff --git a/drivers/w1/w1_zephyr_gpio.c b/drivers/w1/w1_zephyr_gpio.c new file mode 100644 index 00000000000..090df881122 --- /dev/null +++ b/drivers/w1/w1_zephyr_gpio.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2023 Hudson C. Dalpra + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_w1_gpio + +/** + * @brief 1-Wire Bus Master driver using Zephyr GPIO interface. + * + * This file contains the implementation of the 1-Wire Bus Master driver using + * the Zephyr GPIO interface. The driver is based on GPIO bit-banging and + * follows the timing specifications for 1-Wire communication. + * + * The driver supports both standard speed and overdrive speed modes. + * + * This driver is heavily based on the w1_zephyr_serial.c driver and the + * technical documentation from Maxim Integrated. + * + * - w1_zephyr_serial.c: drivers/w1/w1_zephyr_serial.c + * - Maxim Integrated 1-Wire Communication Through Software: + * https://www.analog.com/en/technical-articles/1wire-communication-through-software.html + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(w1_gpio, CONFIG_W1_LOG_LEVEL); + +/* + * The time critical sections are used to ensure that the timing + * between communication operations is correct. + */ +#if defined(CONFIG_W1_ZEPHYR_GPIO_TIME_CRITICAL) +#define W1_GPIO_ENTER_CRITICAL() irq_lock() +#define W1_GPIO_EXIT_CRITICAL(key) irq_unlock(key) +#define W1_GPIO_WAIT_US(us) k_busy_wait(us) +#else +#define W1_GPIO_ENTER_CRITICAL() 0u +#define W1_GPIO_EXIT_CRITICAL(key) (void)key +#define W1_GPIO_WAIT_US(us) k_usleep(us) +#endif + +/* + * Standard timing between communication operations: + */ +#define W1_GPIO_TIMING_STD_A 6u +#define W1_GPIO_TIMING_STD_B 64u +#define W1_GPIO_TIMING_STD_C 60u +#define W1_GPIO_TIMING_STD_D 10u +#define W1_GPIO_TIMING_STD_E 9u +#define W1_GPIO_TIMING_STD_F 55u +#define W1_GPIO_TIMING_STD_G 0u +#define W1_GPIO_TIMING_STD_H 480u +#define W1_GPIO_TIMING_STD_I 70u +#define W1_GPIO_TIMING_STD_J 410u + +/* + * Overdrive timing between communication operations: + * + * Not completely correct since the overdrive communication requires + * delays of 2.5us, 7.5us and 8.5us. + * The delays are approximated by flooring the values. + */ +#define W1_GPIO_TIMING_OD_A 1u +#define W1_GPIO_TIMING_OD_B 7u +#define W1_GPIO_TIMING_OD_C 7u +#define W1_GPIO_TIMING_OD_D 2u +#define W1_GPIO_TIMING_OD_E 1u +#define W1_GPIO_TIMING_OD_F 7u +#define W1_GPIO_TIMING_OD_G 2u +#define W1_GPIO_TIMING_OD_H 70u +#define W1_GPIO_TIMING_OD_I 8u +#define W1_GPIO_TIMING_OD_J 40u + +struct w1_gpio_timing { + uint16_t a; + uint16_t b; + uint16_t c; + uint16_t d; + uint16_t e; + uint16_t f; + uint16_t g; + uint16_t h; + uint16_t i; + uint16_t j; +}; + +struct w1_gpio_config { + /** w1 master config, common to all drivers */ + struct w1_master_config master_config; + /** GPIO device used for 1-Wire communication */ + const struct gpio_dt_spec spec; +}; + +struct w1_gpio_data { + /** w1 master data, common to all drivers */ + struct w1_master_data master_data; + /** timing parameters for 1-Wire communication */ + const struct w1_gpio_timing *timing; + /** overdrive speed mode active */ + bool overdrive_active; +}; + +static const struct w1_gpio_timing std = { + .a = W1_GPIO_TIMING_STD_A, + .b = W1_GPIO_TIMING_STD_B, + .c = W1_GPIO_TIMING_STD_C, + .d = W1_GPIO_TIMING_STD_D, + .e = W1_GPIO_TIMING_STD_E, + .f = W1_GPIO_TIMING_STD_F, + .g = W1_GPIO_TIMING_STD_G, + .h = W1_GPIO_TIMING_STD_H, + .i = W1_GPIO_TIMING_STD_I, + .j = W1_GPIO_TIMING_STD_J, +}; + +static const struct w1_gpio_timing od = { + .a = W1_GPIO_TIMING_OD_A, + .b = W1_GPIO_TIMING_OD_B, + .c = W1_GPIO_TIMING_OD_C, + .d = W1_GPIO_TIMING_OD_D, + .e = W1_GPIO_TIMING_OD_E, + .f = W1_GPIO_TIMING_OD_F, + .g = W1_GPIO_TIMING_OD_G, + .h = W1_GPIO_TIMING_OD_H, + .i = W1_GPIO_TIMING_OD_I, + .j = W1_GPIO_TIMING_OD_J, +}; + +static int w1_gpio_reset_bus(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + W1_GPIO_WAIT_US(timing->g); + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->h); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->i); + ret = gpio_pin_get_dt(spec) ^ 0x01; + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->j); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_read_bit(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->a); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->e); + ret = gpio_pin_get_dt(spec) & 0x01; + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(timing->f); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_write_bit(const struct device *dev, const bool bit) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct w1_gpio_data *data = dev->data; + + const struct gpio_dt_spec *spec = &cfg->spec; + const struct w1_gpio_timing *timing = data->timing; + + int ret = 0; + unsigned int key = W1_GPIO_ENTER_CRITICAL(); + + ret = gpio_pin_set_dt(spec, 0); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(bit ? timing->a : timing->c); + ret = gpio_pin_set_dt(spec, 1); + if (ret < 0) { + goto out; + } + + W1_GPIO_WAIT_US(bit ? timing->b : timing->d); +out: + W1_GPIO_EXIT_CRITICAL(key); + return ret; +} + +static int w1_gpio_read_byte(const struct device *dev) +{ + int ret = 0; + int byte = 0x00; + + for (int i = 0; i < 8; i++) { + ret = w1_gpio_read_bit(dev); + if (ret < 0) { + return ret; + } + + byte >>= 1; + if (ret) { + byte |= 0x80; + } + } + + return byte; +} + +static int w1_gpio_write_byte(const struct device *dev, const uint8_t byte) +{ + int ret = 0; + uint8_t write = byte; + + for (int i = 0; i < 8; i++) { + ret = w1_gpio_write_bit(dev, write & 0x01); + if (ret < 0) { + return ret; + } + write >>= 1; + } + + return ret; +} + +static int w1_gpio_configure(const struct device *dev, enum w1_settings_type type, uint32_t value) +{ + struct w1_gpio_data *data = dev->data; + + switch (type) { + case W1_SETTING_SPEED: + data->overdrive_active = (value != 0); + data->timing = data->overdrive_active ? &od : &std; + return 0; + default: + return -ENOTSUP; + } +} + +static int w1_gpio_init(const struct device *dev) +{ + const struct w1_gpio_config *cfg = dev->config; + const struct gpio_dt_spec *spec = &cfg->spec; + struct w1_gpio_data *data = dev->data; + + if (gpio_is_ready_dt(spec)) { + int ret = gpio_pin_configure_dt(spec, GPIO_OUTPUT_INACTIVE | GPIO_OPEN_DRAIN | + GPIO_PULL_UP); + if (ret < 0) { + LOG_ERR("Failed to configure GPIO port %s pin %d", spec->port->name, + spec->pin); + return ret; + } + } else { + LOG_ERR("GPIO port %s is not ready", spec->port->name); + return -ENODEV; + } + + data->timing = &std; + data->overdrive_active = false; + + LOG_DBG("w1-gpio initialized, with %d slave devices", cfg->master_config.slave_count); + return 0; +} + +static const struct w1_driver_api w1_gpio_driver_api = { + .reset_bus = w1_gpio_reset_bus, + .read_bit = w1_gpio_read_bit, + .write_bit = w1_gpio_write_bit, + .read_byte = w1_gpio_read_byte, + .write_byte = w1_gpio_write_byte, + .configure = w1_gpio_configure, +}; + +#define W1_ZEPHYR_GPIO_INIT(inst) \ + static const struct w1_gpio_config w1_gpio_cfg_##inst = { \ + .master_config.slave_count = W1_INST_SLAVE_COUNT(inst), \ + .spec = GPIO_DT_SPEC_INST_GET(inst, gpios)}; \ + static struct w1_gpio_data w1_gpio_data_##inst = {}; \ + DEVICE_DT_INST_DEFINE(inst, &w1_gpio_init, NULL, &w1_gpio_data_##inst, \ + &w1_gpio_cfg_##inst, POST_KERNEL, CONFIG_W1_INIT_PRIORITY, \ + &w1_gpio_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(W1_ZEPHYR_GPIO_INIT) diff --git a/drivers/watchdog/Kconfig.nrfx b/drivers/watchdog/Kconfig.nrfx index 52cf45dc068..2967fe86489 100644 --- a/drivers/watchdog/Kconfig.nrfx +++ b/drivers/watchdog/Kconfig.nrfx @@ -9,5 +9,9 @@ config WDT_NRFX depends on DT_HAS_NORDIC_NRF_WDT_ENABLED select NRFX_WDT0 if HAS_HW_NRF_WDT0 select NRFX_WDT1 if HAS_HW_NRF_WDT1 + select NRFX_WDT30 if HAS_HW_NRF_WDT30 + select NRFX_WDT31 if HAS_HW_NRF_WDT31 + select NRFX_WDT130 if HAS_HW_NRF_WDT130 + help Enable support for nrfx WDT driver for nRF MCU series. diff --git a/drivers/watchdog/wdt_andes_atcwdt200.c b/drivers/watchdog/wdt_andes_atcwdt200.c index 62a9677b96d..5fca0026805 100644 --- a/drivers/watchdog/wdt_andes_atcwdt200.c +++ b/drivers/watchdog/wdt_andes_atcwdt200.c @@ -7,7 +7,6 @@ #define DT_DRV_COMPAT andestech_atcwdt200 #include -#include #include #define LOG_LEVEL CONFIG_WDT_LOG_LEVEL diff --git a/drivers/watchdog/wdt_dw.c b/drivers/watchdog/wdt_dw.c index f41b3b1b2cd..657001b1b5c 100644 --- a/drivers/watchdog/wdt_dw.c +++ b/drivers/watchdog/wdt_dw.c @@ -11,55 +11,77 @@ #include #include #include +#include +#include #include "wdt_dw.h" #include "wdt_dw_common.h" LOG_MODULE_REGISTER(wdt_dw, CONFIG_WDT_LOG_LEVEL); -#define WDT_IS_INST_IRQ_EN(inst) DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts) -#define WDT_CHECK_INTERRUPT_USED(inst) WDT_IS_INST_IRQ_EN(inst) || -#define WDT_DW_INTERRUPT_SUPPORT DT_INST_FOREACH_STATUS_OKAY(WDT_CHECK_INTERRUPT_USED) 0 - /* Device run time data */ struct dw_wdt_dev_data { + /* MMIO mapping information for watchdog register base address */ + DEVICE_MMIO_RAM; + /* Clock frequency */ + uint32_t clk_freq; uint32_t config; -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) wdt_callback_t callback; #endif }; /* Device constant configuration parameters */ struct dw_wdt_dev_cfg { - uint32_t base; - uint32_t clk_freq; -#if WDT_DW_INTERRUPT_SUPPORT + DEVICE_MMIO_ROM; + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) + /* Clock controller dev instance */ + const struct device *clk_dev; + /* Identifier for timer to get clock freq from clk manager */ + clock_control_subsys_t clkid; +#endif +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) void (*irq_config)(void); #endif uint8_t reset_pulse_length; +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + /* Reset controller device configurations */ + struct reset_dt_spec reset_spec; +#endif }; static int dw_wdt_setup(const struct device *dev, uint8_t options) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); + int ret; - dw_wdt_check_options(options); + ret = dw_wdt_check_options(options); + if (ret != 0) { + return ret; + } -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) /* Configure response mode */ - dw_wdt_response_mode_set(dev_config->base, !!dev_data->callback); + dw_wdt_response_mode_set((uint32_t)reg_base, !!dev_data->callback); #endif - return dw_wdt_configure(dev_config->base, dev_data->config); + return dw_wdt_configure((uint32_t)reg_base, dev_data->config); } static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *config) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; + __maybe_unused const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); -#if WDT_DW_INTERRUPT_SUPPORT + if (config == NULL) { + LOG_ERR("watchdog timeout configuration missing"); + return -ENODATA; + } + +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) if (config->callback && !dev_config->irq_config) { #else if (config->callback) { @@ -69,32 +91,62 @@ static int dw_wdt_install_timeout(const struct device *dev, const struct wdt_tim } if (config->flags) { - LOG_ERR("Watchdog behavior is not configurable."); - return -ENOTSUP; + LOG_WRN("Watchdog behavior is not configurable."); } -#ifdef WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) dev_data->callback = config->callback; #endif - return dw_wdt_calc_period(dev_config->base, dev_config->clk_freq, config, + return dw_wdt_calc_period((uint32_t)reg_base, dev_data->clk_freq, config, &dev_data->config); } static int dw_wdt_feed(const struct device *dev, int channel_id) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); /* Only channel 0 is supported */ if (channel_id) { return -EINVAL; } - dw_wdt_counter_restart(dev_config->base); + dw_wdt_counter_restart((uint32_t)reg_base); return 0; } +int dw_wdt_disable(const struct device *dev) +{ + int ret = -ENOTSUP; + /* + * Once watchdog is enabled by setting WDT_EN bit watchdog cannot be disabled by clearing + * WDT_EN bit and to disable/clear WDT_EN bit watchdog IP should undergo reset + */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + const struct dw_wdt_dev_cfg *const dev_config = dev->config; + + /* + * Assert and de-assert reset only if the reset prop is defined in the device + * tree node for this dev instance + */ + if (dev_config->reset_spec.dev != NULL) { + if (!device_is_ready(dev_config->reset_spec.dev)) { + LOG_ERR("reset controller device not ready"); + return -ENODEV; + } + + /* Assert and de-assert reset watchdog */ + ret = reset_line_toggle(dev_config->reset_spec.dev, dev_config->reset_spec.id); + if (ret != 0) { + LOG_ERR("watchdog disable/reset failed"); + return ret; + } + } +#endif + return ret; +} + static const struct wdt_driver_api dw_wdt_api = { .setup = dw_wdt_setup, .disable = dw_wdt_disable, @@ -104,31 +156,69 @@ static const struct wdt_driver_api dw_wdt_api = { static int dw_wdt_init(const struct device *dev) { + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); const struct dw_wdt_dev_cfg *const dev_config = dev->config; int ret; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); + + /* Reset watchdog controller if reset controller is supported */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(resets) + ret = dw_wdt_disable(dev); + if (ret != 0) { + return ret; + } +#endif - ret = dw_wdt_probe(dev_config->base, dev_config->reset_pulse_length); + /* Get clock frequency from the clock manager if supported */ +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(clocks) + struct dw_wdt_dev_data *const dev_data = dev->data; + + if (!device_is_ready(dev_config->clk_dev)) { + LOG_ERR("Clock controller device not ready"); + return -ENODEV; + } + + ret = clock_control_get_rate(dev_config->clk_dev, dev_config->clkid, + &dev_data->clk_freq); + if (ret != 0) { + LOG_ERR("Failed to get watchdog clock rate"); + return ret; + } +#endif + ret = dw_wdt_probe((uint32_t)reg_base, dev_config->reset_pulse_length); if (ret) return ret; -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) if (dev_config->irq_config) { dev_config->irq_config(); } #endif + /* + * Enable watchdog if it needs to be enabled at boot. + * watchdog timer will be started with maximum timeout + * that is the default value. + */ + if (!IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) { + dw_wdt_enable((uint32_t)reg_base); + } + return 0; } -#if WDT_DW_INTERRUPT_SUPPORT +#if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) static void dw_wdt_isr(const struct device *dev) { - const struct dw_wdt_dev_cfg *const dev_config = dev->config; struct dw_wdt_dev_data *const dev_data = dev->data; + uintptr_t reg_base = DEVICE_MMIO_GET(dev); - if (dw_wdt_interrupt_status_register_get(dev_config->base)) { - dw_wdt_clear_interrupt(dev_config->base); + if (dw_wdt_interrupt_status_register_get((uint32_t)reg_base)) { + /* + * Clearing interrupt here will not assert system reset, so interrupt + * will not be cleared here. + */ if (dev_data->callback) { dev_data->callback(dev, 0); } @@ -143,30 +233,46 @@ static void dw_wdt_isr(const struct device *dev) #error Clock frequency not configured! #endif +/* Bindings to the platform */ +#define DW_WDT_IRQ_FLAGS(inst) \ + COND_CODE_1(DT_INST_IRQ_HAS_CELL(inst, sense), (DT_INST_IRQ(inst, sense)), (0)) + +#define DW_WDT_RESET_SPEC_INIT(inst) \ + .reset_spec = RESET_DT_SPEC_INST_GET(inst), + #define IRQ_CONFIG(inst) \ static void dw_wdt##inst##_irq_config(void) \ { \ IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), dw_wdt_isr, \ - DEVICE_DT_INST_GET(inst), DT_INST_IRQ(inst, sense)); \ + DEVICE_DT_INST_GET(inst), DW_WDT_IRQ_FLAGS(inst)); \ irq_enable(DT_INST_IRQN(inst)); \ } #define DW_WDT_INIT(inst) \ - IF_ENABLED(WDT_IS_INST_IRQ_EN(inst), (IRQ_CONFIG(inst))) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts), (IRQ_CONFIG(inst))) \ \ static const struct dw_wdt_dev_cfg wdt_dw##inst##_config = { \ - .base = DT_INST_REG_ADDR(inst), \ - COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ - (.clk_freq = DT_INST_PROP(inst, clock_frequency)), \ - (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)) \ - ), \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ .reset_pulse_length = ilog2(DT_INST_PROP_OR(inst, reset_pulse_length, 2)) - 1, \ - IF_ENABLED(WDT_IS_INST_IRQ_EN(inst), \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, resets), \ + (DW_WDT_RESET_SPEC_INIT(inst))) \ + IF_ENABLED(DT_PHA_HAS_CELL(DT_DRV_INST(inst), clocks, clkid), \ + ( \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clkid = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(inst, clkid), \ + )) \ + IF_ENABLED(DT_NODE_HAS_PROP(DT_DRV_INST(inst), interrupts), \ (.irq_config = dw_wdt##inst##_irq_config,) \ ) \ }; \ \ - static struct dw_wdt_dev_data wdt_dw##inst##_data; \ + static struct dw_wdt_dev_data wdt_dw##inst##_data = { \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, clock_frequency), \ + (.clk_freq = DT_INST_PROP(inst, clock_frequency)), \ + (COND_CODE_1(DT_PHA_HAS_CELL(DT_DRV_INST(inst), clocks, clkid), \ + (.clk_freq = 0), \ + (.clk_freq = DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency))))), \ + }; \ \ DEVICE_DT_INST_DEFINE(inst, &dw_wdt_init, NULL, &wdt_dw##inst##_data, \ &wdt_dw##inst##_config, POST_KERNEL, \ diff --git a/drivers/watchdog/wdt_dw_common.c b/drivers/watchdog/wdt_dw_common.c index 7c7a1532d15..3f8bce57ce6 100644 --- a/drivers/watchdog/wdt_dw_common.c +++ b/drivers/watchdog/wdt_dw_common.c @@ -20,13 +20,11 @@ LOG_MODULE_REGISTER(wdt_dw_common, CONFIG_WDT_LOG_LEVEL); int dw_wdt_check_options(const uint8_t options) { if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { - LOG_ERR("Pausing watchdog by debugger is not supported."); - return -ENOTSUP; + LOG_WRN("Pausing watchdog by debugger is not configurable"); } if (options & WDT_OPT_PAUSE_IN_SLEEP) { - LOG_ERR("Pausing watchdog in sleep is not supported."); - return -ENOTSUP; + LOG_WRN("Pausing watchdog in sleep is not configurable"); } return 0; @@ -103,8 +101,3 @@ int dw_wdt_probe(const uint32_t base, const uint32_t reset_pulse_length) return 0; } - -int dw_wdt_disable(const struct device *dev) -{ - return -ENOTSUP; -} diff --git a/drivers/watchdog/wdt_intel_adsp.c b/drivers/watchdog/wdt_intel_adsp.c index c0e2c0a7d36..9a30ea4f45b 100644 --- a/drivers/watchdog/wdt_intel_adsp.c +++ b/drivers/watchdog/wdt_intel_adsp.c @@ -72,7 +72,7 @@ static int intel_adsp_wdt_setup(const struct device *dev, uint8_t options) return ret; } - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + for (i = 0; i < arch_num_cpus(); i++) { ret = dw_wdt_configure(dev_data->core_wdt[i], dev_data->period_cfg); if (ret) { return ret; @@ -120,7 +120,7 @@ static int intel_adsp_wdt_feed(const struct device *dev, int channel_id) { struct intel_adsp_wdt_dev_data *const dev_data = dev->data; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } @@ -154,7 +154,7 @@ static int intel_adsp_wdt_init(const struct device *dev) unsigned int i; int ret; - for (i = 0; i < CONFIG_MP_MAX_NUM_CPUS; i++) { + for (i = 0; i < arch_num_cpus(); i++) { dev_data->core_wdt[i] = intel_adsp_wdt_pointer_get(dev_config->base, i); ret = dw_wdt_probe(dev_data->core_wdt[i], reset_pulse_length); if (ret) { @@ -183,7 +183,7 @@ int intel_adsp_watchdog_pause(const struct device *dev, const int channel_id) { const struct intel_adsp_wdt_dev_cfg *const dev_config = dev->config; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } @@ -203,7 +203,7 @@ int intel_adsp_watchdog_resume(const struct device *dev, const int channel_id) { const struct intel_adsp_wdt_dev_cfg *const dev_config = dev->config; - if (channel_id >= CONFIG_MP_MAX_NUM_CPUS) { + if (channel_id >= arch_num_cpus()) { return -EINVAL; } @@ -211,6 +211,11 @@ int intel_adsp_watchdog_resume(const struct device *dev, const int channel_id) return 0; } +int dw_wdt_disable(const struct device *dev) +{ + return -ENOTSUP; +} + static const struct wdt_driver_api intel_adsp_wdt_api = { .setup = intel_adsp_wdt_setup, .disable = dw_wdt_disable, diff --git a/drivers/watchdog/wdt_nrfx.c b/drivers/watchdog/wdt_nrfx.c index 98fcb713b81..8967d1e162b 100644 --- a/drivers/watchdog/wdt_nrfx.c +++ b/drivers/watchdog/wdt_nrfx.c @@ -145,8 +145,12 @@ static const struct wdt_driver_api wdt_nrfx_driver_api = { .feed = wdt_nrf_feed, }; -static void wdt_event_handler(const struct device *dev, uint32_t requests) +static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_type, + uint32_t requests, void *p_context) { + (void)event_type; + (void)p_context; + struct wdt_nrfx_data *data = dev->data; while (requests) { @@ -162,9 +166,12 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) #define WDT(idx) DT_NODELABEL(wdt##idx) #define WDT_NRFX_WDT_DEVICE(idx) \ - static void wdt_##idx##_event_handler(uint32_t requests) \ + static void wdt_##idx##_event_handler(nrf_wdt_event_t event_type, \ + uint32_t requests, \ + void *p_context) \ { \ - wdt_event_handler(DEVICE_DT_GET(WDT(idx)), requests); \ + wdt_event_handler(DEVICE_DT_GET(WDT(idx)), event_type, \ + requests, p_context); \ } \ static int wdt_##idx##_init(const struct device *dev) \ { \ @@ -174,7 +181,8 @@ static void wdt_event_handler(const struct device *dev, uint32_t requests) nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \ err_code = nrfx_wdt_init(&config->wdt, \ NULL, \ - wdt_##idx##_event_handler); \ + wdt_##idx##_event_handler, \ + NULL); \ if (err_code != NRFX_SUCCESS) { \ return -EBUSY; \ } \ @@ -202,3 +210,15 @@ WDT_NRFX_WDT_DEVICE(0); #ifdef CONFIG_HAS_HW_NRF_WDT1 WDT_NRFX_WDT_DEVICE(1); #endif + +#ifdef CONFIG_HAS_HW_NRF_WDT30 +WDT_NRFX_WDT_DEVICE(30); +#endif + +#ifdef CONFIG_HAS_HW_NRF_WDT31 +WDT_NRFX_WDT_DEVICE(31); +#endif + +#ifdef CONFIG_HAS_HW_NRF_WDT130 +WDT_NRFX_WDT_DEVICE(130); +#endif diff --git a/drivers/watchdog/wdt_rpi_pico.c b/drivers/watchdog/wdt_rpi_pico.c index 83285ba659e..7d3f2a5fc60 100644 --- a/drivers/watchdog/wdt_rpi_pico.c +++ b/drivers/watchdog/wdt_rpi_pico.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -19,7 +20,7 @@ LOG_MODULE_REGISTER(wdt_rpi_pico, CONFIG_WDT_LOG_LEVEL); #define RPI_PICO_WDT_TIME_MULTIPLICATION_FACTOR 2 /* Watchdog requires a 1MHz clock source, divided from the crystal oscillator */ -#define RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR 1000000 +#define RPI_PICO_CLK_REF_FREQ_WDT_TICK_DIVISOR 1000000 struct wdt_rpi_pico_data { uint8_t reset_type; @@ -28,13 +29,16 @@ struct wdt_rpi_pico_data { }; struct wdt_rpi_pico_config { - uint32_t xtal_frequency; + const struct device *clk_dev; + clock_control_subsys_t clk_id; }; static int wdt_rpi_pico_setup(const struct device *dev, uint8_t options) { const struct wdt_rpi_pico_config *config = dev->config; struct wdt_rpi_pico_data *data = dev->data; + uint32_t ref_clk; + int err; if ((options & WDT_OPT_PAUSE_IN_SLEEP) == 1) { return -ENOTSUP; @@ -75,7 +79,17 @@ static int wdt_rpi_pico_setup(const struct device *dev, uint8_t options) data->enabled = true; - watchdog_hw->tick = (config->xtal_frequency / RPI_PICO_XTAL_FREQ_WDT_TICK_DIVISOR) | + err = clock_control_on(config->clk_dev, config->clk_id); + if (err < 0) { + return err; + } + + err = clock_control_get_rate(config->clk_dev, config->clk_id, &ref_clk); + if (err < 0) { + return err; + } + + watchdog_hw->tick = (ref_clk / RPI_PICO_CLK_REF_FREQ_WDT_TICK_DIVISOR) | WATCHDOG_TICK_ENABLE_BITS; return 0; @@ -157,7 +171,8 @@ static const struct wdt_driver_api wdt_rpi_pico_driver_api = { #define WDT_RPI_PICO_WDT_DEVICE(idx) \ static const struct wdt_rpi_pico_config wdt_##idx##_config = { \ - .xtal_frequency = DT_INST_PROP_BY_PHANDLE(idx, clocks, clock_frequency) \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \ + .clk_id = (clock_control_subsys_t)DT_INST_PHA_BY_IDX(idx, clocks, 0, clk_id), \ }; \ static struct wdt_rpi_pico_data wdt_##idx##_data = { \ .reset_type = WDT_FLAG_RESET_SOC, \ diff --git a/drivers/wifi/esp32/src/esp_wifi_drv.c b/drivers/wifi/esp32/src/esp_wifi_drv.c index bb89f3e8d2d..2e86ef39552 100644 --- a/drivers/wifi/esp32/src/esp_wifi_drv.c +++ b/drivers/wifi/esp32/src/esp_wifi_drv.c @@ -6,8 +6,6 @@ #define DT_DRV_COMPAT espressif_esp32_wifi -#define _POSIX_C_SOURCE 200809 - #include LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL); @@ -15,6 +13,7 @@ LOG_MODULE_REGISTER(esp32_wifi, CONFIG_WIFI_LOG_LEVEL); #include #include #include +#include #include #include #include "esp_networking_priv.h" @@ -236,25 +235,44 @@ static void scan_done_handler(void) static void esp_wifi_handle_connect_event(void) { esp32_data.state = ESP32_STA_CONNECTED; - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4)) { - net_dhcpv4_start(esp32_wifi_iface); - } else { - wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, 0); - } +#if defined(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4) + net_dhcpv4_start(esp32_wifi_iface); +#else + wifi_mgmt_raise_connect_result_event(esp32_wifi_iface, 0); +#endif } -static void esp_wifi_handle_disconnect_event(void) +static void esp_wifi_handle_disconnect_event(void *event_data) { + wifi_event_sta_disconnected_t *event = (wifi_event_sta_disconnected_t *)event_data; + if (esp32_data.state == ESP32_STA_CONNECTED) { - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4)) { - net_dhcpv4_stop(esp32_wifi_iface); - } +#if defined(CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4) + net_dhcpv4_stop(esp32_wifi_iface); +#endif wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, 0); } else { wifi_mgmt_raise_disconnect_result_event(esp32_wifi_iface, -1); } - if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_RECONNECT)) { + LOG_DBG("Disconnect reason: %d", event->reason); + switch (event->reason) { + case WIFI_REASON_AUTH_EXPIRE: + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + case WIFI_REASON_AUTH_FAIL: + case WIFI_REASON_HANDSHAKE_TIMEOUT: + case WIFI_REASON_MIC_FAILURE: + LOG_DBG("STA Auth Error"); + break; + case WIFI_REASON_NO_AP_FOUND: + LOG_DBG("AP Not found"); + break; + default: + break; + } + + if (IS_ENABLED(CONFIG_ESP32_WIFI_STA_RECONNECT) && + (event->reason != WIFI_REASON_ASSOC_LEAVE)) { esp32_data.state = ESP32_STA_CONNECTING; esp_wifi_connect(); } else { @@ -286,7 +304,7 @@ static void esp_wifi_event_task(void *p1, void *p2, void *p3) esp_wifi_handle_connect_event(); break; case ESP32_WIFI_EVENT_STA_DISCONNECTED: - esp_wifi_handle_disconnect_event(); + esp_wifi_handle_disconnect_event(&evt.event_info); break; case ESP32_WIFI_EVENT_SCAN_DONE: scan_done_handler(); @@ -655,3 +673,5 @@ NET_DEVICE_DT_INST_DEFINE(0, &esp32_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &esp32_api, ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/esp_at/esp.c b/drivers/wifi/esp_at/esp.c index 1ac21abc560..e71a9b2bc1c 100644 --- a/drivers/wifi/esp_at/esp.c +++ b/drivers/wifi/esp_at/esp.c @@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(wifi_esp_at, CONFIG_WIFI_LOG_LEVEL); #include #include #include +#include #include "esp.h" @@ -443,7 +444,9 @@ static void esp_mgmt_disconnect_work(struct k_work *work) esp_flags_clear(dev, EDF_STA_CONNECTED); esp_mode_switch_submit_if_needed(dev); +#if defined(CONFIG_NET_NATIVE_IPV4) net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); +#endif net_if_dormant_on(dev->net_iface); wifi_mgmt_raise_disconnect_result_event(dev->net_iface, 0); } @@ -509,6 +512,7 @@ static void esp_ip_addr_work(struct k_work *work) return; } +#if defined(CONFIG_NET_NATIVE_IPV4) /* update interface addresses */ net_if_ipv4_set_gw(dev->net_iface, &dev->gw); net_if_ipv4_set_netmask(dev->net_iface, &dev->nm); @@ -516,6 +520,7 @@ static void esp_ip_addr_work(struct k_work *work) net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_MANUAL, 0); #else net_if_ipv4_addr_add(dev->net_iface, &dev->ip, NET_ADDR_DHCP, 0); +#endif #endif if (IS_ENABLED(CONFIG_WIFI_ESP_AT_DNS_USE)) { @@ -761,7 +766,9 @@ MODEM_CMD_DEFINE(on_cmd_ready) dev->flags = 0; dev->mode = 0; +#if defined(CONFIG_NET_NATIVE_IPV4) net_if_ipv4_addr_rm(dev->net_iface, &dev->ip); +#endif k_work_submit_to_queue(&dev->workq, &dev->init_work); return 0; @@ -1278,6 +1285,8 @@ NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, esp_init, NULL, CONFIG_WIFI_INIT_PRIORITY, &esp_api, ESP_MTU); +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); + static int esp_init(const struct device *dev) { #if DT_INST_NODE_HAS_PROP(0, power_gpios) || DT_INST_NODE_HAS_PROP(0, reset_gpios) diff --git a/drivers/wifi/esp_at/esp_socket.c b/drivers/wifi/esp_at/esp_socket.c index e3600ea5366..6a4147e528b 100644 --- a/drivers/wifi/esp_at/esp_socket.c +++ b/drivers/wifi/esp_at/esp_socket.c @@ -151,8 +151,16 @@ void esp_socket_rx(struct esp_socket *sock, struct net_buf *buf, flags = esp_socket_flags(sock); +#ifdef CONFIG_WIFI_ESP_AT_PASSIVE_MODE + /* In Passive Receive mode, ESP modem will buffer rx data and make it still + * available even though the peer has closed the connection. + */ + if (!(flags & ESP_SOCK_CONNECTED) && + !(flags & ESP_SOCK_CLOSE_PENDING)) { +#else if (!(flags & ESP_SOCK_CONNECTED) || (flags & ESP_SOCK_CLOSE_PENDING)) { +#endif LOG_DBG("Received data on closed link %d", sock->link_id); return; } diff --git a/drivers/wifi/eswifi/eswifi_core.c b/drivers/wifi/eswifi/eswifi_core.c index 0beecd4a4fc..82f24982d1a 100644 --- a/drivers/wifi/eswifi/eswifi_core.c +++ b/drivers/wifi/eswifi/eswifi_core.c @@ -23,6 +23,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include #include @@ -806,3 +807,5 @@ NET_DEVICE_DT_INST_OFFLOAD_DEFINE(0, eswifi_init, NULL, CONFIG_WIFI_INIT_PRIORITY, &eswifi_offload_api, 1500); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c index c0c780822d8..752e6c9048a 100644 --- a/drivers/wifi/infineon/airoc_wifi.c +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -12,6 +12,7 @@ #define DT_DRV_COMPAT infineon_airoc_wifi #include +#include #include LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); @@ -770,3 +771,5 @@ static const struct net_wifi_mgmt_offload airoc_api = { NET_DEVICE_DT_INST_DEFINE(0, airoc_init, NULL, &airoc_wifi_data, &airoc_wifi_config, CONFIG_WIFI_INIT_PRIORITY, &airoc_api, ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), WHD_LINK_MTU); + +CONNECTIVITY_WIFI_MGMT_BIND(Z_DEVICE_DT_DEV_ID(DT_DRV_INST(0))); diff --git a/drivers/wifi/simplelink/simplelink.c b/drivers/wifi/simplelink/simplelink.c index 6e89275ee6f..c4af70ce003 100644 --- a/drivers/wifi/simplelink/simplelink.c +++ b/drivers/wifi/simplelink/simplelink.c @@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #ifdef CONFIG_NET_SOCKETS_OFFLOAD #include #endif @@ -302,3 +303,5 @@ NET_DEVICE_OFFLOAD_INIT(simplelink, CONFIG_WIFI_SIMPLELINK_NAME, &simplelink_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &simplelink_api, CONFIG_WIFI_SIMPLELINK_MAX_PACKET_SIZE); + +CONNECTIVITY_WIFI_MGMT_BIND(simplelink); diff --git a/drivers/wifi/winc1500/wifi_winc1500.c b/drivers/wifi/winc1500/wifi_winc1500.c index 95d97fcfeaa..588a2e3e0dc 100644 --- a/drivers/wifi/winc1500/wifi_winc1500.c +++ b/drivers/wifi/winc1500/wifi_winc1500.c @@ -21,6 +21,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include +#include #include @@ -1187,3 +1188,5 @@ NET_DEVICE_OFFLOAD_INIT(winc1500, CONFIG_WIFI_WINC1500_NAME, winc1500_init, NULL, &w1500_data, NULL, CONFIG_WIFI_INIT_PRIORITY, &winc1500_api, CONFIG_WIFI_WINC1500_MAX_PACKET_SIZE); + +CONNECTIVITY_WIFI_MGMT_BIND(winc1500); diff --git a/dts/arc/synopsys/arc_hs4xd.dtsi b/dts/arc/synopsys/arc_hs4xd.dtsi index 18a555cfbd4..d6650e651a9 100644 --- a/dts/arc/synopsys/arc_hs4xd.dtsi +++ b/dts/arc/synopsys/arc_hs4xd.dtsi @@ -185,6 +185,7 @@ reg = <0xf0020000 0x100>; interrupts = <40 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -195,6 +196,7 @@ reg = <0xf0021000 0x100>; interrupts = <41 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -205,6 +207,7 @@ reg = <0xf0022000 0x100>; interrupts = <42 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; }; diff --git a/dts/arc/synopsys/arc_hsdk.dtsi b/dts/arc/synopsys/arc_hsdk.dtsi index bb127594e2e..6388db825a0 100644 --- a/dts/arc/synopsys/arc_hsdk.dtsi +++ b/dts/arc/synopsys/arc_hsdk.dtsi @@ -185,6 +185,7 @@ reg = <0xf0020000 0x1000>; interrupts = <40 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -195,6 +196,7 @@ reg = <0xf0021000 0x1000>; interrupts = <41 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; @@ -205,6 +207,7 @@ reg = <0xf0022000 0x1000>; interrupts = <42 1>; fifo-depth = <32>; + max-xfer-size = <16>; status = "disabled"; }; diff --git a/dts/arc/synopsys/arc_iot.dtsi b/dts/arc/synopsys/arc_iot.dtsi index 7d04321e0ee..1c809d1b0f8 100644 --- a/dts/arc/synopsys/arc_iot.dtsi +++ b/dts/arc/synopsys/arc_iot.dtsi @@ -233,6 +233,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010000 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <70 2>, <71 2>, <72 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; @@ -245,6 +246,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010100 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <74 2>, <75 2>, <76 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; @@ -257,6 +259,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x80010200 0x100>; + max-xfer-size = <16>; clocks = <&sysclk>; interrupts = <78 2>, <79 2>, <80 2>; interrupt-names = "err-int", "rx-avail", "tx-req"; diff --git a/dts/arc/synopsys/emsdp.dtsi b/dts/arc/synopsys/emsdp.dtsi index 375eb745594..1d7c4cf238c 100644 --- a/dts/arc/synopsys/emsdp.dtsi +++ b/dts/arc/synopsys/emsdp.dtsi @@ -95,6 +95,7 @@ reg = <0xf0008000 0x1000>; clocks = <&spiclk>; fifo-depth = <32>; + max-xfer-size = <16>; interrupt-parent = <&intc>; #address-cells = <1>; #size-cells = <0>; @@ -112,6 +113,7 @@ reg = <0xf1000000 0x1000>; clocks = <&spiclk>; fifo-depth = <32>; + max-xfer-size = <16>; interrupt-parent = <&intc>; #address-cells = <1>; #size-cells = <0>; @@ -135,8 +137,9 @@ interrupts = <63 2>, <64 2>, <65 2>; interrupt-names = "err_int", "rx_avail", "tx_req"; interrupt-parent = <&intc>; - aux_reg; + aux-reg; fifo-depth = <16>; + max-xfer-size = <16>; }; /* DFSS-SPI1 */ @@ -149,8 +152,9 @@ interrupts = <67 2>, <68 2>, <69 2>; interrupt-names = "err_int", "rx_avail", "tx_req"; interrupt-parent = <&intc>; - aux_reg; + aux-reg; fifo-depth = <16>; + max-xfer-size = <16>; }; }; }; diff --git a/dts/arc/synopsys/emsk.dtsi b/dts/arc/synopsys/emsk.dtsi index a701d2412ee..117421c228f 100644 --- a/dts/arc/synopsys/emsk.dtsi +++ b/dts/arc/synopsys/emsk.dtsi @@ -148,6 +148,7 @@ clocks = <&sysclk>; interrupt-parent = <&intc>; fifo-depth = <32>; + max-xfer-size = <16>; #address-cells = <1>; #size-cells = <0>; @@ -159,6 +160,7 @@ clocks = <&sysclk>; interrupt-parent = <&intc>; fifo-depth = <32>; + max-xfer-size = <16>; #address-cells = <1>; #size-cells = <0>; diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 3f722ae282f..a3abd1093e9 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -2,13 +2,15 @@ #include #include +#include #include +#include / { clocks { uartclk: apb-pclk { compatible = "fixed-clock"; - clock-frequency = <24000000>; + clock-frequency = ; #clock-cells = <0>; }; }; @@ -43,6 +45,8 @@ }; soc { + compatible = "ambiq,apollo4p", "ambiq,apollo4x", "simple-bus"; + pwrcfg: pwrcfg@40021000 { compatible = "ambiq,pwrctrl"; reg = <0x40021000 0x400>; @@ -102,7 +106,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x1000>; }; - iom0: iom@40050000 { + iom0_spi: spi@40050000 { + reg = <0x40050000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <6 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x2>; + }; + + iom0_i2c: i2c@40050000 { reg = <0x40050000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -111,7 +124,7 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x2>; }; - iom1: iom@40051000 { + iom1_spi: spi@40051000 { reg = <0x40051000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -120,7 +133,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x4>; }; - iom2: iom@40052000 { + iom1_i2c: i2c@40051000 { + reg = <0x40051000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <7 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x4>; + }; + + iom2_spi: spi@40052000 { reg = <0x40052000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -129,7 +151,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x8>; }; - iom3: iom@40053000 { + iom2_i2c: i2c@40052000 { + reg = <0x40052000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <8 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x8>; + }; + + iom3_spi: spi@40053000 { + reg = <0x40053000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <9 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; + }; + + iom3_i2c: i2c@40053000 { reg = <0x40053000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -137,7 +177,8 @@ status = "disabled"; ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; }; - iom4: iom@40054000 { + + iom4_spi: spi@40054000 { reg = <0x40054000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -146,7 +187,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; }; - iom5: iom@40055000 { + iom4_i2c: i2c@40054000 { + reg = <0x40054000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <10 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; + }; + + iom5_spi: spi@40055000 { + reg = <0x40055000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <11 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x40>; + }; + + iom5_i2c: i2c@40055000 { reg = <0x40055000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -155,7 +214,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x40>; }; - iom6: iom@40056000 { + iom6_spi: spi@40056000 { + reg = <0x40056000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <12 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x80>; + }; + + iom6_i2c: i2c@40056000 { reg = <0x40056000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -164,7 +232,16 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x80>; }; - iom7: iom@40057000 { + iom7_spi: spi@40057000 { + reg = <0x40057000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <13 0>; + status = "disabled"; + ambiq,pwrcfg = <&pwrcfg 0x4 0x100>; + }; + + iom7_i2c: i2c@40057000 { reg = <0x40057000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -206,6 +283,61 @@ pinctrl: pin-controller@40010000 { compatible = "ambiq,apollo4-pinctrl"; reg = <0x40010000 0x800>; + #address-cells = <1>; + #size-cells = <0>; + + gpio: gpio@40010000 { + compatible = "ambiq,gpio"; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + ranges; + + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; + }; }; wdt0: watchdog@40024000 { diff --git a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi index 65166caa335..dfc2f59de3d 100644 --- a/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p_blue.dtsi @@ -4,12 +4,13 @@ #include #include #include +#include / { clocks { uartclk: apb-pclk { compatible = "fixed-clock"; - clock-frequency = <24000000>; + clock-frequency = ; #clock-cells = <0>; }; xo32m: xo32m { @@ -48,6 +49,8 @@ }; soc { + compatible = "ambiq,apollo4p-blue", "ambiq,apollo4x", "simple-bus"; + flash: flash-controller@18000 { compatible = "ambiq,flash-controller"; reg = <0x00018000 0x1e8000>; @@ -157,13 +160,25 @@ ambiq,pwrcfg = <&pwrcfg 0x4 0x10>; }; - iom4: iom@40054000 { + iom4: spi@40054000 { + /* IOM4 works as SPI and is wired internally for BLE HCI. */ + compatible = "ambiq,spi"; reg = <0x40054000 0x1000>; #address-cells = <1>; #size-cells = <0>; interrupts = <10 0>; + cs-gpios = <&gpio32_63 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + clock-frequency = ; status = "disabled"; ambiq,pwrcfg = <&pwrcfg 0x4 0x20>; + + bt-hci@0 { + compatible = "ambiq,bt-hci-spi"; + reg = <0>; + irq-gpios = <&gpio32_63 21 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio32_63 23 GPIO_ACTIVE_LOW>; + clkreq-gpios = <&gpio32_63 20 GPIO_ACTIVE_HIGH>; + }; }; iom5: iom@40055000 { @@ -226,6 +241,61 @@ pinctrl: pin-controller@40010000 { compatible = "ambiq,apollo4-pinctrl"; reg = <0x40010000 0x800>; + #address-cells = <1>; + #size-cells = <0>; + + gpio: gpio@40010000 { + compatible = "ambiq,gpio"; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + ranges; + + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; + }; }; wdt0: watchdog@40024000 { diff --git a/dts/arm/atmel/sam3x.dtsi b/dts/arm/atmel/sam3x.dtsi index 1fc5dbe9733..67d99418fd2 100644 --- a/dts/arm/atmel/sam3x.dtsi +++ b/dts/arm/atmel/sam3x.dtsi @@ -53,6 +53,7 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; #address-cells = <1>; diff --git a/dts/arm/atmel/sam4e.dtsi b/dts/arm/atmel/sam4e.dtsi index 2e9e916eef2..c90fed140b3 100644 --- a/dts/arm/atmel/sam4e.dtsi +++ b/dts/arm/atmel/sam4e.dtsi @@ -33,7 +33,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -79,16 +78,18 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + status = "okay"; #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - - write-block-size = <16>; - erase-block-size = <8192>; + compatible = "atmel,sam-flash", "soc-nv-flash"; + write-block-size = <8>; + erase-block-size = <4096>; }; }; diff --git a/dts/arm/atmel/sam4e16c.dtsi b/dts/arm/atmel/sam4e16c.dtsi index c3c0226e9d4..ffa4b475c91 100644 --- a/dts/arm/atmel/sam4e16c.dtsi +++ b/dts/arm/atmel/sam4e16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4e16e.dtsi b/dts/arm/atmel/sam4e16e.dtsi index c3c0226e9d4..ffa4b475c91 100644 --- a/dts/arm/atmel/sam4e16e.dtsi +++ b/dts/arm/atmel/sam4e16e.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4e8c.dtsi b/dts/arm/atmel/sam4e8c.dtsi index 1af988dfce5..d47729b0f62 100644 --- a/dts/arm/atmel/sam4e8c.dtsi +++ b/dts/arm/atmel/sam4e8c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4e8e.dtsi b/dts/arm/atmel/sam4e8e.dtsi index 1af988dfce5..d47729b0f62 100644 --- a/dts/arm/atmel/sam4e8e.dtsi +++ b/dts/arm/atmel/sam4e8e.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4l.dtsi b/dts/arm/atmel/sam4l.dtsi index 1f11478044f..7f19f8d21a4 100644 --- a/dts/arm/atmel/sam4l.dtsi +++ b/dts/arm/atmel/sam4l.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/sam4s.dtsi b/dts/arm/atmel/sam4s.dtsi index 8c7cf1acc2a..64828f3a7d5 100644 --- a/dts/arm/atmel/sam4s.dtsi +++ b/dts/arm/atmel/sam4s.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -63,16 +62,17 @@ eefc: flash-controller@400e0a00 { compatible = "atmel,sam-flash-controller"; reg = <0x400e0a00 0x200>; + interrupts = <6 0>; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - - write-block-size = <16>; - erase-block-size = <8192>; + compatible = "atmel,sam-flash", "soc-nv-flash"; + write-block-size = <8>; + erase-block-size = <4096>; }; }; diff --git a/dts/arm/atmel/sam4s16b.dtsi b/dts/arm/atmel/sam4s16b.dtsi index 4ab4d64c4a6..f671f6fccc4 100644 --- a/dts/arm/atmel/sam4s16b.dtsi +++ b/dts/arm/atmel/sam4s16b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4s16c.dtsi b/dts/arm/atmel/sam4s16c.dtsi index 4ab4d64c4a6..f671f6fccc4 100644 --- a/dts/arm/atmel/sam4s16c.dtsi +++ b/dts/arm/atmel/sam4s16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2a.dtsi b/dts/arm/atmel/sam4s2a.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2a.dtsi +++ b/dts/arm/atmel/sam4s2a.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2b.dtsi b/dts/arm/atmel/sam4s2b.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2b.dtsi +++ b/dts/arm/atmel/sam4s2b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s2c.dtsi b/dts/arm/atmel/sam4s2c.dtsi index f85ca2b2a61..b57ddb0cec6 100644 --- a/dts/arm/atmel/sam4s2c.dtsi +++ b/dts/arm/atmel/sam4s2c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(128)>; + erase-blocks = <&eefc 8 2048>, <&eefc 28 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4a.dtsi b/dts/arm/atmel/sam4s4a.dtsi index 36d0ba7729b..1ea079b054c 100644 --- a/dts/arm/atmel/sam4s4a.dtsi +++ b/dts/arm/atmel/sam4s4a.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(256)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4b.dtsi b/dts/arm/atmel/sam4s4b.dtsi index 7fbe9118f18..959c4d591e2 100644 --- a/dts/arm/atmel/sam4s4b.dtsi +++ b/dts/arm/atmel/sam4s4b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(356)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s4c.dtsi b/dts/arm/atmel/sam4s4c.dtsi index 36d0ba7729b..1ea079b054c 100644 --- a/dts/arm/atmel/sam4s4c.dtsi +++ b/dts/arm/atmel/sam4s4c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(256)>; + erase-blocks = <&eefc 8 2048>, <&eefc 60 4096>; }; }; diff --git a/dts/arm/atmel/sam4s8b.dtsi b/dts/arm/atmel/sam4s8b.dtsi index f047b4a073b..2e00a78b4d6 100644 --- a/dts/arm/atmel/sam4s8b.dtsi +++ b/dts/arm/atmel/sam4s8b.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4s8c.dtsi b/dts/arm/atmel/sam4s8c.dtsi index f047b4a073b..2e00a78b4d6 100644 --- a/dts/arm/atmel/sam4s8c.dtsi +++ b/dts/arm/atmel/sam4s8c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 124 4096>; }; }; diff --git a/dts/arm/atmel/sam4sa16c.dtsi b/dts/arm/atmel/sam4sa16c.dtsi index ae96e4b27ad..789e482b0f6 100644 --- a/dts/arm/atmel/sam4sa16c.dtsi +++ b/dts/arm/atmel/sam4sa16c.dtsi @@ -12,6 +12,7 @@ flash-controller@400e0a00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; }; }; diff --git a/dts/arm/atmel/samc21.dtsi b/dts/arm/atmel/samc21.dtsi index d3cdfbda777..72b28386a4b 100644 --- a/dts/arm/atmel/samc21.dtsi +++ b/dts/arm/atmel/samc21.dtsi @@ -48,7 +48,7 @@ compatible = "atmel,sam0-can"; reg = <0x42001c00 0x100>; interrupts = <15 0>; - interrupt-names = "LINE_0"; + interrupt-names = "int0"; clocks = <&gclk 26>, <&mclk 0x10 8>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; @@ -62,7 +62,7 @@ compatible = "atmel,sam0-can"; reg = <0x42002000 0x100>; interrupts = <16 0>; - interrupt-names = "LINE_0"; + interrupt-names = "int0"; clocks = <&gclk 27>, <&mclk 0x10 9>; clock-names = "GCLK", "MCLK"; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; diff --git a/dts/arm/atmel/samd5x.dtsi b/dts/arm/atmel/samd5x.dtsi index 5af30c4680b..b64abc5de45 100644 --- a/dts/arm/atmel/samd5x.dtsi +++ b/dts/arm/atmel/samd5x.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/atmel/same5x.dtsi b/dts/arm/atmel/same5x.dtsi index 1d11fa32c97..c4b1762e5b3 100644 --- a/dts/arm/atmel/same5x.dtsi +++ b/dts/arm/atmel/same5x.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 Stephanos Ioannidis + * Copyright (c) 2023 Sebastian Schlupp * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,5 +26,33 @@ #address-cells = <1>; #size-cells = <0>; }; + + can0: can@42000000 { + compatible = "atmel,sam0-can"; + reg = <0x42000000 0x400>; + interrupts = <78 0>, <78 0>; + interrupt-names = "int0", "int1"; + clocks = <&gclk 27>, <&mclk 0x10 17>; + clock-names = "GCLK", "MCLK"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + divider = <12>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; + + can1: can@42000400 { + compatible = "atmel,sam0-can"; + reg = <0x42000400 0x400>; + interrupts = <79 0>, <79 0>; + interrupt-names = "int0", "int1"; + clocks = <&gclk 28>, <&mclk 0x10 18>; + clock-names = "GCLK", "MCLK"; + bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; + divider = <12>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/atmel/same70.dtsi b/dts/arm/atmel/same70.dtsi index 8c378d90d0d..878ad822d68 100644 --- a/dts/arm/atmel/same70.dtsi +++ b/dts/arm/atmel/same70.dtsi @@ -39,7 +39,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; @@ -72,14 +71,13 @@ #address-cells = <1>; #size-cells = <1>; + #erase-block-cells = <2>; flash0: flash@400000 { - compatible = "soc-nv-flash"; - + compatible = "atmel,sam-flash", "soc-nv-flash"; write-block-size = <16>; erase-block-size = <8192>; }; - }; wdt: watchdog@400e1850 { @@ -423,7 +421,7 @@ compatible = "atmel,sam-can"; reg = <0x40030000 0x100>; interrupts = <35 0>, <36 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&pmc PMC_TYPE_PERIPHERAL 35>; divider = <6>; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; @@ -436,7 +434,7 @@ compatible = "atmel,sam-can"; reg = <0x40034000 0x100>; interrupts = <37 0>, <38 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; divider = <6>; bosch,mram-cfg = <0x0 28 8 3 3 0 1 1>; diff --git a/dts/arm/atmel/same70q19.dtsi b/dts/arm/atmel/same70q19.dtsi index e8f3329bd2e..abf0e5b67e5 100644 --- a/dts/arm/atmel/same70q19.dtsi +++ b/dts/arm/atmel/same70q19.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q19b.dtsi b/dts/arm/atmel/same70q19b.dtsi index 0815fdc2dfa..cc97dc64458 100644 --- a/dts/arm/atmel/same70q19b.dtsi +++ b/dts/arm/atmel/same70q19b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q21.dtsi b/dts/arm/atmel/same70q21.dtsi index 494fdc0d026..4138d6ca066 100644 --- a/dts/arm/atmel/same70q21.dtsi +++ b/dts/arm/atmel/same70q21.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/same70q21b.dtsi b/dts/arm/atmel/same70q21b.dtsi index 8f13909f911..d6fe0fa4a2e 100644 --- a/dts/arm/atmel/same70q21b.dtsi +++ b/dts/arm/atmel/same70q21b.dtsi @@ -18,6 +18,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x19.dtsi b/dts/arm/atmel/samv71x19.dtsi index b124cb7cb40..46c1d7a8756 100644 --- a/dts/arm/atmel/samv71x19.dtsi +++ b/dts/arm/atmel/samv71x19.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x19b.dtsi b/dts/arm/atmel/samv71x19b.dtsi index 966c5b27ca3..520c9398151 100644 --- a/dts/arm/atmel/samv71x19b.dtsi +++ b/dts/arm/atmel/samv71x19b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(512)>; + erase-blocks = <&eefc 8 2048>, <&eefc 62 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x20.dtsi b/dts/arm/atmel/samv71x20.dtsi index e251f68feb6..10228d242a2 100644 --- a/dts/arm/atmel/samv71x20.dtsi +++ b/dts/arm/atmel/samv71x20.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 126 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x20b.dtsi b/dts/arm/atmel/samv71x20b.dtsi index c26a88299ad..d425e524aa8 100644 --- a/dts/arm/atmel/samv71x20b.dtsi +++ b/dts/arm/atmel/samv71x20b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(1024)>; + erase-blocks = <&eefc 8 2048>, <&eefc 126 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x21.dtsi b/dts/arm/atmel/samv71x21.dtsi index bd72c69835a..d59fa5be590 100644 --- a/dts/arm/atmel/samv71x21.dtsi +++ b/dts/arm/atmel/samv71x21.dtsi @@ -16,6 +16,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/atmel/samv71x21b.dtsi b/dts/arm/atmel/samv71x21b.dtsi index c7acf1b2530..c55ac8b1284 100644 --- a/dts/arm/atmel/samv71x21b.dtsi +++ b/dts/arm/atmel/samv71x21b.dtsi @@ -17,6 +17,7 @@ flash-controller@400e0c00 { flash0: flash@400000 { reg = <0x00400000 DT_SIZE_K(2048)>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 8192>; }; }; }; diff --git a/dts/arm/broadcom/valkyrie.dtsi b/dts/arm/broadcom/valkyrie.dtsi index e413018022c..03df61fcdae 100644 --- a/dts/arm/broadcom/valkyrie.dtsi +++ b/dts/arm/broadcom/valkyrie.dtsi @@ -21,7 +21,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/broadcom/viper-m7.dtsi b/dts/arm/broadcom/viper-m7.dtsi index 2c0e7e3b25d..85e38616e8b 100644 --- a/dts/arm/broadcom/viper-m7.dtsi +++ b/dts/arm/broadcom/viper-m7.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi b/dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi similarity index 83% rename from dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi rename to dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi index 674016f5e98..98fad6847f0 100644 --- a/dts/arm/gigadevice/gd32a50x/gd32a503vdt3.dtsi +++ b/dts/arm/gd/gd32a50x/gd32a503vdt3.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(384)>; diff --git a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi b/dts/arm/gd/gd32a50x/gd32a50x.dtsi similarity index 99% rename from dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi rename to dts/arm/gd/gd32a50x/gd32a50x.dtsi index 3a3f1bfed49..af54b98f716 100644 --- a/dts/arm/gigadevice/gd32a50x/gd32a50x.dtsi +++ b/dts/arm/gd/gd32a50x/gd32a50x.dtsi @@ -28,7 +28,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -65,7 +64,7 @@ flash0: flash@8000000 { compatible = "gd,gd32-nv-flash-v2", "soc-nv-flash"; - write-block-size = <2>; + write-block-size = <4>; max-erase-time-ms = <2578>; bank0-page-size = ; bank1-page-size = ; diff --git a/dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi b/dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi similarity index 83% rename from dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi rename to dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi index 2229355de43..7f403134076 100644 --- a/dts/arm/gigadevice/gd32e10x/gd32e103vbt6.dtsi +++ b/dts/arm/gd/gd32e10x/gd32e103vbt6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(128)>; diff --git a/dts/arm/gigadevice/gd32e10x/gd32e10x.dtsi b/dts/arm/gd/gd32e10x/gd32e10x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32e10x/gd32e10x.dtsi rename to dts/arm/gd/gd32e10x/gd32e10x.dtsi diff --git a/dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi b/dts/arm/gd/gd32e50x/gd32e507xe.dtsi similarity index 98% rename from dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi rename to dts/arm/gd/gd32e50x/gd32e507xe.dtsi index 37665e54445..c897ad60f8f 100644 --- a/dts/arm/gigadevice/gd32e50x/gd32e507xe.dtsi +++ b/dts/arm/gd/gd32e50x/gd32e507xe.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi b/dts/arm/gd/gd32e50x/gd32e50x.dtsi similarity index 99% rename from dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi rename to dts/arm/gd/gd32e50x/gd32e50x.dtsi index e073dd8ff4e..a02dd5df866 100644 --- a/dts/arm/gigadevice/gd32e50x/gd32e50x.dtsi +++ b/dts/arm/gd/gd32e50x/gd32e50x.dtsi @@ -74,7 +74,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; usart0: usart@40013800 { diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi b/dts/arm/gd/gd32f3x0/gd32f350.dtsi similarity index 88% rename from dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350.dtsi index 43dbe4b3a5d..e9c5af1ab9f 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi b/dts/arm/gd/gd32f3x0/gd32f350g6.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350g6.dtsi index ae878fac1ff..5304ebae045 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350g6.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350g6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(32)>; diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi b/dts/arm/gd/gd32f3x0/gd32f350rb.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi rename to dts/arm/gd/gd32f3x0/gd32f350rb.dtsi index fda4a635993..054a3848c05 100644 --- a/dts/arm/gigadevice/gd32f3x0/gd32f350rb.dtsi +++ b/dts/arm/gd/gd32f3x0/gd32f350rb.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(128)>; diff --git a/dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi b/dts/arm/gd/gd32f3x0/gd32f3x0.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32f3x0/gd32f3x0.dtsi rename to dts/arm/gd/gd32f3x0/gd32f3x0.dtsi diff --git a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi b/dts/arm/gd/gd32f403/gd32f403.dtsi similarity index 99% rename from dts/arm/gigadevice/gd32f403/gd32f403.dtsi rename to dts/arm/gd/gd32f403/gd32f403.dtsi index e4e57417307..0b6ac33245c 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403.dtsi +++ b/dts/arm/gd/gd32f403/gd32f403.dtsi @@ -28,7 +28,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi b/dts/arm/gd/gd32f403/gd32f403zet6.dtsi similarity index 81% rename from dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi rename to dts/arm/gd/gd32f403/gd32f403zet6.dtsi index e93f69691a8..bfe5145e9fb 100644 --- a/dts/arm/gigadevice/gd32f403/gd32f403zet6.dtsi +++ b/dts/arm/gd/gd32f403/gd32f403zet6.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(512)>; diff --git a/dts/arm/gd/gd32f4xx/gd32f405.dtsi b/dts/arm/gd/gd32f4xx/gd32f405.dtsi new file mode 100644 index 00000000000..0d1b1fdef3f --- /dev/null +++ b/dts/arm/gd/gd32f4xx/gd32f405.dtsi @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021, BrainCo Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&cpu0 { + clock-frequency = <168000000>; +}; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi b/dts/arm/gd/gd32f4xx/gd32f405vg.dtsi similarity index 85% rename from dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi rename to dts/arm/gd/gd32f4xx/gd32f405vg.dtsi index ef9a82f8b44..0197c8c4d9e 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f405vg.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f405vg.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi b/dts/arm/gd/gd32f4xx/gd32f407.dtsi similarity index 77% rename from dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407.dtsi index dc4d74b1a28..bfc8d85c01b 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include &cpu0 { clock-frequency = <168000000>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xe.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xe.dtsi index eb3549aa29b..48a8deff114 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xe.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xe.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(512)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xg.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xg.dtsi index 66e3b3a0af6..7bef0eb8d97 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xg.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xg.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(1024)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi b/dts/arm/gd/gd32f4xx/gd32f407xk.dtsi similarity index 80% rename from dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi rename to dts/arm/gd/gd32f4xx/gd32f407xk.dtsi index e85fddb5609..d48f6d75830 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f407xk.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f407xk.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi b/dts/arm/gd/gd32f4xx/gd32f450.dtsi similarity index 95% rename from dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi rename to dts/arm/gd/gd32f4xx/gd32f450.dtsi index c6d5b0e6b0b..b1aea0ba5a5 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f450.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f450.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi b/dts/arm/gd/gd32f4xx/gd32f450xk.dtsi similarity index 78% rename from dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi rename to dts/arm/gd/gd32f4xx/gd32f450xk.dtsi index 98c0c6e4e8d..c1f76b49382 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f450xk.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f450xk.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gd/gd32f4xx/gd32f470.dtsi b/dts/arm/gd/gd32f4xx/gd32f470.dtsi new file mode 100644 index 00000000000..1900a34abad --- /dev/null +++ b/dts/arm/gd/gd32f4xx/gd32f470.dtsi @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2022, Rtone. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&cpu0 { + clock-frequency = ; +}; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi b/dts/arm/gd/gd32f4xx/gd32f470ik.dtsi similarity index 76% rename from dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi rename to dts/arm/gd/gd32f4xx/gd32f470ik.dtsi index dcd74a8b35a..9f074ec7529 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f470ik.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f470ik.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &flash0 { reg = <0x08000000 DT_SIZE_K(3072)>; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi b/dts/arm/gd/gd32f4xx/gd32f4xx.dtsi similarity index 99% rename from dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi rename to dts/arm/gd/gd32f4xx/gd32f4xx.dtsi index 5a0d2aa85ab..f2e35e981e4 100644 --- a/dts/arm/gigadevice/gd32f4xx/gd32f4xx.dtsi +++ b/dts/arm/gd/gd32f4xx/gd32f4xx.dtsi @@ -26,7 +26,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi b/dts/arm/gd/gd32l23x/gd32l233rc.dtsi similarity index 95% rename from dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi rename to dts/arm/gd/gd32l23x/gd32l233rc.dtsi index 8539b3928a4..d8c2f80ee65 100644 --- a/dts/arm/gigadevice/gd32l23x/gd32l233rc.dtsi +++ b/dts/arm/gd/gd32l23x/gd32l233rc.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include / { soc { diff --git a/dts/arm/gigadevice/gd32l23x/gd32l23x.dtsi b/dts/arm/gd/gd32l23x/gd32l23x.dtsi similarity index 100% rename from dts/arm/gigadevice/gd32l23x/gd32l23x.dtsi rename to dts/arm/gd/gd32l23x/gd32l23x.dtsi diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi deleted file mode 100644 index dd31946ff76..00000000000 --- a/dts/arm/gigadevice/gd32f4xx/gd32f405.dtsi +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2021, BrainCo Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -&cpu0 { - clock-frequency = <168000000>; -}; diff --git a/dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi b/dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi deleted file mode 100644 index a77a11763e4..00000000000 --- a/dts/arm/gigadevice/gd32f4xx/gd32f470.dtsi +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2022, Rtone. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -&cpu0 { - clock-frequency = ; -}; diff --git a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi index fd05d415d3a..4506e0c995f 100644 --- a/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024-pinctrl.dtsi @@ -425,4 +425,193 @@ /omit-if-no-ref/ i2c_scl_dout1_p1_10_u0c0: i2c_scl_dout1_p1_10_u0c0 { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_9_mdo: ebu_p0_9_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p1_11_mdo: ebu_p1_11_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p2_0_mdo: ebu_p2_0_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + + /omit-if-no-ref/ eth_p0_9_mdio: eth_p0_9_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_0_mdio: eth_p2_0_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p0_4_tx_en: eth_p0_4_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_5_txd0: eth_p0_5_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_6_txd1: eth_p0_6_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_10_mdc: eth_p0_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_10_mdc: eth_p1_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_12_tx_en: eth_p1_12_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_13_txd0: eth_p1_13_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_14_txd1: eth_p1_14_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_tx_en: eth_p2_5_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_7_mdc: eth_p2_7_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_8_txd0: eth_p2_8_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_9_txd1: eth_p2_9_txd1 { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p2_2_rxd0: eth_p2_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_2_rxd0: eth_p0_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_8_rxd0: eth_p14_8_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_0_rxd0: eth_p5_0_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_3_rxd1: eth_p2_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_3_rxd1: eth_p0_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_9_rxd1: eth_p14_9_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_1_rxd1: eth_p5_1_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_8_rxd2: eth_p5_8_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_4_rxd2: eth_p6_4_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_rxd3: eth_p5_9_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_3_rxd3: eth_p6_3_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_1_clk_rmii: eth_p2_1_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_0_clk_rmii: eth_p0_0_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_8_clk_rmii: eth_p15_8_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_5_clk_rmii: eth_p6_5_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_crs_dv: eth_p2_5_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_1_crs_dv: eth_p0_1_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_9_crs_dv: eth_p15_9_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_2_crs_dv: eth_p5_2_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_11_crs: eth_p5_11_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_4_crs: eth_p5_4_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_4_rxer: eth_p2_4_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_11_rxer: eth_p0_11_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_3_rxer: eth_p5_3_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_15_col: eth_p2_15_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_5_col: eth_p5_5_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_10_clk_tx: eth_p5_10_clk_tx { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { + pinmux = ; + }; + + /omit-if-no-ref/ can_tx_p0_0_node0: can_tx_p0_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_4_node0: can_tx_p1_4_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_5_node1: can_tx_p1_5_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_9_node2: can_tx_p1_9_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_12_node1: can_tx_p1_12_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_7_node1: can_tx_p2_7_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_2_node0: can_tx_p3_2_node0 { + pinmux = ; + }; + + /omit-if-no-ref/ can_rx_p1_5_node0: can_rx_p1_5_node0 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_3_node0: can_rx_p14_3_node0 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p2_6_node1: can_rx_p2_6_node1 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p1_13_node1: can_rx_p1_13_node1 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p1_4_node1: can_rx_p1_4_node1 { + pinmux = ; /* CAN input src = RXDD */ + }; + /omit-if-no-ref/ can_rx_p1_8_node2: can_rx_p1_8_node2 { + pinmux = ; /* CAN input src = RXDA */ + }; }; diff --git a/dts/arm/infineon/xmc4500_F100x1024.dtsi b/dts/arm/infineon/xmc4500_F100x1024.dtsi index 8a84230511d..d368e397ea3 100644 --- a/dts/arm/infineon/xmc4500_F100x1024.dtsi +++ b/dts/arm/infineon/xmc4500_F100x1024.dtsi @@ -93,3 +93,7 @@ status = "disabled"; }; }; + +&can { + message-objects = <64>; +}; diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 75988d493e7..e6bab488049 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -985,4 +985,283 @@ /omit-if-no-ref/ i2c_scl_dout1_p3_9_u2c0: i2c_scl_dout1_p3_9_u2c0 { pinmux = ; }; + + /omit-if-no-ref/ eth_p0_9_mdo: eth_p0_9_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p1_11_mdo: eth_p1_11_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + /omit-if-no-ref/ eth_p2_0_mdo: eth_p2_0_mdo { + pinmux = ; + hwctrl = "periph1"; + }; + + /omit-if-no-ref/ eth_p0_9_mdio: eth_p0_9_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_0_mdio: eth_p2_0_mdio { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_11_mdio: eth_p1_11_mdio { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p0_4_tx_en: eth_p0_4_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_5_txd0: eth_p0_5_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_6_txd1: eth_p0_6_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_10_mdc: eth_p0_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_10_mdc: eth_p1_10_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_12_tx_en: eth_p1_12_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_13_txd0: eth_p1_13_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p1_14_txd1: eth_p1_14_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_tx_en: eth_p2_5_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_7_mdc: eth_p2_7_mdc { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_8_txd0: eth_p2_8_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_9_txd1: eth_p2_9_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_11_txer: eth_p2_11_txer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_12_txd2: eth_p2_12_txd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_12_txd0: eth_p2_12_txd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_13_txd3: eth_p2_13_txd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_13_txd1: eth_p2_13_txd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_tx_en: eth_p5_9_tx_en { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_0_txd2: eth_p6_0_txd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_1_txd3: eth_p6_1_txd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_2_txer: eth_p6_2_txer { + pinmux = ; + }; + + /omit-if-no-ref/ eth_p2_2_rxd0: eth_p2_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_2_rxd0: eth_p0_2_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_8_rxd0: eth_p14_8_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_0_rxd0: eth_p5_0_rxd0 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_3_rxd1: eth_p2_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_3_rxd1: eth_p0_3_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p14_9_rxd1: eth_p14_9_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_1_rxd1: eth_p5_1_rxd1 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_8_rxd2: eth_p5_8_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_4_rxd2: eth_p6_4_rxd2 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_9_rxd3: eth_p5_9_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_3_rxd3: eth_p6_3_rxd3 { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_1_clk_rmii: eth_p2_1_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_0_clk_rmii: eth_p0_0_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_8_clk_rmii: eth_p15_8_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_5_clk_rmii: eth_p6_5_clk_rmii { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_5_crs_dv: eth_p2_5_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_1_crs_dv: eth_p0_1_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p15_9_crs_dv: eth_p15_9_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_2_crs_dv: eth_p5_2_crs_dv { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_11_crs: eth_p5_11_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_4_crs: eth_p5_4_crs { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_4_rxer: eth_p2_4_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p0_11_rxer: eth_p0_11_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_3_rxer: eth_p5_3_rxer { + pinmux = ; + }; + /omit-if-no-ref/ eth_p2_15_col: eth_p2_15_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_5_col: eth_p5_5_col { + pinmux = ; + }; + /omit-if-no-ref/ eth_p5_10_clk_tx: eth_p5_10_clk_tx { + pinmux = ; + }; + /omit-if-no-ref/ eth_p6_6_clk_tx: eth_p6_6_clk_tx { + pinmux = ; + }; + + /omit-if-no-ref/ can_tx_p0_0_node0: can_tx_p0_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_4_node0: can_tx_p1_4_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_5_node1: can_tx_p1_5_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_9_node2: can_tx_p1_9_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p1_12_node1: can_tx_p1_12_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_0_node0: can_tx_p2_0_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_1_node5: can_tx_p2_1_node5 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_7_node1: can_tx_p2_7_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p2_14_node4: can_tx_p2_14_node4 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_2_node0: can_tx_p3_2_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_7_node2: can_tx_p3_7_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_9_node1: can_tx_p3_9_node1 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p3_10_node0: can_tx_p3_10_node0 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p4_0_node3: can_tx_p4_0_node3 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p4_7_node2: can_tx_p4_7_node2 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p5_8_node4: can_tx_p5_8_node4 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p5_11_node5: can_tx_p5_11_node5 { + pinmux = ; + }; + /omit-if-no-ref/ can_tx_p6_5_node3: can_tx_p6_5_node3 { + pinmux = ; + }; + + /omit-if-no-ref/ can_rx_p1_5_node0: can_rx_p1_5_node0 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_3_node0: can_rx_p14_3_node0 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p3_12_node0: can_rx_p3_12_node0 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p2_6_node1: can_rx_p2_6_node1 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p3_11_node1: can_rx_p3_11_node1 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p1_13_node1: can_rx_p1_13_node1 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p1_4_node1: can_rx_p1_4_node1 { + pinmux = ; /* CAN input src = RXDD */ + }; + /omit-if-no-ref/ can_rx_p1_8_node2: can_rx_p1_8_node2 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p3_8_node2: can_rx_p3_8_node2 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p4_6_node2: can_rx_p4_6_node2 { + pinmux = ; /* CAN input src = RXDC */ + }; + /omit-if-no-ref/ can_rx_p0_8_node3: can_rx_p0_8_node3 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p6_6_node3: can_rx_p6_6_node3 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p2_15_node4: can_rx_p2_15_node4 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p14_4_node4: can_rx_p14_4_node4 { + pinmux = ; /* CAN input src = RXDB */ + }; + /omit-if-no-ref/ can_rx_p5_10_node5: can_rx_p5_10_node5 { + pinmux = ; /* CAN input src = RXDA */ + }; + /omit-if-no-ref/ can_rx_p2_6_node5: can_rx_p2_6_node5 { + pinmux = ; /* CAN input src = RXDB */ + }; }; diff --git a/dts/arm/infineon/xmc4700_F144x2048.dtsi b/dts/arm/infineon/xmc4700_F144x2048.dtsi index bd5250050e9..ad8e1ea6413 100644 --- a/dts/arm/infineon/xmc4700_F144x2048.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048.dtsi @@ -13,14 +13,9 @@ reg = <0x1ffe8000 DT_SIZE_K(96)>; }; - dsram1: memory@20000000 { + dsram_joined: memory@20000000 { compatible = "mmio-sram"; - reg = <0x20000000 DT_SIZE_K(128)>; - }; - - dsram2: memory@20020000 { - compatible = "mmio-sram"; - reg = <0x20020000 DT_SIZE_K(128)>; + reg = <0x20000000 DT_SIZE_K(256)>; }; }; @@ -101,3 +96,27 @@ status = "disabled"; }; }; + +&can { + message-objects = <256>; + can_node3: can_node3@48014500 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014500 0x100>; + interrupts = <79 1>; + status = "disabled"; + }; + + can_node4: can_node4@48014600 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014600 0x100>; + interrupts = <80 1>; + status = "disabled"; + }; + + can_node5: can_node5@48014700 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014700 0x100>; + interrupts = <81 1>; + status = "disabled"; + }; +}; diff --git a/dts/arm/infineon/xmc4xxx.dtsi b/dts/arm/infineon/xmc4xxx.dtsi index 82845683fc6..cab68fbff00 100644 --- a/dts/arm/infineon/xmc4xxx.dtsi +++ b/dts/arm/infineon/xmc4xxx.dtsi @@ -236,6 +236,53 @@ interrupts = <0 1>; status = "disabled"; }; + + ethernet@5000c000 { + reg = <0x5000C000 0x3FFF>; + + eth: ethernet { + compatible = "infineon,xmc4xxx-ethernet"; + interrupts = <108 1>; + status = "disabled"; + }; + + mdio: mdio { + compatible = "infineon,xmc4xxx-mdio"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + can: can@48014000 { + compatible = "infineon,xmc4xxx-can"; + reg = <0x48014000 0x4000>; + clock-prescaler = <1>; + + #address-cells = <1>; + #size-cells = <1>; + + can_node0: can_node0@48014200 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014200 0x100>; + interrupts = <76 1>; + status = "disabled"; + }; + + can_node1: can_node1@48014300 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014300 0x100>; + interrupts = <77 1>; + status = "disabled"; + }; + + can_node2: can_node2@48014400 { + compatible = "infineon,xmc4xxx-can-node"; + reg = <0x48014400 0x100>; + interrupts = <78 1>; + status = "disabled"; + }; + }; }; }; diff --git a/dts/arm/intel_socfpga_std/socfpga.dtsi b/dts/arm/intel_socfpga_std/socfpga.dtsi index e2e852a4791..7e1f37267d5 100644 --- a/dts/arm/intel_socfpga_std/socfpga.dtsi +++ b/dts/arm/intel_socfpga_std/socfpga.dtsi @@ -244,6 +244,7 @@ #size-cells = <0>; reg = <0xfff00000 0x1000>; fifo-depth = <256>; + max-xfer-size = <32>; interrupts = <0 154 4 IRQ_DEFAULT_PRIORITY>; clock-frequency = <200000000>; status = "okay"; @@ -255,6 +256,7 @@ #size-cells = <0>; reg = <0xfff01000 0x1000>; fifo-depth = <256>; + max-xfer-size = <32>; interrupts = <0 155 4 IRQ_DEFAULT_PRIORITY>; clock-frequency = <200000000>; status = "disabled"; diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index 222ccd4854c..b64de1d4985 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -24,6 +24,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -131,11 +132,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 NRF_DEFAULT_IRQ_PRIORITY>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -316,6 +318,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; diff --git a/dts/arm/nordic/nrf52805.dtsi b/dts/arm/nordic/nrf52805.dtsi index dd7845588e7..c5a184d5e28 100644 --- a/dts/arm/nordic/nrf52805.dtsi +++ b/dts/arm/nordic/nrf52805.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -28,6 +28,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -132,11 +133,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -311,6 +313,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; @@ -318,3 +321,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 82f5afb99f6..1ca4a9ea378 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -136,11 +137,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -337,6 +339,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; @@ -344,3 +347,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52811.dtsi b/dts/arm/nordic/nrf52811.dtsi index 9e03d5edb32..63b85676587 100644 --- a/dts/arm/nordic/nrf52811.dtsi +++ b/dts/arm/nordic/nrf52811.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -36,6 +36,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -167,11 +168,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -372,6 +374,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; @@ -379,3 +382,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52820.dtsi b/dts/arm/nordic/nrf52820.dtsi index 71ff85afbeb..f93e449b0b2 100644 --- a/dts/arm/nordic/nrf52820.dtsi +++ b/dts/arm/nordic/nrf52820.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { @@ -37,6 +37,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -180,11 +181,12 @@ status = "disabled"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; timer0: timer@40008000 { @@ -389,6 +391,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; @@ -396,3 +399,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index 69de3aa591a..ed5a21b9935 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -179,11 +180,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -465,6 +467,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; }; }; @@ -472,3 +475,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52833.dtsi b/dts/arm/nordic/nrf52833.dtsi index 8003649385c..5ac9cb2d2f8 100644 --- a/dts/arm/nordic/nrf52833.dtsi +++ b/dts/arm/nordic/nrf52833.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -36,6 +36,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -186,11 +187,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -521,6 +523,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -532,6 +535,7 @@ ngpios = <10>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; }; @@ -539,3 +543,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index 9e3b79b3abd..8efe49a3c91 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -32,6 +32,7 @@ ficr: ficr@10000000 { compatible = "nordic,nrf-ficr"; reg = <0x10000000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -181,11 +182,12 @@ status = "okay"; }; - gpiote: gpiote@40006000 { + gpiote: gpiote0: gpiote@40006000 { compatible = "nordic,nrf-gpiote"; reg = <0x40006000 0x1000>; interrupts = <6 5>; status = "disabled"; + instance = <0>; }; adc: adc@40007000 { @@ -525,6 +527,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@50000300 { @@ -536,6 +539,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; cryptocell: crypto@5002a000 { @@ -551,3 +555,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpuapp.dtsi b/dts/arm/nordic/nrf5340_cpuapp.dtsi index a6ae5d4a316..d48f0ce62dc 100644 --- a/dts/arm/nordic/nrf5340_cpuapp.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -41,6 +41,7 @@ ficr: ficr@ff0000 { compatible = "nordic,nrf-ficr"; reg = <0xff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -84,6 +85,16 @@ reg = <0x5000d000 0x1000>; interrupts = <13 5>; status = "disabled"; + instance = <0>; + }; + + /* Additional Non-Secure GPIOTE instance */ + gpiote1: gpiote@4002f000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x4002f000 0x1000>; + interrupts = <47 5>; + status = "disabled"; + instance = <1>; }; cryptocell: crypto@50844000 { @@ -105,9 +116,7 @@ arm,num-irq-priority-bits = <3>; }; -/* - * Include the non-secure peripherals file here since - * it expects to be at the root level. This provides - * a node for GPIOTE1. - */ -#include "nrf5340_cpuapp_peripherals_ns.dtsi" +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi index e7aa0309f70..94e764ec52c 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi @@ -32,24 +32,25 @@ clock: clock@5000 { power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; + ranges = <0x0 0x5000 0x1000>; interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; status = "okay"; #address-cells = <1>; #size-cells = <1>; - gpregret1: gpregret1@551c { + gpregret1: gpregret1@51c { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x551c 0x1>; + reg = <0x51c 0x1>; status = "okay"; }; - gpregret2: gpregret2@5520 { + gpregret2: gpregret2@520 { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x5520 0x1>; + reg = <0x520 0x1>; status = "okay"; }; }; @@ -526,6 +527,7 @@ gpio0: gpio@842500 { #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@842800 { @@ -536,6 +538,7 @@ gpio1: gpio@842800 { ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; ieee802154: ieee802154 { diff --git a/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi b/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi deleted file mode 100644 index 5cfe561e613..00000000000 --- a/dts/arm/nordic/nrf5340_cpuapp_peripherals_ns.dtsi +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2019 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * GPIOTE1 is always accessible as a non-secure peripheral. - */ - -/ { - soc { - gpiote1: gpiote@4002f000 { - compatible = "nordic,nrf-gpiote"; - reg = <0x4002f000 0x1000>; - interrupts = <47 5>; - status = "disabled"; - }; - }; -}; diff --git a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi index 9a730a39406..a543ffe906b 100644 --- a/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi @@ -15,10 +15,6 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", diff --git a/dts/arm/nordic/nrf5340_cpuappns.dtsi b/dts/arm/nordic/nrf5340_cpuappns.dtsi index b5278745e5d..6df1be54b34 100644 --- a/dts/arm/nordic/nrf5340_cpuappns.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns.dtsi @@ -7,7 +7,7 @@ /* .dtsi header for nRF5340 CPUAPP (Application MCU), Non-Secure domain */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -48,6 +48,19 @@ */ #include "nrf5340_cpuapp_peripherals.dtsi" }; + + /* + * GPIOTE1 is always accessible as a non-secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote1: gpiote@4002f000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x4002f000 0x1000>; + interrupts = <47 5>; + status = "disabled"; + instance = <1>; + }; }; /* Default IPC description */ @@ -65,11 +78,7 @@ arm,num-irq-priority-bits = <3>; }; -/* - * Include the non-secure peripherals file here since - * it expects to be at the root level, adding a 'gpiote' label - * for the GPIOTE1 peripheral defined in that file which is - * always accessible as a non-secure peripheral. - */ -#include "nrf5340_cpuapp_peripherals_ns.dtsi" -gpiote: &gpiote1 {}; +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi index e4f38769d8f..80d5706232f 100644 --- a/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpuappns_qkaa.dtsi @@ -15,10 +15,6 @@ reg = <0x20000000 DT_SIZE_K(512)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpuapp-qkaa", "nordic,nrf5340-cpuapp", diff --git a/dts/arm/nordic/nrf5340_cpunet.dtsi b/dts/arm/nordic/nrf5340_cpunet.dtsi index c1e8371d410..8a95b3e9985 100644 --- a/dts/arm/nordic/nrf5340_cpunet.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { chosen { @@ -35,6 +35,7 @@ ficr: ficr@1ff0000 { compatible = "nordic,nrf-ficr"; reg = <0x01ff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -108,11 +109,12 @@ status = "okay"; }; - gpiote: gpiote@4100a000 { + gpiote: gpiote0: gpiote@4100a000 { compatible = "nordic,nrf-gpiote"; reg = <0x4100a000 0x1000>; interrupts = <10 5>; status = "disabled"; + instance = <0>; }; wdt: wdt0: watchdog@4100b000 { @@ -318,6 +320,7 @@ #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; gpio1: gpio@418c0800 { @@ -328,6 +331,7 @@ ngpios = <16>; status = "disabled"; port = <1>; + gpiote-instance = <&gpiote>; }; }; @@ -347,3 +351,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi index c8047ebf905..19eb682ddfc 100644 --- a/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi +++ b/dts/arm/nordic/nrf5340_cpunet_qkaa.dtsi @@ -19,10 +19,6 @@ reg = <0x21000000 DT_SIZE_K(64)>; }; -&mpu { - arm,num-mpu-regions = <8>; -}; - / { soc { compatible = "nordic,nrf5340-cpunet-qkaa", "nordic,nrf5340-cpunet", diff --git a/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi b/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi new file mode 100644 index 00000000000..f51528d5733 --- /dev/null +++ b/dts/arm/nordic/nrf54h20_enga_cpuapp.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpuapp {}; +systick: &cpuapp_systick {}; +nvic: &cpuapp_nvic {}; + +/delete-node/ &cpuppr; +/delete-node/ &cpurad; +/delete-node/ &cpurad_peripherals; +/delete-node/ &cpurad_ppb; +/delete-node/ &cpurad_ram0; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpuapp_nvic>; + ranges; + }; +}; + +&cpuapp_ppb { + compatible = "simple-bus"; + ranges; +}; + +&gpiote130 { + interrupts = <105 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi b/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi new file mode 100644 index 00000000000..cb2767381da --- /dev/null +++ b/dts/arm/nordic/nrf54h20_enga_cpurad.dtsi @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpurad {}; +systick: &cpurad_systick {}; +nvic: &cpurad_nvic {}; + +/delete-node/ &cpuapp; +/delete-node/ &cpuapp_peripherals; +/delete-node/ &cpuapp_ppb; +/delete-node/ &cpuapp_ram0; +/delete-node/ &cpuppr; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpurad_nvic>; + ranges; + }; +}; + +&cpurad_ppb { + compatible = "simple-bus"; + ranges; +}; + +&gpiote130 { + interrupts = <105 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <109 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/arm/nordic/nrf54l15_cpuapp.dtsi b/dts/arm/nordic/nrf54l15_cpuapp.dtsi new file mode 100644 index 00000000000..df4ccc52294 --- /dev/null +++ b/dts/arm/nordic/nrf54l15_cpuapp.dtsi @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0 { + clock-frequency = ; + device_type = "cpu"; + compatible = "arm,cortex-m33f"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + itm: itm@e0000000 { + compatible = "arm,armv8m-itm"; + reg = <0xe0000000 0x1000>; + swo-ref-frequency = ; + }; + }; + }; + + clocks { + lfxo: lfxo { + compatible = "nordic,nrf-lfxo"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + hfxo: hfxo { + compatible = "nordic,nrf-hfxo"; + #clock-cells = <0>; + clock-frequency = ; + }; + }; + + soc { + uicr: uicr@ffd000 { + compatible = "nordic,nrf-uicr"; + reg = <0xffd000 0x1000>; + }; + + ficr: ficr@ffc000 { + compatible = "nordic,nrf-ficr"; + reg = <0xffc000 0x1000>; + #nordic,ficr-cells = <1>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(256)>; + }; + + peripheral@50000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x50000000 0x10000000>; + + /* Common nRF54L15 peripheral description */ + #include "nrf54l15_cpuapp_peripherals.dtsi" + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&rram_controller { + rram0: rram@0 { + /* + * "1524 KB non-volatile memory (RRAM) and 256 KB RAM" + * -- Product Specification + * NB: 1524 = 1.5 * 1024 - 12 + */ + reg = <0x0 DT_SIZE_K(1524)>; + }; +}; + +/* Disable by default to use GRTC */ +&systick { + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi new file mode 100644 index 00000000000..786c21ab215 --- /dev/null +++ b/dts/arm/nordic/nrf54l15_cpuapp_peripherals.dtsi @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +dppic00: dppic@42000 { + compatible = "nordic,nrf-dppic"; + reg = <0x42000 0x808>; + status = "disabled"; +}; + +spi00: spi@4a000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a000 0x1000>; + interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart00: uart@4a000 { + compatible = "nordic,nrf-uarte"; + reg = <0x4a000 0x1000>; + interrupts = <74 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio2: gpio@50400 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0x50400 0x300>; + #gpio-cells = <2>; + ngpios = <11>; + status = "disabled"; + port = <2>; +}; + +timer00: timer@55000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0x55000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <85 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +dppic10: dppic@82000 { + compatible = "nordic,nrf-dppic"; + reg = <0x82000 0x808>; + status = "disabled"; +}; + +timer10: timer@85000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0x85000 0x1000>; + cc-num = <8>; + max-bit-width = <32>; + interrupts = <133 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +egu10: egu@87000 { + compatible = "nordic,nrf-egu"; + reg = <0x87000 0x1000>; + interrupts = <135 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +radio: radio@8a000 { + compatible = "nordic,nrf-radio"; + reg = <0x8a000 0x1000>; + interrupts = <138 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + dfe-supported; + ieee802154-supported; + ble-2mbps-supported; + ble-coded-phy-supported; + + ieee802154: ieee802154 { + compatible = "nordic,nrf-ieee802154"; + status = "disabled"; + }; +}; + +dppic20: dppic@c2000 { + compatible = "nordic,nrf-dppic"; + reg = <0xc2000 0x808>; + status = "disabled"; +}; + +i2c20: i2c@c6000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc6000 0x1000>; + clock-frequency = ; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi20: spi@c6000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc6000 0x1000>; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart20: uart@c6000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc6000 0x1000>; + interrupts = <198 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +i2c21: i2c@c7000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc7000 0x1000>; + clock-frequency = ; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi21: spi@c7000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc7000 0x1000>; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart21: uart@c7000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc7000 0x1000>; + interrupts = <199 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +i2c22: i2c@c8000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc8000 0x1000>; + clock-frequency = ; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi22: spi@c8000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc8000 0x1000>; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart22: uart@c8000 { + compatible = "nordic,nrf-uarte"; + reg = <0xc8000 0x1000>; + interrupts = <200 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +egu20: egu@c9000 { + compatible = "nordic,nrf-egu"; + reg = <0xc9000 0x1000>; + interrupts = <201 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +timer20: timer@ca000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xca000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <202 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer21: timer@cb000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcb000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <203 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer22: timer@cc000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcc000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <204 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer23: timer@cd000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xcd000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <205 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +timer24: timer@ce000 { + compatible = "nordic,nrf-timer"; + status = "disabled"; + reg = <0xce000 0x1000>; + cc-num = <6>; + max-bit-width = <32>; + interrupts = <206 NRF_DEFAULT_IRQ_PRIORITY>; + prescaler = <0>; +}; + +adc: adc@d5000 { + compatible = "nordic,nrf-saadc"; + reg = <0xd5000 0x1000>; + interrupts = <213 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + #io-channel-cells = <1>; +}; + +nfct: nfct@d6000 { + compatible = "nordic,nrf-nfct"; + reg = <0xd6000 0x1000>; + interrupts = <214 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +temp: temp@d7000 { + compatible = "nordic,nrf-temp"; + reg = <0xd7000 0x1000>; + interrupts = <215 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio1: gpio@d8200 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0xd8200 0x300>; + #gpio-cells = <2>; + ngpios = <16>; + status = "disabled"; + port = <1>; + gpiote-instance = <&gpiote20>; +}; + +gpiote20: gpiote@da000 { + compatible = "nordic,nrf-gpiote"; + reg = <0xda000 0x1000>; + interrupts = <219 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + instance = <20>; +}; + +i2s20: i2s@dd000 { + compatible = "nordic,nrf-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xdd000 0x1000>; + interrupts = <221 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +qdec20: qdec@e0000 { + compatible = "nordic,nrf-qdec"; + reg = <0xe0000 0x1000>; + interrupts = <224 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +qdec21: qdec@e1000 { + compatible = "nordic,nrf-qdec"; + reg = <0xe1000 0x1000>; + interrupts = <225 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +grtc: grtc@e2000 { + compatible = "nordic,nrf-grtc"; + reg = <0xe2000 0x1000>; + cc-num = <12>; + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + interrupts = <228 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +dppic30: dppic@102000 { + compatible = "nordic,nrf-dppic"; + reg = <0x102000 0x808>; + status = "disabled"; +}; + +i2c30: i2c@104000 { + compatible = "nordic,nrf-twim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x104000 0x1000>; + clock-frequency = ; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +spi30: spi@104000 { + /* + * This spi node can be either SPIM or SPIS, + * for the user to pick: + * compatible = "nordic,nrf-spim" or + * "nordic,nrf-spis". + */ + compatible = "nordic,nrf-spim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x104000 0x1000>; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + max-frequency = ; + easydma-maxcnt-bits = <16>; + status = "disabled"; +}; + +uart30: uart@104000 { + compatible = "nordic,nrf-uarte"; + reg = <0x104000 0x1000>; + interrupts = <260 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +wdt30: watchdog@108000 { + compatible = "nordic,nrf-wdt"; + reg = <0x108000 0x620>; + interrupts = <264 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +wdt31: watchdog@109000 { + compatible = "nordic,nrf-wdt"; + reg = <0x109000 0x620>; + interrupts = <265 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; + +gpio0: gpio@10a000 { + compatible = "nordic,nrf-gpio"; + gpio-controller; + reg = <0x10a000 0x300>; + #gpio-cells = <2>; + ngpios = <5>; + status = "disabled"; + port = <0>; + gpiote-instance = <&gpiote30>; +}; + +gpiote30: gpiote@10c000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x10c000 0x1000>; + interrupts = <269 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; + instance = <30>; +}; + +clock: clock@10e000 { + compatible = "nordic,nrf-clock"; + reg = <0x10e000 0x1000>; + interrupts = <270 NRF_DEFAULT_IRQ_PRIORITY>; + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf54l_common.dtsi b/dts/arm/nordic/nrf54l_common.dtsi new file mode 100644 index 00000000000..415f2471174 --- /dev/null +++ b/dts/arm/nordic/nrf54l_common.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + rram_controller: rram-controller@5004b000 { + compatible = "nordic,rram-controller"; + reg = <0x5004b000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <75 NRF_DEFAULT_IRQ_PRIORITY>; + rram0: rram@0 { + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + }; + }; + }; + + chosen { + zephyr,flash-controller = &rram_controller; + }; + + sw_pwm: sw-pwm { + generator = <&timer21>; + }; +}; diff --git a/dts/arm/nordic/nrf91.dtsi b/dts/arm/nordic/nrf91.dtsi index 23d2c7cf20e..0fb4c4addf4 100644 --- a/dts/arm/nordic/nrf91.dtsi +++ b/dts/arm/nordic/nrf91.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -22,7 +22,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; @@ -61,11 +60,26 @@ status = "okay"; }; - gpiote: gpiote@5000d000 { + /* + * GPIOTE0 is always accessible as a secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote0: gpiote@5000d000 { compatible = "nordic,nrf-gpiote"; reg = <0x5000d000 0x1000>; interrupts = <13 5>; status = "disabled"; + instance = <0>; + }; + + /* Additional Non-Secure GPIOTE instance */ + gpiote1: gpiote@40031000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x40031000 0x1000>; + interrupts = <49 5>; + status = "disabled"; + instance = <1>; }; spu: spu@50003000 { @@ -78,6 +92,7 @@ ficr: ficr@ff0000 { compatible = "nordic,nrf-ficr"; reg = <0xff0000 0x1000>; + #nordic,ficr-cells = <1>; status = "okay"; }; @@ -92,3 +107,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nordic/nrf91_peripherals.dtsi b/dts/arm/nordic/nrf91_peripherals.dtsi index 2e437eb082d..b6ed30990be 100644 --- a/dts/arm/nordic/nrf91_peripherals.dtsi +++ b/dts/arm/nordic/nrf91_peripherals.dtsi @@ -313,6 +313,7 @@ gpio0: gpio@842500 { #gpio-cells = <2>; status = "disabled"; port = <0>; + gpiote-instance = <&gpiote>; }; rtc0: rtc@14000 { @@ -345,24 +346,25 @@ clock: clock@5000 { power: power@5000 { compatible = "nordic,nrf-power"; reg = <0x5000 0x1000>; + ranges = <0x0 0x5000 0x1000>; interrupts = <5 NRF_DEFAULT_IRQ_PRIORITY>; status = "okay"; #address-cells = <1>; #size-cells = <1>; - gpregret1: gpregret1@551c { + gpregret1: gpregret1@51c { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x551c 0x1>; + reg = <0x51c 0x1>; status = "okay"; }; - gpregret2: gpregret2@5520 { + gpregret2: gpregret2@520 { #address-cells = <1>; #size-cells = <1>; compatible = "nordic,nrf-gpregret"; - reg = <0x5520 0x1>; + reg = <0x520 0x1>; status = "okay"; }; }; diff --git a/dts/arm/nordic/nrf91ns.dtsi b/dts/arm/nordic/nrf91ns.dtsi index 910f45ec706..13a82c442e0 100644 --- a/dts/arm/nordic/nrf91ns.dtsi +++ b/dts/arm/nordic/nrf91ns.dtsi @@ -5,7 +5,7 @@ */ #include -#include "nrf_common.dtsi" +#include / { cpus { @@ -22,7 +22,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; @@ -46,12 +45,17 @@ #include "nrf91_peripherals.dtsi" }; - /* Additional Non-Secure peripherals */ - gpiote: gpiote@40031000 { + /* + * GPIOTE1 is always accessible as a non-secure peripheral, + * so we give it the 'gpiote' label for use when building + * code for this target. + */ + gpiote: gpiote1: gpiote@40031000 { compatible = "nordic,nrf-gpiote"; reg = <0x40031000 0x1000>; interrupts = <49 5>; status = "disabled"; + instance = <1>; }; }; @@ -64,3 +68,8 @@ &nvic { arm,num-irq-priority-bits = <3>; }; + +&systick { + /* Use RTC for system clock, instead of SysTick. */ + status = "disabled"; +}; diff --git a/dts/arm/nuvoton/m46x.dtsi b/dts/arm/nuvoton/m46x.dtsi index 3e6efbb1745..9e0014f2597 100644 --- a/dts/arm/nuvoton/m46x.dtsi +++ b/dts/arm/nuvoton/m46x.dtsi @@ -10,6 +10,8 @@ #include #include #include +#include +#include / { chosen { @@ -434,7 +436,7 @@ reg = <0x40020000 0x200>, <0x40020200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <112 0>, <113 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD0_RST>; clocks = <&pcc NUMAKER_CANFD0_MODULE NUMAKER_CLK_CLKSEL0_CANFD0SEL_HCLK @@ -450,7 +452,7 @@ reg = <0x40024000 0x200>, <0x40024200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <114 0>, <115 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD1_RST>; clocks = <&pcc NUMAKER_CANFD1_MODULE NUMAKER_CLK_CLKSEL0_CANFD1SEL_HCLK @@ -466,7 +468,7 @@ reg = <0x40028000 0x200>, <0x40028200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <120 0>, <121 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD2_RST>; clocks = <&pcc NUMAKER_CANFD2_MODULE NUMAKER_CLK_CLKSEL0_CANFD2SEL_HCLK @@ -482,7 +484,7 @@ reg = <0x4002c000 0x200>, <0x4002c200 0x1800>; reg-names = "m_can", "message_ram"; interrupts = <122 0>, <123 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; resets = <&rst NUMAKER_CANFD3_RST>; clocks = <&pcc NUMAKER_CANFD3_MODULE NUMAKER_CLK_CLKSEL0_CANFD3SEL_HCLK @@ -502,6 +504,118 @@ clocks = <&pcc NUMAKER_EMAC0_MODULE 0 0>; status = "disabled"; }; + + i2c0: i2c@40080000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40080000 0x1000>; + interrupts = <38 0>; + resets = <&rst NUMAKER_I2C0_RST>; + clocks = <&pcc NUMAKER_I2C0_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c1: i2c@40081000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40081000 0x1000>; + interrupts = <39 0>; + resets = <&rst NUMAKER_I2C1_RST>; + clocks = <&pcc NUMAKER_I2C1_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@40082000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40082000 0x1000>; + interrupts = <82 0>; + resets = <&rst NUMAKER_I2C2_RST>; + clocks = <&pcc NUMAKER_I2C2_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c3: i2c@40083000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40083000 0x1000>; + interrupts = <83 0>; + resets = <&rst NUMAKER_I2C3_RST>; + clocks = <&pcc NUMAKER_I2C3_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c4: i2c@40084000 { + compatible = "nuvoton,numaker-i2c"; + clock-frequency = ; + reg = <0x40084000 0x1000>; + interrupts = <118 0>; + resets = <&rst NUMAKER_I2C4_RST>; + clocks = <&pcc NUMAKER_I2C4_MODULE 0 0>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + eadc0: eadc@40043000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x40043000 0xffc>; + interrupts = <42 0>; + resets = <&rst NUMAKER_EADC0_RST>; + clocks = <&pcc NUMAKER_EADC0_MODULE + NUMAKER_CLK_CLKSEL0_EADC0SEL_HCLK + NUMAKER_CLK_CLKDIV0_EADC0(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + eadc1: eadc@4004b000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x4004b000 0xffc>; + interrupts = <104 0>; + resets = <&rst NUMAKER_EADC1_RST>; + clocks = <&pcc NUMAKER_EADC1_MODULE + NUMAKER_CLK_CLKSEL0_EADC1SEL_HCLK + NUMAKER_CLK_CLKDIV2_EADC1(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + eadc2: eadc@40097000 { + compatible = "nuvoton,numaker-adc"; + reg = <0x40097000 0xffc>; + interrupts = <124 0>; + resets = <&rst NUMAKER_EADC2_RST>; + clocks = <&pcc NUMAKER_EADC2_MODULE + NUMAKER_CLK_CLKSEL0_EADC2SEL_HCLK + NUMAKER_CLK_CLKDIV5_EADC2(12)>; + channels = <19>; + status = "disabled"; + #io-channel-cells = <1>; + }; + + usbd: usbd@400c0000 { + compatible = "nuvoton,numaker-usbd"; + reg = <0x400c0000 0x1000>; + interrupts = <53 0>; + resets = <&rst NUMAKER_USBD_RST>; + clocks = <&pcc NUMAKER_USBD_MODULE NUMAKER_CLK_CLKSEL0_USBSEL_PLL_DIV2 + NUMAKER_CLK_CLKDIV0_USB(2)>; + dma-buffer-size = <1536>; + status = "disabled"; + num-bidir-endpoints = <25>; + disallow-iso-in-out-same-number; + }; }; }; diff --git a/dts/arm/nuvoton/npcx/npcx.dtsi b/dts/arm/nuvoton/npcx/npcx.dtsi index c1a77c4fe69..6c9a82f0145 100644 --- a/dts/arm/nuvoton/npcx/npcx.dtsi +++ b/dts/arm/nuvoton/npcx/npcx.dtsi @@ -376,16 +376,6 @@ status = "disabled"; }; - shi0: shi@4000f000 { - compatible = "nuvoton,npcx-shi"; - reg = <0x4000f000 0x120>; - interrupts = <18 1>; - clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; - status = "disabled"; - buffer-rx-size = <128>; - buffer-tx-size = <128>; - }; - host_sub: lpc@400c1000 { compatible = "nuvoton,npcx-host-sub"; /* host sub-module register address & size */ @@ -556,6 +546,17 @@ &wui_io25 &wui_io24 &wui_io23 &wui_io22>; status = "disabled"; }; + + spip0: spi@400d2000 { + compatible = "nuvoton,npcx-spip"; + reg = <0x400d2000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <57 3>; + clocks = <&pcc NPCX_CLOCK_BUS_APB2 NPCX_PWDWN_CTL4 7>; + status = "disabled"; + + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index a01d5d69abf..004ca5332af 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -289,12 +289,34 @@ clocks = <&pcc NPCX_CLOCK_BUS_FIU0 NPCX_PWDWN_CTL8 6>; }; - sha0: sha@13c { + sha0: sha@148 { compatible = "nuvoton,npcx-sha"; - reg = <0x13c 0x3c>; - context-buffer-size = <228>; + reg = <0x148 0x4c>; + context-buffer-size = <240>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi-enhanced"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <64>; + + espi_taf: espitaf@4000a000 { + compatible = "nuvoton,npcx-espi-taf"; + reg = <0x4000a000 0x2000>; + status = "disabled"; + }; + }; }; soc-if { diff --git a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi index c795a41736b..af45fa59ddb 100644 --- a/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4/npcx4-pinctrl.dtsi @@ -555,4 +555,12 @@ /omit-if-no-ref/ uart4_sout_gp35: periph-uart4-sout { pinmux = <&alte_cr_sout4_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index 529d5bdef35..be003127596 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -244,6 +244,22 @@ qspi_fiu0: quadspi@40020000 { clocks = <&pcc NPCX_CLOCK_BUS_FIU NPCX_PWDWN_CTL1 2>; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <16>; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi index e9acb4a0978..2b219c48ede 100644 --- a/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7/npcx7-pinctrl.dtsi @@ -404,4 +404,12 @@ /omit-if-no-ref/ uart2_sin_sout_gp75_86: periph-uart2 { pinmux = <&alta_uart2_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index 4d0cb7dc69e..e3004ab879d 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -272,6 +272,22 @@ context-buffer-size = <212>; status = "disabled"; }; + + shi0: shi@4000f000 { + compatible = "nuvoton,npcx-shi"; + reg = <0x4000f000 0x120>; + interrupts = <18 1>; + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>; + status = "disabled"; + buffer-rx-size = <128>; + buffer-tx-size = <128>; + shi-cs-wui =<&wui_io53>; + }; + + espi0: espi@4000a000 { + rx-plsize = <64>; + tx-plsize = <16>; + }; }; soc-id { diff --git a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi index 2fe2b1f75c9..2ba0b78fdda 100644 --- a/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9/npcx9-pinctrl.dtsi @@ -462,4 +462,12 @@ /omit-if-no-ref/ uart4_sout_gp35: periph-uart4-sout { pinmux = <&alte_cr_sout4_sl>; }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_sl: periph-spip-sl { + pinmux = <&alt0_spip_sl>; + }; + + /omit-if-no-ref/ spip_sclk_mosi_miso_gp95_gpa1_gpa3_gpa5_no_spip_inv: periph-no-spip-inv { + pinmux = <&alt0_gpio_no_spip>; + }; }; diff --git a/dts/arm/nuvoton/npcx9mfp.dtsi b/dts/arm/nuvoton/npcx9mfp.dtsi new file mode 100644 index 00000000000..fb646513f43 --- /dev/null +++ b/dts/arm/nuvoton/npcx9mfp.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "npcx/npcx9.dtsi" + +/ { + flash0: flash@10058000 { + reg = <0x10058000 DT_SIZE_K(416)>; + }; + + flash1: flash@64000000 { + reg = <0x64000000 DT_SIZE_K(1024)>; + }; + + sram0: memory@200c0000 { + compatible = "mmio-sram"; + reg = <0x200C0000 DT_SIZE_K(92)>; + }; + + /* RAM space used by Booter */ + bootloader_ram: memory@200d7000 { + compatible = "mmio-sram"; + reg = <0x200D7000 DT_SIZE_K(4)>; + }; + + soc-id { + device-id = <0x2b>; + }; +}; + +&qspi_fiu0 { + int_flash: w25q80@0 { + compatible ="nuvoton,npcx-fiu-nor"; + size = ; + reg = <0>; + status = "okay"; + + /* quad spi bus configuration of nor flash device */ + qspi-flags = ; + mapped-addr = <0x64000000>; + pinctrl-0 = <&int_flash_sl>; + pinctrl-names = "default"; + }; +}; diff --git a/dts/arm/nxp/nxp_imx8ml_m7.dtsi b/dts/arm/nxp/nxp_imx8ml_m7.dtsi index f9406fc7546..df4636bc72a 100644 --- a/dts/arm/nxp/nxp_imx8ml_m7.dtsi +++ b/dts/arm/nxp/nxp_imx8ml_m7.dtsi @@ -24,7 +24,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/nxp/nxp_k22fx512.dtsi b/dts/arm/nxp/nxp_k22fx512.dtsi new file mode 100644 index 00000000000..4b2962019c0 --- /dev/null +++ b/dts/arm/nxp/nxp_k22fx512.dtsi @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + soc { + i2c2: i2c@400e6000 { + compatible = "nxp,kinetis-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x400e6000 0x1000>; + interrupts = <74 0>; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 6>; + status = "disabled"; + }; + + spi2: spi@400ac000 { + reg = <0x400ac000 0x88>; + interrupts = <65 3>; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1030 12>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart4: uart@400ea000 { + compatible = "nxp,kinetis-uart"; + reg = <0x400ea000 0x1000>; + interrupts = <66 0>, <67 0>; + interrupt-names = "status", "error"; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 10>; + + status = "disabled"; + }; + + uart5: uart@400eb000 { + compatible = "nxp,kinetis-uart"; + reg = <0x400eb000 0x1000>; + interrupts = <68 0>, <69 0>; + interrupt-names = "status", "error"; + clocks = <&sim KINETIS_SIM_BUS_CLK 0x1028 11>; + + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/nxp/nxp_kw41z.dtsi b/dts/arm/nxp/nxp_kw41z.dtsi index f5eaa94d819..87c69d17f5e 100644 --- a/dts/arm/nxp/nxp_kw41z.dtsi +++ b/dts/arm/nxp/nxp_kw41z.dtsi @@ -32,7 +32,7 @@ sram0: memory@20000000 { compatible = "mmio-sram"; - reg = <0x20000000 DT_SIZE_K(128)>; + reg = <0x20000000 DT_SIZE_K(96)>; }; /* Dummy pinctrl node, filled with pin mux options at board level */ diff --git a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi index ca7a25b765e..c579a917698 100644 --- a/dts/arm/nxp/nxp_lpc55S0x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S0x_common.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -221,6 +220,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x9d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi index 76d551555ef..304bf2e68d9 100644 --- a/dts/arm/nxp/nxp_lpc55S1x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S1x_common.dtsi @@ -25,7 +25,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -216,6 +215,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x9d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 16d9c1312c3..6ec0240b2f1 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -34,7 +34,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi index dd011ece96d..18ca28d03e8 100644 --- a/dts/arm/nxp/nxp_lpc55S3x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S3x_common.dtsi @@ -30,7 +30,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -326,6 +325,7 @@ compatible = "nxp,lpc-mcan"; reg = <0x4009d000 0x1000>; interrupts = <43 0>, <44 0>; + interrupt-names = "int0", "int1"; clocks = <&syscon MCUX_MCAN_CLK>; bosch,mram-cfg = <0x0 15 15 8 8 0 15 15>; sample-point = <875>; diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 5095a96738f..00cbb8fa0a5 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; cpu@1 { diff --git a/dts/arm/nxp/nxp_rt1010.dtsi b/dts/arm/nxp/nxp_rt1010.dtsi index 84d47e0f35e..f9f06dc56d0 100644 --- a/dts/arm/nxp/nxp_rt1010.dtsi +++ b/dts/arm/nxp/nxp_rt1010.dtsi @@ -112,6 +112,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; /* Remove SEMC, it does'nt exist on RT1010 */ diff --git a/dts/arm/nxp/nxp_rt1015.dtsi b/dts/arm/nxp/nxp_rt1015.dtsi index 59c62eb4452..bf905168e10 100644 --- a/dts/arm/nxp/nxp_rt1015.dtsi +++ b/dts/arm/nxp/nxp_rt1015.dtsi @@ -8,11 +8,14 @@ #include &flexram { - flexram,num-ram-banks = <4>; - /* default fuse */ + flexram,num-ram-banks = <5>; + /* Note: RT1015 has five flexram banks, but only 4 of the 5 can + * be used at the same time, for a total of 128KB of RAM. + */ flexram,bank-spec = , , , + , ; }; @@ -25,7 +28,7 @@ }; &dtcm { - reg = <0x20000000 DT_SIZE_K(32)>; + reg = <0x20000000 DT_SIZE_K(64)>; }; &ocram { diff --git a/dts/arm/nxp/nxp_rt1064.dtsi b/dts/arm/nxp/nxp_rt1064.dtsi index 73ed8827738..02ea70d40f9 100644 --- a/dts/arm/nxp/nxp_rt1064.dtsi +++ b/dts/arm/nxp/nxp_rt1064.dtsi @@ -31,6 +31,7 @@ &flexspi2 { status = "okay"; reg = <0x402a4000 0x4000>, <0x70000000 DT_SIZE_M(4)>; + rx-clock-source = <1>; /* WINBOND */ w25q32jvwj0: w25q32jvwj@0 { compatible = "nxp,imx-flexspi-nor"; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index e7e4e6448b2..3bc5749f271 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -35,7 +35,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; itm: itm@e0000000 { @@ -127,6 +126,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0x0>; }; flexspi2: spi@402a4000 { @@ -138,6 +138,7 @@ ahb-bufferable; ahb-cacheable; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0x0>; }; semc: semc0@402f0000 { diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index eb14d37f834..6216b32cb46 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -34,7 +34,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; cpu1: cpu@1 { @@ -49,7 +48,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; @@ -97,6 +95,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI_CLK 0x0 0>; }; flexspi2: spi@400d0000 { @@ -106,6 +105,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&ccm IMX_CCM_FLEXSPI2_CLK 0x0 0>; }; semc: semc0@400d4000 { diff --git a/dts/arm/nxp/nxp_rt5xx_common.dtsi b/dts/arm/nxp/nxp_rt5xx_common.dtsi index 8a1a1aa3c3d..867d30cc8ee 100644 --- a/dts/arm/nxp/nxp_rt5xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt5xx_common.dtsi @@ -33,7 +33,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; @@ -389,6 +388,72 @@ #dma-cells = <1>; }; + dmic0: dmic@121000 { + #address-cells=<1>; + #size-cells=<0>; + compatible = "nxp,dmic"; + reg = <0x121000 0x1000>; + interrupts = <25 0>; + status = "disabled"; + clocks = <&clkctl0 MCUX_DMIC_CLK>; + + pdmc0: dmic-channel@0 { + compatible = "nxp,dmic-channel"; + reg = <0>; + dmas = <&dma0 16>; + status = "disabled"; + }; + + pdmc1: dmic-channel@1 { + compatible = "nxp,dmic-channel"; + reg = <1>; + dmas = <&dma0 17>; + status = "disabled"; + }; + + pdmc2: dmic-channel@2 { + compatible = "nxp,dmic-channel"; + reg = <2>; + dmas = <&dma0 18>; + status = "disabled"; + }; + + pdmc3: dmic-channel@3 { + compatible = "nxp,dmic-channel"; + reg = <3>; + dmas = <&dma0 19>; + status = "disabled"; + }; + + pdmc4: dmic-channel@4 { + compatible = "nxp,dmic-channel"; + reg = <4>; + dmas = <&dma0 20>; + status = "disabled"; + }; + + pdmc5: dmic-channel@5 { + compatible = "nxp,dmic-channel"; + reg = <5>; + dmas = <&dma0 21>; + status = "disabled"; + }; + + pdmc6: dmic-channel@6 { + compatible = "nxp,dmic-channel"; + reg = <6>; + dmas = <&dma0 22>; + status = "disabled"; + }; + + pdmc7: dmic-channel@7 { + compatible = "nxp,dmic-channel"; + reg = <7>; + dmas = <&dma0 23>; + status = "disabled"; + }; + }; + os_timer: timers@113000 { compatible = "nxp,os-timer"; reg = <0x113000 0x1000>; @@ -401,6 +466,10 @@ reg = <0x30000 0x1000>; interrupts = <32 0>; status = "disabled"; + rtc_highres: rtc_highres { + compatible = "nxp,lpc-rtc-highres"; + status = "disabled"; + }; }; trng: random@138000 { @@ -618,6 +687,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &flexspi2 { @@ -626,6 +696,7 @@ interrupts = <42 0>; #address-cells = <1>; #size-cells = <0>; + clocks = <&clkctl1 MCUX_FLEXSPI2_CLK>; }; &nvic { diff --git a/dts/arm/nxp/nxp_rt6xx_common.dtsi b/dts/arm/nxp/nxp_rt6xx_common.dtsi index 0c81f71d140..170622b068c 100644 --- a/dts/arm/nxp/nxp_rt6xx_common.dtsi +++ b/dts/arm/nxp/nxp_rt6xx_common.dtsi @@ -31,7 +31,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; @@ -312,6 +311,10 @@ reg = <0x30000 0x1000>; interrupts = <32 0>; status = "disabled"; + rtc_highres: rtc_highres { + compatible = "nxp,lpc-rtc-highres"; + status = "disabled"; + }; }; trng: random@138000 { @@ -498,6 +501,7 @@ #address-cells = <1>; #size-cells = <0>; status = "disabled"; + clocks = <&clkctl1 MCUX_FLEXSPI_CLK>; }; &nvic { diff --git a/dts/arm/nxp/nxp_s32k146.dtsi b/dts/arm/nxp/nxp_s32k146.dtsi new file mode 100644 index 00000000000..bfbb1558349 --- /dev/null +++ b/dts/arm/nxp/nxp_s32k146.dtsi @@ -0,0 +1,80 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-m4f"; + }; + }; + + soc { + /* + * SRAM_L and SRAM_U ranges form a contiguous block but misaligned + * and burst accesses cannot occur across the 0x20000000 boundary + * that separates the two SRAM arrays. Hence, treat the two arrays + * as separate memory ranges. + */ + sram_l: sram@1fff0000 { + compatible = "mmio-sram"; + reg = <0x1fff0000 DT_SIZE_K(64)>; + }; + + sram_u: sram@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(60)>; + }; + }; +}; + +/delete-node/ &lpi2c1; +/delete-node/ &ftm6; +/delete-node/ &ftm7; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; + +&ftfc { + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0 DT_SIZE_M(1)>; + erase-block-size = ; + write-block-size = <8>; + }; +}; + +&lpuart2 { + clocks = <&clock NXP_S32_LPUART2_CLK>; +}; + +&lpspi1 { + clocks = <&clock NXP_S32_LPSPI1_CLK>; +}; + +&lpspi2 { + clocks = <&clock NXP_S32_LPSPI2_CLK>; +}; + +&flexcan0 { + interrupts = <78 0>, <79 0>, <80 0>, <81 0>, <82 0>; + interrupt-names = "warning", "error", "wake-up", "mb-0-15", "mb-16-31"; +}; + +&flexcan1 { + interrupts = <85 0>, <86 0>, <88 0>, <89 0>; + interrupt-names = "warning", "error", "mb-0-15", "mb-16-31"; + clocks = <&clock NXP_S32_FLEXCAN1_CLK>; +}; + +&flexcan2 { + interrupts = <92 0>, <93 0>, <95 0>; + interrupt-names = "warning", "error", "mb-0-15"; + clocks = <&clock NXP_S32_FLEXCAN2_CLK>; +}; diff --git a/dts/arm/nxp/nxp_s32k1xx.dtsi b/dts/arm/nxp/nxp_s32k1xx.dtsi new file mode 100644 index 00000000000..d6c63c5db5d --- /dev/null +++ b/dts/arm/nxp/nxp_s32k1xx.dtsi @@ -0,0 +1,330 @@ +/* + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + aliases { + watchdog0 = &wdog; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + }; + }; + + /* Dummy pinctrl node, filled with pin mux options at board level */ + pinctrl: pinctrl { + compatible = "nxp,kinetis-pinctrl"; + status = "okay"; + }; + + soc { + interrupt-parent = <&nvic>; + + mpu: mpu@4000d000 { + compatible = "nxp,kinetis-mpu"; + reg = <0x4000d000 0x1000>; + status = "disabled"; + }; + + ftfc: flash-controller@40020000 { + compatible = "nxp,kinetis-ftfc"; + reg = <0x40020000 0x1000>; + interrupts = <18 0>, <19 0>, <21 0>; + interrupt-names = "command-complete", "read-collision", "double-bit"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + }; + + flexcan0: can@40024000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40024000 0x1000>; + clocks = <&clock NXP_S32_FLEXCAN0_CLK>; + clk-source = <1>; + status = "disabled"; + }; + + flexcan1: can@40025000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x40025000 0x1000>; + clk-source = <1>; + status = "disabled"; + }; + + flexcan2: can@4002b000 { + compatible = "nxp,flexcan-fd", "nxp,flexcan"; + reg = <0x4002b000 0x1000>; + clk-source = <1>; + status = "disabled"; + }; + + lpspi0: spi@4002c000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002c000 0x1000>; + interrupts = <26 0>; + clocks = <&clock NXP_S32_LPSPI0_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi1: spi@4002d000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002d000 0x1000>; + interrupts = <27 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + lpspi2: spi@4002e000 { + compatible = "nxp,imx-lpspi"; + reg = <0x4002e000 0x1000>; + interrupts = <28 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + porta: pinmux@40049000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x40049000 0x1000>; + clocks = <&clock NXP_S32_PORTA_CLK>; + }; + + portb: pinmux@4004a000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004a000 0x1000>; + clocks = <&clock NXP_S32_PORTB_CLK>; + }; + + portc: pinmux@4004b000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004b000 0x1000>; + clocks = <&clock NXP_S32_PORTC_CLK>; + }; + + portd: pinmux@4004c000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004c000 0x1000>; + clocks = <&clock NXP_S32_PORTD_CLK>; + }; + + porte: pinmux@4004d000 { + compatible = "nxp,kinetis-pinmux"; + reg = <0x4004d000 0x1000>; + clocks = <&clock NXP_S32_PORTE_CLK>; + }; + + wdog: watchdog@40052000 { + compatible = "nxp,kinetis-wdog32"; + reg = <0x40052000 0x1000>; + interrupts = <22 0>; + clocks = <&clock NXP_S32_LPO_128K_CLK>; + clk-source = <1>; + clk-divider = <256>; + }; + + clock: clock-controller@40064000 { + compatible = "nxp,s32-clock"; + reg = <0x40064000 0x1000>, <0x40065000 0x1000>; + #clock-cells = <1>; + status = "okay"; + }; + + lpi2c0: i2c@40066000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40066000 0x1000>; + interrupts = <24 0>; + clocks = <&clock NXP_S32_LPI2C0_CLK>; + status = "disabled"; + }; + + lpi2c1: i2c@40067000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40067000 0x1000>; + interrupts = <25 0>; + status = "disabled"; + }; + + lpuart0: uart@4006a000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006a000 0x1000>; + interrupts = <31 0>; + clocks = <&clock NXP_S32_LPUART0_CLK>; + status = "disabled"; + }; + + lpuart1: uart@4006b000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006b000 0x1000>; + interrupts = <33 0>; + clocks = <&clock NXP_S32_LPUART1_CLK>; + status = "disabled"; + }; + + lpuart2: uart@4006c000 { + compatible = "nxp,kinetis-lpuart"; + reg = <0x4006c000 0x1000>; + interrupts = <35 0>; + status = "disabled"; + }; + + gpioa: gpio@400ff000 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff000 0x40>; + interrupts = <59 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porta>; + status = "disabled"; + }; + + gpiob: gpio@400ff040 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff040 0x40>; + interrupts = <60 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portb>; + status = "disabled"; + }; + + gpioc: gpio@400ff080 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff080 0x40>; + interrupts = <61 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portc>; + status = "disabled"; + }; + + gpiod: gpio@400ff0c0 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff0c0 0x40>; + interrupts = <62 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&portd>; + status = "disabled"; + }; + + gpioe: gpio@400ff100 { + compatible = "nxp,kinetis-gpio"; + reg = <0x400ff100 0x40>; + interrupts = <63 2>; + gpio-controller; + #gpio-cells = <2>; + nxp,kinetis-port = <&porte>; + status = "disabled"; + }; + + ftm0: ftm@40038000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x40038000 0x1000>; + interrupts = <99 0>, <100 0>, <101 0>, <102 0>, <104 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm1: ftm@40039000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x40039000 0x1000>; + interrupts = <105 0>, <106 0>, <107 0>, <108 0>, <110 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm2: ftm@4003a000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x4003a000 0x1000>; + interrupts = <111 0>, <112 0>, <113 0>, <114 0>, <116 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm3: ftm@40026000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x40026000 0x1000>; + interrupts = <117 0>, <118 0>, <119 0>, <120 0>, <122 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm4: ftm@4006e000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x4006e000 0x1000>; + interrupts = <123 0>, <124 0>, <125 0>, <126 0>, <128 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm5: ftm@4006f000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x4006f000 0x1000>; + interrupts = <129 0>, <130 0>, <131 0>, <132 0>, <134 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm6: ftm@40070000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x40070000 0x1000>; + interrupts = <135 0>, <136 0>, <137 0>, <138 0>, <140 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + ftm7: ftm@40071000 { + compatible = "nxp,kinetis-ftm"; + reg = <0x40071000 0x1000>; + interrupts = <141 0>, <142 0>, <143 0>, <144 0>, <146 0>; + interrupt-names = "0-1", "2-3", "4-5", "6-7", "overflow"; + clocks = <&clock NXP_S32_RTC_CLK>; + prescaler = <1>; + status = "disabled"; + }; + + rtc: rtc@4003d000 { + compatible = "nxp,kinetis-rtc"; + reg = <0x4003d000 0x1000>; + interrupts = <46 0>, <47 0>; + interrupt-names = "alarm", "seconds"; + clock-frequency = <32768>; + prescaler = <32768>; + }; + }; +}; diff --git a/dts/arm/nxp/nxp_s32k344_m7.dtsi b/dts/arm/nxp/nxp_s32k344_m7.dtsi index 60196628a57..0289b24f42e 100644 --- a/dts/arm/nxp/nxp_s32k344_m7.dtsi +++ b/dts/arm/nxp/nxp_s32k344_m7.dtsi @@ -29,7 +29,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; @@ -631,6 +630,16 @@ compatible = "nxp,s32-gmac"; interrupts = <105 0>, <106 0>, <107 0>, <108 0>; interrupt-names = "common", "tx", "rx", "safety"; + status = "disabled"; + }; + + mdio0: mdio@40480200 { + reg = <0x40480200 0x8>; + compatible = "nxp,s32-gmac-mdio"; + clocks = <&clock NXP_S32_AIPS_PLAT_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; }; edma0: dma-controller@4020c000 { @@ -818,6 +827,24 @@ status = "disabled"; }; }; + + lcu0: lcu@40098000 { + compatible = "nxp,s32-lcu"; + reg = <0x40098000 0x4000>; + status = "disabled"; + }; + + lcu1: lcu@4009c000 { + compatible = "nxp,s32-lcu"; + reg = <0x4009c000 0x4000>; + status = "disabled"; + }; + + trgmux: trgmux@40080000 { + compatible = "nxp,s32-trgmux"; + reg = <0x40080000 0x4000>; + status = "disabled"; + }; }; }; diff --git a/dts/arm/nxp/nxp_s32z27x_r52.dtsi b/dts/arm/nxp/nxp_s32z27x_r52.dtsi index 4f92c8ca71a..920f519da0f 100644 --- a/dts/arm/nxp/nxp_s32z27x_r52.dtsi +++ b/dts/arm/nxp/nxp_s32z27x_r52.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -693,10 +693,12 @@ can0: can@4741b000 { compatible = "nxp,s32-canxl"; - reg = <0x4741b000 0x4000>, - <0x47426000 0x4000>, - <0x47424000 0x4000>; - reg-names = "sic", "grp_ctrl", "dsc_ctrl"; + reg = <0x4741b000 0x1000>, + <0x47426000 0x1000>, + <0x47424000 0x1000>, + <0x47423000 0x1000>, + <0x47425000 0x1000>; + reg-names = "sic", "grp_ctrl", "dsc_ctrl", "rx_fifo", "rx_fifo_ctrl"; status = "disabled"; interrupts = , ; @@ -706,10 +708,12 @@ can1: can@4751b000 { compatible = "nxp,s32-canxl"; - reg = <0x4751b000 0x4000>, - <0x47526000 0x4000>, - <0x47524000 0x4000>; - reg-names = "sic", "grp_ctrl", "dsc_ctrl"; + reg = <0x4751b000 0x1000>, + <0x47526000 0x1000>, + <0x47524000 0x1000>, + <0x47523000 0x1000>, + <0x47525000 0x1000>; + reg-names = "sic", "grp_ctrl", "dsc_ctrl", "rx_fifo", "rx_fifo_ctrl"; status = "disabled"; interrupts = , ; diff --git a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi index f29b1c482ff..bdc4ecfe87d 100644 --- a/dts/arm/quicklogic/quicklogic_eos_s3.dtsi +++ b/dts/arm/quicklogic/quicklogic_eos_s3.dtsi @@ -23,7 +23,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; diff --git a/dts/arm/renesas/ra/ra-cm4-common.dtsi b/dts/arm/renesas/ra/ra-cm4-common.dtsi index 60157ab8b72..4ef18141e6c 100644 --- a/dts/arm/renesas/ra/ra-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra-cm4-common.dtsi @@ -39,21 +39,21 @@ hoco: hoco { compatible = "fixed-clock"; clock-frequency = <24000000>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; moco: moco { compatible = "fixed-clock"; clock-frequency = <8000000>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; loco: loco { compatible = "fixed-clock"; clock-frequency = <32768>; - status = "disabled"; + status = "okay"; #clock-cells = <0>; }; @@ -247,7 +247,7 @@ }; sci0: sci@40070000 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070000 0x20>; interrupts = , , @@ -266,7 +266,7 @@ }; sci1: sci@40070020 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070020 0x20>; interrupts = , , @@ -284,7 +284,7 @@ }; sci9: sci@40070120 { - compatible = "renesas,ra-uart-sci"; + compatible = "renesas,ra-sci"; reg = <0x40070120 0x20>; interrupts = , , diff --git a/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi new file mode 100644 index 00000000000..0b1667aa4a1 --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/r8a779f0.dtsi @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + soc { + /* The last four registers of this controller are + * located in the control domain + * A custom G4MH/RH850 µC firmware has to be flashed to access them + */ + pfc: pin-controller@e6050000 { + compatible = "renesas,rcar-pfc"; + reg = <0xe6050000 0x16c>, <0xe6050800 0x16c>, + <0xe6051000 0x16c>, <0xe6051800 0x16c>, + <0xdfd90000 0x16c>, <0xdfd90800 0x16c>, + <0xdfd91000 0x16c>, <0xdfd91800 0x16c>; + }; + + /* Clock controller + * Using domain 0 as Linux + */ + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a779f0-cpg-mssr"; + reg = <0xe6150000 0x4000>; + #clock-cells = <2>; + }; + + gpio0: gpio@e6050180 { + compatible = "renesas,rcar-gpio"; + reg = <0xe6050180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* + * Control domain security has to be released to access gpio4 controller + * A custom G4MH/RH850 µC firmware has to be flashed to do that + */ + gpio4: gpio@dfd90180 { + compatible = "renesas,rcar-gpio"; + reg = <0xdfd90180 0x54>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + clocks = <&cpg CPG_MOD 915>; + status = "disabled"; + }; + + /* Zephyr console */ + scif0: serial@e6e60000 { + interrupts = ; + clocks = <&cpg CPG_MOD 702>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + + /* Linux console */ + scif3: serial@e6c50000 { + interrupts = ; + clocks = <&cpg CPG_MOD 704>, <&cpg CPG_CORE R8A779F0_CLK_S0D12_PER>; + }; + }; +}; diff --git a/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi new file mode 100644 index 00000000000..1ce2ec9151c --- /dev/null +++ b/dts/arm/renesas/rcar/gen4/rcar_gen4_cr52.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r52"; + reg = <0>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + soc { + interrupt-parent = <&gic>; + + sram0: memory@40040000 { + compatible = "mmio-sram"; + reg = <0x40040000 0x100000>; + }; + + gic: interrupt-controller@f0000000 { + compatible = "arm,gic-v3", "arm,gic"; + reg = <0xf0000000 0x1000>, + <0xf0100000 0x20000>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + scif0: serial@e6e60000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6e60000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + + scif3: serial@e6c50000 { + compatible = "renesas,rcar-scif"; + reg = <0xe6c50000 0x64>; + current-speed = <115200>; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/renesas/rzt2m.dtsi b/dts/arm/renesas/rz/rzt2m.dtsi similarity index 100% rename from dts/arm/renesas/rzt2m.dtsi rename to dts/arm/renesas/rz/rzt2m.dtsi diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index 6916b2b804c..72f7e6fa89f 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -86,6 +86,52 @@ clock-src = <&rc32k>; status = "okay"; }; + + regulators { + compatible = "renesas,smartbond-regulator"; + vdd: VDD { + regulator-init-microvolt = <900000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + vdd_clamp: VDD_CLAMP { + regulator-boot-on; + regulator-always-on; + regulator-init-microvolt = <706000>; + }; + vdd_sleep: VDD_SLEEP { + regulator-boot-on; + regulator-init-microvolt = <750000>; + }; + v14: V14 { + regulator-init-microvolt = <1400000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + renesas,regulator-dcdc-vbat-low; + }; + v18: V18 { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-dcdc-vbat-high; + }; + v18p: V18P { + regulator-init-microvolt = <1800000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-dcdc-vbat-high; + }; + v30: V30 { + regulator-init-microvolt = <3000000>; + regulator-boot-on; + renesas,regulator-sleep-ldo; + renesas,regulator-v30-vbus; + renesas,regulator-v30-vbat; + renesas,regulator-v30-clamp; + renesas,regulator-v30-ref-bandgap; + }; + }; }; soc { diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index fd83297fa5a..72c71bfcfdc 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,152 @@ }; }; + clocks { + clk_gpout0: clk-gpout0 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + #address-cells = <0>; + }; + + clk_gpout1: clk-gpout1 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_gpout2: clk-gpout2 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_gpout3: clk-gpout3 { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_ref: clk-ref { + compatible = "raspberrypi,pico-clock"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + clk_sys: clk-sys { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_sys>; + clock-names = "pll_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + clk_usb: clk-usb { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + clk_adc: clk-adc { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + + clk_rtc: clk-rtc { + compatible = "raspberrypi,pico-clock"; + clocks = <&pll_usb>; + clock-names = "pll_usb"; + clock-frequency = <46875>; + #clock-cells = <0>; + }; + + clk_peri: clk-peri { + compatible = "raspberrypi,pico-clock"; + clocks = <&clk_sys>; + clock-names = "clk_sys"; + clock-frequency = <125000000>; + #clock-cells = <0>; + }; + + pll_sys: pll-sys { + compatible = "raspberrypi,pico-pll"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-div= <1>; + fb-div= <125>; + post-div1 = <6>; + post-div2 = <2>; + #clock-cells = <0>; + }; + + pll_usb: pll-usb { + compatible = "raspberrypi,pico-pll"; + clocks = <&xosc>; + clock-names = "xosc"; + clock-div= <1>; + fb-div = <100>; + post-div1 = <5>; + post-div2 = <5>; + #clock-cells = <0>; + }; + + rosc: rosc { + compatible = "raspberrypi,pico-rosc"; + clock-frequency = <6500000>; + range = ; + stage-drive-strength = <0>, <0>, <0>, <0>, <0>, <0>, <0>, <0>; + clock-div = <16>; + phase = <0>; + #clock-cells = <0>; + }; + + rosc_ph: rosc-ph { + compatible = "raspberrypi,pico-clock"; + clock-frequency = <6500000>; + clocks = <&rosc>; + clock-names = "rosc"; + #clock-cells = <0>; + }; + + xosc: xosc { + compatible = "raspberrypi,pico-clock"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + gpin0: gpin0 { + compatible = "raspberrypi,pico-clock"; + status = "disabled"; + clock-frequency = <0>; + #clock-cells = <0>; + }; + + gpin1: gpin1 { + compatible = "raspberrypi,pico-clock"; + status = "disabled"; + clock-frequency = <0>; + #clock-cells = <0>; + }; + }; + soc { + compatible = "raspberrypi,rp2040", "simple-bus"; + sram0: memory@20000000 { compatible = "mmio-sram"; reg = <0x20000000 DT_SIZE_K(264)>; @@ -53,18 +199,6 @@ }; }; - peripheral_clk: peripheral-clk { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - #clock-cells = <0>; - }; - - system_clk: system-clk { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - #clock-cells = <0>; - }; - reset: reset-controller@4000c000 { compatible = "raspberrypi,pico-reset"; reg = <0x4000c000 DT_SIZE_K(4)>; @@ -73,6 +207,28 @@ #reset-cells = <1>; }; + clocks: clock-controller@40008000 { + compatible = "raspberrypi,pico-clock-controller"; + reg = <0x40008000 DT_SIZE_K(4) + 0x40024000 DT_SIZE_K(4) + 0x40028000 DT_SIZE_K(4) + 0x4002c000 DT_SIZE_K(4) + 0x40060000 DT_SIZE_K(4)>; + reg-names = "clocks", "xosc", "pll_sys", "pll_usb", "rosc"; + #clock-cells = <1>; + status = "okay"; + clocks = <&clk_gpout0>, <&clk_gpout1>, <&clk_gpout2>, <&clk_gpout3>, + <&clk_ref>, <&clk_sys>, <&clk_peri>, + <&clk_usb>, <&clk_adc>, <&clk_rtc>, + <&pll_sys>, <&pll_usb>, <&xosc>, <&rosc>, <&rosc_ph>, + <&gpin0>, <&gpin1>; + clock-names = "clk_gpout0", "clk_gpout1", "clk_gpout2", "clk_gpout3", + "clk_ref", "clk_sys", "clk_peri", + "clk_usb", "clk_adc", "clk_rtc", + "pll_sys", "pll_usb", "xosc", "rosc", "rosc_ph", + "gpin0", "gpin1"; + }; + gpio0: gpio@40014000 { compatible = "raspberrypi,pico-gpio"; reg = <0x40014000 DT_SIZE_K(4)>; @@ -86,7 +242,7 @@ uart0: uart@40034000 { compatible = "raspberrypi,pico-uart"; reg = <0x40034000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_UART0>; interrupts = <20 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "uart0"; @@ -96,7 +252,7 @@ uart1: uart@40038000 { compatible = "raspberrypi,pico-uart"; reg = <0x40038000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_UART1>; interrupts = <21 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "uart1"; @@ -108,7 +264,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x4003c000 DT_SIZE_K(4)>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; resets = <&reset RPI_PICO_RESETS_RESET_SPI0>; interrupts = <18 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "spi0"; @@ -121,7 +277,7 @@ #size-cells = <0>; reg = <0x40040000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_SPI1>; - clocks = <&peripheral_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_PERI>; interrupts = <19 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "spi1"; status = "disabled"; @@ -131,6 +287,7 @@ compatible = "raspberrypi,pico-adc"; reg = <0x4004c000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_ADC>; + clocks = <&clocks RPI_PICO_CLKID_CLK_ADC>; interrupts = <22 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "adc0"; status = "disabled"; @@ -143,7 +300,7 @@ #size-cells = <0>; reg = <0x40044000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_I2C0>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <23 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "i2c0"; status = "disabled"; @@ -155,7 +312,7 @@ #size-cells = <0>; reg = <0x40048000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_I2C0>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <24 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "i2c1"; status = "disabled"; @@ -164,7 +321,7 @@ wdt0: watchdog@40058000 { compatible = "raspberrypi,pico-watchdog"; reg = <0x40058000 DT_SIZE_K(4)>; - clocks = <&xtal_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_REF>; status = "disabled"; }; @@ -172,6 +329,7 @@ compatible = "raspberrypi,pico-usbd"; reg = <0x50100000 0x10000>; resets = <&reset RPI_PICO_RESETS_RESET_USBCTRL>; + clocks = <&clocks RPI_PICO_CLKID_CLK_USB>; interrupts = <5 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "usbctrl"; num-bidir-endpoints = <16>; @@ -182,7 +340,7 @@ compatible = "raspberrypi,pico-pwm"; reg = <0x40050000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_PWM>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <4 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "PWM_IRQ_WRAP"; status = "disabled"; @@ -193,7 +351,7 @@ compatible = "raspberrypi,pico-timer"; reg = <0x40054000 DT_SIZE_K(4)>; resets = <&reset RPI_PICO_RESETS_RESET_TIMER>; - clocks = <&xtal_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_REF>; interrupts = <0 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <1 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <2 RPI_PICO_DEFAULT_IRQ_PRIORITY>, @@ -209,7 +367,7 @@ compatible = "raspberrypi,pico-dma"; reg = <0x50000000 DT_SIZE_K(64)>; resets = <&reset RPI_PICO_RESETS_RESET_DMA>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; interrupts = <11 RPI_PICO_DEFAULT_IRQ_PRIORITY>, <12 RPI_PICO_DEFAULT_IRQ_PRIORITY>; interrupt-names = "dma0", "dma1"; @@ -229,7 +387,7 @@ pio0: pio@50200000 { compatible = "raspberrypi,pico-pio"; reg = <0x50200000 DT_SIZE_K(4)>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; resets = <&reset RPI_PICO_RESETS_RESET_PIO0>; status = "disabled"; }; @@ -237,7 +395,7 @@ pio1: pio@50300000 { compatible = "raspberrypi,pico-pio"; reg = <0x50300000 DT_SIZE_K(4)>; - clocks = <&system_clk>; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; resets = <&reset RPI_PICO_RESETS_RESET_PIO1>; status = "disabled"; }; @@ -255,5 +413,5 @@ }; &nvic { - arm,num-irq-priority-bits = <3>; + arm,num-irq-priority-bits = <2>; }; diff --git a/dts/arm/silabs/efr32bg2x.dtsi b/dts/arm/silabs/efr32bg2x.dtsi index 2f50f1bcbda..70df9708d11 100644 --- a/dts/arm/silabs/efr32bg2x.dtsi +++ b/dts/arm/silabs/efr32bg2x.dtsi @@ -23,6 +23,7 @@ compatible = "silabs,hfxo"; clock-frequency = ; ctune = <120>; + precision = <50>; }; }; diff --git a/dts/arm/silabs/efr32mg12p432f1024gl125.dtsi b/dts/arm/silabs/efr32mg12p432f1024gl125.dtsi new file mode 100644 index 00000000000..d3da9a5d894 --- /dev/null +++ b/dts/arm/silabs/efr32mg12p432f1024gl125.dtsi @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(256)>; + }; + + soc { + compatible = "silabs,efr32mg12p432f1024gl125", "silabs,efr32mg12p", "silabs,efr32", + "simple-bus"; + + flash-controller@400e0000 { + flash0: flash@0 { + reg = <0 DT_SIZE_K(1024)>; + }; + }; + }; +}; diff --git a/dts/arm/silabs/efr32mg21.dtsi b/dts/arm/silabs/efr32mg21.dtsi index 4ada3f6ff60..217830f7265 100644 --- a/dts/arm/silabs/efr32mg21.dtsi +++ b/dts/arm/silabs/efr32mg21.dtsi @@ -30,7 +30,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; diff --git a/dts/arm/silabs/efr32mg24.dtsi b/dts/arm/silabs/efr32mg24.dtsi index b42b775397f..860cedddeda 100644 --- a/dts/arm/silabs/efr32mg24.dtsi +++ b/dts/arm/silabs/efr32mg24.dtsi @@ -24,6 +24,7 @@ compatible = "silabs,hfxo"; clock-frequency = ; ctune = <140>; + precision = <50>; }; }; diff --git a/dts/arm/st/c0/stm32c0.dtsi b/dts/arm/st/c0/stm32c0.dtsi index ef71f835ba2..fd37b14b5f9 100644 --- a/dts/arm/st/c0/stm32c0.dtsi +++ b/dts/arm/st/c0/stm32c0.dtsi @@ -343,6 +343,14 @@ io-channels = <&adc1 10>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f0/stm32f0.dtsi b/dts/arm/st/f0/stm32f0.dtsi index e9e521cd47e..0371ac75ac6 100644 --- a/dts/arm/st/f0/stm32f0.dtsi +++ b/dts/arm/st/f0/stm32f0.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m0"; reg = <0>; @@ -364,6 +364,14 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f0/stm32f030X8.dtsi b/dts/arm/st/f0/stm32f030X8.dtsi index 775b3b3ebe4..9044da82c0a 100644 --- a/dts/arm/st/f0/stm32f030X8.dtsi +++ b/dts/arm/st/f0/stm32f030X8.dtsi @@ -77,4 +77,12 @@ }; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f0/stm32f051.dtsi b/dts/arm/st/f0/stm32f051.dtsi index 45165c31e2b..51d23418207 100644 --- a/dts/arm/st/f0/stm32f051.dtsi +++ b/dts/arm/st/f0/stm32f051.dtsi @@ -77,4 +77,12 @@ #io-channel-cells = <1>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f0/stm32f070Xb.dtsi b/dts/arm/st/f0/stm32f070Xb.dtsi index 665945738a8..6962a67ba10 100644 --- a/dts/arm/st/f0/stm32f070Xb.dtsi +++ b/dts/arm/st/f0/stm32f070Xb.dtsi @@ -87,4 +87,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f1/stm32f1.dtsi b/dts/arm/st/f1/stm32f1.dtsi index b70130db308..dc9f140370e 100644 --- a/dts/arm/st/f1/stm32f1.dtsi +++ b/dts/arm/st/f1/stm32f1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; @@ -362,6 +362,22 @@ v25 = <1430>; ntc; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f2/stm32f2.dtsi b/dts/arm/st/f2/stm32f2.dtsi index 845cd6fb5a2..9c913756919 100644 --- a/dts/arm/st/f2/stm32f2.dtsi +++ b/dts/arm/st/f2/stm32f2.dtsi @@ -27,7 +27,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; @@ -713,6 +713,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f3/stm32f3.dtsi b/dts/arm/st/f3/stm32f3.dtsi index a426a84ea3e..e4a64b24304 100644 --- a/dts/arm/st/f3/stm32f3.dtsi +++ b/dts/arm/st/f3/stm32f3.dtsi @@ -25,7 +25,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; @@ -463,6 +463,14 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f3/stm32f302.dtsi b/dts/arm/st/f3/stm32f302.dtsi index 59f4b2f7077..5d2c40be20b 100644 --- a/dts/arm/st/f3/stm32f302.dtsi +++ b/dts/arm/st/f3/stm32f302.dtsi @@ -117,4 +117,20 @@ st,adc-sequencer = ; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f3/stm32f302Xc.dtsi b/dts/arm/st/f3/stm32f302Xc.dtsi index 4c1de5611ee..8d30e7d31d1 100644 --- a/dts/arm/st/f3/stm32f302Xc.dtsi +++ b/dts/arm/st/f3/stm32f302Xc.dtsi @@ -49,3 +49,4 @@ }; /delete-node/ &i2c3; +/delete-node/ &smbus3; diff --git a/dts/arm/st/f3/stm32f303.dtsi b/dts/arm/st/f3/stm32f303.dtsi index 01e5d4233df..5fa8d11b150 100644 --- a/dts/arm/st/f3/stm32f303.dtsi +++ b/dts/arm/st/f3/stm32f303.dtsi @@ -172,4 +172,12 @@ st,adc-sequencer = ; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f3/stm32f303Xb.dtsi b/dts/arm/st/f3/stm32f303Xb.dtsi new file mode 100644 index 00000000000..040566c0b22 --- /dev/null +++ b/dts/arm/st/f3/stm32f303Xb.dtsi @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Martin Gritzan + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + ccm0: memory@10000000 { + compatible = "zephyr,memory-region", "st,stm32-ccm"; + reg = <0x10000000 DT_SIZE_K(8)>; + zephyr,memory-region = "CCM"; + }; + + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(128)>; + }; + }; + + dma2: dma@40020400 { + compatible = "st,stm32-dma-v2bis"; + #dma-cells = <2>; + reg = <0x40020400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; + interrupts = <56 0 57 0 58 0 59 0 60 0>; + status = "disabled"; + }; + + rtc@40002800 { + bbram: backup_regs { + compatible = "st,stm32-bbram"; + st,backup-regs = <16>; + status = "disabled"; + }; + }; + }; +}; diff --git a/dts/arm/st/f3/stm32f303Xc.dtsi b/dts/arm/st/f3/stm32f303Xc.dtsi index fd857c1a8fd..76131f72349 100644 --- a/dts/arm/st/f3/stm32f303Xc.dtsi +++ b/dts/arm/st/f3/stm32f303Xc.dtsi @@ -1,45 +1,16 @@ /* - * Copyright (c) 2018 Linaro Limited + * Copyright (c) 2023 Martin Gritzan * * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include -/ { - ccm0: memory@10000000 { - compatible = "zephyr,memory-region", "st,stm32-ccm"; - reg = <0x10000000 DT_SIZE_K(8)>; - zephyr,memory-region = "CCM"; - }; - - sram0: memory@20000000 { - reg = <0x20000000 DT_SIZE_K(40)>; - }; - - soc { - flash-controller@40022000 { - flash0: flash@8000000 { - reg = <0x08000000 DT_SIZE_K(256)>; - }; - }; - - dma2: dma@40020400 { - compatible = "st,stm32-dma-v2bis"; - #dma-cells = <2>; - reg = <0x40020400 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x2>; - interrupts = <56 0 57 0 58 0 59 0 60 0>; - status = "disabled"; - }; +&sram0 { + reg = <0x20000000 DT_SIZE_K(40)>; +}; - rtc@40002800 { - bbram: backup_regs { - compatible = "st,stm32-bbram"; - st,backup-regs = <16>; - status = "disabled"; - }; - }; - }; +&flash0 { + reg = <0x08000000 DT_SIZE_K(256)>; }; diff --git a/dts/arm/st/f3/stm32f373.dtsi b/dts/arm/st/f3/stm32f373.dtsi index 9c42331c36e..73c4de1eafa 100644 --- a/dts/arm/st/f3/stm32f373.dtsi +++ b/dts/arm/st/f3/stm32f373.dtsi @@ -212,4 +212,12 @@ vbat: vbat { io-channels = <&adc1 18>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f4/stm32f4.dtsi b/dts/arm/st/f4/stm32f4.dtsi index f53c9cdf228..010868a00f2 100644 --- a/dts/arm/st/f4/stm32f4.dtsi +++ b/dts/arm/st/f4/stm32f4.dtsi @@ -22,6 +22,7 @@ / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { @@ -598,6 +599,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f7/stm32f7.dtsi b/dts/arm/st/f7/stm32f7.dtsi index 2df24d0c8d2..cfd98d4bb4d 100644 --- a/dts/arm/st/f7/stm32f7.dtsi +++ b/dts/arm/st/f7/stm32f7.dtsi @@ -30,7 +30,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m7"; reg = <0>; @@ -40,7 +40,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -861,7 +860,7 @@ vref: vref { compatible = "st,stm32-vref"; - vrefint-cal-addr = <0x1FFF7A2A>; + vrefint-cal-addr = <0x1FF0F44A>; vrefint-cal-mv = <3300>; io-channels = <&adc1 17>; status = "disabled"; @@ -883,6 +882,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/f7/stm32f722.dtsi b/dts/arm/st/f7/stm32f722.dtsi new file mode 100644 index 00000000000..0784e99265b --- /dev/null +++ b/dts/arm/st/f7/stm32f722.dtsi @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* 16KB ITCM @ 0x0, 64KB DTCM @ 0x20000000, + * 176KB SRAM1 @ 0x20010000, 16KB SRAM2 @ 0x2003C00 + */ + + sram0: memory@20010000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20010000 DT_SIZE_K(192)>; + zephyr,memory-region = "SRAM0"; + }; + + dtcm: memory@20000000 { + compatible = "zephyr,memory-region", "arm,dtcm"; + reg = <0x20000000 DT_SIZE_K(64)>; + zephyr,memory-region = "DTCM"; + }; + + itcm: memory@0 { + compatible = "zephyr,memory-region", "arm,itcm"; + reg = <0x00000000 DT_SIZE_K(16)>; + zephyr,memory-region = "ITCM"; + }; + + soc { + compatible = "st,stm32f722", "st,stm32f7", "simple-bus"; + + sdmmc2: sdmmc@40011c00 { + compatible = "st,stm32-sdmmc"; + reg = <0x40011c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000080>, + <&rcc STM32_SRC_PLL_Q SDMMC2_SEL(0)>; + resets = <&rctl STM32_RESET(APB2, 7U)>; + interrupts = <103 0>; + status = "disabled"; + }; + }; + + die_temp: dietemp { + ts-cal1-addr = <0x1FF07A2C>; + ts-cal2-addr = <0x1FF07A2E>; + }; + + vref: vref { + vrefint-cal-addr = <0x1FF07A2A>; + }; +}; diff --git a/dts/arm/st/f7/stm32f722Xe.dtsi b/dts/arm/st/f7/stm32f722Xe.dtsi new file mode 100644 index 00000000000..79491e4008b --- /dev/null +++ b/dts/arm/st/f7/stm32f722Xe.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Evan Perry Grove + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + soc { + flash-controller@40023c00 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_K(512)>; + }; + }; + }; +}; diff --git a/dts/arm/st/f7/stm32f723.dtsi b/dts/arm/st/f7/stm32f723.dtsi index e47698a1dea..f8b5448a788 100644 --- a/dts/arm/st/f7/stm32f723.dtsi +++ b/dts/arm/st/f7/stm32f723.dtsi @@ -4,28 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include / { - /* 64KB DTCM @ 0x20000000, 176KB SRAM1 @ 0x20010000, 16KB SRAM2 @ 0x2003C00 */ - - sram0: memory@20010000 { - compatible = "mmio-sram"; - reg = <0x20010000 DT_SIZE_K(192)>; - }; - - dtcm: memory@20000000 { - compatible = "zephyr,memory-region", "arm,dtcm"; - reg = <0x20000000 DT_SIZE_K(64)>; - zephyr,memory-region = "DTCM"; - }; - - itcm: memory@0 { - compatible = "zephyr,memory-region", "arm,itcm"; - reg = <0x00000000 DT_SIZE_K(16)>; - zephyr,memory-region = "ITCM"; - }; - soc { compatible = "st,stm32f723", "st,stm32f7", "simple-bus"; @@ -39,21 +20,6 @@ phys = <&usbphyc>; maximum-speed = "high-speed"; }; - - sdmmc2: sdmmc@40011c00 { - compatible = "st,stm32-sdmmc"; - reg = <0x40011c00 0x400>; - clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00000080>, - <&rcc STM32_SRC_PLL_Q SDMMC2_SEL(0)>; - resets = <&rctl STM32_RESET(APB2, 7U)>; - interrupts = <103 0>; - status = "disabled"; - }; - }; - - die_temp: dietemp { - ts-cal1-addr = <0x1FF07A2C>; - ts-cal2-addr = <0x1FF07A2E>; }; }; diff --git a/dts/arm/st/f7/stm32f745.dtsi b/dts/arm/st/f7/stm32f745.dtsi index d63ddd881ba..551e3af6f3f 100644 --- a/dts/arm/st/f7/stm32f745.dtsi +++ b/dts/arm/st/f7/stm32f745.dtsi @@ -10,8 +10,9 @@ /* 64KB DTCM @ 20000000, 240KB SRAM1 @ 20010000, 16KB SRAM2 @ 2004C000 */ sram0: memory@20010000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20010000 DT_SIZE_K(256)>; + zephyr,memory-region = "SRAM0"; }; dtcm: memory@20000000 { @@ -88,4 +89,12 @@ status = "disabled"; }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/f7/stm32f765.dtsi b/dts/arm/st/f7/stm32f765.dtsi index fccf74e7355..b53203be760 100644 --- a/dts/arm/st/f7/stm32f765.dtsi +++ b/dts/arm/st/f7/stm32f765.dtsi @@ -12,8 +12,9 @@ */ sram0: memory@20020000 { - compatible = "mmio-sram"; + compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20020000 DT_SIZE_K(384)>; + zephyr,memory-region = "SRAM0"; }; dtcm: memory@20000000 { @@ -91,4 +92,12 @@ }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g0/stm32g0.dtsi b/dts/arm/st/g0/stm32g0.dtsi index 5f37fc667db..bfa023d027d 100644 --- a/dts/arm/st/g0/stm32g0.dtsi +++ b/dts/arm/st/g0/stm32g0.dtsi @@ -460,6 +460,22 @@ io-channels = <&adc1 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/g0/stm32g0b0.dtsi b/dts/arm/st/g0/stm32g0b0.dtsi index f9c26bb0dde..861c70f2d5b 100644 --- a/dts/arm/st/g0/stm32g0b0.dtsi +++ b/dts/arm/st/g0/stm32g0b0.dtsi @@ -110,4 +110,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g0/stm32g0b1.dtsi b/dts/arm/st/g0/stm32g0b1.dtsi index b99063d67b8..f6a8ae129e0 100644 --- a/dts/arm/st/g0/stm32g0b1.dtsi +++ b/dts/arm/st/g0/stm32g0b1.dtsi @@ -35,7 +35,20 @@ reg = <0x40006400 0x400>, <0x4000b400 0x350>; reg-names = "m_can", "message_ram"; interrupts = <21 0>, <22 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>; + bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; + sample-point = <875>; + sample-point-data = <875>; + status = "disabled"; + }; + + fdcan2: can@40006800 { + compatible = "st,stm32-fdcan"; + reg = <0x40006800 0x400>, <0x4000b750 0x350>; + reg-names = "m_can", "message_ram"; + interrupts = <21 0>, <22 0>; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00001000>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; @@ -143,4 +156,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g4/stm32g4.dtsi b/dts/arm/st/g4/stm32g4.dtsi index feec71388aa..d42ff353a73 100644 --- a/dts/arm/st/g4/stm32g4.dtsi +++ b/dts/arm/st/g4/stm32g4.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4f"; reg = <0>; @@ -387,7 +387,7 @@ reg = <0x40006400 0x400>, <0x4000a400 0x350>; reg-names = "m_can", "message_ram"; interrupts = <21 0>, <22 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; @@ -691,6 +691,30 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/g4/stm32g473.dtsi b/dts/arm/st/g4/stm32g473.dtsi index 97565c33e73..0cdcc317f0a 100644 --- a/dts/arm/st/g4/stm32g473.dtsi +++ b/dts/arm/st/g4/stm32g473.dtsi @@ -100,7 +100,7 @@ reg = <0x40006c00 0x400>, <0x4000a400 0x9f0>; reg-names = "m_can", "message_ram"; interrupts = <88 0>, <89 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x6a0 28 8 3 3 0 3 3>; sample-point = <875>; @@ -108,4 +108,12 @@ status = "disabled"; }; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/g4/stm32g491.dtsi b/dts/arm/st/g4/stm32g491.dtsi index 865d3700d96..1e616accc77 100644 --- a/dts/arm/st/g4/stm32g491.dtsi +++ b/dts/arm/st/g4/stm32g491.dtsi @@ -15,7 +15,7 @@ reg = <0x40006800 0x400>, <0x4000a400 0x6a0>; reg-names = "m_can", "message_ram"; interrupts = <86 0>, <87 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1 0x02000000>; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; sample-point = <875>; diff --git a/dts/arm/st/h5/stm32h5.dtsi b/dts/arm/st/h5/stm32h5.dtsi index d8a93a58619..dff30f083da 100644 --- a/dts/arm/st/h5/stm32h5.dtsi +++ b/dts/arm/st/h5/stm32h5.dtsi @@ -36,7 +36,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; }; @@ -439,7 +438,7 @@ reg = <0x4000a400 0x400>, <0x4000ac00 0x350>; reg-names = "m_can", "message_ram"; interrupts = <39 0>, <40 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; @@ -537,6 +536,22 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/h5/stm32h562.dtsi b/dts/arm/st/h5/stm32h562.dtsi index 66ed8d3d927..0e407a02be0 100644 --- a/dts/arm/st/h5/stm32h562.dtsi +++ b/dts/arm/st/h5/stm32h562.dtsi @@ -72,6 +72,24 @@ status = "disabled"; }; + uart7: serial@40007800 { + compatible = "st,stm32-uart"; + reg = <0x40007800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x40000000>; + resets = <&rctl STM32_RESET(APB1L, 30U)>; + interrupts = <98 0>; + status = "disabled"; + }; + + uart8: serial@40007c00 { + compatible = "st,stm32-uart"; + reg = <0x40007c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x80000000>; + resets = <&rctl STM32_RESET(APB1L, 31U)>; + interrupts = <99 0>; + status = "disabled"; + }; + uart9: serial@40008000 { compatible = "st,stm32-uart"; reg = <0x40008000 0x400>; @@ -90,6 +108,15 @@ status = "disabled"; }; + usart11: serial@40006c00 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40006c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x08000000>; + resets = <&rctl STM32_RESET(APB1L, 27U)>; + interrupts = <87 0>; + status = "disabled"; + }; + uart12: serial@40008400 { compatible = "st,stm32-uart"; reg = <0x40008400 0x400>; @@ -299,7 +326,7 @@ reg = <0x4000a800 0x400>, <0x4000ac00 0x6a0>; reg-names = "m_can", "message_ram"; interrupts = <109 0>, <110 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; /* common clock FDCAN 1 & 2 */ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; @@ -308,4 +335,20 @@ status = "disabled"; }; }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 58a01b962b2..64ccfbf7241 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -41,7 +41,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv7m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <16>; }; }; }; @@ -467,13 +466,55 @@ status = "disabled"; }; + i2s1: i2s@40013000 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40013000 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00001000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 38 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 37 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <35 3>; + status = "disabled"; + }; + + i2s2: i2s@40003800 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40003800 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00004000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 40 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 39 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <36 0>; + status = "disabled"; + }; + + i2s3: i2s@40003c00 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40003c00 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00008000>, + <&rcc STM32_SRC_PLL1_Q SPI123_SEL(0)>; + dmas = <&dmamux1 0 62 (STM32_DMA_PERIPH_TX | STM32_DMA_PRIORITY_HIGH) + &dmamux1 1 61 (STM32_DMA_PERIPH_RX | STM32_DMA_PRIORITY_HIGH)>; + dma-names = "tx", "rx"; + interrupts = <51 0>; + status = "disabled"; + }; + fdcan1: can@4000a000 { compatible = "st,stm32h7-fdcan"; reg = <0x4000a000 0x400>, <0x4000ac00 0x350>; reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <19 0>, <21 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; @@ -486,7 +527,7 @@ reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <20 0>, <22 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x350 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; @@ -1037,6 +1078,38 @@ vrefint-cal-mv = <3300>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/h7/stm32h723.dtsi b/dts/arm/st/h7/stm32h723.dtsi index f1b0836f6e8..1a2b917bc1e 100644 --- a/dts/arm/st/h7/stm32h723.dtsi +++ b/dts/arm/st/h7/stm32h723.dtsi @@ -121,7 +121,7 @@ reg-names = "m_can", "message_ram"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000100>; interrupts = <159 0>, <160 0>, <63 0>; - interrupt-names = "LINE_0", "LINE_1", "CALIB"; + interrupt-names = "int0", "int1", "calib"; bosch,mram-cfg = <0x6a0 28 8 3 3 0 3 3>; sample-point = <875>; sample-point-data = <875>; diff --git a/dts/arm/st/h7/stm32h7a3.dtsi b/dts/arm/st/h7/stm32h7a3.dtsi index 7f85387ca06..8ff4353855a 100644 --- a/dts/arm/st/h7/stm32h7a3.dtsi +++ b/dts/arm/st/h7/stm32h7a3.dtsi @@ -79,6 +79,19 @@ status = "disabled"; }; + i2s6: i2s@58001400 { + compatible = "st,stm32h7-i2s", "st,stm32-i2s"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x58001400 0x400>; + clocks = <&rcc STM32_CLOCK_BUS_APB4 0x00000020>, + <&rcc STM32_SRC_PLL1_Q SPI6_SEL(0)>; + dmas = <&dmamux2 0 12 0x20440 &dmamux2 1 11 0x20480>; + dma-names = "tx", "rx"; + interrupts = <86 0>; + status = "disabled"; + }; + rng: rng@48021800 { nist-config = <0xf00d00>; health-test-magic = <0x17590abc>; diff --git a/dts/arm/st/l0/stm32l0.dtsi b/dts/arm/st/l0/stm32l0.dtsi index b05dbff210d..7bb62de1f22 100644 --- a/dts/arm/st/l0/stm32l0.dtsi +++ b/dts/arm/st/l0/stm32l0.dtsi @@ -351,6 +351,14 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l0/stm32l051.dtsi b/dts/arm/st/l0/stm32l051.dtsi index e6209dc531b..9c5bfa1b028 100644 --- a/dts/arm/st/l0/stm32l051.dtsi +++ b/dts/arm/st/l0/stm32l051.dtsi @@ -73,4 +73,12 @@ reg = <0x08080000 DT_SIZE_K(2)>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l0/stm32l071.dtsi b/dts/arm/st/l0/stm32l071.dtsi index 56d88c5bd51..95a8fdc8424 100644 --- a/dts/arm/st/l0/stm32l071.dtsi +++ b/dts/arm/st/l0/stm32l071.dtsi @@ -161,4 +161,20 @@ reg = <0x08080000 DT_SIZE_K(6)>; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 0203f740c83..53dbd64492d 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -26,7 +26,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; reg = <0>; @@ -482,6 +482,22 @@ io-channels = <&adc1 17>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l4/stm32l4.dtsi b/dts/arm/st/l4/stm32l4.dtsi index f2b8c1a2ff6..7dcabdf877c 100644 --- a/dts/arm/st/l4/stm32l4.dtsi +++ b/dts/arm/st/l4/stm32l4.dtsi @@ -493,6 +493,22 @@ io-channels = <&adc1 18>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/l4/stm32l412.dtsi b/dts/arm/st/l4/stm32l412.dtsi index f516ccdc57c..152340889fd 100644 --- a/dts/arm/st/l4/stm32l412.dtsi +++ b/dts/arm/st/l4/stm32l412.dtsi @@ -74,4 +74,12 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l431.dtsi b/dts/arm/st/l4/stm32l431.dtsi index 9a9892a0f4d..7fb1d7b4bd4 100644 --- a/dts/arm/st/l4/stm32l431.dtsi +++ b/dts/arm/st/l4/stm32l431.dtsi @@ -129,4 +129,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l433.dtsi b/dts/arm/st/l4/stm32l433.dtsi index c754097bec9..c0e1f0e18be 100644 --- a/dts/arm/st/l4/stm32l433.dtsi +++ b/dts/arm/st/l4/stm32l433.dtsi @@ -68,4 +68,12 @@ status = "disabled"; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l451.dtsi b/dts/arm/st/l4/stm32l451.dtsi index b566db4336a..c22e4ef0820 100644 --- a/dts/arm/st/l4/stm32l451.dtsi +++ b/dts/arm/st/l4/stm32l451.dtsi @@ -162,4 +162,20 @@ }; }; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l471.dtsi b/dts/arm/st/l4/stm32l471.dtsi index c1f5b5978a0..53a7fe28f02 100644 --- a/dts/arm/st/l4/stm32l471.dtsi +++ b/dts/arm/st/l4/stm32l471.dtsi @@ -274,4 +274,12 @@ die_temp: dietemp { ts-cal2-temp = <110>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l496.dtsi b/dts/arm/st/l4/stm32l496.dtsi index c11eba47796..4bba5f13ecc 100644 --- a/dts/arm/st/l4/stm32l496.dtsi +++ b/dts/arm/st/l4/stm32l496.dtsi @@ -82,4 +82,12 @@ die_temp: dietemp { ts-cal2-temp = <130>; }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l4/stm32l4p5.dtsi b/dts/arm/st/l4/stm32l4p5.dtsi index 03973dcf077..648fa936a5f 100644 --- a/dts/arm/st/l4/stm32l4p5.dtsi +++ b/dts/arm/st/l4/stm32l4p5.dtsi @@ -398,4 +398,20 @@ compatible = "usb-nop-xceiv"; #phy-cells = <0>; }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/l5/stm32l5.dtsi b/dts/arm/st/l5/stm32l5.dtsi index c8c94319353..f9c37b33cd8 100644 --- a/dts/arm/st/l5/stm32l5.dtsi +++ b/dts/arm/st/l5/stm32l5.dtsi @@ -40,7 +40,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; @@ -735,6 +734,22 @@ #phy-cells = <0>; }; + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + }; &nvic { diff --git a/dts/arm/st/mp1/stm32mp157.dtsi b/dts/arm/st/mp1/stm32mp157.dtsi index f70a96b6ead..2eec4faa4da 100644 --- a/dts/arm/st/mp1/stm32mp157.dtsi +++ b/dts/arm/st/mp1/stm32mp157.dtsi @@ -22,7 +22,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m4"; reg = <0>; @@ -398,6 +398,14 @@ status = "disabled"; }; }; + + smbus5: smbus5 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c5>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/u5/stm32u5.dtsi b/dts/arm/st/u5/stm32u5.dtsi index 7363181e663..43f4830bf72 100644 --- a/dts/arm/st/u5/stm32u5.dtsi +++ b/dts/arm/st/u5/stm32u5.dtsi @@ -41,7 +41,6 @@ mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; @@ -434,7 +433,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00000800>; interrupts = <67 1>; interrupt-names = "wakeup"; - st,static-prescaler; status = "disabled"; }; @@ -446,7 +444,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000020>; interrupts = <68 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -458,7 +455,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00001000>; interrupts = <98 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -470,7 +466,6 @@ clocks = <&rcc STM32_CLOCK_BUS_APB3 0x00002000>; interrupts = <110 0>; interrupt-names = "global"; - st,static-prescaler; status = "disabled"; }; @@ -803,7 +798,7 @@ reg = <0x4000a400 0x400>, <0x4000ac00 0x350>; reg-names = "m_can", "message_ram"; interrupts = <39 0>, <40 0>; - interrupt-names = "LINE_0", "LINE_1"; + interrupt-names = "int0", "int1"; clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000200>; bosch,mram-cfg = <0x0 28 8 3 3 0 3 3>; sample-point = <875>; @@ -845,6 +840,17 @@ status = "disabled"; }; }; + + }; + + swj_port: swj_port { + compatible = "swj-connector"; + pinctrl-0 = <&debug_jtms_swdio_pa13 &debug_jtck_swclk_pa14 + &debug_jtdi_pa15 &debug_jtdo_swo_pb3 + &debug_jtrst_pb4>; + pinctrl-1 = <&analog_pa13 &analog_pa14 &analog_pa15 + &analog_pb3 &analog_pb4>; + pinctrl-names = "default", "sleep"; }; die_temp: dietemp { @@ -888,6 +894,38 @@ io-channels = <&adc4 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; + + smbus4: smbus4 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c4>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/u5/stm32u595.dtsi b/dts/arm/st/u5/stm32u595.dtsi index db489205f95..3bc16eb120e 100644 --- a/dts/arm/st/u5/stm32u595.dtsi +++ b/dts/arm/st/u5/stm32u595.dtsi @@ -97,4 +97,20 @@ st,adc-sequencer = ; }; }; + + smbus5: smbus5 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c5>; + status = "disabled"; + }; + + smbus6: smbus6 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c6>; + status = "disabled"; + }; }; diff --git a/dts/arm/st/wb/stm32wb.dtsi b/dts/arm/st/wb/stm32wb.dtsi index f6a1c785b86..d76f2f243f7 100644 --- a/dts/arm/st/wb/stm32wb.dtsi +++ b/dts/arm/st/wb/stm32wb.dtsi @@ -547,6 +547,22 @@ clocks = <&rcc STM32_CLOCK_BUS_AHB3 0x00100000>, <&rcc STM32_SRC_LSE RFWKP_SEL(1)>; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 6c5cc8f869a..4ae45491f7f 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -21,6 +22,7 @@ chosen { zephyr,entropy = &rng; zephyr,flash-controller = &flash; + st,lptim-stdby-timer = &rtc; }; cpus { @@ -31,14 +33,13 @@ device_type = "cpu"; compatible = "arm,cortex-m33"; reg = <0>; - cpu-power-states = <&stop0 &stop1>; + cpu-power-states = <&stop0 &stop1 &standby>; #address-cells = <1>; #size-cells = <1>; mpu: mpu@e000ed90 { compatible = "arm,armv8m-mpu"; reg = <0xe000ed90 0x40>; - arm,num-mpu-regions = <8>; }; }; @@ -55,6 +56,13 @@ substate-id = <2>; min-residency-us = <500>; }; + standby: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + substate-id = <1>; + min-residency-us = <1000>; + exit-latency-us = <50>; + }; }; }; @@ -62,6 +70,15 @@ compatible = "mmio-sram"; }; + /* Defining this memory solves unaligned memory access issue */ + sram6: memory@48028000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x48028000 DT_SIZE_K(16)>; + device_type = "memory"; + zephyr,memory-region = "SRAM6"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; + }; + clocks { clk_hse: clk-hse { #clock-cells = <0>; @@ -434,7 +451,7 @@ reg = <0x520c0800 0x400>; interrupts = <59 0>; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00040000>, - <&rcc STM32_SRC_PLL1_Q RNG_SEL(3)>; + <&rcc STM32_SRC_HSI16 RNG_SEL(2)>; nist-config = <0xf00d>; health-test-config = <0xaac7>; status = "disabled"; @@ -452,6 +469,32 @@ status = "disabled"; }; }; + + swj_port: swj_port { + compatible = "swj-connector"; + pinctrl-0 = <&debug_jtms_swdio_pa13 &debug_jtck_swclk_pa14 + &debug_jtdi_pa15 &debug_jtdo_swo_pb3 + &debug_jtrst_pb4>; + pinctrl-1 = <&analog_pa13 &analog_pa14 &analog_pa15 + &analog_pb3 &analog_pb4>; + pinctrl-names = "default", "sleep"; + }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/st/wba/stm32wba52.dtsi b/dts/arm/st/wba/stm32wba52.dtsi new file mode 100644 index 00000000000..ef4f4d0f180 --- /dev/null +++ b/dts/arm/st/wba/stm32wba52.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + soc { + compatible = "st,stm32wba52", "st,stm32wba", "simple-bus"; + }; +}; diff --git a/dts/arm/st/wba/stm32wba52Xg.dtsi b/dts/arm/st/wba/stm32wba52Xg.dtsi index f4ddcbbc9e7..ecae645171b 100644 --- a/dts/arm/st/wba/stm32wba52Xg.dtsi +++ b/dts/arm/st/wba/stm32wba52Xg.dtsi @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include -#include +#include / { sram0: memory@20000000 { @@ -12,8 +12,6 @@ }; soc { - compatible = "st,stm32wba52", "st,stm32wba", "simple-bus"; - flash-controller@40022000 { flash0: flash@8000000 { reg = <0x08000000 DT_SIZE_M(1)>; diff --git a/dts/arm/st/wba/stm32wba55.dtsi b/dts/arm/st/wba/stm32wba55.dtsi new file mode 100644 index 00000000000..b8a8c6125a7 --- /dev/null +++ b/dts/arm/st/wba/stm32wba55.dtsi @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +/ { + soc { + compatible = "st,stm32wba55", "st,stm32wba", "simple-bus"; + }; +}; diff --git a/dts/arm/st/wba/stm32wba55Xg.dtsi b/dts/arm/st/wba/stm32wba55Xg.dtsi new file mode 100644 index 00000000000..f5c23f031e9 --- /dev/null +++ b/dts/arm/st/wba/stm32wba55Xg.dtsi @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(128)>; + }; + + soc { + flash-controller@40022000 { + flash0: flash@8000000 { + reg = <0x08000000 DT_SIZE_M(1)>; + }; + }; + }; +}; diff --git a/dts/arm/st/wl/stm32wl.dtsi b/dts/arm/st/wl/stm32wl.dtsi index cc4b4dc31c9..3dc4b3fcc3f 100644 --- a/dts/arm/st/wl/stm32wl.dtsi +++ b/dts/arm/st/wl/stm32wl.dtsi @@ -259,6 +259,7 @@ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>; resets = <&rctl STM32_RESET(APB1H, 0U)>; interrupts = <38 0>; + wakeup-line = <28>; status = "disabled"; }; @@ -522,6 +523,30 @@ io-channels = <&adc1 14>; status = "disabled"; }; + + smbus1: smbus1 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c1>; + status = "disabled"; + }; + + smbus2: smbus2 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c2>; + status = "disabled"; + }; + + smbus3: smbus3 { + compatible = "st,stm32-smbus"; + #address-cells = <1>; + #size-cells = <0>; + i2c = <&i2c3>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/xilinx/zynqmp.dtsi b/dts/arm/xilinx/zynqmp.dtsi index 84c1c574d22..65abc450543 100644 --- a/dts/arm/xilinx/zynqmp.dtsi +++ b/dts/arm/xilinx/zynqmp.dtsi @@ -11,6 +11,10 @@ / { soc { + pinctrl: pinctrl@ff180000 { + reg = <0xff180000 0xc80>; + compatible = "xlnx,pinctrl-zynqmp"; + }; flash0: flash@c0000000 { compatible = "soc-nv-flash"; reg = <0xc0000000 DT_SIZE_M(32)>; @@ -271,4 +275,5 @@ }; }; }; + }; diff --git a/dts/arm64/intel/intel_socfpga_agilex.dtsi b/dts/arm64/intel/intel_socfpga_agilex.dtsi index 19957a19988..e3b3e9b17ca 100644 --- a/dts/arm64/intel/intel_socfpga_agilex.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex.dtsi @@ -155,6 +155,33 @@ IRQ_DEFAULT_PRIORITY>; reg = <0xffd00100 0x100>; clock-frequency = < 100000000 >; + }; + + watchdog0: watchdog@ffd00200 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00200 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog1: watchdog@ffd00300 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00300 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog2: watchdog@ffd00400 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00400 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; + status = "disabled"; + }; + + watchdog3: watchdog@ffd00500 { + compatible = "snps,designware-watchdog"; + reg = <0xffd00500 0x100>; + clocks = <&clock INTEL_SOCFPGA_CLOCK_WDT>; status = "disabled"; }; }; diff --git a/dts/arm64/intel/intel_socfpga_agilex5.dtsi b/dts/arm64/intel/intel_socfpga_agilex5.dtsi index 6a98aa34df9..21cf2e68ed0 100644 --- a/dts/arm64/intel/intel_socfpga_agilex5.dtsi +++ b/dts/arm64/intel/intel_socfpga_agilex5.dtsi @@ -117,6 +117,19 @@ status = "okay"; }; + sdmmc: sdmmc@10808000 { + compatible = "cdns,sdhc"; + reg = <0x10808000 0x1000>, + <0x10B92000 0x1000>; + reg-names = "reg_base", "combo_phy"; + clock-frequency = <200000000>; + power_delay_ms = <1000>; + resets = <&reset RSTMGR_SDMMC_RSTLINE>, + <&reset RSTMGR_SDMMCECC_RSTLINE>, + <&reset RSTMGR_SOFTPHY_RSTLINE>; + status = "disabled"; + }; + timer0: timer@10C03000 { compatible = "snps,dw-timers"; interrupt-parent = <&gic>; @@ -158,6 +171,45 @@ reg = <0x10D00100 0x100>; clock-frequency = <100000000>; resets = <&reset RSTMGR_L4SYSTIMER1_RSTLINE>; + }; + + watchdog0: watchdog@10d00200 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00200 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG0_RSTLINE>; + status = "disabled"; + }; + + watchdog1: watchdog@10d00300 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00300 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG1_RSTLINE>; + status = "disabled"; + }; + + watchdog2: watchdog@10d00400 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00400 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG2_RSTLINE>; + status = "disabled"; + }; + + watchdog3: watchdog@10d00500 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00500 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG3_RSTLINE>; + status = "disabled"; + }; + + watchdog4: watchdog@10d00600 { + compatible = "snps,designware-watchdog"; + reg = <0x10d00600 0x100>; + clock-frequency = <100000000>; + resets = <&reset RSTMGR_WATCHDOG4_RSTLINE>; status = "disabled"; }; @@ -167,4 +219,20 @@ status = "disabled"; zephyr,num-clients = <2>; }; + + /* cadence Nand Flash controller*/ + nand: nand@10B80000 { + compatible = "cdns,nand"; + reg = <0x10B80000 0X10000>, + <0x10840000 0x10000>; + reg-names = "nand_reg","sdma"; + interrupt-parent = <&gic>; + interrupts = ; + resets = <&reset RSTMGR_NAND_RSTLINE>, + <&reset RSTMGR_SOFTPHY_RSTLINE>; + block-size = <0x20000>; + data-rate-mode = <0>; + status = "disabled"; + }; + }; diff --git a/dts/arm64/nxp/nxp_mimx93_a55.dtsi b/dts/arm64/nxp/nxp_mimx93_a55.dtsi index 22a61e2dfca..4592209c902 100644 --- a/dts/arm64/nxp/nxp_mimx93_a55.dtsi +++ b/dts/arm64/nxp/nxp_mimx93_a55.dtsi @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include / { #address-cells = <1>; @@ -75,6 +77,46 @@ #clock-cells = <3>; }; + gpio1: gpio@47400000 { + compatible = "nxp,imx-rgpio"; + reg = <0x47400000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: gpio@43810000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43810000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio3: gpio@43820000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43820000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio4: gpio@43830000 { + compatible = "nxp,imx-rgpio"; + reg = <0x43830000 DT_SIZE_K(64)>; + interrupt-parent = <&gic>; + interrupts = , + ; + gpio-controller; + #gpio-cells = <2>; + }; + lpuart1: serial@44380000 { compatible = "nxp,imx-lpuart", "nxp,kinetis-lpuart"; reg = <0x44380000 DT_SIZE_K(64)>; @@ -94,4 +136,308 @@ clocks = <&ccm IMX_CCM_LPUART2_CLK 0x6c 24>; status = "disabled"; }; + + lpi2c1: i2c@44340000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x44340000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C1_CLK 0x70 6>; + status = "disabled"; + }; + + lpi2c2: i2c@44350000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x44350000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C2_CLK 0x70 8>; + status = "disabled"; + }; + + lpi2c3: i2c@42530000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x42530000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C3_CLK 0x70 10>; + status = "disabled"; + }; + + lpi2c4: i2c@42540000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x42540000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C4_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c5: i2c@426b0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426b0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C5_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c6: i2c@426c0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426c0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C6_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c7: i2c@426d0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426d0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C7_CLK 0x80 24>; + status = "disabled"; + }; + + lpi2c8: i2c@426e0000 { + compatible = "nxp,imx-lpi2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x426e0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + clocks = <&ccm IMX_CCM_LPI2C8_CLK 0x80 24>; + status = "disabled"; + }; + + lpspi1: spi@44360000 { + compatible = "nxp,imx-lpspi"; + reg = <0x44360000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI1_CLK 0x6c 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi2: spi@44370000 { + compatible = "nxp,imx-lpspi"; + reg = <0x44370000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI2_CLK 0x6c 2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi3: spi@42550000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42550000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI3_CLK 0x6c 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi4: spi@42560000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42560000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI4_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi5: spi@426f0000 { + compatible = "nxp,imx-lpspi"; + reg = <0x426f0000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI5_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi6: spi@42700000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42700000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI6_CLK 0x6c 6>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi7: spi@42710000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42710000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI7_CLK 0x6c 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + lpspi8: spi@42720000 { + compatible = "nxp,imx-lpspi"; + reg = <0x42720000 0x4000>; + interrupts = ; + interrupt-parent = <&gic>; + status = "disabled"; + clocks = <&ccm IMX_CCM_LPSPI8_CLK 0x6c 2>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&gpio1{ + pinmux = <&iomuxc1_i2c1_scl_gpio_io_gpio1_io00>, + <&iomuxc1_i2c1_sda_gpio_io_gpio1_io01>, + <&iomuxc1_i2c2_scl_gpio_io_gpio1_io02>, + <&iomuxc1_i2c2_sda_gpio_io_gpio1_io03>, + <&iomuxc1_uart1_rxd_gpio_io_gpio1_io04>, + <&iomuxc1_uart1_txd_gpio_io_gpio1_io05>, + <&iomuxc1_uart2_rxd_gpio_io_gpio1_io06>, + <&iomuxc1_uart2_txd_gpio_io_gpio1_io07>, + <&iomuxc1_pdm_clk_gpio_io_gpio1_io08>, + <&iomuxc1_pdm_bit_stream0_gpio_io_gpio1_io09>, + <&iomuxc1_pdm_bit_stream1_gpio_io_gpio1_io10>, + <&iomuxc1_sai1_txfs_gpio_io_gpio1_io11>, + <&iomuxc1_sai1_txc_gpio_io_gpio1_io12>, + <&iomuxc1_sai1_txd0_gpio_io_gpio1_io13>, + <&iomuxc1_sai1_rxd0_gpio_io_gpio1_io14>, + <&iomuxc1_wdog_any_gpio_io_gpio1_io15>; +}; + +&gpio2{ + pinmux = <&iomuxc1_gpio_io00_gpio_io_gpio2_io00>, + <&iomuxc1_gpio_io01_gpio_io_gpio2_io01>, + <&iomuxc1_gpio_io02_gpio_io_gpio2_io02>, + <&iomuxc1_gpio_io03_gpio_io_gpio2_io03>, + <&iomuxc1_gpio_io04_gpio_io_gpio2_io04>, + <&iomuxc1_gpio_io05_gpio_io_gpio2_io05>, + <&iomuxc1_gpio_io06_gpio_io_gpio2_io06>, + <&iomuxc1_gpio_io07_gpio_io_gpio2_io07>, + <&iomuxc1_gpio_io08_gpio_io_gpio2_io08>, + <&iomuxc1_gpio_io09_gpio_io_gpio2_io09>, + <&iomuxc1_gpio_io10_gpio_io_gpio2_io10>, + <&iomuxc1_gpio_io11_gpio_io_gpio2_io11>, + <&iomuxc1_gpio_io12_gpio_io_gpio2_io12>, + <&iomuxc1_gpio_io13_gpio_io_gpio2_io13>, + <&iomuxc1_gpio_io14_gpio_io_gpio2_io14>, + <&iomuxc1_gpio_io15_gpio_io_gpio2_io15>, + <&iomuxc1_gpio_io16_gpio_io_gpio2_io16>, + <&iomuxc1_gpio_io17_gpio_io_gpio2_io17>, + <&iomuxc1_gpio_io18_gpio_io_gpio2_io18>, + <&iomuxc1_gpio_io19_gpio_io_gpio2_io19>, + <&iomuxc1_gpio_io20_gpio_io_gpio2_io20>, + <&iomuxc1_gpio_io21_gpio_io_gpio2_io21>, + <&iomuxc1_gpio_io22_gpio_io_gpio2_io22>, + <&iomuxc1_gpio_io23_gpio_io_gpio2_io23>, + <&iomuxc1_gpio_io24_gpio_io_gpio2_io24>, + <&iomuxc1_gpio_io25_gpio_io_gpio2_io25>, + <&iomuxc1_gpio_io26_gpio_io_gpio2_io26>, + <&iomuxc1_gpio_io27_gpio_io_gpio2_io27>, + <&iomuxc1_gpio_io28_gpio_io_gpio2_io28>, + <&iomuxc1_gpio_io29_gpio_io_gpio2_io29>; +}; + +&gpio3{ + pinmux = <&iomuxc1_sd2_cd_b_gpio_io_gpio3_io00>, + <&iomuxc1_sd2_clk_gpio_io_gpio3_io01>, + <&iomuxc1_sd2_cmd_gpio_io_gpio3_io02>, + <&iomuxc1_sd2_data0_gpio_io_gpio3_io03>, + <&iomuxc1_sd2_data1_gpio_io_gpio3_io04>, + <&iomuxc1_sd2_data2_gpio_io_gpio3_io05>, + <&iomuxc1_sd2_data3_gpio_io_gpio3_io06>, + <&iomuxc1_sd2_reset_b_gpio_io_gpio3_io07>, + <&iomuxc1_sd1_clk_gpio_io_gpio3_io08>, + <&iomuxc1_sd1_cmd_gpio_io_gpio3_io09>, + <&iomuxc1_sd1_data0_gpio_io_gpio3_io10>, + <&iomuxc1_sd1_data1_gpio_io_gpio3_io11>, + <&iomuxc1_sd1_data2_gpio_io_gpio3_io12>, + <&iomuxc1_sd1_data3_gpio_io_gpio3_io13>, + <&iomuxc1_sd1_data4_gpio_io_gpio3_io14>, + <&iomuxc1_sd1_data5_gpio_io_gpio3_io15>, + <&iomuxc1_sd1_data6_gpio_io_gpio3_io16>, + <&iomuxc1_sd1_data7_gpio_io_gpio3_io17>, + <&iomuxc1_sd1_strobe_gpio_io_gpio3_io18>, + <&iomuxc1_sd2_vselect_gpio_io_gpio3_io19>, + <&iomuxc1_sd3_clk_gpio_io_gpio3_io20>, + <&iomuxc1_sd3_cmd_gpio_io_gpio3_io21>, + <&iomuxc1_sd3_data0_gpio_io_gpio3_io22>, + <&iomuxc1_sd3_data1_gpio_io_gpio3_io23>, + <&iomuxc1_sd3_data2_gpio_io_gpio3_io24>, + <&iomuxc1_sd3_data3_gpio_io_gpio3_io25>, + <&iomuxc1_ccm_clko1_gpio_io_gpio3_io26>, + <&iomuxc1_ccm_clko2_gpio_io_gpio3_io27>, + <&iomuxc1_dap_tdi_gpio_io_gpio3_io28>, + <&iomuxc1_dap_tms_swdio_gpio_io_gpio3_io29>, + <&iomuxc1_dap_tclk_swclk_gpio_io_gpio3_io30>, + <&iomuxc1_dap_tdo_traceswo_gpio_io_gpio3_io31>; +}; + +&gpio4{ + pinmux = <&iomuxc1_enet1_mdc_gpio_io_gpio4_io00>, + <&iomuxc1_enet1_mdio_gpio_io_gpio4_io01>, + <&iomuxc1_enet1_td3_gpio_io_gpio4_io02>, + <&iomuxc1_enet1_td2_gpio_io_gpio4_io03>, + <&iomuxc1_enet1_td1_gpio_io_gpio4_io04>, + <&iomuxc1_enet1_td0_gpio_io_gpio4_io05>, + <&iomuxc1_enet1_tx_ctl_gpio_io_gpio4_io06>, + <&iomuxc1_enet1_txc_gpio_io_gpio4_io07>, + <&iomuxc1_enet1_rx_ctl_gpio_io_gpio4_io08>, + <&iomuxc1_enet1_rxc_gpio_io_gpio4_io09>, + <&iomuxc1_enet1_rd0_gpio_io_gpio4_io10>, + <&iomuxc1_enet1_rd1_gpio_io_gpio4_io11>, + <&iomuxc1_enet1_rd2_gpio_io_gpio4_io12>, + <&iomuxc1_enet1_rd3_gpio_io_gpio4_io13>, + <&iomuxc1_enet2_mdc_gpio_io_gpio4_io14>, + <&iomuxc1_enet2_mdio_gpio_io_gpio4_io15>, + <&iomuxc1_enet2_td3_gpio_io_gpio4_io16>, + <&iomuxc1_enet2_td2_gpio_io_gpio4_io17>, + <&iomuxc1_enet2_td1_gpio_io_gpio4_io18>, + <&iomuxc1_enet2_td0_gpio_io_gpio4_io19>, + <&iomuxc1_enet2_tx_ctl_gpio_io_gpio4_io20>, + <&iomuxc1_enet2_txc_gpio_io_gpio4_io21>, + <&iomuxc1_enet2_rx_ctl_gpio_io_gpio4_io22>, + <&iomuxc1_enet2_rxc_gpio_io_gpio4_io23>, + <&iomuxc1_enet2_rd0_gpio_io_gpio4_io24>, + <&iomuxc1_enet2_rd1_gpio_io_gpio4_io25>, + <&iomuxc1_enet2_rd2_gpio_io_gpio4_io26>, + <&iomuxc1_enet2_rd3_gpio_io_gpio4_io27>, + <&iomuxc1_ccm_clko3_gpio_io_gpio4_io28>, + <&iomuxc1_ccm_clko4_gpio_io_gpio4_io29>; }; diff --git a/dts/bindings/acpi/acpi.yaml b/dts/bindings/acpi/acpi.yaml new file mode 100644 index 00000000000..26a7dd803b1 --- /dev/null +++ b/dts/bindings/acpi/acpi.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for ACPI informed based devices + +properties: + acpi-hid: + type: string + description: Used to supply OSPM with the device’s PNP ID or ACPI ID. + A node is consder as acpi based or not based on whether this property + is present or not. + + acpi-uid: + type: string + description: | + Provides OSPM with a logical device ID that does not change + across reboots. This object is optional, but is required when the device + has no other way to report a persistent unique device ID. The _UID must be + unique across all devices with either a common _HID or _CID. + + acpi-comp-id: + type: string-array + description: Used to supply OSPM with a device’s Plug and Play-Compatible Device ID diff --git a/dts/bindings/adc/espressif,esp32-adc.yaml b/dts/bindings/adc/espressif,esp32-adc.yaml index 2aedb107c7a..d3907dba640 100644 --- a/dts/bindings/adc/espressif,esp32-adc.yaml +++ b/dts/bindings/adc/espressif,esp32-adc.yaml @@ -14,7 +14,7 @@ description: | Zephyr API is using gain unit to characterize ADC input. To achieve compatibility we choose to select those gain, - which coresponds to the ESP32 ADC attenuation feature. + which corresponds to the ESP32 ADC attenuation feature. ESP32,attenuation ~ zephyr,gain ----------------- ----------- diff --git a/dts/bindings/adc/infineon,cat1-adc.yaml b/dts/bindings/adc/infineon,cat1-adc.yaml index 1cff8da2dd9..7ae64d8845a 100644 --- a/dts/bindings/adc/infineon,cat1-adc.yaml +++ b/dts/bindings/adc/infineon,cat1-adc.yaml @@ -6,7 +6,7 @@ description: | Infineon Cat1 ADC Each ADC group Cat1 is assigned to a Zephyr device. Refer to the Infineon PSoC6 reference - manual (Section Port I/O functions) for the group/chanel mapping to a specific port-pin on + manual (Section Port I/O functions) for the group/channel mapping to a specific port-pin on the board. For example on the cy8cproto_062_4343w P10.0 is mapped to adc0,channel0 and P10.1 is mapped to adc0,channel1. diff --git a/dts/bindings/adc/infineon,xmc4xxx-adc.yaml b/dts/bindings/adc/infineon,xmc4xxx-adc.yaml index 4d1296b1c71..0631ea30367 100644 --- a/dts/bindings/adc/infineon,xmc4xxx-adc.yaml +++ b/dts/bindings/adc/infineon,xmc4xxx-adc.yaml @@ -4,7 +4,7 @@ description: | Infineon XMC4XXX ADC Each ADC group XMC4XXX is assigned to a Zephyr device. Refer to Infineon XMC4XXX reference manual - (Section Port I/O functions) for the group/chanel mapping to a specific port-pin on the board. + (Section Port I/O functions) for the group/channel mapping to a specific port-pin on the board. For example on the xmc45_relax_kit P14.0 is mapped to adc0,channel0 and P14.1 is mapped to adc0,channel1. diff --git a/dts/bindings/adc/microchip,mcp320x-base.yaml b/dts/bindings/adc/microchip,mcp320x-base.yaml index c5d80c9a637..9bee60f1320 100644 --- a/dts/bindings/adc/microchip,mcp320x-base.yaml +++ b/dts/bindings/adc/microchip,mcp320x-base.yaml @@ -7,4 +7,4 @@ properties: const: 1 io-channel-cells: - - channel + - input diff --git a/dts/bindings/adc/nuvoton,numaker-adc.yaml b/dts/bindings/adc/nuvoton,numaker-adc.yaml new file mode 100644 index 00000000000..66708431381 --- /dev/null +++ b/dts/bindings/adc/nuvoton,numaker-adc.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker ADC controller + +compatible: "nuvoton,numaker-adc" + +include: [adc-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + channels: + type: int + description: Number of channels + required: true + + "#io-channel-cells": + const: 1 + +io-channel-cells: + - input diff --git a/dts/bindings/iio/adc/nxp,vf610-adc.yaml b/dts/bindings/adc/nxp,vf610-adc.yaml similarity index 100% rename from dts/bindings/iio/adc/nxp,vf610-adc.yaml rename to dts/bindings/adc/nxp,vf610-adc.yaml diff --git a/dts/bindings/adc/ti,lmp90xxx-base.yaml b/dts/bindings/adc/ti,lmp90xxx-base.yaml index 4225c9b0cc3..8c0bb066b80 100644 --- a/dts/bindings/adc/ti,lmp90xxx-base.yaml +++ b/dts/bindings/adc/ti,lmp90xxx-base.yaml @@ -10,8 +10,7 @@ properties: description: Data Ready Bar "#io-channel-cells": - const: 2 + const: 1 io-channel-cells: - - positive - - negative + - input diff --git a/dts/bindings/arm/atmel,samd2x-pm.yaml b/dts/bindings/arm/atmel,samd2x-pm.yaml index 00dfda33c03..7fa232b815d 100644 --- a/dts/bindings/arm/atmel,samd2x-pm.yaml +++ b/dts/bindings/arm/atmel,samd2x-pm.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2020, Linaro Limited # SPDX-License-Identifier: Apache-2.0 -description: Atmel SAMD2x Power Manger (PM) +description: Atmel SAMD2x Power Manager (PM) compatible: "atmel,samd2x-pm" diff --git a/dts/bindings/arm/nordic,nrf-ficr.yaml b/dts/bindings/arm/nordic,nrf-ficr.yaml deleted file mode 100644 index bea0762573e..00000000000 --- a/dts/bindings/arm/nordic,nrf-ficr.yaml +++ /dev/null @@ -1,9 +0,0 @@ -description: Nordic FICR (Factory Information Configuration Registers) - -compatible: "nordic,nrf-ficr" - -include: base.yaml - -properties: - reg: - required: true diff --git a/dts/bindings/arm/nordic,nrf-uicr-v2.yaml b/dts/bindings/arm/nordic,nrf-uicr-v2.yaml new file mode 100644 index 00000000000..f509fdf4061 --- /dev/null +++ b/dts/bindings/arm/nordic,nrf-uicr-v2.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic UICR v2 (User Information Configuration Registers) + +compatible: "nordic,nrf-uicr-v2" + +include: base.yaml + +properties: + reg: + required: true + + domain: + type: int + required: true + description: | + Domain ID of the domain associated with this UICR instance. Must be unique + across all UICR instances in the system. + + ptr-ext-uicr: + type: phandle + required: true + description: | + Handle of a memory region reserved to contain an Extended UICR instance. + The address of that node will be stored in the UICR.PTREXTUICR register. diff --git a/dts/bindings/audio/nxp,dmic.yaml b/dts/bindings/audio/nxp,dmic.yaml new file mode 100644 index 00000000000..77f1d0e74a7 --- /dev/null +++ b/dts/bindings/audio/nxp,dmic.yaml @@ -0,0 +1,97 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP DMIC + +compatible: "nxp,dmic" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + clocks: + required: true + + use2fs: + type: boolean + description: | + Use 2FS output, and bypass final half band decimator. This will reduce + the required PDM bit clock frequency by a factor of two, and can reduce + power consumption. + +# Child binding definition, describes each channel of the DMIC +child-binding: + description: | + NXP DMIC channel. Can be used to configure filtering and gain attributes + of each channel + include: base.yaml + compatible: "nxp,dmic-channel" + properties: + reg: + required: true + dmas: + required: true + + gainshift: + type: int + default: 0 + description: | + Decimator gain shift. Sets the number of bits to shift decimated PCM + data by, as a positive or negative number. Range of [-15,15]. Default + is reset value of register + + compensation-2fs: + type: string + default: "zero" + enum: + - "zero" + - "-0.16" + - "-0.15" + - "-0.13" + description: | + 2FS compensation filter. See SOC reference manual for filter response + of each value. Default value is reset value of register, and + recommended filter setting. + + compensation-4fs: + type: string + default: "zero" + enum: + - "zero" + - "-0.16" + - "-0.15" + - "-0.13" + description: | + 4FS compensation filter. See SOC reference manual for filter response + of each value. Default value is reset value of register, and + recommended filter setting. + + dc-cutoff: + type: string + default: "flat" + enum: + - "flat" + - "155hz" + - "78hz" + - "39hz" + description: | + DC cutoff filter setting. Default is reset value of register. Note that + each cutoff frequency is based on a sample frequency of 16KHz, so + actual cutoff values will scale up or down based on your sampling + frequency + + dc-gain: + type: int + default: 0 + description: | + DC gain fine adjustment. Number of bits to downshift the final + conversion result. Max value of 15. Default is reset value of + register diff --git a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml index 1a4d5734f36..60c17fc7860 100644 --- a/dts/bindings/auxdisplay/sparkfun,serlcd.yaml +++ b/dts/bindings/auxdisplay/sparkfun,serlcd.yaml @@ -11,6 +11,8 @@ description: | reg = <0x72>; columns = <16>; rows = <2>; + command-delay = <10>; + special-command-delay = <50>; }; }; @@ -32,3 +34,23 @@ properties: enum: - 2 - 4 + + command-delay-ms: + type: int + default: 10 + description: | + Delay in milliseconds (defaults to 10ms if not set) after a normal command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. + + special-command-delay-ms: + type: int + default: 50 + description: | + Delay in milliseconds (defaults to 50ms if not set) after a special command was sent. + The default value is based on the original SparkFun SerLCD library + implementation which assumes 100 kbps I2C configuration. This value + might require tweaking if using I2C at a higher bitrare and/or relativily + high update frequency of the display. diff --git a/dts/bindings/base/mutable.yaml b/dts/bindings/base/mutable.yaml new file mode 100644 index 00000000000..0e2d1cad3b0 --- /dev/null +++ b/dts/bindings/base/mutable.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +# Properties for Mutable devices + +properties: + zephyr,mutable: + type: boolean + description: | + True iff the device structure may be mutated. + + Inherit this binding for devices that are runtime-modifiable, in-place. + This places the device structure into SRAM rather than Flash. diff --git a/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml new file mode 100644 index 00000000000..42df66d2180 --- /dev/null +++ b/dts/bindings/bluetooth/ambiq,bt-hci-spi.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023, Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bluetooth module that uses Ambiq's Bluetooth Host Controller Interface SPI + driver (e.g. Apollo4 Blue Plus). + +compatible: "ambiq,bt-hci-spi" + +properties: + reg: + type: array + required: true + + irq-gpios: + type: phandle-array + description: | + This irq gpio is used to indicate there is packet ready to send to host + from controller. + + reset-gpios: + type: phandle-array + description: | + This reset gpio is used to reset the Bluetooth controller. + + clkreq-gpios: + type: phandle-array + description: | + This clkreq gpio is used to send the XO32MHz clock request to host from + controller. The host needs to enable XO32MHz when receiving low to high + edge interrupts and disable XO32MHz when receiving high to low edge + interrupts. diff --git a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml index e45c7c35983..25213af3ecc 100644 --- a/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml +++ b/dts/bindings/bluetooth/infineon,cyw43xxx-bt-hci.yaml @@ -66,10 +66,10 @@ properties: type: int description: | HCI UART boudrate for feature operation. If not defined - bus/current-speed wil be used as default. + bus/current-speed will be used as default. fw-download-speed: type: int description: | - HCI UART boudrate for FW dowload operation. If not defined - bus/current-speed wil be used as default. + HCI UART boudrate for FW download operation. If not defined + bus/current-speed will be used as default. diff --git a/dts/bindings/bluetooth/st,hci-spi-v1.yaml b/dts/bindings/bluetooth/st,hci-spi-v1.yaml new file mode 100644 index 00000000000..3784c88ded0 --- /dev/null +++ b/dts/bindings/bluetooth/st,hci-spi-v1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STMicroelectronics SPI protocol V1 compatible with BlueNRG-MS devices + +compatible: "st,hci-spi-v1" + +include: zephyr,bt-hci-spi.yaml diff --git a/dts/bindings/bluetooth/st,hci-spi-v2.yaml b/dts/bindings/bluetooth/st,hci-spi-v2.yaml new file mode 100644 index 00000000000..36b25eae768 --- /dev/null +++ b/dts/bindings/bluetooth/st,hci-spi-v2.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STMicroelectronics SPI protocol V2 compatible with BlueNRG-1 and successor devices + +compatible: "st,hci-spi-v2" + +include: zephyr,bt-hci-spi.yaml diff --git a/dts/bindings/can/atmel,sam-can.yaml b/dts/bindings/can/atmel,sam-can.yaml index e6930009194..c224604fa0b 100644 --- a/dts/bindings/can/atmel,sam-can.yaml +++ b/dts/bindings/can/atmel,sam-can.yaml @@ -13,6 +13,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/atmel,sam0-can.yaml b/dts/bindings/can/atmel,sam0-can.yaml index 486620a21b7..7002386c922 100644 --- a/dts/bindings/can/atmel,sam0-can.yaml +++ b/dts/bindings/can/atmel,sam0-can.yaml @@ -13,6 +13,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/infineon,xmc4xxx-can-node.yaml b/dts/bindings/can/infineon,xmc4xxx-can-node.yaml new file mode 100644 index 00000000000..8fa50922ace --- /dev/null +++ b/dts/bindings/can/infineon,xmc4xxx-can-node.yaml @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Infineon XMC4xxx CAN Node + +compatible: "infineon,xmc4xxx-can-node" + +include: ["can-controller.yaml", "pinctrl-device.yaml"] + +properties: + reg: + required: true + + interrupts: + required: true + + clock_div8: + description: Option enables clock divide by a factor of 8. + type: boolean + + input-src: + description: Connects the CAN input line to a specific IO. + type: string + required: true + enum: + - "RXDA" + - "RXDB" + - "RXDC" + - "RXDD" + - "RXDE" + - "RXDF" + - "RXDG" + - "RXDH" diff --git a/dts/bindings/can/infineon,xmc4xxx-can.yaml b/dts/bindings/can/infineon,xmc4xxx-can.yaml new file mode 100644 index 00000000000..66b0fb72a87 --- /dev/null +++ b/dts/bindings/can/infineon,xmc4xxx-can.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Andriy Gelman +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Infineon XMC4xxx CAN + +compatible: "infineon,xmc4xxx-can" + +include: base.yaml + +properties: + reg: + required: true + + clock-prescaler: + type: int + required: true + description: Clock divider for the input clock. Valid range is [1, 1023]. + + message-objects: + type: int + required: true + description: Number of total can messages supported by hardware. diff --git a/dts/bindings/can/microchip,mcp251xfd.yaml b/dts/bindings/can/microchip,mcp251xfd.yaml index de86c320d30..b35cb0fa48a 100644 --- a/dts/bindings/can/microchip,mcp251xfd.yaml +++ b/dts/bindings/can/microchip,mcp251xfd.yaml @@ -47,8 +47,8 @@ properties: pll-enable: type: boolean description: | - Enables controller PLL, which multiples input clock frequency x10. - This parameter also implicity sets whether the clock is from the PLL + Enables controller PLL, which multiplies input clock frequency by 10. + This parameter also implicitly sets whether the clock is from the PLL output or directly from the oscillator. If this option is enabled the clock source is the PLL, otherwise its the oscillator. diff --git a/dts/bindings/can/nuvoton,numaker-canfd.yaml b/dts/bindings/can/nuvoton,numaker-canfd.yaml index e3d28f5ce28..f70e86693c1 100644 --- a/dts/bindings/can/nuvoton,numaker-canfd.yaml +++ b/dts/bindings/can/nuvoton,numaker-canfd.yaml @@ -14,6 +14,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + resets: required: true diff --git a/dts/bindings/can/nxp,lpc-mcan.yaml b/dts/bindings/can/nxp,lpc-mcan.yaml index a17b0132e62..48aef003139 100644 --- a/dts/bindings/can/nxp,lpc-mcan.yaml +++ b/dts/bindings/can/nxp,lpc-mcan.yaml @@ -11,5 +11,8 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/st,stm32-fdcan.yaml b/dts/bindings/can/st,stm32-fdcan.yaml index d950bb4e924..f4cfb310dac 100644 --- a/dts/bindings/can/st,stm32-fdcan.yaml +++ b/dts/bindings/can/st,stm32-fdcan.yaml @@ -11,6 +11,9 @@ properties: interrupts: required: true + interrupt-names: + required: true + clocks: required: true diff --git a/dts/bindings/can/st,stm32h7-fdcan.yaml b/dts/bindings/can/st,stm32h7-fdcan.yaml index 3cee6e29219..14f6fad61c5 100644 --- a/dts/bindings/can/st,stm32h7-fdcan.yaml +++ b/dts/bindings/can/st,stm32h7-fdcan.yaml @@ -13,3 +13,32 @@ properties: interrupts: required: true + + interrupt-names: + required: true + + clk-divider: + type: int + enum: + - 1 + - 2 + - 4 + - 6 + - 8 + - 10 + - 12 + - 14 + - 16 + - 18 + - 20 + - 22 + - 24 + - 26 + - 28 + - 30 + description: | + Divides the kernel clock giving the time quanta clock that is fed to the FDCAN core + (FDCAN_CCU->CCFG CDIV register bits). Note that the divisor is common to all + 'st,stm32h7-fdcan' instances. + + Divide by 1 is the peripherals reset value and remains set unless this property is configured. diff --git a/dts/bindings/can/zephyr,native-linux-can.yaml b/dts/bindings/can/zephyr,native-linux-can.yaml new file mode 100644 index 00000000000..4175617403b --- /dev/null +++ b/dts/bindings/can/zephyr,native-linux-can.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2022 Martin Jäger +# SPDX-License-Identifier: Apache-2.0 + +description: Zephyr CAN driver using Linux SocketCAN + +compatible: "zephyr,native-linux-can" + +include: can-controller.yaml + +properties: + host-interface: + type: string + required: true + description: Linux host interface name (e.g. zcan0, vcan0, can0, ...) diff --git a/dts/bindings/can/zephyr,native-posix-linux-can.yaml b/dts/bindings/can/zephyr,native-posix-linux-can.yaml deleted file mode 100644 index 275019a2c9e..00000000000 --- a/dts/bindings/can/zephyr,native-posix-linux-can.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2022 Martin Jäger -# SPDX-License-Identifier: Apache-2.0 - -description: Zephyr CAN driver using Linux SocketCAN - -compatible: "zephyr,native-posix-linux-can" - -include: can-controller.yaml - -properties: - host-interface: - type: string - required: true - description: Linux host interface name (e.g. zcan0, vcan0, can0, ...) diff --git a/dts/bindings/charger/ti,bq25180.yaml b/dts/bindings/charger/ti,bq25180.yaml new file mode 100644 index 00000000000..be3b336aa50 --- /dev/null +++ b/dts/bindings/charger/ti,bq25180.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + BQ25180 I2C Controlled, 1-Cell, 1-A Linear Battery Charger with Power Path + and Ship Mode. + + The device has a single child node for the charger. For example: + + bq25180@6a { + compatible = "ti,bq25180"; + reg = <0x6a>; + + constant-charge-current-max-microamp = <500000>; + }; + +compatible: "ti,bq25180" + +include: [battery.yaml, i2c-device.yaml] + + +properties: + constant-charge-current-max-microamp: + type: int + default: 0 + description: | + Charge current set at init time in uA, available range is 5 mA to 800 mA. + The value specified will be rounded down to the closest implemented + value. If set to 0 (default) skip setting the charge current value at + driver initialization. diff --git a/dts/bindings/clock/microchip,xec-pcr.yaml b/dts/bindings/clock/microchip,xec-pcr.yaml index 5a07aec6d40..00acde17ff8 100644 --- a/dts/bindings/clock/microchip,xec-pcr.yaml +++ b/dts/bindings/clock/microchip,xec-pcr.yaml @@ -59,7 +59,7 @@ properties: type: int required: true description: | - Mininum number of consecutive 32KHz pulses that pass all monitor tests + Minimum number of consecutive 32KHz pulses that pass all monitor tests xtal-enable-delay-ms: type: int diff --git a/dts/bindings/clock/nordic,nrf-hfxo.yaml b/dts/bindings/clock/nordic,nrf-hfxo.yaml new file mode 100644 index 00000000000..cd82e1c34d3 --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-hfxo.yaml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF high-frequency crystal oscillator + +compatible: "nordic,nrf-hfxo" + +include: fixed-clock.yaml + +properties: + clock-frequency: + const: 32000000 + + load-capacitors: + type: string + enum: + - "internal" + - "external" + description: | + Type of load capacitors connected to the crystal. If not specified, + adjustments may still happen when the device trimming happens during + system initialization. + + load-capacitance-femtofarad: + type: int + enum: + - 4000 + - 4250 + - 4500 + - 4750 + - 5000 + - 5250 + - 5500 + - 5750 + - 6000 + - 6250 + - 6500 + - 6750 + - 7000 + - 7250 + - 7500 + - 7750 + - 8000 + - 8250 + - 8500 + - 8750 + - 9000 + - 9250 + - 9500 + - 9750 + - 10000 + - 10250 + - 10500 + - 10750 + - 11000 + - 11250 + - 11500 + - 11750 + - 12000 + - 12250 + - 12500 + - 12750 + - 13000 + - 13250 + - 13500 + - 13750 + - 14000 + - 14250 + - 14500 + - 14750 + - 15000 + - 15250 + - 15500 + - 15750 + - 16000 + - 16250 + - 16500 + - 16750 + - 17000 + description: | + Load capacitance in femtofarads. This property is only used when + load-capacitors is set to "internal". diff --git a/dts/bindings/clock/nordic,nrf-hsfll.yaml b/dts/bindings/clock/nordic,nrf-hsfll.yaml new file mode 100644 index 00000000000..3614d80870f --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-hsfll.yaml @@ -0,0 +1,65 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic nRF HSFLL + + The HSFLL mixed-mode IP generates several clock frequencies in the range from + 64 MHz to 400 MHz (in steps of 16 MHz). + + Usage example: + + hsfll: clock@deadbeef { + compatible = "nordic,nrf-hsfll"; + reg = <0xdeadbeef 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + + Required FICR entries are for VSUP, COARSE and FINE trim values. + +compatible: "nordic,nrf-hsfll" + +include: [base.yaml, fixed-clock.yaml, nordic-nrf-ficr-client.yaml] + +properties: + reg: + required: true + + clocks: + required: true + + clock-frequency: + enum: + - 64000000 + - 80000000 + - 96000000 + - 112000000 + - 128000000 + - 144000000 + - 160000000 + - 176000000 + - 192000000 + - 208000000 + - 224000000 + - 240000000 + - 256000000 + - 272000000 + - 288000000 + - 304000000 + - 320000000 + - 336000000 + - 352000000 + - 368000000 + - 384000000 + - 400000000 + + nordic,ficrs: + required: true + + nordic,ficr-names: + required: true diff --git a/dts/bindings/clock/nordic,nrf-lfxo.yaml b/dts/bindings/clock/nordic,nrf-lfxo.yaml new file mode 100644 index 00000000000..328c374769c --- /dev/null +++ b/dts/bindings/clock/nordic,nrf-lfxo.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic nRF low-frequency crystal oscillator + +compatible: "nordic,nrf-lfxo" + +include: fixed-clock.yaml + +properties: + clock-frequency: + const: 32768 + + load-capacitors: + type: string + enum: + - "internal" + - "external" + description: | + Type of load capacitors connected to the crystal. If not specified, + adjustments may still happen when the device trimming happens during + system initialization. + + load-capacitance-femtofarad: + type: int + enum: + - 4000 + - 4500 + - 5000 + - 5500 + - 6000 + - 6500 + - 7000 + - 7500 + - 8000 + - 8500 + - 9000 + - 9500 + - 10000 + - 10500 + - 11000 + - 11500 + - 12000 + - 12500 + - 13000 + - 13500 + - 14000 + - 14500 + - 15000 + - 15500 + - 16000 + - 16500 + - 17000 + - 17500 + - 18000 + description: | + Load capacitance in femtofarads. This property is only used when + load-capacitors is set to "internal". diff --git a/dts/bindings/clock/pwm-clock.yaml b/dts/bindings/clock/pwm-clock.yaml index 5e19a245809..d377aa0fb2b 100644 --- a/dts/bindings/clock/pwm-clock.yaml +++ b/dts/bindings/clock/pwm-clock.yaml @@ -22,7 +22,7 @@ description: | property. The PWM node may need to be properly configured to generate - the target period (i.e. using prescaler options). See the documention + the target period (i.e. using prescaler options). See the documentation for the target PWM driver. compatible: "pwm-clock" diff --git a/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml new file mode 100644 index 00000000000..a4f8557e8ca --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-clock-controller.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2022 Andrei-Edward Popa +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico clock controller node + +compatible: "raspberrypi,pico-clock-controller" + +include: [base.yaml, clock-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 1 + +clock-cells: + - clk-id diff --git a/dts/bindings/clock/raspberrypi,pico-clock.yaml b/dts/bindings/clock/raspberrypi,pico-clock.yaml new file mode 100644 index 00000000000..c787f3c7e81 --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-clock.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico's clock + +compatible: "raspberrypi,pico-clock" + +include: fixed-clock.yaml + +properties: + clocks: + type: phandle-array + description: Clock gate information + + clock-names: + type: string-array + description: name of each clock diff --git a/dts/bindings/clock/raspberrypi,pico-pll.yaml b/dts/bindings/clock/raspberrypi,pico-pll.yaml new file mode 100644 index 00000000000..d3859802c7d --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-pll.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico's PLL. + +compatible: "raspberrypi,pico-pll" + +include: [base.yaml, fixed-factor-clock.yaml] + +properties: + fb-div: + type: int + required: true + description: | + The feedback divider value. + The valid range is 16 to 320. + + post-div1: + type: int + required: true + description: | + The post clock divider. + The valid range is 1 to 49. + + post-div2: + type: int + required: true + description: | + The post clock divider. + The valid range is 1 to 49. diff --git a/dts/bindings/clock/raspberrypi,pico-rosc.yaml b/dts/bindings/clock/raspberrypi,pico-rosc.yaml new file mode 100644 index 00000000000..79058bc75c3 --- /dev/null +++ b/dts/bindings/clock/raspberrypi,pico-rosc.yaml @@ -0,0 +1,38 @@ +# Copyright (c) 2023 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The representation of Raspberry Pi Pico ring oscillator. + +compatible: "raspberrypi,pico-rosc" + +include: [fixed-clock.yaml, fixed-factor-clock.yaml] + +properties: + range: + type: int + required: true + description: | + Specify the number of ring oscillator stages to use. + - LOW: 8 (default) + - MEDIUM: 6 + - HIGH: 4 + - TOOHIGH: 2 + + stage-drive-strength: + type: array + required: true + description: | + Specifies the drive strength of the eight stages of the ring oscillator. + The valid range of each value is between 0 and 7. + + phase-flip: + type: boolean + description: | + Flipping phase-shifter output. + + phase: + type: int + description: | + The phase-shift value. + The valid range is 0 to 3 diff --git a/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml new file mode 100644 index 00000000000..89d3fa6fdfe --- /dev/null +++ b/dts/bindings/clock/renesas,r8a779f0-cpg-mssr.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 EPAM Systems +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas R8A779F0 SoC Clock Pulse Generator / Module Standby and Software Reset + +compatible: "renesas,r8a779f0-cpg-mssr" + +include: renesas,rcar-cpg-mssr.yaml diff --git a/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml b/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml index 07b244ea79d..2769a02ce2d 100644 --- a/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml +++ b/dts/bindings/clock/renesas,ra-clock-generation-circuit.yaml @@ -37,7 +37,7 @@ properties: clock-source: type: phandle - description: System clock sorce + description: System clock source "#clock-cells": const: 1 diff --git a/dts/bindings/clock/silabs,hfxo.yaml b/dts/bindings/clock/silabs,hfxo.yaml index cd0d3ad1742..a5d0fdeff95 100644 --- a/dts/bindings/clock/silabs,hfxo.yaml +++ b/dts/bindings/clock/silabs,hfxo.yaml @@ -7,3 +7,7 @@ properties: type: int required: true description: Load capacitance configuration + precision: + type: int + required: true + description: Precision configuration diff --git a/dts/bindings/clock/st,stm32-hse-clock.yaml b/dts/bindings/clock/st,stm32-hse-clock.yaml index 833a393595d..45cfa050c50 100644 --- a/dts/bindings/clock/st,stm32-hse-clock.yaml +++ b/dts/bindings/clock/st,stm32-hse-clock.yaml @@ -13,3 +13,19 @@ properties: description: | HSE crystal oscillator bypass Set to the property to by-pass the oscillator with an external clock. + + css-enabled: + type: boolean + description: | + HSE clock security system enabled + Set the property to enable the clock security system (CSS) for the HSE clock. + + If a failure is detected on the HSE clock, the HSE oscillator is automatically disabled, + a clock failure event is sent to timers, and a non-maskable interrupt is generated to + inform the software about the failure, allowing the MCU to perform rescue operations. + See the MCU reference manual for details. + + The interaction of CSS and low-power modes is unclear from the documentation. + For at least some devices Zephyr will reconfigure the clocks on resuming from low-power + modes; this will include re-enabling CSS. However it is important that you verify + this for your own hardware. diff --git a/dts/bindings/clock/st,stm32-rcc.yaml b/dts/bindings/clock/st,stm32-rcc.yaml index 94aafc01a85..ebc6b7e84e3 100644 --- a/dts/bindings/clock/st,stm32-rcc.yaml +++ b/dts/bindings/clock/st,stm32-rcc.yaml @@ -51,10 +51,10 @@ description: | ... } In this example, I2C1 device is assigned HSI as domain clock source. - Domain clock is independent from the bus/gatted clock and allows access to the device's + Domain clock is independent from the bus/gated clock and allows access to the device's register while the gated clock is off. As it doesn't feed the peripheral's controller, it allows peripheral operation, but can't be used for peripheral configuration. - It is peripheral driver's responsibility to querry and use clock source information in + It is peripheral driver's responsibility to query and use clock source information in accordance with clock_control API specifications. Since the peripheral subsystem rate is dictated by the clock used for peripheral diff --git a/dts/bindings/clock/st,stm32f1-pll-clock.yaml b/dts/bindings/clock/st,stm32f1-pll-clock.yaml index 5b30f52d3e5..04c9a8e2954 100644 --- a/dts/bindings/clock/st,stm32f1-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f1-pll-clock.yaml @@ -35,11 +35,11 @@ properties: xtpre: type: boolean description: | - Otpional HSE divider for PLL entry + Optional HSE divider for PLL entry usbpre: type: boolean description: | - Otpional PLL output divisor to generate a 48MHz USB clock. + Optional PLL output divisor to generate a 48MHz USB clock. When set, PLL clock is not divided. Otherwise, PLL output clock is divided by 1.5. diff --git a/dts/bindings/clock/st,stm32f105-pll-clock.yaml b/dts/bindings/clock/st,stm32f105-pll-clock.yaml index a503e247172..d2f01e8989b 100644 --- a/dts/bindings/clock/st,stm32f105-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f105-pll-clock.yaml @@ -55,6 +55,6 @@ properties: otgfspre: type: boolean description: | - Otpional PLL output divisor to generate a 48MHz USB clock. + Optional PLL output divisor to generate a 48MHz USB clock. When set, PLL output clock is not divided. Otherwise, PLL output clock is divided by 1.5. diff --git a/dts/bindings/clock/st,stm32f3-rcc.yaml b/dts/bindings/clock/st,stm32f3-rcc.yaml index 5e9825129f7..ca0e57dc719 100644 --- a/dts/bindings/clock/st,stm32f3-rcc.yaml +++ b/dts/bindings/clock/st,stm32f3-rcc.yaml @@ -52,4 +52,4 @@ properties: ADC 3 and 4 prescaler - 0: Disables the clock so the ADC can use AHB clock (synchronous mode) - Other values n: The ADC can use the PLL clock divided by n - Check RefMan for availabilty. + Check RefMan for availability. diff --git a/dts/bindings/clock/st,stm32f4-pll-clock.yaml b/dts/bindings/clock/st,stm32f4-pll-clock.yaml index 137a15822ac..1346ec8a55f 100644 --- a/dts/bindings/clock/st,stm32f4-pll-clock.yaml +++ b/dts/bindings/clock/st,stm32f4-pll-clock.yaml @@ -61,3 +61,10 @@ properties: Main PLL (PLL) division factor for USB OTG FS, SDMMC and random number generator clocks. Valid range: 2 - 15 + + div-r: + type: int + description: | + Main PLL (PLL) division factor for I2S and DFSDM + generator clocks. + Valid range: 2 - 7 diff --git a/dts/bindings/clock/st,stm32wba-rcc.yaml b/dts/bindings/clock/st,stm32wba-rcc.yaml index d85ba13ad20..797c366da11 100644 --- a/dts/bindings/clock/st,stm32wba-rcc.yaml +++ b/dts/bindings/clock/st,stm32wba-rcc.yaml @@ -49,7 +49,7 @@ description: | ... } In this example I2C1 device is assigned HSI as clock source. - It is device driver's responsibility to querry and use clock source information in + It is device driver's responsibility to query and use clock source information in accordance with clock_control API specifications. compatible: "st,stm32wba-rcc" diff --git a/dts/bindings/clock/st,stm32wl-hse-clock.yaml b/dts/bindings/clock/st,stm32wl-hse-clock.yaml index c1bc2199b79..f765efc264e 100644 --- a/dts/bindings/clock/st,stm32wl-hse-clock.yaml +++ b/dts/bindings/clock/st,stm32wl-hse-clock.yaml @@ -12,7 +12,7 @@ properties: type: boolean description: | When set, TCXO is selected as external source clock for HSE. - Otherwise, external cyrstal is selected as HSE source clock. + Otherwise, external crystal is selected as HSE source clock. hse-div2: type: boolean diff --git a/dts/bindings/counter/nxp,lpc-rtc-highres.yaml b/dts/bindings/counter/nxp,lpc-rtc-highres.yaml new file mode 100644 index 00000000000..633ca5557a3 --- /dev/null +++ b/dts/bindings/counter/nxp,lpc-rtc-highres.yaml @@ -0,0 +1,8 @@ +# Copyright 2023, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Driver that uses the NXP LPC RTC High resolution counter + +compatible: "nxp,lpc-rtc-highres" + +include: base.yaml diff --git a/dts/bindings/cpu/andes,andescore-v5.yaml b/dts/bindings/cpu/andes,andescore-v5.yaml new file mode 100644 index 00000000000..d535b1dfd97 --- /dev/null +++ b/dts/bindings/cpu/andes,andescore-v5.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: Andes Technology RISC-V core from the AndesCore v5 series + +compatible: "andestech,andescore-v5" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml b/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml new file mode 100644 index 00000000000..ff0d6e2a420 --- /dev/null +++ b/dts/bindings/cpu/efinix,vexriscv-sapphire.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: VexRiscv core with the configuration as used in the Efinix Sapphire SoC + +compatible: "efinix,vexriscv-sapphire" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/litex,vexriscv-standard.yaml b/dts/bindings/cpu/litex,vexriscv-standard.yaml new file mode 100644 index 00000000000..86de7c7a9c0 --- /dev/null +++ b/dts/bindings/cpu/litex,vexriscv-standard.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: VexRiscv core with the standard configuration as used by LiteX + +compatible: "litex,vexriscv-standard" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/lowrisc,ibex.yaml b/dts/bindings/cpu/lowrisc,ibex.yaml new file mode 100644 index 00000000000..051284f703f --- /dev/null +++ b/dts/bindings/cpu/lowrisc,ibex.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: LowRISC Ibex RISC-V core + +compatible: "lowrisc,ibex" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/nordic,vpr.yaml b/dts/bindings/cpu/nordic,vpr.yaml new file mode 100644 index 00000000000..11146f89c51 --- /dev/null +++ b/dts/bindings/cpu/nordic,vpr.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic Semiconductor RISC-V VPR CPU + +compatible: "nordic,vpr" + +include: riscv,cpus.yaml + +properties: + nordic,bus-width: + type: int + enum: + - 32 + - 64 + required: true + description: + Bus width of the CPU. diff --git a/dts/bindings/cpu/nuclei,bumblebee.yaml b/dts/bindings/cpu/nuclei,bumblebee.yaml index 8c9dfc7d35d..96eebcd0fb8 100644 --- a/dts/bindings/cpu/nuclei,bumblebee.yaml +++ b/dts/bindings/cpu/nuclei,bumblebee.yaml @@ -6,9 +6,3 @@ description: Nuclei Bumblebee RISC-V Core compatible: "nuclei,bumblebee" include: riscv,cpus.yaml - -properties: - mcause-exception-mask: - type: int - required: true - description: Specify the bits to use for exception code in mcause register. diff --git a/dts/bindings/cpu/openisa,ri5cy.yaml b/dts/bindings/cpu/openisa,ri5cy.yaml new file mode 100644 index 00000000000..9bcb53c9e89 --- /dev/null +++ b/dts/bindings/cpu/openisa,ri5cy.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: OpenISA RI5CY core + +compatible: "openisa,ri5cy" + +include: riscv,cpus.yaml diff --git a/dts/bindings/cpu/openisa,zero-ri5cy.yaml b/dts/bindings/cpu/openisa,zero-ri5cy.yaml new file mode 100644 index 00000000000..33fe8450899 --- /dev/null +++ b/dts/bindings/cpu/openisa,zero-ri5cy.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: OpenISA Zero-RI5CY core + +compatible: "openisa,zero-ri5cy" + +include: riscv,cpus.yaml diff --git a/dts/bindings/riscv/riscv,cpus.yaml b/dts/bindings/cpu/riscv,cpus.yaml similarity index 100% rename from dts/bindings/riscv/riscv,cpus.yaml rename to dts/bindings/cpu/riscv,cpus.yaml diff --git a/dts/bindings/riscv/sifive,e24.yaml b/dts/bindings/cpu/sifive,e24.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e24.yaml rename to dts/bindings/cpu/sifive,e24.yaml diff --git a/dts/bindings/riscv/sifive,e31.yaml b/dts/bindings/cpu/sifive,e31.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e31.yaml rename to dts/bindings/cpu/sifive,e31.yaml diff --git a/dts/bindings/riscv/sifive,e51.yaml b/dts/bindings/cpu/sifive,e51.yaml similarity index 100% rename from dts/bindings/riscv/sifive,e51.yaml rename to dts/bindings/cpu/sifive,e51.yaml diff --git a/dts/bindings/riscv/sifive,s7.yaml b/dts/bindings/cpu/sifive,s7.yaml similarity index 100% rename from dts/bindings/riscv/sifive,s7.yaml rename to dts/bindings/cpu/sifive,s7.yaml diff --git a/dts/bindings/cpu/sifive,u54.yaml b/dts/bindings/cpu/sifive,u54.yaml new file mode 100644 index 00000000000..2a0bbbfd58c --- /dev/null +++ b/dts/bindings/cpu/sifive,u54.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 + +description: SiFive U54 Standard Core CPU + +compatible: "sifive,u54" + +include: sifive-common.yaml diff --git a/dts/bindings/riscv/sifive-common.yaml b/dts/bindings/cpu/sifive-common.yaml similarity index 100% rename from dts/bindings/riscv/sifive-common.yaml rename to dts/bindings/cpu/sifive-common.yaml diff --git a/dts/bindings/dac/atmel,sam-dac.yaml b/dts/bindings/dac/atmel,sam-dac.yaml index 6b650d2bec1..6775164363f 100644 --- a/dts/bindings/dac/atmel,sam-dac.yaml +++ b/dts/bindings/dac/atmel,sam-dac.yaml @@ -20,7 +20,7 @@ properties: type: int default: 15 description: | - Peripheral Clock to DAC Clock Ratio. Prescaler value is calcuated as + Peripheral Clock to DAC Clock Ratio. Prescaler value is calculated as PRESCAL = (MCK / DACClock) - 2. Should be in range from 0 to 15. The value will be written to DACC_MR.PRESCALER bit-field. The property is applicable only to SAME70, SAMV71 series devices. diff --git a/dts/bindings/dai/nxp,dai-sai.yaml b/dts/bindings/dai/nxp,dai-sai.yaml new file mode 100644 index 00000000000..ae9cd201880 --- /dev/null +++ b/dts/bindings/dai/nxp,dai-sai.yaml @@ -0,0 +1,86 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP Synchronous Audio Interface (SAI) node + +compatible: "nxp,dai-sai" + +include: base.yaml + +properties: + reg: + required: true + mclk-is-output: + type: boolean + description: | + Use this property to set the SAI MCLK as output or as input. + By default, if this property is not specified, MCLK will be + set as input. Setting the MCLK as output for SAIs which don't + support MCLK configuration will result in a BUILD_ASSERT() + failure. + rx-fifo-watermark: + type: int + description: | + Use this property to specify the watermark value for the TX + FIFO. This value needs to be in FIFO words (NOT BYTES). This + value needs to be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + tx-fifo-watermark: + type: int + description: | + Use this property to specify the watermark value for the RX + FIFO. This value needs to be in FIFO words (NOT BYTES). This + value needs to be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + interrupts: + required: true + fifo-depth: + type: int + description: | + Use this property to set the FIFO depth that will be reported + to other applications calling dai_get_properties(). This value + should be in the following interval: (0, DEFAULT_FIFO_DEPTH], + otherwise a BUILD_ASSERT() failure will be raised. + By DEFAULT_FIFO_DEPTH we mean the actual (hardware) value of + the FIFO depth. This is needed because some applications (e.g: SOF) + use this value to compute the DMA burst size, in which case + DEFAULT_FIFO_DEPTH cannot be used. Generally, reporting a false + FIFO depth should be avoided. Please note that the sanity check + for tx/rx-fifo-watermark uses DEFAULT_FIFO_DEPTH instead of this + value so use with caution. If unsure, it's better to simply not + use this property, in which case the reported value will be + DEFAULT_FIFO_DEPTH. + dai-index: + type: int + description: | + Use this property to specify the index of the DAI. At the + moment, this is only used by SOF to fetch the "struct device" + associated with the DAI whose index Linux passes to SOF + through an IPC. If this property is not specified, the DAI + index will be considered 0. + tx-sync-mode: + type: int + enum: + - 0 + - 1 + description: | + Use this property to specify which synchronization mode to use + for the transmitter. At the moment, the only supported modes are: + 1) The transmitter is ASYNC (0) + 2) The transmitter is in SYNC with the receiver (1) + If this property is not specified, the transmitter will be set to ASYNC. + If one side is SYNC then the other MUST be ASYNC. Failing to meet this + condition will result in a failed BUILD_ASSERT(). + rx-sync-mode: + type: int + enum: + - 0 + - 1 + description: | + Use this property to specify which synchronization mode to use + for the receiver. At the moment, the only supported modes are: + 1) The receiver is ASYNC (0) + 2) The receiver is in SYNC with the transmitter (1) + If this property is not specified, the receiver will be set to ASYNC. + If one side is SYNC then the other MUST be ASYNC. Failing to meet this + condition will result in a failed BUILD_ASSERT(). diff --git a/dts/bindings/display/galaxycore,gc9x01x.yaml b/dts/bindings/display/galaxycore,gc9x01x.yaml new file mode 100644 index 00000000000..37c4a5680a5 --- /dev/null +++ b/dts/bindings/display/galaxycore,gc9x01x.yaml @@ -0,0 +1,147 @@ +# Copyright (c) 2023 Mr Beam Lasers GmbH. +# Copyright (c) 2023 Amrith Venkat Kesavamoorthi +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + GC9X01X display driver. + + This driver implements support for various GC9X01X graphics + controllers and different display sizes. It has been validated + for following controllers: + - GC9101A: (Waveshare 240x240, 1.28inch round lcd display 240x240) + + Here is an example to define a display interface: + + &spi2 { + gc9a01a_lcd: gc9a01a_lcd@0 { + compatible = "galaxycore,gc9x01x"; + reg = <0>; + spi-max-frequency = <100000000>; + cmd-data-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + pixel-format = ; + width = <240>; + height = <240>; + }; + }; + + +compatible: "galaxycore,gc9x01x" + +include: [spi-device.yaml, display-controller.yaml, lcd-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + required: true + description: | + RESET pin of the GC9X01X. + If connected directly the MCU pin should be configured + as active low. + + cmd-data-gpios: + type: phandle-array + required: true + description: | + Data/Command pin of the GC9X01X is to be configured + high(1) for data, low(0) for command. + + orientation: + type: string + default: "normal" + enum: + - "normal" + - "90" + - "180" + - "270" + description: Display orientation (CW) in degrees. + + display-inversion: + type: boolean + description: | + Display inversion mode. Every bit is inverted from the frame memory to + the display. + + pwrctrl1: + type: uint8-array + default: [ + 0x00 + ] + description: Power-control 1 register value + + pwrctrl2: + type: uint8-array + default: [ + 0x13 + ] + description: Power-control 2 register value + + pwrctrl3: + type: uint8-array + default: [ + 0x13 + ] + description: Power-control 3 register value + + pwrctrl4: + type: uint8-array + default: [ + 0x22 + ] + description: Power-control 4 register value + + gamma1: + type: uint8-array + default: [ + 0x45, + 0x09, + 0x08, + 0x08, + 0x26, + 0x2A + ] + description: Gamma correction 1 register values (negative polarity) + + gamma2: + type: uint8-array + default: [ + 0x43, + 0x70, + 0x72, + 0x36, + 0x37, + 0x6F + ] + description: Gamma correction 3 register values + + gamma3: + type: uint8-array + default: [ + 0x45, + 0x09, + 0x08, + 0x08, + 0x26, + 0x2A + ] + description: Gamma correction 3 register values (positive polarity) + + gamma4: + type: uint8-array + default: [ + 0x43, + 0x70, + 0x72, + 0x36, + 0x37, + 0x6F + ] + description: Gamma correction 4 register values + + framerate: + type: uint8-array + default: [ + 0x34 + ] + description: Framerate register value diff --git a/dts/bindings/display/ilitek,ili9342c.yaml b/dts/bindings/display/ilitek,ili9342c.yaml index 37cf5999cd9..a2afb6d3983 100644 --- a/dts/bindings/display/ilitek,ili9342c.yaml +++ b/dts/bindings/display/ilitek,ili9342c.yaml @@ -16,7 +16,7 @@ properties: default: [0x01] description: select the desired Gamma curve for the current display. - A maximum of 4 fixed gamma curves canbe selected. + A maximum of 4 fixed gamma curves can be selected. ifmode: type: uint8-array diff --git a/dts/bindings/display/ilitek,ili9xxx-common.yaml b/dts/bindings/display/ilitek,ili9xxx-common.yaml index fe1fd852f87..802250002d6 100644 --- a/dts/bindings/display/ilitek,ili9xxx-common.yaml +++ b/dts/bindings/display/ilitek,ili9xxx-common.yaml @@ -4,26 +4,9 @@ description: ILI9XXX display controllers common properties. -include: [spi-device.yaml, display-controller.yaml] +include: [mipi-dbi-spi-device.yaml, display-controller.yaml] properties: - reset-gpios: - type: phandle-array - description: RESET pin. - - The RESET pin of ILI9340 is active low. - If connected directly the MCU pin should be configured - as active low. - - cmd-data-gpios: - type: phandle-array - required: true - description: D/CX pin. - - The D/CX pin of ILI9340 is active low (transmission command byte). - If connected directly the MCU pin should be configured - as active low. - pixel-format: type: int default: 0 diff --git a/dts/bindings/display/nxp,imx-elcdif.yaml b/dts/bindings/display/nxp,imx-elcdif.yaml index 5f9807bfdcf..a5ef4f13ded 100644 --- a/dts/bindings/display/nxp,imx-elcdif.yaml +++ b/dts/bindings/display/nxp,imx-elcdif.yaml @@ -34,5 +34,5 @@ properties: nxp,pxp: type: phandle description: - NXP PXP device phandle. The LCDIF can utilize the PXP for acclerated + NXP PXP device phandle. The LCDIF can utilize the PXP for accelerated display rotation via the DMA API, when present and enabled. diff --git a/dts/bindings/display/st,stm32-ltdc.yaml b/dts/bindings/display/st,stm32-ltdc.yaml index 73ae19f7fcb..5513c811ac5 100644 --- a/dts/bindings/display/st,stm32-ltdc.yaml +++ b/dts/bindings/display/st,stm32-ltdc.yaml @@ -1,4 +1,5 @@ # Copyright (c) 2022, Byte-Lab d.o.o. +# Copyright (c) 2024 STMicroelectronics # SPDX-License-Identifier: Apache-2.0 description: STM32 LCD-TFT display controller @@ -64,3 +65,9 @@ properties: window0-y1: type: int description: Last pixel in y direction on layer 0. Defaults to height. + + display-controller: + type: phandle + description: | + Phandle of the display's controller. When provided, it's used to forward some of the + configuration calls (e.g. blanking on/off) sent to LTDC device. diff --git a/dts/bindings/display/ultrachip,uc8175.yaml b/dts/bindings/display/ultrachip,uc8175.yaml new file mode 100644 index 00000000000..8c89c86aded --- /dev/null +++ b/dts/bindings/display/ultrachip,uc8175.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Andreas Sandberg +# SPDX-License-Identifier: Apache-2.0 + +description: UltraChip UC8175 EPD controller + +compatible: "ultrachip,uc8175" + +include: ultrachip,uc81xx-common.yaml diff --git a/dts/bindings/dma/andestech,atcdmac300.yaml b/dts/bindings/dma/andestech,atcdmac300.yaml index 931cc1ffaeb..4c0020dd69d 100644 --- a/dts/bindings/dma/andestech,atcdmac300.yaml +++ b/dts/bindings/dma/andestech,atcdmac300.yaml @@ -29,7 +29,7 @@ description: | Andes DMA controller channel: a phandle to the DMA controller plus the following four integer cells: 1. channel: the dma channel - 2. slot: DMA peripherial request ID + 2. slot: DMA peripheral request ID 3. channel-config: A 32bit mask specifying the DMA channel configuration which is device dependent: -bit 0-1 : Direction (see dma.h) diff --git a/dts/bindings/dma/intel,lpss.yaml b/dts/bindings/dma/intel,lpss.yaml index 5f1954216f0..d9fc4a60f11 100644 --- a/dts/bindings/dma/intel,lpss.yaml +++ b/dts/bindings/dma/intel,lpss.yaml @@ -11,10 +11,5 @@ properties: "#dma-cells": const: 1 - dma-parent: - type: phandle - description: | - Parent device for LPSS DMA to get its base address. - dma-cells: - channel diff --git a/dts/bindings/dma/nxp,edma.yaml b/dts/bindings/dma/nxp,edma.yaml new file mode 100644 index 00000000000..5c3305cb7dd --- /dev/null +++ b/dts/bindings/dma/nxp,edma.yaml @@ -0,0 +1,41 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP enhanced Direct Memory Access (eDMA) node + +compatible: "nxp,edma" + +include: [dma-controller.yaml, base.yaml] + +properties: + reg: + required: true + valid-channels: + type: array + description: | + Use this property to specify which channel indexes are + to be considered valid. The difference between this + property and "dma-channels" is the fact that this + property allows you to have "gaps" between the channel + indexes. This is useful in cases where you know you're + not going to be using all of the possible channels, thus + leading to a more readable DTS. Of course, this property + and "dma-channels" are mutually exclusive, meaning you + can't specify both properties as this will lead to a + BUILD_ASSERT() failure. + hal-cfg-index: + type: int + description: | + Use this property to specify which HAL configuration + should be used. In the case of some SoCs (e.g: i.MX93), + there can be multiple eDMA variants, each of them having + different configurations (e.g: i.MX93 eDMA3 has 31 channels, + i.MX93 eDMA4 has 64 channels and both of them have slightly + different register layouts). To overcome this issue, the HAL + exposes an array of configurations called "edma_hal_configs". + To perform various operations, the HAL uses an eDMA configuration + which will tell it what register layout the IP has, the number of + channels, various flags and offsets. As such, if there's multiple + configurations available, the user will have to specify which + configuration to use through this property. If missing, the + configuration found at index 0 will be used. diff --git a/dts/bindings/dma/st,stm32-dma-v1.yaml b/dts/bindings/dma/st,stm32-dma-v1.yaml index 8e33887dace..c4658e6b30e 100644 --- a/dts/bindings/dma/st,stm32-dma-v1.yaml +++ b/dts/bindings/dma/st,stm32-dma-v1.yaml @@ -13,7 +13,7 @@ description: | 2. slot: DMA periph request ID, which is written in the DMAREQ_ID of the DMAMUX_CxCR this value is 0 for Memory-to-memory transfers or a value between <1> .. (not supported yet) - or a value beweeen +1 .. + + or a value between +1 .. + 3. channel-config: A 32bit mask specifying the DMA channel configuration which is device dependent: -bit 6-7 : Direction (see dma.h) diff --git a/dts/bindings/dma/st,stm32-dma-v2.yaml b/dts/bindings/dma/st,stm32-dma-v2.yaml index 38e968c1a3b..632ff53a90b 100644 --- a/dts/bindings/dma/st,stm32-dma-v2.yaml +++ b/dts/bindings/dma/st,stm32-dma-v2.yaml @@ -16,10 +16,10 @@ description: | 2. slot: DMA periph request ID, which is written in the DMAREQ_ID of the DMAMUX_CxCR this value is 0 for Memory-to-memory transfers or a value between <1> .. (not supported yet) - or a value beweeen +1 .. + + or a value between +1 .. + 3. channel-config: A 32bit mask specifying the DMA channel configuration A name custom DMA flags for channel configuration is used - which is device dependent see stm32_dma.h: + which is device dependent. See stm32_dma.h: -bit 5 : DMA cyclic mode config 0x0: STM32_DMA_MODE_NORMAL 0x1: STM32_DMA_MODE_CYCLIC diff --git a/dts/bindings/dma/st,stm32-dmamux.yaml b/dts/bindings/dma/st,stm32-dmamux.yaml index 5ce00b95290..84d5e8668e4 100644 --- a/dts/bindings/dma/st,stm32-dmamux.yaml +++ b/dts/bindings/dma/st,stm32-dmamux.yaml @@ -41,7 +41,7 @@ description: | 0x1: medium 0x2: high 0x3: very high - exemple for stm32wb55x + example for stm32wb55x dmamux1: dmamux@40020800 { compatible = "st,stm32-dmamux"; ... diff --git a/dts/bindings/dma/zephyr,dma-emul.yaml b/dts/bindings/dma/zephyr,dma-emul.yaml new file mode 100644 index 00000000000..b055062cb72 --- /dev/null +++ b/dts/bindings/dma/zephyr,dma-emul.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Emulated DMA Controller + +include: dma-controller.yaml + +compatible: zephyr,dma-emul + +properties: + stack-size: + type: int + required: true + description: > + Stack size (in bytes) for the instance-specific work_q thread. + + priority: + type: int + description: > + Priority for the instance-specific work_q thread. diff --git a/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml new file mode 100644 index 00000000000..115f8e5e4a4 --- /dev/null +++ b/dts/bindings/espi/nuvoton,npcx-espi-taf.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: | + The target flash devices accessed by Nuvoton eSPI TAF controller. + + Representation: + + espi_taf: espitaf@4000a000 { + compatible = "nuvoton,npcx-espi-taf"; + reg = <0x4000a000 0x2000>; + + mapped-addr = <0x68000000>; + max-read-sz = "NPCX_ESPI_TAF_MAX_READ_REQ_64B"; + erase-sz = "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB"; + + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + }; + +compatible: "nuvoton,npcx-espi-taf" + +include: [espi-controller.yaml, pinctrl-device.yaml] + +properties: + mapped-addr: + type: int + description: | + Mapped memory address of direct read access for flash. + required: true + + erase-sz: + type: string + required: true + description: | + Erase block size of target flash. The default was 4KB Erase Block Size. + All Intel platforms require support for at least 4 KB Erase Block Size. + default: "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB" + enum: + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB" + - "NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB" + + max-read-sz: + type: string + required: true + description: | + Maximum read request size of flash access channel. The default was 64 bytes. + This value is recommended in datasheet. + default: "NPCX_ESPI_TAF_MAX_READ_REQ_64B" + enum: + - "NPCX_ESPI_TAF_MAX_READ_REQ_64B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_128B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_256B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_512B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_1024B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_2048B" + - "NPCX_ESPI_TAF_MAX_READ_REQ_4096B" diff --git a/dts/bindings/espi/nuvoton,npcx-espi.yaml b/dts/bindings/espi/nuvoton,npcx-espi.yaml index ebce305a3af..e53c3acb94b 100644 --- a/dts/bindings/espi/nuvoton,npcx-espi.yaml +++ b/dts/bindings/espi/nuvoton,npcx-espi.yaml @@ -30,3 +30,13 @@ properties: For example the WUI mapping on NPCX7 would be espi-rst-wui = <&wui_cr_sin1>; + + rx-plsize: + type: int + required: true + description: The maximum receive channel payload size. + + tx-plsize: + type: int + required: true + description: The maximum transmit channel payload size. diff --git a/dts/bindings/ethernet/atmel,gmac-common.yaml b/dts/bindings/ethernet/atmel,gmac-common.yaml index f17d78df696..0975647e187 100644 --- a/dts/bindings/ethernet/atmel,gmac-common.yaml +++ b/dts/bindings/ethernet/atmel,gmac-common.yaml @@ -43,19 +43,9 @@ properties: gmac driver supports 10Mbit/s and 100Mbit/s. Using 100, as default value, enables driver to configure 10 and 100Mbit/s speeds. - phy-connection-type: - type: string - enum: - - "rmii" - - "mii" - default: "rmii" - description: | - Phy connection type define the physical interface connection between - PHY and MAC. The default value uses gmac register reset value, which - represents Reduced Media-Independent Interface (RMII) mode. - - This property must be used with pinctrl-0. - mac-eeprom: type: phandle description: phandle to I2C eeprom device node. + + phy-connection-type: + default: "rmii" diff --git a/dts/bindings/ethernet/espressif,esp32-eth.yaml b/dts/bindings/ethernet/espressif,esp32-eth.yaml index 3ffd12cdc50..df063fd57a8 100644 --- a/dts/bindings/ethernet/espressif,esp32-eth.yaml +++ b/dts/bindings/ethernet/espressif,esp32-eth.yaml @@ -9,15 +9,10 @@ include: - name: ethernet-controller.yaml properties: - phy-connection-type: - type: string - enum: - - "rmii" - - "mii" - default: "rmii" - description: | - Phy connection type define the physical interface connection between - PHY and MAC. The default value uses Reduced Media-Independent - Interface (RMII) mode. phy-handle: required: true + + ref-clk-output-gpios: + type: phandle-array + description: | + GPIO to output RMII Clock. diff --git a/dts/bindings/ethernet/ethernet-controller.yaml b/dts/bindings/ethernet/ethernet-controller.yaml index a5a9cec2700..8823459d3a9 100644 --- a/dts/bindings/ethernet/ethernet-controller.yaml +++ b/dts/bindings/ethernet/ethernet-controller.yaml @@ -27,3 +27,12 @@ properties: type: phandle description: | Specifies a reference to a node representing a PHY device. + + phy-connection-type: + type: string + description: | + Specifies the interface connection type between ethernet MAC and PHY. + enum: + - "mii" + - "rmii" + - "gmii" diff --git a/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml new file mode 100644 index 00000000000..c526fe89055 --- /dev/null +++ b/dts/bindings/ethernet/infineon,xmc4xxx-ethernet.yaml @@ -0,0 +1,118 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: XMC 4XXX Ethernet + +compatible: "infineon,xmc4xxx-ethernet" + +include: + - name: ethernet-controller.yaml + - name: pinctrl-device.yaml + +properties: + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + phy-connection-type: + required: true + + rxd0-port-ctrl: + required: true + type: string + description: Receive bit 0 (rxd0) signal GPIO connection. Used for RMII and MII interfaces. + enum: + - "P2_2" + - "P0_2" + - "P14_8" + - "P5_0" + + rxd1-port-ctrl: + required: true + type: string + description: Receive bit 1 (rxd1) signal GPIO connection. Used for RMII and MII interfaces. + enum: + - "P2_3" + - "P0_3" + - "P14_9" + - "P5_1" + + rxd2-port-ctrl: + type: string + description: Receive bit 2 (rxd2) signal GPIO connection. Only used for MII interface. + enum: + - "P5_8" + - "P6_4" + + rxd3-port-ctrl: + type: string + description: Receive bit 2 (rxd2) signal GPIO connection. Only used for MII interface. + enum: + - "P5_9" + - "P6_3" + + rmii-rx-clk-port-ctrl: + required: true + description: | + If the RMII interface is used it connects GPIO to the rmii-clk signal. + Otherwise, if the MII interface is used, then it connects to the Receive clock (rx-clk) + signal. + type: string + enum: + - "P2_1" + - "P0_0" + - "P15_8" + - "P6_5" + + crs-rx-dv-port-ctrl: + required: true + description: | + If the RMII interface is used it connects GPIO to the Carrier Sense Data Valid (crs-dv) + signal. Otherwise, if the MII interface is used, it connects to the + Receive Data Valid (rx-dv) signal. + type: string + enum: + - "P2_5" + - "P0_1" + - "P15_9" + - "P5_2" + + crs-port-ctrl: + description: Carrier Sense (crs) signal GPIO connection. Only used for the MII interface. + type: string + enum: + - "P5_11" + - "unused1" + - "unused2" + - "P5_4" + + rxer-port-ctrl: + required: true + description: Receive Error (rxer) signal GPIO connection. Used for MII and RMII interfaces. + type: string + enum: + - "P2_4" + - "P0_11" + - "unused1" + - "P5_3" + + col-port-ctrl: + description: Collision (col) signal GPIO connection. Only used for MII interface. + type: string + enum: + - "P2_15" + - "unused1" + - "unused2" + - "P5_5" + + tx-clk-port-ctrl: + description: Transmit clock (tx-clk) GPIO connection. Only used for MII interface. + type: string + enum: + - "P5_10" + - "P6_6" diff --git a/dts/bindings/ethernet/microchip,ksz8081.yaml b/dts/bindings/ethernet/microchip,ksz8081.yaml new file mode 100644 index 00000000000..83a6be9f72d --- /dev/null +++ b/dts/bindings/ethernet/microchip,ksz8081.yaml @@ -0,0 +1,26 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip KSZ8081 Ethernet PHY device + +compatible: "microchip,ksz8081" + +include: ethernet-phy.yaml + +properties: + mc,reset-gpio: + type: phandle-array + specifier-space: gpio + description: GPIO connected to PHY reset signal pin. Reset is active low. + mc,interrupt-gpio: + type: phandle-array + specifier-space: gpio + description: GPIO for interrupt signal indicating PHY state change. + mc,interface-type: + type: string + required: true + description: Which type of phy connection the phy is set up for + enum: + - "mii" + - "rmii" + - "rmii-25MHz" diff --git a/dts/bindings/ethernet/nxp,enet-mac.yaml b/dts/bindings/ethernet/nxp,enet-mac.yaml new file mode 100644 index 00000000000..8ca42e769f3 --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet-mac.yaml @@ -0,0 +1,24 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET MAC/L2 Device + +compatible: "nxp,enet-mac" + +include: ["ethernet-controller.yaml", "ethernet,fixed-link.yaml", "pinctrl-device.yaml"] + +properties: + interrupts: + required: true + + nxp,mdio: + type: phandle + required: true + description: | + Corresponding mdio device + + nxp,ptp-clock: + type: phandle + required: true + description: | + Corresponding ptp clock device diff --git a/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml b/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml new file mode 100644 index 00000000000..f77e30b3035 --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet-ptp-clock.yaml @@ -0,0 +1,12 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET PTP (Precision Time Protocol) Clock + +compatible: "nxp,enet-ptp-clock" + +include: ["base.yaml", "pinctrl-device.yaml"] + +properties: + interrupts: + required: true diff --git a/dts/bindings/ethernet/nxp,enet.yaml b/dts/bindings/ethernet/nxp,enet.yaml new file mode 100644 index 00000000000..f98af9f002b --- /dev/null +++ b/dts/bindings/ethernet/nxp,enet.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET IP Module + +compatible: "nxp,enet" + +include: ["base.yaml"] + +properties: + reg: + required: true + + clocks: + required: true diff --git a/dts/bindings/ethernet/nxp,s32-gmac.yaml b/dts/bindings/ethernet/nxp,s32-gmac.yaml index 357a5eb1521..7767a755f39 100644 --- a/dts/bindings/ethernet/nxp,s32-gmac.yaml +++ b/dts/bindings/ethernet/nxp,s32-gmac.yaml @@ -16,13 +16,3 @@ properties: interrupt-names: required: true - - phy-connection-type: - type: string - enum: - - "mii" - - "rmii" - - "rgmii" - description: | - Specifies interface type between the Ethernet device and a physical - layer (PHY) device. diff --git a/dts/bindings/ethernet/nxp,tja1103.yaml b/dts/bindings/ethernet/nxp,tja1103.yaml new file mode 100644 index 00000000000..514dec3d376 --- /dev/null +++ b/dts/bindings/ethernet/nxp,tja1103.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: TJA1103 PHY + +compatible: "nxp,tja1103" + +include: phy.yaml + +properties: + reg: + required: true + description: PHY address + + int-gpios: + type: phandle-array + description: + interrupt GPIO for PHY. Will be pulled high in its default state. + + master-slave: + type: string + required: true + description: | + 100BASE-T1 Specifies that either phy has to run in master / slave mode + Default selects the mode set by the pinstrapping on the hardware design. + enum: + - "default" + - "master" + - "slave" diff --git a/dts/bindings/ethernet/xlnx,gem.yaml b/dts/bindings/ethernet/xlnx,gem.yaml index a4c16094b08..90cff14f260 100644 --- a/dts/bindings/ethernet/xlnx,gem.yaml +++ b/dts/bindings/ethernet/xlnx,gem.yaml @@ -303,7 +303,7 @@ properties: multicast-hash: type: boolean description: | - Optional feature flag - Enable multicast hash. When set, mutlicast + Optional feature flag - Enable multicast hash. When set, multicast frames will be accepted when the 6 bit hash function of the desti- nation address points to a bit that is set in the hash register. diff --git a/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml b/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml index 64a84a03758..80257970fad 100644 --- a/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml +++ b/dts/bindings/flash_controller/atmel,sam-flash-controller.yaml @@ -10,3 +10,11 @@ include: flash-controller.yaml properties: clocks: required: true + + "#erase-block-cells": + type: int + const: 2 + +erase-block-cells: + - pages-count + - pages-size diff --git a/dts/bindings/flash_controller/cdns,nand.yaml b/dts/bindings/flash_controller/cdns,nand.yaml new file mode 100644 index 00000000000..c588c1837fe --- /dev/null +++ b/dts/bindings/flash_controller/cdns,nand.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Cadence Nand flash controller + +compatible: "cdns,nand" + +include: [flash-controller.yaml, reset-device.yaml] + +properties: + data-rate-mode: + type: int + required: true + description: Data Rate mode Selection. 0 - SDR , 1 - NVDDR. + enum: + - 0 + - 1 + + block-size: + type: int + required: true + description: Erase Block size of Cadence Nand diff --git a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml index f8f84020f6a..cdcb0b9d800 100644 --- a/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-ospi-nor.yaml @@ -6,13 +6,12 @@ description: | Representation of a serial flash on a octospi bus: - mx25lm51245: ospi-nor-flash@0 { + mx25lm51245: ospi-nor-flash@70000000 { compatible = "st,stm32-ospi-nor"; - reg = <0>; + reg = <0x70000000 DT_SIZE_M(64)>; /* 512 Mbits */ data-mode = ; /* access on 8 data lines */ data-rate = ; /* access in DTR */ ospi-max-frequency = ; - size = ; /* 512 Mbit */ status = "okay"; }; @@ -25,13 +24,11 @@ on-bus: ospi properties: reg: required: true + description: Flash Memory base address and size in bytes ospi-max-frequency: type: int required: true description: Maximum clock frequency of device's OSPI interface in Hz - size: - required: true - description: Flash Memory size in bits reset-gpios: type: phandle-array description: RESETn pin diff --git a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml index 6d7bf5105e6..3f990f4a125 100644 --- a/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml +++ b/dts/bindings/flash_controller/st,stm32-qspi-nor.yaml @@ -6,11 +6,10 @@ description: | Representation of a serial flash on a quadspi bus: - mx25r6435f: qspi-nor-flash@0 { + mx25r6435f: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(8)>; /* 64 Mbits */ qspi-max-frequency = <80000000>; - size = <0x4000000>; reset-gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; reset-gpios-duration = <1>; spi-bus-width = <4>; @@ -26,13 +25,11 @@ on-bus: qspi properties: reg: required: true + description: Flash Memory base address and size in bytes qspi-max-frequency: type: int required: true description: Maximum clock frequency of device's QSPI interface in Hz - size: - required: true - description: Flash Memory size in bits reset-gpios: type: phandle-array description: RESETn pin diff --git a/dts/bindings/gnss/gnss-nmea-generic.yaml b/dts/bindings/gnss/gnss-nmea-generic.yaml new file mode 100644 index 00000000000..a3887995e10 --- /dev/null +++ b/dts/bindings/gnss/gnss-nmea-generic.yaml @@ -0,0 +1,22 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Generic GNSS NMEA receiver + + Implement a generic NMEA based GNSS device. + + Example configuration: + + &uart0 { + current-speed = <9600>; + ... + gnss: gnss-nmea-generic { + compatible = "gnss-nmea-generic"; + }; + }; + +compatible: "gnss-nmea-generic" + +include: + - uart-device.yaml diff --git a/dts/bindings/gnss/quectel-lc76g.yaml b/dts/bindings/gnss/quectel,lc76g.yaml similarity index 100% rename from dts/bindings/gnss/quectel-lc76g.yaml rename to dts/bindings/gnss/quectel,lc76g.yaml diff --git a/dts/bindings/gpio/ambiq,gpio-bank.yaml b/dts/bindings/gpio/ambiq,gpio-bank.yaml new file mode 100644 index 00000000000..8d9114acc5b --- /dev/null +++ b/dts/bindings/gpio/ambiq,gpio-bank.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Antmicro +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq GPIO bank node + +compatible: "ambiq,gpio-bank" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + description: | + This property indicates the register address offset of each GPIO child node + under the "ambiq,gpio" parent node. The register address of pin described in + gpio-cells can be obtained by: base address + child address offset + (pin << 2). + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/ambiq,gpio.yaml b/dts/bindings/gpio/ambiq,gpio.yaml new file mode 100644 index 00000000000..9ce7c7c8779 --- /dev/null +++ b/dts/bindings/gpio/ambiq,gpio.yaml @@ -0,0 +1,84 @@ +# Copyright (c) 2023 Ambiq Micro Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Ambiq GPIO provides the GPIO pin mapping for GPIO child nodes. + + The Ambiq Apollo4x soc designs a single GPIO port with 128 pins. + It uses 128 continuous 32-bit registers to configure the GPIO pins. + This binding provides a pin mapping to solve the limitation of the maximum + 32 pins handling in GPIO driver API. + + The Ambiq Apollo4x soc should define one "ambiq,gpio" parent node in soc + devicetree and some child nodes which are compatible with "ambiq,gpio-bank" + under this parent node. + + Here is an example of how a "ambiq,gpio" node can be used with the combined + gpio child nodes: + + gpio: gpio@40010000 { + compatible = "ambiq,gpio"; + gpio-map-mask = <0xffffffe0 0xffffffc0>; + gpio-map-pass-thru = <0x1f 0x3f>; + gpio-map = < + 0x00 0x0 &gpio0_31 0x0 0x0 + 0x20 0x0 &gpio32_63 0x0 0x0 + 0x40 0x0 &gpio64_95 0x0 0x0 + 0x60 0x0 &gpio96_127 0x0 0x0 + >; + reg = <0x40010000>; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + ranges; + + gpio0_31: gpio0_31@0 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + interrupts = <56 0>; + status = "disabled"; + }; + + gpio32_63: gpio32_63@80 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x80>; + interrupts = <57 0>; + status = "disabled"; + }; + + gpio64_95: gpio64_95@100 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x100>; + interrupts = <58 0>; + status = "disabled"; + }; + + gpio96_127: gpio96_127@180 { + compatible = "ambiq,gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x180>; + interrupts = <59 0>; + status = "disabled"; + }; + }; + + In the above example, the gpio@40010000 is a "ambiq,gpio" parent node which + provides the base register address 0x40010000. It has four "ambiq,gpio-bank" + child nodes. Each of them covers 32 pins (the default value of "ngpios" + property is 32). The "reg" property of child nodes defines the register + address offset. The register address of pin described in gpio-cells can be + obtained by: base address + child address offset + (pin << 2). For example: + the address of pin 20 of gpio32_63@80 node is (0x40010000 + 0x80 + (20 << 2)) + = 0x400100D0 and the real GPIO pin number of this pin in soc is (20 + 32) + = 52. + +compatible: "ambiq,gpio" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/dts/bindings/gpio/ambiq-header.yaml b/dts/bindings/gpio/ambiq-header.yaml new file mode 100644 index 00000000000..b082bc0ae58 --- /dev/null +++ b/dts/bindings/gpio/ambiq-header.yaml @@ -0,0 +1,59 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on Ambiq Apollo4p EVB headers + + The Ambiq Apollo4p EVB layout provides 5x16 and 1x20 pin headers. + + The binding provides a nexus mapping for these pins as depicted below. + + J7 J12 + + VDD_MCU - VDD_MCU - GPIO22 22 GND - + VDD_EXT - VDD_EXT - GPIO23 23 GPIO24 24 + nRST - GND - VDD_MCU - GND - + VDD_EXT - VDD_EXT - GND - GPIO64 64 + VDD_5V - VDD_5V - GPIO61 61 GPIO65 65 + GND - GND - GPIO63 63 GPIO66 66 + GND - GPIO100 100 GPIO62 62 GPIO67 67 + VDDH2 - GPIO97 97 GPIO47 47 GPIO68 68 + GPIO49 49 GPIO69 69 + J9 GPIO48 48 GPIO70 70 + + GPIO19 19 GPIO96 96 J11 + GPIO18 18 GPIO95 95 + GPIO17 17 GPIO98 98 GPIO53 53 GPIO71 71 + GPIO16 16 GPIO99 99 GPIO52 52 GPIO72 72 + GPIO15 15 GPIO102 102 GPIO91 91 GPIO73 73 + GPIO14 14 GPIO34 34 GPIO90 90 GPIO93 93 + GPIO13 13 GPIO35 35 GPIO11 11 GPIO92 92 + GPIO12 12 GPIO36 36 GPIO10 10 GPIO33 33 + GPIO8 8 GPIO32 32 + GPIO9 9 GPIO31 31 + + J10 + + GPIO28 28 GPIO60 60 + GPIO30 30 GPIO59 59 + GPIO94 94 GPIO58 58 + GPIO55 55 GPIO7 7 + GPIO0 0 GPIO54 54 + GPIO51 51 GPIO1 1 + GPIO2 2 GPIO50 50 + GPIO3 3 GPIO4 4 + + Voltage Header + + VDD_EXT - VDD_5V - + GND - GND - + BIAS - BIAS - + GND - AUDA - + GND - GND - + D1P - DON - + D1N - DOP - + GND - GND - + +compatible: "ambiq-header" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/dts/bindings/gpio/infineon,tle9104.yaml b/dts/bindings/gpio/infineon,tle9104.yaml index 5893f1a355a..cb82ecbde92 100644 --- a/dts/bindings/gpio/infineon,tle9104.yaml +++ b/dts/bindings/gpio/infineon,tle9104.yaml @@ -26,7 +26,6 @@ properties: resn-gpios: type: phandle-array - required: true description: "GPIO for reset" in1-gpios: diff --git a/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml b/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml index 7c77e610a23..744365cc5a3 100644 --- a/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml +++ b/dts/bindings/gpio/ite,it8xxx2-gpio-v2.yaml @@ -27,6 +27,20 @@ properties: wuc-mask: type: array + keyboard-controller: + type: boolean + description: | + When set, this GPIO controller has pins associated with the + keyboard controller. In this case the reg_gpcr property is + overloaded and used to write the keyboard GCTRL register. + This setting will be found in the gpio_ite_configure function + when the judgment of gpio_config->ksb_ctrl is true. + The GPIO control register that will be set for these three + nodes is as follows: + gpioksi: 0xf01d40-0xf01d47 + gpioksol: 0xf01d48-0xf01d4f + gpioksoh: 0xf01d50-0xf01d57 + gpio-cells: - pin - flags diff --git a/dts/bindings/gpio/m5stack,atom-header.yaml b/dts/bindings/gpio/m5stack,atom-header.yaml new file mode 100644 index 00000000000..ddb0c38f82c --- /dev/null +++ b/dts/bindings/gpio/m5stack,atom-header.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + Pin-header exposed on M5Stack Atom devices. + + This binding provides a nexus mapping for 9 pins as depicted below. + + x 3.3V + 0 GPIO 1 SCL + 2 GPIO/MOSI 3 GPIO/DAC0/SDA + 4 GPIO/CLK 5 5V + 6 GPIO/ADC0/MISO 7 GND + +compatible: "m5stack,atom-header" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/dts/bindings/gpio/m5stack,stamps3-header.yaml b/dts/bindings/gpio/m5stack,stamps3-header.yaml new file mode 100644 index 00000000000..a04fb9997ba --- /dev/null +++ b/dts/bindings/gpio/m5stack,stamps3-header.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2023 Martin Kiepfer +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on M5Stack StampS3 module headers. + + This binding provides a nexus mapping for 28 pins as depicted below. + + 0 GPIO + 1 GPIO + 2 GPIO/CLKOUT0 + 3 GPIO + 4 GPIO/SPILCD + 5 GPIO/SPILCD + 6 GPIO/SPILCD 27 3V3 + 7 GPIO 26 GPIO + 8 GPIO/CLKOUT0 25 GPIO/CLKOUT/TXD + 9 GPIO 24 GPIO + 10 GND 23 GPIO/CLKOUT/RXD + 11 GPIO/SDA1 22 GPIO/CLKOUT + 12 5V 21 EN + 13 GPIO/SCL1 20 GPIO/CLKOUT + 14 GPIO/SDA0 19 GPIO + 15 GPIO 18 GPIO/CLKOUT + 16 GPIO/SCL0 17 GND + + Note: Please note that the StampS3 is not pin compatible to the + other Stamp variantes like StampC3 or Stamp-Pico. + + +compatible: "m5stack,stamps3-header" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/dts/bindings/gpio/nordic,nrf-gpio.yaml b/dts/bindings/gpio/nordic,nrf-gpio.yaml index 550acd1a865..097a99d8fa9 100644 --- a/dts/bindings/gpio/nordic,nrf-gpio.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpio.yaml @@ -11,6 +11,11 @@ properties: reg: required: true + gpiote-instance: + type: phandle + description: | + GPIOTE instance that can be used with this GPIO port. + "#gpio-cells": const: 2 diff --git a/dts/bindings/gpio/nordic,nrf-gpiote.yaml b/dts/bindings/gpio/nordic,nrf-gpiote.yaml index 49ddba3595b..4bb09574e9b 100644 --- a/dts/bindings/gpio/nordic,nrf-gpiote.yaml +++ b/dts/bindings/gpio/nordic,nrf-gpiote.yaml @@ -5,7 +5,9 @@ description: NRF5 GPIOTE node compatible: "nordic,nrf-gpiote" -include: base.yaml +include: + - base.yaml + - nordic,split-channels.yaml properties: reg: @@ -13,3 +15,15 @@ properties: interrupts: required: true + + instance: + type: int + required: true + description: | + The GPIOTE instance number. GPIOTE instance GPIOTE0 has: + + instance = <0>; + + And GPIOTE1 has: + + instance = <1>; diff --git a/dts/bindings/gpio/nxp,imx-rgpio.yaml b/dts/bindings/gpio/nxp,imx-rgpio.yaml new file mode 100644 index 00000000000..eaa4e08374e --- /dev/null +++ b/dts/bindings/gpio/nxp,imx-rgpio.yaml @@ -0,0 +1,32 @@ +# Copyright 2024, NXP +# SPDX-License-Identifier: Apache-2.0 + +description: i.MX RGPIO node + +compatible: "nxp,imx-rgpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + rdc: + type: int + description: Set the RDC permission for this peripheral + + pinmux: + type: phandles + description: | + IMX pin selection peripheral does not follow specific + pattern for which GPIO port uses which pinmux. Use this property to specify + pinctrl nodes to use for the gpio port when CONFIG_PINCTRL=y. Note that + the order of the nodes matters. The first node for gpio1 will be used + as the pinmux for gpio0, port 0. + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/nxp,pcf8574.yaml b/dts/bindings/gpio/nxp,pcf8574.yaml deleted file mode 100644 index 96cb2409c16..00000000000 --- a/dts/bindings/gpio/nxp,pcf8574.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2022 ithinx GmbH -# SPDX-License-Identifier: Apache-2.0 - -description: PCF8574 8-bit I2C-based I/O expander - -compatible: "nxp,pcf8574" - -include: [i2c-device.yaml, gpio-controller.yaml] - -properties: - ngpios: - required: true - const: 8 - - int-gpios: - type: phandle-array - description: | - GPIO connected to the controller INT pin. This pin is active-low. - - "#gpio-cells": - const: 2 - -gpio-cells: - - pin - - flags diff --git a/dts/bindings/gpio/nxp,pcf857x.yaml b/dts/bindings/gpio/nxp,pcf857x.yaml new file mode 100644 index 00000000000..868ba520571 --- /dev/null +++ b/dts/bindings/gpio/nxp,pcf857x.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2022 ithinx GmbH +# 2023 Amrith Venkat Kesavamoorthi +# 2023 Mr Beam Lasers GmbH. +# SPDX-License-Identifier: Apache-2.0 + +description: PCF857x 8/16-bit I2C-based I/O expander + +compatible: "nxp,pcf857x" + +include: [i2c-device.yaml, gpio-controller.yaml] + +properties: + ngpios: + required: true + enum: + - 8 + - 16 + + int-gpios: + type: phandle-array + description: | + GPIO connected to the controller INT pin. This pin is active-low. + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/gpio/richtek,rt1718s.yaml b/dts/bindings/gpio/richtek,rt1718s.yaml index 446cde37a55..7e1b6b89206 100644 --- a/dts/bindings/gpio/richtek,rt1718s.yaml +++ b/dts/bindings/gpio/richtek,rt1718s.yaml @@ -5,7 +5,7 @@ description: | Richtek RT1718S TCPC chip The Richtek RT1718S chip is TCPC, but also has 3 pins, which can be used as - a usual GPIO. This node collects common proprties for RT1718S chip e.g. I2C + a usual GPIO. This node collects common properties for RT1718S chip e.g. I2C address. Feature-specific(GPIO, TCPC) properties should be placed in a child node e.g. a number of GPIOs. diff --git a/dts/bindings/gpio/rohm,bd8lb600fs.yaml b/dts/bindings/gpio/rohm,bd8lb600fs.yaml index 486953428b4..205b44ce83b 100644 --- a/dts/bindings/gpio/rohm,bd8lb600fs.yaml +++ b/dts/bindings/gpio/rohm,bd8lb600fs.yaml @@ -6,6 +6,8 @@ description: | This is a representation of the Rohm BD8LB600FS SPI Gpio Expander. + Multiple instances may be daisy chained, which can be configured + via the number of supported GPIOs. compatible: "rohm,bd8lb600fs" @@ -18,13 +20,15 @@ properties: ngpios: type: int required: true - const: 8 - description: Number of gpios supported + description: | + Number of pins for the expander. This must be a multiple of 8. + The number of pins also defines how many devices are daisy chained. + Set to 8 for one instance without daisy chaining. reset-gpios: type: phandle-array required: true - description: "GPIO for reset" + description: GPIO for reset gpio-cells: - pin diff --git a/dts/bindings/gpio/swj-connector.yaml b/dts/bindings/gpio/swj-connector.yaml new file mode 100644 index 00000000000..1ced649632b --- /dev/null +++ b/dts/bindings/gpio/swj-connector.yaml @@ -0,0 +1,5 @@ +description: Serial Wire - JTAG Connector + +compatible: "swj-connector" + +include: pinctrl-device.yaml diff --git a/dts/bindings/gpio/ti,tca9538.yaml b/dts/bindings/gpio/ti,tca9538.yaml index 6cb235995ab..9200a9a1606 100644 --- a/dts/bindings/gpio/ti,tca9538.yaml +++ b/dts/bindings/gpio/ti,tca9538.yaml @@ -24,6 +24,20 @@ properties: Connection for the NINT signal. This signal is active-low when produced by tca9538 GPIO node. + input-latch: + type: int + description: | + Input latch register bit is 0 by default and the input pin state + is not latched. When input latch register bit is 1 and the input + pin state is latched. + + interrupt-mask: + type: int + description: | + Interrupt mask register is set to logic 1 by default without + enabling interrupts. Setting corresponding mask bits to logic + 0 to enable the interrupts. + gpio-cells: - pin - flags diff --git a/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml b/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml index 892b208e026..a6c56733444 100644 --- a/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml +++ b/dts/bindings/gpio/zephyr,gpio-emul-sdl.yaml @@ -28,7 +28,7 @@ description: | key1: key1 { gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; }; - key1: key2 { + key2: key2 { gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; }; key3: key3 { diff --git a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml index 1b865d256ca..90c5c6e8388 100644 --- a/dts/bindings/i2c/atmel,sam-i2c-twim.yaml +++ b/dts/bindings/i2c/atmel,sam-i2c-twim.yaml @@ -14,7 +14,7 @@ description: | When using speeds above standard mode, user may need adjust clock and data lines slew and strength parameters. In general, slew 0 and minimal strength - is enougth for short buses and light loads. As reference, the below + is enough for short buses and light loads. As a reference, the below is the lowest power configuration: std-clk-slew-lim = <0>; diff --git a/dts/bindings/i2c/ite,enhance-i2c.yaml b/dts/bindings/i2c/ite,enhance-i2c.yaml index 446f3f09aea..95720c85158 100644 --- a/dts/bindings/i2c/ite,enhance-i2c.yaml +++ b/dts/bindings/i2c/ite,enhance-i2c.yaml @@ -18,6 +18,23 @@ properties: SCL cycle = 2 * (psr + prescale_tweak + 2) * SMBus clock cycle + data-hold-time: + type: int + default: 3 + enum: + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + description: | + This option is used to configure the data hold time of the I2C. + The unit is number of SMB clock cycles. The time calculation + is (data-hold-time / smb_clk) seconds. + target-enable: type: boolean description: | diff --git a/dts/bindings/i2c/nuvoton,numaker-i2c.yaml b/dts/bindings/i2c/nuvoton,numaker-i2c.yaml new file mode 100644 index 00000000000..5ba876448c1 --- /dev/null +++ b/dts/bindings/i2c/nuvoton,numaker-i2c.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NuMaker I2C controller + +compatible: "nuvoton,numaker-i2c" + +include: [i2c-controller.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true diff --git a/dts/bindings/i2s/st,stm32-i2s-common.yaml b/dts/bindings/i2s/st,stm32-i2s-common.yaml new file mode 100644 index 00000000000..09e13c449e9 --- /dev/null +++ b/dts/bindings/i2s/st,stm32-i2s-common.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2018, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for STM32 I2S peripherals. + +include: [i2s-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + dmas: + required: true + + dma-names: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + mck-enabled: + type: boolean + description: | + Master Clock Output function. + An mck pin must be listed within pinctrl-0 when enabling this property. diff --git a/dts/bindings/i2s/st,stm32-i2s.yaml b/dts/bindings/i2s/st,stm32-i2s.yaml index 1de415d0ddf..263e787d465 100644 --- a/dts/bindings/i2s/st,stm32-i2s.yaml +++ b/dts/bindings/i2s/st,stm32-i2s.yaml @@ -5,29 +5,4 @@ description: STM32 I2S controller compatible: "st,stm32-i2s" -include: [i2s-controller.yaml, pinctrl-device.yaml] - -properties: - reg: - required: true - - interrupts: - required: true - - dmas: - required: true - - dma-names: - required: true - - pinctrl-0: - required: true - - pinctrl-names: - required: true - - mck-enabled: - type: boolean - description: | - Master Clock Output function. - An mck pin must be listed within pinctrl-0 when enabling this property. +include: st,stm32-i2s-common.yaml diff --git a/dts/bindings/i2s/st,stm32h7-i2s.yaml b/dts/bindings/i2s/st,stm32h7-i2s.yaml new file mode 100644 index 00000000000..8fa3bf89c5b --- /dev/null +++ b/dts/bindings/i2s/st,stm32h7-i2s.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2018, STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: STM32H7 I2S controller + +compatible: "st,stm32h7-i2s" + +include: st,stm32-i2s-common.yaml diff --git a/dts/bindings/input/analog-axis.yaml b/dts/bindings/input/analog-axis.yaml new file mode 100644 index 00000000000..ded94e86c0f --- /dev/null +++ b/dts/bindings/input/analog-axis.yaml @@ -0,0 +1,90 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + ADC based analog axis input device + + Implement an input device generating absolute axis events by periodically + reading from some ADC channels. + + Example configuration: + + #include + + analog_axis { + compatible = "analog-axis"; + poll-period-ms = <15>; + axis-x { + io-channels = <&adc 0>; + out-deadzone = <8>; + in-min = <100>; + in-max = <800>; + zephyr,axis = ; + }; + }; + +compatible: "analog-axis" + +include: base.yaml + +properties: + poll-period-ms: + type: int + default: 15 + description: | + How often to get new ADC samples for the various configured axes in + milliseconds. Defaults to 15ms if unspecified. + +child-binding: + properties: + io-channels: + type: phandle-array + required: true + description: | + ADC IO channel to use. + + out-min: + type: int + default: 0 + description: | + Minimum value to output on input events. Defaults to 0 if unspecified. + + out-max: + type: int + default: 255 + description: | + Maximum value to output on input events. Defaults to 255 if + unspecified. + + out-deadzone: + type: int + default: 0 + description: | + Deadzone for the output center value. If specified output values + between the center of the range plus or minus this value will be + reported as center. Defaults to 0, no deadzone. + + in-min: + type: int + required: true + description: | + Input value that corresponds to the minimum output value. + + in-max: + type: int + required: true + description: | + Input value that corresponds to the maximum output value. + + zephyr,axis: + type: int + required: true + description: | + The input code for the axis to report for the device, typically any of + INPUT_ABS_*. + + invert: + type: boolean + description: | + If set, invert the raw ADC value before processing it. Useful for + differential channels. diff --git a/dts/bindings/input/espressif,esp32-touch-sensor.yaml b/dts/bindings/input/espressif,esp32-touch-sensor.yaml new file mode 100644 index 00000000000..7fe6a01d0c7 --- /dev/null +++ b/dts/bindings/input/espressif,esp32-touch-sensor.yaml @@ -0,0 +1,131 @@ +# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 + +description: | + Zephyr input touch sensor parent node + + This defines a group of touch sensors that can generate input events. Each touch + sensor is defined in a child node of the touch-sensor node and defines a specific key + code. + + For example: + + #include + #include + + &touch { + compatible = "espressif,esp32-touch"; + status = "okay"; + + debounce-interval-ms = <30>; + href-microvolt = <27000000>; + lref-microvolt = <500000>; + href-atten-microvolt = <1000000>; + filter-mode = ; + filter-debounce-cnt = <1>; + filter-noise-thr = ; + filter-jitter-step = <4>; + filter-smooth-level = ; + + touch_sensor_0 { + channel_num = <1>; + channel_sens = <20>; + zephyr,code = ; + }; + }; + + +compatible: "espressif,esp32-touch" + +include: base.yaml + +properties: + debounce-interval-ms: + type: int + default: 30 + description: Debouncing interval time in milliseconds. + + href-microvolt: + type: int + enum: + - 2400000 + - 2500000 + - 2500000 + - 2700000 + default: 2700000 + description: Touch sensor high reference voltage. + + lref-microvolt: + type: int + enum: + - 500000 + - 600000 + - 700000 + - 800000 + default: 500000 + description: Touch sensor low reference voltage. + + href-atten-microvolt: + type: int + enum: + - 1500000 + - 1000000 + - 500000 + - 0 + default: 1000000 + description: Touch sensor high reference attenuation voltage. + + filter-mode: + type: int + default: 2 + description: | + Touch sensor IIR filter coefficient. + If not specified defaults to ESP32_TOUCH_FILTER_MODE_IIR_16. + + filter-debounce-cnt: + type: int + default: 1 + description: | + Touch sensor debounce count. + If not specified defaults to 1. + + filter-noise-thr: + type: int + default: 0 + description: | + Touch sensor noise threshold coefficient. + If not specified defaults to ESP32_TOUCH_FILTER_NOISE_THR_4_8TH. + + filter-jitter-step: + type: int + default: 4 + description: | + Touch sensor jitter filter step size. + If not specified defaults to 4. + + filter-smooth-level: + type: int + default: 1 + description: | + Touch sensor level of filter applied on the original data against large noise interference. + If not specified defaults to ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_2. + +child-binding: + description: Touch sensor child node + properties: + channel-num: + type: int + required: true + description: Touch sensor channel number + + channel-sens: + type: int + default: 20 + description: | + Touch sensor channel sensibility in 100th. + If not specified defaults to 20. + + zephyr,code: + type: int + required: true + description: Key code to emit. diff --git a/dts/bindings/input/gpio-kbd-matrix.yaml b/dts/bindings/input/gpio-kbd-matrix.yaml index ef08ebaa44e..c8bad93d767 100644 --- a/dts/bindings/input/gpio-kbd-matrix.yaml +++ b/dts/bindings/input/gpio-kbd-matrix.yaml @@ -31,13 +31,34 @@ properties: type: phandle-array required: true description: | - GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO - pins must have interrupt support. + GPIO for the keyboard matrix rows, up to 8 different GPIOs. All row GPIO + pins must have interrupt support if idle-mode is set to "interrupt" + (default). col-gpios: type: phandle-array required: true description: | GPIO for the keyboard matrix columns, supports up to 32 different GPIOs. - The pins will be driven according to the GPIO_ACTIVE_HIGH or - GPIO_ACTIVE_LOW flags when selected, high impedance when not selected. + When unselected, this pin will be either driven to inactive state or + configured to high impedance (input) depending on the col-drive-inactive + property. + + col-drive-inactive: + type: boolean + description: | + If enabled, unselected column GPIOs will be driven to inactive state. + Default to configure unselected column GPIOs to high impedance. + + idle-mode: + type: string + default: "interrupt" + enum: + - "interrupt" + - "poll" + - "scan" + description: | + Controls the driver behavior on idle, "interrupt" waits for a new key + press using GPIO interrupts on the row lines, "poll" periodically polls + the row lines with all the columns selected, "scan" just keep scanning + the matrix continuously, requires "poll-timeout-ms" to be set to 0. diff --git a/dts/bindings/input/gpio-keys.yaml b/dts/bindings/input/gpio-keys.yaml index 9b3581a1c13..f2776bbda9d 100644 --- a/dts/bindings/input/gpio-keys.yaml +++ b/dts/bindings/input/gpio-keys.yaml @@ -35,15 +35,23 @@ properties: Debouncing interval time in milliseconds. If not specified defaults to 30. + polling-mode: + type: boolean + description: | + Do not use interrupts for the key GPIOs, poll the pin periodically at the + specified debounce-interval-ms instead. + child-binding: description: GPIO KEYS child node properties: gpios: type: phandle-array required: true + label: type: string description: Descriptive name of the key + zephyr,code: type: int description: Key code to emit. diff --git a/dts/bindings/input/gpio-qdec.yaml b/dts/bindings/input/gpio-qdec.yaml index 963a60e1491..96afde35b40 100644 --- a/dts/bindings/input/gpio-qdec.yaml +++ b/dts/bindings/input/gpio-qdec.yaml @@ -35,6 +35,19 @@ properties: description: | GPIO for the A and B encoder signals. + led-gpios: + type: phandle-array + description: | + GPIOs for LED or other components needed for sensing the AB signals. + + led-pre-us: + type: int + description: | + Time between enabling the led-gpios output pins and reading the encoder + state on the input pins, meant to give the state detector (such a + phototransistor) time to settle to right state. Required if led-gpios and + idle-poll-time-us are specified, can be explicitly set to 0 for no delay. + steps-per-period: type: int required: true @@ -55,6 +68,15 @@ properties: How often to sample the A and B signal lines when tracking the encoder movement. + idle-poll-time-us: + type: int + description: | + How often to sample the A and B signal while idling. If unset then the + driver will use the GPIO interrupt to exit idle state, and any GPIO + specified in led-gpios will be enabled all the time. If non zero, then + the driver will poll every idle-poll-time-us microseconds while idle, and + only activate led-gpios before sampling the encoder state. + idle-timeout-ms: type: int required: true diff --git a/dts/bindings/input/input-keymap.yaml b/dts/bindings/input/input-keymap.yaml new file mode 100644 index 00000000000..195cb1efb11 --- /dev/null +++ b/dts/bindings/input/input-keymap.yaml @@ -0,0 +1,53 @@ +# Copyright 2024 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Row-column to key mapper + + Listens for row-column events from the parent device and reports key events. + + Example configuration: + + #include + #include + + kbd { + ... + keymap { + compatible = "input-keymap"; + keymap = < + MATRIX_KEY(0, 0, INPUT_KEY_1) + MATRIX_KEY(0, 1, INPUT_KEY_2) + MATRIX_KEY(0, 2, INPUT_KEY_3) + MATRIX_KEY(1, 0, INPUT_KEY_4) + MATRIX_KEY(1, 1, INPUT_KEY_5) + MATRIX_KEY(1, 2, INPUT_KEY_6) + MATRIX_KEY(2, 0, INPUT_KEY_7) + MATRIX_KEY(2, 1, INPUT_KEY_8) + MATRIX_KEY(2, 2, INPUT_KEY_9) + >; + row-size = <3>; + col-size = <3>; + }; + }; + +compatible: "input-keymap" + +properties: + keymap: + type: array + required: true + description: | + List of codes, using the MATRIX_KEY() macro. + + row-size: + type: int + required: true + description: | + The number of rows in the keymap. + + col-size: + type: int + required: true + description: | + The number of columns in the keymap. diff --git a/dts/bindings/input/kbd-matrix-common.yaml b/dts/bindings/input/kbd-matrix-common.yaml index e399bd4431f..075c217fe4d 100644 --- a/dts/bindings/input/kbd-matrix-common.yaml +++ b/dts/bindings/input/kbd-matrix-common.yaml @@ -20,8 +20,8 @@ properties: type: int default: 5 description: | - Defines the poll period in msecs between between matrix scans. Defaults - to 5ms if unsepcified. + Defines the poll period in msecs between between matrix scans, set to 0 + to never exit poll mode. Defaults to 5ms if unspecified. poll-timeout-ms: type: int @@ -49,6 +49,14 @@ properties: Delay between setting column output and reading the row values. Defaults to 50us if unspecified. + actual-key-mask: + type: array + description: + Keyboard scanning mask. For each keyboard column, specify which + keyboard rows actually exist. Can be used to avoid triggering the ghost + detection on non existing keys. No masking by default, any combination is + valid. + no-ghostkey-check: type: boolean description: | diff --git a/dts/bindings/input/zephyr,input-longpress.yaml b/dts/bindings/input/zephyr,input-longpress.yaml index abf87a15803..a6ef96f5d40 100644 --- a/dts/bindings/input/zephyr,input-longpress.yaml +++ b/dts/bindings/input/zephyr,input-longpress.yaml @@ -8,7 +8,9 @@ description: | corresponding to short and long press. Can be optionally be associated to a specific device to listen for events - only from that device. Example configuration: + only from that device. + + Example configuration: #include @@ -23,12 +25,14 @@ description: | Example output: + # short press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # release before one second input event: dev=buttons SYN type= 1 code= 11 value=0 # INPUT_KEY_0 release input event: dev=longpress SYN type= 1 code= 30 value=1 # INPUT_KEY_A press input event: dev=longpress SYN type= 1 code= 30 value=0 # INPUT_KEY_A release + # long press input event: dev=buttons SYN type= 1 code= 11 value=1 # INPUT_KEY_0 press # hold for more than one second input event: dev=longpress SYN type= 1 code= 45 value=1 # INPUT_KEY_X press @@ -52,9 +56,8 @@ properties: short-codes: type: array - required: true description: | - Array of key codes to be generated for short press (INPUT_KEY_* or + Optional array of key codes to be generated for short press (INPUT_KEY_* or INPUT_BTN_*). long-codes: diff --git a/dts/bindings/input/zephyr,lvgl-keypad-input.yaml b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml new file mode 100644 index 00000000000..5fdd3be735a --- /dev/null +++ b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml @@ -0,0 +1,41 @@ +# Copyright 2023 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +description: | + LVGL keypad indev pseudo-device + + Listens for input events and routes the + lv_indev_data_t to the underlying keypad lv_indev_t managed by LVGL. + + The property input-codes can be used to setup a mapping of input codes + to the lvgl keys. There are lvgl keys that have a special function: + https://docs.lvgl.io/master/overview/indev.html#keys. + + The pseudo device can be associated to a specific device to listen only + for events from that device. Example configuration: + + #include + + keypad { + compatible = "zephyr,lvgl-keypad-input"; + input = <&buttons>; + input-codes = ; + lvgl-codes = ; + }; + +compatible: "zephyr,lvgl-keypad-input" + +include: zephyr,lvgl-common-input.yaml + +properties: + input-codes: + type: array + required: true + description: | + Array of input event key codes (INPUT_KEY_* or INPUT_BTN_*). + + lvgl-codes: + type: array + required: true + description: | + Array of mapped lvgl keys. diff --git a/dts/bindings/input/zephyr,native-linux-evdev.yaml b/dts/bindings/input/zephyr,native-linux-evdev.yaml new file mode 100644 index 00000000000..cd3fa219810 --- /dev/null +++ b/dts/bindings/input/zephyr,native-linux-evdev.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Linux evdev based input device + + Allows using a Linux evdev device to read input events and report them back + as Zephyr input events. + + Example configuration: + + evdev { + compatible = "zephyr,native-linux-evdev"; + }; + + Then run the binary specifying the evdev device with the --evdev flag, for + example: + + ./build/zephyr/zephyr.exe --evdev=/dev/input/event0 + +compatible: "zephyr,native-linux-evdev" + +include: base.yaml diff --git a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml index 982d7b4aa08..4e9770e65ce 100644 --- a/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml +++ b/dts/bindings/interrupt-controller/cypress,psoc6-intmux.yaml @@ -28,7 +28,7 @@ description: | ... intmux[7] = {ch31, ch30, ch29, ch28} - In pratical terms, the Cortex-M0+ requires user to define all NVIC interrupt + In practical terms, the Cortex-M0+ requires user to define all NVIC interrupt sources and the proper NVIC interrupt order. With that, the system configures the Cortex-M0+ Interrupt Multiplexer and interrupts can be processed. More information about it at PSoC-6 Architecture Technical Reference Manual, @@ -57,12 +57,12 @@ description: | intmux[20 mod 8] |= 0x02 << (20 mod 4); These results in Cortex-M0+ NVIC line 20 handling PSoC-6 interrupt source 2. - The interrupt can be enabled/disable at NVIC at line 20 as usual. + The interrupt can be enabled/disabled at NVIC at line 20 as usual. Notes: - 1) Multiple definitions will generate multiple interrutps - 2) The interrupt sources are shared between Cortex-M0+/M4. These means, can - trigger action in parallel in both processors. + 1) Multiple definitions will generate multiple interrupts + 2) The interrupt sources are shared between Cortex-M0+/M4. This means, they + can trigger actions in parallel on both processors. 3) User can change priority at Cortex-M0+ NVIC by changing interrupt channels at interrupt-parent properties. 4) Only the peripherals used by Cortex-M0+ should be configured. diff --git a/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml b/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml new file mode 100644 index 00000000000..f570e668ea5 --- /dev/null +++ b/dts/bindings/interrupt-controller/nordic,nrf-clic.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic VPR CLIC + +compatible: "nordic,nrf-clic" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 2 + +interrupt-cells: + - irq + - priority diff --git a/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml b/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml index 10d9ebc311b..d1319c9b1c2 100644 --- a/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml +++ b/dts/bindings/interrupt-controller/nuvoton,npcx-miwu.yaml @@ -16,7 +16,7 @@ properties: "#miwu-cells": type: int required: true - description: Number of items to present a MIWU input souce specifier + description: Number of items to present a MIWU input source specifier miwu-cells: - group diff --git a/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml index 03b5d3b39e0..f3300ae6821 100644 --- a/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml +++ b/dts/bindings/interrupt-controller/nxp,irqsteer-intc.yaml @@ -2,12 +2,8 @@ description: i.MX DSP interrupt controller compatible: "nxp,irqsteer-intc" -include: [interrupt-controller.yaml, base.yaml] +include: [base.yaml] properties: - "#interrupt-cells": - const: 2 - -interrupt-cells: - - irq - - priority + reg: + required: true diff --git a/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml b/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml new file mode 100644 index 00000000000..18c3fac42db --- /dev/null +++ b/dts/bindings/interrupt-controller/nxp,irqsteer-master.yaml @@ -0,0 +1,15 @@ +description: i.MX IRQ_STEER master + +compatible: "nxp,irqsteer-master" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 1 + + reg: + required: true + +interrupt-cells: + - irq diff --git a/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml b/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml new file mode 100644 index 00000000000..d5d41ed38ee --- /dev/null +++ b/dts/bindings/led_strip/worldsemi,ws2812-rpi_pico-pio.yaml @@ -0,0 +1,68 @@ +# Copyright (c) 2023, TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: | + The pio node configured for ws2812. + +compatible: "worldsemi,ws2812-rpi_pico-pio" + +include: pinctrl-device.yaml + +properties: + bit-waveform: + type: array + description: | + This property defines the waveform for sending 1-bit data. + The program uses the first three elements of the array. + The T0 is equal to T0H in the datasheet. + The T2 is equal to T1L in the datasheet. + The T1 is equal to (T1H-T0H) or (T0L-T1L) in the datasheet. + + Code-0 + +------+ +--- + | | | + | T0 | T1+T2 | + | | | + ---+ +-----------------+ + + Code-1 + +---------------+ +--- + | | | + | T0+T1 | T2 | + | | | + ---+ +--------+ + + + The frequency determines the wave period. + The T0~T2 means ratio in one period. + + For example, T0=3, T1=3, T2=4 and the frequency is 800kHz case, + T0H is + (1 / 800kHz) * (3/10) = 375ns + T0L is + (1 / 800kHz) * ((4+3)/10) = 875ns + +child-binding: + description: | + Worldsemi WS2812 or compatible LED strip driver based on RaspberryPi Pico's PIO + The LED strip node can put up to 4 instances under a single PIO node. + + include: ws2812.yaml + + properties: + output-pin: + type: int + required: true + description: | + Select the output pin. + + Note: This driver does not configure the output pin. + You need to configure the pin with pinctrl that is in the parent node configuration + for use by PIO. + + frequency: + type: int + description: | + Specify the number of times a waveform representing 1 bit is + transmitted per second. It is same meaning as bit-per-seconds. + WS2812 works with 800000. Set the value 400000 if use with WS2811. diff --git a/dts/bindings/mbox/microchip,mpfs-mailbox.yaml b/dts/bindings/mbox/microchip,mpfs-mailbox.yaml new file mode 100644 index 00000000000..8a7d9bff2eb --- /dev/null +++ b/dts/bindings/mbox/microchip,mpfs-mailbox.yaml @@ -0,0 +1,45 @@ +# +# Copyright (c) 2024 Microchip Technology Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +include: [base.yaml, mailbox-controller.yaml] + +properties: + compatible: + const: microchip,mpfs-mailbox + + reg: + - items: + - description: mailbox control registers + - description: mailbox interrupt registers + - description: mailbox data registers + + interrupts: + maxItems: 1 + + "#mbox-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - "#mbox-cells" + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + mbox: mailbox@37020000 { + compatible = "microchip,mpfs-mailbox"; + reg = <0x37020000 0x58>, <0x2000318C 0x40>, + <0x37020800 0x100>; + interrupt-parent = <&L1>; + interrupts = <96>; + #mbox-cells = <1>; + }; + }; diff --git a/dts/bindings/mbox/nxp,mbox-mailbox.yaml b/dts/bindings/mbox/nxp,mbox-mailbox.yaml new file mode 100644 index 00000000000..9a98aae9231 --- /dev/null +++ b/dts/bindings/mbox/nxp,mbox-mailbox.yaml @@ -0,0 +1,37 @@ +description: | + NXP Mailbox Unit as Zephyr MBOX. + + This NXP Mailbox driver implements Multi-Channel Inter-Processor Mailbox (MBOX) API + around NXP Inter-CPU Mailbox peripheral IP block. + + The NXP Inter-CPU Mailbox provides up to thirty-two user defined interrupts. + This driver uses 4 interrupts for mbox signalling mode per each channel, + 4 interrupts for mxbox data transfer mode per each channel and 24 as 3 bytes + for data. + +compatible: "nxp,mbox-mailbox" + +include: [base.yaml, mailbox-controller.yaml] + +properties: + interrupts: + required: true + + rx-channels: + type: int + enum: [1, 2, 3, 4] + description: | + Number of receive channels enabled on this instance. + Setting this value to N, will enable channels 0 to N-1, consecutively. + It should be set by the receiver core coupled with this Mailbox instance. + + For example, if receiver A wants to Rx on channels 0 to 3, then A must + set rx-channels of mailbox as follows: + + mbox { + rx-channels = <4>; + status = "okay"; + }; + +mbox-cells: + - channel diff --git a/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml b/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml new file mode 100644 index 00000000000..b9da5926d6b --- /dev/null +++ b/dts/bindings/mdio/infineon,xmc4xxx-mdio.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023 SLB +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon xmc4xxx Family MDIO Driver node + +compatible: "infineon,xmc4xxx-mdio" + +include: + - name: mdio-controller.yaml + - name: pinctrl-device.yaml + +properties: + mdi-port-ctrl: + description: | + The MDIO input is connected to several port/pins via a mux. + This is not handled by pinctrl because the mux is located at the + peripheral and not GPIO. The possible connections are defined by + an enum. + type: string + + enum: + - "P0_9" + - "P2_0" + - "P1_11" + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/dts/bindings/mdio/mdio-controller.yaml b/dts/bindings/mdio/mdio-controller.yaml index 9a2a6782d53..ad83e032787 100644 --- a/dts/bindings/mdio/mdio-controller.yaml +++ b/dts/bindings/mdio/mdio-controller.yaml @@ -15,3 +15,19 @@ properties: "#size-cells": required: true const: 0 + + suppress-preamble: + type: boolean + description: | + When present, the SMA suppresses the 32-bit preamble and transmits + MDIO frames with only 1 preamble bit. By default, the MDIO frame + always has 32 bits of preamble as defined in the IEEE 802.3 specs. + + clock-frequency: + type: int + default: 2500000 + description: | + Some MDIO controllers have the ability to configure the MDC frequency. + If present, this property may be used to specify the MDC frequency based + on what the PHYs connected to the mdio bus can support. Default of 2.5MHz + is the standard and should supported by all PHYs. diff --git a/dts/bindings/mdio/nxp,enet-mdio.yaml b/dts/bindings/mdio/nxp,enet-mdio.yaml new file mode 100644 index 00000000000..68bc917444a --- /dev/null +++ b/dts/bindings/mdio/nxp,enet-mdio.yaml @@ -0,0 +1,15 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP ENET MDIO Features + +compatible: "nxp,enet-mdio" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true diff --git a/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml b/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml new file mode 100644 index 00000000000..7e7f7273c0b --- /dev/null +++ b/dts/bindings/mdio/nxp,s32-gmac-mdio.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 GMAC MDIO controller. + + Driver for the GMAC Station Management Agent (SMA), which is a two wire + interface (MDC/MDIO), implemented as per IEEE 802.3 specification. SMA + supports both MDIO Clause 45 and Clause 22 frame structure. + +compatible: "nxp,s32-gmac-mdio" + +include: [mdio-controller.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + pinctrl-names: + required: true + + clocks: + required: true diff --git a/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml new file mode 100644 index 00000000000..64425b5d914 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-controller.yaml @@ -0,0 +1,20 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for MIPI-DBI controllers + +include: base.yaml + +bus: mipi-dbi + +properties: + clock-frequency: + type: int + description: | + Clock frequency of the SCL signal of the MBI-DBI peripheral, in Hz + "#address-cells": + required: true + const: 1 + "#size-cells": + required: true + const: 0 diff --git a/dts/bindings/mipi-dbi/mipi-dbi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml new file mode 100644 index 00000000000..a24ce07bb48 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-device.yaml @@ -0,0 +1,13 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI-DBI devices + +include: [base.yaml, power.yaml] + +on-bus: mipi-dbi + +properties: + mipi-max-frequency: + type: int + description: Maximum clock frequency of device's MIPI interface in Hz diff --git a/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml new file mode 100644 index 00000000000..2b8465a2667 --- /dev/null +++ b/dts/bindings/mipi-dbi/mipi-dbi-spi-device.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 +# +# Common fields for MIPI DBI devices using Mode C (SPI) + +include: [mipi-dbi-device.yaml] + +properties: + duplex: + type: int + default: 0 + description: | + SPI Duplex mode, full or half. By default it's always full duplex thus 0 + as this is, by far, the most common mode. + Use the macros not the actual enum value, here is the concordance + list (see dt-bindings/spi/spi.h) + 0 SPI_FULL_DUPLEX + 2048 SPI_HALF_DUPLEX + mipi-cpol: + type: boolean + description: | + SPI clock polarity which indicates the clock idle state. + If it is used, the clock idle state is logic high; otherwise, low. + mipi-cpha: + type: boolean + description: | + SPI clock phase that indicates on which edge data is sampled. + If it is used, data is sampled on the second edge; otherwise, on the first edge. + mipi-hold-cs: + type: boolean + description: | + In some cases, it is necessary for the master to manage SPI chip select + under software control, so that multiple spi transactions can be performed + without releasing it. A typical use case is variable length SPI packets + where the first spi transaction reads the length and the second spi transaction + reads length bytes. diff --git a/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml b/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml new file mode 100644 index 00000000000..06ca9a2f465 --- /dev/null +++ b/dts/bindings/mipi-dbi/zephyr,mipi-dbi-spi.yaml @@ -0,0 +1,35 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + MIPI-DBI Mode C compatible SPI controller. This driver emulates MIPI DBI + mode C using a SPI controller and GPIO pins +compatible: "zephyr,mipi-dbi-spi" + +include: ["mipi-dbi-controller.yaml", "pinctrl-device.yaml"] + +properties: + spi-dev: + type: phandle + required: true + description: | + SPI device to use for data transfers with MIPI DBI commands. This SPI + device should be connected to the MIPI DBI display. + + dc-gpios: + type: phandle-array + description: | + Data/command gpio pin. Required when using 4 wire SPI mode (Mode C1). + Set to low when sending a command, or high when sending data. + + reset-gpios: + type: phandle-array + description: | + Reset GPIO pin. Used to reset the display during initialization. + Active low pin. + + write-only: + type: boolean + description: | + Controller is not readable, IE only DOUT pin is connected on the SPI + interface. diff --git a/dts/bindings/misc/nordic,nrf-ficr.yaml b/dts/bindings/misc/nordic,nrf-ficr.yaml new file mode 100644 index 00000000000..ca199c24f07 --- /dev/null +++ b/dts/bindings/misc/nordic,nrf-ficr.yaml @@ -0,0 +1,17 @@ +description: Nordic FICR (Factory Information Configuration Registers) + +compatible: "nordic,nrf-ficr" + +include: base.yaml + +properties: + reg: + required: true + + "#nordic,ficr-cells": + type: int + required: true + const: 1 + +nordic,ficr-cells: + - offset diff --git a/dts/bindings/misc/nordic,split-channels.yaml b/dts/bindings/misc/nordic,split-channels.yaml new file mode 100644 index 00000000000..a875dc12d7f --- /dev/null +++ b/dts/bindings/misc/nordic,split-channels.yaml @@ -0,0 +1,44 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: | + Nordic Split Channels + + Some of Nordic's peripherals support split ownership feature that allows to + be used by independent owners. As an example the configuration of the + Global Real Time Counter (GRTC) is shown below: + owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>; + child-owned-channels = <7 8 9 10 11>; + + Which means that channels 0-11 will be assigned to the particular CPU. + Other CPUs cannot use those and another set must be defined for them. + In addition, `child-owned-channels` property allows to use channels + 7-11 only by child subprocessor. If the CPU you're configuring has no + subprocessor(s) assigned, the `child-owned-channels` property + should not be defined. + +properties: + owned-channels: + type: array + description: | + List of channels in a split-ownership peripheral that are to be owned + for use by the compiled CPU. + + nonsecure-channels: + type: array + description: | + List of channels in a split-ownership, split-security peripheral that + are to be configured as nonsecure. In Trustzone systems, this property + is only evaluated for secure peripherals, as nonsecure channels are + implicitly specified through the owned-channels property. This property + is ignored in non-Trustzone systems. + + child-owned-channels: + type: array + description: | + List of channels in a split-ownership peripheral that are officially + owned by the compiled CPU but intended to be used by its child + subprocessor(s). diff --git a/dts/bindings/misc/nordic-nrf-ficr-client.yaml b/dts/bindings/misc/nordic-nrf-ficr-client.yaml new file mode 100644 index 00000000000..06a1e727f3f --- /dev/null +++ b/dts/bindings/misc/nordic-nrf-ficr-client.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +properties: + nordic,ficrs: + type: phandle-array + description: | + FICR entries, e.g. <&ficr OFFSET>. Available offsets (or FICR entries) are + available at . + + nordic,ficr-names: + type: string-array + description: | + Names of each nordic,ficrs entry. diff --git a/dts/bindings/misc/nxp,s32-lcu.yaml b/dts/bindings/misc/nxp,s32-lcu.yaml new file mode 100644 index 00000000000..51707de20e8 --- /dev/null +++ b/dts/bindings/misc/nxp,s32-lcu.yaml @@ -0,0 +1,16 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 Logic control Unit node for S32 SoCs. + LCU selects multiple inputs from timers, Pulse Width Modulation + signals, and Input/Output (I/O) pads, and combines them + using a programmable logic function to create output waveforms + +compatible: "nxp,s32-lcu" + +include: [base.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/misc/nxp,s32-trgmux.yaml b/dts/bindings/misc/nxp,s32-trgmux.yaml new file mode 100644 index 00000000000..55a589d6836 --- /dev/null +++ b/dts/bindings/misc/nxp,s32-trgmux.yaml @@ -0,0 +1,16 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP S32 Trigger Multiplexing Control node for S32 SoCs. + The device supports the triggering scheme between peripherals. + The supported trigger sources and destination can be found in + the device Ref Manual + +compatible: "nxp,s32-trgmux" + +include: [base.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/misc/zephyr,devmux.yaml b/dts/bindings/misc/zephyr,devmux.yaml new file mode 100644 index 00000000000..744daaca120 --- /dev/null +++ b/dts/bindings/misc/zephyr,devmux.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2023, Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Generic Device Multiplexer + +compatible: "zephyr,devmux" + +include: [base.yaml, mutable.yaml] + +properties: + + devices: + type: phandles + required: true + description: | + Devices to be multiplexed. + + selected: + type: int + default: 0 + description: | + Initial multiplexer selection. + + This must be in the range [0, N-1], where N is the length of the + 'devices' phandle list. + + If unspecified, the default selection is zero in order to ensure that + the multiplexer is ready for use (i.e. one of the [0, N-1] multiplexed + devices is selected). Zero is, necessarily, the only possible valid + default value since the phandle list must have length >= 1. + + Note: Specifying a value of 'selected' outside the range [0, N-1] + results in a compile-time error. diff --git a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml index 6534ec07874..16bdac395e4 100644 --- a/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv6m-mpu.yaml @@ -10,9 +10,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - required: true - type: int - const: 8 - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml index 36de0b9f711..e0c6c3b4cec 100644 --- a/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv7m-mpu.yaml @@ -7,8 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - required: true - type: int - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml index fd924284de8..7800e36d7a1 100644 --- a/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8.1m-mpu.yaml @@ -7,8 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - required: true - type: int - description: number of MPU regions supported by hardware diff --git a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml index 10321622891..0e7c12bf1b0 100644 --- a/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml +++ b/dts/bindings/mmu_mpu/arm,armv8m-mpu.yaml @@ -7,8 +7,3 @@ include: base.yaml properties: reg: required: true - - arm,num-mpu-regions: - required: true - type: int - description: number of MPU regions supported by hardware diff --git a/dts/bindings/modem/u-blox,sara-r5.yaml b/dts/bindings/modem/u-blox,sara-r5.yaml new file mode 100644 index 00000000000..af6c3318fd0 --- /dev/null +++ b/dts/bindings/modem/u-blox,sara-r5.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Emil Lindqvist +# SPDX-License-Identifier: Apache-2.0 + +description: u-blox SARA-R5 modem + +compatible: "u-blox,sara-r5" + +include: uart-device.yaml + +properties: + mdm-power-gpios: + type: phandle-array + + mdm-reset-gpios: + type: phandle-array diff --git a/dts/bindings/mtd/atmel,sam-flash.yaml b/dts/bindings/mtd/atmel,sam-flash.yaml new file mode 100644 index 00000000000..c2a16328105 --- /dev/null +++ b/dts/bindings/mtd/atmel,sam-flash.yaml @@ -0,0 +1,117 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: | + This binding describes the Atmel SAM flash area layout. + + The Atmel SAM flash area varies in write-block-size, memory area, + and the layout of erase-blocks. + + E.g. the flash area layout of the ATSAM4E16C: + + |--------------------| + | 8 Kbytes | erase block size = 2048 + |--------------------| + | 8 Kbytes | erase block size = 2048 + |--------------------| + | 48 Kbytes | erase block size = 4096 + |--------------------| + | 64 Kbytes | erase block size = 4096 + |--------------------| + | ... | + + The ATSAM4E16C has a flash area which is 1000Kbytes + (1024 * 1024 bytes) with a write-block-size of 8 bytes. The first + 16 Kbytes can be erased in blocks of 2048 bytes + (8 blocks of 2048 bytes), the remaining flash area is erasable + in blocks of 4096 bytes (252 blocks of 4096 bytes). + + This flash area layout would described as: + + / { + soc { + eefc: flash-controller@400e0a00 { + compatible = "atmel,sam-flash-controller"; + reg = <0x400e0a00 0x200>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + status = "okay"; + + #address-cells = <1>; + #size-cells = <1>; + #erase-block-cells = <2>; + + flash0: flash@400000 { + compatible = "atmel,sam-flash", "soc-nv-flash"; + reg = <0x400000 0x100000>; + write-block-size = <8>; + erase-block-size = <4096>; + erase-blocks = <&eefc 8 2048>, <&eefc 252 4096>; + }; + }; + }; + + Notes: + The flash area layout node flash0 should have both this + compatible, "atmel,sam-flash", and the "soc-nv-flash" + compatible. The latter is used from mcuboot and other + modules to identify the flash area. + + If partitions are used, remember that their addresses are + offsets relative to the flash area address. E.g. using + mcuboot and a allocating a storage partition: + + &flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x0 0x10000>; + }; + + slot0_partition: partition@10000 { + label = "slot0"; + reg = <0x10000 0x70000>; + }; + + slot1_partition: partition@80000 { + label = "slot1"; + reg = <0x80000 0x70000>; + }; + + storage_partition: partition@f0000 { + label = "storage"; + reg = <0xf0000 0x100000>; + }; + }; + }; + +compatible: "atmel,sam-flash" + +include: base.yaml + +properties: + write-block-size: + type: int + description: | + The flash controller is limited by hardware to writing blocks of + this size, aligned to this size, in bytes, to previously erased + flash, within the flash memory area. + + erase-block-size: + type: int + description: | + The flash controller is limited by hardware to erase whole + blocks of flash at a time. This property describes the largest + erase block size in erase-blocks. + + erase-blocks: + type: phandle-array + required: true + description: | + The flash controller is limited by hardware to erase whole + blocks of flash at a time. This property describes the layout of + the erase-blocks, which can vary in size within the flash memory + area. diff --git a/dts/bindings/mtd/nordic,mram.yaml b/dts/bindings/mtd/nordic,mram.yaml new file mode 100644 index 00000000000..dac7d14305d --- /dev/null +++ b/dts/bindings/mtd/nordic,mram.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Nordic MRAM + +compatible: nordic,mram + +include: soc-nv-flash.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/mtd/nordic,owned-partitions.yaml b/dts/bindings/mtd/nordic,owned-partitions.yaml new file mode 100644 index 00000000000..bf42c13346a --- /dev/null +++ b/dts/bindings/mtd/nordic,owned-partitions.yaml @@ -0,0 +1,89 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic Owned Partitions + + Memory partition table with permission attributes common to its partitions. + This is a special case of the Nordic Owned Memory binding. + + Every compatible node is expected to be a child of a memory node, where the + listed partitions belong. + + A single memory node can contain multiple partition tables, each with a + different set of permissions. For each such table, the smallest memory region + spanning the contained partitions will be recorded in the UICR. These regions + are allowed to contain gaps between the partitions, but this is discouraged. + + Example: + + mram1x: mram@e000000 { + compatible = "nordic,mram"; + reg = <0xe000000 0x200000>; + ... + + rx-partitions { + compatible = "nordic,owned-partitions"; + perm-read; + perm-execute; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@c0000 { + label = "image-0"; + reg = <0xc0000 0x40000>; + }; + }; + + rw-partitions { + compatible = "nordic,owned-partitions"; + perm-read; + perm-write; + #address-cells = <1>; + #size-cells = <1>; + + slot1_partition: partition@100000 { + label = "image-1"; + reg = <0x100000 0x50000>; + }; + storage_partition: partition@150000 { + label = "storage"; + reg = <0x150000 0x6000>; + }; + }; + }; + + From this example, two memory regions will be inferred: + + - 0x0E0C0000--0x0E100000, with read & execute permissions, containing the + partition labeled "image-0". + - 0x0E100000--0x0E156000, with read & write permissions, containing the + partitions labeled "image-1" and "storage". + +compatible: "nordic,owned-partitions" + +include: + - name: nordic,owned-memory.yaml + property-blocklist: + - reg + +properties: + "#address-cells": + required: true + + "#size-cells": + required: true + +child-binding: + description: | + Partitions in the table are defined as subnodes. Each partition must have a + size and an offset relative to the base address of the parent memory node. + + include: + - name: base.yaml + property-blocklist: + - compatible + + properties: + reg: + required: true diff --git a/dts/bindings/net/wireless/gpio-radio-coex.yaml b/dts/bindings/net/wireless/gpio-radio-coex.yaml index e21cc53d433..1acb8e7f9a9 100644 --- a/dts/bindings/net/wireless/gpio-radio-coex.yaml +++ b/dts/bindings/net/wireless/gpio-radio-coex.yaml @@ -2,9 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 description: | - Generic representation of Coexistance pin interface for radios. This + Generic representation of Coexistence pin interface for radios. This interface is usually available on Wifi/Bluetooth/LTE modules to - interact with each other when sharing same antenna. This prevents + interact with each other when sharing the same antenna. This prevents any collisions between transmissions from different modules. The grant signal should signal that the external transceiver/module is not transmitting. Therefore you are free to perform any TX operations as diff --git a/dts/bindings/pcie/host/intel,pcie.yaml b/dts/bindings/pcie/host/intel,pcie.yaml deleted file mode 100644 index 991f44af054..00000000000 --- a/dts/bindings/pcie/host/intel,pcie.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2020 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -description: Intel PCIe host controller - -compatible: "intel,pcie" - -include: pcie-controller.yaml diff --git a/dts/bindings/pcie/host/pcie-controller.yaml b/dts/bindings/pcie/host/pcie-controller.yaml index c5e1bcd83d6..2f83c01dbfe 100644 --- a/dts/bindings/pcie/host/pcie-controller.yaml +++ b/dts/bindings/pcie/host/pcie-controller.yaml @@ -3,7 +3,11 @@ # Common fields for PCIe bus controllers -include: base.yaml +include: [base.yaml, acpi.yaml] + +description: Generic PCIe host controller + +compatible: "pcie-controller" bus: pcie diff --git a/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml b/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml index 79cd24910cf..c55372094ae 100644 --- a/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml +++ b/dts/bindings/pinctrl/espressif,esp32-pinctrl.yaml @@ -65,7 +65,7 @@ description: | target SoC in the following URL - https://github.com/zephyrproject-rtos/hal_espressif/tree/zephyr/include/dt-bindings/pinctrl + https://github.com/zephyrproject-rtos/zephyr/tree/main/include/zephyr/dt-bindings/pinctrl The ESP-WROVER-KIT board is based on the ESP32 SoC, in that case, we search diff --git a/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml b/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml index 36a3a7595a2..01a1c758a9c 100644 --- a/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml +++ b/dts/bindings/pinctrl/ite,it8xxx2-pinctrl.yaml @@ -46,7 +46,7 @@ description: | The 'uart1_rx_pb0_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. + (that is, active) state. To link pin configurations with a device, use a pinctrl-N property for some number N, like this example you could place in your board's DTS file: @@ -65,7 +65,7 @@ include: base.yaml child-binding: description: | - This binding gives a base representation of the ITE IT8XXX2 pins configration. + This binding gives a base representation of the ITE IT8XXX2 pins configuration. include: - name: pincfg-node.yaml diff --git a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml index fa94cd11c05..1743f213193 100644 --- a/dts/bindings/pinctrl/renesas,rcar-pfc.yaml +++ b/dts/bindings/pinctrl/renesas,rcar-pfc.yaml @@ -40,7 +40,7 @@ description: | The 'can0_data_a_tx_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. You would specify the low-power configuration for + (that is, active) state. You would specify the low-power configuration for the same device in a separate child node. A pin configuration can also specify pin properties such as the @@ -51,6 +51,7 @@ description: | - bias-pull-down - bias-pull-up - drive-strength + - power-source To link pin configurations with a device, use a pinctrl-N property for some number N, like this example you could place in your board's DTS file: @@ -82,6 +83,7 @@ child-binding: - bias-pull-down - bias-pull-up - drive-strength + - power-source properties: pin: diff --git a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml index cfc1c2a6fa7..b412d5dfddb 100644 --- a/dts/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/dts/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -34,7 +34,7 @@ properties: child-binding: description: | - This binding gives a base representation of the STM32 pins configration + This binding gives a base representation of the STM32 pins configuration include: - name: pincfg-node.yaml @@ -76,7 +76,7 @@ child-binding: This macro is available here: -include/zephyr/dt-bindings/pinctrl/stm32-pinctrl-common.h Some examples of macro usage: - GPIO A9 set as alernate function 2 + GPIO A9 set as alternate function 2 ... { pinmux = ; }; diff --git a/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml b/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml index f96b3c123ea..77efa78c064 100644 --- a/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml +++ b/dts/bindings/pinctrl/st,stm32f1-pinctrl.yaml @@ -41,7 +41,7 @@ properties: child-binding: description: | This binding gives a base representation of the STM32F1 pins - configration + configuration include: - name: pincfg-node.yaml @@ -85,11 +85,11 @@ child-binding: This macro is available here: -include/zephyr/dt-bindings/pinctrl/stm32f1-pinctrl.h Some examples of macro usage: - GPIO A9 set as alernate with no remap + GPIO A9 set as alternate with no remap ... { pinmux = ; }; - GPIO A9 set as alernate with full remap + GPIO A9 set as alternate with full remap ... { pinmux = ; }; diff --git a/dts/bindings/pinctrl/telink,b91-pinctrl.yaml b/dts/bindings/pinctrl/telink,b91-pinctrl.yaml index 2c19c46a080..df490ffa18a 100644 --- a/dts/bindings/pinctrl/telink,b91-pinctrl.yaml +++ b/dts/bindings/pinctrl/telink,b91-pinctrl.yaml @@ -39,7 +39,7 @@ description: | The 'uart0_tx_pb2_default' child node encodes the pin configurations for a particular state of a device; in this case, the default - (that is, active) sate. You would specify the low-power configuration for + (that is, active) state. You would specify the low-power configuration for the same device in a separate child node. A pin configuration can also specify pin properties such as the @@ -83,7 +83,7 @@ properties: child-binding: description: | - This binding gives a base representation of the Telink B91 pins configration. + This binding gives a base representation of the Telink B91 pins configuration. include: - name: pincfg-node.yaml diff --git a/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml b/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml new file mode 100644 index 00000000000..7a5af3a2b7d --- /dev/null +++ b/dts/bindings/pinctrl/xlnx,pinctrl-zynqmp.yaml @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: | + Xilinx ZynqMP SoC pinctrl node. It allows configuration of pin assignments + for the supported peripherals. + + See Zynq UltraScale+ Devices Register Reference (UG1087) for details regarding + valid pin assignments +compatible: "xlnx,pinctrl-zynqmp" + +include: base.yaml + +child-binding: + description: | + Definitions for a pinctrl state. + child-binding: + + include: + - name: pincfg-node.yaml + + properties: + pinmux: + required: true + type: array + description: | + Pin assignments for the selected group diff --git a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml index d7dfd8779b7..734aab8e6f7 100644 --- a/dts/bindings/power-domain/power-domain-gpio-monitor.yaml +++ b/dts/bindings/power-domain/power-domain-gpio-monitor.yaml @@ -6,8 +6,8 @@ description: | This power domain monitors the state of a GPIO pin to detect whether a power rail is on/off. Therefore, performing resume/suspend on power domain won't - change physical state of power rails and those action won't be triggerd on - child nodes. Additionally, due to the asynchronous nature of monitoring a + change physical state of power rails and that action won't be triggered on + child nodes. Additionally, due to the asynchronous nature of monitoring, a pending transaction won't be interrupted by power state change. compatible: "power-domain-gpio-monitor" diff --git a/dts/bindings/ppc/nxp,nx20p3483.yaml b/dts/bindings/ppc/nxp,nx20p3483.yaml new file mode 100644 index 00000000000..c705ac32c33 --- /dev/null +++ b/dts/bindings/ppc/nxp,nx20p3483.yaml @@ -0,0 +1,39 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: NXP NX20P3483 Power path controller chip + +compatible: "nxp,nx20p3483" + +include: [base.yaml, i2c-device.yaml] + +properties: + irq-gpios: + type: phandle-array + description: Interrupt pin + + snk-ovp: + type: int + default: 1 + description: + Sink high-voltage overvoltage protection threshold in millivolts. + This value must be set using one of the NX20P348X_U_THRESHOLD_* defines. + + src-hv: + type: boolean + description: + If set, source role will use high-voltage path instead of 5V. + + src-hv-ocp: + type: int + default: 6 + description: + Source high-voltage overcurrent protection threshold in milliamperes. + This value must be set using one of the NX20P348X_I_THRESHOLD_* defines. + + src-5v-ocp: + type: int + default: 6 + description: + Source 5V overcurrent protection threshold in milliamperes. + This value must be set using one of the NX20P348X_I_THRESHOLD_* defines. diff --git a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml index 37de69e39e1..0b8a2ffc674 100644 --- a/dts/bindings/pwm/nxp,s32-emios-pwm.yaml +++ b/dts/bindings/pwm/nxp,s32-emios-pwm.yaml @@ -179,7 +179,7 @@ child-binding: default: 0 enum: [0, 2, 4, 8, 16] description: | - Select the minimim input pulse width, in filter clock cycles that can pass + Select the minimum input pulse width, in filter clock cycles that can pass through the input filter. The filter latency - the difference in time between the input and the response is three clock edges. Default 0 means the filter is bypassed. The clock source for programmable input filter is eMIOS clock. diff --git a/dts/bindings/qspi/nxp,s32-qspi.yaml b/dts/bindings/qspi/nxp,s32-qspi.yaml index 7d61e5d8104..0f59af09f25 100644 --- a/dts/bindings/qspi/nxp,s32-qspi.yaml +++ b/dts/bindings/qspi/nxp,s32-qspi.yaml @@ -70,7 +70,7 @@ properties: type: int default: 0 description: | - Column Address Space bit width. For example, if the coulmn address is + Column Address Space bit width. For example, if the column address is [2:0] of QSPI_SFAR/AHB address, then the column address space bit width must be 3. If there is no column address separation in any serial flash device connected to this controller, this value must be programmed to 0. diff --git a/dts/bindings/regulator/maxim,max20335-regulator.yaml b/dts/bindings/regulator/maxim,max20335-regulator.yaml index 44086e0c4fa..d23a1fdf1c1 100644 --- a/dts/bindings/regulator/maxim,max20335-regulator.yaml +++ b/dts/bindings/regulator/maxim,max20335-regulator.yaml @@ -40,10 +40,12 @@ child-binding: include: - name: regulator.yaml property-allowlist: - - regulator-always-on - - regulator-boot-on - - regulator-max-microamp + - regulator-init-microvolt - regulator-min-microvolt - regulator-max-microvolt - - regulator-allowed-modes + - regulator-init-microamp + - regulator-max-microamp + - regulator-always-on + - regulator-boot-on - regulator-initial-mode + - regulator-allowed-modes diff --git a/dts/bindings/regulator/regulator.yaml b/dts/bindings/regulator/regulator.yaml index 167355d9224..635bfa49596 100644 --- a/dts/bindings/regulator/regulator.yaml +++ b/dts/bindings/regulator/regulator.yaml @@ -31,6 +31,10 @@ properties: type: int description: Offset applied to voltages to compensate for voltage drops + regulator-init-microamp: + type: int + description: Current set during initialisation + regulator-min-microamp: type: int description: smallest current consumers may set diff --git a/dts/bindings/regulator/renesas,da1469x-regulator.yaml b/dts/bindings/regulator/renesas,da1469x-regulator.yaml new file mode 100644 index 00000000000..2537b7e09d7 --- /dev/null +++ b/dts/bindings/regulator/renesas,da1469x-regulator.yaml @@ -0,0 +1,46 @@ +# Copyright (c), 2023 Renesas Electronics Corporation +# SPDX -License-Identifier: Apache-2.0 + +description: | + Renesas Smartbond(tm) LDO and DCDC regulators + +compatible: "renesas,smartbond-regulator" + +child-binding: + include: + - name: regulator.yaml + property-allowlist: + - regulator-always-on + - regulator-boot-on + - regulator-init-microvolt + - regulator-initial-mode + - regulator-max-microamp + properties: + renesas,regulator-v30-ref-bandgap: + type: boolean + description: | + Selects reference source for V30 LDO to Bandgap output. + renesas,regulator-v30-clamp: + type: boolean + description: | + Enables clamp that can supply V30 from VBAT. + renesas,regulator-v30-vbus: + type: boolean + description: | + Allow V30 to be powered from VBUS. + renesas,regulator-v30-vbat: + type: boolean + description: | + Allow V30 to be powered from VBAT. + renesas,regulator-dcdc-vbat-high: + type: boolean + description: | + Enable DCDC in high battery voltage mode. + renesas,regulator-dcdc-vbat-low: + type: boolean + description: | + Enable DCDC in low battery voltage mode. + renesas,regulator-sleep-ldo: + type: boolean + description: | + Enable LDO in sleep mode. diff --git a/dts/bindings/reserved-memory/nordic,owned-memory.yaml b/dts/bindings/reserved-memory/nordic,owned-memory.yaml new file mode 100644 index 00000000000..9b13c965ac8 --- /dev/null +++ b/dts/bindings/reserved-memory/nordic,owned-memory.yaml @@ -0,0 +1,46 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: | + Nordic Owned Memory + + Memory region with permission attributes. Each enabled region of this kind + will be recorded in the UICR of the compiled domain. Memory ownership and + access is then configured for the domain at boot time, based on the UICR. + +compatible: "nordic,owned-memory" + +include: base.yaml + +properties: + reg: + required: true + + owner-id: + type: int + description: | + Owner ID of the domain that will own this memory region. If not defined, + the ownership will default to the domain being compiled. + + Note: owner ID is not the same as domain ID; see the product specification + for details. + + perm-read: + type: boolean + description: Owner has read access to the region. + + perm-write: + type: boolean + description: Owner has write access to the region. + + perm-execute: + type: boolean + description: Owner can execute code from the region. + + perm-secure: + type: boolean + description: Owner has secure-only access to the region. + + non-secure-callable: + type: boolean + description: Memory region is used for non-secure-callable code. diff --git a/dts/bindings/retained_mem/zephyr,retained-ram.yaml b/dts/bindings/retained_mem/zephyr,retained-ram.yaml index 5f2c1df1244..0b11fdd1bff 100644 --- a/dts/bindings/retained_mem/zephyr,retained-ram.yaml +++ b/dts/bindings/retained_mem/zephyr,retained-ram.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2023 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 -description: Unitialised RAM-based retained memory area. +description: Uninitialised RAM-based retained memory area. compatible: "zephyr,retained-ram" diff --git a/dts/bindings/retained_mem/zephyr,retained-reg.yaml b/dts/bindings/retained_mem/zephyr,retained-reg.yaml new file mode 100644 index 00000000000..12c9a530390 --- /dev/null +++ b/dts/bindings/retained_mem/zephyr,retained-reg.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Retained register based retained memory area. + +compatible: "zephyr,retained-reg" + +include: base.yaml + +properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + + reg: + required: true diff --git a/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml b/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml new file mode 100644 index 00000000000..6be94dce25d --- /dev/null +++ b/dts/bindings/riscv/nordic,nrf-vpr-coprocessor.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +compatible: "nordic,nrf-vpr-coprocessor" + +description: | + VPR coprocessor + + VPR is a RISC-V CPU implementation. VPR instances are exposed to other CPUs as + peripherals. + +include: base.yaml + +properties: + cpu: + type: int + description: | + Processor ID of the VPR core. + + execution-memory: + type: phandle + required: true + description: | + Memory area from which the VPR core will execute. + + source-memory: + type: phandle + description: | + Memory area or partition from which the VPR code will be loaded. diff --git a/dts/bindings/rng/st,stm32-rng.yaml b/dts/bindings/rng/st,stm32-rng.yaml index a58a8a81aeb..c0e6d5e2ec3 100644 --- a/dts/bindings/rng/st,stm32-rng.yaml +++ b/dts/bindings/rng/st,stm32-rng.yaml @@ -18,8 +18,8 @@ properties: the clock domain used, for instance: <&rcc STM32_SRC_MSI CLK48_SEL(3)> /* RNG clock domain set to MSI */ A correctly configured domain clock is required to allow the integrated low - sampling clock detection mecanism to behave properly. - In provided example, MSI should be configured to provide 48Mhz clock. + sampling clock detection mechanism to behave properly. + In the provided example, MSI should be configured to provide 48Mhz clock. nist-config: type: int diff --git a/dts/bindings/rtc/motorola,mc146818.yaml b/dts/bindings/rtc/motorola,mc146818.yaml index 7974c1d68c3..eebb134351e 100644 --- a/dts/bindings/rtc/motorola,mc146818.yaml +++ b/dts/bindings/rtc/motorola,mc146818.yaml @@ -6,7 +6,7 @@ description: Motorola MC146818 compatible Real Timer Clock compatible: "motorola,mc146818" -include: rtc-device.yaml +include: [rtc-device.yaml, acpi.yaml] properties: clock-frequency: diff --git a/dts/bindings/rtc/nxp,pcf8563.yaml b/dts/bindings/rtc/nxp,pcf8563.yaml index 95ca4a793a4..d354c71af00 100644 --- a/dts/bindings/rtc/nxp,pcf8563.yaml +++ b/dts/bindings/rtc/nxp,pcf8563.yaml @@ -8,9 +8,6 @@ compatible: "nxp,pcf8563" include: - name: rtc-device.yaml - name: i2c-device.yaml - - name: pm.yaml - property-allowlist: - - wakeup-source properties: int1-gpios: diff --git a/dts/bindings/sdhc/cdns,sdhc.yaml b/dts/bindings/sdhc/cdns,sdhc.yaml new file mode 100644 index 00000000000..536b9c4bd58 --- /dev/null +++ b/dts/bindings/sdhc/cdns,sdhc.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Cadence SDHC Controller node + +compatible: "cdns,sdhc" + +include: [sdhc.yaml, reset-device.yaml] + +properties: + clock-frequency: + type: int + description: clock-frequency for SDHC + reg: + required: true + description: register space + power_delay_ms: + type: int + required: true + description: delay required to switch on the SDHC diff --git a/dts/bindings/sensor/ams,tsl2540.yaml b/dts/bindings/sensor/ams,tsl2540.yaml index e47f8a8e8f0..d19bd4ea002 100644 --- a/dts/bindings/sensor/ams,tsl2540.yaml +++ b/dts/bindings/sensor/ams,tsl2540.yaml @@ -20,7 +20,7 @@ properties: default: 100000 description: | Visible light attenuation. - Integer value for a represenation with 5 decimal points. + Integer value for a representation with 5 decimal points. This default value (1.00000) is chosen for free open space (no glass). Example: 1.2 would be 120000 @@ -29,6 +29,6 @@ properties: default: 100000 description: | Infa-red light attenuation. - Integer value for a represenation with 5 decimal points. + Integer value for a representation with 5 decimal points. This default value (1.00000) is chosen for free open space (no glass). Example: 1.2 would be 120000 diff --git a/dts/bindings/sensor/aosong,ags10.yaml b/dts/bindings/sensor/aosong,ags10.yaml new file mode 100644 index 00000000000..fffd0f258fe --- /dev/null +++ b/dts/bindings/sensor/aosong,ags10.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Balthazar Deliers +# SPDX-License-Identifier: Apache-2.0 + +description: | + AOSONG AGS10 a high-performance TVOC Sensor With I2C Interface. + See: http://www.aosong.com/en/products-86.html + +compatible: "aosong,ags10" + +include: [sensor-device.yaml, i2c-device.yaml] diff --git a/dts/bindings/sensor/bosch,bma4xx-common.yaml b/dts/bindings/sensor/bosch,bma4xx-common.yaml new file mode 100644 index 00000000000..f7053021850 --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-common.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +properties: + int1-gpios: + type: phandle-array + description: | + Identifies pin for the INT1 signal on the sensor. The sensor + INT2,3,4 signals are not supported by the driver. diff --git a/dts/bindings/sensor/bosch,bma4xx-i2c.yaml b/dts/bindings/sensor/bosch,bma4xx-i2c.yaml new file mode 100644 index 00000000000..8c5ddce2138 --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bosch BMA4xx 3-axis acceleration sensors in I2C mode. See more info at: + https://www.bosch-sensortec.com/products/motion-sensors/accelerometers/ + +compatible: "bosch,bma4xx" + +include: [sensor-device.yaml, i2c-device.yaml, "bosch,bma4xx-common.yaml"] diff --git a/dts/bindings/sensor/bosch,bma4xx-spi.yaml b/dts/bindings/sensor/bosch,bma4xx-spi.yaml new file mode 100644 index 00000000000..dfadc8c686e --- /dev/null +++ b/dts/bindings/sensor/bosch,bma4xx-spi.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bosch BMA4xx 3-axis acceleration sensors in SPI mode. See more info at: + https://www.bosch-sensortec.com/products/motion-sensors/accelerometers/ + + SPI mode is currently NOT supported in the driver but is specified in the + bindings for ease of future expansion. + +compatible: "bosch,bma4xx" + +include: [sensor-device.yaml, spi-device.yaml, "bosch,bma4xx-common.yaml"] diff --git a/dts/bindings/sensor/bosch,bmp581.yml b/dts/bindings/sensor/bosch,bmp581.yml new file mode 100644 index 00000000000..0d842142929 --- /dev/null +++ b/dts/bindings/sensor/bosch,bmp581.yml @@ -0,0 +1,16 @@ +description: | + The BMP581 is a Barometric pressure sensor. See more info at: + https://www.bosch-sensortec.com/products/environmental-sensors/pressure-sensors/bmp581/ + +compatible: "bosch,bmp581" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + required: false + description: Interrupt pin. + + The interrupt pin of BMP581 is open-drain, active low. If connected directly to the MCU, + the pin should be configured as pull-up, active low. diff --git a/dts/bindings/sensor/espressif,esp32-temp.yaml b/dts/bindings/sensor/espressif,esp32-temp.yaml index 32bf13a3013..31509f40251 100644 --- a/dts/bindings/sensor/espressif,esp32-temp.yaml +++ b/dts/bindings/sensor/espressif,esp32-temp.yaml @@ -11,10 +11,10 @@ properties: range: type: int description: | - The temperature sensor is available on the ESP32-S2, ESP32-C3. Note - that it is unavailable on the ESP32 due to missing offset calibration. - Temperature range is defined by the temperature offset which is used - during calculation of the output temperature from the measured value. + The temperature sensor is available on the ESP32-S2, ESP32-S3, ESP32-C3. + Note that it is unavailable on the ESP32 due to missing offset calibration. + Temperature range is defined by the temperature offset which is used during + calculation of the output temperature from the measured value. default: 2 enum: - 0 # measure range: 50°C ~ 125°C, error < 3°C diff --git a/dts/bindings/sensor/maxim,max31875.yaml b/dts/bindings/sensor/maxim,max31875.yaml index 4ded503bdbd..546a931e6f6 100644 --- a/dts/bindings/sensor/maxim,max31875.yaml +++ b/dts/bindings/sensor/maxim,max31875.yaml @@ -17,7 +17,7 @@ properties: conversions-per-second: description: | Number of temperature readings performed by the MAX31875 per second. - 0.25 converions per second is the power-on reset configuration. + 0.25 conversions per second is the power-on reset configuration. type: string default: "0.25" # Note: the driver relies on the ordering of this enum, diff --git a/dts/bindings/adc/nordic,nrf-comp.yaml b/dts/bindings/sensor/nordic,nrf-comp.yaml similarity index 100% rename from dts/bindings/adc/nordic,nrf-comp.yaml rename to dts/bindings/sensor/nordic,nrf-comp.yaml diff --git a/dts/bindings/adc/nordic,nrf-lpcomp.yaml b/dts/bindings/sensor/nordic,nrf-lpcomp.yaml similarity index 100% rename from dts/bindings/adc/nordic,nrf-lpcomp.yaml rename to dts/bindings/sensor/nordic,nrf-lpcomp.yaml diff --git a/dts/bindings/sensor/nuvoton,adc-cmp.yaml b/dts/bindings/sensor/nuvoton,adc-cmp.yaml index 40d0e1b6e0c..2cc687b8423 100644 --- a/dts/bindings/sensor/nuvoton,adc-cmp.yaml +++ b/dts/bindings/sensor/nuvoton,adc-cmp.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 description: | - This will perform signal comparision with threshold established. + This will perform signal comparison with threshold established. compatible: "nuvoton,adc-cmp" diff --git a/dts/bindings/sensor/nxp,kinetis-temperature.yaml b/dts/bindings/sensor/nxp,kinetis-temperature.yaml index 0b2b4d9df9d..0ad50bf2e97 100644 --- a/dts/bindings/sensor/nxp,kinetis-temperature.yaml +++ b/dts/bindings/sensor/nxp,kinetis-temperature.yaml @@ -25,7 +25,7 @@ properties: type: int required: true description: | - Temperature sensor voltage at 25 degrees Celcius in microvolts + Temperature sensor voltage at 25 degrees Celsius in microvolts sensor-slope-cold: type: int diff --git a/dts/bindings/sensor/nxp,s32-qdec.yaml b/dts/bindings/sensor/nxp,s32-qdec.yaml new file mode 100644 index 00000000000..935d2122f23 --- /dev/null +++ b/dts/bindings/sensor/nxp,s32-qdec.yaml @@ -0,0 +1,112 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + Quadrature Decoder driver which processes encoder signals to determine motor revs + with the cooperation of S32 IP blocks- eMIOS, TRGMUX and LCU. + The sensor qdec application can be used for testing this driver. + The following example uses TRGMUX IN2 and IN3 to connect to LCU1 LC0 I0 and I1. + LCU1 LC0 O2 and O3 connect to eMIOS0 CH6(Clockwise rotation) and + CH7(Counter Clockwise rotation) via TRGMUX_INT_OUT37 and TRGMUX_INT_OUT38 + micro-ticks-per-rev is set as per vehicle gearbox reduction. + lcu output filters are set to capture maximum speed sensitivity and avoid channel noise. + + qdec0 { + compatible = "nxp,qdec-s32"; + pinctrl-0 = <&qdec_s32>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + status = "okay"; + trgmux = <&trgmux>; + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + lcu = <&lcu1>; + lcu-input-idx = <1>; + ; + lcu-mux-sel = + ; + lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + emios = <&emios0>; + emios-channels = <6 7>; + }; + +compatible: "nxp,qdec-s32" + +include: [pinctrl-device.yaml, sensor-device.yaml] + +properties: + micro-ticks-per-rev: + type: int + description: | + This is a number that is used to determine how many revolutions * 1000000 + were done based on the current counter's value. + + trgmux: + type: phandle + description: | + phandle to the TRGMUX node. + + trgmux-io-config: + type: array + description: | + This gives the logic triggers configuration of TRGMUX module. + It contains 3 values for each of the 4 logic triggers used: + logic trigger number, output, input. + Hence, it's length should be '12'. + Ex: + trgmux-io-config = + <0 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2>, + <1 TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3>, + <2 TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 TRGMUX_IP_INPUT_SIUL2_IN2>, + <3 TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 TRGMUX_IP_INPUT_SIUL2_IN3>; + + lcu: + type: phandle + description: | + phandle to the LCU node. + + emios: + type: phandle + description: | + phandle to the eMIOS node. + + lcu-output-filter-config: + type: array + description: | + This array gives the configuration for each of the four outputs of LCU module. + It contains the following for each output: hardware output id, rise filter and fall filter. + The filters specify the delay in terms of CORE_CLK between the input and output line of LC. + We use this delay to generate short pulses at the rising and falling edges of input pulse. + It's length should be '12' - 3 entries for each of the four LCU outputs. + Ex: lcu-output-filter-config = + /* LCU Out HW ID, Rise Filter, Fall Filter */ + <0 5 5>, /* LCU O0 */ + <1 5 5>, /* LCU O1 */ + <2 2 2>, /* LCU O2 */ + <3 2 2>; /* LCU O3 */ + + lcu-mux-sel: + type: array + description: | + This array configures the sources of input to the LCU module by programming the muxsel. + + lcu-input-idx: + type: array + description: | + This array configures the input indices to the LCU module which help to determine the + Logic Cell number used inside an LCU instance. + + emios-channels: + type: array + description: | + This is the array containing 2 emios channel TypeG numbers used by the qdec. diff --git a/dts/bindings/sensor/st,iis2dlpc-common.yaml b/dts/bindings/sensor/st,iis2dlpc-common.yaml index 997b0b189f0..d21f4a6d195 100644 --- a/dts/bindings/sensor/st,iis2dlpc-common.yaml +++ b/dts/bindings/sensor/st,iis2dlpc-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_iis2dlpc.h and use the macros defined there. + iis2dlpc.h and use the macros defined there. Example: - #include + #include iis2dlpc: iis2dlpc@0 { ... diff --git a/dts/bindings/sensor/st,iis2iclx-common.yaml b/dts/bindings/sensor/st,iis2iclx-common.yaml index 0a312824c98..73bf2894081 100644 --- a/dts/bindings/sensor/st,iis2iclx-common.yaml +++ b/dts/bindings/sensor/st,iis2iclx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the range, odr properties in a .dts or .dtsi file you may - include st_iis2iclx.h and use the macros defined there. + include iis2iclx.h and use the macros defined there. Example: - #include + #include iis2iclx: iis2iclx@0 { ... diff --git a/dts/bindings/sensor/st,ism330dhcx-common.yaml b/dts/bindings/sensor/st,ism330dhcx-common.yaml index f00f37c1700..a12ab3446c1 100644 --- a/dts/bindings/sensor/st,ism330dhcx-common.yaml +++ b/dts/bindings/sensor/st,ism330dhcx-common.yaml @@ -3,10 +3,10 @@ description: | When setting the accel-odr and gyro-odr properties in a .dts or .dtsi file you may include - st_ism330dhcx.h and use the macros defined there. + ism330dhcx.h and use the macros defined there. Example: - #include + #include ism330dhcx: ism330dhcx@0 { ... diff --git a/dts/bindings/sensor/st,lis2de12-common.yaml b/dts/bindings/sensor/st,lis2de12-common.yaml new file mode 100644 index 00000000000..502efd15bdd --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-common.yaml @@ -0,0 +1,78 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the accel-range, accel-odr, properties in a .dts or .dtsi + file you may include lis2de12.h and use the macros defined there. + + Example: + #include + + lis2de12: lis2de12@0 { + ... + + accel-range = ; + accel-odr = ; + }; + +include: sensor-device.yaml + +properties: + int1-gpios: + type: phandle-array + description: | + INT1 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + int2-gpios: + type: phandle-array + description: | + INT2 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + 0 # LIS2DE12_DT_FS_2G (15.6 mg/LSB) + 1 # LIS2DE12_DT_FS_4G (31.2 mg/LSB) + 2 # LIS2DE12_DT_FS_8G (62.5 mg/LSB) + 3 # LIS2DE12_DT_FS_16G (187.5 mg/LSB) + + enum: [0, 1, 2, 3] + + accel-odr: + type: int + default: 0x0 + description: | + Specify the default accelerometer output data rate expressed in samples per second (Hz). + The values are taken in accordance to lis2de12_md_t enumerative in hal/st + module. Please note that this values will also enable/disable High performance mode. + Default is power-up configuration. + + 0x00 # LIS2DE12_DT_ODR_OFF + 0x01 # LIS2DE12_DT_ODR_AT_1Hz + 0x02 # LIS2DE12_DT_ODR_AT_10Hz + 0x03 # LIS2DE12_DT_ODR_AT_25Hz + 0x04 # LIS2DE12_DT_ODR_AT_50Hz + 0x05 # LIS2DE12_DT_ODR_AT_100Hz + 0x06 # LIS2DE12_DT_ODR_AT_200Hz + 0x07 # LIS2DE12_DT_ODR_AT_400Hz + 0x08 # LIS2DE12_DT_ODR_AT_1kHz620 + 0x09 # LIS2DE12_DT_ODR_AT_5kHz376 + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09] + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lis2de12-i2c.yaml b/dts/bindings/sensor/st,lis2de12-i2c.yaml new file mode 100644 index 00000000000..3e1b5b70f35 --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through I2C bus + +compatible: "st,lis2de12" + +include: ["i2c-device.yaml", "st,lis2de12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2de12-spi.yaml b/dts/bindings/sensor/st,lis2de12-spi.yaml new file mode 100644 index 00000000000..525d587279a --- /dev/null +++ b/dts/bindings/sensor/st,lis2de12-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DE12 3-axis ultra-low power accelerometer sensor + accessed through SPI bus + +compatible: "st,lis2de12" + +include: ["spi-device.yaml", "st,lis2de12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2dh-common.yaml b/dts/bindings/sensor/st,lis2dh-common.yaml index 351fa0dc97f..1988a7c1deb 100644 --- a/dts/bindings/sensor/st,lis2dh-common.yaml +++ b/dts/bindings/sensor/st,lis2dh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the int1-gpio-config/int2-gpio-config and anym-mode properties - in a .dts or .dtsi file you may include st_lis2dh.h and use the macros defined there. + in a .dts or .dtsi file you may include lis2dh.h and use the macros defined there. Example: - #include + #include lis2dh: lis2dh@0 { ... diff --git a/dts/bindings/sensor/st,lis2ds12-common.yaml b/dts/bindings/sensor/st,lis2ds12-common.yaml index 4ac18b40a55..230e57c0bb5 100644 --- a/dts/bindings/sensor/st,lis2ds12-common.yaml +++ b/dts/bindings/sensor/st,lis2ds12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr and power-mode properties in a .dts or .dtsi file you may include - st_lis2ds12.h and use the macros defined there. + lis2ds12.h and use the macros defined there. Example: - #include + #include lis2ds12: lis2ds12@0 { ... diff --git a/dts/bindings/sensor/st,lis2du12-common.yaml b/dts/bindings/sensor/st,lis2du12-common.yaml new file mode 100644 index 00000000000..0304fd7c512 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-common.yaml @@ -0,0 +1,97 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + When setting the accel-range, accel-odr, properties in a .dts or .dtsi + file you may include lis2du12.h and use the macros defined there. + + Example: + #include + + lis2du12: lis2du12@0 { + ... + + accel-range = ; + accel-odr = ; + }; + +include: sensor-device.yaml + +properties: + int1-gpios: + type: phandle-array + description: | + INT1 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + int2-gpios: + type: phandle-array + description: | + INT2 pin + + This pin defaults to active high when produced by the sensor. + The property value should ensure the flags properly describe + the signal that is presented to the driver. + + drdy-pin: + type: int + default: 1 + description: | + Select DRDY pin number (1 or 2). + + 1 = drdy is generated from INT1 + 2 = drdy is generated from INT2 + + This number represents which of the two interrupt pins + (INT1 or INT2) the drdy line is attached to. This property is not + mandatory and if not present it defaults to 1 which is the + configuration at power-up. + enum: [1, 2] + + accel-range: + type: int + default: 0 + description: | + Range in g. Default is power-up configuration. + + 0 # LIS2DU12_DT_FS_2G (0.061 mg/LSB) + 1 # LIS2DU12_DT_FS_4G (0.122 mg/LSB) + 2 # LIS2DU12_DT_FS_8G (0.244 mg/LSB) + 3 # LIS2DU12_DT_FS_16G (0.488 mg/LSB) + + enum: [0, 1, 2, 3] + + accel-odr: + type: int + default: 0x0 + description: | + Specify the default accelerometer output data rate expressed in samples per second (Hz). + The values are taken in accordance to lis2du12_md_t enumerative in hal/st + module. Please note that this values will also enable/disable High performance mode. + Default is power-up configuration. + + 0x00 # LIS2DU12_DT_ODR_OFF + 0x01 # LIS2DU12_DT_ODR_AT_1Hz6_ULP + 0x02 # LIS2DU12_DT_ODR_AT_3Hz_ULP + 0x03 # LIS2DU12_DT_ODR_AT_6Hz_ULP + 0x04 # LIS2DU12_DT_ODR_AT_6Hz + 0x05 # LIS2DU12_DT_ODR_AT_12Hz + 0x06 # LIS2DU12_DT_ODR_AT_25Hz + 0x07 # LIS2DU12_DT_ODR_AT_50Hz + 0x08 # LIS2DU12_DT_ODR_AT_100Hz + 0x09 # LIS2DU12_DT_ODR_AT_200Hz + 0x0a # LIS2DU12_DT_ODR_AT_400Hz + 0x0b # LIS2DU12_DT_ODR_AT_800Hz + 0x0e # LIS2DU12_DT_ODR_TRIG_PIN + 0x0f # LIS2DU12_DT_ODR_TRIG_SW + + enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0e, 0x0f] + + drdy-pulsed: + type: boolean + description: | + Selects the pulsed mode for data-ready interrupt when enabled, + and the latched mode when disabled. diff --git a/dts/bindings/sensor/st,lis2du12-i2c.yaml b/dts/bindings/sensor/st,lis2du12-i2c.yaml new file mode 100644 index 00000000000..ad09f2601c3 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor + accessed through I2C bus + +compatible: "st,lis2du12" + +include: ["i2c-device.yaml", "st,lis2du12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2du12-spi.yaml b/dts/bindings/sensor/st,lis2du12-spi.yaml new file mode 100644 index 00000000000..0fad5696827 --- /dev/null +++ b/dts/bindings/sensor/st,lis2du12-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LIS2DU12 3-axis ultra-low power accelerometer sensor + accessed through SPI bus + +compatible: "st,lis2du12" + +include: ["spi-device.yaml", "st,lis2du12-common.yaml"] diff --git a/dts/bindings/sensor/st,lis2dw12-common.yaml b/dts/bindings/sensor/st,lis2dw12-common.yaml index 0c9f8dcee67..c95a97da398 100644 --- a/dts/bindings/sensor/st,lis2dw12-common.yaml +++ b/dts/bindings/sensor/st,lis2dw12-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lis2dw12.h and use the macros defined there. + lis2dw12.h and use the macros defined there. Example: - #include + #include lis2dw12: lis2dw12@0 { ... diff --git a/dts/bindings/sensor/st,lis2mdl-common.yaml b/dts/bindings/sensor/st,lis2mdl-common.yaml index 4fe9e877bbc..53e0d723d93 100644 --- a/dts/bindings/sensor/st,lis2mdl-common.yaml +++ b/dts/bindings/sensor/st,lis2mdl-common.yaml @@ -16,7 +16,7 @@ properties: type: boolean description: | Set to config the sensor in single measurement mode. Leave - unset to configure the sensor in continious measurement mode. + unset to configure the sensor in continuous measurement mode. cancel-offset: type: boolean diff --git a/dts/bindings/sensor/st,lps22df-common.yaml b/dts/bindings/sensor/st,lps22df-common.yaml index cc3f11c106f..779d877f901 100644 --- a/dts/bindings/sensor/st,lps22df-common.yaml +++ b/dts/bindings/sensor/st,lps22df-common.yaml @@ -1,19 +1,20 @@ # Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH # SPDX-License-Identifier: Apache-2.0 description: | When setting the odr, lpf, avg properties in a .dts or .dtsi file - you may include st_lps22df.h and use the macros defined there. + you may include lps22df.h and use the macros defined there. Example: - #include + #include lps22df@5d { ... - odr = ; - lpf = ; - avg = ; + odr = ; + lpf = ; + avg = ; }; include: sensor-device.yaml @@ -41,15 +42,15 @@ properties: Specify the output data rate expressed in samples per second (Hz). The default is the power-on reset value. - - 0 # LPS22DF_DT_ODR_POWER_DOWN - - 1 # LPS22DF_DT_ODR_1HZ - - 2 # LPS22DF_DT_ODR_4HZ - - 3 # LPS22DF_DT_ODR_10HZ - - 4 # LPS22DF_DT_ODR_25HZ - - 5 # LPS22DF_DT_ODR_50HZ - - 6 # LPS22DF_DT_ODR_75HZ - - 7 # LPS22DF_DT_ODR_100HZ - - 8 # LPS22DF_DT_ODR_200HZ + - 0 # LPS2xDF_DT_ODR_POWER_DOWN + - 1 # LPS2xDF_DT_ODR_1HZ + - 2 # LPS2xDF_DT_ODR_4HZ + - 3 # LPS2xDF_DT_ODR_10HZ + - 4 # LPS2xDF_DT_ODR_25HZ + - 5 # LPS2xDF_DT_ODR_50HZ + - 6 # LPS2xDF_DT_ODR_75HZ + - 7 # LPS2xDF_DT_ODR_100HZ + - 8 # LPS2xDF_DT_ODR_200HZ enum: [0, 1, 2, 3, 4, 5, 6, 7, 8] @@ -60,9 +61,9 @@ properties: Specify the low pass filter value to be applied to pressure data. The default is the power-on reset value. - - 0 # LPS22DF_DT_LP_FILTER_OFF - - 1 # LPS22DF_DT_LP_FILTER_ODR_4 - - 3 # LPS22DF_DT_LP_FILTER_ODR_9 + - 0 # LPS2xDF_DT_LP_FILTER_OFF + - 1 # LPS2xDF_DT_LP_FILTER_ODR_4 + - 3 # LPS2xDF_DT_LP_FILTER_ODR_9 enum: [0, 1, 3] @@ -74,13 +75,13 @@ properties: to pressure and temperature data. The default is the power-on reset value. - - 0 # LPS22DF_DT_AVG_4_SAMPLES - - 1 # LPS22DF_DT_AVG_8_SAMPLES - - 2 # LPS22DF_DT_AVG_16_SAMPLES - - 3 # LPS22DF_DT_AVG_32_SAMPLES - - 4 # LPS22DF_DT_AVG_64_SAMPLES - - 5 # LPS22DF_DT_AVG_128_SAMPLES - - 6 # LPS22DF_DT_AVG_256_SAMPLES - - 7 # LPS22DF_DT_AVG_512_SAMPLES + - 0 # LPS2xDF_DT_AVG_4_SAMPLES + - 1 # LPS2xDF_DT_AVG_8_SAMPLES + - 2 # LPS2xDF_DT_AVG_16_SAMPLES + - 3 # LPS2xDF_DT_AVG_32_SAMPLES + - 4 # LPS2xDF_DT_AVG_64_SAMPLES + - 5 # LPS2xDF_DT_AVG_128_SAMPLES + - 6 # LPS2xDF_DT_AVG_256_SAMPLES + - 7 # LPS2xDF_DT_AVG_512_SAMPLES enum: [0, 1, 2, 3, 4, 5, 6, 7] diff --git a/dts/bindings/sensor/st,lps22hh-common.yaml b/dts/bindings/sensor/st,lps22hh-common.yaml index eeeffe25f96..a5e27c30b30 100644 --- a/dts/bindings/sensor/st,lps22hh-common.yaml +++ b/dts/bindings/sensor/st,lps22hh-common.yaml @@ -3,10 +3,10 @@ description: | When setting the odr property in a .dts or .dtsi file you may include - st_lps22hh.h and use the macros defined there. + lps22hh.h and use the macros defined there. Example: - #include + #include lps22hh: lps22hh@0 { ... diff --git a/dts/bindings/sensor/st,lps28dfw-common.yaml b/dts/bindings/sensor/st,lps28dfw-common.yaml new file mode 100644 index 00000000000..1ca646fab66 --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-common.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor. This is an + extension of st,lps22df driver binding. + + Example: + #include + + lps28dfw@5d { + ... + + odr = ; + lpf = ; + avg = ; + }; + +include: st,lps22df-common.yaml + +properties: + fs: + type: int + default: 0 + description: | + Specify the full-scale mode. + The default is the power-on reset value. + + - 0 # LPS28DFW_DT_FS_MODE_1_1260 + - 1 # LPS28DFW_DT_FS_MODE_2_4060 + enum: [0, 1] diff --git a/dts/bindings/sensor/st,lps28dfw-i2c.yaml b/dts/bindings/sensor/st,lps28dfw-i2c.yaml new file mode 100644 index 00000000000..0c47d7b27f6 --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-i2c.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor connected to + I2C bus + +compatible: "st,lps28dfw" + +include: ["i2c-device.yaml", "st,lps28dfw-common.yaml"] diff --git a/dts/bindings/sensor/st,lps28dfw-i3c.yaml b/dts/bindings/sensor/st,lps28dfw-i3c.yaml new file mode 100644 index 00000000000..8c3fdb1946d --- /dev/null +++ b/dts/bindings/sensor/st,lps28dfw-i3c.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2023 STMicroelectronics +# Copyright (c) 2023 PHYTEC Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LPS28DFW pressure and temperature sensor connected to + I3C bus + +compatible: "st,lps28dfw" + +include: ["i3c-device.yaml", "st,lps28dfw-common.yaml"] diff --git a/dts/bindings/sensor/st,lsm6dso-common.yaml b/dts/bindings/sensor/st,lsm6dso-common.yaml index 0b4b17df720..fe1c4d90ab1 100644 --- a/dts/bindings/sensor/st,lsm6dso-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-pm, accel-range, accel-odr, gyro-pm, gyro-range, - gyro-odr properties in a .dts or .dtsi file you may include st_lsm6dso.h + gyro-odr properties in a .dts or .dtsi file you may include lsm6dso.h and use the macros defined there. Example: - #include + #include lsm6dso: lsm6dso@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dso16is-common.yaml b/dts/bindings/sensor/st,lsm6dso16is-common.yaml index 49f7fd187fb..07c1f21adef 100644 --- a/dts/bindings/sensor/st,lsm6dso16is-common.yaml +++ b/dts/bindings/sensor/st,lsm6dso16is-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dso16is.h and use the macros + a .dts or .dtsi file you may include lsm6dso16is.h and use the macros defined there. Example: - #include + #include lsm6dso16is: lsm6dso16is@0 { ... diff --git a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml index 99167a6506d..84c0dce96a7 100644 --- a/dts/bindings/sensor/st,lsm6dsv16x-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsv16x-common.yaml @@ -3,11 +3,11 @@ description: | When setting the accel-range, accel-odr, gyro-range, gyro-odr properties in - a .dts or .dtsi file you may include st_lsm6dsv16x.h and use the macros + a .dts or .dtsi file you may include lsm6dsv16x.h and use the macros defined there. Example: - #include + #include lsm6dsv16x: lsm6dsv16x@0 { ... @@ -135,9 +135,9 @@ properties: description: | Specify the default gyro output data rate expressed in samples per second (Hz). The values are taken in accordance to lsm6dsv16x_data_rate_t enumerative in hal/st - module. Please note that this values will not change the operating mode, which will remain + module. Please note that these values will not change the operating mode, which will remain High Performance (device default). Moreover, the values here which will be selected in the - DT are the only way to specifiy the odr accuracy even at runtime with + DT are the only way to specify the odr accuracy even at runtime with SENSOR_ATTR_SAMPLING_FREQUENCY. Default is power-up configuration. diff --git a/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml b/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml new file mode 100644 index 00000000000..88883e14706 --- /dev/null +++ b/dts/bindings/sensor/tdk,ntcg163jf103ft1.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Urban Sky LLC. +# SPDX-License-Identifier: Apache-2.0 + +description: TDK NTCG163JF103FT1 thermistor + +compatible: "tdk,ntcg163jf103ft1" + +include: ntc-thermistor.yaml diff --git a/dts/bindings/sensor/ti,bq274xx.yaml b/dts/bindings/sensor/ti,bq274xx.yaml index f50aba228c1..e92f0d09208 100644 --- a/dts/bindings/sensor/ti,bq274xx.yaml +++ b/dts/bindings/sensor/ti,bq274xx.yaml @@ -24,12 +24,16 @@ properties: taper-current: type: int required: true - description: Battery Taper current in mAh + description: | + Current in mA slightly higher than the taper current threshold at which + point the charger cuts off charging. terminate-voltage: type: int required: true - description: Battery Terminate Voltage in mV + description: | + Minimum operating voltage of your system. This is the target where the + gauge typically reports 0% capacity. In mV. chemistry-id: type: int diff --git a/dts/bindings/sensor/ti,fdc2x1x.yaml b/dts/bindings/sensor/ti,fdc2x1x.yaml index 4d8d9c6f245..b79b2724889 100644 --- a/dts/bindings/sensor/ti,fdc2x1x.yaml +++ b/dts/bindings/sensor/ti,fdc2x1x.yaml @@ -44,7 +44,7 @@ properties: description: | Reference frequency of the used clock source in KHz. The internal clock oscillates at around 43360 KHz (43.36 MHz) - at 20 degrees Celcius. + at 20 degrees Celsius. Recommended external clock source frequency is 40000 KHz (40 MHz). rr-sequence: diff --git a/dts/bindings/sensor/ti,tmag5170.yaml b/dts/bindings/sensor/ti,tmag5170.yaml index c68e704c900..d4f5d3abffc 100644 --- a/dts/bindings/sensor/ti,tmag5170.yaml +++ b/dts/bindings/sensor/ti,tmag5170.yaml @@ -183,7 +183,7 @@ properties: type: int default: 1 description: | - The time in miliseconds the sensor will be in sleep during conversions. + The time in milliseconds the sensor will be in sleep during conversions. For this property to take effect sensor must be in `duty-cycled` mode. Note that to calculate total time between conversions, the conversion time itself must be taken into account. The conversion time is dependent diff --git a/dts/bindings/sensor/vishay,vcnl36825t.yaml b/dts/bindings/sensor/vishay,vcnl36825t.yaml new file mode 100644 index 00000000000..b1188b3d77e --- /dev/null +++ b/dts/bindings/sensor/vishay,vcnl36825t.yaml @@ -0,0 +1,90 @@ +# Copyright (c) 2024 Juliane Schulze, deveritec GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: | + VCNL36825T proximity and ambient light sensor. See datasheet at + https://www.vishay.com/docs/84274/vcnl36825t.pdf + +compatible: "vishay,vcnl36825t" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + operation-mode: + type: string + default: "auto" + enum: ["auto", "force"] + description: | + Mode of operation. + - "auto": the sensor performs sampling continuously, + - "force": the sampling is performed on every fetch command. + + Defaults to sensor reset value. + + measurement-period: + type: int + default: 40 + enum: [10, 20, 40, 80, 160, 320] + description: | + Measurement period of the sensors in ms. + Higher values yield lower power consumption. + Note: + - [10, 80] ms only if low power mode is inactive + - [80, 320] ms only in low power mode + + Defaults to 40 ms which is supported in both normal and low-power mode. + + proximity-it: + type: string + default: "1" + enum: ["1", "1.5", "2", "2.5", "3", "3.5", "4", "8"] + description: | + Proximity integration time in T. + Defaults to sensor reset value. + + proximity-itb: + type: int + default: 25 + enum: [25, 50] + description: | + Duration of the proximity integration time T in us. + Defaults to sensor reset value. + + multi-pulse: + type: int + default: 1 + enum: [1, 2, 4, 8] + description: | + Number of pulses per single measurement. + Higher values increase accuracy and power consumption. + Defaults to sensor reset value. + + laser-current: + type: int + default: 10 + enum: [10, 12, 14, 16, 18, 20] + description: | + Current used by the laser during measurement periods. + Defaults to minimum allowed value. + + low-power: + type: boolean + description: | + Activate low power mode. + This allows to increase the measurement period up to 320 ms. + + high-gain: + type: boolean + description: | + Activate the high gain mode. + + sunlight-cancellation: + type: boolean + description: | + Activate sunlight cancellation. + + high-dynamic-output: + type: boolean + description: | + Activate 16bit high dynamic output mode. + Cannot be used with threshold interrupt. diff --git a/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml b/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml new file mode 100644 index 00000000000..4d4e4415677 --- /dev/null +++ b/dts/bindings/sensor/zephyr,sensing-hinge-angle.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# + +description: Sensing subsystem hinge angle sensor bindings. + +compatible: "zephyr,sensing-hinge-angle" + +# Common sensor subsystem sensor properties. +include: ["zephyr,sensing-sensor.yaml"] diff --git a/dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-phy-3d-sensor.yaml similarity index 100% rename from dts/bindings/sensor/zephyr,senss-phy-3d-sensor.yaml rename to dts/bindings/sensor/zephyr,sensing-phy-3d-sensor.yaml diff --git a/dts/bindings/sensor/zephyr,sensing-sensor.yaml b/dts/bindings/sensor/zephyr,sensing-sensor.yaml index 5bcaa39f257..e0b8aae492d 100644 --- a/dts/bindings/sensor/zephyr,sensing-sensor.yaml +++ b/dts/bindings/sensor/zephyr,sensing-sensor.yaml @@ -7,8 +7,8 @@ description: Sensing subsystem sensor common properties bindings. include: sensor-device.yaml properties: - sensor-type: - type: int + sensor-types: + type: array required: true description: sensor type id (follow HID spec definition) @@ -23,3 +23,11 @@ properties: reporters: type: phandles description: sensor reporters + + reporters-index: + type: array + description: the index in sensor-types of reporter if the reporter support multiple sensor-types + + stream-mode: + type: boolean + description: sensor works on stream mode or poll mode diff --git a/dts/bindings/serial/atmel,sam0-uart.yaml b/dts/bindings/serial/atmel,sam0-uart.yaml index 30588f35dfd..f817137d7b6 100644 --- a/dts/bindings/serial/atmel,sam0-uart.yaml +++ b/dts/bindings/serial/atmel,sam0-uart.yaml @@ -22,12 +22,82 @@ properties: rxpo: type: int required: true - description: Receive Data Pinout + description: | + Receive Data Pinout. An enumeration with the following values: + + +-------+---------------+ + | Value | RX Pin | + +-------+---------------+ + | 0 | SERCOM_PAD[0] | + +-------+---------------+ + | 1 | SERCOM_PAD[1] | + +-------+---------------+ + | 2 | SERCOM_PAD[2] | + +-------+---------------+ + | 3 | SERCOM_PAD[3] | + +-------+---------------+ + txpo: type: int required: true - description: Transmit Data Pinout + description: | + Transmit Data Pinout. An enumeration with values that depend on the + hardware being used. This controls both the transmit pins and if + hardware flow control is used. + + SAMD20: + + +-------+---------------+ + | Value | TX Pin | + +-------+---------------+ + | 0 | SERCOM_PAD[0] | + +-------+---------------+ + | 1 | SERCOM_PAD[2] | + +-------+---------------+ + + SAMD21/DA21/R21: + + +-------+---------------+---------------+---------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | SERCOM_PAD[2] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | Reserved | + +-------+-----------------------------------------------+ + + SAML2x/C2x: + + +-------+----------------+---------------+--------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | SERCOM_PAD[2] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | SERCOM_PAD[0] | SERCOM_PAD[2] | N/A | + +-------+---------------+---------------+---------------+ + + SAMD5/E5: + + +-------+---------------+---------------+---------------+ + | Value | TX Pin | RTS | CTS | + +-------+---------------+---------------+---------------+ + | 0 | SERCOM_PAD[0] | N/A | N/A | + +-------+---------------+---------------+---------------+ + | 1 | Reserved | + +-------+---------------+---------------+---------------+ + | 2 | SERCOM_PAD[0] | SERCOM_PAD[2] | SERCOM_PAD[3] | + +-------+---------------+---------------+---------------+ + | 3 | SERCOM_PAD[0] | SERCOM_PAD[2] | N/A | + +-------+---------------+---------------+---------------+ + collision-detection: type: boolean diff --git a/dts/bindings/serial/infineon,xmc4xxx-uart.yaml b/dts/bindings/serial/infineon,xmc4xxx-uart.yaml index c93ee940825..788ea54c956 100644 --- a/dts/bindings/serial/infineon,xmc4xxx-uart.yaml +++ b/dts/bindings/serial/infineon,xmc4xxx-uart.yaml @@ -100,7 +100,7 @@ properties: dma1 can connect to lines [8, 11]. 2. For a given interrupt, calculate the service request (SR) number. Note the following simple mapping: in USIC0 interrupt 84->SR0, interrupt 85->SR1, ... etc. - In USIC1, intterupt 90->SR0, 91->SR1, etc. + In USIC1, interrupt 90->SR0, 91->SR1, etc. 3. Select request_source from Table "DMA Request Source Selection" in XMC4XXX reference manual. diff --git a/dts/bindings/serial/st,stm32-uart-base.yaml b/dts/bindings/serial/st,stm32-uart-base.yaml index ed8a6e1e3a9..3c20564bdda 100644 --- a/dts/bindings/serial/st,stm32-uart-base.yaml +++ b/dts/bindings/serial/st,stm32-uart-base.yaml @@ -86,3 +86,13 @@ properties: description: | Invert the binary logic of the de pin. When enabled, physical logic levels are inverted and we use 1=Low, 0=High instead of 1=High, 0=Low. + + fifo-enable: + type: boolean + description: | + Enables transmit and receive FIFO using default FIFO configuration (typically threshold is + set to 1/8). + In TX, FIFO allows to work in burst mode, easing scheduling of loaded applications. It also + allows more reliable communication with UART devices sensitive to variation of inter-frames + delays. + In RX, FIFO reduces overrun occurrences. diff --git a/dts/bindings/serial/xen,hvc-consoleio.yaml b/dts/bindings/serial/xen,hvc-consoleio.yaml new file mode 100644 index 00000000000..720dc4e7377 --- /dev/null +++ b/dts/bindings/serial/xen,hvc-consoleio.yaml @@ -0,0 +1,5 @@ +description: Xen Dom0/Dom0less Platform HVC ConsoleIO + +compatible: "xen,hvc-consoleio" + +include: uart-controller.yaml diff --git a/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml new file mode 100644 index 00000000000..dc197fb6fd8 --- /dev/null +++ b/dts/bindings/shi/nuvoton,npcx-shi-enhanced.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX Serial Host Interface (SHI) node + +compatible: "nuvoton,npcx-shi-enhanced" + +include: [pinctrl-device.yaml, shi-device.yaml, "nuvoton,npcx-shi.yaml"] diff --git a/dts/bindings/smbus/st,stm32-smbus.yaml b/dts/bindings/smbus/st,stm32-smbus.yaml new file mode 100644 index 00000000000..2c93189c178 --- /dev/null +++ b/dts/bindings/smbus/st,stm32-smbus.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2023 SILA Embedded Solutions GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: STM32 SMBus controller + +compatible: "st,stm32-smbus" + +include: [smbus-controller.yaml, pinctrl-device.yaml] + +properties: + i2c: + type: phandle + required: true + description: I2C device which maps to the same address diff --git a/dts/bindings/spi/gaisler,spimctrl.yaml b/dts/bindings/spi/gaisler,spimctrl.yaml new file mode 100644 index 00000000000..51dfb4960c1 --- /dev/null +++ b/dts/bindings/spi/gaisler,spimctrl.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Frontgrade Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +description: GRLIB SPIMCTRL + +compatible: "gaisler,spimctrl" + +include: spi-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/spi/infineon,xmc4xxx-spi.yaml b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml index b3475924e14..a4f30d99400 100644 --- a/dts/bindings/spi/infineon,xmc4xxx-spi.yaml +++ b/dts/bindings/spi/infineon,xmc4xxx-spi.yaml @@ -55,7 +55,7 @@ properties: dma1 can connect to lines [8, 11]. 2. For a given interrupt, calculate the service request (SR) number. Note the following simple mapping: in USIC0 interrupt 84->SR0, interrupt 85->SR1, ... etc. - In USIC1, intterupt 90->SR0, 91->SR1, etc. + In USIC1, interrupt 90->SR0, 91->SR1, etc. 3. Select request_source from Table "DMA Request Source Selection" in XMC4XXX reference manual. diff --git a/dts/bindings/spi/microchip,mpfs-spi.yaml b/dts/bindings/spi/microchip,mpfs-spi.yaml new file mode 100644 index 00000000000..7ec6536ca83 --- /dev/null +++ b/dts/bindings/spi/microchip,mpfs-spi.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2022 Microchip Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: Microchip Polarfire SOC SPI IP node + +compatible: "microchip,mpfs-spi" + +include: spi-controller.yaml + +properties: + reg: + required: true + + interrupts: + required: true diff --git a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml index 7654612229a..418d874bb37 100644 --- a/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml +++ b/dts/bindings/spi/microchip,xec-qmspi-ldma.yaml @@ -55,14 +55,14 @@ properties: type: int description: | Delay in QMSPI main clocks from CS# assertion to first clock edge. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. dckcsoff: type: int description: | Delay in QMSPI main clocks from last clock edge to CS# de-assertion. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. dldh: @@ -76,7 +76,7 @@ properties: type: int description: | Delay in QMSPI main clocks from CS# de-assertion to CS# assertion. - If not present use hardware default value. Refer to chip documention + If not present use hardware default value. Refer to chip documentation for QMSPI input clock frequency. cs1-freq: diff --git a/dts/bindings/spi/nuvoton,npcx-spip.yaml b/dts/bindings/spi/nuvoton,npcx-spip.yaml new file mode 100644 index 00000000000..da771b4ba82 --- /dev/null +++ b/dts/bindings/spi/nuvoton,npcx-spip.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX SPI controller. + +compatible: "nuvoton,npcx-spip" + +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true diff --git a/dts/bindings/spi/snps,designware-spi.yaml b/dts/bindings/spi/snps,designware-spi.yaml index 7e6673cd3c0..01073f8d003 100644 --- a/dts/bindings/spi/snps,designware-spi.yaml +++ b/dts/bindings/spi/snps,designware-spi.yaml @@ -1,4 +1,5 @@ # Copyright (c) 2018 Synopsys, Inc. All rights reserved. +# Copyright (c) 2023 Meta Platforms All rights reserved. # SPDX-License-Identifier: Apache-2.0 description: Synopsys DesignWare SPI node @@ -14,11 +15,11 @@ properties: interrupts: required: true - aux_reg: + aux-reg: + type: boolean description: | This value is used for auxiliary register access. For other platform, this value should be default 0. - type: boolean fifo-depth: type: int @@ -26,3 +27,20 @@ properties: RX/TX FIFO depth. Corresponds to the SSI_TX_FIFO_DEPTH and SSI_RX_FIFO_DEPTH of the DesignWare Synchronous Serial Interface. Depth ranges from 2-256. + + serial-target: + type: boolean + description: | + True if it is a Serial Target. False if it is a Serial + Master. Corresponds to SSI_IS_MASTER of the Designware + Synchronous Serial Interface. + + max-xfer-size: + type: int + description: | + Maximum transfer size. Corresponds to SPI_MAX_XFER_SIZE + of the DesignWare Synchronous Serial Interface. Only + values of 16 and 32 are supported. + enum: + - 16 + - 32 diff --git a/dts/bindings/spi/st,stm32h7-spi.yaml b/dts/bindings/spi/st,stm32h7-spi.yaml index 3843e420f71..69f1a8c52ae 100644 --- a/dts/bindings/spi/st,stm32h7-spi.yaml +++ b/dts/bindings/spi/st,stm32h7-spi.yaml @@ -12,3 +12,22 @@ description: | compatible: "st,stm32h7-spi" include: st,stm32-spi-common.yaml + +properties: + midi-clock: + type: int + default: 0 + description: | + (Master Inter-Data Idleness) minimum clock inserted + between two consecutive data frames. + + mssi-clock: + type: int + default: 0 + description: | + (Master SS Idleness) minimum clock inserted between + start and first data transaction. + + fifo-enable: + type: boolean + description: Enable the SPI FIFO usage for performance improvement. diff --git a/dts/bindings/test/vnd,cpu-intc.yaml b/dts/bindings/test/vnd,cpu-intc.yaml new file mode 100644 index 00000000000..75f3c02306c --- /dev/null +++ b/dts/bindings/test/vnd,cpu-intc.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +description: Test CPU Interrupt Controller + +compatible: "vnd,cpu-intc" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + "#interrupt-cells": + const: 1 + +interrupt-cells: + - irq diff --git a/dts/bindings/test/vnd,gpio-intc-device.yaml b/dts/bindings/test/vnd,gpio-intc-device.yaml new file mode 100644 index 00000000000..b506062792c --- /dev/null +++ b/dts/bindings/test/vnd,gpio-intc-device.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Test GPIO with INTC node + +compatible: "vnd,gpio-intc-device" + +include: + - gpio-controller.yaml + - interrupt-controller.yaml + - base.yaml + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + + "#interrupt-cells": + const: 2 + +gpio-cells: + - pin + - flags + +interrupt-cells: + - pin + - flags diff --git a/dts/bindings/test/vnd,interrupt-holder-extended.yaml b/dts/bindings/test/vnd,interrupt-holder-extended.yaml new file mode 100644 index 00000000000..795b15d9313 --- /dev/null +++ b/dts/bindings/test/vnd,interrupt-holder-extended.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Bjarki Arge Andreasen +# SPDX-License-Identifier: Apache-2.0 + +description: Test Interrupt Controller with extended interrupts + +compatible: "vnd,interrupt-holder-extended" + +include: [base.yaml] + +properties: + interrupts-extended: + required: true + + interrupt-names: + required: true diff --git a/dts/bindings/test/vnd,non-deprecated-label.yaml b/dts/bindings/test/vnd,non-deprecated-label.yaml new file mode 100644 index 00000000000..760b683b470 --- /dev/null +++ b/dts/bindings/test/vnd,non-deprecated-label.yaml @@ -0,0 +1,14 @@ +# Copyright 2023 Ampere Computing +# SPDX-License-Identifier: Apache-2.0 + +description: | + This can be used when we need a label property in tests without risk + of generating deprecation warnings, which are errors in some + configurations. + +compatible: vnd,non-deprecated-label + +properties: + label: + type: string + required: true diff --git a/dts/bindings/timer/nordic,nrf-grtc.yaml b/dts/bindings/timer/nordic,nrf-grtc.yaml new file mode 100644 index 00000000000..e78e57df97e --- /dev/null +++ b/dts/bindings/timer/nordic,nrf-grtc.yaml @@ -0,0 +1,25 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +description: Nordic GRTC (Global RTC) + +compatible: "nordic,nrf-grtc" + +include: + - "base.yaml" + - "nordic,split-channels.yaml" + +properties: + reg: + required: true + + interrupts: + required: true + + cc-num: + description: Number of capture/compare channels + type: int + required: true diff --git a/dts/bindings/timer/nuclei,systimer.yaml b/dts/bindings/timer/nuclei,systimer.yaml index cee9e2bc9e7..5c8f319a7c5 100644 --- a/dts/bindings/timer/nuclei,systimer.yaml +++ b/dts/bindings/timer/nuclei,systimer.yaml @@ -44,5 +44,5 @@ properties: Setting clk-divider to 2 specifies the system timer uses the clock that CPU clock frequency divided by (2^2=)4, or 27MHz. - Devision ratio constants can be found in the + Division ratio constants can be found in the dt-bindings/timer/nuclei-systimer.h header file. diff --git a/dts/bindings/timer/nxp,imx-gpt.yaml b/dts/bindings/timer/nxp,imx-gpt.yaml index 31396093097..4d1aac49c14 100644 --- a/dts/bindings/timer/nxp,imx-gpt.yaml +++ b/dts/bindings/timer/nxp,imx-gpt.yaml @@ -17,4 +17,4 @@ properties: gptfreq: type: int required: true - description: gpt frequences + description: gpt frequencies diff --git a/dts/bindings/timer/st,stm32-lptim.yaml b/dts/bindings/timer/st,stm32-lptim.yaml index a13deb1f794..5792e38ef8d 100644 --- a/dts/bindings/timer/st,stm32-lptim.yaml +++ b/dts/bindings/timer/st,stm32-lptim.yaml @@ -1,7 +1,13 @@ # Copyright (c) 2020, STMicroelectronics # SPDX-License-Identifier: Apache-2.0 -description: STM32 lptim +description: | + STM32 lptim : low power timer + The lptim node to be used for counting ticks during lowpower modes + must be named stm32_lp_tick_source in the DTS, as follows: + stm32_lp_tick_source: &lptim1 { + status = "okay"; + } compatible: "st,stm32-lptim" @@ -39,11 +45,3 @@ properties: - 32 - 64 - 128 - - st,static-prescaler: - type: boolean - description: | - Clock x2 factor at the input of the LPTIM, - depending on the serie. - For example, stm32U5x have a x2-factor for LPTIM1,3,4. - To be adapted once the value is selectable. diff --git a/dts/bindings/usb-c/usb-c-connector.yaml b/dts/bindings/usb-c/usb-c-connector.yaml index c5e69653a33..334f2f06e18 100644 --- a/dts/bindings/usb-c/usb-c-connector.yaml +++ b/dts/bindings/usb-c/usb-c-connector.yaml @@ -54,6 +54,11 @@ properties: description: | VBUS measurement and control for this port. + ppc: + type: phandle + description: | + Power path controller for this port + power-role: type: string required: true @@ -110,7 +115,7 @@ properties: type: array description: | An array of source Power Data Objects (PDOs). - Use tht following macros to define the PDOs, defined in + Use the following macros to define the PDOs, defined in dt-bindings/usb-c/pd.h. * PDO_FIXED * PDO_BATT @@ -122,7 +127,7 @@ properties: type: array description: | An array of sink Power Data Objects (PDOs). - Use tht following macros to define the PDOs, defined in + Use the following macros to define the PDOs, defined in dt-bindings/usb-c/pd.h. * PDO_FIXED * PDO_BATT @@ -134,7 +139,7 @@ properties: type: array description: | An array of sink Vendor Defined Objects (VDOs). - Use tht following macros to define the VDOs, defined in + Use the following macros to define the VDOs, defined in dt-bindings/usb-c/pd.h. * VDO_IDH * VDO_CERT @@ -150,7 +155,7 @@ properties: type: array description: | An array of sink Vendor Defined Objects (VDOs). - Use tht following macros to define the VDOs, defined in + Use the following macros to define the VDOs, defined in dt-bindings/usb-c/pd.h. * VDO_IDH * VDO_CERT diff --git a/dts/bindings/usb/nuvoton,numaker-usbd.yaml b/dts/bindings/usb/nuvoton,numaker-usbd.yaml new file mode 100644 index 00000000000..3e688212213 --- /dev/null +++ b/dts/bindings/usb/nuvoton,numaker-usbd.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2022 Nuvoton Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton NuMaker USB 1.1 device controller + +compatible: "nuvoton,numaker-usbd" + +include: [usb-ep.yaml, reset-device.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + resets: + required: true + + clocks: + required: true + + dma-buffer-size: + type: int + required: true + description: | + Size of DMA buffer in bytes + + disallow-iso-in-out-same-number: + type: boolean + description: | + Some soc series don't allow Isochronous IN/OUT endpoints to be assigned the same numbers, + for example, 0x82 (for Isochronous IN) and 0x02 (for Isochronous OUT) are disallowed. diff --git a/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml b/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml new file mode 100644 index 00000000000..6e661d1c73d --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-audio-streaming.yaml @@ -0,0 +1,80 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Audio Streaming interface + +compatible: "zephyr,uac2-audio-streaming" + +properties: + linked-terminal: + type: phandle + required: true + description: | + Input or Output Terminal to which this interface is connected. + + active-alternate-setting-control: + type: string + description: Active Alternate Setting Control capabilities + enum: + - "read-only" + + valid-alternate-settings-control: + type: string + description: Valid Alternate Settings Control capabilities + enum: + - "read-only" + + external-interface: + type: boolean + description: | + Enable if audio stream is not transmitted over USB (Type IV Audio Stream). + + implicit-feedback: + type: boolean + description: | + Enable implicit feedback on asynchronous endpoint. For IN endpoints this + sets endpoint behaviour type to implicit feedback data endpoint. For OUT + endpoints setting this property removes explicit feedback endpoint. + + pitch-control: + type: string + description: Pitch Control capabilities + enum: + - "read-only" + - "host-programmable" + + data-overrun-control: + type: string + description: Data Overrun capabilities + enum: + - "read-only" + + data-underrun-control: + type: string + description: Data Underrun capabilities + enum: + - "read-only" + + lock-delay: + type: int + description: | + Time it takes this endpoint to reliably lock its internal clock recovery + circuitry. Units depend on the lock-delay-units field. Relevant only if + linked-terminal's clock is sof-synchronized. + + lock-delay-units: + type: string + description: Units for lock-delay parameter. + enum: + - "milliseconds" + - "decoded-pcm-samples" + + subslot-size: + type: int + description: | + Number of bytes occupied by one audio subslot. Can be 1, 2, 3 or 4. + + bit-resolution: + type: int + description: | + Number of effectively used bits in audio subslot. diff --git a/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml b/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml new file mode 100644 index 00000000000..e71b2990a29 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-channel-cluster.yaml @@ -0,0 +1,117 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Audio Channel Cluster + +properties: + front-left: + type: boolean + description: Front Left channel present in the cluster + + front-right: + type: boolean + description: Front Right channel present in the cluster + + front-center: + type: boolean + description: Front Center channel present in the cluster + + low-frequency-effects: + type: boolean + description: Low Frequency Effects channel present in the cluster + + back-left: + type: boolean + description: Back Left channel present in the cluster + + back-right: + type: boolean + description: Back Right channel present in the cluster + + front-left-of-center: + type: boolean + description: Front Left of Center channel present in the cluster + + front-right-of-center: + type: boolean + description: Front Right of Center channel present in the cluster + + back-center: + type: boolean + description: Back Center channel present in the cluster + + side-left: + type: boolean + description: Side Left channel present in the cluster + + side-right: + type: boolean + description: Side Right channel present in the cluster + + top-center: + type: boolean + description: Top Center channel present in the cluster + + top-front-left: + type: boolean + description: Top Front Left channel present in the cluster + + top-front-center: + type: boolean + description: Top Front Center channel present in the cluster + + top-front-right: + type: boolean + description: Top Front Right channel present in the cluster + + top-back-left: + type: boolean + description: Top Back Left channel present in the cluster + + top-back-center: + type: boolean + description: Top Back Center channel present in the cluster + + top-back-right: + type: boolean + description: Top Back Right channel present in the cluster + + top-front-left-of-center: + type: boolean + description: Top Front Left of Center channel present in the cluster + + top-front-right-of-center: + type: boolean + description: Top Front Right of Center channel present in the cluster + + left-low-frequency-effects: + type: boolean + description: Left Low Frequency Effects channel present in the cluster + + right-low-frequency-effects: + type: boolean + description: Right Low Frequency Effects channel present in the cluster + + top-side-left: + type: boolean + description: Top Side Left channel present in the cluster + + top-side-right: + type: boolean + description: Top Side Right channel present in the cluster + + bottom-center: + type: boolean + description: Bottom Center channel present in the cluster + + back-left-of-center: + type: boolean + description: Back Left of Center channel present in the cluster + + back-right-of-center: + type: boolean + description: Back Right of Center channel present in the cluster + + raw-data: + type: boolean + description: Raw Data, mutually exclusive with all other spatial locations diff --git a/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml b/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml new file mode 100644 index 00000000000..3a2412b1427 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-clock-source.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Clock Source entity + +compatible: "zephyr,uac2-clock-source" + +properties: + clock-type: + type: string + required: true + description: | + Clock Type indicating whether the Clock Source represents an external + clock or an internal clock with either fixed frequency, variable + frequency, or programmable frequency. + enum: + - "external" + - "internal-fixed" + - "internal-variable" + - "internal-programmable" + + sof-synchronized: + type: boolean + description: | + True if clock is synchronized to USB Start of Frame. False if clock is + free running. External clock must be free running. + + frequency-control: + type: string + description: Clock Frequency Control capabilities + enum: + - "read-only" + - "host-programmable" + + validity-control: + type: string + description: Clock Validity Control capabilities + enum: + - "read-only" + + assoc-terminal: + type: phandle + description: | + Input or Output Terminal associated with this Clock Source. Set if clock + is derived from USB OUT data endpoint (point the handle to respective + Input Terminal) or from input signal on S/PDIF connector. + + sampling-frequencies: + type: array + required: true + description: | + Sampling Frequencies, in Hz, this Clock Source Entity can generate. diff --git a/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml b/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml new file mode 100644 index 00000000000..0c638566c61 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-input-terminal.yaml @@ -0,0 +1,62 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Input Terminal entity + +compatible: "zephyr,uac2-input-terminal" + +include: zephyr,uac2-channel-cluster.yaml + +properties: + terminal-type: + type: int + required: true + description: | + Terminal Type constant specified in USB Audio Terminal Types + + assoc-terminal: + type: phandle + description: | + Associated terminal for bi-directional terminal types. + + clock-source: + type: phandle + required: true + description: | + Connected clock entity + + copy-protect-control: + type: string + description: Copy Protect Control capabilities + enum: + - "read-only" + + connector-control: + type: string + description: Connector Control capabilities + enum: + - "read-only" + + overload-control: + type: string + description: Overload Control capabilities + enum: + - "read-only" + + cluster-control: + type: string + description: Cluster Control capabilities + enum: + - "read-only" + + underflow-control: + type: string + description: Underflow Control capabilities + enum: + - "read-only" + + overflow-control: + type: string + description: Overflow Control capabilities + enum: + - "read-only" diff --git a/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml b/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml new file mode 100644 index 00000000000..c1ce1d842f3 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2-output-terminal.yaml @@ -0,0 +1,60 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 Output Terminal entity + +compatible: "zephyr,uac2-output-terminal" + +properties: + terminal-type: + type: int + required: true + description: | + Terminal Type constant specified in USB Audio Terminal Types + + assoc-terminal: + type: phandle + description: | + Associated terminal, e.g. for bidirectional terminal types. + + data-source: + type: phandle + required: true + description: | + Unit or Terminal this terminal receives data from + + clock-source: + type: phandle + required: true + description: | + Connected clock entity + + copy-protect-control: + type: string + description: Copy Protect Control capabilities + enum: + - "host-programmable" + + connector-control: + type: string + description: Connector Control capabilities + enum: + - "read-only" + + overload-control: + type: string + description: Overload Control capabilities + enum: + - "read-only" + + underflow-control: + type: string + description: Underflow Control capabilities + enum: + - "read-only" + + overflow-control: + type: string + description: Overflow Control capabilities + enum: + - "read-only" diff --git a/dts/bindings/usb/uac2/zephyr,uac2.yaml b/dts/bindings/usb/uac2/zephyr,uac2.yaml new file mode 100644 index 00000000000..a4283f219a0 --- /dev/null +++ b/dts/bindings/usb/uac2/zephyr,uac2.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: USB Audio Class 2 instance + +compatible: "zephyr,uac2" + +# Child nodes of "zephyr,uac2" compatibles are supposed to be Audio Control +# entities, i.e. clock sources, input terminals, output terminals, etc. +# After all Audio Control entities, the Audio Streaming interface compatibles +# should follow (as child nodes of "zephyr,uac2"). +# +# The only reason for putting Audio Streaming interfaces at the end is because +# Audio Control entities derive their unique ID from child index (+ 1). For most +# cases the order shouldn't really matter, but if there happen to be maximum +# possible number of entities (255) then the Audio Streaming would inadvertently +# "consume" one of the available IDs. + +properties: + audio-function: + type: int + required: true + description: | + Constant, indicating the primary use of this audio function, as intended + by the manufacturer. Use Audio Function category codes define from + dt-bindings/usb/audio.h. + + interrupt-endpoint: + type: boolean + description: | + Enable to support an optional interrupt endpoint to inform the Host about + dynamic changes that occur on the different addressable entities. + + latency-control: + type: string + description: Latency Control capabilities + enum: + - "read-only" + - "host-programmable" diff --git a/dts/bindings/usb/usb-audio-hp.yaml b/dts/bindings/usb/usb-audio-hp.yaml index 91968126c1e..a7b1f857d5f 100644 --- a/dts/bindings/usb/usb-audio-hp.yaml +++ b/dts/bindings/usb/usb-audio-hp.yaml @@ -18,6 +18,12 @@ properties: - 16 - 24 - 32 + sample-rate-hz: + type: int + default: 48000 + polling-interval: + type: int + default: 1 # channel configuration options channel-l: type: boolean diff --git a/dts/bindings/usb/usb-audio-hs.yaml b/dts/bindings/usb/usb-audio-hs.yaml index ce0245cc136..f440186f5fe 100644 --- a/dts/bindings/usb/usb-audio-hs.yaml +++ b/dts/bindings/usb/usb-audio-hs.yaml @@ -23,13 +23,19 @@ properties: type: string description: | Type of endpoint synchronization for IN devices. - Default value is Sychronous. + Default value is Synchronous. Adaptive is not supported. enum: - "No Synchronization" - "Asynchronous" - "Adaptive" - "Synchronous" + mic-sample-rate-hz: + type: int + default: 48000 + mic-polling-interval: + type: int + default: 1 hp-resolution: type: int default: 16 @@ -38,6 +44,12 @@ properties: - 16 - 24 - 32 + hp-sample-rate-hz: + type: int + default: 48000 + hp-polling-interval: + type: int + default: 1 # microphone channel configuration options mic-channel-l: type: boolean diff --git a/dts/bindings/usb/usb-audio-mic.yaml b/dts/bindings/usb/usb-audio-mic.yaml index 032021fd363..9a12b78b894 100644 --- a/dts/bindings/usb/usb-audio-mic.yaml +++ b/dts/bindings/usb/usb-audio-mic.yaml @@ -23,13 +23,19 @@ properties: type: string description: | Type of endpoint synchronization for IN devices. - Default value is Sychronous. + Default value is Synchronous. Adaptive is not supported. enum: - "No Synchronization" - "Asynchronous" - "Adaptive" - "Synchronous" + sample-rate-hz: + type: int + default: 48000 + polling-interval: + type: int + default: 1 # channel configuration options channel-l: type: boolean diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index 29a7b78aa70..268e72ea8c7 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -208,6 +208,7 @@ excito Excito ezchip EZchip Semiconductor facebook Facebook (deprecated, use meta) fairphone Fairphone B.V. +fanke FANKE Technology Co., Ltd. faraday Faraday Technology Corporation fastrax Fastrax Oy fcs Fairchild Semiconductor @@ -223,6 +224,7 @@ fsl Freescale Semiconductor ftdi Future Technology Devices International Ltd. fujitsu Fujitsu Ltd. gaisler Gaisler +galaxycore Galaxycore, Inc. gardena GARDENA GmbH gateworks Gateworks Corporation gcw Game Consoles Worldwide @@ -512,6 +514,7 @@ rda Unisoc Communications, Inc. realtek Realtek Semiconductor Corp. remarkable reMarkable AS renesas Renesas Electronics Corporation +renode Antmicro's open source simulation and virtual development framework rex iMX6 Rex Project rervision Shenzhen Rervision Technology Co., Ltd. revotics Revolution Robotics, Inc. (Revotics) @@ -606,6 +609,7 @@ tbs-biometrics Touchless Biometric Systems AG tcg Trusted Computing Group tcl Toby Churchill Ltd. tcs Shenzhen City Tang Cheng Technology Co., Ltd. +tdk TDK Corporation. tdo Shangai Top Display Optoelectronics Co., Ltd technexion TechNexion technologic Technologic Systems diff --git a/dts/bindings/w1/zephyr,w1-gpio.yaml b/dts/bindings/w1/zephyr,w1-gpio.yaml new file mode 100644 index 00000000000..46f4e684e01 --- /dev/null +++ b/dts/bindings/w1/zephyr,w1-gpio.yaml @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Hudson C. Dalpra +# SPDX-License-Identifier: Apache-2.0 + +description: | + Zephyr W1 GPIO node + + This defines a one-wire driver through GPIO bit-banging. + + For example: + + / { + w1: w1 { + compatible = "zephyr,w1-gpio"; + gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN | GPIO_PULL_UP)>; + }; + }; + + Above: + - w1 is pin 13 on gpio0. The gpio is active when the pin is high, is + configured as an open-drain, and has a pull-up resistor. + +compatible: "zephyr,w1-gpio" + +include: [w1-master.yaml] + +properties: + gpios: + type: phandle-array + required: true diff --git a/dts/bindings/watchdog/intel,adsp-watchdog.yaml b/dts/bindings/watchdog/intel,adsp-watchdog.yaml index 379e9e5edaa..495ee67af84 100644 --- a/dts/bindings/watchdog/intel,adsp-watchdog.yaml +++ b/dts/bindings/watchdog/intel,adsp-watchdog.yaml @@ -16,7 +16,7 @@ properties: type: int description: | Clock frequency used by counter in Hz. You can specify a frequency here or specify a clock - using the clocks propertie. + using the property "clocks". reset-pulse-length: type: int diff --git a/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml b/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml index 558f598c542..5660ebf0051 100644 --- a/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml +++ b/dts/bindings/watchdog/lowrisc,opentitan-aontimer.yaml @@ -22,5 +22,5 @@ properties: wdog-lock: type: boolean description: | - When set, lock watchdog configration after setup until the next + When set, lock watchdog configuration after setup until the next reset. diff --git a/dts/bindings/watchdog/snps,designware-watchdog.yaml b/dts/bindings/watchdog/snps,designware-watchdog.yaml index 654fb3b2aa1..5b0b899c621 100644 --- a/dts/bindings/watchdog/snps,designware-watchdog.yaml +++ b/dts/bindings/watchdog/snps,designware-watchdog.yaml @@ -2,7 +2,7 @@ description: Synopsys Designware Watchdog compatible: "snps,designware-watchdog" -include: base.yaml +include: [base.yaml, reset-device.yaml] properties: # This properties is also supported: @@ -16,7 +16,7 @@ properties: type: int description: | Clock frequency used by counter in Hz. You can specify a frequency here or specify a clock - using the clocks propertie. + using the clocks properties. reset-pulse-length: type: int diff --git a/dts/common/nordic/nrf54h20_enga.dtsi b/dts/common/nordic/nrf54h20_enga.dtsi new file mode 100644 index 00000000000..1b8f7b6f9e8 --- /dev/null +++ b/dts/common/nordic/nrf54h20_enga.dtsi @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +/delete-node/ &sw_pwm; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpuapp: cpu@2 { + compatible = "arm,cortex-m33"; + reg = <2>; + device_type = "cpu"; + clock-frequency = ; + }; + + cpurad: cpu@3 { + compatible = "arm,cortex-m33"; + reg = <3>; + device_type = "cpu"; + clock-frequency = ; + }; + + cpuppr: cpu@d { + compatible = "nordic,vpr"; + reg = <13>; + device_type = "cpu"; + clock-frequency = ; + riscv,isa = "rv32emc"; + nordic,bus-width = <32>; + }; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + + cpurad_uicr_ext: memory@e1ff000 { + reg = <0xe1ff000 DT_SIZE_K(2)>; + }; + + cpuapp_uicr_ext: memory@e1ff800 { + reg = <0xe1ff800 DT_SIZE_K(2)>; + }; + }; + + clocks { + fll16m: fll16m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = ; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + + mram1x: mram@e000000 { + compatible = "nordic,mram"; + reg = <0xe000000 DT_SIZE_K(2048)>; + write-block-size = <16>; + }; + + cpuapp_uicr: uicr@fff8000 { + compatible = "nordic,nrf-uicr-v2"; + reg = <0xfff8000 DT_SIZE_K(2)>; + domain = <2>; + ptr-ext-uicr = <&cpuapp_uicr_ext>; + }; + + cpurad_uicr: uicr@fffa000 { + compatible = "nordic,nrf-uicr-v2"; + reg = <0xfffa000 DT_SIZE_K(2)>; + domain = <3>; + ptr-ext-uicr = <&cpurad_uicr_ext>; + }; + + ficr: ficr@fffe000 { + compatible = "nordic,nrf-ficr"; + reg = <0xfffe000 DT_SIZE_K(2)>; + #nordic,ficr-cells = <1>; + }; + + cpuapp_ram0: sram@22000000 { + compatible = "mmio-sram"; + reg = <0x22000000 DT_SIZE_K(32)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x22000000 0x8000>; + }; + + cpurad_ram0: sram@23000000 { + compatible = "mmio-sram"; + reg = <0x23000000 DT_SIZE_K(64)>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x23000000 0x10000>; + }; + + cpuapp_peripherals: peripheral@52000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x52000000 0x1000000>; + + cpuapp_hsfll: clock@d000 { + compatible = "nordic,nrf-hsfll"; + #clock-cells = <0>; + reg = <0xd000 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0>, + <&ficr NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + }; + + cpurad_peripherals: peripheral@53000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x53000000 0x1000000>; + + cpurad_hsfll: clock@d000 { + compatible = "nordic,nrf-hsfll"; + #clock-cells = <0>; + reg = <0xd000 0x1000>; + clocks = <&fll16m>; + clock-frequency = ; + nordic,ficrs = + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_VSUP>, + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_1>, + <&ficr NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_1>; + nordic,ficr-names = "vsup", "coarse", "fine"; + }; + }; + + global_peripherals: peripheral@5f000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x5f000000 0x1000000>; + + cpuppr_vpr: vpr@908000 { + compatible = "nordic,nrf-vpr-coprocessor"; + reg = <0x908000 0x1000>; + status = "disabled"; + cpu = <13>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x908000 0x4000>; + + cpuppr_clic: interrupt-controller@1000 { + compatible = "nordic,nrf-clic"; + reg = <0x1000 0x3000>; + status = "disabled"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; + + gpiote130: gpiote@934000 { + compatible = "nordic,nrf-gpiote"; + reg = <0x934000 0x1000>; + status = "disabled"; + instance = <130>; + }; + + gpio0: gpio@938000 { + compatible = "nordic,nrf-gpio"; + reg = <0x938000 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <0>; + }; + + gpio1: gpio@938200 { + compatible = "nordic,nrf-gpio"; + reg = <0x938200 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <1>; + }; + + gpio2: gpio@938400 { + compatible = "nordic,nrf-gpio"; + reg = <0x938400 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <12>; + port = <2>; + }; + + gpio6: gpio@938c00 { + compatible = "nordic,nrf-gpio"; + reg = <0x938c00 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + ngpios = <14>; + port = <6>; + }; + + gpio7: gpio@938e00 { + compatible = "nordic,nrf-gpio"; + reg = <0x938e00 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + ngpios = <8>; + port = <7>; + }; + + gpio9: gpio@939200 { + compatible = "nordic,nrf-gpio"; + reg = <0x939200 0x200>; + status = "disabled"; + #gpio-cells = <2>; + gpio-controller; + gpiote-instance = <&gpiote130>; + ngpios = <6>; + port = <9>; + }; + + grtc: grtc@99c000 { + compatible = "nordic,nrf-grtc"; + reg = <0x99c000 0x1000>; + status = "disabled"; + cc-num = <16>; + }; + + uart135: uart@9c6000 { + compatible = "nordic,nrf-uarte"; + reg = <0x9c6000 0x1000>; + status = "disabled"; + current-speed = <115200>; + interrupts = <454 NRF_DEFAULT_IRQ_PRIORITY>; + }; + + uart136: uart@9d5000 { + compatible = "nordic,nrf-uarte"; + reg = <0x9d5000 0x1000>; + status = "disabled"; + current-speed = <115200>; + interrupts = <469 NRF_DEFAULT_IRQ_PRIORITY>; + }; + }; + }; + + cpuapp_ppb: cpuapp-ppb-bus { + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_systick: timer@e000e010 { + compatible = "arm,armv8m-systick"; + reg = <0xe000e010 0x10>; + status = "disabled"; + }; + + cpuapp_nvic: interrupt-controller@e000e100 { + compatible = "arm,v8m-nvic"; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <3>; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; + + cpurad_ppb: cpurad-ppb-bus { + #address-cells = <1>; + #size-cells = <1>; + + cpurad_systick: timer@e000e010 { + compatible = "arm,armv8m-systick"; + reg = <0xe000e010 0x10>; + status = "disabled"; + }; + + cpurad_nvic: interrupt-controller@e000e100 { + compatible = "arm,v8m-nvic"; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <3>; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + }; + }; +}; diff --git a/dts/arm/nordic/nrf_common.dtsi b/dts/common/nordic/nrf_common.dtsi similarity index 86% rename from dts/arm/nordic/nrf_common.dtsi rename to dts/common/nordic/nrf_common.dtsi index 8aec8dd0c89..cb2df6bcccd 100644 --- a/dts/arm/nordic/nrf_common.dtsi +++ b/dts/common/nordic/nrf_common.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -43,11 +44,3 @@ #pwm-cells = <3>; }; }; - -&systick { - /* - * Nordic SoCs rely by default on the RTC for system clock - * implementation, so the SysTick node is not to be enabled. - */ - status = "disabled"; -}; diff --git a/dts/riscv/andes/andes_v5_ae350.dtsi b/dts/riscv/andes/andes_v5_ae350.dtsi index 7af3e25ef62..419aa712b73 100644 --- a/dts/riscv/andes/andes_v5_ae350.dtsi +++ b/dts/riscv/andes/andes_v5_ae350.dtsi @@ -15,9 +15,8 @@ cpus { #address-cells = <1>; #size-cells = <0>; - timebase-frequency = <60000000>; - CPU0: cpu@0 { - compatible = "riscv"; + cpu0: cpu@0 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <0>; status = "okay"; @@ -26,15 +25,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU0_intc: interrupt-controller { + cpu0_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU1: cpu@1 { - compatible = "riscv"; + cpu1: cpu@1 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <1>; status = "okay"; @@ -43,15 +42,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU1_intc: interrupt-controller { + cpu1_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU2: cpu@2 { - compatible = "riscv"; + cpu2: cpu@2 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <2>; status = "okay"; @@ -60,15 +59,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU2_intc: interrupt-controller { + cpu2_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU3: cpu@3 { - compatible = "riscv"; + cpu3: cpu@3 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <3>; status = "okay"; @@ -77,15 +76,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU3_intc: interrupt-controller { + cpu3_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU4: cpu@4 { - compatible = "riscv"; + cpu4: cpu@4 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <4>; status = "okay"; @@ -94,15 +93,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU4_intc: interrupt-controller { + cpu4_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU5: cpu@5 { - compatible = "riscv"; + cpu5: cpu@5 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <5>; status = "okay"; @@ -111,15 +110,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU5_intc: interrupt-controller { + cpu5_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU6: cpu@6 { - compatible = "riscv"; + cpu6: cpu@6 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <6>; status = "okay"; @@ -128,15 +127,15 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU6_intc: interrupt-controller { + cpu6_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; interrupt-controller; }; }; - CPU7: cpu@7 { - compatible = "riscv"; + cpu7: cpu@7 { + compatible = "andestech,andescore-v5", "riscv"; device_type = "cpu"; reg = <7>; status = "okay"; @@ -145,7 +144,7 @@ clock-frequency = <60000000>; i-cache-line-size = <32>; d-cache-line-size = <32>; - CPU7_intc: interrupt-controller { + cpu7_intc: interrupt-controller { compatible = "riscv,cpu-intc"; #address-cells = <0>; #interrupt-cells = <1>; @@ -167,17 +166,17 @@ ranges; plic0: interrupt-controller@e4000000 { - compatible = "sifive,plic-1.0.0"; + compatible = "sifive,plic-1.0.0", "andestech,nceplic100"; #address-cells = <1>; #interrupt-cells = <2>; interrupt-controller; reg = <0xe4000000 0x04000000>; riscv,max-priority = <255>; riscv,ndev = <1023>; - interrupts-extended = <&CPU0_intc 11 &CPU1_intc 11 - &CPU2_intc 11 &CPU3_intc 11 - &CPU4_intc 11 &CPU5_intc 11 - &CPU6_intc 11 &CPU7_intc 11>; + interrupts-extended = <&cpu0_intc 11 &cpu1_intc 11 + &cpu2_intc 11 &cpu3_intc 11 + &cpu4_intc 11 &cpu5_intc 11 + &cpu6_intc 11 &cpu7_intc 11>; }; mbox: mbox-controller@e6400000 { @@ -191,10 +190,10 @@ mtimer: timer@e6000000 { compatible = "andestech,machine-timer"; reg = <0xe6000000 0x10>; - interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7 - &CPU2_intc 7 &CPU3_intc 7 - &CPU4_intc 7 &CPU5_intc 7 - &CPU6_intc 7 &CPU7_intc 7>; + interrupts-extended = <&cpu0_intc 7 &cpu1_intc 7 + &cpu2_intc 7 &cpu3_intc 7 + &cpu4_intc 7 &cpu5_intc 7 + &cpu6_intc 7 &cpu7_intc 7>; }; syscon: syscon@f0100000 { diff --git a/dts/riscv/efinix/sapphire_soc.dtsi b/dts/riscv/efinix/sapphire_soc.dtsi index 75043c9dfbb..b83c9bc1b0f 100644 --- a/dts/riscv/efinix/sapphire_soc.dtsi +++ b/dts/riscv/efinix/sapphire_soc.dtsi @@ -27,12 +27,11 @@ #size-cells = <0>; cpu@0 { clock-frequency = <100000000>; - compatible = "riscv"; + compatible = "efinix,vexriscv-sapphire", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; status = "okay"; - timebase-frequency = <100000000>; hlic: interrupt-controller { compatible = "riscv,cpu-intc"; diff --git a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi index 3b2bb6d0781..caee77fc6ef 100644 --- a/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi +++ b/dts/riscv/espressif/esp32c3/esp32c3_common.dtsi @@ -31,7 +31,7 @@ cpu0: cpu@0 { device_type = "cpu"; - compatible = "espressif,riscv"; + compatible = "espressif,riscv", "riscv"; riscv,isa = "rv32imc_zicsr"; reg = <0>; cpu-power-states = <&light_sleep &deep_sleep>; diff --git a/dts/riscv/gigadevice/gd32vf103.dtsi b/dts/riscv/gd/gd32vf103.dtsi similarity index 99% rename from dts/riscv/gigadevice/gd32vf103.dtsi rename to dts/riscv/gd/gd32vf103.dtsi index c9f37db5180..a631cd4ab18 100644 --- a/dts/riscv/gigadevice/gd32vf103.dtsi +++ b/dts/riscv/gd/gd32vf103.dtsi @@ -23,8 +23,7 @@ cpu: cpu@0 { clock-frequency = ; - mcause-exception-mask = <0x7ff>; - compatible = "nuclei,bumblebee"; + compatible = "nuclei,bumblebee", "riscv"; riscv,isa = "rv32imac_zicsr_zifencei"; reg = <0>; }; diff --git a/dts/riscv/gigadevice/gd32vf103X8.dtsi b/dts/riscv/gd/gd32vf103X8.dtsi similarity index 86% rename from dts/riscv/gigadevice/gd32vf103X8.dtsi rename to dts/riscv/gd/gd32vf103X8.dtsi index e92e4b73f7b..4c6c4fd695b 100644 --- a/dts/riscv/gigadevice/gd32vf103X8.dtsi +++ b/dts/riscv/gd/gd32vf103X8.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &sram0 { reg = <0x20000000 DT_SIZE_K(20)>; diff --git a/dts/riscv/gigadevice/gd32vf103Xb.dtsi b/dts/riscv/gd/gd32vf103Xb.dtsi similarity index 86% rename from dts/riscv/gigadevice/gd32vf103Xb.dtsi rename to dts/riscv/gd/gd32vf103Xb.dtsi index aa3cbda7a85..a88aa2f0fe9 100644 --- a/dts/riscv/gigadevice/gd32vf103Xb.dtsi +++ b/dts/riscv/gd/gd32vf103Xb.dtsi @@ -5,7 +5,7 @@ */ #include -#include +#include &sram0 { reg = <0x20000000 DT_SIZE_K(32)>; diff --git a/dts/riscv/ite/it82xx2.dtsi b/dts/riscv/ite/it82xx2.dtsi index 6b3eea97aa9..a400d65914b 100644 --- a/dts/riscv/ite/it82xx2.dtsi +++ b/dts/riscv/ite/it82xx2.dtsi @@ -390,6 +390,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; @@ -411,6 +412,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; @@ -432,6 +434,7 @@ NO_FUNC 0 NO_FUNC 0>; interrupt-parent = <&intc>; + keyboard-controller; #gpio-cells = <2>; }; @@ -521,10 +524,14 @@ pinctrle: pinctrl@f01680 { compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01680 8>; /* GPCR */ - func3-gcr = <0xf02032 0xf03e16 0xf03e16 NO_FUNC - NO_FUNC 0xf03e10 NO_FUNC 0xf02032>; - func3-en-mask = <0x01 0x20 0x20 0 - 0 0x08 0 0x01 >; + func3-gcr = ; + func3-en-mask = <0 0x20 0x20 0 + 0 0x08 0 0 >; + func3-ext = <0xf02032 0xf02032 0xf02032 NO_FUNC + NO_FUNC NO_FUNC NO_FUNC 0xf02032>; + func3-ext-mask = <0x01 0x02 0x02 0 + 0 0 0 0x01 >; func4-gcr = <0xf03e13 NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC >; func4-en-mask = <0x01 0 0 0 diff --git a/dts/riscv/ite/it8xxx2.dtsi b/dts/riscv/ite/it8xxx2.dtsi index 454e9c0c177..faa16fbaefe 100644 --- a/dts/riscv/ite/it8xxx2.dtsi +++ b/dts/riscv/ite/it8xxx2.dtsi @@ -28,7 +28,7 @@ #address-cells = <1>; #size-cells = <0>; cpu0: cpu@0 { - compatible = "ite,riscv-ite"; + compatible = "ite,riscv-ite", "riscv"; riscv,isa = "rv32imafc_zifencei"; device_type = "cpu"; reg = <0>; diff --git a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi index 2df96d71eeb..1f6c23671dc 100644 --- a/dts/riscv/lowrisc/opentitan_earlgrey.dtsi +++ b/dts/riscv/lowrisc/opentitan_earlgrey.dtsi @@ -12,13 +12,12 @@ cpus { #address-cells = <0x01>; #size-cells = <0x00>; - timebase-frequency = <10000000>; cpu@0 { device_type = "cpu"; reg = <0x00>; status = "okay"; - compatible = "riscv"; + compatible = "lowrisc,ibex", "riscv"; riscv,isa = "rv32imcb_zicsr_zifencei"; hlic: interrupt-controller { diff --git a/dts/riscv/microchip/mpfs-icicle.dtsi b/dts/riscv/microchip/mpfs-icicle.dtsi deleted file mode 100644 index 4ed4d45e305..00000000000 --- a/dts/riscv/microchip/mpfs-icicle.dtsi +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2018 Linaro Limited - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/ { - #address-cells = <1>; - #size-cells = <1>; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - cpu@0 { - clock-frequency = <0>; - compatible = "riscv"; - device_type = "cpu"; - reg = < 0x0 >; - riscv,isa = "rv64imac_zicsr_zfencei"; - hlic0: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; - - cpu@1 { - clock-frequency = <0>; - compatible = "riscv"; - device_type = "cpu"; - reg = < 0x1 >; - riscv,isa = "rv64gc"; - hlic1: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; - - cpu@2 { - clock-frequency = <0>; - compatible = "riscv"; - device_type = "cpu"; - reg = < 0x2 >; - riscv,isa = "rv64gc"; - hlic2: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; - - cpu@3 { - clock-frequency = <0>; - compatible = "riscv"; - device_type = "cpu"; - reg = < 0x3 >; - riscv,isa = "rv64gc"; - hlic3: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; - - cpu@4 { - clock-frequency = <0>; - compatible = "riscv"; - device_type = "cpu"; - reg = < 0x4 >; - riscv,isa = "rv64gc"; - hlic4: interrupt-controller { - compatible = "riscv,cpu-intc"; - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; - }; - - soc { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges; - - sram0: memory@8000000 { - compatible = "mmio-sram"; - reg = <0x8000000 0x80000>; - }; - - sram1: memory@80000000 { - compatible = "mmio-sram"; - reg = <0x80000000 0x800000>; - }; - - clint: clint@2000000 { - compatible = "sifive,clint0"; - interrupts-extended = <&hlic0 3 &hlic0 7 - &hlic1 3 &hlic1 7 - &hlic2 3 &hlic2 7 - &hlic3 3 &hlic3 7 - &hlic4 3 &hlic4 7>; - interrupt-names = "soft0", "timer0", "soft1", "timer1", - "soft2", "timer2", "soft3", "timer3", - "soft4", "timer4"; - reg = <0x2000000 0x10000>; - }; - - plic: interrupt-controller@c000000 { - compatible = "sifive,plic-1.0.0"; - #interrupt-cells = <2>; - #address-cells = <1>; - interrupt-controller; - interrupts-extended = <&hlic0 11 - &hlic1 11>; - reg = <0x0c000000 0x04000000>; - riscv,max-priority = <7>; - riscv,ndev = <187>; - }; - - uart0: uart@20000000 { - compatible = "ns16550"; - reg = <0x20000000 0x1000>; - clock-frequency = <150000000>; - current-speed = <115200>; - interrupt-parent = <&plic>; - interrupts = <90 1>; - reg-shift = <2>; - status = "disabled"; - }; - - uart1: uart@20100000 { - compatible = "ns16550"; - reg = <0x20100000 0x1000>; - clock-frequency = <150000000>; - current-speed = <115200>; - interrupt-parent = <&plic>; - interrupts = <91 1>; - reg-shift = <2>; - status = "disabled"; - }; - - uart2: uart@20102000 { - compatible = "ns16550"; - reg = <0x20102000 0x1000>; - clock-frequency = <150000000>; - current-speed = <115200>; - interrupt-parent = <&plic>; - interrupts = <92 1>; - reg-shift = <2>; - status = "disabled"; - }; - - uart3: uart@20104000 { - compatible = "ns16550"; - reg = <0x20104000 0x1000>; - clock-frequency = <150000000>; - current-speed = <115200>; - interrupt-parent = <&plic>; - interrupts = <93 1>; - reg-shift = <2>; - status = "disabled"; - }; - - uart4: uart@20106000 { - compatible = "ns16550"; - reg = <0x20106000 0x1000>; - clock-frequency = <150000000>; - current-speed = <115200>; - interrupt-parent = <&plic>; - interrupts = <94 1>; - reg-shift = <2>; - status = "disabled"; - }; - - qspi0: spi@21000000 { - compatible = "microchip,mpfs-qspi"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x21000000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <85 1>; - status = "disabled"; - clock-frequency = <150000000>; - }; - - gpio0: gpio@20120000 { - compatible = "microchip,mpfs-gpio"; - reg = <0x20120000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <51 1>; - interrupt-controller; - #interrupt-cells = <1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <32>; - status = "disabled"; - }; - - gpio1: gpio@20121000 { - compatible = "microchip,mpfs-gpio"; - reg = <0x20121000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <52 1>; - interrupt-controller; - #interrupt-cells = <1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <32>; - status = "disabled"; - }; - - gpio2: gpio@20122000 { - compatible = "microchip,mpfs-gpio"; - reg = <0x20122000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <53 1>; - interrupt-controller; - #interrupt-cells = <1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <32>; - status = "disabled"; - }; - - i2c0: i2c@2010a000 { - compatible = "microchip,mpfs-i2c"; - reg = <0x2010a000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <58 1>; - #address-cells = <1>; - #size-cells = <0>; - clock-frequency = <100000>; - status = "disabled"; - }; - - i2c1: i2c@2010b000 { - compatible = "microchip,mpfs-i2c"; - reg = <0x2010b000 0x1000>; - interrupt-parent = <&plic>; - interrupts = <61 1>; - #address-cells = <1>; - #size-cells = <0>; - clock-frequency = <100000>; - status = "disabled"; - }; - }; -}; diff --git a/dts/riscv/microchip/mpfs.dtsi b/dts/riscv/microchip/mpfs.dtsi new file mode 100644 index 00000000000..f22c7604bb3 --- /dev/null +++ b/dts/riscv/microchip/mpfs.dtsi @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2018 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + clock-frequency = <0>; + compatible = "sifive,e51", "riscv"; + device_type = "cpu"; + reg = < 0x0 >; + riscv,isa = "rv64imac_zicsr_zifencei"; + hlic0: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + cpu@1 { + clock-frequency = <0>; + compatible = "sifive,u54", "riscv"; + device_type = "cpu"; + reg = < 0x1 >; + riscv,isa = "rv64gc"; + hlic1: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + cpu@2 { + clock-frequency = <0>; + compatible = "sifive,u54", "riscv"; + device_type = "cpu"; + reg = < 0x2 >; + riscv,isa = "rv64gc"; + hlic2: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + cpu@3 { + clock-frequency = <0>; + compatible = "sifive,u54", "riscv"; + device_type = "cpu"; + reg = < 0x3 >; + riscv,isa = "rv64gc"; + hlic3: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + cpu@4 { + clock-frequency = <0>; + compatible = "sifive,u54", "riscv"; + device_type = "cpu"; + reg = < 0x4 >; + riscv,isa = "rv64gc"; + hlic4: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + sram0: memory@8000000 { + compatible = "mmio-sram"; + reg = <0x8000000 0x80000>; + }; + + sram1: memory@80000000 { + compatible = "mmio-sram"; + reg = <0x80000000 0x800000>; + }; + + clint: clint@2000000 { + compatible = "sifive,clint0"; + interrupts-extended = <&hlic0 3 &hlic0 7 + &hlic1 3 &hlic1 7 + &hlic2 3 &hlic2 7 + &hlic3 3 &hlic3 7 + &hlic4 3 &hlic4 7>; + interrupt-names = "soft0", "timer0", "soft1", "timer1", + "soft2", "timer2", "soft3", "timer3", + "soft4", "timer4"; + reg = <0x2000000 0x10000>; + }; + + plic: interrupt-controller@c000000 { + compatible = "sifive,plic-1.0.0"; + #interrupt-cells = <2>; + #address-cells = <1>; + interrupt-controller; + interrupts-extended = <&hlic0 11 + &hlic1 11 &hlic1 9 + &hlic2 11 &hlic2 9 + &hlic3 11 &hlic3 9 + &hlic4 11 &hlic4 9>; + reg = <0x0c000000 0x04000000>; + riscv,max-priority = <7>; + riscv,ndev = <186>; + }; + + mbox: mailbox@37020000 { + compatible = "microchip,mpfs-mailbox"; + reg = <0x37020000 0x58>, <0x2000318C 0x40>, + <0x37020800 0x100>; + interrupt-parent = <&plic>; + interrupts = <96 1>; + #mbox-cells = <1>; + status = "disabled"; + }; + + uart0: uart@20000000 { + compatible = "ns16550"; + reg = <0x20000000 0x1000>; + clock-frequency = <150000000>; + current-speed = <115200>; + interrupt-parent = <&plic>; + interrupts = <90 1>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: uart@20100000 { + compatible = "ns16550"; + reg = <0x20100000 0x1000>; + clock-frequency = <150000000>; + current-speed = <115200>; + interrupt-parent = <&plic>; + interrupts = <91 1>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: uart@20102000 { + compatible = "ns16550"; + reg = <0x20102000 0x1000>; + clock-frequency = <150000000>; + current-speed = <115200>; + interrupt-parent = <&plic>; + interrupts = <92 1>; + reg-shift = <2>; + status = "disabled"; + }; + + uart3: uart@20104000 { + compatible = "ns16550"; + reg = <0x20104000 0x1000>; + clock-frequency = <150000000>; + current-speed = <115200>; + interrupt-parent = <&plic>; + interrupts = <93 1>; + reg-shift = <2>; + status = "disabled"; + }; + + uart4: uart@20106000 { + compatible = "ns16550"; + reg = <0x20106000 0x1000>; + clock-frequency = <150000000>; + current-speed = <115200>; + interrupt-parent = <&plic>; + interrupts = <94 1>; + reg-shift = <2>; + status = "disabled"; + }; + + qspi0: spi@21000000 { + compatible = "microchip,mpfs-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x21000000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <85 1>; + status = "disabled"; + clock-frequency = <150000000>; + }; + + spi1: spi@20109000 { + compatible = "microchip,mpfs-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x20109000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <55 1>; + status = "disabled"; + clock-frequency = <150000000>; + }; + + syscontroller_qspi: spi@37020100 { + compatible = "microchip,mpfs-qspi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x37020100 0x1000>; + interrupt-parent = <&plic>; + interrupts = <110 1>; + status = "disabled"; + clock-frequency = <150000000>; + }; + + gpio0: gpio@20120000 { + compatible = "microchip,mpfs-gpio"; + reg = <0x20120000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <51 1>; + interrupt-controller; + #interrupt-cells = <1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + gpio1: gpio@20121000 { + compatible = "microchip,mpfs-gpio"; + reg = <0x20121000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <52 1>; + interrupt-controller; + #interrupt-cells = <1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + gpio2: gpio@20122000 { + compatible = "microchip,mpfs-gpio"; + reg = <0x20122000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <53 1>; + interrupt-controller; + #interrupt-cells = <1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + i2c0: i2c@2010a000 { + compatible = "microchip,mpfs-i2c"; + reg = <0x2010a000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <58 1>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@2010b000 { + compatible = "microchip,mpfs-i2c"; + reg = <0x2010b000 0x1000>; + interrupt-parent = <&plic>; + interrupts = <61 1>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + status = "disabled"; + }; + }; +}; diff --git a/dts/riscv/neorv32.dtsi b/dts/riscv/neorv32.dtsi index 429d4372418..31fb06b1c49 100644 --- a/dts/riscv/neorv32.dtsi +++ b/dts/riscv/neorv32.dtsi @@ -19,7 +19,7 @@ #size-cells = <0>; cpu0: cpu@0 { - compatible = "neorv32-cpu"; + compatible = "neorv32-cpu", "riscv"; riscv,isa = "rv32imc_zicsr"; reg = <0>; device_type = "cpu"; diff --git a/dts/riscv/niosv/niosv-g.dtsi b/dts/riscv/niosv/niosv-g.dtsi index 90869676f2b..2022e984ff5 100644 --- a/dts/riscv/niosv/niosv-g.dtsi +++ b/dts/riscv/niosv/niosv-g.dtsi @@ -17,7 +17,7 @@ #size-cells = <0>; cpu0: cpu@0 { device_type = "cpu"; - compatible = "intel,niosv"; + compatible = "intel,niosv", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <0>; clock-frequency = <50000000>; diff --git a/dts/riscv/niosv/niosv-m.dtsi b/dts/riscv/niosv/niosv-m.dtsi index 88f8042383c..e6594a23546 100644 --- a/dts/riscv/niosv/niosv-m.dtsi +++ b/dts/riscv/niosv/niosv-m.dtsi @@ -17,7 +17,7 @@ #size-cells = <0>; cpu0: cpu@0 { device_type = "cpu"; - compatible = "intel,niosv"; + compatible = "intel,niosv", "riscv"; riscv,isa = "rv32ia_zicsr_zifencei"; reg = <0>; clock-frequency = <50000000>; diff --git a/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi b/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi new file mode 100644 index 00000000000..d42a815a4b2 --- /dev/null +++ b/dts/riscv/nordic/nrf54h20_enga_cpuppr.dtsi @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +cpu: &cpuppr {}; +clic: &cpuppr_clic {}; + +/delete-node/ &cpuapp; +/delete-node/ &cpuapp_peripherals; +/delete-node/ &cpuapp_ppb; +/delete-node/ &cpuapp_ram0; +/delete-node/ &cpurad; +/delete-node/ &cpurad_peripherals; +/delete-node/ &cpurad_ppb; +/delete-node/ &cpurad_ram0; + +/ { + soc { + compatible = "simple-bus"; + interrupt-parent = <&cpuppr_clic>; + ranges; + }; +}; + +&gpiote130 { + interrupts = <104 NRF_DEFAULT_IRQ_PRIORITY>; +}; + +&grtc { + interrupts = <108 NRF_DEFAULT_IRQ_PRIORITY>; +}; diff --git a/dts/riscv/openisa/rv32m1.dtsi b/dts/riscv/openisa/rv32m1.dtsi index 567a6959f1f..afbc7c41c23 100644 --- a/dts/riscv/openisa/rv32m1.dtsi +++ b/dts/riscv/openisa/rv32m1.dtsi @@ -22,14 +22,14 @@ #size-cells = <0>; cpu@0 { device_type = "cpu"; - compatible = "riscv"; + compatible = "openisa,ri5cy", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <0>; }; cpu@1 { device_type = "cpu"; - compatible = "riscv"; + compatible = "openisa,zero-ri5cy", "riscv"; riscv,isa = "rv32ima_zicsr_zifencei"; reg = <1>; }; diff --git a/dts/riscv/renode_riscv32_virt.dtsi b/dts/riscv/renode_riscv32_virt.dtsi new file mode 100644 index 00000000000..a0db375501f --- /dev/null +++ b/dts/riscv/renode_riscv32_virt.dtsi @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + clock-frequency = <0>; + compatible = "renode,virt", "riscv"; + device_type = "cpu"; + reg = <0>; + riscv,isa = "rv32imac_zicsr_zifencei"; + hlic: interrupt-controller { + compatible = "riscv,cpu-intc"; + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renode,virt-soc", "simple-bus"; + ranges; + + flash0: flash@80000000 { + compatible = "soc-nv-flash"; + reg = <0x80000000 DT_SIZE_M(4)>; + }; + + sram0: memory@80400000 { + compatible = "mmio-sram"; + reg = <0x80400000 DT_SIZE_M(4)>; + }; + + clint: clint@2000000 { + compatible = "sifive,clint0"; + interrupts-extended = <&hlic 3>, <&hlic 7>; + reg = <0x2000000 0x10000>; + }; + + plic0: interrupt-controller@c000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts-extended = <&hlic 11>; + reg = <0xc000000 0x04000000>; + riscv,max-priority = <1>; + riscv,ndev = <1023>; + }; + + plic1: interrupt-controller@8000000 { + compatible = "sifive,plic-1.0.0"; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts-extended = <&hlic 4>; + reg = <0x8000000 0x04000000>; + riscv,max-priority = <1>; + riscv,ndev = <1023>; + }; + + uart0: uart@10000000 { + interrupts = < 0x0a 1 >; + interrupt-parent = < &plic0 >; + clock-frequency = <150000000>; + current-speed = <115200>; + reg = < 0x10000000 0x100 >; + compatible = "ns16550"; + reg-shift = < 0 >; + status = "disabled"; + }; + + uart1: uart@10000100 { + interrupts = < 0x0a 1 >; + interrupt-parent = < &plic1 >; + clock-frequency = <150000000>; + current-speed = <115200>; + reg = < 0x10000100 0x100 >; + compatible = "ns16550"; + reg-shift = < 0 >; + status = "disabled"; + }; + }; +}; diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index 3eefacccf6d..8013decbafd 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -20,12 +20,11 @@ #size-cells = <0>; cpu@0 { clock-frequency = <100000000>; - compatible = "riscv"; + compatible = "litex,vexriscv-standard", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32ima_zicsr_zifencei"; status = "okay"; - timebase-frequency = <32768>; }; }; soc { diff --git a/dts/riscv/sifive/riscv32-fe310.dtsi b/dts/riscv/sifive/riscv32-fe310.dtsi index c028db37c4e..f2128e1d37b 100644 --- a/dts/riscv/sifive/riscv32-fe310.dtsi +++ b/dts/riscv/sifive/riscv32-fe310.dtsi @@ -27,7 +27,7 @@ #address-cells = <1>; #size-cells = <0>; cpu: cpu@0 { - compatible = "sifive,e31"; + compatible = "sifive,e31", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv32imac_zicsr_zifencei"; diff --git a/dts/riscv/sifive/riscv64-fu540.dtsi b/dts/riscv/sifive/riscv64-fu540.dtsi index ed56401d462..7ccd950129a 100644 --- a/dts/riscv/sifive/riscv64-fu540.dtsi +++ b/dts/riscv/sifive/riscv64-fu540.dtsi @@ -33,7 +33,7 @@ #size-cells = <0>; cpu: cpu@0 { - compatible = "sifive,e51"; + compatible = "sifive,e51", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv64imac_zicsr_zifencei"; @@ -179,6 +179,7 @@ gpio0: gpio@10060000 { compatible = "sifive,gpio0"; gpio-controller; + ngpios = <16>; interrupt-parent = <&plic>; interrupts = <7 1>, <8 1>, <9 1>, <10 1>, <11 1>, <12 1>, <13 1>, <14 1>, diff --git a/dts/riscv/sifive/riscv64-fu740.dtsi b/dts/riscv/sifive/riscv64-fu740.dtsi index bbe45b98aab..61421cd557e 100644 --- a/dts/riscv/sifive/riscv64-fu740.dtsi +++ b/dts/riscv/sifive/riscv64-fu740.dtsi @@ -32,7 +32,7 @@ #size-cells = <0>; cpu0: cpu@0 { - compatible = "sifive,s7"; + compatible = "sifive,s7", "riscv"; device_type = "cpu"; reg = <0>; riscv,isa = "rv64imac_zicsr_zifencei"; @@ -46,7 +46,7 @@ }; }; cpu1: cpu@1 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x1>; @@ -59,7 +59,7 @@ }; }; cpu2: cpu@2 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x2>; @@ -72,7 +72,7 @@ }; }; cpu3: cpu@3 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x3>; @@ -85,7 +85,7 @@ }; }; cpu4: cpu@4 { - compatible = "sifive,u74"; + compatible = "sifive,u74", "riscv"; device_type = "cpu"; mmu-type = "riscv,sv39"; reg = <0x4>; diff --git a/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi b/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi index c355ac89a5f..c36ea625b02 100644 --- a/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi +++ b/dts/riscv/starfive/starfive_jh7100_beagle_v.dtsi @@ -16,7 +16,6 @@ cpus: cpus { #address-cells = <1>; #size-cells = <0>; - timebase-frequency = <6250000>; compatible = "starfive,fu74-g000"; cpu@0 { clock-frequency = <0>; diff --git a/dts/riscv/virt.dtsi b/dts/riscv/virt.dtsi index caef8cb28d3..20873731c6e 100644 --- a/dts/riscv/virt.dtsi +++ b/dts/riscv/virt.dtsi @@ -36,7 +36,6 @@ cpus { #address-cells = < 0x01 >; #size-cells = < 0x00 >; - timebase-frequency = < 10000000 >; cpu@0 { device_type = "cpu"; diff --git a/dts/sparc/gaisler/gr716a.dtsi b/dts/sparc/gaisler/gr716a.dtsi index 78b9c806bbe..a3c79e1eaa9 100644 --- a/dts/sparc/gaisler/gr716a.dtsi +++ b/dts/sparc/gaisler/gr716a.dtsi @@ -89,5 +89,23 @@ reg = <0x80305000 0x100>; status = "disabled"; }; + + spim0: spi@fff00100 { + compatible = "gaisler,spimctrl"; + reg = <0xfff00100 0x100>; + interrupts = <2 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spim1: spi@fff00200 { + compatible = "gaisler,spimctrl"; + reg = <0xfff00200 0x100>; + interrupts = <2 0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; }; diff --git a/dts/x86/intel/alder_lake.dtsi b/dts/x86/intel/alder_lake.dtsi index 610c9f4ba72..968ca3ab1cf 100644 --- a/dts/x86/intel/alder_lake.dtsi +++ b/dts/x86/intel/alder_lake.dtsi @@ -48,7 +48,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; smbus0: smbus0 { @@ -78,6 +79,12 @@ status = "disabled"; }; + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + uart1: uart1 { compatible = "ns16550"; vendor-id = <0x8086>; @@ -87,6 +94,14 @@ reg-shift = <2>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&uart1_dma 0>, <&uart1_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart2_dma: uart2_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; status = "disabled"; }; @@ -99,6 +114,8 @@ reg-shift = <2>; interrupts = ; interrupt-parent = <&intc>; + dmas = <&uart2_dma 0>, <&uart2_dma 1>; + dma-names = "tx", "rx"; status = "disabled"; }; @@ -258,6 +275,12 @@ compatible = "simple-bus"; ranges; + vtd: vtd@fed91000 { + compatible = "intel,vt-d"; + reg = <0xfed91000 0x1000>; + status = "okay"; + }; + uart0_legacy: uart@3f8 { compatible = "ns16550"; reg = <0x000003f8 0x100>; diff --git a/dts/x86/intel/apollo_lake.dtsi b/dts/x86/intel/apollo_lake.dtsi index ffe50483434..a439feea175 100644 --- a/dts/x86/intel/apollo_lake.dtsi +++ b/dts/x86/intel/apollo_lake.dtsi @@ -47,7 +47,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; uart0: uart0 { diff --git a/dts/x86/intel/elkhart_lake.dtsi b/dts/x86/intel/elkhart_lake.dtsi index e23183df1d0..07b8dc5dc1a 100644 --- a/dts/x86/intel/elkhart_lake.dtsi +++ b/dts/x86/intel/elkhart_lake.dtsi @@ -52,7 +52,8 @@ pcie0: pcie0 { #address-cells = <1>; #size-cells = <1>; - compatible = "intel,pcie"; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; ranges; ptm_root0: ptm_root0 { diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi deleted file mode 100644 index 797a3fa0e54..00000000000 --- a/dts/x86/intel/raptor_lake.dtsi +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation. - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "skeleton.dtsi" -#include -#include -#include -#include - -/ { - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "intel,raptor-lake"; - d-cache-line-size = <64>; - reg = <0>; - }; - - }; - - dram0: memory@0 { - device_type = "memory"; - reg = <0x0 DT_DRAM_SIZE>; - }; - - intc: ioapic@fec00000 { - compatible = "intel,ioapic"; - #address-cells = <1>; - #interrupt-cells = <3>; - reg = <0xfec00000 0x1000>; - interrupt-controller; - }; - - intc_loapic: loapic@fee00000 { - compatible = "intel,loapic"; - reg = <0xfee00000 0x1000>; - interrupt-controller; - #interrupt-cells = <3>; - #address-cells = <1>; - }; - - pcie0: pcie0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "intel,pcie"; - ranges; - - smbus0: smbus0 { - compatible = "intel,pch-smbus"; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7a23>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "okay"; - }; - - i2c0: i2c0 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7acc>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "okay"; - }; - - i2c0_dma: i2c0_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c0>; - #dma-cells = <1>; - status = "okay"; - }; - - i2c1: i2c1 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7acd>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c1_dma: i2c1_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c1>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c2: i2c2 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7ace>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c2_dma: i2c2_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c2>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c3: i2c3 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7acf>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c3_dma: i2c3_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c3>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c4: i2c4 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7afc>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c4_dma: i2c4_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c4>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c5: i2c5 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7afd>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c5_dma: i2c5_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c5>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c6: i2c6 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7ada>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c6_dma: i2c6_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c6>; - #dma-cells = <1>; - status = "disabled"; - }; - - i2c7: i2c7 { - compatible = "snps,designware-i2c"; - clock-frequency = ; - #address-cells = <1>; - #size-cells = <0>; - vendor-id = <0x8086>; - device-id = <0x7adb>; - interrupts = ; - interrupt-parent = <&intc>; - - status = "disabled"; - }; - - i2c7_dma: i2c7_dma { - compatible = "intel,lpss"; - dma-parent = <&i2c7>; - #dma-cells = <1>; - status = "disabled"; - }; - - spi0: spi0 { - compatible = "intel,penwell-spi"; - vendor-id = <0x8086>; - device-id = <0x7aaa>; - #address-cells = <1>; - #size-cells = <0>; - pw,cs-mode = <0>; - pw,cs-output = <0>; - pw,fifo-depth = <64>; - cs-gpios = <&gpio_0_i 15 GPIO_ACTIVE_LOW>; - clock-frequency = <100000000>; - interrupts = ; - interrupt-parent = <&intc>; - status = "okay"; - }; - - spi1: spi1 { - compatible = "intel,penwell-spi"; - vendor-id = <0x8086>; - device-id = <0x7aab>; - #address-cells = <1>; - #size-cells = <0>; - pw,cs-mode = <0>; - pw,cs-output = <0>; - pw,fifo-depth = <64>; - cs-gpios = <&gpio_0_i 19 GPIO_ACTIVE_LOW>; - clock-frequency = <100000000>; - interrupts = ; - interrupt-parent = <&intc>; - status = "disabled"; - }; - - spi2: spi2 { - compatible = "intel,penwell-spi"; - vendor-id = <0x8086>; - device-id = <0x7afb>; - #address-cells = <1>; - #size-cells = <0>; - pw,cs-mode = <0>; - pw,cs-output = <0>; - pw,fifo-depth = <64>; - cs-gpios = <&gpio_0_r 12 GPIO_ACTIVE_LOW>; - clock-frequency = <100000000>; - interrupts = ; - interrupt-parent = <&intc>; - status = "disabled"; - }; - - uart0: uart0 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7aa8>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "okay"; - }; - - uart1: uart1 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7aa9>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "okay"; - }; - - uart2: uart2 { - compatible = "ns16550"; - vendor-id = <0x8086>; - device-id = <0x7afe>; - reg-shift = <2>; - clock-frequency = <1843200>; - interrupts = ; - interrupt-parent = <&intc>; - current-speed = <115200>; - status = "disabled"; - }; - }; - - soc { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges; - - vtd: vtd@fed91000 { - compatible = "intel,vt-d"; - reg = <0xfed91000 0x1000>; - - status = "okay"; - }; - - uart_ec_0: uart@3f8 { - compatible = "ns16550"; - reg = <0x000003f8 0x100>; - io-mapped; - clock-frequency = <1843200>; - interrupts = <4 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - reg-shift = <0>; - io-mapped; - status = "okay"; - }; - - gpio_0_i: gpio@e06e0700 { - compatible = "intel,gpio"; - reg = <0xe06e0700 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x0>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <23>; - pin-offset = <0>; - - status = "okay"; - }; - - gpio_0_r: gpio@e06e0890 { - compatible = "intel,gpio"; - reg = <0xe06e0890 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <22>; - pin-offset = <26>; - - status = "okay"; - }; - - gpio_0_j: gpio@e06e0a00 { - compatible = "intel,gpio"; - reg = <0xe06e0a00 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x2>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <12>; - pin-offset = <49>; - - status = "okay"; - }; - - gpio_1_b: gpio@e06d0700 { - compatible = "intel,gpio"; - reg = <0xe06d0700 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x0>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <24>; - pin-offset = <0>; - - status = "okay"; - }; - - gpio_1_g: gpio@e06d0880 { - compatible = "intel,gpio"; - reg = <0xe06d0880 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <8>; - pin-offset = <24>; - - status = "okay"; - }; - - gpio_1_h: gpio@e06d0900 { - compatible = "intel,gpio"; - reg = <0xe06d0900 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x2>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <24>; - pin-offset = <32>; - - status = "okay"; - }; - - gpio_3_a: gpio@e06b0790 { - compatible = "intel,gpio"; - reg = <0xe06b0790 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <15>; - pin-offset = <9>; - - status = "okay"; - }; - - gpio_3_c: gpio@e06b0890 { - compatible = "intel,gpio"; - reg = <0xe06b0890 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x2>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <24>; - pin-offset = <25>; - - status = "okay"; - }; - - gpio_4_s: gpio@e06a0700 { - compatible = "intel,gpio"; - reg = <0xe06a0700 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x0>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <8>; - pin-offset = <0>; - - status = "okay"; - }; - - gpio_4_e: gpio@e06a0780 { - compatible = "intel,gpio"; - reg = <0xe06a0780 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x1>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <22>; - pin-offset = <8>; - - status = "okay"; - }; - - gpio_4_k: gpio@e06a08f0 { - compatible = "intel,gpio"; - reg = <0xe06a08f0 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x2>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <12>; - pin-offset = <25>; - - status = "okay"; - }; - - gpio_4_f: gpio@e06a09e0 { - compatible = "intel,gpio"; - reg = <0xe06a09e0 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x3>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <24>; - pin-offset = <41>; - - status = "okay"; - }; - - gpio_5_d: gpio@e0690700 { - compatible = "intel,gpio"; - reg = <0xe0690700 0x1000>; - interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; - interrupt-parent = <&intc>; - group-index = <0x0>; - gpio-controller; - #gpio-cells = <2>; - ngpios = <24>; - pin-offset = <0>; - - status = "okay"; - }; - - pwm0: pwm@e06a0000 { - compatible = "intel,blinky-pwm"; - reg = <0xe06a0000 0x400>; - reg-offset = <0x304>; - clock-frequency = <32768>; - max-pins = <1>; - #pwm-cells = <2>; - status = "okay"; - }; - - rtc: counter: rtc@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; - interrupt-parent = <&intc>; - alarms-count = <1>; - - status = "okay"; - }; - - tgpio: tgpio@fe001200 { - compatible = "intel,timeaware-gpio"; - reg = <0xfe001200 0x100>; - timer-clock = <19200000>; - max-pins = <2>; - status = "okay"; - }; - - hpet: hpet@fed00000 { - compatible = "intel,hpet"; - reg = <0xfed00000 0x400>; - interrupts = <2 IRQ_TYPE_FIXED_EDGE_RISING 4>; - interrupt-parent = <&intc>; - - status = "okay"; - }; - - tco_wdt: tco_wdt@400 { - compatible = "intel,tco-wdt"; - reg = <0x0400 0x20>; - - status = "disabled"; - }; - }; -}; diff --git a/dts/x86/intel/raptor_lake_p.dtsi b/dts/x86/intel/raptor_lake_p.dtsi new file mode 100644 index 00000000000..1c6de091d2f --- /dev/null +++ b/dts/x86/intel/raptor_lake_p.dtsi @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "intel,raptor-lake"; + device_type = "cpu"; + d-cache-line-size = <64>; + reg = <0>; + }; + }; + + dram0: memory@0 { + device_type = "memory"; + reg = <0x0 DT_DRAM_SIZE>; + }; + + intc: ioapic@fec00000 { + compatible = "intel,ioapic"; + reg = <0xfec00000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + intc_loapic: loapic@fee00000 { + compatible = "intel,loapic"; + reg = <0xfee00000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + #address-cells = <1>; + }; + + pcie0: pcie0 { + compatible = "pcie-controller"; + #address-cells = <1>; + #size-cells = <1>; + acpi-hid = "PNP0A08"; + ranges; + + smbus0: smbus0 { + compatible = "intel,pch-smbus"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51a3>; + interrupts = <16 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + uart0: uart0 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x51a8>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + + status = "okay"; + }; + + uart1: uart1 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x51A9>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + + status = "okay"; + }; + + spi0: spi0 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51aa>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_4_e 10 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + spi1: spi1 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51ab>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_4_f 16 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + spi2: spi2 { + compatible = "intel,penwell-spi"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x51fb>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_1_d 9 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c0: i2c0 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51e8>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + i2c1: i2c1 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51e9>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + i2c2: i2c2 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51ea>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c3: i2c3 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51eb>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c4: i2c4 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51c5>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c5: i2c5 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51c6>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c6: i2c6 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51d8>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + + i2c7: i2c7 { + compatible = "snps,designware-i2c"; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = ; + vendor-id = <0x8086>; + device-id = <0x51d9>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "disabled"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio_0_b: gpio@fd6e0700 { + compatible = "intel,gpio"; + reg = <0xfd6e0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_0_t: gpio@fd6e08a0 { + compatible = "intel,gpio"; + reg = <0xfd6e08a0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <4>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_0_a: gpio@fd6e09a0 { + compatible = "intel,gpio"; + reg = <0xfd6e09a0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <41>; + + status = "okay"; + }; + + gpio_1_s: gpio@fd6d0700 { + compatible = "intel,gpio"; + reg = <0xfd6d0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <8>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_1_h: gpio@fd6d0780 { + compatible = "intel,gpio"; + reg = <0xfd6d0780 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <8>; + + status = "okay"; + }; + + + gpio_1_d: gpio@fd6d0900 { + compatible = "intel,gpio"; + reg = <0xfd6d0900 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <20>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_2_gpd: gpio@fd6c0700 { + compatible = "intel,gpio"; + reg = <0xfd6c0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <12>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_4_c: gpio@fd6a0700 { + compatible = "intel,gpio"; + reg = <0xfd6a0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_4_f: gpio@fd6a0880 { + compatible = "intel,gpio"; + reg = <0xfd6a0880 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <24>; + + status = "okay"; + }; + + gpio_4_e: gpio@fd6a0a70 { + compatible = "intel,gpio"; + reg = <0xfd6a0a70 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x3>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <24>; + pin-offset = <57>; + + status = "okay"; + }; + + gpio_5_r: gpio@fd690700 { + compatible = "intel,gpio"; + reg = <0xfd690700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + + ngpios = <8>; + pin-offset = <0>; + + status = "okay"; + }; + + tgpio: tgpio@fe001200 { + compatible = "intel,timeaware-gpio"; + reg = <0xfe001200 0x100>; + timer-clock = <19200000>; + max-pins = <2>; + + status = "okay"; + }; + + rtc: counter: rtc@70 { + compatible = "motorola,mc146818"; + reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + hpet: hpet@fed00000 { + compatible = "intel,hpet"; + reg = <0xfed00000 0x400>; + interrupts = <2 IRQ_TYPE_FIXED_EDGE_RISING 4>; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + tco_wdt: tco_wdt@400 { + compatible = "intel,tco-wdt"; + reg = <0x0400 0x20>; + + status = "disabled"; + }; + + pwm0: pwm0@fd6d0000 { + compatible = "intel,blinky-pwm"; + reg = <0xfd6d0000 0x400>; + reg-offset = <0x204>; + clock-frequency = <32768>; + max-pins = <1>; + #pwm-cells = <2>; + + status = "okay"; + }; + }; +}; diff --git a/dts/x86/intel/raptor_lake_s.dtsi b/dts/x86/intel/raptor_lake_s.dtsi new file mode 100644 index 00000000000..0e55b60a0b3 --- /dev/null +++ b/dts/x86/intel/raptor_lake_s.dtsi @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "skeleton.dtsi" +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "intel,raptor-lake"; + d-cache-line-size = <64>; + reg = <0>; + }; + + }; + + dram0: memory@0 { + device_type = "memory"; + reg = <0x0 DT_DRAM_SIZE>; + }; + + intc: ioapic@fec00000 { + compatible = "intel,ioapic"; + #address-cells = <1>; + #interrupt-cells = <3>; + reg = <0xfec00000 0x1000>; + interrupt-controller; + }; + + intc_loapic: loapic@fee00000 { + compatible = "intel,loapic"; + reg = <0xfee00000 0x1000>; + interrupt-controller; + #interrupt-cells = <3>; + #address-cells = <1>; + }; + + pcie0: pcie0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "pcie-controller"; + acpi-hid = "PNP0A08"; + ranges; + + smbus0: smbus0 { + compatible = "intel,pch-smbus"; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7a23>; + interrupts = ; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + i2c0_dma: i2c0_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "okay"; + }; + + i2c0: i2c0 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7acc>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c0_dma 0>; + + status = "okay"; + }; + + i2c1_dma: i2c1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c1: i2c1 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7acd>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c1_dma 0>; + + status = "disabled"; + }; + + i2c2_dma: i2c2_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c2: i2c2 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7ace>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c2_dma 0>; + + status = "disabled"; + }; + + i2c3_dma: i2c3_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c3: i2c3 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7acf>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c3_dma 0>; + + status = "disabled"; + }; + + i2c4_dma: i2c4_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c4: i2c4 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7afc>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c4_dma 0>; + + status = "disabled"; + }; + + i2c5_dma: i2c5_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c5: i2c5 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7afd>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c5_dma 0>; + + status = "disabled"; + }; + + i2c6_dma: i2c6_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c6: i2c6 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7ada>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c6_dma 0>; + + status = "disabled"; + }; + + i2c7_dma: i2c7_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + i2c7: i2c7 { + compatible = "snps,designware-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + vendor-id = <0x8086>; + device-id = <0x7adb>; + interrupts = ; + interrupt-parent = <&intc>; + dmas = <&i2c7_dma 0>; + + status = "disabled"; + }; + + spi0: spi0 { + compatible = "intel,penwell-spi"; + vendor-id = <0x8086>; + device-id = <0x7aaa>; + #address-cells = <1>; + #size-cells = <0>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_0_i 15 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + status = "okay"; + }; + + spi1: spi1 { + compatible = "intel,penwell-spi"; + vendor-id = <0x8086>; + device-id = <0x7aab>; + #address-cells = <1>; + #size-cells = <0>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_0_i 19 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + + spi2: spi2 { + compatible = "intel,penwell-spi"; + vendor-id = <0x8086>; + device-id = <0x7afb>; + #address-cells = <1>; + #size-cells = <0>; + pw,cs-mode = <0>; + pw,cs-output = <0>; + pw,fifo-depth = <64>; + cs-gpios = <&gpio_0_r 12 GPIO_ACTIVE_LOW>; + clock-frequency = <100000000>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + + uart0_dma: uart0_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + uart0: uart0 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x7aa8>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + dmas = <&uart0_dma 0>, <&uart0_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart1_dma: uart1_dma { + compatible = "intel,lpss"; + #dma-cells = <1>; + status = "disabled"; + }; + + uart1: uart1 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x7aa9>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + dmas = <&uart1_dma 0>, <&uart1_dma 1>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + uart2: uart2 { + compatible = "ns16550"; + vendor-id = <0x8086>; + device-id = <0x7afe>; + reg-shift = <2>; + clock-frequency = <1843200>; + interrupts = ; + interrupt-parent = <&intc>; + current-speed = <115200>; + status = "disabled"; + }; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges; + + vtd: vtd@fed91000 { + compatible = "intel,vt-d"; + reg = <0xfed91000 0x1000>; + + status = "okay"; + }; + + uart_ec_0: uart@3f8 { + compatible = "ns16550"; + reg = <0x000003f8 0x100>; + io-mapped; + clock-frequency = <1843200>; + interrupts = <4 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + reg-shift = <0>; + io-mapped; + status = "okay"; + }; + + gpio_0_i: gpio@e06e0700 { + compatible = "intel,gpio"; + reg = <0xe06e0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <23>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_0_r: gpio@e06e0890 { + compatible = "intel,gpio"; + reg = <0xe06e0890 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <22>; + pin-offset = <26>; + + status = "okay"; + }; + + gpio_0_j: gpio@e06e0a00 { + compatible = "intel,gpio"; + reg = <0xe06e0a00 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <12>; + pin-offset = <49>; + + status = "okay"; + }; + + gpio_1_b: gpio@e06d0700 { + compatible = "intel,gpio"; + reg = <0xe06d0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_1_g: gpio@e06d0880 { + compatible = "intel,gpio"; + reg = <0xe06d0880 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + pin-offset = <24>; + + status = "okay"; + }; + + gpio_1_h: gpio@e06d0900 { + compatible = "intel,gpio"; + reg = <0xe06d0900 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + pin-offset = <32>; + + status = "okay"; + }; + + gpio_3_a: gpio@e06b0790 { + compatible = "intel,gpio"; + reg = <0xe06b0790 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <15>; + pin-offset = <9>; + + status = "okay"; + }; + + gpio_3_c: gpio@e06b0890 { + compatible = "intel,gpio"; + reg = <0xe06b0890 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_4_s: gpio@e06a0700 { + compatible = "intel,gpio"; + reg = <0xe06a0700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + pin-offset = <0>; + + status = "okay"; + }; + + gpio_4_e: gpio@e06a0780 { + compatible = "intel,gpio"; + reg = <0xe06a0780 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x1>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <22>; + pin-offset = <8>; + + status = "okay"; + }; + + gpio_4_k: gpio@e06a08f0 { + compatible = "intel,gpio"; + reg = <0xe06a08f0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x2>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <12>; + pin-offset = <25>; + + status = "okay"; + }; + + gpio_4_f: gpio@e06a09e0 { + compatible = "intel,gpio"; + reg = <0xe06a09e0 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + pin-offset = <41>; + + status = "okay"; + }; + + gpio_5_d: gpio@e0690700 { + compatible = "intel,gpio"; + reg = <0xe0690700 0x1000>; + interrupts = <14 IRQ_TYPE_LOWEST_LEVEL_LOW 3>; + interrupt-parent = <&intc>; + group-index = <0x0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <24>; + pin-offset = <0>; + + status = "okay"; + }; + + pwm0: pwm@e06a0000 { + compatible = "intel,blinky-pwm"; + reg = <0xe06a0000 0x400>; + reg-offset = <0x304>; + clock-frequency = <32768>; + max-pins = <1>; + #pwm-cells = <2>; + status = "okay"; + }; + + rtc: counter: rtc@70 { + compatible = "motorola,mc146818"; + reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + + tgpio: tgpio@fe001200 { + compatible = "intel,timeaware-gpio"; + reg = <0xfe001200 0x100>; + timer-clock = <19200000>; + max-pins = <2>; + status = "okay"; + }; + + hpet: hpet@fed00000 { + compatible = "intel,hpet"; + reg = <0xfed00000 0x400>; + interrupts = <2 IRQ_TYPE_FIXED_EDGE_RISING 4>; + interrupt-parent = <&intc>; + + status = "okay"; + }; + + tco_wdt: tco_wdt@400 { + compatible = "intel,tco-wdt"; + reg = <0x0400 0x20>; + + status = "disabled"; + }; + }; +}; diff --git a/dts/xtensa/espressif/esp32/esp32_net.dtsi b/dts/xtensa/espressif/esp32/esp32_appcpu.dtsi similarity index 100% rename from dts/xtensa/espressif/esp32/esp32_net.dtsi rename to dts/xtensa/espressif/esp32/esp32_appcpu.dtsi diff --git a/dts/xtensa/espressif/esp32/esp32_common.dtsi b/dts/xtensa/espressif/esp32/esp32_common.dtsi index 0f61150cead..b7aba9f2350 100644 --- a/dts/xtensa/espressif/esp32/esp32_common.dtsi +++ b/dts/xtensa/espressif/esp32/esp32_common.dtsi @@ -271,6 +271,14 @@ }; }; + touch: touch@3ff48858 { + compatible = "espressif,esp32-touch"; + reg = <0x3ff48858 0x38>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@3ff53000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; diff --git a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi index b523ec53364..727b26e4a53 100644 --- a/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi +++ b/dts/xtensa/espressif/esp32s2/esp32s2_common.dtsi @@ -184,6 +184,14 @@ ngpios = <22>; /* 32..53 */ }; + touch: touch@3f40885c { + compatible = "espressif,esp32-touch"; + reg = <0x3f40885c 0xc0 0x3f408104 0x18>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@3f413000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi index 3c373272593..27a90f797d0 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi @@ -13,6 +13,11 @@ #include / { + + aliases { + die-temp0 = &coretemp; + }; + chosen { zephyr,canbus = &twai; zephyr,entropy = &trng0; @@ -193,6 +198,14 @@ }; }; + touch: touch@6000885c { + compatible = "espressif,esp32-touch"; + reg = <0x6000885c 0x88 0x60008908 0x18>; + interrupts = ; + interrupt-parent = <&intc>; + status = "disabled"; + }; + i2c0: i2c@60013000 { compatible = "espressif,esp32-i2c"; #address-cells = <1>; @@ -237,6 +250,13 @@ status = "disabled"; }; + coretemp: coretemp@60008800 { + compatible = "espressif,esp32-temp"; + friendly-name = "coretemp"; + reg = <0x60008800 0x4>; + status = "disabled"; + }; + adc0: adc@60040000 { compatible = "espressif,esp32-adc"; reg = <0x60040000 4>; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi new file mode 100644 index 00000000000..c4c0929063d --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n16r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 16MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(16)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi new file mode 100644 index 00000000000..b8f733a3c54 --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n4r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 4MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(4)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi new file mode 100644 index 00000000000..b77169f172b --- /dev/null +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r2.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp32s3_common.dtsi" + +/* 8MB flash */ +&flash0 { + reg = <0x0 DT_SIZE_M(8)>; +}; + +/* 2MB psram */ +&psram0 { + reg = <0x3c000000 DT_SIZE_M(2)>; + status = "okay"; +}; diff --git a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi index eac737e3d61..34ec0ec5ac1 100644 --- a/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi +++ b/dts/xtensa/espressif/esp32s3/esp32s3_wroom_n8r8.dtsi @@ -14,4 +14,5 @@ /* 8MB psram */ &psram0 { reg = <0x3c000000 DT_SIZE_M(8)>; + status = "okay"; }; diff --git a/dts/xtensa/intel/intel_adsp_cavs18.dtsi b/dts/xtensa/intel/intel_adsp_cavs18.dtsi index 4ba04636a47..def86567e75 100644 --- a/dts/xtensa/intel/intel_adsp_cavs18.dtsi +++ b/dts/xtensa/intel/intel_adsp_cavs18.dtsi @@ -140,7 +140,7 @@ reg = <0x78820 0x10>; interrupt-controller; #interrupt-cells = <3>; - interrupts = <0XD 0 0>; + interrupts = <0xD 0 0>; interrupt-parent = <&core_intc>; }; diff --git a/dts/xtensa/nxp/nxp_imx8m.dtsi b/dts/xtensa/nxp/nxp_imx8m.dtsi index 21a094c0461..70bfd500798 100644 --- a/dts/xtensa/nxp/nxp_imx8m.dtsi +++ b/dts/xtensa/nxp/nxp_imx8m.dtsi @@ -17,6 +17,16 @@ device_type = "cpu"; compatible = "cdns,tensilica-xtensa-lx6"; reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + clic: interrupt-controller@0 { + compatible = "cdns,xtensa-core-intc"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <3>; + }; }; }; @@ -33,14 +43,6 @@ }; soc { - interrupt-parent = <&irqsteer>; - - irqsteer: interrupt-controller { - compatible = "nxp,irqsteer-intc"; - interrupt-controller; - #interrupt-cells = <2>; - }; - ccm: ccm@30380000 { compatible = "nxp,imx-ccm"; reg = <0x30380000 DT_SIZE_K(64)>; @@ -67,7 +69,8 @@ /* TODO: This INTID is just a dummy * until we can support UART interrupts */ - interrupts = <29 0>; + interrupt-parent = <&clic>; + interrupts = <29 0 0>; clocks = <&ccm IMX_CCM_UART4_CLK 0x6c 24>; status = "disabled"; }; @@ -75,7 +78,8 @@ mailbox0: mailbox@30e70000 { compatible = "nxp,imx-mu"; reg = <0x30e70000 0x10000>; - interrupts = <7 0>; + interrupt-parent = <&clic>; + interrupts = <7 0 0>; rdc = <0>; status = "disabled"; }; diff --git a/dts/xtensa/nxp/nxp_imx8ulp.dtsi b/dts/xtensa/nxp/nxp_imx8ulp.dtsi new file mode 100644 index 00000000000..71f3de1958b --- /dev/null +++ b/dts/xtensa/nxp/nxp_imx8ulp.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "cdns,tensilica-xtensa-lx7"; + reg = <0>; + }; + }; + + sram0: memory@8e000000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x8e000000 DT_SIZE_K(512)>; + }; + + sram1: memory@8e800000 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x8e800000 DT_SIZE_K(512)>; + }; +}; diff --git a/include/zephyr/acpi/acpi.h b/include/zephyr/acpi/acpi.h index 589cd7d6c4d..0685355e6d1 100644 --- a/include/zephyr/acpi/acpi.h +++ b/include/zephyr/acpi/acpi.h @@ -15,10 +15,30 @@ #define ACPI_DMAR_FLAG_X2APIC_OPT_OUT BIT(1) #define ACPI_DMAR_FLAG_DMA_CTRL_PLATFORM_OPT_IN BIT(2) +#define ACPI_MMIO_GET(res) (res)->reg_base[0].mmio +#define ACPI_IO_GET(res) (res)->reg_base[0].port +#define ACPI_RESOURCE_SIZE_GET(res) (res)->reg_base[0].length +#define ACPI_RESOURCE_TYPE_GET(res) (res)->reg_base[0].type + +#define ACPI_MULTI_MMIO_GET(res, idx) (res)->reg_base[idx].mmio +#define ACPI_MULTI_IO_GET(res, idx) (res)->reg_base[idx].port +#define ACPI_MULTI_RESOURCE_SIZE_GET(res, idx) (res)->reg_base[idx].length +#define ACPI_MULTI_RESOURCE_TYPE_GET(res, idx) (res)->reg_base[idx].type + +#define ACPI_RESOURCE_COUNT_GET(res) (res)->mmio_max + +enum acpi_res_type { + /** IO mapped Resource type */ + ACPI_RES_TYPE_IO, + /** Memory mapped Resource type */ + ACPI_RES_TYPE_MEM, + /** Unknown Resource type */ + ACPI_RES_TYPE_UNKNOWN, +}; + struct acpi_dev { ACPI_HANDLE handle; char *path; - char hid[CONFIG_ACPI_HID_LEN_MAX]; ACPI_RESOURCE *res_lst; int res_type; ACPI_DEVICE_INFO *dev_info; @@ -40,6 +60,72 @@ struct acpi_mcfg { ACPI_MCFG_ALLOCATION pci_segs[]; } __packed; +struct acpi_irq_resource { + uint32_t flags; + union { + uint16_t irq; + uint16_t irqs[CONFIG_ACPI_IRQ_VECTOR_MAX]; + }; + uint8_t irq_vector_max; +}; + +struct acpi_reg_base { + enum acpi_res_type type; + union { + uintptr_t mmio; + uintptr_t port; + }; + uint32_t length; +}; + +struct acpi_mmio_resource { + struct acpi_reg_base reg_base[CONFIG_ACPI_MMIO_ENTRIES_MAX]; + uint8_t mmio_max; +}; + +/** + * @brief Get the ACPI HID for a node + * + * @param node_id DTS node identifier + * @return The HID of the ACPI node + */ +#define ACPI_DT_HID(node_id) DT_PROP(node_id, acpi_hid) + +/** + * @brief Get the ACPI UID for a node if one exist + * + * @param node_id DTS node identifier + * @return The UID of the ACPI node else NULL if does not exist + */ +#define ACPI_DT_UID(node_id) DT_PROP_OR(node_id, acpi_uid, NULL) + +/** + * @brief check whether the node has ACPI HID property or not + * + * @param node_id DTS node identifier + * @return 1 if the node has the HID, 0 otherwise. + */ +#define ACPI_DT_HAS_HID(node_id) DT_NODE_HAS_PROP(node_id, acpi_hid) + +/** + * @brief check whether the node has ACPI UID property or not + * + * @param node_id DTS node identifier + * @return 1 if the node has the UID, 0 otherwise. + */ +#define ACPI_DT_HAS_UID(node_id) DT_NODE_HAS_PROP(node_id, acpi_uid) + +/** + * @brief Init legacy interrupt routing table information from ACPI. + * Currently assume platform have only one PCI bus. + * + * @param hid the hardware id of the ACPI child device + * @param uid the unique id of the ACPI child device. The uid can be + * NULL if only one device with given hid present in the platform. + * @return return 0 on success or error code + */ +int acpi_legacy_irq_init(const char *hid, const char *uid); + /** * @brief Retrieve a legacy interrupt number for a PCI device. * @@ -75,16 +161,6 @@ int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res); */ int acpi_current_resource_free(ACPI_RESOURCE *res); -/** - * @brief Retrieve IRQ routing table of a bus. - * - * @param bus_name the name of the bus - * @param rt_table the IRQ routing table - * @param rt_size number of elements in the IRQ routing table - * @return return 0 on success or error code - */ -int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size); - /** * @brief Parse resource table for a given resource type. * @@ -95,13 +171,14 @@ int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type); /** - * @brief Retrieve acpi device info for given hardware id and unique id. + * @brief Retrieve ACPI device info for given hardware id and unique id. * - * @param hid the hardware id of the acpi child device - * @param inst the unique id of the acpi child device - * @return acpi child device info on success or NULL + * @param hid the hardware id of the ACPI child device + * @param uid the unique id of the ACPI child device. The uid can be + * NULL if only one device with given HID present in the platform. + * @return ACPI child device info on success or NULL */ -struct acpi_dev *acpi_device_get(char *hid, int inst); +struct acpi_dev *acpi_device_get(const char *hid, const char *uid); /** * @brief Retrieve acpi device info from the index. @@ -124,6 +201,24 @@ static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst) return res ? &res->Data.Irq : NULL; } +/** + * @brief Parse resource table for irq info. + * + * @param child_dev the device object of the ACPI node + * @param irq_res irq resource info + * @return return 0 on success or error code + */ +int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res); + +/** + * @brief Parse resource table for MMIO info. + * + * @param child_dev the device object of the ACPI node + * @param mmio_res MMIO resource info + * @return return 0 on success or error code + */ +int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res); + /** * @brief Parse resource table for identify resource type. * @@ -173,6 +268,22 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables); int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope, union acpi_dmar_id *dmar_id, int *num_inst, int max_inst); +typedef void (*dmar_foreach_subtable_func_t)(ACPI_DMAR_HEADER *subtable, void *arg); +typedef void (*dmar_foreach_devscope_func_t)(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg); + +void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, dmar_foreach_subtable_func_t func, + void *arg); +void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, + dmar_foreach_devscope_func_t func, void *arg); + +/** + * @brief Retrieve IOAPIC id + * + * @param ioapic_id IOAPIC id + * @return return 0 on success or error code + */ +int acpi_dmar_ioapic_get(uint16_t *ioapic_id); + /** * @brief Retrieve the 'n'th enabled local apic info. * @@ -180,4 +291,15 @@ int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scop * @return local apic info on success or NULL otherwise */ ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num); + +/** + * @brief invoke an ACPI method and return the result. + * + * @param path the path name of the ACPI object + * @param arg_list the list of arguments to be pass down + * @param ret_obj the ACPI result to be return + * @return return 0 on success or error code + */ +int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj); + #endif diff --git a/include/zephyr/arch/arc/arch.h b/include/zephyr/arch/arc/arch.h index 1eadf5a14b0..1144faa6ebc 100644 --- a/include/zephyr/arch/arc/arch.h +++ b/include/zephyr/arch/arc/arch.h @@ -23,7 +23,7 @@ #include #include "sys-io-common.h" -#include +#include #include #include #include diff --git a/include/zephyr/arch/arc/cluster.h b/include/zephyr/arch/arc/cluster.h new file mode 100644 index 00000000000..8fb535be9ec --- /dev/null +++ b/include/zephyr/arch/arc/cluster.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 Synopsys. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARC Cluster registers and accessors + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ +#define ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ + +#include +#include + +/* Cluster AUX */ +#define _ARC_REG_CLN_BCR 0xcf + +#define _ARC_CLNR_ADDR 0x640 /* CLN address for CLNR_DATA */ +#define _ARC_CLNR_DATA 0x641 /* CLN data indicated by CLNR_ADDR */ +#define _ARC_CLNR_DATA_NXT 0x642 /* CLNR_DATA and then CLNR_ADDR++ */ +#define _ARC_CLNR_BCR_0 0xF61 +#define _ARC_CLNR_BCR_1 0xF62 +#define _ARC_CLNR_BCR_2 0xF63 +#define _ARC_CLNR_SCM_BCR_0 0xF64 +#define _ARC_CLNR_SCM_BCR_1 0xF65 + +#define _ARC_REG_CLN_BCR_VER_MAJOR_ARCV3_MIN 32 /* Minimal version of cluster in ARCv3 */ +#define _ARC_CLN_BCR_VER_MAJOR_MASK 0xff +#define _ARC_CLNR_BCR_0_HAS_SCM BIT(29) + +/* Cluster registers (not in the AUX address space - indirect access via CLNR_ADDR + CLNR_DATA) */ +#define ARC_CLN_MST_NOC_0_BCR 0 +#define ARC_CLN_MST_NOC_1_BCR 1 +#define ARC_CLN_MST_NOC_2_BCR 2 +#define ARC_CLN_MST_NOC_3_BCR 3 +#define ARC_CLN_MST_PER_0_BCR 16 +#define ARC_CLN_MST_PER_1_BCR 17 +#define ARC_CLN_PER_0_BASE 2688 +#define ARC_CLN_PER_0_SIZE 2689 +#define ARC_CLN_PER_1_BASE 2690 +#define ARC_CLN_PER_1_SIZE 2691 + +#define ARC_CLN_SCM_BCR_0 100 +#define ARC_CLN_SCM_BCR_1 101 + +#define ARC_CLN_MST_NOC_0_0_ADDR 292 +#define ARC_CLN_MST_NOC_0_0_SIZE 293 +#define ARC_CLN_MST_NOC_0_1_ADDR 2560 +#define ARC_CLN_MST_NOC_0_1_SIZE 2561 +#define ARC_CLN_MST_NOC_0_2_ADDR 2562 +#define ARC_CLN_MST_NOC_0_2_SIZE 2563 +#define ARC_CLN_MST_NOC_0_3_ADDR 2564 +#define ARC_CLN_MST_NOC_0_3_SIZE 2565 +#define ARC_CLN_MST_NOC_0_4_ADDR 2566 +#define ARC_CLN_MST_NOC_0_4_SIZE 2567 + +#define ARC_CLN_PER0_BASE 2688 +#define ARC_CLN_PER0_SIZE 2689 + +#define ARC_CLN_SHMEM_ADDR 200 +#define ARC_CLN_SHMEM_SIZE 201 +#define ARC_CLN_CACHE_ADDR_LO0 204 +#define ARC_CLN_CACHE_ADDR_LO1 205 +#define ARC_CLN_CACHE_ADDR_HI0 206 +#define ARC_CLN_CACHE_ADDR_HI1 207 +#define ARC_CLN_CACHE_CMD 207 +#define ARC_CLN_CACHE_CMD_OP_NOP 0b0000 +#define ARC_CLN_CACHE_CMD_OP_LOOKUP 0b0001 +#define ARC_CLN_CACHE_CMD_OP_PROBE 0b0010 +#define ARC_CLN_CACHE_CMD_OP_IDX_INV 0b0101 +#define ARC_CLN_CACHE_CMD_OP_IDX_CLN 0b0110 +#define ARC_CLN_CACHE_CMD_OP_IDX_CLN_INV 0b0111 +#define ARC_CLN_CACHE_CMD_OP_REG_INV 0b1001 +#define ARC_CLN_CACHE_CMD_OP_REG_CLN 0b1010 +#define ARC_CLN_CACHE_CMD_OP_REG_CLN_INV 0b1011 +#define ARC_CLN_CACHE_CMD_OP_ADDR_INV 0b1101 +#define ARC_CLN_CACHE_CMD_OP_ADDR_CLN 0b1110 +#define ARC_CLN_CACHE_CMD_OP_ADDR_CLN_INV 0b1111 +#define ARC_CLN_CACHE_CMD_INCR BIT(4) + +#define ARC_CLN_CACHE_STATUS 209 +#define ARC_CLN_CACHE_STATUS_BUSY BIT(23) +#define ARC_CLN_CACHE_STATUS_DONE BIT(24) +#define ARC_CLN_CACHE_STATUS_MASK BIT(26) +#define ARC_CLN_CACHE_STATUS_EN BIT(27) +#define ARC_CLN_CACHE_ERR 210 +#define ARC_CLN_CACHE_ERR_ADDR0 211 +#define ARC_CLN_CACHE_ERR_ADDR1 212 + + +static inline unsigned int arc_cln_read_reg_nolock(unsigned int reg) +{ + z_arc_v2_aux_reg_write(_ARC_CLNR_ADDR, reg); + return z_arc_v2_aux_reg_read(_ARC_CLNR_DATA); +} + +static inline void arc_cln_write_reg_nolock(unsigned int reg, unsigned int data) +{ + z_arc_v2_aux_reg_write(_ARC_CLNR_ADDR, reg); + z_arc_v2_aux_reg_write(_ARC_CLNR_DATA, data); +} + +#endif /* ZEPHYR_INCLUDE_ARCH_ARC_CLUSTER_H_ */ diff --git a/include/zephyr/arch/arc/v2/aux_regs.h b/include/zephyr/arch/arc/v2/aux_regs.h index a2b5d96d8d4..b5e90327177 100644 --- a/include/zephyr/arch/arc/v2/aux_regs.h +++ b/include/zephyr/arch/arc/v2/aux_regs.h @@ -15,6 +15,8 @@ #ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_AUX_REGS_H_ #define ZEPHYR_INCLUDE_ARCH_ARC_V2_AUX_REGS_H_ +#include + #define _ARC_V2_LP_START 0x002 #define _ARC_V2_LP_END 0x003 #define _ARC_V2_IDENTITY 0x004 @@ -173,6 +175,11 @@ #define _ARC_V2_AGU_MOD21 0x5f5 #define _ARC_V2_AGU_MOD22 0x5f6 #define _ARC_V2_AGU_MOD23 0x5f7 +#define _ARC_HW_PF_BUILD 0xf70 +#define _ARC_HW_PF_CTRL 0x4f + +/* _ARC_HW_PF_CTRL bits */ +#define _ARC_HW_PF_CTRL_ENABLE BIT(0) /* STATUS32/STATUS32_P0 bits */ #define _ARC_V2_STATUS32_H (1 << 0) diff --git a/include/zephyr/arch/arc/v2/error.h b/include/zephyr/arch/arc/v2/error.h index edee6fb6aa0..65a85c3e3a7 100644 --- a/include/zephyr/arch/arc/v2/error.h +++ b/include/zephyr/arch/arc/v2/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARC_V2_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/arc/v2/exc.h b/include/zephyr/arch/arc/v2/exc.h deleted file mode 100644 index b5c6a8ddf3e..00000000000 --- a/include/zephyr/arch/arc/v2/exc.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARCv2 public exception handling - * - * ARC-specific kernel exception handling interface. Included by arc/arch.h. - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _ASMLANGUAGE -#else -typedef struct _irq_stack_frame z_arch_esf_t; -#endif - -#ifdef __cplusplus -} -#endif - -/* ARCv2 Exception vector numbers */ -#define ARC_EV_RESET 0x0 -#define ARC_EV_MEM_ERROR 0x1 -#define ARC_EV_INS_ERROR 0x2 -#define ARC_EV_MACHINE_CHECK 0x3 -#define ARC_EV_TLB_MISS_I 0x4 -#define ARC_EV_TLB_MISS_D 0x5 -#define ARC_EV_PROT_V 0x6 -#define ARC_EV_PRIVILEGE_V 0x7 -#define ARC_EV_SWI 0x8 -#define ARC_EV_TRAP 0x9 -#define ARC_EV_EXTENSION 0xA -#define ARC_EV_DIV_ZERO 0xB -#define ARC_EV_DC_ERROR 0xC -#define ARC_EV_MISALIGNED 0xD -#define ARC_EV_VEC_UNIT 0xE - -#endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_EXC_H_ */ diff --git a/include/zephyr/arch/arc/v2/exception.h b/include/zephyr/arch/arc/v2/exception.h new file mode 100644 index 00000000000..553024fa3a8 --- /dev/null +++ b/include/zephyr/arch/arc/v2/exception.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARCv2 public exception handling + * + * ARC-specific kernel exception handling interface. Included by arc/arch.h. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _ASMLANGUAGE +#else +typedef struct _irq_stack_frame z_arch_esf_t; +#endif + +#ifdef __cplusplus +} +#endif + +/* ARCv2 Exception vector numbers */ +#define ARC_EV_RESET 0x0 +#define ARC_EV_MEM_ERROR 0x1 +#define ARC_EV_INS_ERROR 0x2 +#define ARC_EV_MACHINE_CHECK 0x3 +#define ARC_EV_TLB_MISS_I 0x4 +#define ARC_EV_TLB_MISS_D 0x5 +#define ARC_EV_PROT_V 0x6 +#define ARC_EV_PRIVILEGE_V 0x7 +#define ARC_EV_SWI 0x8 +#define ARC_EV_TRAP 0x9 +#define ARC_EV_EXTENSION 0xA +#define ARC_EV_DIV_ZERO 0xB +#define ARC_EV_DC_ERROR 0xC +#define ARC_EV_MISALIGNED 0xD +#define ARC_EV_VEC_UNIT 0xE + +#endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arc/v2/irq.h b/include/zephyr/arch/arc/v2/irq.h index e0b42549597..45b9d138857 100644 --- a/include/zephyr/arch/arc/v2/irq.h +++ b/include/zephyr/arch/arc/v2/irq.h @@ -77,7 +77,7 @@ extern void z_irq_priority_set(unsigned int irq, unsigned int prio, */ #define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ { \ - Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p, ISR_FLAG_DIRECT, isr_p); \ BUILD_ASSERT(priority_p || !IS_ENABLED(CONFIG_ARC_FIRQ) || \ (IS_ENABLED(CONFIG_ARC_FIRQ_STACK) && \ !IS_ENABLED(CONFIG_ARC_STACK_CHECKING)), \ diff --git a/include/zephyr/arch/arm/arch.h b/include/zephyr/arch/arm/arch.h index a726bba8502..804e1d23dbd 100644 --- a/include/zephyr/arch/arm/arch.h +++ b/include/zephyr/arch/arm/arch.h @@ -13,8 +13,8 @@ * (include/arm/cpu.h) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ /* Add include for DTS generated information */ #include @@ -23,7 +23,7 @@ #define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } #include -#include +#include #include #include #include @@ -32,6 +32,9 @@ #include #include #include +#if defined(CONFIG_GDBSTUB) +#include +#endif #ifdef CONFIG_CPU_CORTEX_M #include @@ -279,4 +282,4 @@ enum k_fatal_error_reason_arch { } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ARCH_H_ */ diff --git a/include/zephyr/arch/arm/arch_inlines.h b/include/zephyr/arch/arm/arch_inlines.h index 96822e0eff1..f5149799adf 100644 --- a/include/zephyr/arch/arm/arch_inlines.h +++ b/include/zephyr/arch/arm/arch_inlines.h @@ -4,18 +4,28 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H +#define ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H #include +#if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include #include static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) { - /* Dummy implementation always return the first cpu */ return (_cpu_t *)(read_tpidruro() & TPIDRURO_CURR_CPU); } +#else + +#ifndef CONFIG_SMP +static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) +{ + /* Dummy implementation always return the first cpu */ + return &_kernel.cpus[0]; +} +#endif +#endif static ALWAYS_INLINE uint32_t arch_proc_id(void) { @@ -31,4 +41,4 @@ static ALWAYS_INLINE unsigned int arch_num_cpus(void) return CONFIG_MP_MAX_NUM_CPUS; } -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ARCH_INLINES_H */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ARCH_INLINES_H */ diff --git a/include/zephyr/arch/arm/asm_inline.h b/include/zephyr/arch/arm/asm_inline.h index c083adcd47a..fe36fb2d0e1 100644 --- a/include/zephyr/arch/arm/asm_inline.h +++ b/include/zephyr/arch/arm/asm_inline.h @@ -6,8 +6,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ /* * The file must not be included directly @@ -20,4 +20,4 @@ #include #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ */ diff --git a/include/zephyr/arch/arm/asm_inline_gcc.h b/include/zephyr/arch/arm/asm_inline_gcc.h index 3b8e8e19c92..77729149e36 100644 --- a/include/zephyr/arch/arm/asm_inline_gcc.h +++ b/include/zephyr/arch/arm/asm_inline_gcc.h @@ -8,8 +8,8 @@ /* Either public functions or macros or invoked by public functions */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ /* * The file must not be included directly @@ -20,7 +20,7 @@ #include #include -#include +#include #if defined(CONFIG_CPU_AARCH32_CORTEX_R) || defined(CONFIG_CPU_AARCH32_CORTEX_A) #include @@ -126,4 +126,4 @@ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ASM_INLINE_GCC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_GCC_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/cpu.h b/include/zephyr/arch/arm/cortex_a_r/cpu.h index 806d28247ac..61e520ffc23 100644 --- a/include/zephyr/arch/arm/cortex_a_r/cpu.h +++ b/include/zephyr/arch/arm/cortex_a_r/cpu.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ #if defined(CONFIG_ARM_MPU) #include @@ -116,4 +116,4 @@ (((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \ ((_tgt) & SGIR_TGT_MASK)) -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_CPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_CPU_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/exc.h b/include/zephyr/arch/arm/cortex_a_r/exc.h deleted file mode 100644 index 92f074f1b36..00000000000 --- a/include/zephyr/arch/arm/cortex_a_r/exc.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM AArch32 Cortex-A and Cortex-R public exception handling - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ - -#ifdef _ASMLANGUAGE -GTEXT(z_arm_exc_exit); -#else -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) - -/* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls. - * - * Registers s0-s15 (d0-d7, q0-q3) do not have to be preserved (and can be used - * for passing arguments or returning results in standard procedure-call variants). - * - * Registers d16-d31 (q8-q15), do not have to be preserved. - */ -struct __fpu_sf { - uint32_t s[16]; /* s0~s15 (d0-d7) */ -#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 - uint64_t d[16]; /* d16~d31 */ -#endif - uint32_t fpscr; - uint32_t undefined; -}; -#endif - -/* Additional register state that is not stacked by hardware on exception - * entry. - * - * These fields are ONLY valid in the ESF copy passed into z_arm_fatal_error(). - * When information for a member is unavailable, the field is set to zero. - */ -#if defined(CONFIG_EXTRA_EXCEPTION_INFO) -struct __extra_esf_info { - _callee_saved_t *callee; - uint32_t msp; - uint32_t exc_return; -}; -#endif /* CONFIG_EXTRA_EXCEPTION_INFO */ - -struct __esf { -#if defined(CONFIG_EXTRA_EXCEPTION_INFO) - struct __extra_esf_info extra_info; -#endif -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) - struct __fpu_sf fpu; -#endif - struct __basic_sf { - sys_define_gpr_with_alias(a1, r0); - sys_define_gpr_with_alias(a2, r1); - sys_define_gpr_with_alias(a3, r2); - sys_define_gpr_with_alias(a4, r3); - sys_define_gpr_with_alias(ip, r12); - sys_define_gpr_with_alias(lr, r14); - sys_define_gpr_with_alias(pc, r15); - uint32_t xpsr; - } basic; -}; - -extern uint32_t z_arm_coredump_fault_sp; - -typedef struct __esf z_arch_esf_t; - -extern void z_arm_exc_exit(bool fatal); - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_EXC_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/exception.h b/include/zephyr/arch/arm/cortex_a_r/exception.h new file mode 100644 index 00000000000..3bef647566d --- /dev/null +++ b/include/zephyr/arch/arm/cortex_a_r/exception.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM AArch32 Cortex-A and Cortex-R public exception handling + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ + +#ifdef _ASMLANGUAGE +GTEXT(z_arm_exc_exit); +#else +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + +/* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls. + * + * Registers s0-s15 (d0-d7, q0-q3) do not have to be preserved (and can be used + * for passing arguments or returning results in standard procedure-call variants). + * + * Registers d16-d31 (q8-q15), do not have to be preserved. + */ +struct __fpu_sf { + uint32_t s[16]; /* s0~s15 (d0-d7) */ +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + uint64_t d[16]; /* d16~d31 */ +#endif + uint32_t fpscr; + uint32_t undefined; +}; +#endif + +/* Additional register state that is not stacked by hardware on exception + * entry. + * + * These fields are ONLY valid in the ESF copy passed into z_arm_fatal_error(). + * When information for a member is unavailable, the field is set to zero. + */ +#if defined(CONFIG_EXTRA_EXCEPTION_INFO) +struct __extra_esf_info { + _callee_saved_t *callee; + uint32_t msp; + uint32_t exc_return; +}; +#endif /* CONFIG_EXTRA_EXCEPTION_INFO */ + +struct __esf { +#if defined(CONFIG_EXTRA_EXCEPTION_INFO) + struct __extra_esf_info extra_info; +#endif +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + struct __fpu_sf fpu; +#endif + struct __basic_sf { + sys_define_gpr_with_alias(a1, r0); + sys_define_gpr_with_alias(a2, r1); + sys_define_gpr_with_alias(a3, r2); + sys_define_gpr_with_alias(a4, r3); + sys_define_gpr_with_alias(ip, r12); + sys_define_gpr_with_alias(lr, r14); + sys_define_gpr_with_alias(pc, r15); + uint32_t xpsr; + } basic; +}; + +extern uint32_t z_arm_coredump_fault_sp; + +typedef struct __esf z_arch_esf_t; + +extern void z_arm_exc_exit(bool fatal); + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h b/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h index 7b89ddf515c..983654ce138 100644 --- a/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h +++ b/include/zephyr/arch/arm/cortex_a_r/lib_helpers.h @@ -7,8 +7,8 @@ * */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ #ifndef _ASMLANGUAGE @@ -103,4 +103,4 @@ MAKE_REG_HELPER(ICC_IGRPEN1_EL1, 0, 12, 12, 7); #define wfe() __asm__ volatile("wfe" : : : "memory") #endif /* !_ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_LIB_HELPERS_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_LIB_HELPERS_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld index a27dd55a8cf..947c18de313 100644 --- a/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld @@ -32,10 +32,16 @@ #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 - #define ROM_SIZE CONFIG_FLASH_LOAD_SIZE + #define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else - #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET) + #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #if defined(CONFIG_XIP) @@ -75,13 +81,15 @@ _region_min_align = 4; #define BSS_ALIGN ALIGN(_region_min_align) +#define MMU_ALIGN . = ALIGN(_region_min_align) + MEMORY { FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF8000, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) diff --git a/include/zephyr/arch/arm/cortex_a_r/sys_io.h b/include/zephyr/arch/arm/cortex_a_r/sys_io.h index c4598302aae..888e328e6b2 100644 --- a/include/zephyr/arch/arm/cortex_a_r/sys_io.h +++ b/include/zephyr/arch/arm/cortex_a_r/sys_io.h @@ -9,8 +9,8 @@ * gcc builtins) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ #ifndef _ASMLANGUAGE @@ -88,4 +88,4 @@ static ALWAYS_INLINE uint64_t sys_read64(mem_addr_t addr) #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_SYS_IO_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_SYS_IO_H_ */ diff --git a/include/zephyr/arch/arm/cortex_a_r/timer.h b/include/zephyr/arch/arm/cortex_a_r/timer.h index d513ecdffc8..6cd10c5d8e0 100644 --- a/include/zephyr/arch/arm/cortex_a_r/timer.h +++ b/include/zephyr/arch/arm/cortex_a_r/timer.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ #ifdef CONFIG_ARM_ARCH_TIMER @@ -149,4 +149,4 @@ static ALWAYS_INLINE uint64_t arm_arch_timer_count(void) #endif /* CONFIG_ARM_ARCH_TIMER */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_A_R_TIMER_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_A_R_TIMER_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/exc.h b/include/zephyr/arch/arm/cortex_m/exc.h deleted file mode 100644 index 8a2cfc8cc3f..00000000000 --- a/include/zephyr/arch/arm/cortex_m/exc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM AArch32 Cortex-M public exception handling - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ - -#include - -#include - -/* for assembler, only works with constants */ -#define Z_EXC_PRIO(pri) (((pri) << (8 - NUM_IRQ_PRIO_BITS)) & 0xff) - -/* - * In architecture variants with non-programmable fault exceptions - * (e.g. Cortex-M Baseline variants), hardware ensures processor faults - * are given the highest interrupt priority level. SVCalls are assigned - * the highest configurable priority level (level 0); note, however, that - * this interrupt level may be shared with HW interrupts. - * - * In Cortex variants with programmable fault exception priorities we - * assign the highest interrupt priority level (level 0) to processor faults - * with configurable priority. - * The highest priority level may be shared with either Zero-Latency IRQs (if - * support for the feature is enabled) or with SVCall priority level. - * Regular HW IRQs are always assigned priority levels lower than the priority - * levels for SVCalls, Zero-Latency IRQs and processor faults. - * - * PendSV IRQ (which is used in Cortex-M variants to implement thread - * context-switching) is assigned the lowest IRQ priority level. - */ -#if defined(CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS) -#define _EXCEPTION_RESERVED_PRIO 1 -#else -#define _EXCEPTION_RESERVED_PRIO 0 -#endif - -#define _EXC_FAULT_PRIO 0 -#define _EXC_ZERO_LATENCY_IRQS_PRIO 0 -#define _EXC_SVC_PRIO COND_CODE_1(CONFIG_ZERO_LATENCY_IRQS, \ - (CONFIG_ZERO_LATENCY_LEVELS), (0)) -#define _IRQ_PRIO_OFFSET (_EXCEPTION_RESERVED_PRIO + _EXC_SVC_PRIO) -#define IRQ_PRIO_LOWEST (BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET) - 1) - -#define _EXC_IRQ_DEFAULT_PRIO Z_EXC_PRIO(_IRQ_PRIO_OFFSET) - -/* Use lowest possible priority level for PendSV */ -#define _EXC_PENDSV_PRIO 0xff -#define _EXC_PENDSV_PRIO_MASK Z_EXC_PRIO(_EXC_PENDSV_PRIO) - -#ifdef _ASMLANGUAGE -GTEXT(z_arm_exc_exit); -#else -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) - -/* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls. - * - * Registers s0-s15 (d0-d7, q0-q3) do not have to be preserved (and can be used - * for passing arguments or returning results in standard procedure-call variants). - * - * Registers d16-d31 (q8-q15), do not have to be preserved. - */ -struct __fpu_sf { - uint32_t s[16]; /* s0~s15 (d0-d7) */ -#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 - uint64_t d[16]; /* d16~d31 */ -#endif - uint32_t fpscr; - uint32_t undefined; -}; -#endif - -/* Additional register state that is not stacked by hardware on exception - * entry. - * - * These fields are ONLY valid in the ESF copy passed into z_arm_fatal_error(). - * When information for a member is unavailable, the field is set to zero. - */ -#if defined(CONFIG_EXTRA_EXCEPTION_INFO) -struct __extra_esf_info { - _callee_saved_t *callee; - uint32_t msp; - uint32_t exc_return; -}; -#endif /* CONFIG_EXTRA_EXCEPTION_INFO */ - -struct __esf { - struct __basic_sf { - sys_define_gpr_with_alias(a1, r0); - sys_define_gpr_with_alias(a2, r1); - sys_define_gpr_with_alias(a3, r2); - sys_define_gpr_with_alias(a4, r3); - sys_define_gpr_with_alias(ip, r12); - sys_define_gpr_with_alias(lr, r14); - sys_define_gpr_with_alias(pc, r15); - uint32_t xpsr; - } basic; -#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) - struct __fpu_sf fpu; -#endif -#if defined(CONFIG_EXTRA_EXCEPTION_INFO) - struct __extra_esf_info extra_info; -#endif -}; - -extern uint32_t z_arm_coredump_fault_sp; - -typedef struct __esf z_arch_esf_t; - -extern void z_arm_exc_exit(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_EXC_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/exception.h b/include/zephyr/arch/arm/cortex_m/exception.h new file mode 100644 index 00000000000..a9896cea1e4 --- /dev/null +++ b/include/zephyr/arch/arm/cortex_m/exception.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM AArch32 Cortex-M public exception handling + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ + +#include + +#include + +/* for assembler, only works with constants */ +#define Z_EXC_PRIO(pri) (((pri) << (8 - NUM_IRQ_PRIO_BITS)) & 0xff) + +/* + * In architecture variants with non-programmable fault exceptions + * (e.g. Cortex-M Baseline variants), hardware ensures processor faults + * are given the highest interrupt priority level. SVCalls are assigned + * the highest configurable priority level (level 0); note, however, that + * this interrupt level may be shared with HW interrupts. + * + * In Cortex variants with programmable fault exception priorities we + * assign the highest interrupt priority level (level 0) to processor faults + * with configurable priority. + * The highest priority level may be shared with either Zero-Latency IRQs (if + * support for the feature is enabled) or with SVCall priority level. + * Regular HW IRQs are always assigned priority levels lower than the priority + * levels for SVCalls, Zero-Latency IRQs and processor faults. + * + * PendSV IRQ (which is used in Cortex-M variants to implement thread + * context-switching) is assigned the lowest IRQ priority level. + */ +#if defined(CONFIG_CPU_CORTEX_M_HAS_PROGRAMMABLE_FAULT_PRIOS) +#define _EXCEPTION_RESERVED_PRIO 1 +#else +#define _EXCEPTION_RESERVED_PRIO 0 +#endif + +#define _EXC_FAULT_PRIO 0 +#define _EXC_ZERO_LATENCY_IRQS_PRIO 0 +#define _EXC_SVC_PRIO COND_CODE_1(CONFIG_ZERO_LATENCY_IRQS, \ + (CONFIG_ZERO_LATENCY_LEVELS), (0)) +#define _IRQ_PRIO_OFFSET (_EXCEPTION_RESERVED_PRIO + _EXC_SVC_PRIO) +#define IRQ_PRIO_LOWEST (BIT(NUM_IRQ_PRIO_BITS) - (_IRQ_PRIO_OFFSET) - 1) + +#define _EXC_IRQ_DEFAULT_PRIO Z_EXC_PRIO(_IRQ_PRIO_OFFSET) + +/* Use lowest possible priority level for PendSV */ +#define _EXC_PENDSV_PRIO 0xff +#define _EXC_PENDSV_PRIO_MASK Z_EXC_PRIO(_EXC_PENDSV_PRIO) + +#ifdef _ASMLANGUAGE +GTEXT(z_arm_exc_exit); +#else +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + +/* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls. + * + * Registers s0-s15 (d0-d7, q0-q3) do not have to be preserved (and can be used + * for passing arguments or returning results in standard procedure-call variants). + * + * Registers d16-d31 (q8-q15), do not have to be preserved. + */ +struct __fpu_sf { + uint32_t s[16]; /* s0~s15 (d0-d7) */ +#ifdef CONFIG_VFP_FEATURE_REGS_S64_D32 + uint64_t d[16]; /* d16~d31 */ +#endif + uint32_t fpscr; + uint32_t undefined; +}; +#endif + +/* Additional register state that is not stacked by hardware on exception + * entry. + * + * These fields are ONLY valid in the ESF copy passed into z_arm_fatal_error(). + * When information for a member is unavailable, the field is set to zero. + */ +#if defined(CONFIG_EXTRA_EXCEPTION_INFO) +struct __extra_esf_info { + _callee_saved_t *callee; + uint32_t msp; + uint32_t exc_return; +}; +#endif /* CONFIG_EXTRA_EXCEPTION_INFO */ + +struct __esf { + struct __basic_sf { + sys_define_gpr_with_alias(a1, r0); + sys_define_gpr_with_alias(a2, r1); + sys_define_gpr_with_alias(a3, r2); + sys_define_gpr_with_alias(a4, r3); + sys_define_gpr_with_alias(ip, r12); + sys_define_gpr_with_alias(lr, r14); + sys_define_gpr_with_alias(pc, r15); + uint32_t xpsr; + } basic; +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + struct __fpu_sf fpu; +#endif +#if defined(CONFIG_EXTRA_EXCEPTION_INFO) + struct __extra_esf_info extra_info; +#endif +}; + +extern uint32_t z_arm_coredump_fault_sp; + +typedef struct __esf z_arch_esf_t; + +extern void z_arm_exc_exit(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/fpu.h b/include/zephyr/arch/arm/cortex_m/fpu.h index 17f75cec50e..cf01fddf4f9 100644 --- a/include/zephyr/arch/arm/cortex_m/fpu.h +++ b/include/zephyr/arch/arm/cortex_m/fpu.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ struct fpu_ctx_full { uint32_t caller_saved[16]; @@ -17,4 +17,4 @@ struct fpu_ctx_full { void z_arm_save_fp_context(struct fpu_ctx_full *buffer); void z_arm_restore_fp_context(const struct fpu_ctx_full *buffer); -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_FPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_FPU_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/memory_map.h b/include/zephyr/arch/arm/cortex_m/memory_map.h index 82310273019..b73a77f10ea 100644 --- a/include/zephyr/arch/arm/cortex_m/memory_map.h +++ b/include/zephyr/arch/arm/cortex_m/memory_map.h @@ -12,8 +12,8 @@ * processors. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ #include @@ -110,4 +110,4 @@ #define _VENDOR_BASE_ADDR 0xE0100000 #define _VENDOR_END_ADDR 0xFFFFFFFF -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_MEMORY_MAP_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_MEMORY_MAP_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/nvic.h b/include/zephyr/arch/arm/cortex_m/nvic.h index caececd3c0d..947bfb6eaf5 100644 --- a/include/zephyr/arch/arm/cortex_m/nvic.h +++ b/include/zephyr/arch/arm/cortex_m/nvic.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ #include @@ -25,4 +25,4 @@ #define NUM_IRQ_PRIO_BITS DT_PROP(NVIC_NODEID, arm_num_irq_priority_bits) -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_NVIC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_CORTEX_M_NVIC_H_ */ diff --git a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld index 5050c778627..14eb78f3e70 100644 --- a/include/zephyr/arch/arm/cortex_m/scripts/linker.ld +++ b/include/zephyr/arch/arm/cortex_m/scripts/linker.ld @@ -61,10 +61,16 @@ _image_1_primary_slot_id = PM_S1_ID; #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 -#define ROM_SIZE CONFIG_FLASH_LOAD_SIZE +#define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else -#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - CONFIG_FLASH_LOAD_OFFSET) +#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #if defined(CONFIG_XIP) @@ -132,7 +138,7 @@ MEMORY #endif LINKER_DT_REGIONS() /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF7FFF, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) @@ -436,6 +442,11 @@ GROUP_START(ITCM) __itcm_start = .; *(.itcm) *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __itcm_end = .; } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) @@ -470,6 +481,11 @@ GROUP_START(DTCM) __dtcm_data_start = .; *(.dtcm_data) *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __dtcm_data_end = .; } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) diff --git a/include/zephyr/arch/arm/error.h b/include/zephyr/arch/arm/error.h index 603e1d00088..a30c674c4ff 100644 --- a/include/zephyr/arch/arm/error.h +++ b/include/zephyr/arch/arm/error.h @@ -12,11 +12,11 @@ * arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus @@ -83,4 +83,4 @@ do { \ } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_ERROR_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ERROR_H_ */ diff --git a/include/zephyr/arch/arm/exc.h b/include/zephyr/arch/arm/exc.h deleted file mode 100644 index 9cd664e2c6b..00000000000 --- a/include/zephyr/arch/arm/exc.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM AArch32 public exception handling - * - * ARM AArch32-specific kernel exception handling interface. Included by - * arm/arch.h. - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ - -#if defined(CONFIG_CPU_CORTEX_M) -#include -#elif defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) -#include -#else -#error Unknown ARM architecture -#endif /* CONFIG_CPU_CORTEX_M */ - -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_EXC_H_ */ diff --git a/include/zephyr/arch/arm/exception.h b/include/zephyr/arch/arm/exception.h new file mode 100644 index 00000000000..cc20225e483 --- /dev/null +++ b/include/zephyr/arch/arm/exception.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013-2014 Wind River Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM AArch32 public exception handling + * + * ARM AArch32-specific kernel exception handling interface. Included by + * arm/arch.h. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ + +#if defined(CONFIG_CPU_CORTEX_M) +#include +#elif defined(CONFIG_CPU_AARCH32_CORTEX_A) || defined(CONFIG_CPU_AARCH32_CORTEX_R) +#include +#else +#error Unknown ARM architecture +#endif /* CONFIG_CPU_CORTEX_M */ + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm/gdbstub.h b/include/zephyr/arch/arm/gdbstub.h new file mode 100644 index 00000000000..e8e606d7def --- /dev/null +++ b/include/zephyr/arch/arm/gdbstub.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Marek Vedral + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_GDBSTUB_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_GDBSTUB_H_ + +#include + +#ifndef _ASMLANGUAGE + +#define DBGDSCR_MONITOR_MODE_EN 0x8000 + +#define SPSR_ISETSTATE_ARM 0x0 +#define SPSR_ISETSTATE_JAZELLE 0x2 +#define SPSR_J 24 +#define SPSR_T 5 + +/* Debug Breakpoint Control Register constants */ +#define DBGDBCR_MEANING_MASK 0x7 +#define DBGDBCR_MEANING_SHIFT 20 +#define DBGDBCR_MEANING_ADDR_MISMATCH 0x4 +#define DBGDBCR_BYTE_ADDR_MASK 0xF +#define DBGDBCR_BYTE_ADDR_SHIFT 5 +#define DBGDBCR_BRK_EN_MASK 0x1 + +/* Regno of the SPSR */ +#define SPSR_REG_IDX 25 +/* Minimal size of the packet - SPSR is the last, 42-nd byte, see packet_pos array */ +#define GDB_READALL_PACKET_SIZE (42 * 8) + +#define IFSR_DEBUG_EVENT 0x2 + +enum AARCH32_GDB_REG { + R0 = 0, + R1, + R2, + R3, + /* READONLY registers (R4 - R13) except R12 */ + R4, + R5, + R6, + R7, + R8, + R9, + R10, + R11, + R12, + /* Stack pointer - READONLY */ + R13, + LR, + PC, + /* Saved program status register */ + SPSR, + GDB_NUM_REGS +}; + +/* required structure */ +struct gdb_ctx { + /* cause of the exception */ + unsigned int exception; + unsigned int registers[GDB_NUM_REGS]; +}; + +void z_gdb_entry(z_arch_esf_t *esf, unsigned int exc_cause); + +#endif + +#endif diff --git a/include/zephyr/arch/arm/irq.h b/include/zephyr/arch/arm/irq.h index 357c91a83ae..31cfce1e667 100644 --- a/include/zephyr/arch/arm/irq.h +++ b/include/zephyr/arch/arm/irq.h @@ -13,8 +13,8 @@ * arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ #include #include @@ -127,7 +127,7 @@ extern void z_arm_interrupt_init(void); BUILD_ASSERT(IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) || !(flags_p & IRQ_ZERO_LATENCY), \ "ZLI interrupt registered but feature is disabled"); \ _CHECK_PRIO(priority_p, flags_p) \ - Z_ISR_DECLARE(irq_p, ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p, ISR_FLAG_DIRECT, isr_p); \ z_arm_irq_priority_set(irq_p, priority_p, flags_p); \ } @@ -254,4 +254,4 @@ typedef enum { } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_IRQ_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_IRQ_H_ */ diff --git a/include/zephyr/arch/arm/misc.h b/include/zephyr/arch/arm/misc.h index ab67a35e94c..99f99b59b2b 100644 --- a/include/zephyr/arch/arm/misc.h +++ b/include/zephyr/arch/arm/misc.h @@ -11,8 +11,8 @@ * ARM AArch32-specific kernel miscellaneous interface. Included by arm/arch.h. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ #ifdef __cplusplus extern "C" { @@ -66,4 +66,4 @@ void z_arm_on_enter_cpu_idle_prepare(void); } #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MISC_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MISC_H_ */ diff --git a/include/zephyr/arch/arm/mmu/arm_mmu.h b/include/zephyr/arch/arm/mmu/arm_mmu.h index a4f0fe34b4d..4179436615d 100644 --- a/include/zephyr/arch/arm/mmu/arm_mmu.h +++ b/include/zephyr/arch/arm/mmu/arm_mmu.h @@ -67,6 +67,45 @@ #define MMU_REGION_FLAT_ENTRY(name, adr, sz, attrs) \ MMU_REGION_ENTRY(name, adr, adr, sz, attrs) +/* + * @brief Auto generate mmu region entry for node_id + * + * Example usage: + * + * @code{.c} + * DT_FOREACH_STATUS_OKAY_VARGS(nxp_imx_gpio, + * MMU_REGION_DT_FLAT_ENTRY, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note Since devicetree_generated.h does not include + * node_id##_P_reg_FOREACH_PROP_ELEM* definitions, + * we can't automate dts node with multiple reg + * entries. + */ +#define MMU_REGION_DT_FLAT_ENTRY(node_id, attrs) \ + MMU_REGION_FLAT_ENTRY(DT_NODE_FULL_NAME(node_id), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + attrs), + +/* + * @brief Auto generate mmu region entry for status = "okay" + * nodes compatible to a driver + * + * Example usage: + * + * @code{.c} + * MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_gpio, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note This is a wrapper of @ref MMU_REGION_DT_FLAT_ENTRY + */ +#define MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(compat, attr) \ + DT_FOREACH_STATUS_OKAY_VARGS(compat, \ + MMU_REGION_DT_FLAT_ENTRY, attr) + /* Region definition data structure */ struct arm_mmu_region { /* Region Base Physical Address */ diff --git a/include/zephyr/arch/arm/mpu/arm_mpu.h b/include/zephyr/arch/arm/mpu/arm_mpu.h index 857465a4824..9a8ffc7a724 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \ defined(CONFIG_CPU_CORTEX_M3) || \ @@ -74,4 +74,4 @@ extern const struct arm_mpu_config mpu_config; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_ARM_MPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_ARM_MPU_H_ */ diff --git a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h index cf60cca99da..11d4a2e7547 100644 --- a/include/zephyr/arch/arm/mpu/arm_mpu_v8.h +++ b/include/zephyr/arch/arm/mpu/arm_mpu_v8.h @@ -220,7 +220,14 @@ .mair_idx = MPU_MAIR_INDEX_SRAM, \ .r_limit = limit - 1, /* Region Limit */ \ } - +#define REGION_RAM_NOCACHE_ATTR(limit) \ + { \ + .rbar = NOT_EXEC | \ + P_RW_U_NA_Msk | NON_SHAREABLE_Msk, /* AP, XN, SH */ \ + /* Cache-ability */ \ + .mair_idx = MPU_MAIR_INDEX_SRAM_NOCACHE, \ + .r_limit = limit - 1, /* Region Limit */ \ + } #if defined(CONFIG_MPU_ALLOW_FLASH_WRITE) /* Note that the access permissions allow for un-privileged writes, contrary * to ARMv7-M where un-privileged code has Read-Only permissions. diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index d1f5882bfed..b9556565802 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -3,8 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ #ifndef _ASMLANGUAGE @@ -266,4 +266,4 @@ extern const struct nxp_mpu_config mpu_config; "start address of the partition must align with minimum MPU \ region size.") -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_MPU_NXP_MPU_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_MPU_NXP_MPU_H_ */ diff --git a/include/zephyr/arch/arm/nmi.h b/include/zephyr/arch/arm/nmi.h index a4bd85802c1..33f46084248 100644 --- a/include/zephyr/arch/arm/nmi.h +++ b/include/zephyr/arch/arm/nmi.h @@ -10,11 +10,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ #if !defined(_ASMLANGUAGE) && defined(CONFIG_RUNTIME_NMI) extern void z_arm_nmi_set_handler(void (*pHandler)(void)); #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_NMI_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_NMI_H_ */ diff --git a/include/zephyr/arch/arm/syscall.h b/include/zephyr/arch/arm/syscall.h index a4e067307ec..e07dab12a9e 100644 --- a/include/zephyr/arch/arm/syscall.h +++ b/include/zephyr/arch/arm/syscall.h @@ -13,8 +13,8 @@ * (include/arch/syscall.h) */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ #define _SVC_CALL_CONTEXT_SWITCH 0 #define _SVC_CALL_IRQ_OFFLOAD 1 @@ -184,4 +184,4 @@ static inline bool arch_is_user_context(void) #endif /* _ASMLANGUAGE */ #endif /* CONFIG_USERSPACE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_SYSCALL_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_SYSCALL_H_ */ diff --git a/include/zephyr/arch/arm/thread.h b/include/zephyr/arch/arm/thread.h index b4d34b137cb..139f606809f 100644 --- a/include/zephyr/arch/arm/thread.h +++ b/include/zephyr/arch/arm/thread.h @@ -16,8 +16,8 @@ * necessary to instantiate instances of struct k_thread. */ -#ifndef ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ #ifndef _ASMLANGUAGE #include @@ -143,4 +143,4 @@ typedef struct _thread_arch _thread_arch_t; #endif /* _ASMLANGUAGE */ -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_THREAD_H_ */ +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_THREAD_H_ */ diff --git a/include/zephyr/arch/arm64/arch.h b/include/zephyr/arch/arm64/arch.h index c181b08f55e..1f38bd84a2f 100644 --- a/include/zephyr/arch/arm64/arch.h +++ b/include/zephyr/arch/arm64/arch.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/zephyr/arch/arm64/arm_mmu.h b/include/zephyr/arch/arm64/arm_mmu.h index 6f71ac25897..b0c197b9b2b 100644 --- a/include/zephyr/arch/arm64/arm_mmu.h +++ b/include/zephyr/arch/arm64/arm_mmu.h @@ -207,6 +207,45 @@ struct arm_mmu_ptables { #define MMU_REGION_FLAT_ENTRY(name, adr, sz, attrs) \ MMU_REGION_ENTRY(name, adr, adr, sz, attrs) +/* + * @brief Auto generate mmu region entry for node_id + * + * Example usage: + * + * @code{.c} + * DT_FOREACH_STATUS_OKAY_VARGS(nxp_imx_gpio, + * MMU_REGION_DT_FLAT_ENTRY, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note Since devicetree_generated.h does not include + * node_id##_P_reg_FOREACH_PROP_ELEM* definitions, + * we can't automate dts node with multiple reg + * entries. + */ +#define MMU_REGION_DT_FLAT_ENTRY(node_id, attrs) \ + MMU_REGION_FLAT_ENTRY(DT_NODE_FULL_NAME(node_id), \ + DT_REG_ADDR(node_id), \ + DT_REG_SIZE(node_id), \ + attrs), + +/* + * @brief Auto generate mmu region entry for status = "okay" + * nodes compatible to a driver + * + * Example usage: + * + * @code{.c} + * MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_gpio, + * (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + * @endcode + * + * @note This is a wrapper of @ref MMU_REGION_DT_FLAT_ENTRY + */ +#define MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(compat, attr) \ + DT_FOREACH_STATUS_OKAY_VARGS(compat, \ + MMU_REGION_DT_FLAT_ENTRY, attr) + /* Kernel macros for memory attribution * (access permissions and cache-ability). * diff --git a/include/zephyr/arch/arm64/error.h b/include/zephyr/arch/arm64/error.h index 34565107d08..d4d15fc3e99 100644 --- a/include/zephyr/arch/arm64/error.h +++ b/include/zephyr/arch/arm64/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_ARM64_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/arm64/exc.h b/include/zephyr/arch/arm64/exc.h deleted file mode 100644 index 5a46671d157..00000000000 --- a/include/zephyr/arch/arm64/exc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019 Carlo Caione - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Cortex-A public exception handling - * - * ARM-specific kernel exception handling interface. Included by arm64/arch.h. - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ - -/* for assembler, only works with constants */ - -#ifdef _ASMLANGUAGE -#else -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct __esf { - uint64_t x0; - uint64_t x1; - uint64_t x2; - uint64_t x3; - uint64_t x4; - uint64_t x5; - uint64_t x6; - uint64_t x7; - uint64_t x8; - uint64_t x9; - uint64_t x10; - uint64_t x11; - uint64_t x12; - uint64_t x13; - uint64_t x14; - uint64_t x15; - uint64_t x16; - uint64_t x17; - uint64_t x18; - uint64_t lr; - uint64_t spsr; - uint64_t elr; -#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER - uint64_t fp; -#endif -#ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK - uint64_t sp; -#endif -} __aligned(16); - -typedef struct __esf z_arch_esf_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_EXC_H_ */ diff --git a/include/zephyr/arch/arm64/exception.h b/include/zephyr/arch/arm64/exception.h new file mode 100644 index 00000000000..4ccdc41f19c --- /dev/null +++ b/include/zephyr/arch/arm64/exception.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Cortex-A public exception handling + * + * ARM-specific kernel exception handling interface. Included by arm64/arch.h. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ + +/* for assembler, only works with constants */ + +#ifdef _ASMLANGUAGE +#else +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct __esf { + uint64_t x0; + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + uint64_t x12; + uint64_t x13; + uint64_t x14; + uint64_t x15; + uint64_t x16; + uint64_t x17; + uint64_t x18; + uint64_t lr; + uint64_t spsr; + uint64_t elr; +#ifdef CONFIG_ARM64_ENABLE_FRAME_POINTER + uint64_t fp; +#endif +#ifdef CONFIG_ARM64_SAFE_EXCEPTION_STACK + uint64_t sp; +#endif +} __aligned(16); + +typedef struct __esf z_arch_esf_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM64_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/arm64/scripts/linker.ld b/include/zephyr/arch/arm64/scripts/linker.ld index fa08b730304..5a8e1404a98 100644 --- a/include/zephyr/arch/arm64/scripts/linker.ld +++ b/include/zephyr/arch/arm64/scripts/linker.ld @@ -31,10 +31,16 @@ #define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) #endif +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #if CONFIG_FLASH_LOAD_SIZE > 0 - #define ROM_SIZE CONFIG_FLASH_LOAD_SIZE + #define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) #else - #define ROM_SIZE (CONFIG_FLASH_SIZE * 1K - CONFIG_FLASH_LOAD_OFFSET) + #define ROM_SIZE (CONFIG_FLASH_SIZE * 1K - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) #endif #define RAM_SIZE (CONFIG_SRAM_SIZE * 1K) @@ -61,7 +67,7 @@ MEMORY FLASH (rx) : ORIGIN = ROM_ADDR, LENGTH = ROM_SIZE RAM (wx) : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K + IDT_LIST (wx) : ORIGIN = 0xFFFF8000, LENGTH = 32K } ENTRY(CONFIG_KERNEL_ENTRY) @@ -105,8 +111,11 @@ SECTIONS KEEP(*(.exc_vector_table)) KEEP(*(".exc_vector_table.*")) +#if LINKER_ZEPHYR_FINAL && defined(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + INCLUDE isr_tables_vt.ld +#else KEEP(*(.vectors)) - +#endif _vector_end = .; *(.text) diff --git a/include/zephyr/arch/cache.h b/include/zephyr/arch/cache.h index 8cbef3d2b9d..1516f03ee72 100644 --- a/include/zephyr/arch/cache.h +++ b/include/zephyr/arch/cache.h @@ -25,7 +25,7 @@ #include #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) /** * @brief Enable the d-cache @@ -157,7 +157,7 @@ int arch_dcache_flush_and_invd_range(void *addr, size_t size); #define cache_data_flush_and_invd_range(addr, size) \ arch_dcache_flush_and_invd_range(addr, size) -#if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) +#if defined(CONFIG_DCACHE_LINE_SIZE_DETECT) || defined(__DOXYGEN__) /** * @@ -176,11 +176,11 @@ size_t arch_dcache_line_size_get(void); #define cache_data_line_size_get arch_dcache_line_size_get -#endif /* CONFIG_DCACHE_LINE_SIZE_DETECT */ +#endif /* CONFIG_DCACHE_LINE_SIZE_DETECT || __DOXYGEN__ */ -#endif /* CONFIG_DCACHE */ +#endif /* CONFIG_DCACHE || __DOXYGEN__ */ -#if defined(CONFIG_ICACHE) +#if defined(CONFIG_ICACHE) || defined(__DOXYGEN__) /** * @brief Enable the i-cache @@ -311,7 +311,7 @@ int arch_icache_flush_and_invd_range(void *addr, size_t size); #define cache_instr_flush_and_invd_range(addr, size) \ arch_icache_flush_and_invd_range(addr, size) -#if defined(CONFIG_ICACHE_LINE_SIZE_DETECT) +#if defined(CONFIG_ICACHE_LINE_SIZE_DETECT) || defined(__DOXYGEN__) /** * @@ -331,9 +331,23 @@ size_t arch_icache_line_size_get(void); #define cache_instr_line_size_get arch_icache_line_size_get -#endif /* CONFIG_ICACHE_LINE_SIZE_DETECT */ +#endif /* CONFIG_ICACHE_LINE_SIZE_DETECT || __DOXYGEN__ */ -#endif /* CONFIG_ICACHE */ +#endif /* CONFIG_ICACHE || __DOXYGEN__ */ + +#if CONFIG_CACHE_DOUBLEMAP || __DOXYGEN__ +bool arch_cache_is_ptr_cached(void *ptr); +#define cache_is_ptr_cached(ptr) arch_cache_is_ptr_cached(ptr) + +bool arch_cache_is_ptr_uncached(void *ptr); +#define cache_is_ptr_uncached(ptr) arch_cache_is_ptr_uncached(ptr) + +void __sparse_cache *arch_cache_cached_ptr_get(void *ptr); +#define cache_cached_ptr(ptr) arch_cache_cached_ptr_get(ptr) + +void *arch_cache_uncached_ptr_get(void __sparse_cache *ptr); +#define cache_uncached_ptr(ptr) arch_cache_uncached_ptr_get(ptr) +#endif /* CONFIG_CACHE_DOUBLEMAP */ /** * @} diff --git a/include/zephyr/arch/mips/arch.h b/include/zephyr/arch/mips/arch.h index 67f6c846041..f99744bf086 100644 --- a/include/zephyr/arch/mips/arch.h +++ b/include/zephyr/arch/mips/arch.h @@ -10,7 +10,7 @@ #define ZEPHYR_INCLUDE_ARCH_MIPS_ARCH_H_ #include -#include +#include #include #include #include diff --git a/include/zephyr/arch/mips/exception.h b/include/zephyr/arch/mips/exception.h new file mode 100644 index 00000000000..d4403f1d599 --- /dev/null +++ b/include/zephyr/arch/mips/exception.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Antony Pavlov + * + * based on include/arch/riscv/exception.h + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ + +#ifndef _ASMLANGUAGE +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct __esf { + unsigned long ra; /* return address */ + unsigned long gp; /* global pointer */ + + unsigned long t0; /* Caller-saved temporary register */ + unsigned long t1; /* Caller-saved temporary register */ + unsigned long t2; /* Caller-saved temporary register */ + unsigned long t3; /* Caller-saved temporary register */ + unsigned long t4; /* Caller-saved temporary register */ + unsigned long t5; /* Caller-saved temporary register */ + unsigned long t6; /* Caller-saved temporary register */ + unsigned long t7; /* Caller-saved temporary register */ + unsigned long t8; /* Caller-saved temporary register */ + unsigned long t9; /* Caller-saved temporary register */ + + unsigned long a0; /* function argument */ + unsigned long a1; /* function argument */ + unsigned long a2; /* function argument */ + unsigned long a3; /* function argument */ + + unsigned long v0; /* return value */ + unsigned long v1; /* return value */ + + unsigned long at; /* assembly temporary */ + + unsigned long epc; + unsigned long badvaddr; + unsigned long hi; + unsigned long lo; + unsigned long status; + unsigned long cause; +}; + +typedef struct __esf z_arch_esf_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_MIPS_EXPCEPTION_H_ */ diff --git a/include/zephyr/arch/mips/exp.h b/include/zephyr/arch/mips/exp.h deleted file mode 100644 index 37b2cadb2fa..00000000000 --- a/include/zephyr/arch/mips/exp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2021 Antony Pavlov - * - * based on include/arch/riscv/exp.h - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ -#define ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ - -#ifndef _ASMLANGUAGE -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct __esf { - unsigned long ra; /* return address */ - unsigned long gp; /* global pointer */ - - unsigned long t0; /* Caller-saved temporary register */ - unsigned long t1; /* Caller-saved temporary register */ - unsigned long t2; /* Caller-saved temporary register */ - unsigned long t3; /* Caller-saved temporary register */ - unsigned long t4; /* Caller-saved temporary register */ - unsigned long t5; /* Caller-saved temporary register */ - unsigned long t6; /* Caller-saved temporary register */ - unsigned long t7; /* Caller-saved temporary register */ - unsigned long t8; /* Caller-saved temporary register */ - unsigned long t9; /* Caller-saved temporary register */ - - unsigned long a0; /* function argument */ - unsigned long a1; /* function argument */ - unsigned long a2; /* function argument */ - unsigned long a3; /* function argument */ - - unsigned long v0; /* return value */ - unsigned long v1; /* return value */ - - unsigned long at; /* assembly temporary */ - - unsigned long epc; - unsigned long badvaddr; - unsigned long hi; - unsigned long lo; - unsigned long status; - unsigned long cause; -}; - -typedef struct __esf z_arch_esf_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_INCLUDE_ARCH_MIPS_EXP_H_ */ diff --git a/include/zephyr/arch/nios2/linker.ld b/include/zephyr/arch/nios2/linker.ld index 6958533eaf6..f7ba64088fc 100644 --- a/include/zephyr/arch/nios2/linker.ld +++ b/include/zephyr/arch/nios2/linker.ld @@ -39,6 +39,11 @@ * the exception vector is in RAM */ +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif #ifdef CONFIG_XIP #define ROMABLE_REGION FLASH @@ -54,7 +59,7 @@ ASSERT(_RESET_VECTOR == _ROM_ADDR, "Reset vector not at beginning of ROM!") MEMORY { RESET (rx) : ORIGIN = _RESET_VECTOR, LENGTH = 0x20 - FLASH (rx) : ORIGIN = _RESET_VECTOR + 0x20 , LENGTH = (_ROM_SIZE - 0x20) + FLASH (rx) : ORIGIN = _RESET_VECTOR + 0x20 , LENGTH = (_ROM_SIZE - 0x20 - ROM_END_OFFSET) RAM (wx) : ORIGIN = _EXC_VECTOR, LENGTH = _RAM_SIZE - (_EXC_VECTOR - _RAM_ADDR) /* Used by and documented in include/linker/intlist.ld */ IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K diff --git a/include/zephyr/arch/riscv/arch.h b/include/zephyr/arch/riscv/arch.h index 99bccb74a08..e7dcfbef3ae 100644 --- a/include/zephyr/arch/riscv/arch.h +++ b/include/zephyr/arch/riscv/arch.h @@ -16,7 +16,7 @@ #define ZEPHYR_INCLUDE_ARCH_RISCV_ARCH_H_ #include -#include +#include #include #include #include @@ -26,10 +26,9 @@ #endif /* CONFIG_USERSPACE */ #include #include -#include #include #include -#include +#include /* stacks, for RISCV architecture stack should be 16byte-aligned */ #define ARCH_STACK_PTR_ALIGN 16 @@ -300,7 +299,7 @@ static inline uint64_t arch_k_cycle_get_64(void) #endif /*_ASMLANGUAGE */ -#if defined(CONFIG_SOC_FAMILY_RISCV_PRIVILEGED) +#if defined(CONFIG_RISCV_PRIVILEGED) #include #endif diff --git a/include/zephyr/arch/riscv/common/linker.ld b/include/zephyr/arch/riscv/common/linker.ld index eb5c4782441..a9bfa7a42ee 100644 --- a/include/zephyr/arch/riscv/common/linker.ld +++ b/include/zephyr/arch/riscv/common/linker.ld @@ -11,7 +11,6 @@ * Generic Linker script for the riscv platform */ -#include #include #include @@ -30,27 +29,52 @@ #define _EXCEPTION_SECTION_NAME exceptions #define _RESET_SECTION_NAME reset +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + +#if defined(CONFIG_FLASH_LOAD_OFFSET) +#define FLASH_LOAD_OFFSET CONFIG_FLASH_LOAD_OFFSET +#else +#define FLASH_LOAD_OFFSET 0 +#endif + #ifdef CONFIG_XIP + +#if CONFIG_FLASH_LOAD_SIZE > 0 +#define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) +#endif + #if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) -#ifdef CONFIG_FLASH_LOAD_OFFSET -#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + \ - CONFIG_FLASH_LOAD_OFFSET) -#else /* !CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_BASE DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) -#endif /* CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) +#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE +#define ROM_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) +#endif + #elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), jedec_spi_nor) /* For jedec,spi-nor we expect the spi controller to memory map the flash * and for that mapping to be the second register property of the spi * controller. */ #define SPI_CTRL DT_PARENT(DT_CHOSEN(zephyr_flash)) -#define ROM_BASE DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) -#define ROM_SIZE DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) +#define ROM_BASE (DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE +#define ROM_SIZE (DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) - ROM_END_OFFSET) #endif + +#else /* Use Kconfig to cover the remaining cases */ +#define ROM_BASE (CONFIG_FLASH_BASE_ADDRESS + FLASH_LOAD_OFFSET) +#ifndef ROM_SIZE +#define ROM_SIZE (CONFIG_FLASH_SIZE * 1024 - FLASH_LOAD_OFFSET - ROM_END_OFFSET) +#endif + +#endif /* DT_NODE_HAS_COMPAT_STATUS */ + #else /* CONFIG_XIP */ #define ROM_BASE CONFIG_SRAM_BASE_ADDRESS -#define ROM_SIZE KB(CONFIG_SRAM_SIZE) +#define ROM_SIZE (KB(CONFIG_SRAM_SIZE) - ROM_END_OFFSET) #endif /* CONFIG_XIP */ #define RAM_BASE CONFIG_SRAM_BASE_ADDRESS @@ -322,6 +346,11 @@ GROUP_START(ITCM) __itcm_start = .; *(.itcm) *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __itcm_end = .; } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) @@ -356,6 +385,11 @@ GROUP_START(DTCM) __dtcm_data_start = .; *(.dtcm_data) *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + __dtcm_data_end = .; } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) diff --git a/include/zephyr/arch/riscv/error.h b/include/zephyr/arch/riscv/error.h index e6af12f700e..a7c3e02b482 100644 --- a/include/zephyr/arch/riscv/error.h +++ b/include/zephyr/arch/riscv/error.h @@ -15,7 +15,7 @@ #define ZEPHYR_INCLUDE_ARCH_RISCV_ERROR_H_ #include -#include +#include #include #ifdef __cplusplus diff --git a/include/zephyr/arch/riscv/exception.h b/include/zephyr/arch/riscv/exception.h new file mode 100644 index 00000000000..644df2cd1fb --- /dev/null +++ b/include/zephyr/arch/riscv/exception.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne + * Copyright (c) 2018 Foundries.io Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief RISCV public exception handling + * + * RISCV-specific kernel exception handling interface. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ + +#ifndef _ASMLANGUAGE +#include +#include + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +#include +#endif + +#ifdef CONFIG_RISCV_SOC_HAS_ISR_STACKING +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The name of the structure which contains soc-specific state, if + * any, as well as the soc_esf_t typedef below, are part of the RISC-V + * arch API. + * + * The contents of the struct are provided by a SOC-specific + * definition in soc_context.h. + */ +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +struct soc_esf { + SOC_ESF_MEMBERS; +}; +#endif + +#if defined(CONFIG_RISCV_SOC_HAS_ISR_STACKING) + SOC_ISR_STACKING_ESF_DECLARE; +#else +struct __esf { + unsigned long ra; /* return address */ + + unsigned long t0; /* Caller-saved temporary register */ + unsigned long t1; /* Caller-saved temporary register */ + unsigned long t2; /* Caller-saved temporary register */ +#if !defined(CONFIG_RISCV_ISA_RV32E) + unsigned long t3; /* Caller-saved temporary register */ + unsigned long t4; /* Caller-saved temporary register */ + unsigned long t5; /* Caller-saved temporary register */ + unsigned long t6; /* Caller-saved temporary register */ +#endif /* !CONFIG_RISCV_ISA_RV32E */ + + unsigned long a0; /* function argument/return value */ + unsigned long a1; /* function argument */ + unsigned long a2; /* function argument */ + unsigned long a3; /* function argument */ + unsigned long a4; /* function argument */ + unsigned long a5; /* function argument */ +#if !defined(CONFIG_RISCV_ISA_RV32E) + unsigned long a6; /* function argument */ + unsigned long a7; /* function argument */ +#endif /* !CONFIG_RISCV_ISA_RV32E */ + + unsigned long mepc; /* machine exception program counter */ + unsigned long mstatus; /* machine status register */ + + unsigned long s0; /* callee-saved s0 */ + +#ifdef CONFIG_USERSPACE + unsigned long sp; /* preserved (user or kernel) stack pointer */ +#endif + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + struct soc_esf soc_context; +#endif +} __aligned(16); +#endif /* CONFIG_RISCV_SOC_HAS_ISR_STACKING */ + +typedef struct __esf z_arch_esf_t; +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +typedef struct soc_esf soc_esf_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ + +#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/riscv/exp.h b/include/zephyr/arch/riscv/exp.h deleted file mode 100644 index e661e5aa86e..00000000000 --- a/include/zephyr/arch/riscv/exp.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2016 Jean-Paul Etienne - * Copyright (c) 2018 Foundries.io Ltd - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief RISCV public exception handling - * - * RISCV-specific kernel exception handling interface. - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ -#define ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ - -#ifndef _ASMLANGUAGE -#include -#include - -#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE -#include -#endif - -#ifdef CONFIG_RISCV_SOC_HAS_ISR_STACKING -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * The name of the structure which contains soc-specific state, if - * any, as well as the soc_esf_t typedef below, are part of the RISC-V - * arch API. - * - * The contents of the struct are provided by a SOC-specific - * definition in soc_context.h. - */ -#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE -struct soc_esf { - SOC_ESF_MEMBERS; -}; -#endif - -#if defined(CONFIG_RISCV_SOC_HAS_ISR_STACKING) - SOC_ISR_STACKING_ESF_DECLARE; -#else -struct __esf { - unsigned long ra; /* return address */ - - unsigned long t0; /* Caller-saved temporary register */ - unsigned long t1; /* Caller-saved temporary register */ - unsigned long t2; /* Caller-saved temporary register */ -#if !defined(CONFIG_RISCV_ISA_RV32E) - unsigned long t3; /* Caller-saved temporary register */ - unsigned long t4; /* Caller-saved temporary register */ - unsigned long t5; /* Caller-saved temporary register */ - unsigned long t6; /* Caller-saved temporary register */ -#endif /* !CONFIG_RISCV_ISA_RV32E */ - - unsigned long a0; /* function argument/return value */ - unsigned long a1; /* function argument */ - unsigned long a2; /* function argument */ - unsigned long a3; /* function argument */ - unsigned long a4; /* function argument */ - unsigned long a5; /* function argument */ -#if !defined(CONFIG_RISCV_ISA_RV32E) - unsigned long a6; /* function argument */ - unsigned long a7; /* function argument */ -#endif /* !CONFIG_RISCV_ISA_RV32E */ - - unsigned long mepc; /* machine exception program counter */ - unsigned long mstatus; /* machine status register */ - - unsigned long s0; /* callee-saved s0 */ - -#ifdef CONFIG_USERSPACE - unsigned long sp; /* preserved (user or kernel) stack pointer */ -#endif - -#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE - struct soc_esf soc_context; -#endif -} __aligned(16); -#endif /* CONFIG_RISCV_SOC_HAS_ISR_STACKING */ - -typedef struct __esf z_arch_esf_t; -#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE -typedef struct soc_esf soc_esf_t; -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _ASMLANGUAGE */ - -#endif /* ZEPHYR_INCLUDE_ARCH_RISCV_EXP_H_ */ diff --git a/include/zephyr/arch/riscv/irq.h b/include/zephyr/arch/riscv/irq.h index 77c0d4057aa..3d81415e0d7 100644 --- a/include/zephyr/arch/riscv/irq.h +++ b/include/zephyr/arch/riscv/irq.h @@ -14,16 +14,39 @@ #ifndef ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ #define ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ -#ifndef _ASMLANGUAGE - #ifdef __cplusplus extern "C" { #endif +#ifndef _ASMLANGUAGE #include #include #include -#include +#endif /* !_ASMLANGUAGE */ + +/* Exceptions 0-15 (MCAUSE interrupt=0) */ + +/* Environment Call from U-mode */ +#define RISCV_EXC_ECALLU 8 +/** Environment Call from M-mode */ +#define RISCV_EXC_ECALLM 11 + +/* IRQs 0-15 (MCAUSE interrupt=1) */ + +/** Machine Software Interrupt */ +#define RISCV_IRQ_MSOFT 3 +/** Machine External Interrupt */ +#define RISCV_IRQ_MEXT 11 + +#ifdef CONFIG_64BIT +#define RISCV_MCAUSE_IRQ_POS 63U +#define RISCV_MCAUSE_IRQ_BIT BIT64(RISCV_MCAUSE_IRQ_POS) +#else +#define RISCV_MCAUSE_IRQ_POS 31U +#define RISCV_MCAUSE_IRQ_BIT BIT(RISCV_MCAUSE_IRQ_POS) +#endif + +#ifndef _ASMLANGUAGE extern void arch_irq_enable(unsigned int irq); extern void arch_irq_disable(unsigned int irq); @@ -46,8 +69,9 @@ extern void z_riscv_irq_priority_set(unsigned int irq, #define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \ { \ - Z_ISR_DECLARE(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ - ISR_FLAG_DIRECT, isr_p, NULL); \ + Z_ISR_DECLARE_DIRECT(irq_p + CONFIG_RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET, \ + ISR_FLAG_DIRECT, isr_p); \ + z_riscv_irq_priority_set(irq_p, priority_p, flags_p); \ } #define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header() @@ -76,7 +100,7 @@ static inline void arch_isr_direct_footer(int swap) /* Get the IRQ number */ __asm__ volatile("csrr %0, mcause" : "=r" (mcause)); - mcause &= SOC_MCAUSE_EXP_MASK; + mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK; /* Clear the pending IRQ */ __soc_handle_irq(mcause); @@ -102,10 +126,10 @@ static inline void arch_isr_direct_footer(int swap) } \ static inline int name##_body(void) +#endif /* _ASMLANGUAGE */ #ifdef __cplusplus } #endif -#endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_INCLUDE_ARCH_RISCV_IRQ_H_ */ diff --git a/include/zephyr/arch/syscall.h b/include/zephyr/arch/syscall.h index b657717e3d4..5b41561b681 100644 --- a/include/zephyr/arch/syscall.h +++ b/include/zephyr/arch/syscall.h @@ -23,6 +23,8 @@ #include #elif defined(CONFIG_RISCV) #include +#elif defined(CONFIG_XTENSA) +#include #endif #endif /* ZEPHYR_INCLUDE_ARCH_SYSCALL_H_ */ diff --git a/include/zephyr/arch/x86/arch_inlines.h b/include/zephyr/arch/x86/arch_inlines.h index 4b255acc853..356e7920c66 100644 --- a/include/zephyr/arch/x86/arch_inlines.h +++ b/include/zephyr/arch/x86/arch_inlines.h @@ -10,6 +10,8 @@ #ifndef _ASMLANGUAGE +#include + #if defined(CONFIG_X86_64) #include diff --git a/include/zephyr/arch/x86/ia32/arch.h b/include/zephyr/arch/x86/ia32/arch.h index e4bc3c5dba9..bd6ae1ed040 100644 --- a/include/zephyr/arch/x86/ia32/arch.h +++ b/include/zephyr/arch/x86/ia32/arch.h @@ -397,18 +397,6 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) */ #define NANO_SOFT_IRQ ((unsigned int) (-1)) -/** - * @defgroup float_apis Floating Point APIs - * @ingroup kernel_apis - * @{ - */ - -struct k_thread; - -/** - * @} - */ - #ifdef CONFIG_X86_ENABLE_TSS extern struct task_state_segment _main_tss; #endif diff --git a/include/zephyr/arch/x86/memory.ld b/include/zephyr/arch/x86/memory.ld index 72b400dd079..c9ede2b9d23 100644 --- a/include/zephyr/arch/x86/memory.ld +++ b/include/zephyr/arch/x86/memory.ld @@ -50,12 +50,18 @@ /* "kernel RAM" for linker VMA allocations starts at the offset */ +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + #ifdef CONFIG_XIP /* "ROM" is flash, we leave rodata and text there and just copy in data. * Board-level DTS must specify a flash region that doesn't overlap with * sram0, so that DT_PHYS_LOAD_ADDR is set. */ - #define FLASH_ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) + #define FLASH_ROM_SIZE (DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) - ROM_END_OFFSET) #define PHYS_LOAD_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) #else /* Physical RAM location where the kernel image is loaded */ diff --git a/include/zephyr/arch/x86/x86_acpi.h b/include/zephyr/arch/x86/x86_acpi.h new file mode 100644 index 00000000000..013400e6fe6 --- /dev/null +++ b/include/zephyr/arch/x86/x86_acpi.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief Encode interrupt flag for x86 architecture. + * + * @param polarity the interrupt polarity received from ACPICA lib + * @param trigger the interrupt level received from ACPICA lib + * @return return encoded interrupt flag + */ +uint32_t arch_acpi_encode_irq_flags(uint8_t polarity, uint8_t trigger); diff --git a/include/zephyr/arch/x86/x86_acpi_osal.h b/include/zephyr/arch/x86/x86_acpi_osal.h index 8f742b024b7..2395cac1951 100644 --- a/include/zephyr/arch/x86/x86_acpi_osal.h +++ b/include/zephyr/arch/x86/x86_acpi_osal.h @@ -26,4 +26,9 @@ static inline void *acpi_rsdp_get(void) return bios_acpi_rsdp_get(); } #endif /* CONFIG_X86_EFI */ + +static inline uint64_t acpi_timer_get(void) +{ + return z_tsc_read(); +} #endif /* ZEPHYR_ARCH_X86_INCLUDE_X86_ACPI_H_ */ diff --git a/include/zephyr/arch/xtensa/arch.h b/include/zephyr/arch/xtensa/arch.h index 2d13615a753..f3358cafe2f 100644 --- a/include/zephyr/arch/xtensa/arch.h +++ b/include/zephyr/arch/xtensa/arch.h @@ -7,7 +7,7 @@ * @file * @brief Xtensa specific kernel interface header * This header contains the Xtensa specific kernel interface. It is included - * by the generic kernel interface header (include/arch/cpu.h) + * by the generic kernel interface header (include/zephyr/arch/cpu.h) */ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_ARCH_H_ @@ -23,81 +23,135 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include -#include +#include -#ifdef CONFIG_KERNEL_COHERENCE -#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE -#else -#define ARCH_STACK_PTR_ALIGN 16 -#endif +#include -/* Xtensa GPRs are often designated by two different names */ -#define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; } +/** + * @defgroup xtensa_apis Xtensa APIs + * @{ + * @} + * + * @defgroup xtensa_internal_apis Xtensa Internal APIs + * @ingroup xtensa_apis + * @{ + * @} + */ -#include +#include #ifdef __cplusplus extern "C" { #endif +struct arch_mem_domain { +#ifdef CONFIG_XTENSA_MMU + uint32_t *ptables __aligned(CONFIG_MMU_PAGE_SIZE); + uint8_t asid; + bool dirty; +#endif + sys_snode_t node; +}; + +/** + * @brief Generate hardware exception. + * + * This generates hardware exception which is used by ARCH_EXCEPT(). + * + * @param reason_p Reason for exception. + */ extern void xtensa_arch_except(int reason_p); +/** + * @brief Generate kernel oops. + * + * This generates kernel oops which is used by arch_syscall_oops(). + * + * @param reason_p Reason for exception. + * @param ssf Stack pointer. + */ +extern void xtensa_arch_kernel_oops(int reason_p, void *ssf); + +#ifdef CONFIG_USERSPACE + #define ARCH_EXCEPT(reason_p) do { \ - xtensa_arch_except(reason_p); \ + if (k_is_user_context()) { \ + arch_syscall_invoke1(reason_p, \ + K_SYSCALL_XTENSA_USER_FAULT); \ + } else { \ + xtensa_arch_except(reason_p); \ + } \ CODE_UNREACHABLE; \ } while (false) +#else + +#define ARCH_EXCEPT(reason_p) do { \ + xtensa_arch_except(reason_p); \ + CODE_UNREACHABLE; \ + } while (false) + +#endif + +__syscall void xtensa_user_fault(unsigned int reason); + +#include + /* internal routine documented in C file, needed by IRQ_CONNECT() macro */ extern void z_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags); #define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \ -{ \ - Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ -} - -#define XTENSA_ERR_NORET - -extern uint32_t sys_clock_cycle_get_32(void); + { \ + Z_ISR_DECLARE(irq_p, flags_p, isr_p, isr_param_p); \ + } +/** Implementation of @ref arch_k_cycle_get_32. */ static inline uint32_t arch_k_cycle_get_32(void) { return sys_clock_cycle_get_32(); } -extern uint64_t sys_clock_cycle_get_64(void); - +/** Implementation of @ref arch_k_cycle_get_64. */ static inline uint64_t arch_k_cycle_get_64(void) { return sys_clock_cycle_get_64(); } +/** Implementation of @ref arch_nop. */ static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); } +/** + * @brief Lock VECBASE if supported by hardware. + * + * The bit 0 of VECBASE acts as a lock bit on hardware supporting + * this feature. When this bit is set, VECBASE cannot be changed + * until it is cleared by hardware reset. When the hardware does not + * support this bit, it is hardwired to 0. + */ static ALWAYS_INLINE void xtensa_vecbase_lock(void) { int vecbase; __asm__ volatile("rsr.vecbase %0" : "=r" (vecbase)); - - /* In some targets the bit 0 of VECBASE works as lock bit. - * When this bit set, VECBASE can't be changed until it is cleared by - * reset. When the target does not have it, it is hardwired to 0. - **/ __asm__ volatile("wsr.vecbase %0; rsync" : : "r" (vecbase | 1)); } -#if defined(CONFIG_XTENSA_RPO_CACHE) -#if defined(CONFIG_ARCH_HAS_COHERENCE) +#if defined(CONFIG_XTENSA_RPO_CACHE) || defined(__DOXYGEN__) +#if defined(CONFIG_ARCH_HAS_COHERENCE) || defined(__DOXYGEN__) +/** Implementation of @ref arch_mem_coherent. */ static inline bool arch_mem_coherent(void *ptr) { size_t addr = (size_t) ptr; @@ -106,91 +160,6 @@ static inline bool arch_mem_coherent(void *ptr) } #endif -static inline bool arch_xtensa_is_ptr_cached(void *ptr) -{ - size_t addr = (size_t) ptr; - - return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; -} - -static inline bool arch_xtensa_is_ptr_uncached(void *ptr) -{ - size_t addr = (size_t) ptr; - - return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION; -} - -static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t rfrom) -{ - /* The math here is all compile-time: when the two regions - * differ by a power of two, we can convert between them by - * setting or clearing just one bit. Otherwise it needs two - * operations. - */ - uint32_t rxor = (rto ^ rfrom) << 29; - - rto <<= 29; - if (Z_IS_POW2(rxor)) { - if ((rxor & rto) == 0) { - return addr & ~rxor; - } else { - return addr | rxor; - } - } else { - return (addr & ~(7U << 29)) | rto; - } -} -/** - * @brief Return cached pointer to a RAM address - * - * The Xtensa coherence architecture maps addressable RAM twice, in - * two different 512MB regions whose L1 cache settings can be - * controlled independently. So for any given pointer, it is possible - * to convert it to and from a cached version. - * - * This function takes a pointer to any addressable object (either in - * cacheable memory or not) and returns a pointer that can be used to - * refer to the same memory through the L1 data cache. Data read - * through the resulting pointer will reflect locally cached values on - * the current CPU if they exist, and writes will go first into the - * cache and be written back later. - * - * @see arch_xtensa_uncached_ptr() - * - * @param ptr A pointer to a valid C object - * @return A pointer to the same object via the L1 dcache - */ -static inline void __sparse_cache *arch_xtensa_cached_ptr(void *ptr) -{ - return (__sparse_force void __sparse_cache *)z_xtrpoflip((uint32_t) ptr, - CONFIG_XTENSA_CACHED_REGION, - CONFIG_XTENSA_UNCACHED_REGION); -} - -/** - * @brief Return uncached pointer to a RAM address - * - * The Xtensa coherence architecture maps addressable RAM twice, in - * two different 512MB regions whose L1 cache settings can be - * controlled independently. So for any given pointer, it is possible - * to convert it to and from a cached version. - * - * This function takes a pointer to any addressable object (either in - * cacheable memory or not) and returns a pointer that can be used to - * refer to the same memory while bypassing the L1 data cache. Data - * in the L1 cache will not be inspected nor modified by the access. - * - * @see arch_xtensa_cached_ptr() - * - * @param ptr A pointer to a valid C object - * @return A pointer to the same object bypassing the L1 dcache - */ -static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) -{ - return (void *)z_xtrpoflip((__sparse_force uint32_t)ptr, - CONFIG_XTENSA_UNCACHED_REGION, - CONFIG_XTENSA_CACHED_REGION); -} /* Utility to generate an unrolled and optimal[1] code sequence to set * the RPO TLB registers (contra the HAL cacheattr macros, which @@ -238,14 +207,27 @@ static inline void *arch_xtensa_uncached_ptr(void __sparse_cache *ptr) addr += addrincr; \ } while (0) -#define ARCH_XTENSA_SET_RPO_TLB() do { \ - register uint32_t addr = 0, addrincr = 0x20000000; \ - FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ -} while (0) - -#endif - -#ifdef CONFIG_XTENSA_MMU +/** + * @brief Setup RPO TLB registers. + */ +#define ARCH_XTENSA_SET_RPO_TLB() \ + do { \ + register uint32_t addr = 0, addrincr = 0x20000000; \ + FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \ + } while (0) +#endif /* CONFIG_XTENSA_RPO_CACHE */ + +#if defined(CONFIG_XTENSA_MMU) || defined(__DOXYGEN__) +/** + * @brief Peform additional steps after MMU initialization. + * + * This performs additional steps related to memory management + * after the main MMU initialization code. This needs to defined + * in the SoC layer. Default is do no nothing. + * + * @param is_core0 True if this is called while executing on + * CPU core #0. + */ extern void arch_xtensa_mmu_post_init(bool is_core0); #endif diff --git a/include/zephyr/arch/xtensa/arch_inlines.h b/include/zephyr/arch/xtensa/arch_inlines.h index d5fcc55af47..4e7b5200276 100644 --- a/include/zephyr/arch/xtensa/arch_inlines.h +++ b/include/zephyr/arch/xtensa/arch_inlines.h @@ -13,26 +13,53 @@ #include #include +/** + * @brief Read a special register. + * + * @param sr Name of special register. + * + * @return Value of special register. + */ #define XTENSA_RSR(sr) \ ({uint32_t v; \ __asm__ volatile ("rsr." sr " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a special register. + * + * @param sr Name of special register. + * @param v Value to be written to special register. + */ #define XTENSA_WSR(sr, v) \ do { \ __asm__ volatile ("wsr." sr " %0" : : "r"(v)); \ } while (false) +/** + * @brief Read a user register. + * + * @param ur Name of user register. + * + * @return Value of user register. + */ #define XTENSA_RUR(ur) \ ({uint32_t v; \ __asm__ volatile ("rur." ur " %0" : "=a"(v)); \ v; }) +/** + * @brief Write to a user register. + * + * @param ur Name of user register. + * @param v Value to be written to user register. + */ #define XTENSA_WUR(ur, v) \ do { \ __asm__ volatile ("wur." ur " %0" : : "r"(v)); \ } while (false) +/** Implementation of @ref arch_curr_cpu. */ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) { _cpu_t *cpu; @@ -42,6 +69,7 @@ static ALWAYS_INLINE _cpu_t *arch_curr_cpu(void) return cpu; } +/** Implementation of @ref arch_proc_id. */ static ALWAYS_INLINE uint32_t arch_proc_id(void) { uint32_t prid; @@ -54,6 +82,7 @@ static ALWAYS_INLINE uint32_t arch_proc_id(void) extern unsigned int soc_num_cpus; #endif +/** Implementation of @ref arch_num_cpus. */ static ALWAYS_INLINE unsigned int arch_num_cpus(void) { #ifdef CONFIG_SOC_HAS_RUNTIME_NUM_CPUS diff --git a/include/zephyr/arch/xtensa/atomic_xtensa.h b/include/zephyr/arch/xtensa/atomic_xtensa.h index c518f4df4ed..a8f5d0f78e9 100644 --- a/include/zephyr/arch/xtensa/atomic_xtensa.h +++ b/include/zephyr/arch/xtensa/atomic_xtensa.h @@ -1,11 +1,12 @@ -/** +/* * Copyright (c) 2021 Intel Corporation * SPDX-License-Identifier: Apache-2.0 */ + #ifndef ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ #define ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ -/* Included from */ +/* Included from */ /* Recent GCC versions actually do have working atomics support on * Xtensa (and so should work with CONFIG_ATOMIC_OPERATIONS_BUILTIN), @@ -13,6 +14,7 @@ * inline implementation here that is more or less identical */ +/** Implementation of @ref atomic_get. */ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) { atomic_val_t ret; @@ -28,6 +30,23 @@ static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target) return ret; } +/** + * @brief Xtensa specific atomic compare-and-set (CAS). + * + * @param addr Address of atomic variable. + * @param oldval Original value to compare against. + * @param newval New value to store. + * + * This utilizes SCOMPARE1 register and s32c1i instruction to + * perform compare-and-set atomic operation. This will + * unconditionally read from the atomic variable at @p addr + * before the comparison. This value is returned from + * the function. + * + * @return The value at the memory location before CAS. + * + * @see atomic_cas. + */ static ALWAYS_INLINE atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, atomic_val_t newval) @@ -38,12 +57,14 @@ atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval, return newval; /* got swapped with the old memory by s32c1i */ } +/** Implementation of @ref atomic_cas. */ static ALWAYS_INLINE bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval) { return oldval == xtensa_cas(target, oldval, newval); } +/** Implementation of @ref atomic_ptr_cas. */ static ALWAYS_INLINE bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) { @@ -57,7 +78,6 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) * specified expression. Evaluates to the old value which was * atomically replaced. */ - #define Z__GEN_ATOMXCHG(expr) ({ \ atomic_val_t res, cur; \ do { \ @@ -66,75 +86,88 @@ bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval) } while (res != cur); \ res; }) +/** Implementation of @ref atomic_set. */ static ALWAYS_INLINE atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(value); } +/** Implementation of @ref atomic_add. */ static ALWAYS_INLINE atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur + value); } +/** Implementation of @ref atomic_sub. */ static ALWAYS_INLINE atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur - value); } +/** Implementation of @ref atomic_inc. */ static ALWAYS_INLINE atomic_val_t atomic_inc(atomic_t *target) { return Z__GEN_ATOMXCHG(cur + 1); } +/** Implementation of @ref atomic_dec. */ static ALWAYS_INLINE atomic_val_t atomic_dec(atomic_t *target) { return Z__GEN_ATOMXCHG(cur - 1); } +/** Implementation of @ref atomic_or. */ static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur | value); } +/** Implementation of @ref atomic_xor. */ static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur ^ value); } +/** Implementation of @ref atomic_and. */ static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(cur & value); } +/** Implementation of @ref atomic_nand. */ static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) { return Z__GEN_ATOMXCHG(~(cur & value)); } +/** Implementation of @ref atomic_ptr_get. */ static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target) { return (void *) atomic_get((atomic_t *)target); } +/** Implementation of @ref atomic_ptr_set. */ static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value) { return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value); } +/** Implementation of @ref atomic_clear. */ static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target) { return atomic_set(target, 0); } +/** Implementation of @ref atomic_ptr_clear. */ static ALWAYS_INLINE void *atomic_ptr_clear(atomic_ptr_t *target) { return (void *) atomic_set((atomic_t *) target, 0); diff --git a/include/zephyr/arch/xtensa/cache.h b/include/zephyr/arch/xtensa/cache.h index 4f472b3667c..c5964c16ce7 100644 --- a/include/zephyr/arch/xtensa/cache.h +++ b/include/zephyr/arch/xtensa/cache.h @@ -22,7 +22,9 @@ BUILD_ASSERT(Z_IS_POW2(XCHAL_DCACHE_LINESIZE)); BUILD_ASSERT(Z_IS_POW2(Z_DCACHE_MAX)); #endif -#if defined(CONFIG_DCACHE) +#if defined(CONFIG_DCACHE) || defined(__DOXYGEN__) + +/** Implementation of @ref arch_dcache_flush_range. */ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -38,6 +40,7 @@ static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -53,6 +56,7 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t byt return 0; } +/** Implementation of @ref arch_dcache_invd_range. */ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) { #if XCHAL_DCACHE_SIZE @@ -68,6 +72,7 @@ static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes) return 0; } +/** Implementation of @ref arch_dcache_invd_all. */ static ALWAYS_INLINE int arch_dcache_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -81,6 +86,7 @@ static ALWAYS_INLINE int arch_dcache_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_all. */ static ALWAYS_INLINE int arch_dcache_flush_all(void) { #if XCHAL_DCACHE_SIZE @@ -94,6 +100,7 @@ static ALWAYS_INLINE int arch_dcache_flush_all(void) return 0; } +/** Implementation of @ref arch_dcache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) { #if XCHAL_DCACHE_SIZE @@ -107,11 +114,13 @@ static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void) return 0; } +/** Implementation of @ref arch_dcache_enable. */ static ALWAYS_INLINE void arch_dcache_enable(void) { /* nothing */ } +/** Implementation of @ref arch_dcache_disable. */ static ALWAYS_INLINE void arch_dcache_disable(void) { /* nothing */ @@ -119,21 +128,21 @@ static ALWAYS_INLINE void arch_dcache_disable(void) #endif /* CONFIG_DCACHE */ -#if defined(CONFIG_ICACHE) +#if defined(CONFIG_ICACHE) || defined(__DOXYGEN__) -static size_t arch_icache_line_size_get(void) +/** Implementation of @ref arch_icache_line_size_get. */ +static ALWAYS_INLINE size_t arch_icache_line_size_get(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_all. */ static ALWAYS_INLINE int arch_icache_flush_all(void) { -#if XCHAL_ICACHE_SIZE - xthal_icache_all_writeback(); -#endif - return 0; + return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_all. */ static ALWAYS_INLINE int arch_icache_invd_all(void) { #if XCHAL_ICACHE_SIZE @@ -142,16 +151,19 @@ static ALWAYS_INLINE int arch_icache_invd_all(void) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_all. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_all(void) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_flush_range. */ static ALWAYS_INLINE int arch_icache_flush_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_invd_range. */ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) { #if XCHAL_ICACHE_SIZE @@ -160,23 +172,164 @@ static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size) return 0; } +/** Implementation of @ref arch_icache_flush_and_invd_range. */ static ALWAYS_INLINE int arch_icache_flush_and_invd_range(void *addr, size_t size) { return -ENOTSUP; } +/** Implementation of @ref arch_icache_enable. */ static ALWAYS_INLINE void arch_icache_enable(void) { /* nothing */ } -static ALWAYS_INLINE vid arch_icache_disable(void) +/** Implementation of @ref arch_icache_disable. */ +static ALWAYS_INLINE void arch_icache_disable(void) { /* nothing */ } #endif /* CONFIG_ICACHE */ +#if defined(CONFIG_CACHE_DOUBLEMAP) +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ +static inline bool arch_cache_is_ptr_cached(void *ptr) +{ + size_t addr = (size_t) ptr; + + return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION; +} + +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ +static inline bool arch_cache_is_ptr_uncached(void *ptr) +{ + size_t addr = (size_t) ptr; + + return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION; +} + +static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t rfrom) +{ + /* The math here is all compile-time: when the two regions + * differ by a power of two, we can convert between them by + * setting or clearing just one bit. Otherwise it needs two + * operations. + */ + uint32_t rxor = (rto ^ rfrom) << 29; + + rto <<= 29; + if (Z_IS_POW2(rxor)) { + if ((rxor & rto) == 0) { + return addr & ~rxor; + } else { + return addr | rxor; + } + } else { + return (addr & ~(7U << 29)) | rto; + } +} + +/** + * @brief Return cached pointer to a RAM address + * + * The Xtensa coherence architecture maps addressable RAM twice, in + * two different 512MB regions whose L1 cache settings can be + * controlled independently. So for any given pointer, it is possible + * to convert it to and from a cached version. + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory through the L1 data cache. Data read + * through the resulting pointer will reflect locally cached values on + * the current CPU if they exist, and writes will go first into the + * cache and be written back later. + * + * @see arch_uncached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object via the L1 dcache + */ +static inline void __sparse_cache *arch_cache_cached_ptr_get(void *ptr) +{ + return (__sparse_force void __sparse_cache *)z_xtrpoflip((uint32_t) ptr, + CONFIG_XTENSA_CACHED_REGION, + CONFIG_XTENSA_UNCACHED_REGION); +} + +/** + * @brief Return uncached pointer to a RAM address + * + * The Xtensa coherence architecture maps addressable RAM twice, in + * two different 512MB regions whose L1 cache settings can be + * controlled independently. So for any given pointer, it is possible + * to convert it to and from a cached version. + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory while bypassing the L1 data cache. Data + * in the L1 cache will not be inspected nor modified by the access. + * + * @see arch_cached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object bypassing the L1 dcache + */ +static inline void *arch_cache_uncached_ptr_get(void __sparse_cache *ptr) +{ + return (void *)z_xtrpoflip((__sparse_force uint32_t)ptr, + CONFIG_XTENSA_UNCACHED_REGION, + CONFIG_XTENSA_CACHED_REGION); +} +#else +static inline bool arch_cache_is_ptr_cached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline bool arch_cache_is_ptr_uncached(void *ptr) +{ + ARG_UNUSED(ptr); + + return false; +} + +static inline void *arch_cache_cached_ptr_get(void *ptr) +{ + return ptr; +} + +static inline void *arch_cache_uncached_ptr_get(void *ptr) +{ + return ptr; +} +#endif #ifdef __cplusplus diff --git a/include/zephyr/arch/xtensa/exc.h b/include/zephyr/arch/xtensa/exc.h deleted file mode 100644 index e207261a027..00000000000 --- a/include/zephyr/arch/xtensa/exc.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2014 Wind River Systems, Inc. - * Copyright (c) 2016 Cadence Design Systems, Inc. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Xtensa public exception handling - * - * Xtensa-specific kernel exception handling interface. Included by - * arch/xtensa/arch.h. - */ - -#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ -#define ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ASMLANGUAGE - -/* Xtensa uses a variable length stack frame depending on how many - * register windows are in use. This isn't a struct type, it just - * matches the register/stack-unit width. - */ -typedef int z_arch_esf_t; - -void z_xtensa_dump_stack(const z_arch_esf_t *stack); -char *z_xtensa_exccause(unsigned int cause_code); - -#endif - -#ifdef __cplusplus -} -#endif - - -#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_EXC_H_ */ diff --git a/include/zephyr/arch/xtensa/exception.h b/include/zephyr/arch/xtensa/exception.h new file mode 100644 index 00000000000..51a5d5aef90 --- /dev/null +++ b/include/zephyr/arch/xtensa/exception.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Wind River Systems, Inc. + * Copyright (c) 2016 Cadence Design Systems, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Xtensa public exception handling + * + * Xtensa-specific kernel exception handling interface. Included by + * arch/xtensa/arch.h. + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ASMLANGUAGE + +/* Xtensa uses a variable length stack frame depending on how many + * register windows are in use. This isn't a struct type, it just + * matches the register/stack-unit width. + */ +typedef int z_arch_esf_t; + +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_EXCEPTION_H_ */ diff --git a/include/zephyr/arch/xtensa/gdbstub.h b/include/zephyr/arch/xtensa/gdbstub.h index 627bb79e678..89aabb02905 100644 --- a/include/zephyr/arch/xtensa/gdbstub.h +++ b/include/zephyr/arch/xtensa/gdbstub.h @@ -17,8 +17,8 @@ #define XTREG_GRP_SPECIAL 0x0200 #define XTREG_GRP_USER 0x0300 -/* - * Register description fot GDB stub. +/** + * @brief Register description for GDB stub. * * Values are based on gdb/gdb/xtensa-config.c in the Xtensa overlay, * where registers are defined using XTREG() macro: @@ -35,32 +35,35 @@ * gpkt_offset : ofs */ struct xtensa_register { - /* Register value */ + /** Register value */ uint32_t val; - /* GDB register index (for p/P packets) */ + /** GDB register index (for p/P packets) */ uint8_t idx; - /* Size of register */ + /** Size of register */ uint8_t byte_size; - /* Xtensa register number */ + /** Xtensa register number */ uint16_t regno; - /* Offset of this register in GDB G-packet. + /** + * Offset of this register in GDB G-packet. * -1 if register is not in G-packet. */ int16_t gpkt_offset; - /* Offset of saved register in stack frame. + /** + * Offset of saved register in stack frame. * 0 if not saved in stack frame. */ int8_t stack_offset; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Set 1 to if register should not be written + /** + * Set to 1 if register should not be written * to during debugging. */ uint8_t is_read_only:1; @@ -78,26 +81,29 @@ struct xtensa_register { */ #include +/** + * @brief Architecture specific GDB context. + */ struct gdb_ctx { - /* Exception reason */ + /** Exception reason */ unsigned int exception; - /* Register descriptions */ + /** Register descriptions */ struct xtensa_register *regs; - /* Number of registers */ + /** Number of registers */ uint8_t num_regs; - /* Sequence number */ + /** Sequence number */ uint8_t seqno; - /* Index in register descriptions of A0 register */ + /** Index in register descriptions of A0 register */ uint8_t a0_idx; - /* Index in register descriptions of AR0 register */ + /** Index in register descriptions of AR0 register */ uint8_t ar_idx; - /* Index in register descriptions of WINDOWBASE register */ + /** Index in register descriptions of WINDOWBASE register */ uint8_t wb_idx; }; diff --git a/include/zephyr/arch/xtensa/irq.h b/include/zephyr/arch/xtensa/irq.h index 69cef4e8627..938ab7b2303 100644 --- a/include/zephyr/arch/xtensa/irq.h +++ b/include/zephyr/arch/xtensa/irq.h @@ -13,6 +13,10 @@ #define CONFIG_GEN_IRQ_START_VECTOR 0 +/** + * @cond INTERNAL_HIDDEN + */ + /* * Call this function to enable the specified interrupts. * @@ -42,6 +46,7 @@ static inline void z_xt_ints_off(unsigned int mask) __asm__ volatile("wsr.intenable %0; rsync" : : "r"(val)); } + /* * Call this function to set the specified (s/w) interrupt. */ @@ -54,6 +59,10 @@ static inline void z_xt_set_intset(unsigned int arg) #endif } +/** + * INTERNAL_HIDDEN @endcond + */ + #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS /* for _soc_irq_*() */ @@ -94,23 +103,34 @@ extern int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority, #define CONFIG_NUM_IRQS XCHAL_NUM_INTERRUPTS -#define arch_irq_enable(irq) z_xtensa_irq_enable(irq) -#define arch_irq_disable(irq) z_xtensa_irq_disable(irq) +#define arch_irq_enable(irq) xtensa_irq_enable(irq) +#define arch_irq_disable(irq) xtensa_irq_disable(irq) -#define arch_irq_is_enabled(irq) z_xtensa_irq_is_enabled(irq) +#define arch_irq_is_enabled(irq) xtensa_irq_is_enabled(irq) #endif -static ALWAYS_INLINE void z_xtensa_irq_enable(uint32_t irq) +/** + * @brief Enable interrupt on Xtensa core. + * + * @param irq Interrupt to be enabled. + */ +static ALWAYS_INLINE void xtensa_irq_enable(uint32_t irq) { z_xt_ints_on(1 << irq); } -static ALWAYS_INLINE void z_xtensa_irq_disable(uint32_t irq) +/** + * @brief Disable interrupt on Xtensa core. + * + * @param irq Interrupt to be disabled. + */ +static ALWAYS_INLINE void xtensa_irq_disable(uint32_t irq) { z_xt_ints_off(1 << irq); } +/** Implementation of @ref arch_irq_lock. */ static ALWAYS_INLINE unsigned int arch_irq_lock(void) { unsigned int key; @@ -120,18 +140,27 @@ static ALWAYS_INLINE unsigned int arch_irq_lock(void) return key; } +/** Implementation of @ref arch_irq_unlock. */ static ALWAYS_INLINE void arch_irq_unlock(unsigned int key) { __asm__ volatile("wsr.ps %0; rsync" :: "r"(key) : "memory"); } +/** Implementation of @ref arch_irq_unlocked. */ static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { return (key & 0xf) == 0; /* INTLEVEL field */ } -extern int z_xtensa_irq_is_enabled(unsigned int irq); +/** + * @brief Query if an interrupt is enabled on Xtensa core. + * + * @param irq Interrupt to be queried. + * + * @return True if interrupt is enabled, false otherwise. + */ +extern int xtensa_irq_is_enabled(unsigned int irq); #include diff --git a/include/zephyr/arch/xtensa/syscall.h b/include/zephyr/arch/xtensa/syscall.h new file mode 100644 index 00000000000..b8b0bea8cdb --- /dev/null +++ b/include/zephyr/arch/xtensa/syscall.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2022 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Xtensa specific syscall header + * + * This header contains the Xtensa specific syscall interface. It is + * included by the syscall interface architecture-abstraction header + * (include/arch/syscall.h) + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ + +#ifdef CONFIG_USERSPACE +#ifndef _ASMLANGUAGE + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER +uintptr_t xtensa_syscall_helper(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id); + +#define SYSINL ALWAYS_INLINE +#else +#define SYSINL inline +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ + +/** + * We are following Linux Xtensa syscall ABI: + * + * syscall number arg1, arg2, arg3, arg4, arg5, arg6 + * -------------- ---------------------------------- + * a2 a6, a3, a4, a5, a8, a9 + * + **/ + +static SYSINL uintptr_t arch_syscall_invoke6(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t arg6, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, arg6, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + register uintptr_t a9 __asm__("%a9") = arg6; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8), "r" (a9) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static SYSINL uintptr_t arch_syscall_invoke5(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, arg5, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + register uintptr_t a8 __asm__("%a8") = arg5; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5), "r" (a8) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static SYSINL uintptr_t arch_syscall_invoke4(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, arg2, arg3, arg4, 0, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + register uintptr_t a5 __asm__("%a5") = arg4; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4), + "r" (a5) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static SYSINL uintptr_t arch_syscall_invoke3(uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, arg2, arg3, 0, 0, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + register uintptr_t a4 __asm__("%a4") = arg3; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3), "r" (a4) + : "memory"); + + return a2; +#endif /* CONFIG_XTENSA_SYSCALL_USE_HELPER */ +} + +static SYSINL uintptr_t arch_syscall_invoke2(uintptr_t arg1, uintptr_t arg2, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, arg2, 0, 0, 0, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + register uintptr_t a3 __asm__("%a3") = arg2; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6), "r" (a3) + : "memory"); + + return a2; +#endif +} + +static SYSINL uintptr_t arch_syscall_invoke1(uintptr_t arg1, + uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(arg1, 0, 0, 0, 0, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + register uintptr_t a6 __asm__("%a6") = arg1; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2), "r" (a6) + : "memory"); + + return a2; +#endif +} + +static SYSINL uintptr_t arch_syscall_invoke0(uintptr_t call_id) +{ +#ifdef CONFIG_XTENSA_SYSCALL_USE_HELPER + return xtensa_syscall_helper(0, 0, 0, 0, 0, 0, call_id); +#else + register uintptr_t a2 __asm__("%a2") = call_id; + + __asm__ volatile("syscall\n\t" + : "=r" (a2) + : "r" (a2) + : "memory"); + + return a2; +#endif +} + +/* + * There is no easy (or generic) way to figure out if a thread is runnining + * in un-privileged mode. Reading the currrent ring (PS.CRING) is a privileged + * instruction and not thread local storage is not available in xcc. + */ +static inline bool arch_is_user_context(void) +{ + uint32_t thread; + + __asm__ volatile( + "rur.THREADPTR %0\n\t" + : "=a" (thread) + ); +#ifdef CONFIG_THREAD_LOCAL_STORAGE + extern __thread uint32_t is_user_mode; + + if (!thread) { + return false; + } + + return is_user_mode != 0; +#else + return !!thread; +#endif +} + +#undef SYSINL + +#ifdef __cplusplus +} +#endif + +#endif /* _ASMLANGUAGE */ +#endif /* CONFIG_USERSPACE */ +#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_SYSCALL_H_ */ diff --git a/include/zephyr/arch/xtensa/thread.h b/include/zephyr/arch/xtensa/thread.h index 4ec5da1ea2c..2bebe2722bc 100644 --- a/include/zephyr/arch/xtensa/thread.h +++ b/include/zephyr/arch/xtensa/thread.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ #define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_H_ +#include #ifndef _ASMLANGUAGE /* Xtensa doesn't use these structs, but Zephyr core requires they be @@ -22,6 +23,14 @@ typedef struct _callee_saved _callee_saved_t; struct _thread_arch { uint32_t last_cpu; +#ifdef CONFIG_USERSPACE + uint32_t *ptables; + + /* Initial privilege mode stack pointer when doing a system call. + * Un-set for surpervisor threads. + */ + uint8_t *psp; +#endif }; typedef struct _thread_arch _thread_arch_t; diff --git a/include/zephyr/arch/xtensa/thread_stack.h b/include/zephyr/arch/xtensa/thread_stack.h new file mode 100644 index 00000000000..b862b7a8c1e --- /dev/null +++ b/include/zephyr/arch/xtensa/thread_stack.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ +#define ZEPHYR_INCLUDE_ARCH_XTENSA_THREAD_STACK_H_ + +#include +#include + +#ifdef CONFIG_KERNEL_COHERENCE +#define ARCH_STACK_PTR_ALIGN XCHAL_DCACHE_LINESIZE +#else +#define ARCH_STACK_PTR_ALIGN 16 +#endif + + +#if CONFIG_USERSPACE +#define XTENSA_STACK_BASE_ALIGN CONFIG_MMU_PAGE_SIZE +#define XTENSA_STACK_SIZE_ALIGN CONFIG_MMU_PAGE_SIZE +#else +#define XTENSA_STACK_BASE_ALIGN ARCH_STACK_PTR_ALIGN +#define XTENSA_STACK_SIZE_ALIGN ARCH_STACK_PTR_ALIGN +#endif + +/* + * + * High memory addresses + * + * +-------------------+ <- thread.stack_info.start + thread.stack_info.size + * | TLS | + * +-------------------+ <- initial sp (computable with thread.stack_info.delta) + * | | + * | Thread stack | + * | | + * +-------------------+ <- thread.stack_info.start + * | Privileged stack | } CONFIG_MMU_PAGE_SIZE + * +-------------------+ <- thread.stack_obj + * + * Low Memory addresses + */ + +#ifndef _ASMLANGUAGE + +/* thread stack */ +#ifdef CONFIG_XTENSA_MMU +struct xtensa_thread_stack_header { + char privilege_stack[CONFIG_MMU_PAGE_SIZE]; +} __packed __aligned(XTENSA_STACK_BASE_ALIGN); + +#define ARCH_THREAD_STACK_RESERVED \ + sizeof(struct xtensa_thread_stack_header) +#endif /* CONFIG_XTENSA_MMU */ + +#define ARCH_THREAD_STACK_OBJ_ALIGN(size) XTENSA_STACK_BASE_ALIGN +#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \ + ROUND_UP((size), XTENSA_STACK_SIZE_ALIGN) + +/* kernel stack */ +#define ARCH_KERNEL_STACK_RESERVED 0 +#define ARCH_KERNEL_STACK_OBJ_ALIGN ARCH_STACK_PTR_ALIGN + +#endif /* _ASMLANGUAGE */ + +#endif diff --git a/include/zephyr/arch/xtensa/xtensa_mmu.h b/include/zephyr/arch/xtensa/xtensa_mmu.h index d03f876af30..d4deca40b31 100644 --- a/include/zephyr/arch/xtensa/xtensa_mmu.h +++ b/include/zephyr/arch/xtensa/xtensa_mmu.h @@ -4,28 +4,147 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H #define ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H -#define Z_XTENSA_MMU_X BIT(0) -#define Z_XTENSA_MMU_W BIT(1) -#define Z_XTENSA_MMU_CACHED_WB BIT(2) -#define Z_XTENSA_MMU_CACHED_WT BIT(3) -#define Z_XTENSA_MMU_ILLEGAL (BIT(3) | BIT(2)) +/** + * @defgroup xtensa_mmu_apis Xtensa Memory Management Unit (MMU) APIs + * @ingroup xtensa_apis + * @{ + */ + +/** + * @name Memory region permission and caching mode. + * @{ + */ + +/** Memory region is executable. */ +#define XTENSA_MMU_PERM_X BIT(0) + +/** Memory region is writable. */ +#define XTENSA_MMU_PERM_W BIT(1) + +/** Memory region is both executable and writable */ +#define XTENSA_MMU_PERM_WX (XTENSA_MMU_PERM_W | XTENSA_MMU_PERM_X) + +/** Memory region has write-back cache. */ +#define XTENSA_MMU_CACHED_WB BIT(2) + +/** Memory region has write-through cache. */ +#define XTENSA_MMU_CACHED_WT BIT(3) + +/** + * @} + */ + +/** + * @name Memory domain and partitions + * @{ + */ + +typedef uint32_t k_mem_partition_attr_t; + +#define K_MEM_PARTITION_IS_EXECUTABLE(attr) (((attr) & XTENSA_MMU_PERM_X) != 0) +#define K_MEM_PARTITION_IS_WRITABLE(attr) (((attr) & XTENSA_MMU_PERM_W) != 0) +#define K_MEM_PARTITION_IS_USER(attr) (((attr) & XTENSA_MMU_MAP_USER) != 0) + +/* Read-Write access permission attributes */ +#define K_MEM_PARTITION_P_RW_U_RW \ + ((k_mem_partition_attr_t) {XTENSA_MMU_PERM_W | XTENSA_MMU_MAP_USER}) +#define K_MEM_PARTITION_P_RW_U_NA \ + ((k_mem_partition_attr_t) {0}) +#define K_MEM_PARTITION_P_RO_U_RO \ + ((k_mem_partition_attr_t) {XTENSA_MMU_MAP_USER}) +#define K_MEM_PARTITION_P_RO_U_NA \ + ((k_mem_partition_attr_t) {0}) +#define K_MEM_PARTITION_P_NA_U_NA \ + ((k_mem_partition_attr_t) {0}) + +/* Execution-allowed attributes */ +#define K_MEM_PARTITION_P_RX_U_RX \ + ((k_mem_partition_attr_t) {XTENSA_MMU_PERM_X}) + +/** + * @} + */ + +/** + * @brief Software only bit to indicate a memory region can be accessed by user thread(s). + * + * This BIT tells the mapping code which ring PTE entries to use. + */ +#define XTENSA_MMU_MAP_USER BIT(4) -/* Struct used to map a memory region */ +/** + * @brief Software only bit to indicate a memory region is shared by all threads. + * + * This BIT tells the mapping code whether the memory region should + * be shared between all threads. That is not used in the HW, it is + * just for the implementation. + * + * The PTE mapping this memory will use an ASID that is set in the + * ring 4 spot in RASID. + */ +#define XTENSA_MMU_MAP_SHARED BIT(30) + +/** + * Struct used to map a memory region. + */ struct xtensa_mmu_range { + /** Name of the memory region. */ const char *name; + + /** Start address of the memory region. */ const uint32_t start; + + /** End address of the memory region. */ const uint32_t end; + + /** Attributes for the memory region. */ const uint32_t attrs; }; +/** + * @brief Additional memory regions required by SoC. + * + * These memory regions will be setup by MMU initialization code at boot. + */ extern const struct xtensa_mmu_range xtensa_soc_mmu_ranges[]; + +/** Number of SoC additional memory regions. */ extern int xtensa_soc_mmu_ranges_num; -void z_xtensa_mmu_init(void); +/** + * @brief Initialize hardware MMU. + * + * This initializes the MMU hardware and setup the memory regions at boot. + */ +void xtensa_mmu_init(void); + +/** + * @brief Tell other processors to flush TLBs. + * + * This sends IPI to other processors to telling them to + * invalidate cache to page tables and flush TLBs. This is + * needed when one processor is updating page tables that + * may affect threads running on other processors. + * + * @note This needs to be implemented in the SoC layer. + */ +void xtensa_mmu_tlb_ipi(void); -void z_xtensa_mmu_smp_init(void); +/** + * @brief Invalidate cache to page tables and flush TLBs. + * + * This invalidates cache to all page tables and flush TLBs + * as they may have been modified by other processors. + */ +void xtensa_mmu_tlb_shootdown(void); + +/** + * @} + */ #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_MMU_H */ diff --git a/include/zephyr/audio/dmic.h b/include/zephyr/audio/dmic.h index e6736b8676c..e0582c45deb 100644 --- a/include/zephyr/audio/dmic.h +++ b/include/zephyr/audio/dmic.h @@ -48,6 +48,7 @@ enum dmic_state { DMIC_STATE_CONFIGURED, /**< Configured */ DMIC_STATE_ACTIVE, /**< Active */ DMIC_STATE_PAUSED, /**< Paused */ + DMIC_STATE_ERROR, /**< Error */ }; /** @@ -231,8 +232,8 @@ static inline void dmic_parse_channel_map(uint32_t channel_map_lo, channel_map = (channel < 8) ? channel_map_lo : channel_map_hi; channel_map >>= ((channel & BIT_MASK(3)) * 4U); - *pdm = (channel >> 1) & BIT_MASK(3); - *lr = (enum pdm_lr) (channel & BIT(0)); + *pdm = (channel_map >> 1) & BIT_MASK(3); + *lr = (enum pdm_lr) (channel_map & BIT(0)); } /** diff --git a/include/zephyr/bluetooth/audio/audio.h b/include/zephyr/bluetooth/audio/audio.h index 03f451a3c8b..e6ad69e58ce 100644 --- a/include/zephyr/bluetooth/audio/audio.h +++ b/include/zephyr/bluetooth/audio/audio.h @@ -174,12 +174,14 @@ enum bt_audio_metadata_type { }; /** - * Helper to check whether metadata type is known by the stack. + * @brief Helper to check whether metadata type is known by the stack. + * + * @note @p _type is evaluated thrice. */ -#define BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ - (IN_RANGE(_type, BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ - BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE) || \ - IN_RANGE(_type, BT_AUDIO_METADATA_TYPE_EXTENDED, BT_AUDIO_METADATA_TYPE_VENDOR)) +#define BT_AUDIO_METADATA_TYPE_IS_KNOWN(_type) \ + (IN_RANGE((_type), BT_AUDIO_METADATA_TYPE_PREF_CONTEXT, \ + BT_AUDIO_METADATA_TYPE_BROADCAST_IMMEDIATE) || \ + (_type) == BT_AUDIO_METADATA_TYPE_EXTENDED || (_type) == BT_AUDIO_METADATA_TYPE_VENDOR) /* Unicast Announcement Type, Generic Audio */ #define BT_AUDIO_UNICAST_ANNOUNCEMENT_GENERAL 0x00 @@ -247,7 +249,7 @@ enum bt_audio_metadata_type { * These values are defined by the Generic Audio Assigned Numbers, bluetooth.com */ enum bt_audio_location { - BT_AUDIO_LOCATION_PROHIBITED = 0, + BT_AUDIO_LOCATION_MONO_AUDIO = 0, BT_AUDIO_LOCATION_FRONT_LEFT = BIT(0), BT_AUDIO_LOCATION_FRONT_RIGHT = BIT(1), BT_AUDIO_LOCATION_FRONT_CENTER = BIT(2), @@ -800,10 +802,13 @@ int bt_audio_codec_cfg_set_frame_blocks_per_sdu(struct bt_audio_codec_cfg *codec * @param[in] codec_cfg The codec data to search in. * @param[in] type The type id to look for * @param[out] data Pointer to the data-pointer to update when item is found - * @return Length of found @p data or 0 if not found + * + * @retval Length of found @p data (may be 0) + * @retval -EINVAL if arguments are invalid + * @retval -ENODATA if not found */ -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, - enum bt_audio_codec_config_type type, const uint8_t **data); +int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data); /** * @brief Set or add a specific codec configuration value @@ -821,6 +826,20 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_codec_config_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration value + * + * The type and the value will be removed from the codec configuration. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type); + /** @brief Lookup a specific metadata value based on type * * @@ -851,6 +870,19 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec configuration metadata value + * + * The type and the value will be removed from the codec configuration metadata. + * + * @param codec_cfg The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cfg on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type); /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. @@ -1165,10 +1197,12 @@ int bt_audio_codec_cfg_meta_set_vendor(struct bt_audio_codec_cfg *codec_cfg, * @param[in] type The type id to look for * @param[out] data Pointer to the data-pointer to update when item is found * - * @return Length of found @p data or 0 if not found + * @retval Length of found @p data (may be 0) + * @retval -EINVAL if arguments are invalid + * @retval -ENODATA if not found */ -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, - enum bt_audio_codec_capability_type type, const uint8_t **data); +int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data); /** * @brief Set or add a specific codec capability value @@ -1186,6 +1220,20 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_codec_capability_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability value + * + * The type and the value will be removed from the codec capability. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The data_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type); + /** * @brief Extract the frequency from a codec capability. * @@ -1344,6 +1392,20 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, enum bt_audio_metadata_type type, const uint8_t *data, size_t data_len); +/** + * @brief Unset a specific codec capability metadata value + * + * The type and the value will be removed from the codec capability metadata. + * + * @param codec_cap The codec data to set the value in. + * @param type The type id to unset. + * + * @retval The meta_len of @p codec_cap on success + * @retval -EINVAL if arguments are invalid + */ +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type); + /** @brief Extract preferred contexts * * See @ref BT_AUDIO_METADATA_TYPE_PREF_CONTEXT for more information about this value. diff --git a/include/zephyr/bluetooth/audio/bap.h b/include/zephyr/bluetooth/audio/bap.h index 77c63ba598b..793364435d3 100644 --- a/include/zephyr/bluetooth/audio/bap.h +++ b/include/zephyr/bluetooth/audio/bap.h @@ -34,22 +34,6 @@ extern "C" { #define BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS 0 #endif -/** The minimum size of a Broadcast Audio Source Endpoint (BASE) - * 2 octets UUID - * 3 octets presentation delay - * 1 octet number of subgroups (which is minimum 1) - * 1 octet number of BIS (which is minimum 1) - * 5 octets codec_id - * 1 octet codec configuration length (which may be 0) - * 1 octet metadata length (which may be 0) - * 1 octet BIS index - * 1 octet BIS specific codec configuration length (which may be 0) - */ -#define BT_BAP_BASE_MIN_SIZE 16 - -/** The minimum size of a bt_bap_base_bis_data */ -#define BT_BAP_BASE_BIS_DATA_MIN_SIZE 2 /* index and length */ - /** Periodic advertising state reported by the Scan Delegator */ enum bt_bap_pa_state { /** The periodic advertising has not been synchronized */ @@ -102,17 +86,6 @@ enum bt_bap_bass_att_err { */ #define BT_BAP_BIS_SYNC_NO_PREF 0xFFFFFFFF -#if defined(CONFIG_BT_BAP_BROADCAST_SINK) -/* TODO: Since these are also used for the broadcast assistant, - * they should not be tied to the broadcast sink - */ -#define BROADCAST_SNK_STREAM_CNT CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT -#define BROADCAST_SNK_SUBGROUP_CNT CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT -#else /* !CONFIG_BT_BAP_BROADCAST_SINK */ -#define BROADCAST_SNK_STREAM_CNT 0 -#define BROADCAST_SNK_SUBGROUP_CNT 0 -#endif /* CONFIG_BT_BAP_BROADCAST_SINK*/ - /** Endpoint states */ enum bt_bap_ep_state { /** Audio Stream Endpoint Idle state */ @@ -210,7 +183,19 @@ enum bt_bap_ascs_reason { /** @brief Structure storing values of fields of ASE Control Point notification. */ struct bt_bap_ascs_rsp { - /** @brief Value of the Response Code field. */ + /** + * @brief Value of the Response Code field. + * + * The following response codes are accepted: + * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS + * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED + * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED + * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM + * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED + */ enum bt_bap_ascs_rsp_code code; /** @@ -225,16 +210,10 @@ struct bt_bap_ascs_rsp { * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED - * - @ref BT_BAP_ASCS_RSP_CODE_CONF_INVALID * all values from @ref bt_bap_ascs_reason can be used. * * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS - * - @ref BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_LENGTH - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE - * - @ref BT_BAP_ASCS_RSP_CODE_INVALID_DIR * - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM * - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED @@ -248,7 +227,6 @@ struct bt_bap_ascs_rsp { * If the Response Code is one of the following: * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED - * - @ref BT_BAP_ASCS_RSP_CODE_METADATA_INVALID * the value of the Metadata Type shall be used. */ enum bt_audio_metadata_type metadata_type; @@ -276,7 +254,6 @@ struct bt_bap_unicast_group; /** @brief Abstract Audio Endpoint structure. */ struct bt_bap_ep; -/* TODO: Replace with struct bt_bap_base_subgroup */ /** Struct to hold subgroup specific information for the receive state */ struct bt_bap_scan_delegator_subgroup { /** BIS synced bitfield */ @@ -597,15 +574,45 @@ struct bt_bap_stream_ops { /** * @brief Stream audio HCI sent callback * - * If this callback is provided it will be called whenever a SDU has been completely sent, - * or otherwise flushed due to transmission issues. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. * * This callback is only used if the ISO data path is HCI. * - * @param chan The channel which has sent data. + * @param stream Stream object. */ void (*sent)(struct bt_bap_stream *stream); #endif /* CONFIG_BT_AUDIO_TX */ + + /** + * @brief Isochronous channel connected callback + * + * If this callback is provided it will be called whenever the isochronous channel for the + * stream has been connected. This does not mean that the stream is ready to be used, which + * is indicated by the @ref bt_bap_stream_ops.started callback. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * still be called, without the stream going into the started state. + * + * @param stream Stream object. + */ + void (*connected)(struct bt_bap_stream *stream); + + /** + * @brief Isochronous channel disconnected callback + * + * If this callback is provided it will be called whenever the isochronous channel is + * disconnected, including when a connection gets rejected. + * + * If the stream shares an isochronous channel with another stream, then this callback may + * not be called, even if the stream is leaving the streaming state. + * + * @param stream Stream object. + * @param reason BT_HCI_ERR_* reason for the disconnection. + */ + void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason); }; /** @@ -1351,55 +1358,178 @@ int bt_bap_unicast_client_discover(struct bt_conn *conn, enum bt_audio_dir dir); * @{ */ -struct bt_bap_base_bis_data { +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) subgroup structure. */ +struct bt_bap_base_subgroup; +/** @brief Abstract Broadcast Audio Source Endpoint (BASE) structure. */ +struct bt_bap_base; + +/** Codec ID structure for a Broadcast Audio Source Endpoint (BASE) */ +struct bt_bap_base_codec_id { + /** Codec ID */ + uint8_t id; + /** Codec Company ID */ + uint16_t cid; + /** Codec Company Vendor ID */ + uint16_t vid; +}; + +/** BIS structure for each BIS in a Broadcast Audio Source Endpoint (BASE) subgroup */ +struct bt_bap_base_subgroup_bis { /* Unique index of the BIS */ uint8_t index; -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 /** Codec Specific Data length. */ - size_t data_len; + uint8_t data_len; /** Codec Specific Data */ - uint8_t data[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE]; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ + uint8_t *data; }; -struct bt_bap_base_subgroup { - /* Number of BIS in the subgroup */ - size_t bis_count; - /** Codec information for the subgroup - * - * If the data_len of the codec is 0, then codec specific data may be - * found for each BIS in the bis_data. - */ - struct bt_audio_codec_cfg codec_cfg; - /* Array of BIS specific data for each BIS in the subgroup */ - struct bt_bap_base_bis_data bis_data[BROADCAST_SNK_STREAM_CNT]; -}; +/** + * @brief Generate a pointer to a BASE from periodic advertising data + * + * @param ad The periodic advertising data + * + * @retval NULL if the data does not contain a BASE + * @retval Pointer to a bt_bap_base structure + */ +const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad); -struct bt_bap_base { - /** @brief QoS Presentation Delay in microseconds - * - * Value range 0 to @ref BT_AUDIO_PD_MAX. - */ - uint32_t pd; +/** + * @brief Get the presentation delay value of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 24-bit presentation delay value + */ +int bt_bap_base_get_pres_delay(const struct bt_bap_base *base); + +/** + * @brief Get the subgroup count of a BASE + * + * @param base The BASE pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit subgroup count value + */ +int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base); + +/** + * @brief Get all BIS indexes of a BASE + * + * @param[in] base The BASE pointer + * @param[out] bis_indexes 32-bit BIS index bitfield that will be populated + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes); - /* Number of subgroups in the BASE */ - size_t subgroup_count; +/** + * @brief Iterate on all subgroups in the BASE + * + * @param base The BASE pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all subgroups were iterated + */ +int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, + bool (*func)(const struct bt_bap_base_subgroup *subgroup, + void *user_data), + void *user_data); - /* Array of subgroups in the BASE */ - struct bt_bap_base_subgroup subgroups[BROADCAST_SNK_SUBGROUP_CNT]; -}; +/** + * @brief Get the codec ID of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_id Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup, + struct bt_bap_base_codec_id *codec_id); -/** @brief Decode a Broadcast Audio Source Endpoint (BASE) from advertising data +/** + * @brief Get the codec configuration data of a subgroup * - * The BASE is sent via periodic advertising, and can be decoded into a - * bt_bap_base using this function. + * @param[in] subgroup The subgroup pointer + * @param[out] data Pointer that will point to the resulting codec configuration data * - * @param data The periodic advertising data - * @param base The output struct to put the decode BASE in + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, + uint8_t **data); + +/** + * @brief Get the codec metadata of a subgroup + * + * @param[in] subgroup The subgroup pointer + * @param[out] meta Pointer that will point to the resulting codec metadata * - * @return 0 in case of success or negative errno value in case of error. + * @retval -EINVAL if arguments are invalid + * @retval 0 on success + */ +int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, + uint8_t **meta); + +/** + * @brief Store subgroup codec data in a @ref bt_audio_codec_cfg + * + * @param[in] subgroup The subgroup pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success + */ +int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup, + struct bt_audio_codec_cfg *codec_cfg); + +/** + * @brief Get the BIS count of a subgroup + * + * @param subgroup The subgroup pointer + * + * @retval -EINVAL if arguments are invalid + * @retval The 8-bit BIS count value + */ +int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup); + +/** + * @brief Iterate on all BIS in the subgroup + * + * @param subgroup The subgroup pointer + * @param func Callback function. Return true to continue iterating, or false to stop. + * @param user_data Userdata supplied to @p func + * + * @retval -EINVAL if arguments are invalid + * @retval -ECANCELED if iterating over the subgroups stopped prematurely by @p func + * @retval 0 if all BIS were iterated + */ +int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup, + bool (*func)(const struct bt_bap_base_subgroup_bis *bis, + void *user_data), + void *user_data); + +/** + * @brief Store BIS codec configuration data in a @ref bt_audio_codec_cfg + * + * This only sets the @ref bt_audio_codec_cfg data and @ref bt_audio_codec_cfg data_len, but is + * useful to use the BIS codec configuration data with the bt_audio_codec_cfg_* functions. + * + * @param[in] bis The BIS pointer + * @param[out] codec_cfg Pointer to the struct where the results are placed + * + * @retval -EINVAL if arguments are invalid + * @retval -ENOMEM if the @p codec_cfg cannot store the @p subgroup codec data + * @retval 0 on success */ -int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base); +int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis, + struct bt_audio_codec_cfg *codec_cfg); /** @} */ /* End of group bt_bap_broadcast */ @@ -1649,8 +1779,10 @@ struct bt_bap_broadcast_sink_cb { * * @param sink Pointer to the sink structure. * @param base Broadcast Audio Source Endpoint (BASE). + * @param base_size Size of the @p base */ - void (*base_recv)(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base); + void (*base_recv)(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size); /** @brief Broadcast sink is syncable * diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 06da5700506..c595e6171fd 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -76,8 +76,6 @@ struct bt_cap_initiator_cb { /** * @brief Callback for bt_cap_initiator_unicast_audio_start(). * - * @param unicast_group The unicast group pointer supplied to - * bt_cap_initiator_unicast_audio_start(). * @param err 0 if success, BT_GATT_ERR() with a * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled * by bt_cap_initiator_unicast_audio_cancel(). @@ -85,8 +83,7 @@ struct bt_cap_initiator_cb { * occurred. NULL if @p err is 0 or if cancelled by * bt_cap_initiator_unicast_audio_cancel() */ - void (*unicast_start_complete)(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn); + void (*unicast_start_complete)(int err, struct bt_conn *conn); /** * @brief Callback for bt_cap_initiator_unicast_audio_update(). @@ -103,14 +100,6 @@ struct bt_cap_initiator_cb { /** * @brief Callback for bt_cap_initiator_unicast_audio_stop(). * - * If @p err is 0, then @p unicast_group has been deleted and can no - * longer be used. - * - * If @p err is not 0 and @p conn is NULL, then the deletion of the - * @p unicast_group failed with @p err as the error. - * - * @param unicast_group The unicast group pointer supplied to - * bt_cap_initiator_unicast_audio_stop(). * @param err 0 if success, BT_GATT_ERR() with a * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled * by bt_cap_initiator_unicast_audio_cancel(). @@ -118,8 +107,7 @@ struct bt_cap_initiator_cb { * occurred. NULL if @p err is 0 or if cancelled by * bt_cap_initiator_unicast_audio_cancel() */ - void (*unicast_stop_complete)(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn); + void (*unicast_stop_complete)(int err, struct bt_conn *conn); #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ }; @@ -131,7 +119,10 @@ struct bt_cap_initiator_cb { * * @param conn Connection to a remote server. * - * @return 0 on success or negative error value on failure. + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request */ int bt_cap_initiator_unicast_discover(struct bt_conn *conn); @@ -203,6 +194,7 @@ int bt_cap_stream_send(struct bt_cap_stream *stream, struct net_buf *buf, uint16 */ int bt_cap_stream_get_tx_sync(struct bt_cap_stream *stream, struct bt_iso_tx_info *info); +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_start() function */ struct bt_cap_unicast_audio_start_stream_param { /** Coordinated or ad-hoc set member. */ union bt_cap_set_member member; @@ -223,6 +215,7 @@ struct bt_cap_unicast_audio_start_stream_param { struct bt_audio_codec_cfg *codec_cfg; }; +/** Parameters for the bt_cap_initiator_unicast_audio_start() function */ struct bt_cap_unicast_audio_start_param { /** The type of the set. */ enum bt_cap_set_type type; @@ -234,8 +227,9 @@ struct bt_cap_unicast_audio_start_param { struct bt_cap_unicast_audio_start_stream_param *stream_params; }; -struct bt_cap_unicast_audio_update_param { - /** @brief Stream for the @p member */ +/** Stream specific parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_stream_param { + /** Stream to update */ struct bt_cap_stream *stream; /** The length of @p meta. */ @@ -249,8 +243,32 @@ struct bt_cap_unicast_audio_update_param { uint8_t *meta; }; +/** Parameters for the bt_cap_initiator_unicast_audio_update() function */ +struct bt_cap_unicast_audio_update_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of parameters in @p stream_params */ + size_t count; + + /** Array of stream parameters */ + struct bt_cap_unicast_audio_update_stream_param *stream_params; +}; + +/** Parameters for the bt_cap_initiator_unicast_audio_stop() function */ +struct bt_cap_unicast_audio_stop_param { + /** The type of the set. */ + enum bt_cap_set_type type; + + /** The number of streams in @p streams */ + size_t count; + + /** Array of streams to stop */ + struct bt_cap_stream **streams; +}; + /** - * @brief Register Common Audio Profile callbacks + * @brief Register Common Audio Profile Initiator callbacks * * @param cb The callback structure. Shall remain static. * @@ -269,13 +287,11 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb); * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param[in] param Parameters to start the audio streams. - * @param[out] unicast_group Pointer to the unicast group. + * @param param Parameters to start the audio streams. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group); +int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param); /** * @brief Update unicast audio streams. @@ -286,35 +302,33 @@ int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param params Array of update parameters. - * @param count The number of entries in @p params. + * @param param Update parameters. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], - size_t count); +int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param); /** - * @brief Stop unicast audio streams for a unicast group. + * @brief Stop unicast audio streams. + * + * This will stop one or more streams. * * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} must be enabled for this function * to be enabled. * - * @param unicast_group The group of unicast devices to stop. The audio streams - * in this will be stopped and reset, and the - * @p unicast_group will be invalidated. + * @param param Stop parameters. * * @return 0 on success or negative error value on failure. */ -int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group); +int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param); /** @brief Cancel any current Common Audio Profile procedure * * This will stop the current procedure from continuing and making it possible to run a new * Common Audio Profile procedure. * - * It is recommended to do this if any existing procedure take longer time than expected, which + * It is recommended to do this if any existing procedure takes longer time than expected, which * could indicate a missing response from the Common Audio Profile Acceptor. * * This does not send any requests to any Common Audio Profile Acceptors involved with the current @@ -427,7 +441,7 @@ struct bt_cap_initiator_broadcast_create_param { * @brief Create a Common Audio Profile broadcast source. * * Create a new audio broadcast source with one or more audio streams. - * * * + * * @note @kconfig{CONFIG_BT_CAP_INITIATOR} and * @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} must be enabled for this function * to be enabled. @@ -493,7 +507,7 @@ int bt_cap_initiator_broadcast_audio_update(struct bt_cap_broadcast_source *broa */ int bt_cap_initiator_broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source); -/* +/** * @brief Delete Common Audio Profile broadcast source * * This can only be done after the broadcast source has been stopped by calling @@ -636,6 +650,73 @@ struct bt_cap_broadcast_to_unicast_param { int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unicast_param *param, struct bt_bap_unicast_group **unicast_group); +/** Callback structure for CAP procedures */ +struct bt_cap_commander_cb { + /** + * @brief Callback for bt_cap_initiator_unicast_discover(). + * + * @param conn The connection pointer supplied to + * bt_cap_initiator_unicast_discover(). + * @param err 0 if Common Audio Service was found else -ENODATA. + * @param csis_inst The Coordinated Set Identification Service if + * Common Audio Service was found and includes a + * Coordinated Set Identification Service. + * NULL on error or if remote device does not include + * Coordinated Set Identification Service. + */ + void (*discovery_complete)(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst); + +#if defined(CONFIG_BT_VCP_VOL_CTLR) + /** + * @brief Callback for bt_cap_commander_change_volume(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_commander_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_commander_cancel(). + */ + void (*volume_changed)(struct bt_conn *conn, int err); + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + /** + * @brief Callback for bt_cap_commander_change_volume_offset(). + * + * @param conn Pointer to the connection where the error + * occurred. NULL if @p err is 0 or if cancelled by + * bt_cap_initiator_unicast_audio_cancel() + * @param err 0 on success, BT_GATT_ERR() with a + * specific ATT (BT_ATT_ERR_*) error code or -ECANCELED if cancelled + * by bt_cap_initiator_unicast_audio_cancel(). + */ + void (*volume_offset_changed)(struct bt_conn *conn, int err); +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#endif /* CONFIG_BT_VCP_VOL_CTLR */ +}; + +/** + * @brief Register Common Audio Profile Commander callbacks + * + * @param cb The callback structure. Shall remain static. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL + * @retval -EALREADY Callbacks are already registered + */ +int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb); + +/** + * @brief Unregister Common Audio Profile Commander callbacks + * + * @param cb The callback structure that was previously registered. + * + * @retval 0 Success + * @retval -EINVAL @p cb is NULL or @p cb was not registered + */ +int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb); + /** * @brief Discovers audio support on a remote device. * @@ -644,13 +725,41 @@ int bt_cap_initiator_broadcast_to_unicast(const struct bt_cap_broadcast_to_unica * * @note @kconfig{CONFIG_BT_CAP_COMMANDER} must be enabled for this function. If * @kconfig{CONFIG_BT_CAP_INITIATOR} is also enabled, it does not matter if - * bt_cap_commander_unicast_discover() or bt_cap_initiator_unicast_discover() is used. + * bt_cap_commander_discover() or bt_cap_initiator_unicast_discover() is used. * * @param conn Connection to a remote server. * - * @return 0 on success or negative error value on failure. + * @retval 0 Success + * @retval -EINVAL @p conn is NULL + * @retval -ENOTCONN @p conn is not connected + * @retval -ENOMEM Could not allocated memory for the request + * @retval -EBUSY Already doing discovery for @p conn + */ +int bt_cap_commander_discover(struct bt_conn *conn); + +/** @brief Cancel any current Common Audio Profile commander procedure + * + * This will stop the current procedure from continuing and making it possible to run a new + * Common Audio Profile procedure. + * + * It is recommended to do this if any existing procedure takes longer time than expected, which + * could indicate a missing response from the Common Audio Profile Acceptor. + * + * This does not send any requests to any Common Audio Profile Acceptors involved with the current + * procedure, and thus notifications from the Common Audio Profile Acceptors may arrive after this + * has been called. It is thus recommended to either only use this if a procedure has stalled, or + * wait a short while before starting any new Common Audio Profile procedure after this has been + * called to avoid getting notifications from the cancelled procedure. The wait time depends on + * the connection interval, the number of devices in the previous procedure and the behavior of the + * Common Audio Profile Acceptors. + * + * The respective callbacks of the procedure will be called as part of this with the connection + * pointer set to NULL and the err value set to -ECANCELED. + * + * @retval 0 on success + * @retval -EALREADY if no procedure is active */ -int bt_cap_commander_unicast_discover(struct bt_conn *conn); +int bt_cap_commander_cancel(void); struct bt_cap_commander_broadcast_reception_start_member_param { /** Coordinated or ad-hoc set member. */ diff --git a/include/zephyr/bluetooth/audio/csip.h b/include/zephyr/bluetooth/audio/csip.h index 9e96ef58748..a8b04dcb440 100644 --- a/include/zephyr/bluetooth/audio/csip.h +++ b/include/zephyr/bluetooth/audio/csip.h @@ -186,6 +186,17 @@ void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst * int bt_csip_set_member_register(const struct bt_csip_set_member_register_param *param, struct bt_csip_set_member_svc_inst **svc_inst); +/** + * @brief Unregister a Coordinated Set Identification Service instance. + * + * This will unregister and disable the service instance. + * + * @param svc_inst Pointer to the registered Coordinated Set Identification Service. + * + * @return 0 if success, errno on failure. + */ +int bt_csip_set_member_unregister(struct bt_csip_set_member_svc_inst *svc_inst); + /** * @brief Print the SIRK to the debug output * diff --git a/include/zephyr/bluetooth/audio/gmap.h b/include/zephyr/bluetooth/audio/gmap.h new file mode 100644 index 00000000000..292fd6eca2b --- /dev/null +++ b/include/zephyr/bluetooth/audio/gmap.h @@ -0,0 +1,235 @@ +/** + * @file + * @brief Header for Bluetooth Gaming Audio Profile (GMAP). + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ + +#include +#include + +/** + * @brief Bluetooth Gaming Audio Profile (GMAP) + * @defgroup bt_gmap Bluetooth Gaming Audio Profile + * @ingroup bluetooth + * @{ + */ + +/** Gaming Role bitfield */ +enum bt_gmap_role { + /** + * @brief Gaming Role Unicast Game Gateway + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR}, @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT} and + * @kconfig{CONFIG_BT_VCP_VOL_CTLR} to be enabled. + */ + BT_GMAP_ROLE_UGG = BIT(0), + /** + * @brief Gaming Role Unicast Game Terminal + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR} and @kconfig{CONFIG_BT_BAP_UNICAST_SERVER} to + * be enabled. + */ + BT_GMAP_ROLE_UGT = BIT(1), + /** + * @brief Gaming Role Broadcast Game Sender + * + * Requires @kconfig{CONFIG_BT_CAP_INITIATOR} and @kconfig{CONFIG_BT_BAP_BROADCAST_SOURCE} + * to be enabled. + */ + BT_GMAP_ROLE_BGS = BIT(2), + /** + * @brief Gaming Role Broadcast Game Receiver + * + * Requires @kconfig{CONFIG_BT_CAP_ACCEPTOR}, @kconfig{CONFIG_BT_BAP_BROADCAST_SINK} and + * @kconfig{CONFIG_BT_VCP_VOL_REND} to be enabled. + */ + BT_GMAP_ROLE_BGR = BIT(3), +}; + +/** Unicast Game Gateway Feature bitfield */ +enum bt_gmap_ugg_feat { + /** + * @brief Support transmitting multiple LC3 codec frames per block in an SDU + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_MULTIPLEX = BIT(0), + /** + * @brief 96 kbps source support + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGG_FEAT_96KBPS_SOURCE = BIT(1), + /** + * @brief Support for receiving at least two channels of audio, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT} > 1 + */ + BT_GMAP_UGG_FEAT_MULTISINK = BIT(2), +}; + +/** Unicast Game Terminal Feature bitfield */ +enum bt_gmap_ugt_feat { + /** + * @brief Source support + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SOURCE = BIT(0), + /** + * @brief 80 kbps source support + * + * Requires BT_GMAP_UGT_FEAT_SOURCE to be set as well + */ + BT_GMAP_UGT_FEAT_80KBPS_SOURCE = BIT(1), + /** + * @brief Sink support + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 0 + */ + BT_GMAP_UGT_FEAT_SINK = BIT(2), + /** + * @brief 64 kbps sink support + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_64KBPS_SINK = BIT(3), + /** + * @brief Support for receiving multiple LC3 codec frames per block in an SDU + * + * Requires BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTIPLEX = BIT(4), + /** + * @brief Support for receiving at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SNK_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SINK to be set as well + */ + BT_GMAP_UGT_FEAT_MULTISINK = BIT(5), + /** + * @brief Support for sending at least two audio channels, each in a separate CIS + * + * Requires @kconfig{CONFIG_BT_ASCS_ASE_SRC_COUNT} > 1 and + * @kconfig{CONFIG_BT_ASCS_MAX_ACTIVE_ASES} > 1, and BT_GMAP_UGT_FEAT_SOURCE to be set + * as well + */ + BT_GMAP_UGT_FEAT_MULTISOURCE = BIT(6), +}; + +/** Broadcast Game Sender Feature bitfield */ +enum bt_gmap_bgs_feat { + /** 96 kbps support */ + BT_GMAP_BGS_FEAT_96KBPS = BIT(0), +}; + +/** Broadcast Game Receiver Feature bitfield */ +enum bt_gmap_bgr_feat { + /** + * @brief Support for receiving at least two audio channels, each in a separate BIS + * + * Requires @kconfig{CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT} > 1 + */ + BT_GMAP_BGR_FEAT_MULTISINK = BIT(0), + /** @brief Support for receiving multiple LC3 codec frames per block in an SDU */ + BT_GMAP_BGR_FEAT_MULTIPLEX = BIT(1), +}; + +/** Broadcast Game Receiver Feature bitfield */ +struct bt_gmap_feat { + /** Unicast Game Gateway features */ + enum bt_gmap_ugg_feat ugg_feat; + /** Unicast Game Terminal features */ + enum bt_gmap_ugt_feat ugt_feat; + /** Remote Broadcast Game Sender features */ + enum bt_gmap_bgs_feat bgs_feat; + /** Remote Broadcast Game Receiver features */ + enum bt_gmap_bgr_feat bgr_feat; +}; + +/** @brief Hearing Access Service Client callback structure. */ +struct bt_gmap_cb { + /** + * @brief Callback function for bt_has_discover. + * + * This callback is called when discovery procedure is complete. + * + * @param conn Bluetooth connection object. + * @param err 0 on success, ATT error or negative errno otherwise. + * @param role Role of remote device. 0 on failure. + * @param features Remote features. + */ + void (*discover)(struct bt_conn *conn, int err, enum bt_gmap_role role, + struct bt_gmap_feat features); +}; + +/** + * @brief Registers the callbacks used by the Gaming Audio Profile. + * + * @param cb The callback structure. + * + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if callbacks have already be registered + * @retval 0 on success + */ +int bt_gmap_cb_register(const struct bt_gmap_cb *cb); + +/** + * @brief Discover Gaming Service on a remote device. + * + * Procedure to find a Gaming Service on a server identified by @p conn. + * The @ref bt_gmap_cb.discover callback is called when the discovery procedure completes of fails. + * On discovery success the callback contains information about the remote device. + * + * @param conn Bluetooth connection object. + * + * @retval -EINVAL if @p conn is NULL + * @retval -EBUSY if discovery is already in progress for @p conn + * @retval -ENOEXEC if discovery failed to initiate + * @retval 0 on success + */ +int bt_gmap_discover(struct bt_conn *conn); + +/** + * @brief Adds GMAS instance to database and sets the received Gaming Audio Profile role(s). + * + * @param role Gaming Audio Profile role(s) of the device (one or multiple). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -EINVAL on invalid arguments + * @retval -ENOEXEC on service register failure + * @retval 0 on success + */ +int bt_gmap_register(enum bt_gmap_role role, struct bt_gmap_feat features); + +/** + * @brief Set one or multiple Gaming Audio Profile roles and features dynamically. + * + * Previously registered value will be overwritten. If there is a role change, this will trigger + * a Gaming Audio Service (GMAS) service change. If there is only a feature change, no service + * change will happen. + * + * @param role Gaming Audio Profile role(s). + * @param features Features of the roles. If a role is not in the @p role parameter, then the + * feature value for that role is simply ignored. + * + * @retval -ENOEXEC if the service has not yet been registered + * @retval -EINVAL on invalid arguments + * @retval -EALREADY if the @p role and @p features are the same as existing ones + * @retval -ENOENT on service unregister failure + * @retval -ECANCELED on service re-register failure + * @retval 0 on success + */ +int bt_gmap_set_role(enum bt_gmap_role role, struct bt_gmap_feat features); + +/** @} */ /* end of bt_gmap */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_ */ diff --git a/include/zephyr/bluetooth/audio/gmap_lc3_preset.h b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h new file mode 100644 index 00000000000..71289da2292 --- /dev/null +++ b/include/zephyr/bluetooth/audio/gmap_lc3_preset.h @@ -0,0 +1,182 @@ +/** @file + * @brief Header for Bluetooth GMAP LC3 presets. + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ + +#include + +/* GMAP LC3 unicast presets defined by table 3.16 in the GMAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 32_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 32_2_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_1_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_gr codec configuration + * + * Mandatory to support as both unicast client and server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_gr codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_3_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90U, 1U, 15U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_gr codec configuration + * + * Mandatory to support as unicast server + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_4_GR(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120U, 1U, 20U, 10000U)) + +/** + * @brief Helper to declare LC3 16_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_16_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(30U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 16_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_16_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_16_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(40U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 32_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(60U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 32_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_32_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_32_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(80U, 1U, 20U, 60000U)) + +/** + * @brief Helper to declare LC3 48_1_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 15U, 60000U)) + +/** + * @brief Helper to declare LC3 48_2_gs codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_GS(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 20U, 60000U)) + +/* GMAP LC3 broadcast presets defined by table 3.22 in the GMAP v1.0 specification */ + +/** + * @brief Helper to declare LC3 48_1_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_1_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_1(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(75U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_2_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_2_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_2(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(100U, 1U, 10U, 10000U)) + +/** + * @brief Helper to declare LC3 48_3_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_3_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_3(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_7_5_UNFRAMED(90U, 1U, 8U, 10000U)) + +/** + * @brief Helper to declare LC3 48_4_g codec configuration + * + * @param _loc Audio channel location bitfield (@ref bt_audio_location) + * @param _stream_context Stream context (``BT_AUDIO_CONTEXT_*``) + */ +#define BT_GMAP_LC3_PRESET_48_4_G(_loc, _stream_context) \ + BT_BAP_LC3_PRESET(BT_AUDIO_CODEC_LC3_CONFIG_48_4(_loc, _stream_context), \ + BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(120U, 1U, 10U, 10000U)) + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_GMAP_LC3_PRESET_ */ diff --git a/include/zephyr/bluetooth/audio/mcc.h b/include/zephyr/bluetooth/audio/mcc.h index 9744bb05863..f67eb768318 100644 --- a/include/zephyr/bluetooth/audio/mcc.h +++ b/include/zephyr/bluetooth/audio/mcc.h @@ -54,7 +54,6 @@ typedef void (*bt_mcc_discover_mcs_cb)(struct bt_conn *conn, int err); */ typedef void (*bt_mcc_read_player_name_cb)(struct bt_conn *conn, int err, const char *name); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_read_icon_obj_id() * @@ -64,8 +63,7 @@ typedef void (*bt_mcc_read_player_name_cb)(struct bt_conn *conn, int err, const * @param err Error value. 0 on success, GATT error or errno on fail * @param icon_id The ID of the Icon Object. This is a UINT48 in a uint64_t */ -typedef void (*bt_mcc_read_icon_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); -#endif /* CONFIG_BT_OTS_CLIENT */ +typedef void (*bt_mcc_read_icon_obj_id_cb)(struct bt_conn *conn, int err, uint64_t icon_id); /** * @brief Callback function for bt_mcc_read_icon_url() @@ -169,7 +167,6 @@ typedef void (*bt_mcc_set_playback_speed_cb)(struct bt_conn *conn, int err, int8 */ typedef void (*bt_mcc_read_seeking_speed_cb)(struct bt_conn *conn, int err, int8_t speed); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_read_segments_obj_id() * @@ -254,12 +251,10 @@ typedef void (*bt_mcc_read_current_group_obj_id_cb)(struct bt_conn *conn, int er * * @param conn The connection that was used to initialise the media control client * @param err Error value. 0 on success, GATT error or errno on fail - * @param id The Object ID (UINT48) set (or attempted to set) + * @param obj_id The Object ID (UINT48) set (or attempted to set) */ typedef void (*bt_mcc_set_current_group_obj_id_cb)(struct bt_conn *conn, int err, uint64_t obj_id); -#endif /* CONFIG_BT_OTS_CLIENT */ - /** * @brief Callback function for bt_mcc_read_playing_order() * @@ -343,7 +338,6 @@ typedef void (*bt_mcc_cmd_ntf_cb)(struct bt_conn *conn, int err, const struct mp typedef void (*bt_mcc_read_opcodes_supported_cb)(struct bt_conn *conn, int err, uint32_t opcodes); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Callback function for bt_mcc_send_search() * @@ -367,7 +361,7 @@ typedef void (*bt_mcc_send_search_cb)(struct bt_conn *conn, int err, * * @param conn The connection that was used to initialise the media control client * @param err Error value. 0 on success, GATT error or errno on fail - * @param ntf The search notification + * @param result_code The search notification */ typedef void (*bt_mcc_search_ntf_cb)(struct bt_conn *conn, int err, uint8_t result_code); @@ -387,7 +381,6 @@ typedef void (*bt_mcc_search_ntf_cb)(struct bt_conn *conn, int err, */ typedef void (*bt_mcc_read_search_results_obj_id_cb)(struct bt_conn *conn, int err, uint64_t id); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Callback function for bt_mcc_read_content_control_id() @@ -400,7 +393,7 @@ typedef void (*bt_mcc_read_search_results_obj_id_cb)(struct bt_conn *conn, */ typedef void (*bt_mcc_read_content_control_id_cb)(struct bt_conn *conn, int err, uint8_t ccid); -#ifdef CONFIG_BT_OTS_CLIENT + /**** Callback functions for the included Object Transfer service *************/ /** @@ -507,8 +500,6 @@ typedef void (*bt_mcc_otc_read_parent_group_object_cb)(struct bt_conn *conn, int typedef void (*bt_mcc_otc_read_current_group_object_cb)(struct bt_conn *conn, int err, struct net_buf_simple *buf); -#endif /* CONFIG_BT_OTS_CLIENT */ - /** * @brief Media control client callbacks @@ -519,15 +510,31 @@ struct bt_mcc_cb { #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_read_icon_obj_id_cb read_icon_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) bt_mcc_read_icon_url_cb read_icon_url; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ bt_mcc_track_changed_ntf_cb track_changed_ntf; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) bt_mcc_read_track_title_cb read_track_title; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) bt_mcc_read_track_duration_cb read_track_duration; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) bt_mcc_read_track_position_cb read_track_position; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) bt_mcc_set_track_position_cb set_track_position; +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) bt_mcc_read_playback_speed_cb read_playback_speed; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) bt_mcc_set_playback_speed_cb set_playback_speed; +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) bt_mcc_read_seeking_speed_cb read_seeking_speed; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_read_segments_obj_id_cb read_segments_obj_id; bt_mcc_read_current_track_obj_id_cb read_current_track_obj_id; @@ -538,19 +545,33 @@ struct bt_mcc_cb { bt_mcc_set_current_group_obj_id_cb set_current_group_obj_id; bt_mcc_read_parent_group_obj_id_cb read_parent_group_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) bt_mcc_read_playing_order_cb read_playing_order; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) bt_mcc_set_playing_order_cb set_playing_order; +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) bt_mcc_read_playing_orders_supported_cb read_playing_orders_supported; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) bt_mcc_read_media_state_cb read_media_state; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) bt_mcc_send_cmd_cb send_cmd; +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ bt_mcc_cmd_ntf_cb cmd_ntf; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) bt_mcc_read_opcodes_supported_cb read_opcodes_supported; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_send_search_cb send_search; bt_mcc_search_ntf_cb search_ntf; bt_mcc_read_search_results_obj_id_cb read_search_results_obj_id; #endif /* CONFIG_BT_OTS_CLIENT */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) bt_mcc_read_content_control_id_cb read_content_control_id; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_OTS_CLIENT bt_mcc_otc_obj_selected_cb otc_obj_selected; bt_mcc_otc_obj_metadata_cb otc_obj_metadata; @@ -600,7 +621,6 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe); */ int bt_mcc_read_player_name(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read Icon Object ID * @@ -609,7 +629,6 @@ int bt_mcc_read_player_name(struct bt_conn *conn); * @return 0 if success, errno on failure. */ int bt_mcc_read_icon_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Icon Object URL @@ -685,7 +704,6 @@ int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed); */ int bt_mcc_read_seeking_speed(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read Track Segments Object ID * @@ -720,7 +738,6 @@ int bt_mcc_set_current_track_obj_id(struct bt_conn *conn, uint64_t id); * @brief Read Next Track Object ID * * @param conn Connection to the peer device - * @param id Object Transfer Service ID (UINT48) of the track to set as the current track * * @return 0 if success, errno on failure. */ @@ -767,7 +784,6 @@ int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t id); * @return 0 if success, errno on failure. */ int bt_mcc_read_parent_group_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Playing Order @@ -827,7 +843,6 @@ int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd); */ int bt_mcc_read_opcodes_supported(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Send a Search command * @@ -848,7 +863,6 @@ int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search); * @return 0 if success, errno on failure. */ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn); -#endif /* CONFIG_BT_OTS_CLIENT */ /** * @brief Read Content Control ID @@ -859,7 +873,6 @@ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn); */ int bt_mcc_read_content_control_id(struct bt_conn *conn); -#ifdef CONFIG_BT_OTS_CLIENT /** * @brief Read the current object metadata * @@ -923,10 +936,15 @@ int bt_mcc_otc_read_current_group_object(struct bt_conn *conn); */ int bt_mcc_otc_read_parent_group_object(struct bt_conn *conn); -#if defined(CONFIG_BT_MCC_SHELL) +/** + * @brief Look up MCC OTC instance + * + * @param conn The connection to the MCC server. + * + * @return Pointer to a MCC OTC instance if found else NULL. + * + */ struct bt_ots_client *bt_mcc_otc_inst(struct bt_conn *conn); -#endif /* defined(CONFIG_BT_MCC_SHELL) */ -#endif /* CONFIG_BT_OTS_CLIENT */ #ifdef __cplusplus } diff --git a/include/zephyr/bluetooth/audio/micp.h b/include/zephyr/bluetooth/audio/micp.h index e5cbf523be0..27359ca7ffa 100644 --- a/include/zephyr/bluetooth/audio/micp.h +++ b/include/zephyr/bluetooth/audio/micp.h @@ -185,6 +185,9 @@ struct bt_micp_mic_ctlr_cb { /** Audio Input Control Service client callback */ struct bt_aics_cb aics_cb; #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + + /** Internally used field for list handling */ + sys_snode_t _node; }; /** @@ -217,6 +220,20 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, int bt_micp_mic_ctlr_conn_get(const struct bt_micp_mic_ctlr *mic_ctlr, struct bt_conn **conn); +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_micp_mic_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Microphone Control Profile Microphone Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn); + /** * @brief Discover Microphone Control Service * diff --git a/include/zephyr/bluetooth/audio/pacs.h b/include/zephyr/bluetooth/audio/pacs.h index 4b9b7e29a2a..6db4d34b0a2 100644 --- a/include/zephyr/bluetooth/audio/pacs.h +++ b/include/zephyr/bluetooth/audio/pacs.h @@ -1,5 +1,5 @@ /* @file - * @brief Internal APIs for Audio Capabilities handling + * @brief APIs for Audio Capabilities handling * * Copyright (c) 2021 Intel Corporation * Copyright (c) 2021-2022 Nordic Semiconductor ASA @@ -76,6 +76,7 @@ int bt_pacs_cap_unregister(enum bt_audio_dir dir, struct bt_pacs_cap *cap); * @param dir Direction of the endpoints to change location for. * @param location The location to be set. * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_location(enum bt_audio_dir dir, enum bt_audio_location location); @@ -84,6 +85,8 @@ int bt_pacs_set_location(enum bt_audio_dir dir, * * @param dir Direction of the endpoints to change available contexts for. * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts); @@ -96,10 +99,44 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, */ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir); +/** @brief Set the available contexts for a given connection + * + * This function sets the available contexts value for a given @p conn connection object. + * If the @p contexts parameter is NULL the available contexts value is reset to default. + * The default value of the available contexts is set using @ref bt_pacs_set_available_contexts + * function. + * The Available Context Value is reset to default on ACL disconnection. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to change available contexts for. + * @param contexts The contexts to be set or NULL to reset to default. + * + * @return 0 in case of success or negative value in case of error. + */ +int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts); + +/** @brief Get the available contexts for a given connection + * + * This server function returns the available contexts value for a given @p conn connection object. + * The value returned is the one set with @ref bt_pacs_conn_set_available_contexts_for_conn function + * or the default value set with @ref bt_pacs_set_available_contexts function. + * + * @param conn Connection object. + * @param dir Direction of the endpoints to get contexts for. + * + * @return Bitmask of available contexts. + * @retval BT_AUDIO_CONTEXT_TYPE_PROHIBITED if @p conn or @p dir are invalid + */ +enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir); + /** @brief Set the supported contexts for an endpoint type * * @param dir Direction of the endpoints to change available contexts for. * @param contexts The contexts to be set. + * + * @return 0 in case of success or negative value in case of error. */ int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts); diff --git a/include/zephyr/bluetooth/audio/pbp.h b/include/zephyr/bluetooth/audio/pbp.h new file mode 100644 index 00000000000..acc53adb5ad --- /dev/null +++ b/include/zephyr/bluetooth/audio/pbp.h @@ -0,0 +1,84 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ + +/** + * @brief Public Broadcast Profile (PBP) + * + * @defgroup bt_pbp Public Broadcast Profile (PBP) + * + * @ingroup bluetooth + * @{ + * + * [Experimental] Users should note that the APIs can change + * as a part of ongoing development. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* PBA Service UUID + Public Broadcast Announcement features + Metadata Length */ +#define BT_PBP_MIN_PBA_SIZE (BT_UUID_SIZE_16 + 1 + 1) + +/** Public Broadcast Announcement features */ +enum bt_pbp_announcement_feature { + /** Broadcast Streams encryption status */ + BT_PBP_ANNOUNCEMENT_FEATURE_ENCRYPTION = BIT(0), + /** Standard Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY = BIT(1), + /** High Quality Public Broadcast Audio configuration */ + BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY = BIT(2), +}; + +/** + * @brief Creates a Public Broadcast Announcement based on the information received + * in the features parameter. + * + * @param meta Metadata to be included in the advertising data + * @param meta_len Size of the metadata fields to be included in the advertising data + * @param features Public Broadcast Announcement features + * @param pba_data_buf Pointer to store the PBA advertising data. Buffer size needs to be + * meta_len + @ref BT_PBP_MIN_PBA_SIZE. + * + * @return 0 on success or an appropriate error code. + */ +int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + enum bt_pbp_announcement_feature features, + struct net_buf_simple *pba_data_buf); + +/** + * @brief Parses the received advertising data corresponding to a Public Broadcast + * Announcement. Returns the advertised Public Broadcast Announcement features and metadata. + * + * @param[in] data Advertising data to be checked + * @param[out] features Pointer to public broadcast source features to store the parsed features in + * @param[out] meta Pointer to the metadata present in the advertising data + * + * @return parsed metadata length on success. + * @retval -EINVAL if @p data, @p features or @p meta are NULL. + * @retval -ENOENT if @p data is not of type @ref BT_DATA_SVC_DATA16 or if the UUID in the service + * data is not @ref BT_UUID_PBA. + * @retval -EMSGSIZE if @p data is not large enough to contain a PBP announcement. + * @retval -EBADMSG if the @p data contains invalid data. + */ +int bt_pbp_parse_announcement(struct bt_data *data, enum bt_pbp_announcement_feature *features, + uint8_t **meta); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_PBP_ */ diff --git a/include/zephyr/bluetooth/audio/vcp.h b/include/zephyr/bluetooth/audio/vcp.h index 961fed483d5..15d91fae330 100644 --- a/include/zephyr/bluetooth/audio/vcp.h +++ b/include/zephyr/bluetooth/audio/vcp.h @@ -353,6 +353,9 @@ struct bt_vcp_vol_ctlr_cb { /* Audio Input Control Service callbacks */ struct bt_aics_cb aics_cb; + + /** Internally used field for list handling */ + sys_snode_t _node; }; /** @@ -360,10 +363,23 @@ struct bt_vcp_vol_ctlr_cb { * * @param cb The callback structure. * - * @return 0 if success, errno on failure. + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was already registered */ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb); +/** + * @brief Unregisters the callbacks used by the Volume Controller. + * + * @param cb The callback structure. + * + * @retval 0 on success + * @retval -EINVAL if @p cb is NULL + * @retval -EALREADY if @p cb was not registered + */ +int bt_vcp_vol_ctlr_cb_unregister(struct bt_vcp_vol_ctlr_cb *cb); + /** * @brief Discover Volume Control Service and included services. * @@ -383,6 +399,20 @@ int bt_vcp_vol_ctlr_cb_register(struct bt_vcp_vol_ctlr_cb *cb); int bt_vcp_vol_ctlr_discover(struct bt_conn *conn, struct bt_vcp_vol_ctlr **vol_ctlr); +/** + * @brief Get the volume controller from a connection pointer + * + * Get the Volume Control Profile Volume Controller pointer from a connection pointer. + * Only volume controllers that have been initiated via bt_vcp_vol_ctlr_discover() can be + * retrieved. + * + * @param conn Connection pointer. + * + * @retval Pointer to a Volume Control Profile Volume Controller instance + * @retval NULL if @p conn is NULL or if the connection has not done discovery yet + */ +struct bt_vcp_vol_ctlr *bt_vcp_vol_ctlr_get_by_conn(const struct bt_conn *conn); + /** * @brief Get the connection pointer of a client instance * @@ -405,6 +435,9 @@ int bt_vcp_vol_ctlr_conn_get(const struct bt_vcp_vol_ctlr *vol_ctlr, * Volume Offset Control Service (Volume Offset Control Service) or * Audio Input Control Service (AICS) instances. * + * Requires that @kconfig{CONFIG_BT_VCP_VOL_CTLR_VOCS} or @kconfig{CONFIG_BT_VCP_VOL_CTLR_AICS} is + * enabled. + * * @param vol_ctlr Volume Controller instance pointer. * @param[out] included Pointer to store the result in. * diff --git a/include/zephyr/bluetooth/audio/vocs.h b/include/zephyr/bluetooth/audio/vocs.h index eee5c43533a..d34e6bcd16e 100644 --- a/include/zephyr/bluetooth/audio/vocs.h +++ b/include/zephyr/bluetooth/audio/vocs.h @@ -29,6 +29,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index c97e1445cb3..0cfad9b1f6b 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -340,6 +340,12 @@ void bt_id_get(bt_addr_le_t *addrs, size_t *count); * If an insufficient amount of identities were recovered the app may then * call bt_id_create() to create new ones. * + * If supported by the HCI driver (indicated by setting + * @kconfig{CONFIG_BT_HCI_SET_PUBLIC_ADDR}), the first call to this function can be + * used to set the controller's public identity address. This call must happen + * before calling bt_enable(). Subsequent calls always add/generate random + * static addresses. + * * @param addr Address to use for the new identity. If NULL or initialized * to BT_ADDR_LE_ANY the stack will generate a new random * static address for the identity and copy it to the given @@ -622,6 +628,8 @@ enum { * * @note Enabling this option requires extended advertising support in * the peer devices scanning for advertisement packets. + * + * @note This cannot be used with bt_le_adv_start(). */ BT_LE_ADV_OPT_EXT_ADV = BIT(10), @@ -1049,6 +1057,9 @@ struct bt_le_per_adv_param { * response data parameters are ignored. If the mode is high duty cycle * the timeout will be @ref BT_GAP_ADV_HIGH_DUTY_CYCLE_MAX_TIMEOUT. * + * This function cannot be used with @ref BT_LE_ADV_OPT_EXT_ADV in the @p param.options. + * For extended advertising, the bt_le_ext_adv_* functions must be used. + * * @param param Advertising parameters. * @param ad Data to be used in advertisement packets. * @param ad_len Number of elements in ad diff --git a/include/zephyr/bluetooth/buf.h b/include/zephyr/bluetooth/buf.h index b6c377a9369..b079695d61c 100644 --- a/include/zephyr/bluetooth/buf.h +++ b/include/zephyr/bluetooth/buf.h @@ -129,17 +129,6 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout); struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout, const void *data, size_t size); -/** Allocate a buffer for an HCI Command Complete/Status Event - * - * This will set the buffer type so bt_buf_set_type() does not need to - * be explicitly called before bt_recv_prio(). - * - * @param timeout Non-negative waiting period to obtain a buffer or one of the - * special values K_NO_WAIT and K_FOREVER. - * @return A new buffer. - */ -struct net_buf *bt_buf_get_cmd_complete(k_timeout_t timeout); - /** Allocate a buffer for an HCI Event * * This will set the buffer type so bt_buf_set_type() does not need to diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index bdc644d82e9..edd37bde31e 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -871,11 +871,12 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, * the device has bond information or is already paired and the keys are too * weak then the pairing procedure will be initiated. * - * This function may return error if required level of security is not possible - * to achieve due to local or remote device limitation (e.g., input output - * capabilities), or if the maximum number of paired devices has been reached. + * This function may return an error if the required level of security defined using + * @p sec is not possible to achieve due to local or remote device limitation + * (e.g., input output capabilities), or if the maximum number of paired devices + * has been reached. * - * This function may return error if the pairing procedure has already been + * This function may return an error if the pairing procedure has already been * initiated by the local device or the peer device. * * @note When @kconfig{CONFIG_BT_SMP_SC_ONLY} is enabled then the security @@ -888,7 +889,7 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, * procedure will always be initiated. * * @param conn Connection object. - * @param sec Requested security level. + * @param sec Requested minimum security level. * * @return 0 on success or negative error */ @@ -999,6 +1000,20 @@ struct bt_conn_cb { */ void (*disconnected)(struct bt_conn *conn, uint8_t reason); + /** @brief A connection object has been returned to the pool. + * + * This callback notifies the application that it might be able to + * allocate a connection object. No guarantee, first come, first serve. + * + * Use this to e.g. re-start connectable advertising or scanning. + * + * Treat this callback as an ISR, as it originates from + * @ref bt_conn_unref which is used by the BT stack. Making + * Bluetooth API calls in this context is error-prone and strongly + * discouraged. + */ + void (*recycled)(void); + /** @brief LE connection parameter update request. * * This callback notifies the application that a remote device @@ -1150,6 +1165,19 @@ struct bt_conn_cb { */ void bt_conn_cb_register(struct bt_conn_cb *cb); +/** + * @brief Unregister connection callbacks. + * + * Unregister the state of connections callbacks. + * + * @param cb Callback struct point to memory that remains valid. + * + * @retval 0 Success + * @retval -EINVAL If @p cb is NULL + * @retval -ENOENT if @p cb was not registered + */ +int bt_conn_cb_unregister(struct bt_conn_cb *cb); + /** * @brief Register a callback structure for connection events. * diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index eb38f765afb..585387a02aa 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -677,7 +677,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, */ #define BT_GATT_PRIMARY_SERVICE(_service) \ BT_GATT_ATTRIBUTE(BT_UUID_GATT_PRIMARY, BT_GATT_PERM_READ, \ - bt_gatt_attr_read_service, NULL, _service) + bt_gatt_attr_read_service, NULL, (void *)_service) /** * @brief Secondary Service Declaration Macro. @@ -691,7 +691,7 @@ ssize_t bt_gatt_attr_read_service(struct bt_conn *conn, */ #define BT_GATT_SECONDARY_SERVICE(_service) \ BT_GATT_ATTRIBUTE(BT_UUID_GATT_SECONDARY, BT_GATT_PERM_READ, \ - bt_gatt_attr_read_service, NULL, _service) + bt_gatt_attr_read_service, NULL, (void *)_service) /** @brief Read Include Attribute helper. * @@ -1387,7 +1387,7 @@ struct bt_gatt_exchange_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. * * @retval -EALREADY The MTU exchange procedure has been already performed. */ @@ -1553,7 +1553,7 @@ struct bt_gatt_discover_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_discover(struct bt_conn *conn, struct bt_gatt_discover_params *params); @@ -1668,7 +1668,7 @@ struct bt_gatt_read_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); @@ -1721,7 +1721,7 @@ struct bt_gatt_write_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside Bluetooth event context to get blocking behavior. Queue size is - * controlled by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * controlled by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); @@ -1758,7 +1758,7 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, const void *data, uint16_t length, @@ -1784,7 +1784,7 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ static inline int bt_gatt_write_without_response(struct bt_conn *conn, uint16_t handle, const void *data, @@ -1946,7 +1946,12 @@ struct bt_gatt_subscribe_params { * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + * + * @retval -EALREADY if there already exist a subscription using the @p params. + * + * @retval -EBUSY if @p params.ccc_handle is 0 and @kconfig{CONFIG_BT_GATT_AUTO_DISCOVER_CCC} is + * enabled and discovery for the @p params is already in progress. */ int bt_gatt_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); @@ -1992,7 +1997,7 @@ int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer, * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function * outside the BT RX thread to get blocking behavior. Queue size is controlled - * by @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}. + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_unsubscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params); diff --git a/include/zephyr/bluetooth/iso.h b/include/zephyr/bluetooth/iso.h index 68ceec3ac3d..e280951eda7 100644 --- a/include/zephyr/bluetooth/iso.h +++ b/include/zephyr/bluetooth/iso.h @@ -663,8 +663,10 @@ struct bt_iso_chan_ops { /** @brief Channel sent callback * - * If this callback is provided it will be called whenever a SDU has - * been completely sent. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air or flushed. * * @param chan The channel which has sent data. */ diff --git a/include/zephyr/bluetooth/l2cap.h b/include/zephyr/bluetooth/l2cap.h index 34d1f2dc2ab..dfd01dcc455 100644 --- a/include/zephyr/bluetooth/l2cap.h +++ b/include/zephyr/bluetooth/l2cap.h @@ -120,7 +120,7 @@ typedef enum bt_l2cap_chan_state { /** @brief Status of L2CAP channel. */ typedef enum bt_l2cap_chan_status { - /** Channel output status */ + /** Channel can send at least one PDU */ BT_L2CAP_STATUS_OUT, /** @brief Channel shutdown status @@ -346,8 +346,10 @@ struct bt_l2cap_chan_ops { /** @brief Channel sent callback * - * If this callback is provided it will be called whenever a SDU has - * been completely sent. + * This callback will be called once the controller marks the SDU + * as completed. When the controller does so is implementation + * dependent. It could be after the SDU is enqueued for transmission, + * or after it is sent on air. * * @param chan The channel which has sent data. */ @@ -577,22 +579,28 @@ int bt_l2cap_chan_disconnect(struct bt_l2cap_chan *chan); * size the buffers for the for the outgoing buffer pool. * * When sending L2CAP data over an LE connection the application is sending - * L2CAP SDUs. The application can optionally reserve + * L2CAP SDUs. The application shall reserve * @ref BT_L2CAP_SDU_CHAN_SEND_RESERVE bytes in the buffer before sending. - * By reserving bytes in the buffer the stack can use this buffer as a segment - * directly, otherwise it will have to allocate a new segment for the first - * segment. - * If the application is reserving the bytes it should use the - * BT_L2CAP_BUF_SIZE() helper to correctly size the buffers for the for the - * outgoing buffer pool. - * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt - * to allocate buffers from the original buffer pool of the L2CAP SDU before - * using the stacks own buffer pool. + * + * The application can use the BT_L2CAP_SDU_BUF_SIZE() helper to correctly size + * the buffer to account for the reserved headroom. + * + * When segmenting an L2CAP SDU into L2CAP PDUs the stack will first attempt to + * allocate buffers from the channel's `alloc_seg` callback and will fallback + * on the stack's global buffer pool (sized + * @kconfig{CONFIG_BT_L2CAP_TX_BUF_COUNT}). * * @note Buffer ownership is transferred to the stack in case of success, in * case of an error the caller retains the ownership of the buffer. * - * @return Bytes sent in case of success or negative value in case of error. + * @return 0 in case of success or negative value in case of error. + * @return -EINVAL if `buf` or `chan` is NULL. + * @return -EINVAL if `chan` is not either BR/EDR or LE credit-based. + * @return -EINVAL if buffer doesn't have enough bytes reserved to fit header. + * @return -EMSGSIZE if `buf` is larger than `chan`'s MTU. + * @return -ENOTCONN if underlying conn is disconnected. + * @return -ESHUTDOWN if L2CAP channel is disconnected. + * @return -other (from lower layers) if chan is BR/EDR. */ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf); diff --git a/include/zephyr/bluetooth/mesh/main.h b/include/zephyr/bluetooth/mesh/main.h index a213e8ce22c..1622ccebbd8 100644 --- a/include/zephyr/bluetooth/mesh/main.h +++ b/include/zephyr/bluetooth/mesh/main.h @@ -783,7 +783,6 @@ struct bt_mesh_snb { uint64_t auth_val; }; -#if defined(CONFIG_BT_MESH_V1d1) struct bt_mesh_prb { /** Random */ uint8_t random[13]; @@ -797,7 +796,6 @@ struct bt_mesh_prb { /** Authentication tag */ uint64_t auth_tag; }; -#endif /** Beacon callback functions. */ struct bt_mesh_beacon_cb { @@ -810,7 +808,6 @@ struct bt_mesh_beacon_cb { */ void (*snb_received)(const struct bt_mesh_snb *snb); -#if defined(CONFIG_BT_MESH_V1d1) /** @brief Private Beacon received. * * This callback notifies the application that Private Beacon @@ -819,7 +816,6 @@ struct bt_mesh_beacon_cb { * @param prb Structure describing received Private Beacon */ void (*priv_received)(const struct bt_mesh_prb *prb); -#endif }; /** diff --git a/include/zephyr/bluetooth/services/hrs.h b/include/zephyr/bluetooth/services/hrs.h index 097998f5caf..f19b2924ce0 100644 --- a/include/zephyr/bluetooth/services/hrs.h +++ b/include/zephyr/bluetooth/services/hrs.h @@ -19,10 +19,50 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif +/** @brief Heart rate service callback structure */ +struct bt_hrs_cb { + /** @brief Heart rate notifications changed + * + * @param enabled Flag that is true if notifications were enabled, false + * if they were disabled. + */ + void (*ntf_changed)(bool enabled); + + /** Internal member to form a list of callbacks */ + sys_snode_t _node; +}; + +/** @brief Heart rate service callback register + * + * This function will register callbacks that will be called in + * certain events related to Heart rate service. + * + * @param cb Pointer to callbacks structure. Must point to memory that remains valid + * until unregistered. + * + * @return 0 on success + * @return -EINVAL in case @p cb is NULL + */ +int bt_hrs_cb_register(struct bt_hrs_cb *cb); + +/** @brief Heart rate service callback unregister + * + * This function will unregister callback from Heart rate service. + * + * @param cb Pointer to callbacks structure + * + * @return 0 on success + * @return -EINVAL in case @p cb is NULL + * @return -ENOENT in case the @p cb was not found in registered callbacks + */ +int bt_hrs_cb_unregister(struct bt_hrs_cb *cb); + /** @brief Notify heart rate measurement. * * This will send a GATT notification to all current subscribers. diff --git a/include/zephyr/bluetooth/uuid.h b/include/zephyr/bluetooth/uuid.h index cab12eac74b..16943f89e63 100644 --- a/include/zephyr/bluetooth/uuid.h +++ b/include/zephyr/bluetooth/uuid.h @@ -110,7 +110,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_16(value) \ - ((struct bt_uuid *) ((struct bt_uuid_16[]) {BT_UUID_INIT_16(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_16[]) {BT_UUID_INIT_16(value)})) /** @brief Helper to declare a 32-bit UUID inline. * @@ -119,7 +119,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_32(value) \ - ((struct bt_uuid *) ((struct bt_uuid_32[]) {BT_UUID_INIT_32(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_32[]) {BT_UUID_INIT_32(value)})) /** @brief Helper to declare a 128-bit UUID inline. * @@ -130,7 +130,7 @@ struct bt_uuid_128 { * @return Pointer to a generic UUID. */ #define BT_UUID_DECLARE_128(value...) \ - ((struct bt_uuid *) ((struct bt_uuid_128[]) {BT_UUID_INIT_128(value)})) + ((const struct bt_uuid *) ((const struct bt_uuid_128[]) {BT_UUID_INIT_128(value)})) /** Helper macro to access the 16-bit UUID from a generic UUID. */ #define BT_UUID_16(__u) CONTAINER_OF(__u, struct bt_uuid_16, uuid) @@ -5090,6 +5090,61 @@ struct bt_uuid_128 { */ #define BT_UUID_GATT_SL \ BT_UUID_DECLARE_16(BT_UUID_GATT_SL_VAL) + +/** + * @brief Gaming Service UUID value + */ +#define BT_UUID_GMAS_VAL 0x1858 +/** + * @brief Common Audio Service + */ +#define BT_UUID_GMAS BT_UUID_DECLARE_16(BT_UUID_GMAS_VAL) + +/** + * @brief Gaming Audio Profile Role UUID value + */ +#define BT_UUID_GMAP_ROLE_VAL 0x2C00 +/** + * @brief Gaming Audio Profile Role + */ +#define BT_UUID_GMAP_ROLE BT_UUID_DECLARE_16(BT_UUID_GMAP_ROLE_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features UUID value + */ +#define BT_UUID_GMAP_UGG_FEAT_VAL 0x2C01 +/** + * @brief Gaming Audio Profile Unicast Game Gateway Features + */ +#define BT_UUID_GMAP_UGG_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGG_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features UUID value + */ +#define BT_UUID_GMAP_UGT_FEAT_VAL 0x2C02 +/** + * @brief Gaming Audio Profile Unicast Game Terminal Features + */ +#define BT_UUID_GMAP_UGT_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_UGT_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features UUID value + */ +#define BT_UUID_GMAP_BGS_FEAT_VAL 0x2C03 +/** + * @brief Gaming Audio Profile Broadcast Game Sender Features + */ +#define BT_UUID_GMAP_BGS_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGS_FEAT_VAL) + +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features UUID value + */ +#define BT_UUID_GMAP_BGR_FEAT_VAL 0x2C04 +/** + * @brief Gaming Audio Profile Broadcast Game Receiver Features + */ +#define BT_UUID_GMAP_BGR_FEAT BT_UUID_DECLARE_16(BT_UUID_GMAP_BGR_FEAT_VAL) + /* * Protocol UUIDs */ diff --git a/include/zephyr/cache.h b/include/zephyr/cache.h index 994d96dccbe..f5547f64afd 100644 --- a/include/zephyr/cache.h +++ b/include/zephyr/cache.h @@ -15,6 +15,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -441,6 +442,107 @@ static ALWAYS_INLINE size_t sys_cache_instr_line_size_get(void) #endif } +/** + * @brief Test if a pointer is in cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the cached, coherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is in cached region. + * @retval False if pointer is not in cached region. + */ +static ALWAYS_INLINE bool sys_cache_is_ptr_cached(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_is_ptr_cached(ptr); +#else + ARG_UNUSED(ptr); + + return false; +#endif +} + +/** + * @brief Test if a pointer is in un-cached region. + * + * Some hardware may map the same physical memory twice + * so that it can be seen in both (incoherent) cached mappings + * and a coherent "shared" area. This tests if a particular + * pointer is within the un-cached, incoherent area. + * + * @param ptr Pointer + * + * @retval True if pointer is not in cached region. + * @retval False if pointer is in cached region. + */ +static ALWAYS_INLINE bool sys_cache_is_ptr_uncached(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_is_ptr_uncached(ptr); +#else + ARG_UNUSED(ptr); + + return false; +#endif +} + +/** + * @brief Return cached pointer to a RAM address + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory through the L1 data cache. Data read + * through the resulting pointer will reflect locally cached values on + * the current CPU if they exist, and writes will go first into the + * cache and be written back later. + * + * @note This API returns the same pointer if CONFIG_CACHE_DOUBLEMAP is not + * enabled. + * + * @see arch_uncached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object via the L1 dcache + */ +static ALWAYS_INLINE void __sparse_cache *sys_cache_cached_ptr_get(void *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_cached_ptr(ptr); +#else + return (__sparse_force void __sparse_cache *)ptr; +#endif +} + +/** + * @brief Return uncached pointer to a RAM address + * + * This function takes a pointer to any addressable object (either in + * cacheable memory or not) and returns a pointer that can be used to + * refer to the same memory while bypassing the L1 data cache. Data + * in the L1 cache will not be inspected nor modified by the access. + * + * @note This API returns the same pointer if CONFIG_CACHE_DOUBLEMAP is not + * enabled. + * + * @see arch_cached_ptr() + * + * @param ptr A pointer to a valid C object + * @return A pointer to the same object bypassing the L1 dcache + */ +static ALWAYS_INLINE void *sys_cache_uncached_ptr_get(void __sparse_cache *ptr) +{ +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_CACHE_DOUBLEMAP) + return cache_uncached_ptr(ptr); +#else + return (__sparse_force void *)ptr; +#endif +} + + #ifdef CONFIG_LIBMETAL static ALWAYS_INLINE void sys_cache_flush(void *addr, size_t size) { diff --git a/include/zephyr/console/console.h b/include/zephyr/console/console.h index 9ce09c081de..fbecfdad0d3 100644 --- a/include/zephyr/console/console.h +++ b/include/zephyr/console/console.h @@ -15,6 +15,13 @@ extern "C" { #endif +/** + * @brief Console API + * @defgroup console_api Console API + * @ingroup os_services + * @{ + */ + /** @brief Initialize console device. * * This function should be called once to initialize pull-style @@ -107,4 +114,8 @@ char *console_getline(void); } #endif +/** + * @} + */ + #endif /* ZEPHYR_INCLUDE_CONSOLE_CONSOLE_H_ */ diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 630a059c155..e581fe74d38 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -41,6 +41,10 @@ extern "C" { */ #define Z_DEVICE_DEPS_ENDS INT16_MAX +/** @brief Determine if a DT node is mutable */ +#define Z_DEVICE_IS_MUTABLE(node_id) \ + COND_CODE_1(IS_ENABLED(CONFIG_DEVICE_MUTABLE), (DT_PROP(node_id, zephyr_mutable)), (0)) + /** @endcond */ /** @@ -367,7 +371,9 @@ struct device_state { bool initialized : 1; }; +struct pm_device_base; struct pm_device; +struct pm_device_isr; #ifdef CONFIG_DEVICE_DEPS_DYNAMIC #define Z_DEVICE_DEPS_CONST @@ -405,7 +411,11 @@ struct device { * Reference to the device PM resources (only available if * @kconfig{CONFIG_PM_DEVICE} is enabled). */ - struct pm_device *pm; + union { + struct pm_device_base *pm_base; + struct pm_device *pm; + struct pm_device_isr *pm_isr; + }; #endif }; @@ -881,7 +891,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @brief Initializer for @ref device. * * @param name_ Name of the device. - * @param pm_ Reference to @ref pm_device (optional). + * @param pm_ Reference to @ref pm_device_base (optional). * @param data_ Reference to device data. * @param config_ Reference to device config. * @param api_ Reference to device API ops. @@ -896,7 +906,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) .state = (state_), \ .data = (data_), \ IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \ - IF_ENABLED(CONFIG_PM_DEVICE, (.pm = (pm_),)) /**/ \ + IF_ENABLED(CONFIG_PM_DEVICE, (.pm_base = (pm_),)) /**/ \ } /** @@ -915,7 +925,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * software device). * @param dev_id Device identifier (used to name the defined @ref device). * @param name Name of the device. - * @param pm Reference to @ref pm_device associated with the device. + * @param pm Reference to @ref pm_device_base associated with the device. * (optional). * @param data Reference to device data. * @param config Reference to device config. @@ -924,12 +934,13 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param api Reference to device API. * @param ... Optional dependencies, manually specified. */ -#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, \ - prio, api, state, deps) \ - COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \ - const STRUCT_SECTION_ITERABLE_NAMED(device, \ - Z_DEVICE_SECTION_NAME(level, prio), \ - DEVICE_NAME_GET(dev_id)) = \ +#define Z_DEVICE_BASE_DEFINE(node_id, dev_id, name, pm, data, config, level, prio, api, state, \ + deps) \ + COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static)) \ + COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), (const)) \ + STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \ + device, COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (device_mutable), (device)), \ + Z_DEVICE_SECTION_NAME(level, prio), DEVICE_NAME_GET(dev_id)) = \ Z_DEVICE_INIT(name, pm, data, config, api, state, deps) /* deprecated device initialization levels */ @@ -961,15 +972,18 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param level Initialization level. * @param prio Initialization priority. */ -#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ - Z_DEVICE_LEVEL_CHECK_DEPRECATED_LEVEL(level) \ - \ - static const Z_DECL_ALIGN(struct init_entry) __used __noasan \ - Z_INIT_ENTRY_SECTION(level, prio, \ - Z_DEVICE_INIT_SUB_PRIO(node_id)) \ - Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ - .init_fn = {.dev = (init_fn_)}, \ - .dev = &DEVICE_NAME_GET(dev_id), \ +#define Z_DEVICE_INIT_ENTRY_DEFINE(node_id, dev_id, init_fn_, level, prio) \ + Z_DEVICE_LEVEL_CHECK_DEPRECATED_LEVEL(level) \ + \ + static const Z_DECL_ALIGN(struct init_entry) __used __noasan Z_INIT_ENTRY_SECTION( \ + level, prio, Z_DEVICE_INIT_SUB_PRIO(node_id)) \ + Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ + .init_fn = {COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (.dev_rw), (.dev)) = \ + (init_fn_)}, \ + { \ + COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (.dev_rw), (.dev)) = \ + &DEVICE_NAME_GET(dev_id), \ + }, \ } /** @@ -983,7 +997,7 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * @param dev_id Device identifier (used to name the defined @ref device). * @param name Name of the device. * @param init_fn Device init function. - * @param pm Reference to @ref pm_device associated with the device. + * @param pm Reference to @ref pm_device_base associated with the device. * (optional). * @param data Reference to device data. * @param config Reference to device config. @@ -1015,8 +1029,9 @@ static inline bool z_impl_device_is_ready(const struct device *dev) * don't have a corresponding @ref device allocated. There's no way to figure * that out until after we've built the zephyr image, though. */ -#define Z_MAYBE_DEVICE_DECLARE_INTERNAL(node_id) \ - extern const struct device DEVICE_DT_NAME_GET(node_id); +#define Z_MAYBE_DEVICE_DECLARE_INTERNAL(node_id) \ + extern COND_CODE_1(Z_DEVICE_IS_MUTABLE(node_id), (), \ + (const)) struct device DEVICE_DT_NAME_GET(node_id); DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_DEVICE_DECLARE_INTERNAL) diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index 017bcab442a..7a71cf2fb42 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -356,7 +356,7 @@ * @param node_id node identifier * @return a node identifier for the node's parent */ -#define DT_PARENT(node_id) UTIL_CAT(node_id, _PARENT) +#define DT_PARENT(node_id) DT_CAT(node_id, _PARENT) /** * @brief Get a node identifier for a grandparent node @@ -778,17 +778,6 @@ COND_CODE_1(DT_NODE_HAS_PROP(node_id, prop), \ (DT_PROP(node_id, prop)), (default_value)) -/** - * @deprecated Use DT_PROP(node_id, label) - * @brief Equivalent to DT_PROP(node_id, label) - * - * This is a convenience for the Zephyr device API, which uses label - * properties as device_get_binding() arguments. - * @param node_id node identifier - * @return node's label property value - */ -#define DT_LABEL(node_id) DT_PROP(node_id, label) __DEPRECATED_MACRO - /** * @brief Get a property value's index into its enumeration values * @@ -1219,7 +1208,7 @@ * @return the property's value as a sequence of tokens, with no quotes */ #define DT_STRING_UNQUOTED_BY_IDX(node_id, prop, idx) \ - DT_CAT4(node_id, _P_, prop##_IDX_##idx, _STRING_UNQUOTED) + DT_CAT6(node_id, _P_, prop, _IDX_, idx, _STRING_UNQUOTED) /* * phandle properties @@ -1394,7 +1383,7 @@ * @return the cell's value or @p default_value */ #define DT_PHA_BY_IDX_OR(node_id, pha, idx, cell, default_value) \ - DT_PROP_OR(node_id, pha##_IDX_##idx##_VAL_##cell, default_value) + DT_PROP_OR(node_id, DT_CAT5(pha, _IDX_, idx, _VAL_, cell), default_value) /** * @brief Equivalent to DT_PHA_BY_IDX(node_id, pha, 0, cell) @@ -1487,7 +1476,7 @@ * @return the cell's value or @p default_value */ #define DT_PHA_BY_NAME_OR(node_id, pha, name, cell, default_value) \ - DT_PROP_OR(node_id, pha##_NAME_##name##_VAL_##cell, default_value) + DT_PROP_OR(node_id, DT_CAT5(pha, _NAME_, name, _VAL_, cell), default_value) /** * @brief Get a phandle's node identifier from a phandle array by @p name @@ -1623,7 +1612,7 @@ * * @code{.dts} * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1668,7 +1657,7 @@ * * @code{.dts} * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1722,7 +1711,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1775,7 +1764,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1815,7 +1804,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1864,7 +1853,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -1913,7 +1902,7 @@ * #address-cells = <2>; * * pcie0: pcie@0 { - * compatible = "intel,pcie"; + * compatible = "pcie-controller"; * reg = <0 0 1>; * #address-cells = <3>; * #size-cells = <2>; @@ -2298,6 +2287,14 @@ */ #define DT_NUM_IRQS(node_id) DT_CAT(node_id, _IRQ_NUM) +/** + * @brief Get the interrupt level for the node + * + * @param node_id node identifier + * @return interrupt level + */ +#define DT_IRQ_LEVEL(node_id) DT_CAT(node_id, _IRQ_LEVEL) + /** * @brief Is @p idx a valid interrupt index? * @@ -2411,58 +2408,162 @@ #define DT_IRQ(node_id, cell) DT_IRQ_BY_IDX(node_id, 0, cell) /** - * @cond INTERNAL_HIDDEN + * @brief Get an interrupt specifier's interrupt controller by index + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>, <2 2>; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>, <&pic0 4>; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>, <6>; + * interrupt-names = "int1", "int2"; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(foo), 0) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(foo), 1) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(bar), 0) // &gpio0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(bar), 1) // &pic0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(qux), 0) // &pic0 + * DT_IRQ_INTC_BY_IDX(DT_NODELABEL(qux), 1) // &pic0 + * + * @param node_id node identifier + * @param idx interrupt specifier's index + * @return node_id of interrupt specifier's interrupt controller */ +#define DT_IRQ_INTC_BY_IDX(node_id, idx) \ + DT_CAT4(node_id, _IRQ_IDX_, idx, _CONTROLLER) -/* DT helper macro to get interrupt-parent node */ -#define DT_PARENT_INTC_INTERNAL(node_id) DT_PROP(node_id, interrupt_parent) -/* DT helper macro to get the node's interrupt grandparent node */ -#define DT_GPARENT_INTC_INTERNAL(node_id) DT_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)) -/* DT helper macro to check if a node is an interrupt controller */ -#define DT_IS_INTC_INTERNAL(node_id) DT_NODE_HAS_PROP(node_id, interrupt_controller) -/* DT helper macro to check if the node has a parent interrupt controller */ -#define DT_HAS_PARENT_INTC_INTERNAL(node_id) \ - /* node has `interrupt-parent`? */ \ - IF_ENABLED(DT_NODE_HAS_PROP(node_id, interrupt_parent), \ - /* `interrupt-parent` node is an interrupt controller? */ \ - (IF_ENABLED(DT_IS_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)), \ - /* `interrupt-parent` node has interrupt cell(s) ? 1 : 0 */ \ - (COND_CODE_0(DT_NUM_IRQS(DT_PARENT_INTC_INTERNAL(node_id)), (0), \ - (1)))))) -/* DT helper macro to check if the node has a grandparent interrupt controller */ -#define DT_HAS_GPARENT_INTC_INTERNAL(node_id) \ - IF_ENABLED(DT_HAS_PARENT_INTC_INTERNAL(node_id), \ - (DT_HAS_PARENT_INTC_INTERNAL(DT_PARENT_INTC_INTERNAL(node_id)))) - -/** - * DT helper macro to get the as-seen interrupt number in devicetree, - * or ARM GIC IRQ encoded output from `gen_defines.py` - */ -#define DT_IRQN_BY_IDX_INTERNAL(node_id, idx) DT_IRQ_BY_IDX(node_id, idx, irq) - -/* DT helper macro to get the node's parent intc's (only) irq number */ -#define DT_PARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_PARENT_INTC_INTERNAL(node_id), irq) -/* DT helper macro to get the node's grandparent intc's (only) irq number */ -#define DT_GPARENT_INTC_IRQN_INTERNAL(node_id) DT_IRQ(DT_GPARENT_INTC_INTERNAL(node_id), irq) +/** + * @brief Get an interrupt specifier's interrupt controller by name + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>, <2 2>; + * interrupt-names = "int1", "int2"; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>, <&pic0 4>; + * interrupt-names = "int1", "int2"; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>, <6>; + * interrupt-names = "int1", "int2"; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(foo), int1) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(foo), int2) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(bar), int1) // &gpio0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(bar), int2) // &pic0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(qux), int1) // &pic0 + * DT_IRQ_INTC_BY_NAME(DT_NODELABEL(qux), int2) // &pic0 + * + * @param node_id node identifier + * @param name interrupt specifier's name + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_IRQ_INTC_BY_NAME(node_id, name) \ + DT_CAT4(node_id, _IRQ_NAME_, name, _CONTROLLER) +/** + * @brief Get an interrupt specifier's interrupt controller + * @note Equivalent to DT_IRQ_INTC_BY_IDX(node_id, 0) + * + * @code{.dts} + * gpio0: gpio0 { + * interrupt-controller; + * #interrupt-cells = <2>; + * }; + * + * foo: foo { + * interrupt-parent = <&gpio0>; + * interrupts = <1 1>; + * }; + * + * bar: bar { + * interrupts-extended = <&gpio0 3 3>; + * }; + * + * pic0: pic0 { + * interrupt-controller; + * #interrupt-cells = <1>; + * + * qux: qux { + * interrupts = <5>; + * }; + * }; + * @endcode + * + * Example usage: + * + * DT_IRQ_INTC(DT_NODELABEL(foo)) // &gpio0 + * DT_IRQ_INTC(DT_NODELABEL(bar)) // &gpio0 + * DT_IRQ_INTC(DT_NODELABEL(qux)) // &pic0 + * + * @param node_id node identifier + * @return node_id of interrupt specifier's interrupt controller + * @see DT_IRQ_INTC_BY_IDX() + */ +#define DT_IRQ_INTC(node_id) \ + DT_IRQ_INTC_BY_IDX(node_id, 0) + +/** + * @cond INTERNAL_HIDDEN + */ + +/* DT helper macro to encode a node's IRQN to level 1 according to the multi-level scheme */ +#define DT_IRQN_L1_INTERNAL(node_id, idx) DT_IRQ_BY_IDX(node_id, idx, irq) /* DT helper macro to encode a node's IRQN to level 2 according to the multi-level scheme */ #define DT_IRQN_L2_INTERNAL(node_id, idx) \ - (IRQ_TO_L2(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \ - DT_PARENT_INTC_IRQN_INTERNAL(node_id)) + (IRQ_TO_L2(DT_IRQN_L1_INTERNAL(node_id, idx)) | DT_IRQ(DT_IRQ_INTC(node_id), irq)) /* DT helper macro to encode a node's IRQN to level 3 according to the multi-level scheme */ #define DT_IRQN_L3_INTERNAL(node_id, idx) \ - (IRQ_TO_L3(DT_IRQN_BY_IDX_INTERNAL(node_id, idx)) | \ - IRQ_TO_L2(DT_PARENT_INTC_IRQN_INTERNAL(node_id)) | \ - DT_GPARENT_INTC_IRQN_INTERNAL(node_id)) + (IRQ_TO_L3(DT_IRQN_L1_INTERNAL(node_id, idx)) | \ + IRQ_TO_L2(DT_IRQ(DT_IRQ_INTC(node_id), irq)) | \ + DT_IRQ(DT_IRQ_INTC(DT_IRQ_INTC(node_id)), irq)) +/* DT helper macro for the macros above */ +#define DT_IRQN_LVL_INTERNAL(node_id, idx, level) DT_CAT3(DT_IRQN_L, level, _INTERNAL)(node_id, idx) + /** * DT helper macro to encode a node's interrupt number according to the Zephyr's multi-level scheme * See doc/kernel/services/interrupts.rst for details */ #define DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx) \ - COND_CODE_1(DT_HAS_GPARENT_INTC_INTERNAL(node_id), (DT_IRQN_L3_INTERNAL(node_id, idx)), \ - (COND_CODE_1(DT_HAS_PARENT_INTC_INTERNAL(node_id), \ - (DT_IRQN_L2_INTERNAL(node_id, idx)), \ - (DT_IRQN_BY_IDX_INTERNAL(node_id, idx))))) + DT_IRQN_LVL_INTERNAL(node_id, idx, DT_IRQ_LEVEL(node_id)) /** * INTERNAL_HIDDEN @endcond @@ -2479,7 +2580,7 @@ #define DT_IRQN_BY_IDX(node_id, idx) \ COND_CODE_1(IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS), \ (DT_MULTI_LEVEL_IRQN_INTERNAL(node_id, idx)), \ - (DT_IRQN_BY_IDX_INTERNAL(node_id, idx))) + (DT_IRQ_BY_IDX(node_id, idx, irq))) /** * @brief Get a node's (only) irq number @@ -2986,7 +3087,7 @@ */ #define DT_FOREACH_STATUS_OKAY(compat, fn) \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \ - (UTIL_CAT(DT_FOREACH_OKAY_, compat)(fn)), \ + (DT_CAT(DT_FOREACH_OKAY_, compat)(fn)), \ ()) /** @@ -3035,7 +3136,7 @@ */ #define DT_FOREACH_STATUS_OKAY_VARGS(compat, fn, ...) \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \ - (UTIL_CAT(DT_FOREACH_OKAY_VARGS_, \ + (DT_CAT(DT_FOREACH_OKAY_VARGS_, \ compat)(fn, __VA_ARGS__)), \ ()) @@ -3260,16 +3361,6 @@ */ #define DT_BUS(node_id) DT_CAT(node_id, _BUS) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_BUS(node)). - * - * @brief Node's bus controller's `label` property - * @param node_id node identifier - * @return the label property of the node's bus controller DT_BUS(node) - */ -#define DT_BUS_LABEL(node_id) DT_PROP(DT_BUS(node_id), label) __DEPRECATED_MACRO - /** * @brief Is a node on a bus of a given type? * @@ -3581,14 +3672,6 @@ #define DT_INST_PROP_LEN_OR(inst, prop, default_value) \ DT_PROP_LEN_OR(DT_DRV_INST(inst), prop, default_value) -/** - * @deprecated Use DT_INST_PROP(inst, label) - * @brief Get a `DT_DRV_COMPAT` instance's `label` property - * @param inst instance number - * @return instance's label property value - */ -#define DT_INST_LABEL(inst) DT_INST_PROP(inst, label) __DEPRECATED_MACRO - /** * @brief Get a `DT_DRV_COMPAT` instance's string property's value as a * token. @@ -3864,6 +3947,14 @@ */ #define DT_INST_REG_SIZE(inst) DT_INST_REG_SIZE_BY_IDX(inst, 0) +/** + * @brief Get a `DT_DRV_COMPAT` interrupt level + * + * @param inst instance number + * @return interrupt level + */ +#define DT_INST_IRQ_LEVEL(inst) DT_IRQ_LEVEL(DT_DRV_INST(inst)) + /** * @brief Get a `DT_DRV_COMPAT` interrupt specifier value at an index * @param inst instance number @@ -3874,6 +3965,34 @@ #define DT_INST_IRQ_BY_IDX(inst, idx, cell) \ DT_IRQ_BY_IDX(DT_DRV_INST(inst), idx, cell) +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller by index + * @param inst instance number + * @param idx interrupt specifier's index + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_INST_IRQ_INTC_BY_IDX(inst, idx) \ + DT_IRQ_INTC_BY_IDX(DT_DRV_INST(inst), idx) + +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller by name + * @param inst instance number + * @param name interrupt specifier's name + * @return node_id of interrupt specifier's interrupt controller + */ +#define DT_INST_IRQ_INTC_BY_NAME(inst, name) \ + DT_IRQ_INTC_BY_NAME(DT_DRV_INST(inst), name) + +/** + * @brief Get a `DT_DRV_COMPAT` interrupt specifier's interrupt controller + * @note Equivalent to DT_INST_IRQ_INTC_BY_IDX(node_id, 0) + * @param inst instance number + * @return node_id of interrupt specifier's interrupt controller + * @see DT_INST_IRQ_INTC_BY_IDX() + */ +#define DT_INST_IRQ_INTC(inst) \ + DT_INST_IRQ_INTC_BY_IDX(inst, 0) + /** * @brief Get a `DT_DRV_COMPAT` interrupt specifier value by name * @param inst instance number @@ -3914,16 +4033,6 @@ */ #define DT_INST_BUS(inst) DT_BUS(DT_DRV_INST(inst)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_BUS(inst)). - * - * @brief Get a `DT_DRV_COMPAT`'s bus node's label property - * @param inst instance number - * @return the label property of the instance's bus controller - */ -#define DT_INST_BUS_LABEL(inst) DT_BUS_LABEL(DT_DRV_INST(inst)) __DEPRECATED_MACRO - /** * @brief Test if a `DT_DRV_COMPAT`'s bus type is a given type * @param inst instance number @@ -3998,7 +4107,7 @@ * 0 otherwise */ #define DT_HAS_COMPAT_ON_BUS_STATUS_OKAY(compat, bus) \ - IS_ENABLED(UTIL_CAT(DT_CAT(DT_COMPAT_, compat), _BUS_##bus)) + IS_ENABLED(DT_CAT4(DT_COMPAT_, compat, _BUS_, bus)) /** * @brief Test if any `DT_DRV_COMPAT` node is on a bus of a given type diff --git a/include/zephyr/devicetree/gpio.h b/include/zephyr/devicetree/gpio.h index 965de6f7149..93426796f89 100644 --- a/include/zephyr/devicetree/gpio.h +++ b/include/zephyr/devicetree/gpio.h @@ -65,60 +65,6 @@ extern "C" { #define DT_GPIO_CTLR(node_id, gpio_pha) \ DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, 0) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node, gpio_pha, idx)). - * - * @brief Get a label property from a gpio phandle-array property - * at an index - * - * It's an error if the GPIO controller node referenced by the phandle - * in node_id's "gpio_pha" property at index "idx" has no label - * property. - * - * Example devicetree fragment: - * - * gpio1: gpio@... { - * label = "GPIO_1"; - * }; - * - * gpio2: gpio@... { - * label = "GPIO_2"; - * }; - * - * n: node { - * gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, - * <&gpio2 30 GPIO_ACTIVE_HIGH>; - * }; - * - * Example usage: - * - * DT_GPIO_LABEL_BY_IDX(DT_NODELABEL(n), gpios, 1) // "GPIO_2" - * - * @param node_id node identifier - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @param idx logical index into "gpio_pha" - * @return the label property of the node referenced at index "idx" - * @see DT_PHANDLE_BY_IDX() - */ -#define DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, idx) \ - DT_PROP(DT_GPIO_CTLR_BY_IDX(node_id, gpio_pha, idx), label) __DEPRECATED_MACRO - -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_GPIO_CTLR(node, gpio_pha)). - * - * @brief Equivalent to DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, 0) - * @param node_id node identifier - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @return the label property of the node referenced at index 0 - * @see DT_GPIO_LABEL_BY_IDX() - */ -#define DT_GPIO_LABEL(node_id, gpio_pha) \ - DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, 0) __DEPRECATED_MACRO - /** * @brief Get a GPIO specifier's pin cell at an index * @@ -362,34 +308,6 @@ extern "C" { COND_CODE_1(IS_ENABLED(DT_CAT4(node_id, _GPIO_HOGS_IDX_, idx, _VAL_flags_EXISTS)), \ (DT_CAT4(node_id, _GPIO_HOGS_IDX_, idx, _VAL_flags)), (0)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_GPIO_CTLR_BY_IDX(node, gpio_pha, idx)). - * - * @brief Get a label property from a DT_DRV_COMPAT instance's GPIO - * property at an index - * @param inst DT_DRV_COMPAT instance number - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @param idx logical index into "gpio_pha" - * @return the label property of the node referenced at index "idx" - */ -#define DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, idx) \ - DT_GPIO_LABEL_BY_IDX(DT_DRV_INST(inst), gpio_pha, idx) __DEPRECATED_MACRO - -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_GPIO_CTLR(node, gpio_pha)). - * - * @brief Equivalent to DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, 0) - * @param inst DT_DRV_COMPAT instance number - * @param gpio_pha lowercase-and-underscores GPIO property with - * type "phandle-array" - * @return the label property of the node referenced at index 0 - */ -#define DT_INST_GPIO_LABEL(inst, gpio_pha) \ - DT_INST_GPIO_LABEL_BY_IDX(inst, gpio_pha, 0) __DEPRECATED_MACRO - /** * @brief Get a DT_DRV_COMPAT instance's GPIO specifier's pin cell value * at an index diff --git a/include/zephyr/devicetree/spi.h b/include/zephyr/devicetree/spi.h index e7994982a7e..d1f916c3df9 100644 --- a/include/zephyr/devicetree/spi.h +++ b/include/zephyr/devicetree/spi.h @@ -150,47 +150,6 @@ extern "C" { #define DT_SPI_DEV_CS_GPIOS_CTLR(spi_dev) \ DT_GPIO_CTLR_BY_IDX(DT_BUS(spi_dev), cs_gpios, DT_REG_ADDR(spi_dev)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_SPI_DEV_CS_GPIOS_CTLR(node)). - * - * @brief Get a SPI device's chip select GPIO controller's label property - * - * Example devicetree fragment: - * - * gpio1: gpio@... { - * label = "GPIO_1"; - * }; - * - * gpio2: gpio@... { - * label = "GPIO_2"; - * }; - * - * spi1: spi@... { - * compatible = "vnd,spi"; - * cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, - * <&gpio2 20 GPIO_ACTIVE_LOW>; - * - * a: spi-dev-a@0 { - * reg = <0>; - * }; - * - * b: spi-dev-b@1 { - * reg = <1>; - * }; - * }; - * - * Example usage: - * - * DT_SPI_DEV_CS_GPIOS_LABEL(DT_NODELABEL(a)) // "GPIO_1" - * DT_SPI_DEV_CS_GPIOS_LABEL(DT_NODELABEL(b)) // "GPIO_2" - * - * @param spi_dev a SPI device node identifier - * @return label property of spi_dev's chip select GPIO controller - */ -#define DT_SPI_DEV_CS_GPIOS_LABEL(spi_dev) \ - DT_GPIO_LABEL_BY_IDX(DT_BUS(spi_dev), cs_gpios, DT_REG_ADDR(spi_dev)) __DEPRECATED_MACRO - /** * @brief Get a SPI device's chip select GPIO pin number * @@ -272,19 +231,6 @@ extern "C" { #define DT_INST_SPI_DEV_CS_GPIOS_CTLR(inst) \ DT_SPI_DEV_CS_GPIOS_CTLR(DT_DRV_INST(inst)) -/** - * @deprecated If used to obtain a device instance with device_get_binding, - * consider using @c DEVICE_DT_GET(DT_INST_SPI_DEV_CS_GPIOS_CTLR(node)). - * - * @brief Get GPIO controller name for a SPI device instance - * This is equivalent to DT_SPI_DEV_CS_GPIOS_LABEL(DT_DRV_INST(inst)). - * @param inst DT_DRV_COMPAT instance number - * @return label property of the instance's chip select GPIO controller - * @see DT_SPI_DEV_CS_GPIOS_LABEL() - */ -#define DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst) \ - DT_SPI_DEV_CS_GPIOS_LABEL(DT_DRV_INST(inst)) __DEPRECATED_MACRO - /** * @brief Equivalent to DT_SPI_DEV_CS_GPIOS_PIN(DT_DRV_INST(inst)). * @param inst DT_DRV_COMPAT instance number diff --git a/include/zephyr/display/mipi_display.h b/include/zephyr/display/mipi_display.h new file mode 100644 index 00000000000..f369cb8de42 --- /dev/null +++ b/include/zephyr/display/mipi_display.h @@ -0,0 +1,163 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Display definitions for MIPI devices + */ + +#ifndef ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ +#define ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ + +/** + * @brief MIPI Display definitions + * @defgroup mipi_interface MIPI Display interface + * @ingroup io_interfaces + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name MIPI-DSI DCS (Display Command Set) + * @{ + */ + +#define MIPI_DCS_NOP 0x00U +#define MIPI_DCS_SOFT_RESET 0x01U +#define MIPI_DCS_GET_COMPRESSION_MODE 0x03U +#define MIPI_DCS_GET_DISPLAY_ID 0x04U +#define MIPI_DCS_GET_RED_CHANNEL 0x06U +#define MIPI_DCS_GET_GREEN_CHANNEL 0x07U +#define MIPI_DCS_GET_BLUE_CHANNEL 0x08U +#define MIPI_DCS_GET_DISPLAY_STATUS 0x09U +#define MIPI_DCS_GET_POWER_MODE 0x0AU +#define MIPI_DCS_GET_ADDRESS_MODE 0x0BU +#define MIPI_DCS_GET_PIXEL_FORMAT 0x0CU +#define MIPI_DCS_GET_DISPLAY_MODE 0x0DU +#define MIPI_DCS_GET_SIGNAL_MODE 0x0EU +#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0FU +#define MIPI_DCS_ENTER_SLEEP_MODE 0x10U +#define MIPI_DCS_EXIT_SLEEP_MODE 0x11U +#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12U +#define MIPI_DCS_ENTER_NORMAL_MODE 0x13U +#define MIPI_DCS_EXIT_INVERT_MODE 0x20U +#define MIPI_DCS_ENTER_INVERT_MODE 0x21U +#define MIPI_DCS_SET_GAMMA_CURVE 0x26U +#define MIPI_DCS_SET_DISPLAY_OFF 0x28U +#define MIPI_DCS_SET_DISPLAY_ON 0x29U +#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2AU +#define MIPI_DCS_SET_PAGE_ADDRESS 0x2BU +#define MIPI_DCS_WRITE_MEMORY_START 0x2CU +#define MIPI_DCS_WRITE_LUT 0x2DU +#define MIPI_DCS_READ_MEMORY_START 0x2EU +#define MIPI_DCS_SET_PARTIAL_ROWS 0x30U +#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31U +#define MIPI_DCS_SET_SCROLL_AREA 0x33U +#define MIPI_DCS_SET_TEAR_OFF 0x34U +#define MIPI_DCS_SET_TEAR_ON 0x35U +#define MIPI_DCS_SET_ADDRESS_MODE 0x36U +#define MIPI_DCS_SET_SCROLL_START 0x37U +#define MIPI_DCS_EXIT_IDLE_MODE 0x38U +#define MIPI_DCS_ENTER_IDLE_MODE 0x39U +#define MIPI_DCS_SET_PIXEL_FORMAT 0x3AU +#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3CU +#define MIPI_DCS_SET_3D_CONTROL 0x3DU +#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3EU +#define MIPI_DCS_GET_3D_CONTROL 0x3FU +#define MIPI_DCS_SET_VSYNC_TIMING 0x40U +#define MIPI_DCS_SET_TEAR_SCANLINE 0x44U +#define MIPI_DCS_GET_SCANLINE 0x45U +#define MIPI_DCS_SET_DISPLAY_BRIGHTNESS 0x51U +#define MIPI_DCS_GET_DISPLAY_BRIGHTNESS 0x52U +#define MIPI_DCS_WRITE_CONTROL_DISPLAY 0x53U +#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54U +#define MIPI_DCS_WRITE_POWER_SAVE 0x55U +#define MIPI_DCS_GET_POWER_SAVE 0x56U +#define MIPI_DCS_SET_CABC_MIN_BRIGHTNESS 0x5EU +#define MIPI_DCS_GET_CABC_MIN_BRIGHTNESS 0x5FU +#define MIPI_DCS_READ_DDB_START 0xA1U +#define MIPI_DCS_READ_DDB_CONTINUE 0xA8U + +#define MIPI_DCS_PIXEL_FORMAT_24BIT 0x77 +#define MIPI_DCS_PIXEL_FORMAT_18BIT 0x66 +#define MIPI_DCS_PIXEL_FORMAT_16BIT 0x55 +#define MIPI_DCS_PIXEL_FORMAT_12BIT 0x33 +#define MIPI_DCS_PIXEL_FORMAT_8BIT 0x22 +#define MIPI_DCS_PIXEL_FORMAT_3BIT 0x11 + +/** @} */ + +/** + * @name MIPI-DSI Address mode register fields. + * @{ + */ + +#define MIPI_DCS_ADDRESS_MODE_MIRROR_Y BIT(7) +#define MIPI_DCS_ADDRESS_MODE_MIRROR_X BIT(6) +#define MIPI_DCS_ADDRESS_MODE_SWAP_XY BIT(5) +#define MIPI_DCS_ADDRESS_MODE_REFRESH_BT BIT(4) +#define MIPI_DCS_ADDRESS_MODE_BGR BIT(3) +#define MIPI_DCS_ADDRESS_MODE_LATCH_RL BIT(2) +#define MIPI_DCS_ADDRESS_MODE_FLIP_X BIT(1) +#define MIPI_DCS_ADDRESS_MODE_FLIP_Y BIT(0) + +/** @} */ + +/** + * @name MIPI-DSI Processor-to-Peripheral transaction types. + * @{ + */ + +#define MIPI_DSI_V_SYNC_START 0x01U +#define MIPI_DSI_V_SYNC_END 0x11U +#define MIPI_DSI_H_SYNC_START 0x21U +#define MIPI_DSI_H_SYNC_END 0x31U +#define MIPI_DSI_COLOR_MODE_OFF 0x02U +#define MIPI_DSI_COLOR_MODE_ON 0x12U +#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22U +#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32U +#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03U +#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13U +#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23U +#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04U +#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14U +#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24U +#define MIPI_DSI_DCS_SHORT_WRITE 0x05U +#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15U +#define MIPI_DSI_DCS_READ 0x06U +#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37U +#define MIPI_DSI_END_OF_TRANSMISSION 0x08U +#define MIPI_DSI_NULL_PACKET 0x09U +#define MIPI_DSI_BLANKING_PACKET 0x19U +#define MIPI_DSI_GENERIC_LONG_WRITE 0x29U +#define MIPI_DSI_DCS_LONG_WRITE 0x39U +#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2CU +#define MIPI_DSI_PACKED_PIXEL_STREAM_30 0x0DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_36 0x1DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 0x3DU +#define MIPI_DSI_PACKED_PIXEL_STREAM_16 0x0EU +#define MIPI_DSI_PACKED_PIXEL_STREAM_18 0x1EU +#define MIPI_DSI_PIXEL_STREAM_3BYTE_18 0x2EU +#define MIPI_DSI_PACKED_PIXEL_STREAM_24 0x3EU + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DISPLAY_MIPI_DISPLAY_H_ */ diff --git a/include/zephyr/drivers/adc/adc_emul.h b/include/zephyr/drivers/adc/adc_emul.h index a07b86e38c9..03c2fbbb3fd 100644 --- a/include/zephyr/drivers/adc/adc_emul.h +++ b/include/zephyr/drivers/adc/adc_emul.h @@ -38,7 +38,7 @@ extern "C" { * function which will be used to obtain voltage on emulated ADC input * * An example of an appropriate Device Tree overlay file is in - * tests/drivers/adc/adc_api/boards/native_posix.overlay + * tests/drivers/adc/adc_api/boards/native_sim.overlay * * An example of using emulated ADC backend API is in the file * tests/drivers/adc/adc_emul/src/main.c diff --git a/include/zephyr/drivers/bluetooth/hci_driver.h b/include/zephyr/drivers/bluetooth/hci_driver.h index b318ad55ffb..e8a26b2cb94 100644 --- a/include/zephyr/drivers/bluetooth/hci_driver.h +++ b/include/zephyr/drivers/bluetooth/hci_driver.h @@ -139,6 +139,16 @@ enum bt_hci_driver_bus { BT_HCI_DRIVER_BUS_IPM = 9, }; +#if defined(CONFIG_BT_HCI_SETUP) || defined(__DOXYGEN__) +struct bt_hci_setup_params { + /** The public identity address to give to the controller. This field is used when the + * driver selects @kconfig{CONFIG_BT_HCI_SET_PUBLIC_ADDR} to indicate that it supports + * setting the controller's public address. + */ + bt_addr_t public_addr; +}; +#endif + /** * @brief Abstraction which represents the HCI transport to the controller. * @@ -213,7 +223,7 @@ struct bt_hci_driver { * * @return 0 on success or negative error number on failure. */ - int (*setup)(void); + int (*setup)(const struct bt_hci_setup_params *params); #endif /* defined(CONFIG_BT_HCI_SETUP) || defined(__DOXYGEN__)*/ }; diff --git a/include/zephyr/drivers/can.h b/include/zephyr/drivers/can.h index 0028abb330d..59be684fd38 100644 --- a/include/zephyr/drivers/can.h +++ b/include/zephyr/drivers/can.h @@ -203,14 +203,6 @@ struct can_frame { /** Filter matches frames with extended (29-bit) CAN IDs */ #define CAN_FILTER_IDE BIT(0) -/** Filter matches Remote Transmission Request (RTR) frames */ -#define CAN_FILTER_RTR BIT(1) - -/** Filter matches data frames */ -#define CAN_FILTER_DATA BIT(2) - -/** Filter matches CAN FD frames (FDF) */ -#define CAN_FILTER_FDF BIT(3) /** @} */ @@ -325,6 +317,73 @@ typedef void (*can_state_change_callback_t)(const struct device *dev, * For internal driver use only, skip these in public documentation. */ +/** + * @brief Common CAN controller driver configuration. + * + * This structure is common to all CAN controller drivers and is expected to be the first element in + * the object pointed to by the config field in the device structure. + */ +struct can_driver_config { + /** Pointer to the device structure for the associated CAN transceiver device or NULL. */ + const struct device *phy; + /** The maximum bitrate supported by the CAN controller/transceiver combination. */ + uint32_t max_bitrate; + /** Initial CAN classic/CAN FD arbitration phase bitrate. */ + uint32_t bus_speed; + /** Initial CAN classic/CAN FD arbitration phase sample point in permille. */ + uint16_t sample_point; +#ifdef CONFIG_CAN_FD_MODE + /** Initial CAN FD data phase sample point in permille. */ + uint16_t sample_point_data; + /** Initial CAN FD data phase bitrate. */ + uint32_t bus_speed_data; +#endif /* CONFIG_CAN_FD_MODE */ +}; + +/** + * @brief Static initializer for @p can_driver_config struct + * + * @param node_id Devicetree node identifier + * @param _max_bitrate maximum bitrate supported by the CAN controller + */ +#define CAN_DT_DRIVER_CONFIG_GET(node_id, _max_bitrate) \ + { \ + .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ + .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, _max_bitrate), \ + .bus_speed = DT_PROP(node_id, bus_speed), \ + .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ + IF_ENABLED(CONFIG_CAN_FD_MODE, \ + (.bus_speed_data = DT_PROP_OR(node_id, bus_speed_data, 0), \ + .sample_point_data = DT_PROP_OR(node_id, sample_point_data, 0),)) \ + } + +/** + * @brief Static initializer for @p can_driver_config struct from DT_DRV_COMPAT instance + * + * @param inst DT_DRV_COMPAT instance number + * @param _max_bitrate maximum bitrate supported by the CAN controller + * @see CAN_DT_DRIVER_CONFIG_GET() + */ +#define CAN_DT_DRIVER_CONFIG_INST_GET(inst, _max_bitrate) \ + CAN_DT_DRIVER_CONFIG_GET(DT_DRV_INST(inst), _max_bitrate) + +/** + * @brief Common CAN controller driver data. + * + * This structure is common to all CAN controller drivers and is expected to be the first element in + * the driver's struct driver_data declaration. + */ +struct can_driver_data { + /** Current CAN controller mode. */ + can_mode_t mode; + /** True if the CAN controller is started, false otherwise. */ + bool started; + /** State change callback function pointer or NULL. */ + can_state_change_callback_t state_change_cb; + /** State change callback user data pointer or NULL. */ + void *state_change_cb_user_data; +}; + /** * @brief Callback API upon setting CAN bus timing * See @a can_set_timing() for argument description @@ -423,12 +482,6 @@ typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate); */ typedef int (*can_get_max_filters_t)(const struct device *dev, bool ide); -/** - * @brief Optional callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -typedef int (*can_get_max_bitrate_t)(const struct device *dev, uint32_t *max_bitrate); - __subsystem struct can_driver_api { can_get_capabilities_t get_capabilities; can_start_t start; @@ -445,7 +498,6 @@ __subsystem struct can_driver_api { can_set_state_change_callback_t set_state_change_callback; can_get_core_clock_t get_core_clock; can_get_max_filters_t get_max_filters; - can_get_max_bitrate_t get_max_bitrate; /* Min values for the timing registers */ struct can_timing timing_min; /* Max values for the timing registers */ @@ -765,13 +817,15 @@ __syscall int can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrat static inline int z_impl_can_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) { - const struct can_driver_api *api = (const struct can_driver_api *)dev->api; + const struct can_driver_config *common = (const struct can_driver_config *)dev->config; - if (api->get_max_bitrate == NULL) { + if (common->max_bitrate == 0U) { return -ENOSYS; } - return api->get_max_bitrate(dev, max_bitrate); + *max_bitrate = common->max_bitrate; + + return 0; } /** @@ -1007,6 +1061,24 @@ static inline int z_impl_can_get_capabilities(const struct device *dev, can_mode return api->get_capabilities(dev, cap); } +/** + * @brief Get the CAN transceiver associated with the CAN controller + * + * Get a pointer to the device structure for the CAN transceiver associated with the CAN controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @return Pointer to the device structure for the associated CAN transceiver driver instance, or + * NULL if no transceiver is associated. + */ +__syscall const struct device *can_get_transceiver(const struct device *dev); + +static const struct device *z_impl_can_get_transceiver(const struct device *dev) +{ + const struct can_driver_config *common = (const struct can_driver_config *)dev->config; + + return common->phy; +} + /** * @brief Start the CAN controller * @@ -1076,6 +1148,22 @@ static inline int z_impl_can_set_mode(const struct device *dev, can_mode_t mode) return api->set_mode(dev, mode); } +/** + * @brief Get the operation mode of the CAN controller + * + * @param dev Pointer to the device structure for the driver instance. + * + * @return Current operation mode. + */ +__syscall can_mode_t can_get_mode(const struct device *dev); + +static inline can_mode_t z_impl_can_get_mode(const struct device *dev) +{ + const struct can_driver_data *common = (const struct can_driver_data *)dev->data; + + return common->mode; +} + /** * @brief Set the bitrate of the CAN controller * @@ -1195,7 +1283,7 @@ static inline int can_add_rx_filter(const struct device *dev, can_rx_callback_t { const struct can_driver_api *api = (const struct can_driver_api *)dev->api; - if (filter == NULL || (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) == 0) { + if (filter == NULL) { return -EINVAL; } @@ -1619,26 +1707,6 @@ static inline bool can_frame_matches_filter(const struct can_frame *frame, return false; } - if ((frame->flags & CAN_FRAME_RTR) == 0 && (filter->flags & CAN_FILTER_DATA) == 0) { - /* non-RTR frame, remote transmission request (RTR) filter */ - return false; - } - - if ((frame->flags & CAN_FRAME_RTR) != 0 && (filter->flags & CAN_FILTER_RTR) == 0) { - /* Remote transmission request (RTR) frame, non-RTR filter */ - return false; - } - - if ((frame->flags & CAN_FRAME_FDF) != 0 && (filter->flags & CAN_FILTER_FDF) == 0) { - /* CAN FD format frame, classic format filter */ - return false; - } - - if ((frame->flags & CAN_FRAME_FDF) == 0 && (filter->flags & CAN_FILTER_FDF) != 0) { - /* Classic frame, CAN FD format filter */ - return false; - } - if ((frame->id ^ filter->id) & filter->mask) { /* Masked ID mismatch */ return false; diff --git a/include/zephyr/drivers/can/can_fake.h b/include/zephyr/drivers/can/can_fake.h index ac2e000d6d1..1f66a9852fc 100644 --- a/include/zephyr/drivers/can/can_fake.h +++ b/include/zephyr/drivers/can/can_fake.h @@ -45,6 +45,8 @@ DECLARE_FAKE_VOID_FUNC(fake_can_set_state_change_callback, const struct device * DECLARE_FAKE_VALUE_FUNC(int, fake_can_get_max_filters, const struct device *, bool); +DECLARE_FAKE_VALUE_FUNC(int, fake_can_get_core_clock, const struct device *, uint32_t *); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index b29adc857f7..a20f9864880 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -1061,15 +1061,10 @@ struct can_mcan_ext_filter { * @brief Bosch M_CAN driver internal data structure. */ struct can_mcan_data { + struct can_driver_data common; struct k_mutex lock; struct k_sem tx_sem; struct k_mutex tx_mtx; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; - bool started; -#ifdef CONFIG_CAN_FD_MODE - bool fd; -#endif /* CONFIG_CAN_FD_MODE */ void *custom; } __aligned(4); @@ -1169,7 +1164,6 @@ struct can_mcan_tx_callback { struct can_mcan_rx_callback { can_rx_callback_t function; void *user_data; - uint8_t flags; }; /** @@ -1237,26 +1231,21 @@ struct can_mcan_callbacks { * @brief Bosch M_CAN driver internal configuration structure. */ struct can_mcan_config { + const struct can_driver_config common; const struct can_mcan_ops *ops; const struct can_mcan_callbacks *callbacks; uint16_t mram_elements[CAN_MCAN_MRAM_CFG_NUM_CELLS]; uint16_t mram_offsets[CAN_MCAN_MRAM_CFG_NUM_CELLS]; size_t mram_size; - uint32_t bus_speed; uint16_t sjw; - uint16_t sample_point; uint16_t prop_ts1; uint16_t ts2; #ifdef CONFIG_CAN_FD_MODE - uint32_t bus_speed_data; - uint16_t sample_point_data; uint8_t sjw_data; uint8_t prop_ts1_data; uint8_t ts2_data; uint8_t tx_delay_comp_offset; #endif - const struct device *phy; - uint32_t max_bitrate; const void *custom; }; @@ -1311,42 +1300,34 @@ struct can_mcan_config { #ifdef CONFIG_CAN_FD_MODE #define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops, _cbs) \ { \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 8000000), \ .ops = _ops, \ .callbacks = _cbs, \ .mram_elements = CAN_MCAN_DT_MRAM_ELEMENTS_GET(node_id), \ .mram_offsets = CAN_MCAN_DT_MRAM_OFFSETS_GET(node_id), \ .mram_size = CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id), \ - .bus_speed = DT_PROP(node_id, bus_speed), \ .sjw = DT_PROP(node_id, sjw), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .bus_speed_data = DT_PROP(node_id, bus_speed_data), \ .sjw_data = DT_PROP(node_id, sjw_data), \ - .sample_point_data = DT_PROP_OR(node_id, sample_point_data, 0), \ .prop_ts1_data = DT_PROP_OR(node_id, prop_seg_data, 0) + \ DT_PROP_OR(node_id, phase_seg1_data, 0), \ .ts2_data = DT_PROP_OR(node_id, phase_seg2_data, 0), \ .tx_delay_comp_offset = DT_PROP(node_id, tx_delay_comp_offset), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 8000000), \ .custom = _custom, \ } #else /* CONFIG_CAN_FD_MODE */ #define CAN_MCAN_DT_CONFIG_GET(node_id, _custom, _ops, _cbs) \ { \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 8000000), \ .ops = _ops, \ .callbacks = _cbs, \ .mram_elements = CAN_MCAN_DT_MRAM_ELEMENTS_GET(node_id), \ .mram_offsets = CAN_MCAN_DT_MRAM_OFFSETS_GET(node_id), \ .mram_size = CAN_MCAN_DT_MRAM_ELEMENTS_SIZE(node_id), \ - .bus_speed = DT_PROP(node_id, bus_speed), \ .sjw = DT_PROP(node_id, sjw), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ .prop_ts1 = DT_PROP_OR(node_id, prop_seg, 0) + DT_PROP_OR(node_id, phase_seg1, 0), \ .ts2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 1000000), \ .custom = _custom, \ } #endif /* !CONFIG_CAN_FD_MODE */ @@ -1728,10 +1709,4 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state, void can_mcan_set_state_change_callback(const struct device *dev, can_state_change_callback_t callback, void *user_data); -/** - * @brief Bosch M_CAN driver callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -int can_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); - #endif /* ZEPHYR_INCLUDE_DRIVERS_CAN_CAN_MCAN_H_ */ diff --git a/include/zephyr/drivers/can/can_sja1000.h b/include/zephyr/drivers/can/can_sja1000.h index fe826296db9..a3a316c26b8 100644 --- a/include/zephyr/drivers/can/can_sja1000.h +++ b/include/zephyr/drivers/can/can_sja1000.h @@ -102,15 +102,12 @@ typedef uint8_t (*can_sja1000_read_reg_t)(const struct device *dev, uint8_t reg) * @brief SJA1000 driver internal configuration structure. */ struct can_sja1000_config { + const struct can_driver_config common; can_sja1000_read_reg_t read_reg; can_sja1000_write_reg_t write_reg; - uint32_t bitrate; - uint32_t sample_point; uint32_t sjw; uint32_t phase_seg1; uint32_t phase_seg2; - const struct device *phy; - uint32_t max_bitrate; uint8_t ocr; uint8_t cdr; const void *custom; @@ -128,14 +125,15 @@ struct can_sja1000_config { */ #define CAN_SJA1000_DT_CONFIG_GET(node_id, _custom, _read_reg, _write_reg, _ocr, _cdr) \ { \ - .read_reg = _read_reg, .write_reg = _write_reg, \ - .bitrate = DT_PROP(node_id, bus_speed), .sjw = DT_PROP(node_id, sjw), \ + .common = CAN_DT_DRIVER_CONFIG_GET(node_id, 1000000), \ + .read_reg = _read_reg, \ + .write_reg = _write_reg, \ + .sjw = DT_PROP(node_id, sjw), \ .phase_seg1 = DT_PROP_OR(node_id, phase_seg1, 0), \ .phase_seg2 = DT_PROP_OR(node_id, phase_seg2, 0), \ - .sample_point = DT_PROP_OR(node_id, sample_point, 0), \ - .max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 1000000), \ - .phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, phys)), \ - .ocr = _ocr, .cdr = _cdr, .custom = _custom, \ + .ocr = _ocr, \ + .cdr = _cdr, \ + .custom = _custom, \ } /** @@ -165,14 +163,11 @@ struct can_sja1000_rx_filter { * @brief SJA1000 driver internal data structure. */ struct can_sja1000_data { + struct can_driver_data common; ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_MAX_FILTER); struct can_sja1000_rx_filter filters[CONFIG_CAN_MAX_FILTER]; struct k_mutex mod_lock; - bool started; - can_mode_t mode; enum can_state state; - can_state_change_callback_t state_change_cb; - void *state_change_cb_data; struct k_sem tx_idle; can_tx_callback_t tx_callback; void *tx_user_data; @@ -266,12 +261,6 @@ void can_sja1000_set_state_change_callback(const struct device *dev, */ int can_sja1000_get_max_filters(const struct device *dev, bool ide); -/** - * @brief SJA1000 callback API upon getting the maximum supported bitrate - * See @a can_get_max_bitrate() for argument description - */ -int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate); - /** * @brief SJA1000 IRQ handler callback. * diff --git a/include/zephyr/drivers/can/transceiver.h b/include/zephyr/drivers/can/transceiver.h index e4c6828983c..19c22e7733d 100644 --- a/include/zephyr/drivers/can/transceiver.h +++ b/include/zephyr/drivers/can/transceiver.h @@ -7,6 +7,7 @@ #ifndef ZEPHYR_INCLUDE_DRIVERS_CAN_TRANSCEIVER_H_ #define ZEPHYR_INCLUDE_DRIVERS_CAN_TRANSCEIVER_H_ +#include #include #ifdef __cplusplus @@ -30,7 +31,7 @@ extern "C" { * @brief Callback API upon enabling CAN transceiver * See @a can_transceiver_enable() for argument description */ -typedef int (*can_transceiver_enable_t)(const struct device *dev); +typedef int (*can_transceiver_enable_t)(const struct device *dev, can_mode_t mode); /** * @brief Callback API upon disabling CAN transceiver @@ -56,15 +57,16 @@ __subsystem struct can_transceiver_driver_api { * @see can_start() * * @param dev Pointer to the device structure for the driver instance. + * @param mode Operation mode. * @retval 0 If successful. * @retval -EIO General input/output error, failed to enable device. */ -static inline int can_transceiver_enable(const struct device *dev) +static inline int can_transceiver_enable(const struct device *dev, can_mode_t mode) { const struct can_transceiver_driver_api *api = (const struct can_transceiver_driver_api *)dev->api; - return api->enable(dev); + return api->enable(dev, mode); } /** diff --git a/include/zephyr/drivers/cellular.h b/include/zephyr/drivers/cellular.h new file mode 100644 index 00000000000..fba05e6e440 --- /dev/null +++ b/include/zephyr/drivers/cellular.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2023 Bjarki Arge Andreasen + * Copyright (c) 2023 Lucas Denefle + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file drivers/cellular.h + * @brief Public cellular network API + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ + +/** + * @brief Cellular interface + * @defgroup cellular_interface Cellular Interface + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Cellular access technologies */ +enum cellular_access_technology { + CELLULAR_ACCESS_TECHNOLOGY_GSM = 0, + CELLULAR_ACCESS_TECHNOLOGY_GPRS, + CELLULAR_ACCESS_TECHNOLOGY_UMTS, + CELLULAR_ACCESS_TECHNOLOGY_EDGE, + CELLULAR_ACCESS_TECHNOLOGY_LTE, + CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M1, + CELLULAR_ACCESS_TECHNOLOGY_LTE_CAT_M2, + CELLULAR_ACCESS_TECHNOLOGY_NB_IOT, +}; + +/** Cellular network structure */ +struct cellular_network { + /** Cellular access technology */ + enum cellular_access_technology technology; + /** + * List of bands, as defined by the specified cellular access technology, + * to enables. All supported bands are enabled if none are provided. + */ + uint16_t *bands; + /** Size of bands */ + uint16_t size; +}; + +/** Cellular signal type */ +enum cellular_signal_type { + CELLULAR_SIGNAL_RSSI, + CELLULAR_SIGNAL_RSRP, + CELLULAR_SIGNAL_RSRQ, +}; + +/** Cellular modem info type */ +enum cellular_modem_info_type { + /** International Mobile Equipment Identity */ + CELLULAR_MODEM_INFO_IMEI, + /** Modem model ID */ + CELLULAR_MODEM_INFO_MODEL_ID, + /** Modem manufacturer */ + CELLULAR_MODEM_INFO_MANUFACTURER, + /** Modem fw version */ + CELLULAR_MODEM_INFO_FW_VERSION, + /** International Mobile Subscriber Identity */ + CELLULAR_MODEM_INFO_SIM_IMSI, + /** Integrated Circuit Card Identification Number (SIM) */ + CELLULAR_MODEM_INFO_SIM_ICCID, +}; + +/** API for configuring networks */ +typedef int (*cellular_api_configure_networks)(const struct device *dev, + const struct cellular_network *networks, + uint8_t size); + +/** API for getting supported networks */ +typedef int (*cellular_api_get_supported_networks)(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size); + +/** API for getting network signal strength */ +typedef int (*cellular_api_get_signal)(const struct device *dev, + const enum cellular_signal_type type, int16_t *value); + +/** API for getting modem information */ +typedef int (*cellular_api_get_modem_info)(const struct device *dev, + const enum cellular_modem_info_type type, + char *info, size_t size); + +/** Cellular driver API */ +__subsystem struct cellular_driver_api { + cellular_api_configure_networks configure_networks; + cellular_api_get_supported_networks get_supported_networks; + cellular_api_get_signal get_signal; + cellular_api_get_modem_info get_modem_info; +}; + +/** + * @brief Configure cellular networks for the device + * + * @details Cellular network devices support at least one cellular access technology. + * Each cellular access technology defines a set of bands, of which the cellular device + * will support all or a subset of. + * + * The cellular device can only use one cellular network technology at a time. It must + * exclusively use the cellular network configurations provided, and will prioritize + * the cellular network configurations in the order they are provided in case there are + * multiple (the first cellular network configuration has the highest priority). + * + * @param dev Cellular network device instance. + * @param networks List of cellular network configurations to apply. + * @param size Size of list of cellular network configurations. + * + * @retval 0 if successful. + * @retval -EINVAL if any provided cellular network configuration is invalid or unsupported. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval Negative errno-code otherwise. + */ +static inline int cellular_configure_networks(const struct device *dev, + const struct cellular_network *networks, uint8_t size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->configure_networks == NULL) { + return -ENOSYS; + } + + return api->configure_networks(dev, networks, size); +} + +/** + * @brief Get supported cellular networks for the device + * + * @param dev Cellular network device instance + * @param networks Pointer to list of supported cellular network configurations. + * @param size Size of list of cellular network configurations. + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval Negative errno-code otherwise. + */ +static inline int cellular_get_supported_networks(const struct device *dev, + const struct cellular_network **networks, + uint8_t *size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_supported_networks == NULL) { + return -ENOSYS; + } + + return api->get_supported_networks(dev, networks, size); +} + +/** + * @brief Get signal for the device + * + * @param dev Cellular network device instance + * @param type Type of the signal information requested + * @param value Signal strength destination (one of RSSI, RSRP, RSRQ) + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval -ENODATA if device is not in a state where signal can be polled + * @retval Negative errno-code otherwise. + */ +static inline int cellular_get_signal(const struct device *dev, + const enum cellular_signal_type type, int16_t *value) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_signal == NULL) { + return -ENOSYS; + } + + return api->get_signal(dev, type, value); +} + +/** + * @brief Get modem info for the device + * + * @param dev Cellular network device instance + * @param type Type of the modem info requested + * @param info Info string destination + * @param size Info string size + * + * @retval 0 if successful. + * @retval -ENOTSUP if API is not supported by cellular network device. + * @retval -ENODATA if modem does not provide info requested + * @retval Negative errno-code from chat module otherwise. + */ +static inline int cellular_get_modem_info(const struct device *dev, + const enum cellular_modem_info_type type, char *info, + size_t size) +{ + const struct cellular_driver_api *api = (const struct cellular_driver_api *)dev->api; + + if (api->get_modem_info == NULL) { + return -ENOSYS; + } + + return api->get_modem_info(dev, type, info, size); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CELLULAR_H_ */ diff --git a/include/zephyr/drivers/charger.h b/include/zephyr/drivers/charger.h index 6159f41dcc0..cf55fd88402 100644 --- a/include/zephyr/drivers/charger.h +++ b/include/zephyr/drivers/charger.h @@ -56,6 +56,27 @@ enum charger_property { CHARGER_PROP_CHARGE_TERM_CURRENT_UA, /** Configuration of charge voltage regulation target in µV */ CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV, + /** + * Configuration of the input current regulation target in µA + * + * This value is a rising current threshold that is regulated by reducing the charge + * current output + */ + CHARGER_PROP_INPUT_REGULATION_CURRENT_UA, + /** + * Configuration of the input voltage regulation target in µV + * + * This value is a falling voltage threshold that is regulated by reducing the charge + * current output + */ + CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV, + /** + * Configuration to issue a notification to the system based on the input current + * level and timing + * + * Value should be of type struct charger_input_current_notifier + */ + CHARGER_PROP_INPUT_CURRENT_NOTIFICATION, /** Reserved to demark end of common charger properties */ CHARGER_PROP_COMMON_COUNT, /** @@ -173,6 +194,30 @@ enum charger_health { CHARGER_HEALTH_NO_BATTERY, }; +/** + * @brief Charger severity levels for system notifications + */ +enum charger_notification_severity { + /** Most severe level, typically triggered instantaneously */ + CHARGER_SEVERITY_PEAK = 0, + /** More severe than the warning level, less severe than peak */ + CHARGER_SEVERITY_CRITICAL, + /** Base severity level */ + CHARGER_SEVERITY_WARNING, +}; + +/** + * @brief The input current thresholds for the charger to notify the system + */ +struct charger_current_notifier { + /** The severity of the notification where CHARGER_SEVERITY_PEAK is the most severe */ + uint8_t severity; + /** The current threshold to be exceeded */ + uint32_t current_ua; + /** The duration of excess current before notifying the system */ + uint32_t duration_us; +}; + /** * @brief container for a charger_property value * @@ -200,6 +245,12 @@ union charger_propval { uint32_t charge_term_current_ua; /** CHARGER_PROP_CONSTANT_CHARGE_VOLTAGE_UV */ uint32_t const_charge_voltage_uv; + /** CHARGER_PROP_INPUT_REGULATION_CURRENT_UA */ + uint32_t input_current_regulation_current_ua; + /** CHARGER_PROP_INPUT_REGULATION_VOLTAGE_UV */ + uint32_t input_voltage_regulation_voltage_uv; + /** CHARGER_PROP_INPUT_CURRENT_NOTIFICATION */ + struct charger_current_notifier input_current_notification; }; /** @@ -220,6 +271,14 @@ typedef int (*charger_get_property_t)(const struct device *dev, const charger_pr typedef int (*charger_set_property_t)(const struct device *dev, const charger_prop_t prop, const union charger_propval *val); +/** + * @typedef charger_charge_enable_t + * @brief Callback API enabling or disabling a charge cycle. + * + * See charger_charge_enable() for argument description + */ +typedef int (*charger_charge_enable_t)(const struct device *dev, const bool enable); + /** * @brief Charging device API * @@ -228,6 +287,7 @@ typedef int (*charger_set_property_t)(const struct device *dev, const charger_pr __subsystem struct charger_driver_api { charger_get_property_t get_property; charger_set_property_t set_property; + charger_charge_enable_t charge_enable; }; /** @@ -272,6 +332,25 @@ static inline int z_impl_charger_set_prop(const struct device *dev, const charge return api->set_property(dev, prop, val); } +/** + * @brief Enable or disable a charge cycle + * + * @param dev Pointer to the battery charger device + * @param enable true enables a charge cycle, false disables a charge cycle + * + * @retval 0 if successful + * @retval -EIO if communication with the charger failed + * @retval -EINVAL if the conditions for initiating charging are invalid + */ +__syscall int charger_charge_enable(const struct device *dev, const bool enable); + +static inline int z_impl_charger_charge_enable(const struct device *dev, const bool enable) +{ + const struct charger_driver_api *api = (const struct charger_driver_api *)dev->api; + + return api->charge_enable(dev, enable); +} + /** * @} */ diff --git a/include/zephyr/drivers/clock_control/stm32_clock_control.h b/include/zephyr/drivers/clock_control/stm32_clock_control.h index f18c351c0d5..062fae034e3 100644 --- a/include/zephyr/drivers/clock_control/stm32_clock_control.h +++ b/include/zephyr/drivers/clock_control/stm32_clock_control.h @@ -369,6 +369,7 @@ #define STM32_HSE_ENABLED 1 #define STM32_HSE_BYPASS DT_PROP(DT_NODELABEL(clk_hse), hse_bypass) #define STM32_HSE_FREQ DT_PROP(DT_NODELABEL(clk_hse), clock_frequency) +#define STM32_HSE_CSS DT_PROP(DT_NODELABEL(clk_hse), css_enabled) #elif DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_hse), st_stm32wl_hse_clock, okay) #define STM32_HSE_ENABLED 1 #define STM32_HSE_TCXO DT_PROP(DT_NODELABEL(clk_hse), hse_tcxo) @@ -460,4 +461,16 @@ struct stm32_pclken { #define STM32_CLOCK_VAL_GET(clock) \ (((clock) >> STM32_CLOCK_VAL_SHIFT) & STM32_CLOCK_VAL_MASK) +#if defined(STM32_HSE_CSS) +/** + * @brief Called if the HSE clock security system detects a clock fault. + * + * The function is called in interrupt context. + * + * The default (weakly-linked) implementation does nothing and should be + * overridden. + */ +void stm32_hse_css_callback(void); +#endif + #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_STM32_CLOCK_CONTROL_H_ */ diff --git a/include/zephyr/drivers/dai.h b/include/zephyr/drivers/dai.h index da124b4512d..e0969292fbb 100644 --- a/include/zephyr/drivers/dai.h +++ b/include/zephyr/drivers/dai.h @@ -33,6 +33,61 @@ extern "C" { #endif +/** Used to extract the clock configuration from the format attribute of struct dai_config */ +#define DAI_FORMAT_CLOCK_PROVIDER_MASK 0xf000 +/** Used to extract the protocol from the format attribute of struct dai_config */ +#define DAI_FORMAT_PROTOCOL_MASK 0x000f +/** Used to extract the clock inversion from the format attribute of struct dai_config */ +#define DAI_FORMAT_CLOCK_INVERSION_MASK 0x0f00 + +/** @brief DAI clock configurations + * + * This is used to describe all of the possible + * clock-related configurations w.r.t the DAI + * and the codec. + */ +enum dai_clock_provider { + /**< codec BLCK provider, codec FSYNC provider */ + DAI_CBP_CFP = (0 << 12), + /**< codec BCLK consumer, codec FSYNC provider */ + DAI_CBC_CFP = (2 << 12), + /**< codec BCLK provider, codec FSYNC consumer */ + DAI_CBP_CFC = (3 << 12), + /**< codec BCLK consumer, codec FSYNC consumer */ + DAI_CBC_CFC = (4 << 12), +}; + +/** @brief DAI protocol + * + * The communication between the DAI and the CODEC + * may use different protocols depending on the scenario. + */ +enum dai_protocol { + DAI_PROTO_I2S = 1, /**< I2S */ + DAI_PROTO_RIGHT_J, /**< Right Justified */ + DAI_PROTO_LEFT_J, /**< Left Justified */ + DAI_PROTO_DSP_A, /**< TDM, FSYNC asserted 1 BCLK early */ + DAI_PROTO_DSP_B, /**< TDM, FSYNC asserted at the same time as MSB */ + DAI_PROTO_PDM, /**< Pulse Density Modulation */ +}; + +/** @brief DAI clock inversion + * + * Some applications may require a different + * clock polarity (FSYNC/BCLK) compared to + * the default one chosen based on the protocol. + */ +enum dai_clock_inversion { + /**< no BCLK inversion, no FSYNC inversion */ + DAI_INVERSION_NB_NF = 0, + /**< no BCLK inversion, FSYNC inversion */ + DAI_INVERSION_NB_IF = (2 << 8), + /**< BCLK inversion, no FSYNC inversion */ + DAI_INVERSION_IB_NF = (3 << 8), + /**< BCLK inversion, FSYNC inversion */ + DAI_INVERSION_IB_IF = (4 << 8), +}; + /** @brief Types of DAI * * The type of the DAI. This ID type is used to configure bespoke DAI HW @@ -64,10 +119,10 @@ enum dai_type { * @brief DAI Direction */ enum dai_dir { - /** Receive data */ - DAI_DIR_RX = 1, /** Transmit data */ - DAI_DIR_TX, + DAI_DIR_TX = 0, + /** Receive data */ + DAI_DIR_RX, /** Both receive and transmit data */ DAI_DIR_BOTH, }; diff --git a/include/zephyr/drivers/display.h b/include/zephyr/drivers/display.h index a72534b4e50..010443e319f 100644 --- a/include/zephyr/drivers/display.h +++ b/include/zephyr/drivers/display.h @@ -38,12 +38,12 @@ extern "C" { * big endian. */ enum display_pixel_format { - PIXEL_FORMAT_RGB_888 = BIT(0), - PIXEL_FORMAT_MONO01 = BIT(1), /* 0=Black 1=White */ - PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ - PIXEL_FORMAT_ARGB_8888 = BIT(3), - PIXEL_FORMAT_RGB_565 = BIT(4), - PIXEL_FORMAT_BGR_565 = BIT(5), + PIXEL_FORMAT_RGB_888 = BIT(0), /**< 24-bit RGB */ + PIXEL_FORMAT_MONO01 = BIT(1), /**< Monochrome (0=Black 1=White) */ + PIXEL_FORMAT_MONO10 = BIT(2), /**< Monochrome (1=Black 0=White) */ + PIXEL_FORMAT_ARGB_8888 = BIT(3), /**< 32-bit ARGB */ + PIXEL_FORMAT_RGB_565 = BIT(4), /**< 16-bit RGB */ + PIXEL_FORMAT_BGR_565 = BIT(5), /**< 16-bit BGR */ }; /** @@ -61,6 +61,9 @@ enum display_pixel_format { (((fmt & PIXEL_FORMAT_RGB_565) >> 4) * 16U) + \ (((fmt & PIXEL_FORMAT_BGR_565) >> 5) * 16U)) +/** + * @brief Display screen information + */ enum display_screen_info { /** * If selected, one octet represents 8 pixels ordered vertically, @@ -87,15 +90,13 @@ enum display_screen_info { }; /** - * @enum display_orientation * @brief Enumeration with possible display orientation - * */ enum display_orientation { - DISPLAY_ORIENTATION_NORMAL, - DISPLAY_ORIENTATION_ROTATED_90, - DISPLAY_ORIENTATION_ROTATED_180, - DISPLAY_ORIENTATION_ROTATED_270, + DISPLAY_ORIENTATION_NORMAL, /**< No rotation */ + DISPLAY_ORIENTATION_ROTATED_90, /**< Rotated 90 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_180, /**< Rotated 180 degrees clockwise */ + DISPLAY_ORIENTATION_ROTATED_270, /**< Rotated 270 degrees clockwise */ }; /** @brief Structure holding display capabilities. */ @@ -259,6 +260,7 @@ static inline int display_write(const struct device *dev, const uint16_t x, * @param buf Pointer to buffer array * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_read(const struct device *dev, const uint16_t x, const uint16_t y, @@ -268,6 +270,10 @@ static inline int display_read(const struct device *dev, const uint16_t x, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->read == NULL) { + return -ENOSYS; + } + return api->read(dev, x, y, desc, buf); } @@ -285,6 +291,10 @@ static inline void *display_get_framebuffer(const struct device *dev) struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->get_framebuffer == NULL) { + return NULL; + } + return api->get_framebuffer(dev); } @@ -305,12 +315,17 @@ static inline void *display_get_framebuffer(const struct device *dev) * @param dev Pointer to device structure * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_blanking_on(const struct device *dev) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->blanking_on == NULL) { + return -ENOSYS; + } + return api->blanking_on(dev); } @@ -324,12 +339,17 @@ static inline int display_blanking_on(const struct device *dev) * @param dev Pointer to device structure * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_blanking_off(const struct device *dev) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->blanking_off == NULL) { + return -ENOSYS; + } + return api->blanking_off(dev); } @@ -343,6 +363,7 @@ static inline int display_blanking_off(const struct device *dev) * @param brightness Brightness in steps of 1/256 * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_brightness(const struct device *dev, uint8_t brightness) @@ -350,6 +371,10 @@ static inline int display_set_brightness(const struct device *dev, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_brightness == NULL) { + return -ENOSYS; + } + return api->set_brightness(dev, brightness); } @@ -363,12 +388,17 @@ static inline int display_set_brightness(const struct device *dev, * @param contrast Contrast in steps of 1/256 * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_contrast(const struct device *dev, uint8_t contrast) { struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_contrast == NULL) { + return -ENOSYS; + } + return api->set_contrast(dev, contrast); } @@ -395,6 +425,7 @@ static inline void display_get_capabilities(const struct device *dev, * @param pixel_format Pixel format to be used by display * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_pixel_format(const struct device *dev, @@ -403,6 +434,10 @@ display_set_pixel_format(const struct device *dev, struct display_driver_api *api = (struct display_driver_api *)dev->api; + if (api->set_pixel_format == NULL) { + return -ENOSYS; + } + return api->set_pixel_format(dev, pixel_format); } @@ -413,6 +448,7 @@ display_set_pixel_format(const struct device *dev, * @param orientation Orientation to be used by display * * @retval 0 on success else negative errno code. + * @retval -ENOSYS if not implemented. */ static inline int display_set_orientation(const struct device *dev, const enum display_orientation diff --git a/include/zephyr/drivers/dma/dma_stm32.h b/include/zephyr/drivers/dma/dma_stm32.h index 3ccfeb9be10..c4c593457cb 100644 --- a/include/zephyr/drivers/dma/dma_stm32.h +++ b/include/zephyr/drivers/dma/dma_stm32.h @@ -33,8 +33,10 @@ /* macro for dma slot (only for dma-v1 or dma-v2 types) */ #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2bis) #define STM32_DMA_SLOT(id, dir, slot) 0 +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) #else #define STM32_DMA_SLOT(id, dir, slot) DT_INST_DMAS_CELL_BY_NAME(id, dir, slot) +#define STM32_DMA_SLOT_BY_IDX(id, idx, slot) DT_INST_DMAS_CELL_BY_IDX(id, idx, slot) #endif #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_dma_v2) || \ @@ -50,6 +52,8 @@ DT_INST_DMAS_CTLR_BY_NAME(id, dir) #define STM32_DMA_CHANNEL_CONFIG(id, dir) \ DT_INST_DMAS_CELL_BY_NAME(id, dir, channel_config) +#define STM32_DMA_CHANNEL_CONFIG_BY_IDX(id, idx) \ + DT_INST_DMAS_CELL_BY_IDX(id, idx, channel_config) /* macros for channel-config */ /* direction defined on bits 6-7 */ diff --git a/include/zephyr/drivers/emul.h b/include/zephyr/drivers/emul.h index 7c306de9889..01297666dac 100644 --- a/include/zephyr/drivers/emul.h +++ b/include/zephyr/drivers/emul.h @@ -36,6 +36,7 @@ enum emul_bus_type { EMUL_BUS_TYPE_I2C, EMUL_BUS_TYPE_ESPI, EMUL_BUS_TYPE_SPI, + EMUL_BUS_TYPE_NONE, }; /** @@ -62,6 +63,14 @@ struct emul_list_for_bus { */ typedef int (*emul_init_t)(const struct emul *emul, const struct device *parent); +/** + * Emulator API stub when an emulator is not actually placed on a bus. + */ +struct no_bus_emul { + void *api; + uint16_t addr; +}; + /** An emulator instance - represents the *target* emulated device/peripheral that is * interacted with through an emulated bus. Instances of emulated bus nodes (e.g. i2c_emul) * and emulators (i.e. struct emul) are exactly 1..1 @@ -82,6 +91,7 @@ struct emul { struct i2c_emul *i2c; struct espi_emul *espi; struct spi_emul *spi; + struct no_bus_emul *none; } bus; /** Address of the API structure exposed by the emulator instance */ const void *backend_api; @@ -101,10 +111,10 @@ struct emul { #define Z_EMUL_REG_BUS_IDENTIFIER(_dev_node_id) (_CONCAT(_CONCAT(__emulreg_, _dev_node_id), _bus)) /* Conditionally places text based on what bus _dev_node_id is on. */ -#define Z_EMUL_BUS(_dev_node_id, _i2c, _espi, _spi) \ +#define Z_EMUL_BUS(_dev_node_id, _i2c, _espi, _spi, _none) \ COND_CODE_1(DT_ON_BUS(_dev_node_id, i2c), (_i2c), \ (COND_CODE_1(DT_ON_BUS(_dev_node_id, espi), (_espi), \ - (COND_CODE_1(DT_ON_BUS(_dev_node_id, spi), (_spi), (-EINVAL)))))) + (COND_CODE_1(DT_ON_BUS(_dev_node_id, spi), (_spi), (_none)))))) /** * @brief Define a new emulator * @@ -120,10 +130,10 @@ struct emul { * @param _backend_api emulator-specific backend api */ #define EMUL_DT_DEFINE(node_id, init_fn, data_ptr, cfg_ptr, bus_api, _backend_api) \ - static struct Z_EMUL_BUS(node_id, i2c_emul, espi_emul, spi_emul) \ + static struct Z_EMUL_BUS(node_id, i2c_emul, espi_emul, spi_emul, no_bus_emul) \ Z_EMUL_REG_BUS_IDENTIFIER(node_id) = { \ .api = bus_api, \ - .Z_EMUL_BUS(node_id, addr, chipsel, chipsel) = DT_REG_ADDR(node_id), \ + .Z_EMUL_BUS(node_id, addr, chipsel, chipsel, addr) = DT_REG_ADDR(node_id), \ }; \ const STRUCT_SECTION_ITERABLE(emul, EMUL_DT_NAME_GET(node_id)) \ __used = { \ @@ -132,8 +142,8 @@ struct emul { .cfg = (cfg_ptr), \ .data = (data_ptr), \ .bus_type = Z_EMUL_BUS(node_id, EMUL_BUS_TYPE_I2C, EMUL_BUS_TYPE_ESPI, \ - EMUL_BUS_TYPE_SPI), \ - .bus = {.Z_EMUL_BUS(node_id, i2c, espi, spi) = \ + EMUL_BUS_TYPE_SPI, EMUL_BUS_TYPE_NONE), \ + .bus = {.Z_EMUL_BUS(node_id, i2c, espi, spi, none) = \ &(Z_EMUL_REG_BUS_IDENTIFIER(node_id))}, \ .backend_api = (_backend_api), \ }; @@ -164,6 +174,18 @@ struct emul { */ #define EMUL_DT_GET(node_id) (&EMUL_DT_NAME_GET(node_id)) +/** + * @brief Utility macro to obtain an optional reference to an emulator + * + * If the node identifier referes to a node with status `okay`, this returns `EMUL_DT_GET(node_id)`. + * Otherwise, it returns `NULL`. + * + * @param node_id A devicetree node identifier + * @return a @ref emul reference for the node identifier, which may be `NULL`. + */ +#define EMUL_DT_GET_OR_NULL(node_id) \ + COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay), (EMUL_DT_GET(node_id)), (NULL)) + /** * @brief Set up a list of emulators * diff --git a/include/zephyr/drivers/emul_bbram.h b/include/zephyr/drivers/emul_bbram.h new file mode 100644 index 00000000000..441f101c934 --- /dev/null +++ b/include/zephyr/drivers/emul_bbram.h @@ -0,0 +1,96 @@ +/* + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ +#define INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ + +#include + +#include + +/** + * @brief BBRAM emulator backend API + * @defgroup bbram_emulator_backend BBRAM emulator backend API + * @ingroup io_interfaces + * @{ + */ + +/** + * @cond INTERNAL_HIDDEN + * + * These are for internal use only, so skip these in public documentation. + */ + +__subsystem struct emul_bbram_backend_api { + /** Sets the data */ + int (*set_data)(const struct emul *target, size_t offset, size_t count, + const uint8_t *data); + /** Checks the data */ + int (*get_data)(const struct emul *target, size_t offset, size_t count, uint8_t *data); +}; + +/** + * @endcond + */ + +/** + * @brief Set the expected data in the bbram region + * + * @param target Pointer to the emulator instance to operate on + * @param offset Offset within the memory to set + * @param count Number of bytes to write + * @param data The data to write + * @return 0 if successful + * @return -ENOTSUP if no backend API or if the set_data function isn't implemented + * @return -ERANGE if the destination address is out of range. + */ +static inline int emul_bbram_backend_set_data(const struct emul *target, size_t offset, + size_t count, const uint8_t *data) +{ + if (target == NULL || target->backend_api == NULL) { + return -ENOTSUP; + } + + struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + + if (api->set_data == NULL) { + return -ENOTSUP; + } + + return api->set_data(target, offset, count, data); +} + +/** + * @brief Get the expected data in the bbram region + * + * @param target Pointer to the emulator instance to operate on + * @param offset Offset within the memory to get + * @param count Number of bytes to read + * @param data The data buffer to hold the result + * @return 0 if successful + * @return -ENOTSUP if no backend API or if the get_data function isn't implemented + * @return -ERANGE if the address is out of range. + */ +static inline int emul_bbram_backend_get_data(const struct emul *target, size_t offset, + size_t count, uint8_t *data) +{ + if (target == NULL || target->backend_api == NULL) { + return -ENOTSUP; + } + + struct emul_bbram_backend_api *api = (struct emul_bbram_backend_api *)target->backend_api; + + if (api->get_data == NULL) { + return -ENOTSUP; + } + + return api->get_data(target, offset, count, data); +} + +/** + * @} + */ + +#endif /* INCLUDE_ZEPHYR_DRIVERS_EMUL_BBRAM_H_ */ diff --git a/include/zephyr/drivers/emul_sensor.h b/include/zephyr/drivers/emul_sensor.h index 44a497ee401..30345cc6a0b 100644 --- a/include/zephyr/drivers/emul_sensor.h +++ b/include/zephyr/drivers/emul_sensor.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -26,11 +27,18 @@ */ __subsystem struct emul_sensor_backend_api { /** Sets a given fractional value for a given sensor channel. */ - int (*set_channel)(const struct emul *target, enum sensor_channel ch, q31_t value, + int (*set_channel)(const struct emul *target, enum sensor_channel ch, const q31_t *value, int8_t shift); /** Retrieve a range of sensor values to use with test. */ int (*get_sample_range)(const struct emul *target, enum sensor_channel ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift); + /** Set the attribute value(s) of a given chanel. */ + int (*set_attribute)(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, const void *value); + /** Get metadata about an attribute. */ + int (*get_attribute_metadata)(const struct emul *target, enum sensor_channel ch, + enum sensor_attribute attribute, q31_t *min, q31_t *max, + q31_t *increment, int8_t *shift); }; /** * @endcond @@ -61,7 +69,7 @@ static inline bool emul_sensor_backend_is_supported(const struct emul *target) * @return -ERANGE if provided value is not in the sensor's supported range */ static inline int emul_sensor_backend_set_channel(const struct emul *target, enum sensor_channel ch, - q31_t value, int8_t shift) + const q31_t *value, int8_t shift) { if (!target || !target->backend_api) { return -ENOTSUP; @@ -108,6 +116,68 @@ static inline int emul_sensor_backend_get_sample_range(const struct emul *target return -ENOTSUP; } +/** + * @brief Set the emulator's attribute values + * + * @param[in] target Pointer to emulator instance to operate on + * @param[in] ch The channel to request info for. If \p ch is unsupported, return `-ENOTSUP` + * @param[in] attribute The attribute to set + * @param[in] value the value to use (cast according to the channel/attribute pair) + * @return 0 is successful + * @return < 0 on error + */ +static inline int emul_sensor_backend_set_attribute(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, + const void *value) +{ + if (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->set_attribute == NULL) { + return -ENOTSUP; + } + return api->set_attribute(target, ch, attribute, value); +} + +/** + * @brief Get metadata about an attribute. + * + * Information provided by this function includes the minimum/maximum values of the attribute as + * well as the increment (value per LSB) which can be used as an epsilon when comparing results. + * + * @param[in] target Pointer to emulator instance to operate on + * @param[in] ch The channel to request info for. If \p ch is unsupported, return '-ENOTSUP' + * @param[in] attribute The attribute to request info for. If \p attribute is unsupported, return + * '-ENOTSUP' + * @param[out] min The minimum value the attribute can be set to + * @param[out] max The maximum value the attribute can be set to + * @param[out] increment The value that the attribute increses by for every LSB + * @param[out] shift The shift for \p min, \p max, and \p increment + * @return 0 on SUCCESS + * @return < 0 on error + */ +static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target, + enum sensor_channel ch, + enum sensor_attribute attribute, + q31_t *min, q31_t *max, + q31_t *increment, int8_t *shift) +{ + if (!target || !target->backend_api) { + return -ENOTSUP; + } + + struct emul_sensor_backend_api *api = (struct emul_sensor_backend_api *)target->backend_api; + + if (api->get_attribute_metadata == NULL) { + return -ENOTSUP; + } + return api->get_attribute_metadata(target, ch, attribute, min, max, increment, shift); +} + /** * @} */ diff --git a/include/zephyr/drivers/espi_saf.h b/include/zephyr/drivers/espi_saf.h index 9c6f47d1590..31fc23c0808 100644 --- a/include/zephyr/drivers/espi_saf.h +++ b/include/zephyr/drivers/espi_saf.h @@ -145,6 +145,8 @@ typedef int (*espi_saf_api_flash_write)(const struct device *dev, struct espi_saf_packet *pckt); typedef int (*espi_saf_api_flash_erase)(const struct device *dev, struct espi_saf_packet *pckt); +typedef int (*espi_saf_api_flash_unsuccess)(const struct device *dev, + struct espi_saf_packet *pckt); /* Callbacks and traffic intercept */ typedef int (*espi_saf_api_manage_callback)(const struct device *dev, struct espi_callback *callback, @@ -158,6 +160,7 @@ __subsystem struct espi_saf_driver_api { espi_saf_api_flash_read flash_read; espi_saf_api_flash_write flash_write; espi_saf_api_flash_erase flash_erase; + espi_saf_api_flash_unsuccess flash_unsuccess; espi_saf_api_manage_callback manage_callback; }; @@ -383,6 +386,35 @@ static inline int z_impl_espi_saf_flash_erase(const struct device *dev, return api->flash_erase(dev, pckt); } +/** + * @brief Response unsuccessful completion for slave attached flash. + * + * This routines provides an interface to response that transaction is + * invalid and return unsuccessful completion from target to controller. + * + * @param dev Pointer to the device structure for the driver instance. + * @param pckt Address of the representation of flash transaction. + * + * @retval -ENOTSUP eSPI flash logical channel transactions not supported. + * @retval -EBUSY eSPI flash channel is not ready or disabled by master. + * @retval -EIO General input / output error, failed request to master. + */ +__syscall int espi_saf_flash_unsuccess(const struct device *dev, + struct espi_saf_packet *pckt); + +static inline int z_impl_espi_saf_flash_unsuccess(const struct device *dev, + struct espi_saf_packet *pckt) +{ + const struct espi_saf_driver_api *api = + (const struct espi_saf_driver_api *)dev->api; + + if (!api->flash_unsuccess) { + return -ENOTSUP; + } + + return api->flash_unsuccess(dev, pckt); +} + /** * Callback model * diff --git a/include/zephyr/drivers/ethernet/eth_nxp_enet.h b/include/zephyr/drivers/ethernet/eth_nxp_enet.h new file mode 100644 index 00000000000..767acbea09e --- /dev/null +++ b/include/zephyr/drivers/ethernet/eth_nxp_enet.h @@ -0,0 +1,73 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ +#define ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ + +/* + * This header is for NXP ENET driver development + * and has definitions for internal implementations + * not to be used by application + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Reasons for callback to a driver: + * + * Module reset: The ENET module was reset, perhaps because of power management + * actions, and subdriver should reinitialize part of the module. + * Interrupt: An interrupt of a type relevant to the subdriver occurred. + * Interrupt enable: The driver's relevant interrupt was enabled in NVIC + */ +enum nxp_enet_callback_reason { + NXP_ENET_MODULE_RESET, + NXP_ENET_INTERRUPT, + NXP_ENET_INTERRUPT_ENABLED, +}; + +enum nxp_enet_driver { + NXP_ENET_MAC, + NXP_ENET_MDIO, + NXP_ENET_PTP_CLOCK, +}; + +extern void nxp_enet_mdio_callback(const struct device *mdio_dev, + enum nxp_enet_callback_reason event, + void *data); + +#ifdef CONFIG_PTP_CLOCK_NXP_ENET +extern void nxp_enet_ptp_clock_callback(const struct device *dev, + enum nxp_enet_callback_reason event, + void *data); +#else +#define nxp_enet_ptp_clock_callback(...) +#endif + +/* + * Internal implementation, inter-driver communication function + * + * dev: target device to call back + * dev_type: which driver to call back + * event: reason/cause of callback + * data: opaque data, will be interpreted based on reason and target driver + */ +extern void nxp_enet_driver_cb(const struct device *dev, + enum nxp_enet_driver dev_type, + enum nxp_enet_callback_reason event, + void *data); + +#ifdef __cplusplus +} +#endif + + +#endif /* ZEPHYR_INCLUDE_DRIVERS_ETH_NXP_ENET_H__ */ diff --git a/drivers/gnss/gnss_publish.h b/include/zephyr/drivers/gnss/gnss_publish.h similarity index 100% rename from drivers/gnss/gnss_publish.h rename to include/zephyr/drivers/gnss/gnss_publish.h diff --git a/include/zephyr/drivers/i2c.h b/include/zephyr/drivers/i2c.h index f0268322ecb..70cc0840db7 100644 --- a/include/zephyr/drivers/i2c.h +++ b/include/zephyr/drivers/i2c.h @@ -468,6 +468,18 @@ static inline bool i2c_is_ready_dt(const struct i2c_dt_spec *spec) return device_is_ready(spec->bus); } +/** + * @brief Check if the current message is a read operation + * + * @param msg The message to check + * @return true if the I2C message is sa read operation + * @return false if the I2C message is a write operation + */ +static inline bool i2c_is_read_op(struct i2c_msg *msg) +{ + return (msg->flags & I2C_MSG_READ) == I2C_MSG_READ; +} + /** * @brief Dump out an I2C message * @@ -972,7 +984,7 @@ static inline int i2c_transfer_signal(const struct device *dev, */ static inline void i2c_iodev_submit(struct rtio_iodev_sqe *iodev_sqe) { - const struct i2c_dt_spec *dt_spec = iodev_sqe->sqe->iodev->data; + const struct i2c_dt_spec *dt_spec = (const struct i2c_dt_spec *)iodev_sqe->sqe.iodev->data; const struct device *dev = dt_spec->bus; const struct i2c_driver_api *api = (const struct i2c_driver_api *)dev->api; diff --git a/include/zephyr/drivers/i2c/stm32.h b/include/zephyr/drivers/i2c/stm32.h new file mode 100644 index 00000000000..ac943d74664 --- /dev/null +++ b/include/zephyr/drivers/i2c/stm32.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions GmbH + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ +#define ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ + +#include + +enum i2c_stm32_mode { + I2CSTM32MODE_I2C, + I2CSTM32MODE_SMBUSHOST, + I2CSTM32MODE_SMBUSDEVICE, + I2CSTM32MODE_SMBUSDEVICEARP, +}; + +void i2c_stm32_set_smbus_mode(const struct device *dev, enum i2c_stm32_mode mode); + +#ifdef CONFIG_SMBUS_STM32_SMBALERT +typedef void (*i2c_stm32_smbalert_cb_func_t)(const struct device *dev); + +void i2c_stm32_smbalert_set_callback(const struct device *dev, i2c_stm32_smbalert_cb_func_t func, + const struct device *cb_dev); +void i2c_stm32_smbalert_enable(const struct device *dev); +void i2c_stm32_smbalert_disable(const struct device *dev); +#endif /* CONFIG_SMBUS_STM32_SMBALERT */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_I2C_STM32_H_ */ diff --git a/include/zephyr/drivers/i2c_emul.h b/include/zephyr/drivers/i2c_emul.h index dcbdd1c5496..4c0b86b18f5 100644 --- a/include/zephyr/drivers/i2c_emul.h +++ b/include/zephyr/drivers/i2c_emul.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -42,6 +43,12 @@ struct i2c_emul { /* API provided for this device */ const struct i2c_emul_api *api; + /** + * A mock API that if not NULL will take precedence over the actual API. If set, a return + * value of -ENOSYS will revert back to the default api. + */ + struct i2c_emul_api *mock_api; + /* I2C address of the emulated device */ uint16_t addr; }; diff --git a/include/zephyr/drivers/i3c.h b/include/zephyr/drivers/i3c.h index 36a93fc01de..a814b7d436b 100644 --- a/include/zephyr/drivers/i3c.h +++ b/include/zephyr/drivers/i3c.h @@ -1,5 +1,6 @@ /* * Copyright 2022 Intel Corporation + * Copyright 2023 Meta Platforms, Inc. and its affiliates * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,27 +36,34 @@ extern "C" { * - 1: I3C Controller capable * - 2: Reserved * - 3: Reserved + * . * - BCR[5]: Advanced Capabilities * - 0: Does not support optional advanced capabilities. * - 1: Supports optional advanced capabilities which * can be viewed via GETCAPS CCC. - * - BCR[4}: Virtual Target Support + * . + * - BCR[4]: Virtual Target Support * - 0: Is not a virtual target. * - 1: Is a virtual target. + * . * - BCR[3]: Offline Capable * - 0: Will always response to I3C commands. * - 1: Will not always response to I3C commands. + * . * - BCR[2]: IBI Payload * - 0: No data bytes following the accepted IBI. * - 1: One data byte (MDB, Mandatory Data Byte) follows * the accepted IBI. Additional data bytes may also * follows. + * . * - BCR[1]: IBI Request Capable * - 0: Not capable * - 1: Capable + * . * - BCR[0]: Max Data Speed Limitation * - 0: No Limitation * - 1: Limitation obtained via GETMXDS CCC. + * . * * @{ */ @@ -130,7 +138,7 @@ extern "C" { /** @} */ /** - * @name Device Characteristic Register (DCR) + * @name Legacy Virtual Register (LVR) * * Legacy Virtual Register (LVR) * - LVR[7:5]: I2C device index: @@ -149,26 +157,26 @@ extern "C" { */ /** I2C FM+ Mode. */ -#define I3C_DCR_I2C_FM_PLUS_MODE 0 +#define I3C_LVR_I2C_FM_PLUS_MODE 0 /** I2C FM Mode. */ -#define I3C_DCR_I2C_FM_MODE 1 +#define I3C_LVR_I2C_FM_MODE 1 /** I2C Mode Indicator bit shift value. */ -#define I3C_DCR_I2C_MODE_SHIFT 4 +#define I3C_LVR_I2C_MODE_SHIFT 4 /** I2C Mode Indicator bitmask. */ -#define I3C_DCR_I2C_MODE_MASK BIT(4) +#define I3C_LVR_I2C_MODE_MASK BIT(4) /** * @brief I2C Mode * - * Obtain I2C Mode value from the DCR value obtained via GETDCR. + * Obtain I2C Mode value from the LVR value. * - * @param dcr DCR value + * @param lvr LVR value */ -#define I3C_DCR_I2C_MODE(dcr) \ - (((mode) & I3C_DCR_I2C_MODE_MASK) >> I3C_DCR_I2C_MODE_SHIFT) +#define I3C_LVR_I2C_MODE(lvr) \ + (((lvr) & I3C_LVR_I2C_MODE_MASK) >> I3C_LVR_I2C_MODE_SHIFT) /** * @brief I2C Device Index 0. @@ -176,7 +184,7 @@ extern "C" { * I2C device has a 50 ns spike filter where it is not affected by high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_0 0 +#define I3C_LVR_I2C_DEV_IDX_0 0 /** * @brief I2C Device Index 1. @@ -184,7 +192,7 @@ extern "C" { * I2C device does not have a 50 ns spike filter but can work with high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_1 1 +#define I3C_LVR_I2C_DEV_IDX_1 1 /** * @brief I2C Device Index 2. @@ -192,23 +200,23 @@ extern "C" { * I2C device does not have a 50 ns spike filter and cannot work with high * frequency on SCL. */ -#define I3C_DCR_I2C_DEV_IDX_2 2 +#define I3C_LVR_I2C_DEV_IDX_2 2 /** I2C Device Index bit shift value. */ -#define I3C_DCR_I2C_DEV_IDX_SHIFT 5 +#define I3C_LVR_I2C_DEV_IDX_SHIFT 5 /** I2C Device Index bitmask. */ -#define I3C_DCR_I2C_DEV_IDX_MASK (0x07U << I3C_DCR_I2C_DEV_IDX_SHIFT) +#define I3C_LVR_I2C_DEV_IDX_MASK (0x07U << I3C_LVR_I2C_DEV_IDX_SHIFT) /** * @brief I2C Device Index * - * Obtain I2C Device Index value from the DCR value obtained via GETDCR. + * Obtain I2C Device Index value from the LVR value. * - * @param dcr DCR value + * @param lvr LVR value */ -#define I3C_DCR_I2C_DEV_IDX(dcr) \ - (((dcr) & I3C_DCR_I2C_DEV_IDX_MASK) >> I3C_DCR_I2C_DEV_IDX_SHIFT) +#define I3C_LVR_I2C_DEV_IDX(lvr) \ + (((lvr) & I3C_LVR_I2C_DEV_IDX_MASK) >> I3C_LVR_I2C_DEV_IDX_SHIFT) /** @} */ @@ -469,6 +477,15 @@ struct i3c_msg { /** Length of buffer in bytes */ uint32_t len; + /** + * Total number of bytes transferred + * + * A Target can issue an EoD or the Controller can abort a transfer + * before the length of the buffer. It is expected for the driver to + * write to this after the transfer. + */ + uint32_t num_xfer; + /** Flags for this message */ uint8_t flags; diff --git a/include/zephyr/drivers/i3c/ccc.h b/include/zephyr/drivers/i3c/ccc.h index 606d44f79ae..116750bcac5 100644 --- a/include/zephyr/drivers/i3c/ccc.h +++ b/include/zephyr/drivers/i3c/ccc.h @@ -1,5 +1,6 @@ /* * Copyright 2022 Intel Corporation + * Copyright 2023 Meta Platforms, Inc. and its affiliates * * SPDX-License-Identifier: Apache-2.0 */ @@ -248,6 +249,15 @@ struct i3c_ccc_target_payload { /** Length in bytes for @p data. */ size_t data_len; + + /** + * Total number of bytes transferred + * + * A Target can issue an EoD or the Controller can abort a transfer + * before the length of the buffer. It is expected for the driver to + * write to this after the transfer. + */ + size_t num_xfer; }; /** @@ -270,6 +280,14 @@ struct i3c_ccc_payload { /** Length in bytes for optional data array. */ size_t data_len; + + /** + * Total number of bytes transferred + * + * A Controller can abort a transfer before the length of the buffer. + * It is expected for the driver to write to this after the transfer. + */ + size_t num_xfer; } ccc; struct { diff --git a/include/zephyr/drivers/interrupt_controller/exti_stm32.h b/include/zephyr/drivers/interrupt_controller/exti_stm32.h index 2bd41415983..0bd808f921c 100644 --- a/include/zephyr/drivers/interrupt_controller/exti_stm32.h +++ b/include/zephyr/drivers/interrupt_controller/exti_stm32.h @@ -49,7 +49,7 @@ enum stm32_exti_trigger { STM32_EXTI_TRIG_RISING = 0x1, /* trigger on falling edge */ STM32_EXTI_TRIG_FALLING = 0x2, - /* trigger on falling edge */ + /* trigger on both rising & falling edge */ STM32_EXTI_TRIG_BOTH = 0x3, }; diff --git a/include/zephyr/drivers/interrupt_controller/intc_esp32.h b/include/zephyr/drivers/interrupt_controller/intc_esp32.h index 6c489723d7e..c1e86068ad3 100644 --- a/include/zephyr/drivers/interrupt_controller/intc_esp32.h +++ b/include/zephyr/drivers/interrupt_controller/intc_esp32.h @@ -249,7 +249,7 @@ int esp_intr_get_intno(struct intr_handle_data_t *handle); * @brief Disable the interrupt associated with the handle * * @note - * 1. For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the + * 1. For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the * CPU the interrupt is allocated on. Other interrupts have no such restriction. * 2. When several handlers sharing a same interrupt source, interrupt status bits, which are * handled in the handler to be disabled, should be masked before the disabling, or handled @@ -266,7 +266,7 @@ int esp_intr_disable(struct intr_handle_data_t *handle); /** * @brief Enable the interrupt associated with the handle * - * @note For local interrupts (ESP_INTERNAL_* sources), this function has to be called on the + * @note For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the * CPU the interrupt is allocated on. Other interrupts have no such restriction. * * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus diff --git a/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h b/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h index fcbef647d29..d347d81cad8 100644 --- a/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h +++ b/include/zephyr/drivers/interrupt_controller/intc_ra_icu.h @@ -35,4 +35,8 @@ extern int ra_icu_irq_connect_dynamic(unsigned int irq, unsigned int priority, void (*routine)(const void *parameter), const void *parameter, uint32_t flags); +extern int ra_icu_irq_disconnect_dynamic(unsigned int irq, unsigned int priority, + void (*routine)(const void *parameter), + const void *parameter, uint32_t flags); + #endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RA_ICU_H_ */ diff --git a/include/zephyr/drivers/led.h b/include/zephyr/drivers/led.h index b9dd8cc2775..cb178a9442d 100644 --- a/include/zephyr/drivers/led.h +++ b/include/zephyr/drivers/led.h @@ -32,16 +32,15 @@ extern "C" { * @brief LED information structure * * This structure gathers useful information about LED controller. - * - * @param label LED label. - * @param num_colors Number of colors per LED. - * @param index Index of the LED on the controller. - * @param color_mapping Mapping of the LED colors. */ struct led_info { + /** LED label */ const char *label; + /** Number of colors per LED */ uint32_t index; + /** Index of the LED on the controller */ uint8_t num_colors; + /** Mapping of the LED colors */ const uint8_t *color_mapping; }; diff --git a/include/zephyr/drivers/mdio.h b/include/zephyr/drivers/mdio.h index 1d030c0f586..9ee8deebd41 100644 --- a/include/zephyr/drivers/mdio.h +++ b/include/zephyr/drivers/mdio.h @@ -21,6 +21,7 @@ */ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/drivers/mipi_dbi.h b/include/zephyr/drivers/mipi_dbi.h new file mode 100644 index 00000000000..5dca3d6f659 --- /dev/null +++ b/include/zephyr/drivers/mipi_dbi.h @@ -0,0 +1,265 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for MIPI-DBI drivers + * + * MIPI-DBI defines the following 3 interfaces: + * Type A: Motorola 6800 type parallel bus + * Type B: Intel 8080 type parallel bus + * Type C: SPI Type (1 bit bus) with 3 options: + * 1. 9 write clocks per byte, final bit is command/data selection bit + * 2. Same as above, but 16 write clocks per byte + * 3. 8 write clocks per byte. Command/data selected via GPIO pin + * The current driver interface only supports type C modes 1 and 3 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ +#define ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ + +/** + * @brief MIPI-DBI driver APIs + * @defgroup mipi_dbi_interface MIPI-DBI driver APIs + * @ingroup io_interfaces + * @{ + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SPI 3 wire (Type C1). Uses 9 write clocks to send a byte of data. + * The bit sent on the 9th clock indicates whether the byte is a + * command or data byte + * + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT |D/C| D7| D6| D5| D4| D3| D2| D1| D0|D/C| D7| D6| D5| D4|...| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '-----------------------------------------------------------' + */ +#define MIPI_DBI_MODE_SPI_3WIRE 0x1 +/** + * SPI 4 wire (Type C3). Uses 8 write clocks to send a byte of data. + * an additional C/D pin will be use to indicate whether the byte is a + * command or data byte + * + * .---. .---. .---. .---. .---. .---. .---. .---. + * SCK -' '---' '---' '---' '---' '---' '---' '---' '--- + * + * -.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---. + * DOUT | D7| D6| D5| D4| D3| D2| D1| D0| D7| D6| D5| D4| D3| D2| D1| D0| + * -'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---' + * | Word 1 | Word n + * + * -. .-- + * CS '---------------------------------------------------------------' + * + * -.-------------------------------.-------------------------------.- + * CD | D/C | D/C | + * -'-------------------------------'-------------------------------'- + */ +#define MIPI_DBI_MODE_SPI_4WIRE 0x2 + +/** + * @brief initialize a MIPI DBI SPI configuration struct from devicetree + * + * This helper allows drivers to initialize a MIPI DBI SPI configuration + * structure using devicetree. + * @param node_id Devicetree node identifier for the MIPI DBI device whose + * struct spi_config to create an initializer for + * @param operation_ the desired operation field in the struct spi_config + * @param delay_ the desired delay field in the struct spi_config's + * spi_cs_control, if there is one + */ +#define MIPI_DBI_SPI_CONFIG_DT(node_id, operation_, delay_) \ + { \ + .frequency = DT_PROP(node_id, mipi_max_frequency), \ + .operation = (operation_) | \ + DT_PROP(node_id, duplex), \ + COND_CODE_1(DT_PROP(node_id, mipi_cpol), SPI_MODE_CPOL, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_cpha), SPI_MODE_CPHA, (0)) | \ + COND_CODE_1(DT_PROP(node_id, mipi_hold_cs), SPI_HOLD_ON_CS, (0)), \ + .slave = DT_REG_ADDR(node_id), \ + .cs = { \ + .gpio = GPIO_DT_SPEC_GET_BY_IDX_OR(DT_PHANDLE(DT_PARENT(node_id), \ + spi_dev), cs_gpios, \ + DT_REG_ADDR(node_id), \ + {}), \ + .delay = (delay_), \ + }, \ + } + +/** + * @brief MIPI DBI controller configuration + * + * Configuration for MIPI DBI controller write + */ +struct mipi_dbi_config { + /** MIPI DBI mode (SPI 3 wire or 4 wire) */ + uint8_t mode; + /** SPI configuration */ + struct spi_config config; +}; + + +/** MIPI-DBI host driver API */ +__subsystem struct mipi_dbi_driver_api { + int (*command_write)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t cmd, + const uint8_t *data, size_t len); + int (*command_read)(const struct device *dev, + const struct mipi_dbi_config *config, uint8_t *cmds, + size_t num_cmds, uint8_t *response, size_t len); + int (*write_display)(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt); + int (*reset)(const struct device *dev, uint32_t delay); +}; + +/** + * @brief Write a command to the display controller + * + * Writes a command, along with an optional data buffer to the display. + * If data buffer and buffer length are NULL and 0 respectively, then + * only a command will be sent. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmd command to write to display controller + * @param data optional data buffer to write after command + * @param len size of data buffer in bytes. Set to 0 to skip sending data. + * @retval 0 command write succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_write(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t cmd, const uint8_t *data, + size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_write == NULL) { + return -ENOSYS; + } + return api->command_write(dev, config, cmd, data, len); +} + +/** + * @brief Read a command response from the display controller + * + * Reads a command response from the display controller. + * + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param cmds array of one byte commands to send to display controller + * @param num_cmd number of commands to write to display controller + * @param response response buffer, filled with display controller response + * @param len size of response buffer in bytes. + * @retval 0 command read succeeded + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_command_read(const struct device *dev, + const struct mipi_dbi_config *config, + uint8_t *cmds, size_t num_cmd, + uint8_t *response, size_t len) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->command_read == NULL) { + return -ENOSYS; + } + return api->command_read(dev, config, cmds, num_cmd, response, len); +} + +/** + * @brief Write a display buffer to the display controller. + * + * Writes a display buffer to the controller. If the controller requires + * a "Write memory" command before writing display data, this should be + * sent with @ref mipi_dbi_command_write + * @param dev mipi dbi controller + * @param config MIPI DBI configuration + * @param framebuf: framebuffer to write to display + * @param desc: descriptor of framebuffer to write. Note that the pitch must + * be equal to width. "buf_size" field determines how many bytes will be + * written. + * @param pixfmt: pixel format of framebuffer data + * @retval 0 buffer write succeeded. + * @retval -EIO I/O error + * @retval -ETIMEDOUT transfer timed out + * @retval -EBUSY controller is busy + * @retval -ENOSYS not implemented + */ +static inline int mipi_dbi_write_display(const struct device *dev, + const struct mipi_dbi_config *config, + const uint8_t *framebuf, + struct display_buffer_descriptor *desc, + enum display_pixel_format pixfmt) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->write_display == NULL) { + return -ENOSYS; + } + return api->write_display(dev, config, framebuf, desc, pixfmt); +} + +/** + * @brief Resets attached display controller + * + * Resets the attached display controller. + * @param dev mipi dbi controller + * @param delay duration to set reset signal for, in milliseconds + * @retval 0 reset succeeded + * @retval -EIO I/O error + * @retval -ENOSYS not implemented + * @retval -ENOTSUP not supported + */ +static inline int mipi_dbi_reset(const struct device *dev, uint32_t delay) +{ + const struct mipi_dbi_driver_api *api = + (const struct mipi_dbi_driver_api *)dev->api; + + if (api->reset == NULL) { + return -ENOSYS; + } + return api->reset(dev, delay); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_MIPI_DBI_H_ */ diff --git a/include/zephyr/drivers/mipi_dsi.h b/include/zephyr/drivers/mipi_dsi.h index e6ac1e0a787..f26a6928196 100644 --- a/include/zephyr/drivers/mipi_dsi.h +++ b/include/zephyr/drivers/mipi_dsi.h @@ -21,139 +21,13 @@ #include #include #include +#include #include #ifdef __cplusplus extern "C" { #endif -/** - * @name MIPI-DSI DCS (Display Command Set) - * @{ - */ - -#define MIPI_DCS_NOP 0x00U -#define MIPI_DCS_SOFT_RESET 0x01U -#define MIPI_DCS_GET_COMPRESSION_MODE 0x03U -#define MIPI_DCS_GET_DISPLAY_ID 0x04U -#define MIPI_DCS_GET_RED_CHANNEL 0x06U -#define MIPI_DCS_GET_GREEN_CHANNEL 0x07U -#define MIPI_DCS_GET_BLUE_CHANNEL 0x08U -#define MIPI_DCS_GET_DISPLAY_STATUS 0x09U -#define MIPI_DCS_GET_POWER_MODE 0x0AU -#define MIPI_DCS_GET_ADDRESS_MODE 0x0BU -#define MIPI_DCS_GET_PIXEL_FORMAT 0x0CU -#define MIPI_DCS_GET_DISPLAY_MODE 0x0DU -#define MIPI_DCS_GET_SIGNAL_MODE 0x0EU -#define MIPI_DCS_GET_DIAGNOSTIC_RESULT 0x0FU -#define MIPI_DCS_ENTER_SLEEP_MODE 0x10U -#define MIPI_DCS_EXIT_SLEEP_MODE 0x11U -#define MIPI_DCS_ENTER_PARTIAL_MODE 0x12U -#define MIPI_DCS_ENTER_NORMAL_MODE 0x13U -#define MIPI_DCS_EXIT_INVERT_MODE 0x20U -#define MIPI_DCS_ENTER_INVERT_MODE 0x21U -#define MIPI_DCS_SET_GAMMA_CURVE 0x26U -#define MIPI_DCS_SET_DISPLAY_OFF 0x28U -#define MIPI_DCS_SET_DISPLAY_ON 0x29U -#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2AU -#define MIPI_DCS_SET_PAGE_ADDRESS 0x2BU -#define MIPI_DCS_WRITE_MEMORY_START 0x2CU -#define MIPI_DCS_WRITE_LUT 0x2DU -#define MIPI_DCS_READ_MEMORY_START 0x2EU -#define MIPI_DCS_SET_PARTIAL_ROWS 0x30U -#define MIPI_DCS_SET_PARTIAL_COLUMNS 0x31U -#define MIPI_DCS_SET_SCROLL_AREA 0x33U -#define MIPI_DCS_SET_TEAR_OFF 0x34U -#define MIPI_DCS_SET_TEAR_ON 0x35U -#define MIPI_DCS_SET_ADDRESS_MODE 0x36U -#define MIPI_DCS_SET_SCROLL_START 0x37U -#define MIPI_DCS_EXIT_IDLE_MODE 0x38U -#define MIPI_DCS_ENTER_IDLE_MODE 0x39U -#define MIPI_DCS_SET_PIXEL_FORMAT 0x3AU -#define MIPI_DCS_WRITE_MEMORY_CONTINUE 0x3CU -#define MIPI_DCS_SET_3D_CONTROL 0x3DU -#define MIPI_DCS_READ_MEMORY_CONTINUE 0x3EU -#define MIPI_DCS_GET_3D_CONTROL 0x3FU -#define MIPI_DCS_SET_VSYNC_TIMING 0x40U -#define MIPI_DCS_SET_TEAR_SCANLINE 0x44U -#define MIPI_DCS_GET_SCANLINE 0x45U -#define MIPI_DCS_SET_DISPLAY_BRIGHTNESS 0x51U -#define MIPI_DCS_GET_DISPLAY_BRIGHTNESS 0x52U -#define MIPI_DCS_WRITE_CONTROL_DISPLAY 0x53U -#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54U -#define MIPI_DCS_WRITE_POWER_SAVE 0x55U -#define MIPI_DCS_GET_POWER_SAVE 0x56U -#define MIPI_DCS_SET_CABC_MIN_BRIGHTNESS 0x5EU -#define MIPI_DCS_GET_CABC_MIN_BRIGHTNESS 0x5FU -#define MIPI_DCS_READ_DDB_START 0xA1U -#define MIPI_DCS_READ_DDB_CONTINUE 0xA8U - -#define MIPI_DCS_PIXEL_FORMAT_24BIT 0x77 -#define MIPI_DCS_PIXEL_FORMAT_18BIT 0x66 -#define MIPI_DCS_PIXEL_FORMAT_16BIT 0x55 -#define MIPI_DCS_PIXEL_FORMAT_12BIT 0x33 -#define MIPI_DCS_PIXEL_FORMAT_8BIT 0x22 -#define MIPI_DCS_PIXEL_FORMAT_3BIT 0x11 - -/** @} */ - -/** - * @name MIPI-DSI Address mode register fields. - * @{ - */ - -#define MIPI_DCS_ADDRESS_MODE_MIRROR_Y BIT(7) -#define MIPI_DCS_ADDRESS_MODE_MIRROR_X BIT(6) -#define MIPI_DCS_ADDRESS_MODE_SWAP_XY BIT(5) -#define MIPI_DCS_ADDRESS_MODE_REFRESH_BT BIT(4) -#define MIPI_DCS_ADDRESS_MODE_BGR BIT(3) -#define MIPI_DCS_ADDRESS_MODE_LATCH_RL BIT(2) -#define MIPI_DCS_ADDRESS_MODE_FLIP_X BIT(1) -#define MIPI_DCS_ADDRESS_MODE_FLIP_Y BIT(0) - -/** @} */ - -/** - * @name MIPI-DSI Processor-to-Peripheral transaction types. - * @{ - */ - -#define MIPI_DSI_V_SYNC_START 0x01U -#define MIPI_DSI_V_SYNC_END 0x11U -#define MIPI_DSI_H_SYNC_START 0x21U -#define MIPI_DSI_H_SYNC_END 0x31U -#define MIPI_DSI_COLOR_MODE_OFF 0x02U -#define MIPI_DSI_COLOR_MODE_ON 0x12U -#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22U -#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32U -#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03U -#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13U -#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23U -#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04U -#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14U -#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24U -#define MIPI_DSI_DCS_SHORT_WRITE 0x05U -#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15U -#define MIPI_DSI_DCS_READ 0x06U -#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37U -#define MIPI_DSI_END_OF_TRANSMISSION 0x08U -#define MIPI_DSI_NULL_PACKET 0x09U -#define MIPI_DSI_BLANKING_PACKET 0x19U -#define MIPI_DSI_GENERIC_LONG_WRITE 0x29U -#define MIPI_DSI_DCS_LONG_WRITE 0x39U -#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2CU -#define MIPI_DSI_PACKED_PIXEL_STREAM_30 0x0DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_36 0x1DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 0x3DU -#define MIPI_DSI_PACKED_PIXEL_STREAM_16 0x0EU -#define MIPI_DSI_PACKED_PIXEL_STREAM_18 0x1EU -#define MIPI_DSI_PIXEL_STREAM_3BYTE_18 0x2EU -#define MIPI_DSI_PACKED_PIXEL_STREAM_24 0x3EU - -/** @} */ - /** MIPI-DSI display timings. */ struct mipi_dsi_timings { /** Horizontal active video. */ diff --git a/include/zephyr/drivers/misc/devmux/devmux.h b/include/zephyr/drivers/misc/devmux/devmux.h new file mode 100644 index 00000000000..1772d719d96 --- /dev/null +++ b/include/zephyr/drivers/misc/devmux/devmux.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public APIs for the Device Multiplexer driver + */ + +#ifndef INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ +#define INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Devmux Driver APIs + * @defgroup demux_interface Devmux Driver APIs + * @ingroup misc_interfaces + * + * @details + * Devmux operates as a device multiplexer, forwarding the characteristics of + * the selected device. + * + * ``` + * +----------+ +----------+ + * | devmux | | devmux | + * | | | | + * dev0 | | dev0 | | + * +----------> \ | +----------> | + * | \ | | | + * dev1 | \ | dev0 dev1 | | dev2 + * +----------> O +----------> +----------> O +----------> + * | | | / | + * dev2 | | dev2 | / | + * +----------> | +----------> / | + * | | | | + * | | | | + * | | | | + * +-----^----+ +-----^----+ + * | | + * select == 0 | select == 2 | + * +--------------+ +---------------+ + * ``` + * @{ + */ + +/** + * @brief Get the current selection of a devmux device. + * + * Return the index of the currently selected device. + * + * @param dev the devmux device + * @return The index (>= 0) of the currently active multiplexed device on success + * @retval -EINVAL If @p dev is invalid + */ +__syscall ssize_t devmux_select_get(const struct device *dev); + +/** + * @brief Set the selection of a devmux device. + * + * Select the device at @p index. + * + * @param[in] dev the devmux device + * @param index the index representing the desired selection + * @retval 0 On success + * @retval -EINVAL If @p dev is invalid + * @retval -ENODEV If the multiplexed device at @p index is not ready + */ +__syscall int devmux_select_set(struct device *dev, size_t index); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* INCLUDE_ZEPHYR_DRIVERS_MISC_DEVMUX_H_ */ diff --git a/include/zephyr/drivers/pinctrl.h b/include/zephyr/drivers/pinctrl.h index b0fd60e891b..e03456c76c3 100644 --- a/include/zephyr/drivers/pinctrl.h +++ b/include/zephyr/drivers/pinctrl.h @@ -76,8 +76,8 @@ struct pinctrl_dev_config { /** @cond INTERNAL_HIDDEN */ -#ifndef CONFIG_PM_DEVICE -/** If device power management is not enabled, "sleep" state will be ignored. */ +#if !defined(CONFIG_PM) && !defined(CONFIG_PM_DEVICE) +/** Out of power management configurations, ignore "sleep" state. */ #define PINCTRL_SKIP_SLEEP 1 #endif diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index bad9de28239..77e441d0dae 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -3,6 +3,7 @@ * Copyright (c) 2021 NXP * Copyright (c) 2022 Nordic Semiconductor ASA * Copyright (c) 2023 EPAM Systems + * Copyright (c) 2023 Meta Platforms * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +88,10 @@ typedef int (*regulator_set_mode_t)(const struct device *dev, regulator_mode_t mode); typedef int (*regulator_get_mode_t)(const struct device *dev, regulator_mode_t *mode); +typedef int (*regulator_set_active_discharge_t)(const struct device *dev, + bool active_discharge); +typedef int (*regulator_get_active_discharge_t)(const struct device *dev, + bool *active_discharge); typedef int (*regulator_get_error_flags_t)( const struct device *dev, regulator_error_flags_t *flags); @@ -104,6 +109,8 @@ __subsystem struct regulator_driver_api { regulator_get_current_limit_t get_current_limit; regulator_set_mode_t set_mode; regulator_get_mode_t get_mode; + regulator_set_active_discharge_t set_active_discharge; + regulator_get_active_discharge_t get_active_discharge; regulator_get_error_flags_t get_error_flags; }; @@ -113,11 +120,27 @@ __subsystem struct regulator_driver_api { * @{ */ /** Indicates regulator must stay always ON */ -#define REGULATOR_ALWAYS_ON BIT(0) +#define REGULATOR_ALWAYS_ON BIT(0) /** Indicates regulator must be initialized ON */ -#define REGULATOR_BOOT_ON BIT(1) +#define REGULATOR_BOOT_ON BIT(1) /** Indicates if regulator must be enabled when initialized */ -#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON) +#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON) +/** Regulator active discharge state mask */ +#define REGULATOR_ACTIVE_DISCHARGE_MASK GENMASK(3, 2) +/** Regulator active discharge state flag position*/ +#define REGULATOR_ACTIVE_DISCHARGE_POS 2 +/** Disable regulator active discharge */ +#define REGULATOR_ACTIVE_DISCHARGE_DISABLE 0 +/** Enable regulator active discharge */ +#define REGULATOR_ACTIVE_DISCHARGE_ENABLE 1 +/** Leave regulator active discharge state as default */ +#define REGULATOR_ACTIVE_DISCHARGE_DEFAULT 2 +/** Regulator active discharge set bits */ +#define REGULATOR_ACTIVE_DISCHARGE_SET_BITS(x) \ + (((x) << REGULATOR_ACTIVE_DISCHARGE_POS) & REGULATOR_ACTIVE_DISCHARGE_MASK) +/** Regulator active discharge get bits */ +#define REGULATOR_ACTIVE_DISCHARGE_GET_BITS(x) \ + (((x) & REGULATOR_ACTIVE_DISCHARGE_MASK) >> REGULATOR_ACTIVE_DISCHARGE_POS) /** @} */ @@ -140,6 +163,8 @@ struct regulator_common_config { int32_t min_ua; /** Maximum allowed current, in microamps. */ int32_t max_ua; + /** Initial current, in microamps. */ + int32_t init_ua; /** Startup delay, in microseconds. */ uint32_t startup_delay_us; /** Off to on delay, in microseconds. */ @@ -171,6 +196,8 @@ struct regulator_common_config { INT32_MIN), \ .max_ua = DT_PROP_OR(node_id, regulator_max_microamp, \ INT32_MAX), \ + .init_ua = DT_PROP_OR(node_id, regulator_init_microamp, \ + INT32_MIN), \ .startup_delay_us = DT_PROP_OR(node_id, startup_delay_us, 0), \ .off_on_delay_us = DT_PROP_OR(node_id, off_on_delay_us, 0), \ .allowed_modes = (const regulator_mode_t []) \ @@ -182,7 +209,10 @@ struct regulator_common_config { .flags = ((DT_PROP_OR(node_id, regulator_always_on, 0U) * \ REGULATOR_ALWAYS_ON) | \ (DT_PROP_OR(node_id, regulator_boot_on, 0U) * \ - REGULATOR_BOOT_ON)), \ + REGULATOR_BOOT_ON) | \ + (REGULATOR_ACTIVE_DISCHARGE_SET_BITS( \ + DT_PROP_OR(node_id, regulator_active_discharge, \ + REGULATOR_ACTIVE_DISCHARGE_DEFAULT)))), \ } /** @@ -631,6 +661,52 @@ static inline int regulator_get_mode(const struct device *dev, return api->get_mode(dev, mode); } +/** + * @brief Set active discharge setting. + * + * @param dev Regulator device instance. + * @param active_discharge Active discharge enable or disable. + * + * @retval 0 If successful. + * @retval -ENOSYS If function is not implemented. + * @retval -errno In case of any other error. + */ +static inline int regulator_set_active_discharge(const struct device *dev, + bool active_discharge) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->set_active_discharge == NULL) { + return -ENOSYS; + } + + return api->set_active_discharge(dev, active_discharge); +} + +/** + * @brief Get active discharge setting. + * + * @param dev Regulator device instance. + * @param[out] active_discharge Where active discharge will be stored. + * + * @retval 0 If successful. + * @retval -ENOSYS If function is not implemented. + * @retval -errno In case of any other error. + */ +static inline int regulator_get_active_discharge(const struct device *dev, + bool *active_discharge) +{ + const struct regulator_driver_api *api = + (const struct regulator_driver_api *)dev->api; + + if (api->get_active_discharge == NULL) { + return -ENOSYS; + } + + return api->get_active_discharge(dev, active_discharge); +} + /** * @brief Get active error flags. * diff --git a/include/zephyr/drivers/regulator/fake.h b/include/zephyr/drivers/regulator/fake.h index 1bfffe6381b..d91161dbc7a 100644 --- a/include/zephyr/drivers/regulator/fake.h +++ b/include/zephyr/drivers/regulator/fake.h @@ -31,6 +31,10 @@ DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *, regulator_mode_t); DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *, regulator_mode_t *); +DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *, + bool); +DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *, + bool *); DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags, const struct device *, regulator_error_flags_t *); diff --git a/include/zephyr/drivers/rtc/maxim_ds3231.h b/include/zephyr/drivers/rtc/maxim_ds3231.h index 6e9a4a1cb39..2e8b9fe60ec 100644 --- a/include/zephyr/drivers/rtc/maxim_ds3231.h +++ b/include/zephyr/drivers/rtc/maxim_ds3231.h @@ -15,7 +15,7 @@ * * The core Zephyr API to this device is as a counter, with the * following limitations: - * * counter_read() and counter_*_alarm() cannot be invoked from + * * ``counter_read()`` and ``counter_*_alarm()`` cannot be invoked from * interrupt context, as they require communication with the device * over an I2C bus. * * many other counter APIs, such as start/stop/set_top_value are not diff --git a/include/zephyr/drivers/sensor.h b/include/zephyr/drivers/sensor.h index e652c3a2040..53d55e1f1a3 100644 --- a/include/zephyr/drivers/sensor.h +++ b/include/zephyr/drivers/sensor.h @@ -418,7 +418,7 @@ typedef int (*sensor_channel_get_t)(const struct device *dev, * @brief Decodes a single raw data buffer * * Data buffers are provided on the @ref rtio context that's supplied to - * c:func:`sensor_read`. + * @ref sensor_read. */ struct sensor_decoder_api { /** @@ -1353,6 +1353,46 @@ static inline int64_t sensor_value_to_micro(const struct sensor_value *val) return ((int64_t)val->val1 * 1000000) + val->val2; } +/** + * @brief Helper function for converting integer milli units to struct sensor_value. + * + * @param val A pointer to a sensor_value struct. + * @param milli The converted value. + * @return 0 if successful, negative errno code if failure. + */ +static inline int sensor_value_from_milli(struct sensor_value *val, int64_t milli) +{ + if (milli < ((int64_t)INT32_MIN - 1) * 1000LL || + milli > ((int64_t)INT32_MAX + 1) * 1000LL) { + return -ERANGE; + } + + val->val1 = (int32_t)(milli / 1000); + val->val2 = (int32_t)(milli % 1000) * 1000; + + return 0; +} + +/** + * @brief Helper function for converting integer micro units to struct sensor_value. + * + * @param val A pointer to a sensor_value struct. + * @param micro The converted value. + * @return 0 if successful, negative errno code if failure. + */ +static inline int sensor_value_from_micro(struct sensor_value *val, int64_t micro) +{ + if (micro < ((int64_t)INT32_MIN - 1) * 1000000LL || + micro > ((int64_t)INT32_MAX + 1) * 1000000LL) { + return -ERANGE; + } + + val->val1 = (int32_t)(micro / 1000000LL); + val->val2 = (int32_t)(micro % 1000000LL); + + return 0; +} + /** * @} */ diff --git a/include/zephyr/drivers/sensor/bmp581_user.h b/include/zephyr/drivers/sensor/bmp581_user.h new file mode 100644 index 00000000000..e0fd000c8c0 --- /dev/null +++ b/include/zephyr/drivers/sensor/bmp581_user.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022 Badgerd Technologies B.V. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Driver is developed to be used with Zephyr. And it only supports i2c interface. + * + * Author: Talha Can Havadar + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ + +#include + +#define BMP5_SEA_LEVEL_PRESSURE_PA 101325 + +/* ODR settings */ +#define BMP5_ODR_240_HZ 0x00 +#define BMP5_ODR_218_5_HZ 0x01 +#define BMP5_ODR_199_1_HZ 0x02 +#define BMP5_ODR_179_2_HZ 0x03 +#define BMP5_ODR_160_HZ 0x04 +#define BMP5_ODR_149_3_HZ 0x05 +#define BMP5_ODR_140_HZ 0x06 +#define BMP5_ODR_129_8_HZ 0x07 +#define BMP5_ODR_120_HZ 0x08 +#define BMP5_ODR_110_1_HZ 0x09 +#define BMP5_ODR_100_2_HZ 0x0A +#define BMP5_ODR_89_6_HZ 0x0B +#define BMP5_ODR_80_HZ 0x0C +#define BMP5_ODR_70_HZ 0x0D +#define BMP5_ODR_60_HZ 0x0E +#define BMP5_ODR_50_HZ 0x0F +#define BMP5_ODR_45_HZ 0x10 +#define BMP5_ODR_40_HZ 0x11 +#define BMP5_ODR_35_HZ 0x12 +#define BMP5_ODR_30_HZ 0x13 +#define BMP5_ODR_25_HZ 0x14 +#define BMP5_ODR_20_HZ 0x15 +#define BMP5_ODR_15_HZ 0x16 +#define BMP5_ODR_10_HZ 0x17 +#define BMP5_ODR_05_HZ 0x18 +#define BMP5_ODR_04_HZ 0x19 +#define BMP5_ODR_03_HZ 0x1A +#define BMP5_ODR_02_HZ 0x1B +#define BMP5_ODR_01_HZ 0x1C +#define BMP5_ODR_0_5_HZ 0x1D +#define BMP5_ODR_0_250_HZ 0x1E +#define BMP5_ODR_0_125_HZ 0x1F + +/* Oversampling for temperature and pressure */ +#define BMP5_OVERSAMPLING_1X 0x00 +#define BMP5_OVERSAMPLING_2X 0x01 +#define BMP5_OVERSAMPLING_4X 0x02 +#define BMP5_OVERSAMPLING_8X 0x03 +#define BMP5_OVERSAMPLING_16X 0x04 +#define BMP5_OVERSAMPLING_32X 0x05 +#define BMP5_OVERSAMPLING_64X 0x06 +#define BMP5_OVERSAMPLING_128X 0x07 + +/* IIR filter for temperature and pressure */ +#define BMP5_IIR_FILTER_BYPASS 0x00 +#define BMP5_IIR_FILTER_COEFF_1 0x01 +#define BMP5_IIR_FILTER_COEFF_3 0x02 +#define BMP5_IIR_FILTER_COEFF_7 0x03 +#define BMP5_IIR_FILTER_COEFF_15 0x04 +#define BMP5_IIR_FILTER_COEFF_31 0x05 +#define BMP5_IIR_FILTER_COEFF_63 0x06 +#define BMP5_IIR_FILTER_COEFF_127 0x07 + +/* Custom ATTR values */ + +/* This is used to enable IIR config, + * keep in mind that disabling IIR back in runtime is not + * supported yet + */ +#define BMP5_ATTR_IIR_CONFIG (SENSOR_ATTR_PRIV_START + 1u) +#define BMP5_ATTR_POWER_MODE (SENSOR_ATTR_PRIV_START + 2u) + +enum bmp5_powermode { + /*! Standby powermode */ + BMP5_POWERMODE_STANDBY, + /*! Normal powermode */ + BMP5_POWERMODE_NORMAL, + /*! Forced powermode */ + BMP5_POWERMODE_FORCED, + /*! Continuous powermode */ + BMP5_POWERMODE_CONTINUOUS, + /*! Deep standby powermode */ + BMP5_POWERMODE_DEEP_STANDBY +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_BMP581_USER_H_ */ diff --git a/include/zephyr/drivers/sensor/max31865.h b/include/zephyr/drivers/sensor/max31865.h new file mode 100644 index 00000000000..901637379bf --- /dev/null +++ b/include/zephyr/drivers/sensor/max31865.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 SILA Embedded Solutions + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _MAX31865_PUB_H +#define _MAX31865_PUB_H + +#define SENSOR_ATTR_MAX31865_THREE_WIRE SENSOR_ATTR_PRIV_START + +#endif /* _MAX31865_PUB_H */ diff --git a/include/zephyr/drivers/sensor/veml7700.h b/include/zephyr/drivers/sensor/veml7700.h index 05bcca14252..c2a716ed663 100644 --- a/include/zephyr/drivers/sensor/veml7700.h +++ b/include/zephyr/drivers/sensor/veml7700.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023 Andreas Kilian + * Copyright (c) 2024 Jeff Welder (Ellenby Technologies, Inc.) * * SPDX-License-Identifier: Apache-2.0 */ @@ -134,6 +135,15 @@ enum sensor_channel_veml7700 { */ SENSOR_CHAN_VEML7700_RAW_COUNTS = SENSOR_CHAN_PRIV_START, + /** + * @brief Channel for white light sensor values. + * + * This channel is the White Channel count output of the sensor. + * The white channel can be used to correct for light sources with + * strong infrared content in the 750-800nm spectrum. + */ + SENSOR_CHAN_VEML7700_WHITE_RAW_COUNTS, + /** * @brief This channel is used to query the ALS interrupt state (ALS_INT). * diff --git a/include/zephyr/drivers/sensor_attribute_types.h b/include/zephyr/drivers/sensor_attribute_types.h new file mode 100644 index 00000000000..8ccb9dba110 --- /dev/null +++ b/include/zephyr/drivers/sensor_attribute_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Used by the following channel/attribute pairs: + * - SENSOR_CHAN_ACCEL_XYZ + * - SENSOR_ATTR_OFFSET + * - SENSOR_CHAN_GYRO_XYZ + * - SENSOR_ATTR_OFFSET + * - SENSOR_CHAN_MAGN_XYZ + * - SENSOR_ATTR_OFFSET + */ +struct sensor_three_axis_attribute { + int8_t shift; + union { + struct { + q31_t x; + q31_t y; + q31_t z; + }; + q31_t values[3]; + }; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_ATTRIBUTE_TYPES_H */ diff --git a/include/zephyr/drivers/serial/uart_async_to_irq.h b/include/zephyr/drivers/serial/uart_async_to_irq.h new file mode 100644 index 00000000000..d5116dee2c0 --- /dev/null +++ b/include/zephyr/drivers/serial/uart_async_to_irq.h @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ + +#include +#include +#include +#include +#include + +/** + * @brief UART Asynchronous to Interrupt driven API adaptation layer + * @ingroup uart_interface + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations. */ + +/** @brief Data structure used by the adaptation layer. + * + * Pointer to that data must be the first element of the UART device data structure. + */ +struct uart_async_to_irq_data; + +/** @brief Configuration structure used by the adaptation layer. + * + * Pointer to this data must be the first element of the UART device configuration structure. + */ +struct uart_async_to_irq_config; + +/* @brief Function that triggers trampoline to the interrupt context. + * + * This context is used to call user UART interrupt handler. It is to used to + * fulfill the requirement that UART interrupt driven API shall be called from + * the UART interrupt. Trampoline context shall have the same priority as UART. + * + * One option may be to use k_timer configured to expire immediately. + */ +typedef void (*uart_async_to_irq_trampoline)(const struct device *dev); + +/** @brief Callback to be called from trampoline context. + * + * @param dev UART device. + */ +void uart_async_to_irq_trampoline_cb(const struct device *dev); + +/** @brief Interrupt driven API initializer. + * + * It should be used in the initialization of the UART API structure in the + * driver to provide interrupt driven API functions. + */ +#define UART_ASYNC_TO_IRQ_API_INIT() \ + .fifo_fill = z_uart_async_to_irq_fifo_fill, \ + .fifo_read = z_uart_async_to_irq_fifo_read, \ + .irq_tx_enable = z_uart_async_to_irq_irq_tx_enable, \ + .irq_tx_disable = z_uart_async_to_irq_irq_tx_disable, \ + .irq_tx_ready = z_uart_async_to_irq_irq_tx_ready, \ + .irq_rx_enable = z_uart_async_to_irq_irq_rx_enable, \ + .irq_rx_disable = z_uart_async_to_irq_irq_rx_disable, \ + .irq_tx_complete = z_uart_async_to_irq_irq_tx_complete,\ + .irq_rx_ready = z_uart_async_to_irq_irq_rx_ready, \ + .irq_err_enable = z_uart_async_to_irq_irq_err_enable, \ + .irq_err_disable = z_uart_async_to_irq_irq_err_disable,\ + .irq_is_pending = z_uart_async_to_irq_irq_is_pending, \ + .irq_update = z_uart_async_to_irq_irq_update, \ + .irq_callback_set = z_uart_async_to_irq_irq_callback_set + +/** @brief Configuration structure initializer. + * + * @param _api Structure with UART asynchronous API. + * @param _trampoline Function that trampolines to the interrupt context. + * @param _baudrate UART baudrate. + * @param _tx_buf TX buffer. + * @param _tx_len TX buffer length. + * @param _rx_buf RX buffer. + * @param _rx_len RX buffer length. + * @param _rx_cnt Number of chunks into which RX buffer is divided. + * @param _log Logging instance, if not provided (empty) then default is used. + */ +#define UART_ASYNC_TO_IRQ_API_CONFIG_INITIALIZER(_api, _trampoline, _baudrate, _tx_buf, \ + _tx_len, _rx_buf, _rx_len, _rx_cnt, _log) \ + { \ + .tx_buf = _tx_buf, \ + .tx_len = _tx_len, \ + .async_rx = { \ + .buffer = _rx_buf, \ + .length = _rx_len, \ + .buf_cnt = _rx_cnt \ + }, \ + .api = _api, \ + .trampoline = _trampoline, \ + .baudrate = _baudrate, \ + LOG_OBJECT_PTR_INIT(log, \ + COND_CODE_1(IS_EMPTY(_log), \ + (LOG_OBJECT_PTR(UART_ASYNC_TO_IRQ_LOG_NAME)), \ + (_log) \ + ) \ + ) \ + } + +/** @brief Initialize the adaptation layer. + * + * @param data Data associated with the given adaptation layer instance. + * @param config Configuration structure. Must be persistent. + * + * @retval 0 On successful initialization. + */ +int uart_async_to_irq_init(struct uart_async_to_irq_data *data, + const struct uart_async_to_irq_config *config); + +/* @brief Enable RX for interrupt driven API. + * + * @param dev UART device. Device must support asynchronous API. + * + * @retval 0 on successful operation. + * @retval -EINVAL if adaption layer has wrong configuration. + * @retval negative value Error reported by the UART API. + */ +int uart_async_to_irq_rx_enable(const struct device *dev); + +/* @brief Disable RX for interrupt driven API. + * + * @param dev UART device. Device must support asynchronous API. + * + * @retval 0 on successful operation. + * @retval -EINVAL if adaption layer has wrong configuration. + * @retval negative value Error reported by the UART API. + */ +int uart_async_to_irq_rx_disable(const struct device *dev); + +/* Starting from here API is internal only. */ + +/** @cond INTERNAL_HIDDEN + * @brief Structure used by the adaptation layer. + */ +struct uart_async_to_irq_config { + /** Pointer to the TX buffer. */ + uint8_t *tx_buf; + + /** TX buffer length. */ + size_t tx_len; + + /** UART Asynchronous RX helper configuration. */ + struct uart_async_rx_config async_rx; + + /** Async API used by the a2i layer. */ + const struct uart_async_to_irq_async_api *api; + + /** Trampoline callback. */ + uart_async_to_irq_trampoline trampoline; + + /** Initial baudrate. */ + uint32_t baudrate; + + /** Instance logging handler. */ + LOG_INSTANCE_PTR_DECLARE(log); +}; + +/** @brief Asynchronous API used by the adaptation layer. */ +struct uart_async_to_irq_async_api { + int (*callback_set)(const struct device *dev, + uart_callback_t callback, + void *user_data); + + int (*tx)(const struct device *dev, const uint8_t *buf, size_t len, + int32_t timeout); + int (*tx_abort)(const struct device *dev); + + int (*rx_enable)(const struct device *dev, uint8_t *buf, size_t len, + int32_t timeout); + int (*rx_buf_rsp)(const struct device *dev, uint8_t *buf, size_t len); + int (*rx_disable)(const struct device *dev); +}; + +/** @brief Structure holding receiver data. */ +struct uart_async_to_irq_rx_data { + /** Asynchronous RX helper data. */ + struct uart_async_rx async_rx; + + /** Semaphore for pending on RX disable. */ + struct k_sem sem; + + /** Number of pending buffer requests which weren't handled because lack of free buffers. */ + atomic_t pending_buf_req; +}; + +/** @brief Structure holding transmitter data. */ +struct uart_async_to_irq_tx_data { + /** TX buffer. */ + uint8_t *buf; + + /** Length of the buffer. */ + size_t len; +}; + +/** @briref Data associated with the asynchronous to the interrupt driven API adaptation layer. */ +struct uart_async_to_irq_data { + /** User callback for interrupt driven API. */ + uart_irq_callback_user_data_t callback; + + /** User data. */ + void *user_data; + + /** Interrupt request counter. */ + atomic_t irq_req; + + /** RX specific data. */ + struct uart_async_to_irq_rx_data rx; + + /** TX specific data. */ + struct uart_async_to_irq_tx_data tx; + + /** Spinlock. */ + struct k_spinlock lock; + + /** Internally used flags for holding the state of the a2i layer. */ + atomic_t flags; +}; + +/** Interrupt driven FIFO fill function. */ +int z_uart_async_to_irq_fifo_fill(const struct device *dev, + const uint8_t *buf, + int len); + +/** Interrupt driven FIFO read function. */ +int z_uart_async_to_irq_fifo_read(const struct device *dev, + uint8_t *buf, + const int len); + +/** Interrupt driven transfer enabling function. */ +void z_uart_async_to_irq_irq_tx_enable(const struct device *dev); + +/** Interrupt driven transfer disabling function */ +void z_uart_async_to_irq_irq_tx_disable(const struct device *dev); + +/** Interrupt driven transfer ready function */ +int z_uart_async_to_irq_irq_tx_ready(const struct device *dev); + +/** Interrupt driven receiver enabling function */ +void z_uart_async_to_irq_irq_rx_enable(const struct device *dev); + +/** Interrupt driven receiver disabling function */ +void z_uart_async_to_irq_irq_rx_disable(const struct device *dev); + +/** Interrupt driven transfer complete function */ +int z_uart_async_to_irq_irq_tx_complete(const struct device *dev); + +/** Interrupt driven receiver ready function */ +int z_uart_async_to_irq_irq_rx_ready(const struct device *dev); + +/** Interrupt driven error enabling function */ +void z_uart_async_to_irq_irq_err_enable(const struct device *dev); + +/** Interrupt driven error disabling function */ +void z_uart_async_to_irq_irq_err_disable(const struct device *dev); + +/** Interrupt driven pending status function */ +int z_uart_async_to_irq_irq_is_pending(const struct device *dev); + +/** Interrupt driven interrupt update function */ +int z_uart_async_to_irq_irq_update(const struct device *dev); + +/** Set the irq callback function */ +void z_uart_async_to_irq_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *user_data); + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_ASYNC_TO_IRQ_H_ */ diff --git a/include/zephyr/drivers/smbus.h b/include/zephyr/drivers/smbus.h index c4995febb7b..c0348c367f1 100644 --- a/include/zephyr/drivers/smbus.h +++ b/include/zephyr/drivers/smbus.h @@ -19,6 +19,8 @@ * @{ */ +#include +#include #include #include diff --git a/include/zephyr/drivers/spi.h b/include/zephyr/drivers/spi.h index fa3b8834c9e..7042c73be0a 100644 --- a/include/zephyr/drivers/spi.h +++ b/include/zephyr/drivers/spi.h @@ -37,9 +37,12 @@ extern "C" { * @name SPI operational mode * @{ */ -#define SPI_OP_MODE_MASTER 0U -#define SPI_OP_MODE_SLAVE BIT(0) +#define SPI_OP_MODE_MASTER 0U /**< Master mode. */ +#define SPI_OP_MODE_SLAVE BIT(0) /**< Slave mode. */ +/** @cond INTERNAL_HIDDEN */ #define SPI_OP_MODE_MASK 0x1U +/** @endcond */ +/** Get SPI operational mode. */ #define SPI_OP_MODE_GET(_operation_) ((_operation_) & SPI_OP_MODE_MASK) /** @} */ @@ -70,8 +73,10 @@ extern "C" { * support this, and can be used for testing purposes only. */ #define SPI_MODE_LOOP BIT(3) - +/** @cond INTERNAL_HIDDEN */ #define SPI_MODE_MASK (0xEU) +/** @endcond */ +/** Get SPI polarity and phase mode bits. */ #define SPI_MODE_GET(_mode_) \ ((_mode_) & SPI_MODE_MASK) @@ -81,19 +86,22 @@ extern "C" { * @name SPI Transfer modes (host controller dependent) * @{ */ -#define SPI_TRANSFER_MSB (0U) -#define SPI_TRANSFER_LSB BIT(4) +#define SPI_TRANSFER_MSB (0U) /**< Most significant bit first. */ +#define SPI_TRANSFER_LSB BIT(4) /**< Least significant bit first. */ /** @} */ /** * @name SPI word size * @{ */ +/** @cond INTERNAL_HIDDEN */ #define SPI_WORD_SIZE_SHIFT (5U) #define SPI_WORD_SIZE_MASK (0x3FU << SPI_WORD_SIZE_SHIFT) +/** @endcond */ +/** Get SPI word size. */ #define SPI_WORD_SIZE_GET(_operation_) \ (((_operation_) & SPI_WORD_SIZE_MASK) >> SPI_WORD_SIZE_SHIFT) - +/** Set SPI word size. */ #define SPI_WORD_SET(_word_size_) \ ((_word_size_) << SPI_WORD_SIZE_SHIFT) /** @} */ @@ -102,16 +110,16 @@ extern "C" { * @name Specific SPI devices control bits * @{ */ -/* Requests - if possible - to keep CS asserted after the transaction */ +/** Requests - if possible - to keep CS asserted after the transaction */ #define SPI_HOLD_ON_CS BIT(12) -/* Keep the device locked after the transaction for the current config. +/** Keep the device locked after the transaction for the current config. * Use this with extreme caution (see spi_release() below) as it will * prevent other callers to access the SPI device until spi_release() is * properly called. */ #define SPI_LOCK_ON BIT(13) -/* Active high logic on CS - Usually, and by default, CS logic is active +/** Active high logic on CS. Usually, and by default, CS logic is active * low. However, some devices may require the reverse logic: active high. * This bit will request the controller to use that logic. Note that not * all controllers are able to handle that natively. In this case deferring @@ -130,12 +138,13 @@ extern "C" { * Without @kconfig{CONFIG_SPI_EXTENDED_MODES} being enabled, single is the * only supported one. */ -#define SPI_LINES_SINGLE (0U << 16) -#define SPI_LINES_DUAL (1U << 16) -#define SPI_LINES_QUAD (2U << 16) -#define SPI_LINES_OCTAL (3U << 16) +#define SPI_LINES_SINGLE (0U << 16) /**< Single line */ +#define SPI_LINES_DUAL (1U << 16) /**< Dual lines */ +#define SPI_LINES_QUAD (2U << 16) /**< Quad lines */ +#define SPI_LINES_OCTAL (3U << 16) /**< Octal lines */ + +#define SPI_LINES_MASK (0x3U << 16) /**< Mask for MISO lines in spi_operation_t */ -#define SPI_LINES_MASK (0x3U << 16) /** @} */ /** @@ -225,22 +234,28 @@ struct spi_cs_control { * * Example devicetree fragment: * - * spi@... { + * @code{.devicetree} + * spi@abcd0001 { * cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; * spidev: spi-device@0 { ... }; * }; + * @endcode * * Example usage: * + * @code{.c} * struct spi_cs_control ctrl = * SPI_CS_CONTROL_INIT(DT_NODELABEL(spidev), 2); + * @endcode * * This example is equivalent to: * + * @code{.c} * struct spi_cs_control ctrl = { * .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spidev)), * .delay = 2, * }; + * @endcode * * @param node_id Devicetree node identifier for a device on a SPI bus * @param delay_ The @p delay field to set in the @p spi_cs_control @@ -356,12 +371,11 @@ struct spi_config { /** * @brief Complete SPI DT information - * - * @param bus is the SPI bus - * @param config is the slave specific configuration */ struct spi_dt_spec { + /** SPI bus */ const struct device *bus; + /** Slave specific configuration */ struct spi_config config; }; @@ -405,25 +419,24 @@ struct spi_dt_spec { /** * @brief SPI buffer structure - * - * @param buf is a valid pointer on a data buffer, or NULL otherwise. - * @param len is the length of the buffer or, if buf is NULL, will be the - * length which as to be sent as dummy bytes (as TX buffer) or - * the length of bytes that should be skipped (as RX buffer). */ struct spi_buf { + /** Valid pointer to a data buffer, or NULL otherwise */ void *buf; + /** Length of the buffer @a buf. + * If @a buf is NULL, length which as to be sent as dummy bytes (as TX + * buffer) or the length of bytes that should be skipped (as RX buffer). + */ size_t len; }; /** * @brief SPI buffer array structure - * - * @param buffers is a valid pointer on an array of spi_buf, or NULL. - * @param count is the length of the array pointed by buffers. */ struct spi_buf_set { + /** Pointer to an array of spi_buf, or NULL */ const struct spi_buf *buffers; + /** Length of the array pointed by @a buffers */ size_t count; }; @@ -786,6 +799,7 @@ static inline int spi_transceive_dt(const struct spi_dt_spec *spec, * previous operations. * @param rx_bufs Buffer array where data to be read will be written to. * + * @retval frames Positive number of frames received in slave mode. * @retval 0 If successful. * @retval -errno Negative errno code on failure. */ @@ -974,6 +988,7 @@ __deprecated static inline int spi_transceive_async(const struct device *dev, * notify the end of the transaction, and whether it went * successfully or not). * + * @retval frames Positive number of frames received in slave mode. * @retval 0 If successful * @retval -errno Negative errno code on failure. */ diff --git a/include/zephyr/drivers/spi_emul.h b/include/zephyr/drivers/spi_emul.h index fe189efb82b..9f7eb958089 100644 --- a/include/zephyr/drivers/spi_emul.h +++ b/include/zephyr/drivers/spi_emul.h @@ -43,6 +43,12 @@ struct spi_emul { /* API provided for this device */ const struct spi_emul_api *api; + /** + * A mock API that if not NULL will take precedence over the actual API. If set, a return + * value of -ENOSYS will revert back to the default api. + */ + struct spi_emul_api *mock_api; + /* SPI chip-select of the emulated device */ uint16_t chipsel; }; diff --git a/include/zephyr/drivers/timer/nrf_grtc_timer.h b/include/zephyr/drivers/timer/nrf_grtc_timer.h new file mode 100644 index 00000000000..172a904fdef --- /dev/null +++ b/include/zephyr/drivers/timer/nrf_grtc_timer.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H +#define ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @brief GRTC timer compare event handler. + * + * Called from GRTC ISR context when processing a compare event. + * + * @param id Compare channel ID. + * + * @param expire_time An actual absolute expiration time set for a compare + * channel. It can differ from the requested target time + * and the difference can be used to determine whether the + * time set was delayed. + * + * @param user_data Pointer to a user context data. + */ +typedef void (*z_nrf_grtc_timer_compare_handler_t)(int32_t id, uint64_t expire_time, + void *user_data); + +/** @brief Allocate GRTC capture/compare channel. + * + * @retval >=0 Non-negative indicates allocated channel ID. + * @retval -ENOMEM if channel cannot be allocated. + */ +int32_t z_nrf_grtc_timer_chan_alloc(void); + +/** @brief Free GRTC capture/compare channel. + * + * @param chan Previously allocated channel ID. + */ +void z_nrf_grtc_timer_chan_free(int32_t chan); + +/** @brief Read current absolute time. + * + * @return Current absolute time. + */ +uint64_t z_nrf_grtc_timer_read(void); + +/** @brief Check COMPARE event state. + * + * @param chan Channel ID. + * + * @retval true The event has been generated. + * @retval false The event has not been generated. + */ +bool z_nrf_grtc_timer_compare_evt_check(int32_t chan); + +/** @brief Get COMPARE event register address. + * + * Address can be used for DPPIC. + * + * @param chan Channel ID. + * + * @return Register address. + */ +uint32_t z_nrf_grtc_timer_compare_evt_address_get(int32_t chan); + +/** @brief Get CAPTURE task register address. + * + * Address can be used for DPPIC. + * + * @param chan Channel ID. + * + * @return Register address. + */ +uint32_t z_nrf_grtc_timer_capture_task_address_get(int32_t chan); + +/** @brief Safely disable compare event interrupt. + * + * Function returns key indicating whether interrupt was already disabled. + * + * @param chan Channel ID. + * + * @return key passed to z_nrf_grtc_timer_compare_int_unlock(). + */ +bool z_nrf_grtc_timer_compare_int_lock(int32_t chan); + +/** @brief Safely enable compare event interrupt. + * + * Event interrupt is conditionally enabled based on @p key. + * + * @param chan Channel ID. + * + * @param key Key returned by z_nrf_grtc_timer_compare_int_lock(). + */ +void z_nrf_grtc_timer_compare_int_unlock(int32_t chan, bool key); + +/** @brief Read compare register value. + * + * @param chan Channel ID. + * + * @retval >=0 Positive is a Value set in the compare register + * @retval -EAGAIN if compare for given channel is not set. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +uint64_t z_nrf_grtc_timer_compare_read(int32_t chan); + +/** @brief Set compare channel to given value. + * + * @param chan Channel ID. + * + * @param target_time Absolute target time in ticks. + * + * @param handler User function called in the context of the GRTC interrupt. + * + * @param user_data Data passed to the handler. + * + * @retval 0 if the compare channel was set successfully. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +int z_nrf_grtc_timer_set(int32_t chan, uint64_t target_time, + z_nrf_grtc_timer_compare_handler_t handler, void *user_data); + +/** @brief Abort a timer requested with z_nrf_grtc_timer_set(). + * + * If an abort operation is performed too late it is still possible for an event + * to fire. The user can detect a spurious event by comparing absolute time + * provided in callback and a result of z_nrf_grtc_timer_read(). During this + * operation interrupt from that compare channel is disabled. Other interrupts + * are not locked during this operation. + * + * @param chan Channel ID between 1 and CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT. + */ +void z_nrf_grtc_timer_abort(int32_t chan); + +/** @brief Convert system clock time to GRTC ticks. + * + * @p t can be absolute or relative. + * + * @retval >=0 Positive value represents @p t in GRTC tick value. + * @retval -EINVAL if @p t is out of range. + */ +uint64_t z_nrf_grtc_timer_get_ticks(k_timeout_t t); + +/** @brief Prepare channel for timestamp capture. + * + * Use z_nrf_grtc_timer_capture_task_address_get() to determine the register + * address that is used to trigger capture. + * + * @note Capture and compare are mutually exclusive features - they cannot be + * used simultaneously on the same GRTC channel. + * + * @param chan Channel ID. + * + * @retval 0 if the channel was successfully prepared. + * @retval -EPERM if either channel is unavailable or SYSCOUNTER is not running. + */ +int z_nrf_grtc_timer_capture_prepare(int32_t chan); + +/** @brief Read timestamp value captured on the channel. + * + * The @p chan must be prepared using z_nrf_grtc_timer_capture_prepare(). + * + * @param chan Channel ID. + * + * @param captured_time Pointer to store the value. + * + * @retval 0 if the timestamp was successfully caught and read. + * @retval -EBUSY if capturing has not been triggered. + */ +int z_nrf_grtc_timer_capture_read(int32_t chan, uint64_t *captured_time); + +/** @brief Prepare GRTC as a source of wake up event and set the wake up time. + * + * @note Calling this function should be immediately followed by low-power mode enter + * (if it executed successfully). + * + * @param wake_time_us Relative wake up time in microseconds. + * + * @retval 0 if wake up time was successfully set. + * @retval -EPERM if the SYSCOUNTER is not running. + * @retval -ENOMEM if no available GRTC channels were found. + * @retval -EINVAL if @p wake_time_us is too low. + */ +int z_nrf_grtc_wakeup_prepare(uint64_t wake_time_us); + +/** + * @brief Initialize the GRTC clock timer driver from an application- + * defined function. + * + * @retval 0 on success. + * @retval -errno Negative error code on failure. + */ +int nrf_grtc_timer_clock_driver_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_TIMER_NRF_GRTC_TIMER_H */ diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 0f01d877e54..7e13d565a73 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -40,6 +40,8 @@ struct udc_device_caps { uint32_t rwup : 1; /** Controller performs status OUT stage automatically */ uint32_t out_ack : 1; + /** Controller expects device address to be set before status stage */ + uint32_t addr_before_status : 1; /** Maximum packet size for control endpoint */ enum udc_mps0 mps0 : 2; }; @@ -215,7 +217,7 @@ typedef int (*udc_event_cb_t)(const struct device *dev, * @brief UDC driver API * This is the mandatory API any USB device controller driver needs to expose * with exception of: - * device_speed() used by udc_device_speed(), not required for FS only devices + * device_speed(), test_mode() are only required for HS controllers */ struct udc_api { enum udc_bus_speed (*device_speed)(const struct device *dev); @@ -237,6 +239,8 @@ struct udc_api { int (*host_wakeup)(const struct device *dev); int (*set_address)(const struct device *dev, const uint8_t addr); + int (*test_mode)(const struct device *dev, + const uint8_t mode, const bool dryrun); int (*enable)(const struct device *dev); int (*disable)(const struct device *dev); int (*init)(const struct device *dev); @@ -444,6 +448,42 @@ static inline int udc_set_address(const struct device *dev, const uint8_t addr) return ret; } +/** + * @brief Enable Test Mode. + * + * For compliance testing, high-speed controllers must support test modes. + * A particular test is enabled by a SetFeature(TEST_MODE) request. + * To disable a test mode, device needs to be power cycled. + * + * @param[in] dev Pointer to device struct of the driver instance + * @param[in] mode Test mode + * @param[in] dryrun Verify that a particular mode can be enabled, but do not + * enable test mode + * + * @return 0 on success, all other values should be treated as error. + * @retval -ENOTSUP Test mode is not supported + */ +static inline int udc_test_mode(const struct device *dev, + const uint8_t mode, const bool dryrun) +{ + const struct udc_api *api = dev->api; + int ret; + + if (!udc_is_enabled(dev)) { + return -EPERM; + } + + if (api->test_mode != NULL) { + api->lock(dev); + ret = api->test_mode(dev, mode, dryrun); + api->unlock(dev); + } else { + ret = -ENOTSUP; + } + + return ret; +} + /** * @brief Initiate host wakeup procedure. * diff --git a/include/zephyr/drivers/usb_c/usbc_ppc.h b/include/zephyr/drivers/usb_c/usbc_ppc.h new file mode 100644 index 00000000000..c8f76c9227f --- /dev/null +++ b/include/zephyr/drivers/usb_c/usbc_ppc.h @@ -0,0 +1,277 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB Type-C Power Path Controller device API + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Type of event being notified by Power Path Controller */ +enum usbc_ppc_event { + /** Exit from dead-battery mode failed */ + USBC_PPC_EVENT_DEAD_BATTERY_ERROR = 0, + + /** Overvoltage detected while being in a source role */ + USBC_PPC_EVENT_SRC_OVERVOLTAGE, + /** Reverse current detected while being in a source role */ + USBC_PPC_EVENT_SRC_REVERSE_CURRENT, + /** Overcurrent detected while being in a source role */ + USBC_PPC_EVENT_SRC_OVERCURRENT, + /** VBUS short detected while being in a source role */ + USBC_PPC_EVENT_SRC_SHORT, + + /** Chip over temperature detected */ + USBC_PPC_EVENT_OVER_TEMPERATURE, + /** Sink and source paths enabled simultaneously */ + USBC_PPC_EVENT_BOTH_SNKSRC_ENABLED, + + /** Reverse current detected while being in a sink role */ + USBC_PPC_EVENT_SNK_REVERSE_CURRENT, + /** VBUS short detected while being in a sink role */ + USBC_PPC_EVENT_SNK_SHORT, + /** Overvoltage detected while being in a sink role */ + USBC_PPC_EVENT_SNK_OVERVOLTAGE, +}; + +typedef void (*usbc_ppc_event_cb_t)(const struct device *dev, void *data, enum usbc_ppc_event ev); + +/** Structure with pointers to the functions implemented by driver */ +__subsystem struct usbc_ppc_drv { + int (*is_dead_battery_mode)(const struct device *dev); + int (*exit_dead_battery_mode)(const struct device *dev); + int (*is_vbus_source)(const struct device *dev); + int (*is_vbus_sink)(const struct device *dev); + int (*set_snk_ctrl)(const struct device *dev, bool enable); + int (*set_src_ctrl)(const struct device *dev, bool enable); + int (*set_vbus_discharge)(const struct device *dev, bool enable); + int (*is_vbus_present)(const struct device *dev); + int (*set_event_handler)(const struct device *dev, usbc_ppc_event_cb_t handler, void *data); + int (*dump_regs)(const struct device *dev); +}; + +/* + * API functions + */ + +/** + * @brief Check if PPC is in the dead battery mode + * + * @param dev PPC device structure + * @retval 1 if PPC is in the dead battery mode + * @retval 0 if PPC is not in the dead battery mode + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_dead_battery_mode(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_dead_battery_mode == NULL) { + return -ENOSYS; + } + + return api->is_dead_battery_mode(dev); +} + +/** + * @brief Request the PPC to exit from the dead battery mode + * Return from this call doesn't mean that the PPC is not in the dead battery anymore. + * In the case of error, the driver should execute the callback with + * USBC_PPC_EVENT_DEAD_BATTERY_ERROR enum. To check if the PPC disabled the dead battery mode, + * the call to ppc_is_dead_battery_mode should be done. + * + * @param dev PPC device structure + * @retval 0 if request was successfully sent + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_exit_dead_battery_mode(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->exit_dead_battery_mode == NULL) { + return -ENOSYS; + } + + return api->exit_dead_battery_mode(dev); +} + +/** + * @brief Check if the PPC is sourcing the VBUS + * + * @param dev PPC device structure + * @retval 1 if the PPC is sourcing the VBUS + * @retval 0 if the PPC is not sourcing the VBUS + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_source(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_source == NULL) { + return -ENOSYS; + } + + return api->is_vbus_source(dev); +} + +/** + * @brief Check if the PPC is sinking the VBUS + * + * @param dev PPC device structure + * @retval 1 if the PPC is sinking the VBUS + * @retval 0 if the PPC is not sinking the VBUS + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_sink(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_sink == NULL) { + return -ENOSYS; + } + + return api->is_vbus_sink(dev); +} + +/** + * @brief Set the state of VBUS sinking + * + * @param dev PPC device structure + * @param enable True if sinking VBUS should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_snk_ctrl(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_snk_ctrl == NULL) { + return -ENOSYS; + } + + return api->set_snk_ctrl(dev, enable); +} + +/** + * @brief Set the state of VBUS sourcing + * + * @param dev PPC device structure + * @param enable True if sourcing VBUS should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_src_ctrl(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_src_ctrl == NULL) { + return -ENOSYS; + } + + return api->set_src_ctrl(dev, enable); +} + +/** + * @brief Set the state of VBUS discharging + * + * @param dev PPC device structure + * @param enable True if VBUS discharging should be enabled, false if should be disabled + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_vbus_discharge(const struct device *dev, bool enable) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_vbus_discharge == NULL) { + return -ENOSYS; + } + + return api->set_vbus_discharge(dev, enable); +} + +/** + * @brief Check if VBUS is present + * + * @param dev PPC device structure + * @retval 1 if VBUS voltage is present + * @retval 0 if no VBUS voltage is detected + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_is_vbus_present(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->is_vbus_present == NULL) { + return -ENOSYS; + } + + return api->is_vbus_present(dev); +} + +/** + * @brief Set the callback used to notify about PPC events + * + * @param dev PPC device structure + * @param handler Handler that will be called with events notifications + * @param data Pointer used as an argument to the callback + * @retval 0 if success + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_set_event_handler(const struct device *dev, + usbc_ppc_event_cb_t handler, void *data) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->set_event_handler == NULL) { + return -ENOSYS; + } + + return api->set_event_handler(dev, handler, data); +} + +/** + * @brief Print the values or PPC registers + * + * @param dev PPC device structure + * @retval 0 if success + * @retval -EIO if I2C communication failed + * @retval -ENOSYS if this function is not supported by the driver + */ +static inline int ppc_dump_regs(const struct device *dev) +{ + const struct usbc_ppc_drv *api = (const struct usbc_ppc_drv *)dev->api; + + if (api->dump_regs == NULL) { + return -ENOSYS; + } + + return api->dump_regs(dev); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DRIVERS_USBC_USBC_PPC_H_ */ diff --git a/include/zephyr/drivers/virtualization/ivshmem.h b/include/zephyr/drivers/virtualization/ivshmem.h index 0507eb6ae1a..20bd1e42336 100644 --- a/include/zephyr/drivers/virtualization/ivshmem.h +++ b/include/zephyr/drivers/virtualization/ivshmem.h @@ -84,6 +84,12 @@ __subsystem struct ivshmem_driver_api { /** * @brief Get the inter-VM shared memory * + * Note: This API is not supported for ivshmem-v2, as + * the R/W and R/O areas may not be mapped contiguously. + * For ivshmem-v2, use the ivshmem_get_rw_mem_section, + * ivshmem_get_output_mem_section and ivshmem_get_state + * APIs to access the shared memory. + * * @param dev Pointer to the device structure for the driver instance * @param memmap A pointer to fill in with the memory address * diff --git a/include/zephyr/dt-bindings/clock/imx_ccm.h b/include/zephyr/dt-bindings/clock/imx_ccm.h index 93c3b0b3b15..b20d1e5aecb 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm.h @@ -55,4 +55,10 @@ #define IMX_CCM_QTMR_CLK 0x0D00UL +#define IMX_CCM_ENET_CLK 0x0E00UL +#define IMX_CCM_ENET_PLL 0x0E01UL + +#define IMX_CCM_FLEXSPI_CLK 0x0F00UL +#define IMX_CCM_FLEXSPI2_CLK 0x0F01UL + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ diff --git a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h index fb105454377..c36d140b534 100644 --- a/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h +++ b/include/zephyr/dt-bindings/clock/imx_ccm_rev2.h @@ -42,6 +42,8 @@ #define IMX_CCM_LPI2C4_CLK 0x403UL #define IMX_CCM_LPI2C5_CLK 0x404UL #define IMX_CCM_LPI2C6_CLK 0x405UL +#define IMX_CCM_LPI2C7_CLK 0x406UL +#define IMX_CCM_LPI2C8_CLK 0x407UL /* LPSPI */ #define IMX_CCM_LPSPI_CLK 0x500UL @@ -51,6 +53,8 @@ #define IMX_CCM_LPSPI4_CLK 0x503UL #define IMX_CCM_LPSPI5_CLK 0x504UL #define IMX_CCM_LPSPI6_CLK 0x505UL +#define IMX_CCM_LPSPI7_CLK 0x506UL +#define IMX_CCM_LPSPI8_CLK 0x507UL /* USDHC */ #define IMX_CCM_USDHC1_CLK 0x600UL @@ -84,5 +88,12 @@ #define IMX_CCM_SAI3_CLK 0x2002UL #define IMX_CCM_SAI4_CLK 0x2003UL +/* ENET */ +#define IMX_CCM_ENET_CLK 0x3000UL +#define IMX_CCM_ENET_PLL 0x3001UL + +/* FLEXSPI */ +#define IMX_CCM_FLEXSPI_CLK 0x4000UL +#define IMX_CCM_FLEXSPI2_CLK 0x4001UL #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */ diff --git a/include/zephyr/dt-bindings/clock/kinetis_sim.h b/include/zephyr/dt-bindings/clock/kinetis_sim.h index 6c06928ec80..8395a05b483 100644 --- a/include/zephyr/dt-bindings/clock/kinetis_sim.h +++ b/include/zephyr/dt-bindings/clock/kinetis_sim.h @@ -24,5 +24,7 @@ #define KINETIS_SIM_ER32KSEL_RTC 2 #define KINETIS_SIM_ER32KSEL_LPO1KHZ 3 +#define KINETIS_SIM_ENET_CLK 4321 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_KINETIS_SIM_H_ */ diff --git a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h index 9f80b662c60..404ba96de96 100644 --- a/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h +++ b/include/zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h @@ -51,6 +51,11 @@ #define MCUX_SCTIMER_CLK 34 +#define MCUX_DMIC_CLK 35 + +#define MCUX_FLEXSPI_CLK 36 +#define MCUX_FLEXSPI2_CLK 37 + #define MCUX_MRT_CLK 40 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MCUX_LPC_SYSCON_H_ */ diff --git a/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h b/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h new file mode 100644 index 00000000000..f3a11104e74 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/nxp_s32k146_clock.h @@ -0,0 +1,99 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ + +#define NXP_S32_LPO_128K_CLK 1U +#define NXP_S32_SIRC_CLK 2U +#define NXP_S32_SIRC_VLP_CLK 3U +#define NXP_S32_SIRC_STOP_CLK 4U +#define NXP_S32_FIRC_CLK 5U +#define NXP_S32_FIRC_VLP_CLK 6U +#define NXP_S32_FIRC_STOP_CLK 7U +#define NXP_S32_SOSC_CLK 8U +#define NXP_S32_SPLL_CLK 9U +#define NXP_S32_SIRCDIV1_CLK 10U +#define NXP_S32_SIRCDIV2_CLK 11U +#define NXP_S32_FIRCDIV1_CLK 12U +#define NXP_S32_FIRCDIV2_CLK 13U +#define NXP_S32_SOSCDIV1_CLK 14U +#define NXP_S32_SOSCDIV2_CLK 15U +#define NXP_S32_SPLLDIV1_CLK 16U +#define NXP_S32_SPLLDIV2_CLK 17U +#define NXP_S32_LPO_32K_CLK 18U +#define NXP_S32_LPO_1K_CLK 19U +#define NXP_S32_TCLK0_REF_CLK 20U +#define NXP_S32_TCLK1_REF_CLK 21U +#define NXP_S32_TCLK2_REF_CLK 22U +#define NXP_S32_SCS_CLK 24U +#define NXP_S32_SCS_RUN_CLK 25U +#define NXP_S32_SCS_VLPR_CLK 26U +#define NXP_S32_SCS_HSRUN_CLK 27U +#define NXP_S32_CORE_CLK 28U +#define NXP_S32_CORE_RUN_CLK 29U +#define NXP_S32_CORE_VLPR_CLK 30U +#define NXP_S32_CORE_HSRUN_CLK 31U +#define NXP_S32_BUS_CLK 32U +#define NXP_S32_BUS_RUN_CLK 33U +#define NXP_S32_BUS_VLPR_CLK 34U +#define NXP_S32_BUS_HSRUN_CLK 35U +#define NXP_S32_SLOW_CLK 36U +#define NXP_S32_SLOW_RUN_CLK 37U +#define NXP_S32_SLOW_VLPR_CLK 38U +#define NXP_S32_SLOW_HSRUN_CLK 39U +#define NXP_S32_RTC_CLK 40U +#define NXP_S32_LPO_CLK 41U +#define NXP_S32_SCG_CLKOUT_CLK 42U +#define NXP_S32_FTM0_EXT_CLK 43U +#define NXP_S32_FTM1_EXT_CLK 44U +#define NXP_S32_FTM2_EXT_CLK 45U +#define NXP_S32_FTM3_EXT_CLK 46U +#define NXP_S32_FTM4_EXT_CLK 47U +#define NXP_S32_FTM5_EXT_CLK 48U +#define NXP_S32_ADC0_CLK 50U +#define NXP_S32_ADC1_CLK 51U +#define NXP_S32_CLKOUT0_CLK 52U +#define NXP_S32_CMP0_CLK 53U +#define NXP_S32_CRC0_CLK 54U +#define NXP_S32_DMA0_CLK 55U +#define NXP_S32_DMAMUX0_CLK 56U +#define NXP_S32_EIM0_CLK 57U +#define NXP_S32_ERM0_CLK 58U +#define NXP_S32_EWM0_CLK 59U +#define NXP_S32_FLEXCAN0_CLK 60U +#define NXP_S32_FLEXCAN1_CLK 61U +#define NXP_S32_FLEXCAN2_CLK 62U +#define NXP_S32_FLEXIO_CLK 63U +#define NXP_S32_FTFC_CLK 64U +#define NXP_S32_FTM0_CLK 65U +#define NXP_S32_FTM1_CLK 66U +#define NXP_S32_FTM2_CLK 67U +#define NXP_S32_FTM3_CLK 68U +#define NXP_S32_FTM4_CLK 69U +#define NXP_S32_FTM5_CLK 70U +#define NXP_S32_LPI2C0_CLK 71U +#define NXP_S32_LPIT0_CLK 72U +#define NXP_S32_LPSPI0_CLK 73U +#define NXP_S32_LPSPI1_CLK 74U +#define NXP_S32_LPSPI2_CLK 75U +#define NXP_S32_LPTMR0_CLK 76U +#define NXP_S32_LPUART0_CLK 77U +#define NXP_S32_LPUART1_CLK 78U +#define NXP_S32_LPUART2_CLK 79U +#define NXP_S32_MPU0_CLK 80U +#define NXP_S32_MSCM0_CLK 81U +#define NXP_S32_PDB0_CLK 82U +#define NXP_S32_PDB1_CLK 83U +#define NXP_S32_PORTA_CLK 84U +#define NXP_S32_PORTB_CLK 85U +#define NXP_S32_PORTC_CLK 86U +#define NXP_S32_PORTD_CLK 87U +#define NXP_S32_PORTE_CLK 88U +#define NXP_S32_RTC0_CLK 89U +#define NXP_S32_TRACE_CLK 90U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_NXP_S32K146_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h new file mode 100644 index 00000000000..d0f01809795 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ + +#include "renesas_cpg_mssr.h" + +/* r8a779f0 CPG Core Clocks */ +#define R8A779F0_CLK_Z0 0 +#define R8A779F0_CLK_Z1 1 +#define R8A779F0_CLK_ZR 2 +#define R8A779F0_CLK_ZX 3 +#define R8A779F0_CLK_ZS 4 +#define R8A779F0_CLK_ZT 5 +#define R8A779F0_CLK_ZTR 6 +#define R8A779F0_CLK_S0D2 7 +#define R8A779F0_CLK_S0D3 8 +#define R8A779F0_CLK_S0D4 9 +#define R8A779F0_CLK_S0D2_MM 10 +#define R8A779F0_CLK_S0D3_MM 11 +#define R8A779F0_CLK_S0D4_MM 12 +#define R8A779F0_CLK_S0D2_RT 13 +#define R8A779F0_CLK_S0D3_RT 14 +#define R8A779F0_CLK_S0D4_RT 15 +#define R8A779F0_CLK_S0D6_RT 16 +#define R8A779F0_CLK_S0D3_PER 17 +#define R8A779F0_CLK_S0D6_PER 18 +#define R8A779F0_CLK_S0D12_PER 19 +#define R8A779F0_CLK_S0D24_PER 20 +#define R8A779F0_CLK_S0D2_HSC 21 +#define R8A779F0_CLK_S0D3_HSC 22 +#define R8A779F0_CLK_S0D4_HSC 23 +#define R8A779F0_CLK_S0D6_HSC 24 +#define R8A779F0_CLK_S0D12_HSC 25 +#define R8A779F0_CLK_S0D2_CC 26 +#define R8A779F0_CLK_CL 27 +#define R8A779F0_CLK_CL16M 28 +#define R8A779F0_CLK_CL16M_MM 29 +#define R8A779F0_CLK_CL16M_RT 30 +#define R8A779F0_CLK_CL16M_PER 31 +#define R8A779F0_CLK_CL16M_HSC 32 +#define R8A779F0_CLK_ZB3 33 +#define R8A779F0_CLK_ZB3D2 34 +#define R8A779F0_CLK_ZB3D4 35 +#define R8A779F0_CLK_SD0H 36 +#define R8A779F0_CLK_SD0 37 +#define R8A779F0_CLK_RPC 38 +#define R8A779F0_CLK_RPCD2 39 +#define R8A779F0_CLK_MSO 40 +#define R8A779F0_CLK_POST 41 +#define R8A779F0_CLK_POST2 42 +#define R8A779F0_CLK_SASYNCRT 43 +#define R8A779F0_CLK_SASYNCPERD1 44 +#define R8A779F0_CLK_SASYNCPERD2 45 +#define R8A779F0_CLK_SASYNCPERD4 46 +#define R8A779F0_CLK_DBGSOC_HSC 47 +#define R8A779F0_CLK_RSW2 48 +#define R8A779F0_CLK_CPEX 49 +#define R8A779F0_CLK_CBFUSA 50 +#define R8A779F0_CLK_R 51 +#define R8A779F0_CLK_OSC 52 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RENESAS_CLOCK_R8A779F0_H_ */ diff --git a/include/zephyr/dt-bindings/clock/rpi_pico_clock.h b/include/zephyr/dt-bindings/clock/rpi_pico_clock.h new file mode 100644 index 00000000000..07522be6632 --- /dev/null +++ b/include/zephyr/dt-bindings/clock/rpi_pico_clock.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Andrei-Edward Popa + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ + +#define RPI_PICO_PLL_SYS 0 +#define RPI_PICO_PLL_USB 1 +#define RPI_PICO_PLL_COUNT 2 + +#define RPI_PICO_GPIN_0 0 +#define RPI_PICO_GPIN_1 1 +#define RPI_PICO_GPIN_COUNT 2 + +#define RPI_PICO_CLKID_CLK_GPOUT0 0 +#define RPI_PICO_CLKID_CLK_GPOUT1 1 +#define RPI_PICO_CLKID_CLK_GPOUT2 2 +#define RPI_PICO_CLKID_CLK_GPOUT3 3 +#define RPI_PICO_CLKID_CLK_REF 4 +#define RPI_PICO_CLKID_CLK_SYS 5 +#define RPI_PICO_CLKID_CLK_PERI 6 +#define RPI_PICO_CLKID_CLK_USB 7 +#define RPI_PICO_CLKID_CLK_ADC 8 +#define RPI_PICO_CLKID_CLK_RTC 9 + +#define RPI_PICO_CLKID_PLL_SYS 10 +#define RPI_PICO_CLKID_PLL_USB 11 +#define RPI_PICO_CLKID_XOSC 12 +#define RPI_PICO_CLKID_ROSC 13 +#define RPI_PICO_CLKID_ROSC_PH 14 +#define RPI_PICO_CLKID_GPIN0 15 +#define RPI_PICO_CLKID_GPIN1 16 + +#define RPI_PICO_ROSC_RANGE_RESET 0xAA0 +#define RPI_PICO_ROSC_RANGE_LOW 0xFA4 +#define RPI_PICO_ROSC_RANGE_MEDIUM 0xFA5 +#define RPI_PICO_ROSC_RANGE_HIGH 0xFA7 +#define RPI_PICO_ROSC_RANGE_TOOHIGH 0xFA6 + +#define RPI_PICO_CLOCK_COUNT 10 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_RPI_PICO_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32_common_clocks.h b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h new file mode 100644 index 00000000000..030ec2d939b --- /dev/null +++ b/include/zephyr/dt-bindings/clock/stm32_common_clocks.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ + +/** System clock */ +#define STM32_SRC_SYSCLK 0x001 +/** Fixed clocks */ +#define STM32_SRC_LSE 0x002 +#define STM32_SRC_LSI 0x003 + +/** Dummy: Add a specifier when no selection is possible */ +#define NO_SEL 0xFF + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32_COMMON_CLOCKS_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32c0_clock.h b/include/zephyr/dt-bindings/clock/stm32c0_clock.h index b48aa7d2ef1..224bd1517d5 100644 --- a/include/zephyr/dt-bindings/clock/stm32c0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32c0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_IOP 0x034 #define STM32_CLOCK_BUS_AHB1 0x038 @@ -18,15 +20,14 @@ /** Domain clocks */ /* RM0490, §5.4.21/22 Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI48 0x001 -#define STM32_SRC_HSE 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI48 (STM32_SRC_LSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI48 + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x006 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -70,7 +71,5 @@ #define ADC_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR_REG) /** CSR1 devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, CSR1_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32C0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f0_clock.h b/include/zephyr/dt-bindings/clock/stm32f0_clock.h index 309c31877e3..11645735830 100644 --- a/include/zephyr/dt-bindings/clock/stm32f0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x014 #define STM32_CLOCK_BUS_APB2 0x018 @@ -16,18 +18,17 @@ /** Domain clocks */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -#define STM32_SRC_HSI14 0x004 -#define STM32_SRC_HSI48 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI14 (STM32_SRC_HSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI14 + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_HSI48 + 1) /** PLL clock */ -#define STM32_SRC_PLLCLK 0x008 +#define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -73,7 +74,5 @@ #define USART3_SEL(val) STM32_CLOCK(val, 3, 18, CFGR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f1_clock.h b/include/zephyr/dt-bindings/clock/stm32f1_clock.h index e65be1c72e3..571014dd2f0 100644 --- a/include/zephyr/dt-bindings/clock/stm32f1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f1_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -16,13 +18,13 @@ #define STM32_PERIPH_BUS_MIN STM32_CLOCK_BUS_AHB1 #define STM32_PERIPH_BUS_MAX STM32_CLOCK_BUS_APB1 -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSE 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI + 1) #define STM32_CLOCK_REG_MASK 0xFFU @@ -65,7 +67,5 @@ #define I2S3_SEL(val) STM32_CLOCK(val, 1, 18, CFGR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f3_clock.h b/include/zephyr/dt-bindings/clock/stm32f3_clock.h index 90614f385b9..377eb4fdaad 100644 --- a/include/zephyr/dt-bindings/clock/stm32f3_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f3_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x014 #define STM32_CLOCK_BUS_APB2 0x018 @@ -17,17 +19,17 @@ /** Domain clocks */ /* RM0316, §9.4.13 Clock configuration register (RCC_CFGR3) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x007 -/* #define STM32_SRC_HSI48 0x003 */ /** System clock */ -#define STM32_SRC_SYSCLK 0x004 +/* Defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/* #define STM32_SRC_HSI48 TDB */ /** Bus clock */ -#define STM32_SRC_PCLK 0x005 +#define STM32_SRC_PCLK (STM32_SRC_HSI + 1) /** PLL clock */ -#define STM32_SRC_PLLCLK 0x006 +#define STM32_SRC_PLLCLK (STM32_SRC_PCLK + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -86,7 +88,5 @@ #define TIM3_4_SEL(val) STM32_CLOCK(val, 1, 25, CFGR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F3_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f4_clock.h b/include/zephyr/dt-bindings/clock/stm32f4_clock.h index e0edf742d79..93355865fdd 100644 --- a/include/zephyr/dt-bindings/clock/stm32f4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -22,19 +24,18 @@ /** Domain clocks */ /* RM0386, 0390, 0402, 0430 § Dedicated Clock configuration register (RCC_DCKCFGRx) */ -/** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x001 -#define STM32_SRC_PLL_Q 0x002 -#define STM32_SRC_PLL_R 0x003 -/** Fixed clocks */ -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +/** PLL clock outputs */ +#define STM32_SRC_PLL_P (STM32_SRC_LSI + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /** I2S sources */ -#define STM32_SRC_PLLI2S_R 0x007 +#define STM32_SRC_PLLI2S_R (STM32_SRC_PLL_R + 1) /* I2S_CKIN not supported yet */ -/* #define STM32_SRC_I2S_CKIN 0x008 */ +/* #define STM32_SRC_I2S_CKIN TBD */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -76,7 +77,4 @@ /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF - #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32f7_clock.h b/include/zephyr/dt-bindings/clock/stm32f7_clock.h index fd404f1001c..92d3b7e1221 100644 --- a/include/zephyr/dt-bindings/clock/stm32f7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32f7_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /** Bus clocks */ @@ -22,18 +24,18 @@ /** Domain clocks */ /* RM0386, 0390, 0402, 0430 § Dedicated Clock configuration register (RCC_DCKCFGRx) */ -/** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x001 -#define STM32_SRC_PLL_Q 0x002 -#define STM32_SRC_PLL_R 0x003 -/** Fixed clocks */ -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 -#define STM32_SRC_HSI 0x008 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/** PLL clock outputs */ +#define STM32_SRC_PLL_P (STM32_SRC_HSI + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_PLL_R + 1) #define STM32_CLOCK_REG_MASK 0xFFU @@ -100,7 +102,5 @@ #define SDMMC1_SEL(val) STM32_CLOCK(val, 1, 28, DCKCFGR2_REG) #define SDMMC2_SEL(val) STM32_CLOCK(val, 1, 29, DCKCFGR2_REG) #define DSI_SEL(val) STM32_CLOCK(val, 1, 30, DCKCFGR2_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F7_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g0_clock.h b/include/zephyr/dt-bindings/clock/stm32g0_clock.h index 3752a06b9a0..86d93e83d14 100644 --- a/include/zephyr/dt-bindings/clock/stm32g0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_IOP 0x034 #define STM32_CLOCK_BUS_AHB1 0x038 @@ -18,21 +20,20 @@ /** Domain clocks */ /* RM0444, §5.4.21/22 Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_MSI 0x003 -#define STM32_SRC_HSE 0x004 -#define STM32_SRC_LSE 0x005 -#define STM32_SRC_LSI 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) +#define STM32_SRC_HSE (STM32_SRC_MSI + 1) /** Peripheral bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -92,7 +93,5 @@ #define USB_SEL(val) STM32_CLOCK(val, 3, 12, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32g4_clock.h b/include/zephyr/dt-bindings/clock/stm32g4_clock.h index d2720fa0b7f..0cc0b1be2dc 100644 --- a/include/zephyr/dt-bindings/clock/stm32g4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32g4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,21 +22,21 @@ /** Domain clocks */ /* RM0440, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_HSE 0x003 -#define STM32_SRC_LSE 0x004 -#define STM32_SRC_LSI 0x005 -#define STM32_SRC_MSI 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_HSE (STM32_SRC_HSI48 + 1) +#define STM32_SRC_MSI (STM32_SRC_HSE + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -95,7 +97,5 @@ #define QSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32G4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32h5_clock.h b/include/zephyr/dt-bindings/clock/stm32h5_clock.h index c5172c4e6b6..070f3b3aad4 100644 --- a/include/zephyr/dt-bindings/clock/stm32h5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h5_clock.h @@ -6,33 +6,33 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H5_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H5_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0481/0492, Table 47 Kernel clock distribution summary */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_CSI 0x00D -#define STM32_SRC_HSI 0x00E -#define STM32_SRC_HSI48 0x00F - -/** Core clock */ -#define STM32_SRC_SYSCLK 0x011 - +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_CSI (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI (STM32_SRC_CSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_HSI48 + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -#define STM32_SRC_CKPER 0x012 +#define STM32_SRC_CKPER (STM32_SRC_PLL3_R + 1) + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x088 diff --git a/include/zephyr/dt-bindings/clock/stm32h7_clock.h b/include/zephyr/dt-bindings/clock/stm32h7_clock.h index d3507bc2fdb..02ed14f2a7b 100644 --- a/include/zephyr/dt-bindings/clock/stm32h7_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32h7_clock.h @@ -6,34 +6,37 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0468, Table 56 Kernel clock dictribution summary */ +/** System clock */ +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI_KER (STM32_SRC_HSI48 + 1) /* HSI + HSIKERON */ +#define STM32_SRC_CSI_KER (STM32_SRC_HSI_KER + 1) /* CSI + CSIKERON */ /** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 -/** Oscillators */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_HSI48 0x00D -#define STM32_SRC_HSI_KER 0x00E /* HSI + HSIKERON */ -#define STM32_SRC_CSI_KER 0x00F /* CSI + CSIKERON */ -/** Core clock */ -#define STM32_SRC_SYSCLK 0x010 -/** Others: Not yet supported */ -/* #define STM32_SRC_I2SCKIN 0x011 */ -/* #define STM32_SRC_SPDIFRX 0x012 */ +#define STM32_SRC_PLL1_P (STM32_SRC_CSI_KER + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -#define STM32_SRC_CKPER 0x013 +#define STM32_SRC_CKPER (STM32_SRC_PLL3_R + 1) +/** Others: Not yet supported */ +/* #define STM32_SRC_I2SCKIN TBD */ +/* #define STM32_SRC_SPDIFRX TBD */ + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB3 0x0D4 @@ -129,7 +132,5 @@ #define SPI6_SEL(val) STM32_CLOCK(val, 7, 28, D3CCIPR_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specifier when no selection is possible, value may not occur in used RCC regs */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32H7_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l0_clock.h b/include/zephyr/dt-bindings/clock/stm32l0_clock.h index a6e5565a2b5..5c4d80a2b34 100644 --- a/include/zephyr/dt-bindings/clock/stm32l0_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l0_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_IOP 0x02c #define STM32_CLOCK_BUS_AHB1 0x030 @@ -18,16 +20,16 @@ /** Domain clocks */ /* RM0367, §7.3.20 Clock configuration register (RCC_CCIPR) */ -/** Fixed clocks */ -#define STM32_SRC_HSE 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -#define STM32_SRC_HSI 0x004 -#define STM32_SRC_HSI48 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ + +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_HSI48 + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -74,7 +76,5 @@ #define HSI48_SEL(val) STM32_CLOCK(val, 1, 26, CCIPR_REG) /** CSR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 16, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L0_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l1_clock.h b/include/zephyr/dt-bindings/clock/stm32l1_clock.h index ae580af85b4..1dd1fbb90c2 100644 --- a/include/zephyr/dt-bindings/clock/stm32l1_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l1_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus gatting clocks */ #define STM32_CLOCK_BUS_AHB1 0x01c #define STM32_CLOCK_BUS_APB2 0x020 @@ -17,12 +19,11 @@ /** Domain clocks */ /* RM0038.pdf, §6.3.14 Control/status register (RCC_CSR) */ -/** Fixed clocks */ -#define STM32_SRC_HSE 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 /** System clock */ -#define STM32_SRC_SYSCLK 0x004 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -57,7 +58,4 @@ #define RTC_SEL(val) STM32_CLOCK(val, 3, 16, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF - #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L1_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32l4_clock.h b/include/zephyr/dt-bindings/clock/stm32l4_clock.h index 3a042bc34e9..8249a1bf171 100644 --- a/include/zephyr/dt-bindings/clock/stm32l4_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32l4_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,20 +22,19 @@ /** Domain clocks */ /* RM0351/RM0432/RM0438, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 -#define STM32_SRC_MSI 0x005 /** System clock */ -#define STM32_SRC_SYSCLK 0x006 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x007 +#define STM32_SRC_PCLK (STM32_SRC_MSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x008 -#define STM32_SRC_PLL_Q 0x009 -#define STM32_SRC_PLL_R 0x00a +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -101,7 +102,5 @@ #define OSPI_SEL(val) STM32_CLOCK(val, 3, 20, CCIPR2_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32L4_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32u5_clock.h b/include/zephyr/dt-bindings/clock/stm32u5_clock.h index ca4b774d802..6f240fb37b3 100644 --- a/include/zephyr/dt-bindings/clock/stm32u5_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32u5_clock.h @@ -7,32 +7,32 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Domain clocks */ /* RM0468, Table 56 Kernel clock distribution summary */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 -#define STM32_SRC_PLL2_P 0x004 -#define STM32_SRC_PLL2_Q 0x005 -#define STM32_SRC_PLL2_R 0x006 -#define STM32_SRC_PLL3_P 0x007 -#define STM32_SRC_PLL3_Q 0x008 -#define STM32_SRC_PLL3_R 0x009 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x00A -#define STM32_SRC_LSE 0x00B -#define STM32_SRC_LSI 0x00C -#define STM32_SRC_HSI16 0x00D -#define STM32_SRC_HSI48 0x00E -#define STM32_SRC_MSIS 0x00F -#define STM32_SRC_MSIK 0x010 -/** Core clock */ -#define STM32_SRC_SYSCLK 0x011 +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI16 (STM32_SRC_HSE + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI16 + 1) +#define STM32_SRC_MSIS (STM32_SRC_HSI48 + 1) +#define STM32_SRC_MSIK (STM32_SRC_MSIS + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_MSIK + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) +#define STM32_SRC_PLL2_P (STM32_SRC_PLL1_R + 1) +#define STM32_SRC_PLL2_Q (STM32_SRC_PLL2_P + 1) +#define STM32_SRC_PLL2_R (STM32_SRC_PLL2_Q + 1) +#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1) +#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1) +#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1) /** Clock muxes */ -/* #define STM32_SRC_ICLK 0x012 */ +/* #define STM32_SRC_ICLK TBD */ /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x088 @@ -126,10 +126,5 @@ #define ADF1_SEL(val) STM32_CLOCK(val, 7, 16, CCIPR3_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** - * Dummy: Add a specifier when no selection is possible, value may not occur - * in used RCC regs - */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32U5_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wb_clock.h b/include/zephyr/dt-bindings/clock/stm32wb_clock.h index f339f2ac19f..d90b640d2dc 100644 --- a/include/zephyr/dt-bindings/clock/stm32wb_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wb_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -20,21 +22,20 @@ /** Domain clocks */ /* RM0434, § Clock configuration register (RCC_CCIPRx) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_HSI48 0x002 -#define STM32_SRC_LSE 0x003 -#define STM32_SRC_LSI 0x004 -#define STM32_SRC_MSI 0x005 -#define STM32_SRC_HSE 0x006 /** System clock */ -#define STM32_SRC_SYSCLK 0x007 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI48 (STM32_SRC_HSI + 1) +#define STM32_SRC_MSI (STM32_SRC_HSI48 + 1) +#define STM32_SRC_HSE (STM32_SRC_MSI + 1) /** Bus clock */ -#define STM32_SRC_PCLK 0x008 +#define STM32_SRC_PCLK (STM32_SRC_HSE + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x009 -#define STM32_SRC_PLL_Q 0x00a -#define STM32_SRC_PLL_R 0x00b +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) /* TODO: PLLSAI clocks */ #define STM32_CLOCK_REG_MASK 0xFFU @@ -90,7 +91,5 @@ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) /** CSR devices */ #define RFWKP_SEL(val) STM32_CLOCK(val, 3, 14, CSR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WB_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/clock/stm32wba_clock.h b/include/zephyr/dt-bindings/clock/stm32wba_clock.h index 50ec4703e3f..4dc686e8943 100644 --- a/include/zephyr/dt-bindings/clock/stm32wba_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wba_clock.h @@ -6,22 +6,22 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WBA_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Peripheral clock sources */ /* RM0493, Figure 30, clock tree */ -/** PLL outputs */ -#define STM32_SRC_PLL1_P 0x001 -#define STM32_SRC_PLL1_Q 0x002 -#define STM32_SRC_PLL1_R 0x003 +/** System clock */ +/* defined in stm32_common_clocks.h */ /** Fixed clocks */ -#define STM32_SRC_HSE 0x004 -#define STM32_SRC_LSE 0x005 -#define STM32_SRC_LSI 0x006 -#define STM32_SRC_HSI16 0x007 -/** Core clock */ -#define STM32_SRC_SYSCLK 0x08 - +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSE (STM32_SRC_LSI + 1) +#define STM32_SRC_HSI16 (STM32_SRC_HSE + 1) +/** PLL outputs */ +#define STM32_SRC_PLL1_P (STM32_SRC_HSI16 + 1) +#define STM32_SRC_PLL1_Q (STM32_SRC_PLL1_P + 1) +#define STM32_SRC_PLL1_R (STM32_SRC_PLL1_Q + 1) #define STM32_SRC_CLOCK_MIN STM32_SRC_PLL1_P #define STM32_SRC_CLOCK_MAX STM32_SRC_SYSCLK diff --git a/include/zephyr/dt-bindings/clock/stm32wl_clock.h b/include/zephyr/dt-bindings/clock/stm32wl_clock.h index 7bff72937c1..081490d37e1 100644 --- a/include/zephyr/dt-bindings/clock/stm32wl_clock.h +++ b/include/zephyr/dt-bindings/clock/stm32wl_clock.h @@ -6,6 +6,8 @@ #ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ +#include "stm32_common_clocks.h" + /** Bus clocks */ #define STM32_CLOCK_BUS_AHB1 0x048 #define STM32_CLOCK_BUS_AHB2 0x04c @@ -21,19 +23,19 @@ /** Domain clocks */ /* RM0461, §6.4.29 Clock configuration register (RCC_CFGR3) */ -/** Fixed clocks */ -#define STM32_SRC_HSI 0x001 -#define STM32_SRC_LSE 0x002 -#define STM32_SRC_LSI 0x003 -/* #define STM32_SRC_HSI48 0x004 */ + /** System clock */ -#define STM32_SRC_SYSCLK 0x005 +/* defined in stm32_common_clocks.h */ +/** Fixed clocks */ +/* Low speed clocks defined in stm32_common_clocks.h */ +#define STM32_SRC_HSI (STM32_SRC_LSI + 1) +/* #define STM32_SRC_HSI48 TBD */ /** Bus clock */ -#define STM32_SRC_PCLK 0x006 +#define STM32_SRC_PCLK (STM32_SRC_HSI + 1) /** PLL clock outputs */ -#define STM32_SRC_PLL_P 0x007 -#define STM32_SRC_PLL_Q 0x008 -#define STM32_SRC_PLL_R 0x009 +#define STM32_SRC_PLL_P (STM32_SRC_PCLK + 1) +#define STM32_SRC_PLL_Q (STM32_SRC_PLL_P + 1) +#define STM32_SRC_PLL_R (STM32_SRC_PLL_Q + 1) #define STM32_CLOCK_REG_MASK 0xFFU #define STM32_CLOCK_REG_SHIFT 0U @@ -85,7 +87,5 @@ #define RNG_SEL(val) STM32_CLOCK(val, 3, 30, CCIPR_REG) /** BDCR devices */ #define RTC_SEL(val) STM32_CLOCK(val, 3, 8, BDCR_REG) -/** Dummy: Add a specificier when no selection is possible */ -#define NO_SEL 0xFF #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32WL_CLOCK_H_ */ diff --git a/include/zephyr/dt-bindings/ethernet/nxp_enet.h b/include/zephyr/dt-bindings/ethernet/nxp_enet.h new file mode 100644 index 00000000000..e084825da4c --- /dev/null +++ b/include/zephyr/dt-bindings/ethernet/nxp_enet.h @@ -0,0 +1,14 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ + +#define NXP_ENET_MII_MODE 0 +#define NXP_ENET_RMII_MODE 1 +#define NXP_ENET_INVALID_MII_MODE 100 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_NXP_ENET_H_ */ diff --git a/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h b/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h new file mode 100644 index 00000000000..83a8035551f --- /dev/null +++ b/include/zephyr/dt-bindings/input/esp32-touch-sensor-input.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ + +#include + +/* Touch sensor IIR filter mode */ +#define ESP32_TOUCH_FILTER_MODE_IIR_4 0 +#define ESP32_TOUCH_FILTER_MODE_IIR_8 1 +#define ESP32_TOUCH_FILTER_MODE_IIR_16 2 +#define ESP32_TOUCH_FILTER_MODE_IIR_32 3 +#define ESP32_TOUCH_FILTER_MODE_IIR_64 4 +#define ESP32_TOUCH_FILTER_MODE_IIR_128 5 +#define ESP32_TOUCH_FILTER_MODE_IIR_256 6 +#define ESP32_TOUCH_FILTER_MODE_JITTER 7 + +/* Touch sensor level of filter noise threshold coefficient*/ +#define ESP32_TOUCH_FILTER_NOISE_THR_4_8TH 0 +#define ESP32_TOUCH_FILTER_NOISE_THR_3_8TH 1 +#define ESP32_TOUCH_FILTER_NOISE_THR_2_8TH 2 +#define ESP32_TOUCH_FILTER_NOISE_THR_8_8TH 3 + +/* Touch sensor level of filter applied on the original data */ +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_OFF 0 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_2 1 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_4 2 +#define ESP32_TOUCH_FILTER_SMOOTH_MODE_IIR_8 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_ESP32_TOUCH_SENSOR_INPUT_H_ */ diff --git a/include/zephyr/dt-bindings/input/input-event-codes.h b/include/zephyr/dt-bindings/input/input-event-codes.h index 73d5f49b9bb..34dd00f8514 100644 --- a/include/zephyr/dt-bindings/input/input-event-codes.h +++ b/include/zephyr/dt-bindings/input/input-event-codes.h @@ -35,6 +35,8 @@ * @anchor INPUT_KEY_CODES * @{ */ +#define INPUT_KEY_RESERVED 0 /**< Reserved, do not use */ + #define INPUT_KEY_0 11 /**< 0 Key */ #define INPUT_KEY_1 2 /**< 1 Key */ #define INPUT_KEY_2 3 /**< 2 Key */ @@ -117,10 +119,12 @@ #define INPUT_KEY_KPASTERISK 55 /**< Keypad Asterisk Key */ #define INPUT_KEY_KPCOMMA 121 /**< Keypad Comma Key */ #define INPUT_KEY_KPDOT 83 /**< Keypad Dot Key */ +#define INPUT_KEY_KPENTER 96 /**< Keypad Enter Key */ #define INPUT_KEY_KPEQUAL 117 /**< Keypad Equal Key */ #define INPUT_KEY_KPMINUS 74 /**< Keypad Minus Key */ #define INPUT_KEY_KPPLUS 78 /**< Keypad Plus Key */ #define INPUT_KEY_KPPLUSMINUS 118 /**< Keypad Plus Key */ +#define INPUT_KEY_KPSLASH 98 /**< Keypad Slash Key */ #define INPUT_KEY_L 38 /**< L Key */ #define INPUT_KEY_LEFT 105 /**< Left Key */ #define INPUT_KEY_LEFTALT 56 /**< Left Alt Key */ @@ -145,7 +149,9 @@ #define INPUT_KEY_Q 16 /**< Q Key */ #define INPUT_KEY_R 19 /**< R Key */ #define INPUT_KEY_RIGHT 106 /**< Right Key */ +#define INPUT_KEY_RIGHTALT 100 /**< Right Alt Key */ #define INPUT_KEY_RIGHTBRACE 27 /**< Right Brace Key */ +#define INPUT_KEY_RIGHTCTRL 97 /**< Right Ctrl Key */ #define INPUT_KEY_RIGHTMETA 126 /**< Right Meta Key */ #define INPUT_KEY_RIGHTSHIFT 54 /**< Right Shift Key */ #define INPUT_KEY_S 31 /**< S Key */ @@ -155,6 +161,7 @@ #define INPUT_KEY_SLASH 53 /**< Slash Key */ #define INPUT_KEY_SLEEP 142 /**< System Sleep Key */ #define INPUT_KEY_SPACE 57 /**< Space Key */ +#define INPUT_KEY_SYSRQ 99 /**< SysReq Key */ #define INPUT_KEY_T 20 /**< T Key */ #define INPUT_KEY_TAB 15 /**< Tab Key*/ #define INPUT_KEY_U 22 /**< U Key */ diff --git a/include/zephyr/dt-bindings/input/keymap.h b/include/zephyr/dt-bindings/input/keymap.h new file mode 100644 index 00000000000..65d4b108b03 --- /dev/null +++ b/include/zephyr/dt-bindings/input/keymap.h @@ -0,0 +1,13 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ + +#define MATRIX_KEY(row, col, code) \ + ((((row) & 0xff) << 24) | (((col) & 0xff) << 16) | ((code) & 0xffff)) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INPUT_KEYMAP_H_ */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h b/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h index 77372b76e21..4df6bfeae52 100644 --- a/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h +++ b/include/zephyr/dt-bindings/interrupt-controller/renesas-ra-icu.h @@ -70,123 +70,124 @@ #define RA_ICU_IIC1_EEI (61 << 8) #define RA_ICU_SSIE0_SSITXI (62 << 8) #define RA_ICU_SSIE0_SSIRXI (63 << 8) -#define RA_ICU_SSIE0_SSIF (64 << 8) -#define RA_ICU_CTSU_CTSUWR (65 << 8) -#define RA_ICU_CTSU_CTSURD (66 << 8) -#define RA_ICU_CTSU_CTSUFN (67 << 8) -#define RA_ICU_KEY_INTKR (68 << 8) -#define RA_ICU_DOC_DOPCI (69 << 8) -#define RA_ICU_CAC_FERRI (70 << 8) -#define RA_ICU_CAC_MENDI (71 << 8) -#define RA_ICU_CAC_OVFI (72 << 8) -#define RA_ICU_CAN0_ERS (73 << 8) -#define RA_ICU_CAN0_RXF (74 << 8) -#define RA_ICU_CAN0_TXF (75 << 8) -#define RA_ICU_CAN0_RXM (76 << 8) -#define RA_ICU_CAN0_TXM (77 << 8) -#define RA_ICU_IOPORT_GROUP1 (78 << 8) -#define RA_ICU_IOPORT_GROUP2 (79 << 8) -#define RA_ICU_IOPORT_GROUP3 (80 << 8) -#define RA_ICU_IOPORT_GROUP4 (81 << 8) -#define RA_ICU_ELC_SWEVT0 (82 << 8) -#define RA_ICU_ELC_SWEVT1 (83 << 8) -#define RA_ICU_POEG_GROUP0 (84 << 8) -#define RA_ICU_POEG_GROUP1 (85 << 8) -#define RA_ICU_GPT0_CCMPA (86 << 8) -#define RA_ICU_GPT0_CCMPB (87 << 8) -#define RA_ICU_GPT0_CMPC (88 << 8) -#define RA_ICU_GPT0_CMPD (89 << 8) -#define RA_ICU_GPT0_CMPE (90 << 8) -#define RA_ICU_GPT0_CMPF (91 << 8) -#define RA_ICU_GPT0_OVF (92 << 8) -#define RA_ICU_GPT0_UDF (93 << 8) -#define RA_ICU_GPT1_CCMPA (94 << 8) -#define RA_ICU_GPT1_CCMPB (95 << 8) -#define RA_ICU_GPT1_CMPC (96 << 8) -#define RA_ICU_GPT1_CMPD (97 << 8) -#define RA_ICU_GPT1_CMPE (98 << 8) -#define RA_ICU_GPT1_CMPF (99 << 8) -#define RA_ICU_GPT1_OVF (100 << 8) -#define RA_ICU_GPT1_UDF (101 << 8) -#define RA_ICU_GPT2_CCMPA (102 << 8) -#define RA_ICU_GPT2_CCMPB (103 << 8) -#define RA_ICU_GPT2_CMPC (104 << 8) -#define RA_ICU_GPT2_CMPD (105 << 8) -#define RA_ICU_GPT2_CMPE (106 << 8) -#define RA_ICU_GPT2_CMPF (107 << 8) -#define RA_ICU_GPT2_OVF (108 << 8) -#define RA_ICU_GPT2_UDF (109 << 8) -#define RA_ICU_GPT3_CCMPA (110 << 8) -#define RA_ICU_GPT3_CCMPB (111 << 8) -#define RA_ICU_GPT3_CMPC (112 << 8) -#define RA_ICU_GPT3_CMPD (113 << 8) -#define RA_ICU_GPT3_CMPE (114 << 8) -#define RA_ICU_GPT3_CMPF (115 << 8) -#define RA_ICU_GPT3_OVF (116 << 8) -#define RA_ICU_GPT3_UDF (117 << 8) -#define RA_ICU_GPT4_CCMPA (118 << 8) -#define RA_ICU_GPT4_CCMPB (119 << 8) -#define RA_ICU_GPT4_CMPC (120 << 8) -#define RA_ICU_GPT4_CMPD (121 << 8) -#define RA_ICU_GPT4_CMPE (122 << 8) -#define RA_ICU_GPT4_CMPF (123 << 8) -#define RA_ICU_GPT4_OVF (124 << 8) -#define RA_ICU_GPT4_UDF (125 << 8) -#define RA_ICU_GPT5_CCMPA (126 << 8) -#define RA_ICU_GPT5_CCMPB (127 << 8) -#define RA_ICU_GPT5_CMPC (128 << 8) -#define RA_ICU_GPT5_CMPD (129 << 8) -#define RA_ICU_GPT5_CMPE (130 << 8) -#define RA_ICU_GPT5_CMPF (131 << 8) -#define RA_ICU_GPT5_OVF (132 << 8) -#define RA_ICU_GPT5_UDF (133 << 8) -#define RA_ICU_GPT6_CCMPA (134 << 8) -#define RA_ICU_GPT6_CCMPB (135 << 8) -#define RA_ICU_GPT6_CMPC (136 << 8) -#define RA_ICU_GPT6_CMPD (137 << 8) -#define RA_ICU_GPT6_CMPE (138 << 8) -#define RA_ICU_GPT6_CMPF (139 << 8) -#define RA_ICU_GPT6_OVF (140 << 8) -#define RA_ICU_GPT6_UDF (141 << 8) -#define RA_ICU_GPT7_CCMPA (142 << 8) -#define RA_ICU_GPT7_CCMPB (143 << 8) -#define RA_ICU_GPT7_CMPC (144 << 8) -#define RA_ICU_GPT7_CMPD (145 << 8) -#define RA_ICU_GPT7_CMPE (146 << 8) -#define RA_ICU_GPT7_CMPF (147 << 8) -#define RA_ICU_GPT7_OVF (148 << 8) -#define RA_ICU_GPT7_UDF (149 << 8) -#define RA_ICU_GPT_UVWEDGE (150 << 8) -#define RA_ICU_SCI0_RXI (151 << 8) -#define RA_ICU_SCI0_TXI (152 << 8) -#define RA_ICU_SCI0_TEI (153 << 8) -#define RA_ICU_SCI0_ERI (154 << 8) -#define RA_ICU_SCI0_AM (155 << 8) -#define RA_ICU_SCI0_RXI_OR_ERI (156 << 8) -#define RA_ICU_SCI1_RXI (157 << 8) -#define RA_ICU_SCI1_TXI (158 << 8) -#define RA_ICU_SCI1_TEI (159 << 8) -#define RA_ICU_SCI1_ERI (160 << 8) -#define RA_ICU_SCI1_AM (161 << 8) -#define RA_ICU_SCI2_RXI (162 << 8) -#define RA_ICU_SCI2_TXI (163 << 8) -#define RA_ICU_SCI2_TEI (164 << 8) -#define RA_ICU_SCI2_ERI (165 << 8) -#define RA_ICU_SCI2_AM (166 << 8) -#define RA_ICU_SCI9_RXI (167 << 8) -#define RA_ICU_SCI9_TXI (168 << 8) -#define RA_ICU_SCI9_TEI (169 << 8) -#define RA_ICU_SCI9_ERI (170 << 8) -#define RA_ICU_SCI9_AM (171 << 8) -#define RA_ICU_SPI0_SPRI (172 << 8) -#define RA_ICU_SPI0_SPTI (173 << 8) -#define RA_ICU_SPI0_SPII (174 << 8) -#define RA_ICU_SPI0_SPEI (175 << 8) -#define RA_ICU_SPI0_SPTEND (176 << 8) -#define RA_ICU_SPI1_SPRI (177 << 8) -#define RA_ICU_SPI1_SPTI (178 << 8) -#define RA_ICU_SPI1_SPII (179 << 8) -#define RA_ICU_SPI1_SPEI (180 << 8) -#define RA_ICU_SPI1_SPTEND (181 << 8) + +#define RA_ICU_SSIE0_SSIF (65 << 8) +#define RA_ICU_CTSU_CTSUWR (66 << 8) +#define RA_ICU_CTSU_CTSURD (67 << 8) +#define RA_ICU_CTSU_CTSUFN (68 << 8) +#define RA_ICU_KEY_INTKR (69 << 8) +#define RA_ICU_DOC_DOPCI (70 << 8) +#define RA_ICU_CAC_FERRI (71 << 8) +#define RA_ICU_CAC_MENDI (72 << 8) +#define RA_ICU_CAC_OVFI (73 << 8) +#define RA_ICU_CAN0_ERS (74 << 8) +#define RA_ICU_CAN0_RXF (75 << 8) +#define RA_ICU_CAN0_TXF (76 << 8) +#define RA_ICU_CAN0_RXM (77 << 8) +#define RA_ICU_CAN0_TXM (78 << 8) +#define RA_ICU_IOPORT_GROUP1 (70 << 8) +#define RA_ICU_IOPORT_GROUP2 (80 << 8) +#define RA_ICU_IOPORT_GROUP3 (81 << 8) +#define RA_ICU_IOPORT_GROUP4 (82 << 8) +#define RA_ICU_ELC_SWEVT0 (83 << 8) +#define RA_ICU_ELC_SWEVT1 (84 << 8) +#define RA_ICU_POEG_GROUP0 (85 << 8) +#define RA_ICU_POEG_GROUP1 (86 << 8) +#define RA_ICU_GPT0_CCMPA (87 << 8) +#define RA_ICU_GPT0_CCMPB (88 << 8) +#define RA_ICU_GPT0_CMPC (89 << 8) +#define RA_ICU_GPT0_CMPD (90 << 8) +#define RA_ICU_GPT0_CMPE (91 << 8) +#define RA_ICU_GPT0_CMPF (92 << 8) +#define RA_ICU_GPT0_OVF (93 << 8) +#define RA_ICU_GPT0_UDF (94 << 8) +#define RA_ICU_GPT1_CCMPA (95 << 8) +#define RA_ICU_GPT1_CCMPB (96 << 8) +#define RA_ICU_GPT1_CMPC (97 << 8) +#define RA_ICU_GPT1_CMPD (98 << 8) +#define RA_ICU_GPT1_CMPE (99 << 8) +#define RA_ICU_GPT1_CMPF (100 << 8) +#define RA_ICU_GPT1_OVF (101 << 8) +#define RA_ICU_GPT1_UDF (102 << 8) +#define RA_ICU_GPT2_CCMPA (103 << 8) +#define RA_ICU_GPT2_CCMPB (104 << 8) +#define RA_ICU_GPT2_CMPC (105 << 8) +#define RA_ICU_GPT2_CMPD (106 << 8) +#define RA_ICU_GPT2_CMPE (107 << 8) +#define RA_ICU_GPT2_CMPF (108 << 8) +#define RA_ICU_GPT2_OVF (109 << 8) +#define RA_ICU_GPT2_UDF (110 << 8) +#define RA_ICU_GPT3_CCMPA (111 << 8) +#define RA_ICU_GPT3_CCMPB (112 << 8) +#define RA_ICU_GPT3_CMPC (113 << 8) +#define RA_ICU_GPT3_CMPD (114 << 8) +#define RA_ICU_GPT3_CMPE (115 << 8) +#define RA_ICU_GPT3_CMPF (116 << 8) +#define RA_ICU_GPT3_OVF (117 << 8) +#define RA_ICU_GPT3_UDF (118 << 8) +#define RA_ICU_GPT4_CCMPA (119 << 8) +#define RA_ICU_GPT4_CCMPB (120 << 8) +#define RA_ICU_GPT4_CMPC (121 << 8) +#define RA_ICU_GPT4_CMPD (122 << 8) +#define RA_ICU_GPT4_CMPE (123 << 8) +#define RA_ICU_GPT4_CMPF (124 << 8) +#define RA_ICU_GPT4_OVF (125 << 8) +#define RA_ICU_GPT4_UDF (126 << 8) +#define RA_ICU_GPT5_CCMPA (127 << 8) +#define RA_ICU_GPT5_CCMPB (128 << 8) +#define RA_ICU_GPT5_CMPC (129 << 8) +#define RA_ICU_GPT5_CMPD (130 << 8) +#define RA_ICU_GPT5_CMPE (131 << 8) +#define RA_ICU_GPT5_CMPF (132 << 8) +#define RA_ICU_GPT5_OVF (133 << 8) +#define RA_ICU_GPT5_UDF (134 << 8) +#define RA_ICU_GPT6_CCMPA (135 << 8) +#define RA_ICU_GPT6_CCMPB (136 << 8) +#define RA_ICU_GPT6_CMPC (137 << 8) +#define RA_ICU_GPT6_CMPD (138 << 8) +#define RA_ICU_GPT6_CMPE (139 << 8) +#define RA_ICU_GPT6_CMPF (140 << 8) +#define RA_ICU_GPT6_OVF (141 << 8) +#define RA_ICU_GPT6_UDF (142 << 8) +#define RA_ICU_GPT7_CCMPA (143 << 8) +#define RA_ICU_GPT7_CCMPB (144 << 8) +#define RA_ICU_GPT7_CMPC (145 << 8) +#define RA_ICU_GPT7_CMPD (146 << 8) +#define RA_ICU_GPT7_CMPE (147 << 8) +#define RA_ICU_GPT7_CMPF (148 << 8) +#define RA_ICU_GPT7_OVF (149 << 8) +#define RA_ICU_GPT7_UDF (150 << 8) +#define RA_ICU_GPT_UVWEDGE (151 << 8) +#define RA_ICU_SCI0_RXI (152 << 8) +#define RA_ICU_SCI0_TXI (153 << 8) +#define RA_ICU_SCI0_TEI (154 << 8) +#define RA_ICU_SCI0_ERI (155 << 8) +#define RA_ICU_SCI0_AM (156 << 8) +#define RA_ICU_SCI0_RXI_OR_ERI (157 << 8) +#define RA_ICU_SCI1_RXI (158 << 8) +#define RA_ICU_SCI1_TXI (159 << 8) +#define RA_ICU_SCI1_TEI (160 << 8) +#define RA_ICU_SCI1_ERI (161 << 8) +#define RA_ICU_SCI1_AM (162 << 8) +#define RA_ICU_SCI2_RXI (163 << 8) +#define RA_ICU_SCI2_TXI (164 << 8) +#define RA_ICU_SCI2_TEI (165 << 8) +#define RA_ICU_SCI2_ERI (166 << 8) +#define RA_ICU_SCI2_AM (167 << 8) +#define RA_ICU_SCI9_RXI (168 << 8) +#define RA_ICU_SCI9_TXI (169 << 8) +#define RA_ICU_SCI9_TEI (170 << 8) +#define RA_ICU_SCI9_ERI (171 << 8) +#define RA_ICU_SCI9_AM (172 << 8) +#define RA_ICU_SPI0_SPRI (173 << 8) +#define RA_ICU_SPI0_SPTI (174 << 8) +#define RA_ICU_SPI0_SPII (175 << 8) +#define RA_ICU_SPI0_SPEI (176 << 8) +#define RA_ICU_SPI0_SPTEND (177 << 8) +#define RA_ICU_SPI1_SPRI (178 << 8) +#define RA_ICU_SPI1_SPTI (179 << 8) +#define RA_ICU_SPI1_SPII (180 << 8) +#define RA_ICU_SPI1_SPEI (181 << 8) +#define RA_ICU_SPI1_SPTEND (182 << 8) #endif /* ZEPHYR_DT_BINDINGS_INTERRUPT_CONTROLLER_RENESAS_RA_ICU_H_ */ diff --git a/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h b/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h new file mode 100644 index 00000000000..e723227a022 --- /dev/null +++ b/include/zephyr/dt-bindings/led/worldsemi_ws2812c.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Martin Kiepfer + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DT_LED_WS2812C_H_ +#define ZEPHYR_DT_LED_WS2812C_H_ + +/* + * At 7 MHz: 1 bit in 142.86 ns + * 1090 ns -> 7.6 bits + * 300 ns -> 2.1 bits + * 790 ns -> 5.5 bits + */ +#define WS2812C_SPI_FREQ (7000000U) +#define WS2812C_ZERO_FRAME (0xC0U) +#define WS2812C_ONE_FRAME (0xFCU) + +#endif diff --git a/include/zephyr/dt-bindings/lvgl/lvgl.h b/include/zephyr/dt-bindings/lvgl/lvgl.h new file mode 100644 index 00000000000..09ad0ae361b --- /dev/null +++ b/include/zephyr/dt-bindings/lvgl/lvgl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ + +/* Predefined keys to control the focused object. + * Values taken from enum _lv_key_t in lv_group.h + */ +#define LV_KEY_UP 17 +#define LV_KEY_DOWN 18 +#define LV_KEY_RIGHT 19 +#define LV_KEY_LEFT 20 +#define LV_KEY_ESC 27 +#define LV_KEY_DEL 127 +#define LV_KEY_BACKSPACE 8 +#define LV_KEY_ENTER 10 +#define LV_KEY_NEXT 9 +#define LV_KEY_PREV 11 +#define LV_KEY_HOME 2 +#define LV_KEY_END 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ */ diff --git a/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h b/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h new file mode 100644 index 00000000000..ccd47addf11 --- /dev/null +++ b/include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ + +#include +#include + +/* + * Software specific memory attributes. + */ +#define DT_MEM_SW_MASK DT_MEM_SW_ATTR_MASK +#define DT_MEM_SW_GET(x) ((x) & DT_MEM_SW_ATTR_MASK) +#define DT_MEM_SW(x) ((x) << DT_MEM_SW_ATTR_SHIFT) + +#define ATTR_SW_ALLOC_CACHE BIT(0) +#define ATTR_SW_ALLOC_NON_CACHE BIT(1) +#define ATTR_SW_ALLOC_DMA BIT(2) + +#define DT_MEM_SW_ALLOC_CACHE DT_MEM_SW(ATTR_SW_ALLOC_CACHE) +#define DT_MEM_SW_ALLOC_NON_CACHE DT_MEM_SW(ATTR_SW_ALLOC_NON_CACHE) +#define DT_MEM_SW_ALLOC_DMA DT_MEM_SW(ATTR_SW_ALLOC_DMA) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ */ diff --git a/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h b/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h new file mode 100644 index 00000000000..60b788a3516 --- /dev/null +++ b/include/zephyr/dt-bindings/misc/nordic-nrf-ficr-nrf54h20-enga.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/* autogenerated using Nordic HAL utils/gen_offsets.py script */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ + +#define NRF_FICR_BLE_ADDRTYPE 0x00CU +#define NRF_FICR_BLE_ADDR_0 0x010U +#define NRF_FICR_BLE_ADDR_1 0x014U +#define NRF_FICR_BLE_ER_0 0x018U +#define NRF_FICR_BLE_ER_1 0x01CU +#define NRF_FICR_BLE_ER_2 0x020U +#define NRF_FICR_BLE_ER_3 0x024U +#define NRF_FICR_BLE_IR_0 0x028U +#define NRF_FICR_BLE_IR_1 0x02CU +#define NRF_FICR_BLE_IR_2 0x030U +#define NRF_FICR_BLE_IR_3 0x034U +#define NRF_FICR_NFC_TAGHEADER_0 0x040U +#define NRF_FICR_NFC_TAGHEADER_1 0x044U +#define NRF_FICR_NFC_TAGHEADER_2 0x048U +#define NRF_FICR_NFC_TAGHEADER_3 0x04CU +#define NRF_FICR_INFO_CONFIGID 0x050U +#define NRF_FICR_INFO_PART 0x054U +#define NRF_FICR_INFO_VARIANT 0x058U +#define NRF_FICR_INFO_PACKAGE 0x05CU +#define NRF_FICR_INFO_RAM 0x060U +#define NRF_FICR_INFO_MRAM 0x064U +#define NRF_FICR_INFO_CODEPAGESIZE 0x068U +#define NRF_FICR_INFO_CODESIZE 0x06CU +#define NRF_FICR_INFO_DEVICETYPE 0x070U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALVREF 0x384U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_0 0x388U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_1 0x38CU +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALGAIN_2 0x390U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALOFFSET 0x394U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_0 0x398U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_1 0x39CU +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_2 0x3A0U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_3 0x3A4U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_4 0x3A8U +#define NRF_FICR_TRIM_GLOBAL_SAADC_LINCALCOEFF_5 0x3ACU +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALIREF 0x3B0U +#define NRF_FICR_TRIM_GLOBAL_SAADC_CALVREFTC 0x3B4U +#define NRF_FICR_TRIM_GLOBAL_NFCT_BIASCFG 0x3BCU +#define NRF_FICR_TRIM_GLOBAL_CANPLL_TRIM_CTUNE 0x3C0U +#define NRF_FICR_TRIM_GLOBAL_COMP_REFTRIM 0x3D0U +#define NRF_FICR_TRIM_GLOBAL_COMP_RCALTRIM 0x3D4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_VSUP 0x3D8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_0 0x3DCU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_1 0x3E0U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_2 0x3E4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_3 0x3E8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_4 0x3ECU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_COARSE_5 0x3F0U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_0 0x3F4U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_1 0x3F8U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_2 0x3FCU +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_3 0x400U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_4 0x404U +#define NRF_FICR_TRIM_APPLICATION_HSFLL_TRIM_FINE_5 0x408U +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_0_TRIM 0x40CU +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_1_TRIM 0x410U +#define NRF_FICR_TRIM_APPLICATION_MEMCONF_BLOCKTYPE_2_TRIM 0x414U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_VSUP 0x418U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_0 0x41CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_1 0x420U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_2 0x424U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_3 0x428U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_4 0x42CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_COARSE_5 0x430U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_0 0x434U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_1 0x438U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_2 0x43CU +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_3 0x440U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_4 0x444U +#define NRF_FICR_TRIM_RADIOCORE_HSFLL_TRIM_FINE_5 0x448U +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_0_TRIM 0x44CU +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_1_TRIM 0x450U +#define NRF_FICR_TRIM_RADIOCORE_MEMCONF_BLOCKTYPE_2_TRIM 0x454U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL0 0x458U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL1 0x45CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_FSCTRL2 0x460U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_RXCTRL 0x464U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_SPHYNXANA_OVRRXTRIMCODE 0x468U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_RXAGC_CALIBRATION 0x46CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_PVTTOT 0x470U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_KDTC 0x474U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_TXHFGAIN 0x478U +#define NRF_FICR_TRIM_RADIOCORE_RADIO_PVTTOFIX 0x47CU +#define NRF_FICR_TRIM_RADIOCORE_RADIO_LOOPGAIN 0x480U + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MISC_NORDIC_NRF_FICR_NRF54H20_ENGA_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h new file mode 100644 index 00000000000..b961c27facf --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32-pinctrl.h @@ -0,0 +1,11363 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ + +/* DAC_CH1 */ +#define DAC_CH1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_DAC1_OUT) + +/* DAC_CH2 */ +#define DAC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_DAC2_OUT) + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO22 \ + ESP32_PINMUX(22, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO23 \ + ESP32_PINMUX(23, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO25 \ + ESP32_PINMUX(25, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH10 */ +#define LEDC_CH10_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +#define LEDC_CH10_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT2) + +/* LEDC_CH11 */ +#define LEDC_CH11_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +#define LEDC_CH11_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT3) + +/* LEDC_CH12 */ +#define LEDC_CH12_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +#define LEDC_CH12_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT4) + +/* LEDC_CH13 */ +#define LEDC_CH13_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +#define LEDC_CH13_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT5) + +/* LEDC_CH14 */ +#define LEDC_CH14_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +#define LEDC_CH14_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT6) + +/* LEDC_CH15 */ +#define LEDC_CH15_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +#define LEDC_CH15_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT7) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* LEDC_CH8 */ +#define LEDC_CH8_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +#define LEDC_CH8_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT0) + +/* LEDC_CH9 */ +#define LEDC_CH9_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +#define LEDC_CH9_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_HS_SIG_OUT1) + +/* MCPWM0_CAP0 */ +#define MCPWM0_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +/* MCPWM0_CAP1 */ +#define MCPWM0_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +/* MCPWM0_CAP2 */ +#define MCPWM0_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +/* MCPWM0_FAULT0 */ +#define MCPWM0_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F0_IN, ESP_NOSIG) + +/* MCPWM0_FAULT1 */ +#define MCPWM0_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F1_IN, ESP_NOSIG) + +/* MCPWM0_FAULT2 */ +#define MCPWM0_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F2_IN, ESP_NOSIG) + +/* MCPWM0_OUT0A */ +#define MCPWM0_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0A) + +/* MCPWM0_OUT0B */ +#define MCPWM0_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0B) + +/* MCPWM0_OUT1A */ +#define MCPWM0_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1A) + +/* MCPWM0_OUT1B */ +#define MCPWM0_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1B) + +/* MCPWM0_OUT2A */ +#define MCPWM0_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2A) + +/* MCPWM0_OUT2B */ +#define MCPWM0_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2B) + +/* MCPWM0_SYNC0 */ +#define MCPWM0_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +/* MCPWM0_SYNC1 */ +#define MCPWM0_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +/* MCPWM0_SYNC2 */ +#define MCPWM0_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +/* MCPWM1_CAP0 */ +#define MCPWM1_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +/* MCPWM1_CAP1 */ +#define MCPWM1_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +/* MCPWM1_CAP2 */ +#define MCPWM1_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +/* MCPWM1_FAULT0 */ +#define MCPWM1_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F0_IN, ESP_NOSIG) + +/* MCPWM1_FAULT1 */ +#define MCPWM1_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F1_IN, ESP_NOSIG) + +/* MCPWM1_FAULT2 */ +#define MCPWM1_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F2_IN, ESP_NOSIG) + +/* MCPWM1_OUT0A */ +#define MCPWM1_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0A) + +/* MCPWM1_OUT0B */ +#define MCPWM1_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0B) + +/* MCPWM1_OUT1A */ +#define MCPWM1_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1A) + +/* MCPWM1_OUT1B */ +#define MCPWM1_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1B) + +/* MCPWM1_OUT2A */ +#define MCPWM1_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2A) + +/* MCPWM1_OUT2B */ +#define MCPWM1_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2B) + +/* MCPWM1_SYNC0 */ +#define MCPWM1_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +/* MCPWM1_SYNC1 */ +#define MCPWM1_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +/* MCPWM1_SYNC2 */ +#define MCPWM1_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO22 \ + ESP32_PINMUX(22, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO23 \ + ESP32_PINMUX(23, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO25 \ + ESP32_PINMUX(25, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* PCNT4_CH0CTRL */ +#define PCNT4_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN4, ESP_NOSIG) + +/* PCNT4_CH0SIG */ +#define PCNT4_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +#define PCNT4_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN4, ESP_NOSIG) + +/* PCNT4_CH1CTRL */ +#define PCNT4_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN4, ESP_NOSIG) + +/* PCNT4_CH1SIG */ +#define PCNT4_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +#define PCNT4_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN4, ESP_NOSIG) + +/* PCNT5_CH0CTRL */ +#define PCNT5_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN5, ESP_NOSIG) + +/* PCNT5_CH0SIG */ +#define PCNT5_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +#define PCNT5_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN5, ESP_NOSIG) + +/* PCNT5_CH1CTRL */ +#define PCNT5_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN5, ESP_NOSIG) + +/* PCNT5_CH1SIG */ +#define PCNT5_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +#define PCNT5_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN5, ESP_NOSIG) + +/* PCNT6_CH0CTRL */ +#define PCNT6_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN6, ESP_NOSIG) + +/* PCNT6_CH0SIG */ +#define PCNT6_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +#define PCNT6_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN6, ESP_NOSIG) + +/* PCNT6_CH1CTRL */ +#define PCNT6_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN6, ESP_NOSIG) + +/* PCNT6_CH1SIG */ +#define PCNT6_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +#define PCNT6_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN6, ESP_NOSIG) + +/* PCNT7_CH0CTRL */ +#define PCNT7_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN7, ESP_NOSIG) + +/* PCNT7_CH0SIG */ +#define PCNT7_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +#define PCNT7_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN7, ESP_NOSIG) + +/* PCNT7_CH1CTRL */ +#define PCNT7_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN7, ESP_NOSIG) + +/* PCNT7_CH1SIG */ +#define PCNT7_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO22 \ + ESP32_PINMUX(22, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO23 \ + ESP32_PINMUX(23, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO25 \ + ESP32_PINMUX(25, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +#define PCNT7_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN7, ESP_NOSIG) + +/* SMI_MDC */ +#define SMI_MDC_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_EMAC_MDC_O) + +#define SMI_MDC_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_EMAC_MDC_O) + +/* SMI_MDIO */ +#define SMI_MDIO_GPIO0 \ + ESP32_PINMUX(0, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO1 \ + ESP32_PINMUX(1, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO2 \ + ESP32_PINMUX(2, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO3 \ + ESP32_PINMUX(3, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO4 \ + ESP32_PINMUX(4, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO5 \ + ESP32_PINMUX(5, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO6 \ + ESP32_PINMUX(6, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO7 \ + ESP32_PINMUX(7, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO8 \ + ESP32_PINMUX(8, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO9 \ + ESP32_PINMUX(9, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO10 \ + ESP32_PINMUX(10, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO11 \ + ESP32_PINMUX(11, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO12 \ + ESP32_PINMUX(12, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO13 \ + ESP32_PINMUX(13, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO14 \ + ESP32_PINMUX(14, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO15 \ + ESP32_PINMUX(15, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO16 \ + ESP32_PINMUX(16, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO17 \ + ESP32_PINMUX(17, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO18 \ + ESP32_PINMUX(18, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO19 \ + ESP32_PINMUX(19, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO20 \ + ESP32_PINMUX(20, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO21 \ + ESP32_PINMUX(21, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO22 \ + ESP32_PINMUX(22, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO23 \ + ESP32_PINMUX(23, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO25 \ + ESP32_PINMUX(25, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO26 \ + ESP32_PINMUX(26, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO27 \ + ESP32_PINMUX(27, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO32 \ + ESP32_PINMUX(32, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +#define SMI_MDIO_GPIO33 \ + ESP32_PINMUX(33, ESP_EMAC_MDI_I, ESP_EMAC_MDO_O) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICS2_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO22 \ + ESP32_PINMUX(22, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO23 \ + ESP32_PINMUX(23, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO25 \ + ESP32_PINMUX(25, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_HSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_HSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_HSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_HSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO22 \ + ESP32_PINMUX(22, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO23 \ + ESP32_PINMUX(23, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO25 \ + ESP32_PINMUX(25, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_VSPIQ_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_VSPIQ_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPID_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPID_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_VSPICLK_OUT) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_VSPICLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO22 \ + ESP32_PINMUX(22, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO23 \ + ESP32_PINMUX(23, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO25 \ + ESP32_PINMUX(25, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO22 \ + ESP32_PINMUX(22, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO23 \ + ESP32_PINMUX(23, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO25 \ + ESP32_PINMUX(25, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +/* UART2_CTS */ +#define UART2_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO22 \ + ESP32_PINMUX(22, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO23 \ + ESP32_PINMUX(23, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO25 \ + ESP32_PINMUX(25, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U2CTS_IN, ESP_NOSIG) + +/* UART2_RTS */ +#define UART2_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2RTS_OUT) + +/* UART2_RX */ +#define UART2_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO22 \ + ESP32_PINMUX(22, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO23 \ + ESP32_PINMUX(23, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO25 \ + ESP32_PINMUX(25, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U2RXD_IN, ESP_NOSIG) + +/* UART2_TX */ +#define UART2_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO22 \ + ESP32_PINMUX(22, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO23 \ + ESP32_PINMUX(23, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO25 \ + ESP32_PINMUX(25, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h new file mode 100644 index 00000000000..2eda20f9cb3 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32c3-pinctrl.h @@ -0,0 +1,2224 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32C3_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h new file mode 100644 index 00000000000..5d97a79b176 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32s2-pinctrl.h @@ -0,0 +1,7587 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_SPI3_Q_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_D_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +#define SPIM3_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CLK_OUT_MUX) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32S2_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h new file mode 100644 index 00000000000..f8713bec265 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h @@ -0,0 +1,12661 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * NOTE: Autogenerated file using esp_genpinctrl.py + */ + +#ifndef INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ +#define INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ + +/* I2C0_SCL */ +#define I2C0_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +#define I2C0_SCL_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT0_SCL_IN, ESP_I2CEXT0_SCL_OUT) + +/* I2C0_SDA */ +#define I2C0_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +#define I2C0_SDA_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT0_SDA_IN, ESP_I2CEXT0_SDA_OUT) + +/* I2C1_SCL */ +#define I2C1_SCL_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +#define I2C1_SCL_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT1_SCL_IN, ESP_I2CEXT1_SCL_OUT) + +/* I2C1_SDA */ +#define I2C1_SDA_GPIO0 \ + ESP32_PINMUX(0, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO1 \ + ESP32_PINMUX(1, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO2 \ + ESP32_PINMUX(2, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO3 \ + ESP32_PINMUX(3, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO4 \ + ESP32_PINMUX(4, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO5 \ + ESP32_PINMUX(5, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO6 \ + ESP32_PINMUX(6, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO7 \ + ESP32_PINMUX(7, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO8 \ + ESP32_PINMUX(8, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO9 \ + ESP32_PINMUX(9, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO10 \ + ESP32_PINMUX(10, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO11 \ + ESP32_PINMUX(11, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO12 \ + ESP32_PINMUX(12, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO13 \ + ESP32_PINMUX(13, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO14 \ + ESP32_PINMUX(14, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO15 \ + ESP32_PINMUX(15, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO16 \ + ESP32_PINMUX(16, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO17 \ + ESP32_PINMUX(17, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO18 \ + ESP32_PINMUX(18, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO19 \ + ESP32_PINMUX(19, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO20 \ + ESP32_PINMUX(20, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO21 \ + ESP32_PINMUX(21, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO26 \ + ESP32_PINMUX(26, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO27 \ + ESP32_PINMUX(27, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO28 \ + ESP32_PINMUX(28, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO29 \ + ESP32_PINMUX(29, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO30 \ + ESP32_PINMUX(30, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO31 \ + ESP32_PINMUX(31, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO32 \ + ESP32_PINMUX(32, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO33 \ + ESP32_PINMUX(33, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO34 \ + ESP32_PINMUX(34, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO35 \ + ESP32_PINMUX(35, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO36 \ + ESP32_PINMUX(36, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO37 \ + ESP32_PINMUX(37, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO38 \ + ESP32_PINMUX(38, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO39 \ + ESP32_PINMUX(39, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO40 \ + ESP32_PINMUX(40, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO41 \ + ESP32_PINMUX(41, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO42 \ + ESP32_PINMUX(42, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO43 \ + ESP32_PINMUX(43, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO44 \ + ESP32_PINMUX(44, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO45 \ + ESP32_PINMUX(45, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO46 \ + ESP32_PINMUX(46, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO47 \ + ESP32_PINMUX(47, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +#define I2C1_SDA_GPIO48 \ + ESP32_PINMUX(48, ESP_I2CEXT1_SDA_IN, ESP_I2CEXT1_SDA_OUT) + +/* LEDC_CH0 */ +#define LEDC_CH0_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +#define LEDC_CH0_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT0) + +/* LEDC_CH1 */ +#define LEDC_CH1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +#define LEDC_CH1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT1) + +/* LEDC_CH2 */ +#define LEDC_CH2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +#define LEDC_CH2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT2) + +/* LEDC_CH3 */ +#define LEDC_CH3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +#define LEDC_CH3_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT3) + +/* LEDC_CH4 */ +#define LEDC_CH4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +#define LEDC_CH4_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT4) + +/* LEDC_CH5 */ +#define LEDC_CH5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +#define LEDC_CH5_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT5) + +/* LEDC_CH6 */ +#define LEDC_CH6_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +#define LEDC_CH6_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT6) + +/* LEDC_CH7 */ +#define LEDC_CH7_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +#define LEDC_CH7_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_LEDC_LS_SIG_OUT7) + +/* MCPWM0_CAP0 */ +#define MCPWM0_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +#define MCPWM0_CAP0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP0_IN, ESP_NOSIG) + +/* MCPWM0_CAP1 */ +#define MCPWM0_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +#define MCPWM0_CAP1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP1_IN, ESP_NOSIG) + +/* MCPWM0_CAP2 */ +#define MCPWM0_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +#define MCPWM0_CAP2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_CAP2_IN, ESP_NOSIG) + +/* MCPWM0_FAULT0 */ +#define MCPWM0_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F0_IN, ESP_NOSIG) + +#define MCPWM0_FAULT0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F0_IN, ESP_NOSIG) + +/* MCPWM0_FAULT1 */ +#define MCPWM0_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F1_IN, ESP_NOSIG) + +#define MCPWM0_FAULT1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F1_IN, ESP_NOSIG) + +/* MCPWM0_FAULT2 */ +#define MCPWM0_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_F2_IN, ESP_NOSIG) + +#define MCPWM0_FAULT2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_F2_IN, ESP_NOSIG) + +/* MCPWM0_OUT0A */ +#define MCPWM0_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT0A) + +#define MCPWM0_OUT0A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT0A) + +/* MCPWM0_OUT0B */ +#define MCPWM0_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT0B) + +#define MCPWM0_OUT0B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT0B) + +/* MCPWM0_OUT1A */ +#define MCPWM0_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT1A) + +#define MCPWM0_OUT1A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT1A) + +/* MCPWM0_OUT1B */ +#define MCPWM0_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT1B) + +#define MCPWM0_OUT1B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT1B) + +/* MCPWM0_OUT2A */ +#define MCPWM0_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT2A) + +#define MCPWM0_OUT2A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT2A) + +/* MCPWM0_OUT2B */ +#define MCPWM0_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM0_OUT2B) + +#define MCPWM0_OUT2B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM0_OUT2B) + +/* MCPWM0_SYNC0 */ +#define MCPWM0_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +#define MCPWM0_SYNC0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC0_IN, ESP_NOSIG) + +/* MCPWM0_SYNC1 */ +#define MCPWM0_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +#define MCPWM0_SYNC1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC1_IN, ESP_NOSIG) + +/* MCPWM0_SYNC2 */ +#define MCPWM0_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +#define MCPWM0_SYNC2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM0_SYNC2_IN, ESP_NOSIG) + +/* MCPWM1_CAP0 */ +#define MCPWM1_CAP0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +#define MCPWM1_CAP0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP0_IN, ESP_NOSIG) + +/* MCPWM1_CAP1 */ +#define MCPWM1_CAP1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +#define MCPWM1_CAP1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP1_IN, ESP_NOSIG) + +/* MCPWM1_CAP2 */ +#define MCPWM1_CAP2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +#define MCPWM1_CAP2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_CAP2_IN, ESP_NOSIG) + +/* MCPWM1_FAULT0 */ +#define MCPWM1_FAULT0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F0_IN, ESP_NOSIG) + +#define MCPWM1_FAULT0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F0_IN, ESP_NOSIG) + +/* MCPWM1_FAULT1 */ +#define MCPWM1_FAULT1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F1_IN, ESP_NOSIG) + +#define MCPWM1_FAULT1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F1_IN, ESP_NOSIG) + +/* MCPWM1_FAULT2 */ +#define MCPWM1_FAULT2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_F2_IN, ESP_NOSIG) + +#define MCPWM1_FAULT2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_F2_IN, ESP_NOSIG) + +/* MCPWM1_OUT0A */ +#define MCPWM1_OUT0A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT0A) + +#define MCPWM1_OUT0A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT0A) + +/* MCPWM1_OUT0B */ +#define MCPWM1_OUT0B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT0B) + +#define MCPWM1_OUT0B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT0B) + +/* MCPWM1_OUT1A */ +#define MCPWM1_OUT1A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT1A) + +#define MCPWM1_OUT1A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT1A) + +/* MCPWM1_OUT1B */ +#define MCPWM1_OUT1B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT1B) + +#define MCPWM1_OUT1B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT1B) + +/* MCPWM1_OUT2A */ +#define MCPWM1_OUT2A_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT2A) + +#define MCPWM1_OUT2A_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT2A) + +/* MCPWM1_OUT2B */ +#define MCPWM1_OUT2B_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_PWM1_OUT2B) + +#define MCPWM1_OUT2B_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_PWM1_OUT2B) + +/* MCPWM1_SYNC0 */ +#define MCPWM1_SYNC0_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +#define MCPWM1_SYNC0_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC0_IN, ESP_NOSIG) + +/* MCPWM1_SYNC1 */ +#define MCPWM1_SYNC1_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +#define MCPWM1_SYNC1_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC1_IN, ESP_NOSIG) + +/* MCPWM1_SYNC2 */ +#define MCPWM1_SYNC2_GPIO0 \ + ESP32_PINMUX(0, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO1 \ + ESP32_PINMUX(1, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO2 \ + ESP32_PINMUX(2, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO3 \ + ESP32_PINMUX(3, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO4 \ + ESP32_PINMUX(4, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO5 \ + ESP32_PINMUX(5, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO6 \ + ESP32_PINMUX(6, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO7 \ + ESP32_PINMUX(7, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO8 \ + ESP32_PINMUX(8, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO9 \ + ESP32_PINMUX(9, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO10 \ + ESP32_PINMUX(10, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO11 \ + ESP32_PINMUX(11, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO12 \ + ESP32_PINMUX(12, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO13 \ + ESP32_PINMUX(13, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO14 \ + ESP32_PINMUX(14, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO15 \ + ESP32_PINMUX(15, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO16 \ + ESP32_PINMUX(16, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO17 \ + ESP32_PINMUX(17, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO18 \ + ESP32_PINMUX(18, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO19 \ + ESP32_PINMUX(19, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO20 \ + ESP32_PINMUX(20, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO21 \ + ESP32_PINMUX(21, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO26 \ + ESP32_PINMUX(26, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO27 \ + ESP32_PINMUX(27, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO28 \ + ESP32_PINMUX(28, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO29 \ + ESP32_PINMUX(29, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO30 \ + ESP32_PINMUX(30, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO31 \ + ESP32_PINMUX(31, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO32 \ + ESP32_PINMUX(32, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO33 \ + ESP32_PINMUX(33, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO34 \ + ESP32_PINMUX(34, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO35 \ + ESP32_PINMUX(35, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO36 \ + ESP32_PINMUX(36, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO37 \ + ESP32_PINMUX(37, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO38 \ + ESP32_PINMUX(38, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO39 \ + ESP32_PINMUX(39, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO40 \ + ESP32_PINMUX(40, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO41 \ + ESP32_PINMUX(41, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO42 \ + ESP32_PINMUX(42, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO43 \ + ESP32_PINMUX(43, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO44 \ + ESP32_PINMUX(44, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO45 \ + ESP32_PINMUX(45, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO46 \ + ESP32_PINMUX(46, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO47 \ + ESP32_PINMUX(47, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +#define MCPWM1_SYNC2_GPIO48 \ + ESP32_PINMUX(48, ESP_PWM1_SYNC2_IN, ESP_NOSIG) + +/* PCNT0_CH0CTRL */ +#define PCNT0_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH0SIG */ +#define PCNT0_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +#define PCNT0_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN0, ESP_NOSIG) + +/* PCNT0_CH1CTRL */ +#define PCNT0_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN0, ESP_NOSIG) + +/* PCNT0_CH1SIG */ +#define PCNT0_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +#define PCNT0_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN0, ESP_NOSIG) + +/* PCNT1_CH0CTRL */ +#define PCNT1_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH0SIG */ +#define PCNT1_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +#define PCNT1_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN1, ESP_NOSIG) + +/* PCNT1_CH1CTRL */ +#define PCNT1_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN1, ESP_NOSIG) + +/* PCNT1_CH1SIG */ +#define PCNT1_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +#define PCNT1_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN1, ESP_NOSIG) + +/* PCNT2_CH0CTRL */ +#define PCNT2_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +#define PCNT2_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN2, ESP_NOSIG) + +/* PCNT2_CH0SIG */ +#define PCNT2_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT2_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT2_CH1CTRL */ +#define PCNT2_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN2, ESP_NOSIG) + +/* PCNT2_CH1SIG */ +#define PCNT2_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +#define PCNT2_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN2, ESP_NOSIG) + +/* PCNT3_CH0CTRL */ +#define PCNT3_CH0CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH0SIG */ +#define PCNT3_CH0SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +#define PCNT3_CH0SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH0_IN3, ESP_NOSIG) + +/* PCNT3_CH1CTRL */ +#define PCNT3_CH1CTRL_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1CTRL_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_CTRL_CH1_IN3, ESP_NOSIG) + +/* PCNT3_CH1SIG */ +#define PCNT3_CH1SIG_GPIO0 \ + ESP32_PINMUX(0, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO1 \ + ESP32_PINMUX(1, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO2 \ + ESP32_PINMUX(2, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO3 \ + ESP32_PINMUX(3, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO4 \ + ESP32_PINMUX(4, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO5 \ + ESP32_PINMUX(5, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO6 \ + ESP32_PINMUX(6, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO7 \ + ESP32_PINMUX(7, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO8 \ + ESP32_PINMUX(8, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO9 \ + ESP32_PINMUX(9, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO10 \ + ESP32_PINMUX(10, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO11 \ + ESP32_PINMUX(11, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO12 \ + ESP32_PINMUX(12, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO13 \ + ESP32_PINMUX(13, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO14 \ + ESP32_PINMUX(14, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO15 \ + ESP32_PINMUX(15, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO16 \ + ESP32_PINMUX(16, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO17 \ + ESP32_PINMUX(17, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO18 \ + ESP32_PINMUX(18, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO19 \ + ESP32_PINMUX(19, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO20 \ + ESP32_PINMUX(20, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO21 \ + ESP32_PINMUX(21, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO26 \ + ESP32_PINMUX(26, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO27 \ + ESP32_PINMUX(27, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO28 \ + ESP32_PINMUX(28, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO29 \ + ESP32_PINMUX(29, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO30 \ + ESP32_PINMUX(30, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO31 \ + ESP32_PINMUX(31, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO32 \ + ESP32_PINMUX(32, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO33 \ + ESP32_PINMUX(33, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO34 \ + ESP32_PINMUX(34, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO35 \ + ESP32_PINMUX(35, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO36 \ + ESP32_PINMUX(36, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO37 \ + ESP32_PINMUX(37, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO38 \ + ESP32_PINMUX(38, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO39 \ + ESP32_PINMUX(39, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO40 \ + ESP32_PINMUX(40, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO41 \ + ESP32_PINMUX(41, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO42 \ + ESP32_PINMUX(42, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO43 \ + ESP32_PINMUX(43, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO44 \ + ESP32_PINMUX(44, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO45 \ + ESP32_PINMUX(45, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO46 \ + ESP32_PINMUX(46, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO47 \ + ESP32_PINMUX(47, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +#define PCNT3_CH1SIG_GPIO48 \ + ESP32_PINMUX(48, ESP_PCNT_SIG_CH1_IN3, ESP_NOSIG) + +/* SPIM2_CSEL */ +#define SPIM2_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS0_OUT) + +#define SPIM2_CSEL_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS0_OUT) + +/* SPIM2_CSEL1 */ +#define SPIM2_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS1_OUT) + +#define SPIM2_CSEL1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS1_OUT) + +/* SPIM2_CSEL2 */ +#define SPIM2_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS2_OUT) + +#define SPIM2_CSEL2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS2_OUT) + +/* SPIM2_CSEL3 */ +#define SPIM2_CSEL3_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS3_OUT) + +#define SPIM2_CSEL3_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS3_OUT) + +/* SPIM2_CSEL4 */ +#define SPIM2_CSEL4_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS4_OUT) + +#define SPIM2_CSEL4_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS4_OUT) + +/* SPIM2_CSEL5 */ +#define SPIM2_CSEL5_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICS5_OUT) + +#define SPIM2_CSEL5_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICS5_OUT) + +/* SPIM2_MISO */ +#define SPIM2_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO47 \ + ESP32_PINMUX(47, ESP_FSPIQ_IN, ESP_NOSIG) + +#define SPIM2_MISO_GPIO48 \ + ESP32_PINMUX(48, ESP_FSPIQ_IN, ESP_NOSIG) + +/* SPIM2_MOSI */ +#define SPIM2_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPID_OUT) + +#define SPIM2_MOSI_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPID_OUT) + +/* SPIM2_SCLK */ +#define SPIM2_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_FSPICLK_OUT) + +#define SPIM2_SCLK_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_FSPICLK_OUT) + +/* SPIM3_CSEL */ +#define SPIM3_CSEL_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +#define SPIM3_CSEL_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS0_OUT) + +/* SPIM3_CSEL1 */ +#define SPIM3_CSEL1_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +#define SPIM3_CSEL1_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS1_OUT) + +/* SPIM3_CSEL2 */ +#define SPIM3_CSEL2_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +#define SPIM3_CSEL2_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CS2_OUT) + +/* SPIM3_MISO */ +#define SPIM3_MISO_GPIO0 \ + ESP32_PINMUX(0, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO1 \ + ESP32_PINMUX(1, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO2 \ + ESP32_PINMUX(2, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO3 \ + ESP32_PINMUX(3, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO4 \ + ESP32_PINMUX(4, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO5 \ + ESP32_PINMUX(5, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO6 \ + ESP32_PINMUX(6, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO7 \ + ESP32_PINMUX(7, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO8 \ + ESP32_PINMUX(8, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO9 \ + ESP32_PINMUX(9, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO10 \ + ESP32_PINMUX(10, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO11 \ + ESP32_PINMUX(11, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO12 \ + ESP32_PINMUX(12, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO13 \ + ESP32_PINMUX(13, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO14 \ + ESP32_PINMUX(14, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO15 \ + ESP32_PINMUX(15, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO16 \ + ESP32_PINMUX(16, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO17 \ + ESP32_PINMUX(17, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO18 \ + ESP32_PINMUX(18, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO19 \ + ESP32_PINMUX(19, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO20 \ + ESP32_PINMUX(20, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO21 \ + ESP32_PINMUX(21, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO26 \ + ESP32_PINMUX(26, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO27 \ + ESP32_PINMUX(27, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO28 \ + ESP32_PINMUX(28, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO29 \ + ESP32_PINMUX(29, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO30 \ + ESP32_PINMUX(30, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO31 \ + ESP32_PINMUX(31, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO32 \ + ESP32_PINMUX(32, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO33 \ + ESP32_PINMUX(33, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO34 \ + ESP32_PINMUX(34, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO35 \ + ESP32_PINMUX(35, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO36 \ + ESP32_PINMUX(36, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO37 \ + ESP32_PINMUX(37, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO38 \ + ESP32_PINMUX(38, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO39 \ + ESP32_PINMUX(39, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO40 \ + ESP32_PINMUX(40, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO41 \ + ESP32_PINMUX(41, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO42 \ + ESP32_PINMUX(42, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO43 \ + ESP32_PINMUX(43, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO44 \ + ESP32_PINMUX(44, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO45 \ + ESP32_PINMUX(45, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO46 \ + ESP32_PINMUX(46, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO47 \ + ESP32_PINMUX(47, ESP_SPI3_Q_IN, ESP_NOSIG) + +#define SPIM3_MISO_GPIO48 \ + ESP32_PINMUX(48, ESP_SPI3_Q_IN, ESP_NOSIG) + +/* SPIM3_MOSI */ +#define SPIM3_MOSI_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_D_OUT) + +#define SPIM3_MOSI_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_D_OUT) + +/* SPIM3_SCLK */ +#define SPIM3_SCLK_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +#define SPIM3_SCLK_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_SPI3_CLK_OUT) + +/* TWAI_BUS_OFF */ +#define TWAI_BUS_OFF_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +#define TWAI_BUS_OFF_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_BUS_OFF_ON) + +/* TWAI_CLKOUT */ +#define TWAI_CLKOUT_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_CLKOUT) + +#define TWAI_CLKOUT_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_CLKOUT) + +/* TWAI_RX */ +#define TWAI_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_TWAI_RX, ESP_NOSIG) + +#define TWAI_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_TWAI_RX, ESP_NOSIG) + +/* TWAI_TX */ +#define TWAI_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_TWAI_TX) + +#define TWAI_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_TWAI_TX) + +/* UART0_CTS */ +#define UART0_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U0CTS_IN, ESP_NOSIG) + +#define UART0_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U0CTS_IN, ESP_NOSIG) + +/* UART0_DSR */ +#define UART0_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO47 \ + ESP32_PINMUX(47, ESP_U0DSR_IN, ESP_NOSIG) + +#define UART0_DSR_GPIO48 \ + ESP32_PINMUX(48, ESP_U0DSR_IN, ESP_NOSIG) + +/* UART0_DTR */ +#define UART0_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0DTR_OUT) + +#define UART0_DTR_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0DTR_OUT) + +/* UART0_RTS */ +#define UART0_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0RTS_OUT) + +#define UART0_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0RTS_OUT) + +/* UART0_RX */ +#define UART0_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U0RXD_IN, ESP_NOSIG) + +#define UART0_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U0RXD_IN, ESP_NOSIG) + +/* UART0_TX */ +#define UART0_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U0TXD_OUT) + +#define UART0_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U0TXD_OUT) + +/* UART1_CTS */ +#define UART1_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U1CTS_IN, ESP_NOSIG) + +#define UART1_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U1CTS_IN, ESP_NOSIG) + +/* UART1_DSR */ +#define UART1_DSR_GPIO0 \ + ESP32_PINMUX(0, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO1 \ + ESP32_PINMUX(1, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO2 \ + ESP32_PINMUX(2, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO3 \ + ESP32_PINMUX(3, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO4 \ + ESP32_PINMUX(4, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO5 \ + ESP32_PINMUX(5, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO6 \ + ESP32_PINMUX(6, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO7 \ + ESP32_PINMUX(7, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO8 \ + ESP32_PINMUX(8, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO9 \ + ESP32_PINMUX(9, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO10 \ + ESP32_PINMUX(10, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO11 \ + ESP32_PINMUX(11, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO12 \ + ESP32_PINMUX(12, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO13 \ + ESP32_PINMUX(13, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO14 \ + ESP32_PINMUX(14, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO15 \ + ESP32_PINMUX(15, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO16 \ + ESP32_PINMUX(16, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO17 \ + ESP32_PINMUX(17, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO18 \ + ESP32_PINMUX(18, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO19 \ + ESP32_PINMUX(19, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO20 \ + ESP32_PINMUX(20, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO21 \ + ESP32_PINMUX(21, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO26 \ + ESP32_PINMUX(26, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO27 \ + ESP32_PINMUX(27, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO28 \ + ESP32_PINMUX(28, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO29 \ + ESP32_PINMUX(29, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO30 \ + ESP32_PINMUX(30, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO31 \ + ESP32_PINMUX(31, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO32 \ + ESP32_PINMUX(32, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO33 \ + ESP32_PINMUX(33, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO34 \ + ESP32_PINMUX(34, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO35 \ + ESP32_PINMUX(35, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO36 \ + ESP32_PINMUX(36, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO37 \ + ESP32_PINMUX(37, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO38 \ + ESP32_PINMUX(38, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO39 \ + ESP32_PINMUX(39, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO40 \ + ESP32_PINMUX(40, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO41 \ + ESP32_PINMUX(41, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO42 \ + ESP32_PINMUX(42, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO43 \ + ESP32_PINMUX(43, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO44 \ + ESP32_PINMUX(44, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO45 \ + ESP32_PINMUX(45, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO46 \ + ESP32_PINMUX(46, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO47 \ + ESP32_PINMUX(47, ESP_U1DSR_IN, ESP_NOSIG) + +#define UART1_DSR_GPIO48 \ + ESP32_PINMUX(48, ESP_U1DSR_IN, ESP_NOSIG) + +/* UART1_DTR */ +#define UART1_DTR_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1DTR_OUT) + +#define UART1_DTR_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1DTR_OUT) + +/* UART1_RTS */ +#define UART1_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1RTS_OUT) + +#define UART1_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1RTS_OUT) + +/* UART1_RX */ +#define UART1_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U1RXD_IN, ESP_NOSIG) + +#define UART1_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U1RXD_IN, ESP_NOSIG) + +/* UART1_TX */ +#define UART1_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U1TXD_OUT) + +#define UART1_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U1TXD_OUT) + +/* UART2_CTS */ +#define UART2_CTS_GPIO0 \ + ESP32_PINMUX(0, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO1 \ + ESP32_PINMUX(1, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO2 \ + ESP32_PINMUX(2, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO3 \ + ESP32_PINMUX(3, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO4 \ + ESP32_PINMUX(4, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO5 \ + ESP32_PINMUX(5, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO6 \ + ESP32_PINMUX(6, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO7 \ + ESP32_PINMUX(7, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO8 \ + ESP32_PINMUX(8, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO9 \ + ESP32_PINMUX(9, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO10 \ + ESP32_PINMUX(10, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO11 \ + ESP32_PINMUX(11, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO12 \ + ESP32_PINMUX(12, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO13 \ + ESP32_PINMUX(13, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO14 \ + ESP32_PINMUX(14, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO15 \ + ESP32_PINMUX(15, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO16 \ + ESP32_PINMUX(16, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO17 \ + ESP32_PINMUX(17, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO18 \ + ESP32_PINMUX(18, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO19 \ + ESP32_PINMUX(19, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO20 \ + ESP32_PINMUX(20, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO21 \ + ESP32_PINMUX(21, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO26 \ + ESP32_PINMUX(26, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO27 \ + ESP32_PINMUX(27, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO28 \ + ESP32_PINMUX(28, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO29 \ + ESP32_PINMUX(29, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO30 \ + ESP32_PINMUX(30, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO31 \ + ESP32_PINMUX(31, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO32 \ + ESP32_PINMUX(32, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO33 \ + ESP32_PINMUX(33, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO34 \ + ESP32_PINMUX(34, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO35 \ + ESP32_PINMUX(35, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO36 \ + ESP32_PINMUX(36, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO37 \ + ESP32_PINMUX(37, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO38 \ + ESP32_PINMUX(38, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO39 \ + ESP32_PINMUX(39, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO40 \ + ESP32_PINMUX(40, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO41 \ + ESP32_PINMUX(41, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO42 \ + ESP32_PINMUX(42, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO43 \ + ESP32_PINMUX(43, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO44 \ + ESP32_PINMUX(44, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO45 \ + ESP32_PINMUX(45, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO46 \ + ESP32_PINMUX(46, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO47 \ + ESP32_PINMUX(47, ESP_U2CTS_IN, ESP_NOSIG) + +#define UART2_CTS_GPIO48 \ + ESP32_PINMUX(48, ESP_U2CTS_IN, ESP_NOSIG) + +/* UART2_RTS */ +#define UART2_RTS_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U2RTS_OUT) + +#define UART2_RTS_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U2RTS_OUT) + +/* UART2_RX */ +#define UART2_RX_GPIO0 \ + ESP32_PINMUX(0, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO1 \ + ESP32_PINMUX(1, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO2 \ + ESP32_PINMUX(2, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO3 \ + ESP32_PINMUX(3, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO4 \ + ESP32_PINMUX(4, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO5 \ + ESP32_PINMUX(5, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO6 \ + ESP32_PINMUX(6, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO7 \ + ESP32_PINMUX(7, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO8 \ + ESP32_PINMUX(8, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO9 \ + ESP32_PINMUX(9, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO10 \ + ESP32_PINMUX(10, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO11 \ + ESP32_PINMUX(11, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO12 \ + ESP32_PINMUX(12, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO13 \ + ESP32_PINMUX(13, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO14 \ + ESP32_PINMUX(14, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO15 \ + ESP32_PINMUX(15, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO16 \ + ESP32_PINMUX(16, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO17 \ + ESP32_PINMUX(17, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO18 \ + ESP32_PINMUX(18, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO19 \ + ESP32_PINMUX(19, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO20 \ + ESP32_PINMUX(20, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO21 \ + ESP32_PINMUX(21, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO26 \ + ESP32_PINMUX(26, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO27 \ + ESP32_PINMUX(27, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO28 \ + ESP32_PINMUX(28, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO29 \ + ESP32_PINMUX(29, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO30 \ + ESP32_PINMUX(30, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO31 \ + ESP32_PINMUX(31, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO32 \ + ESP32_PINMUX(32, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO33 \ + ESP32_PINMUX(33, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO34 \ + ESP32_PINMUX(34, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO35 \ + ESP32_PINMUX(35, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO36 \ + ESP32_PINMUX(36, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO37 \ + ESP32_PINMUX(37, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO38 \ + ESP32_PINMUX(38, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO39 \ + ESP32_PINMUX(39, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO40 \ + ESP32_PINMUX(40, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO41 \ + ESP32_PINMUX(41, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO42 \ + ESP32_PINMUX(42, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO43 \ + ESP32_PINMUX(43, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO44 \ + ESP32_PINMUX(44, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO45 \ + ESP32_PINMUX(45, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO46 \ + ESP32_PINMUX(46, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO47 \ + ESP32_PINMUX(47, ESP_U2RXD_IN, ESP_NOSIG) + +#define UART2_RX_GPIO48 \ + ESP32_PINMUX(48, ESP_U2RXD_IN, ESP_NOSIG) + +/* UART2_TX */ +#define UART2_TX_GPIO0 \ + ESP32_PINMUX(0, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO1 \ + ESP32_PINMUX(1, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO2 \ + ESP32_PINMUX(2, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO3 \ + ESP32_PINMUX(3, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO4 \ + ESP32_PINMUX(4, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO5 \ + ESP32_PINMUX(5, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO6 \ + ESP32_PINMUX(6, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO7 \ + ESP32_PINMUX(7, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO8 \ + ESP32_PINMUX(8, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO9 \ + ESP32_PINMUX(9, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO10 \ + ESP32_PINMUX(10, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO11 \ + ESP32_PINMUX(11, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO12 \ + ESP32_PINMUX(12, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO13 \ + ESP32_PINMUX(13, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO14 \ + ESP32_PINMUX(14, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO15 \ + ESP32_PINMUX(15, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO16 \ + ESP32_PINMUX(16, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO17 \ + ESP32_PINMUX(17, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO18 \ + ESP32_PINMUX(18, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO19 \ + ESP32_PINMUX(19, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO20 \ + ESP32_PINMUX(20, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO21 \ + ESP32_PINMUX(21, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO26 \ + ESP32_PINMUX(26, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO27 \ + ESP32_PINMUX(27, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO28 \ + ESP32_PINMUX(28, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO29 \ + ESP32_PINMUX(29, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO30 \ + ESP32_PINMUX(30, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO31 \ + ESP32_PINMUX(31, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO32 \ + ESP32_PINMUX(32, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO33 \ + ESP32_PINMUX(33, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO34 \ + ESP32_PINMUX(34, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO35 \ + ESP32_PINMUX(35, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO36 \ + ESP32_PINMUX(36, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO37 \ + ESP32_PINMUX(37, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO38 \ + ESP32_PINMUX(38, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO39 \ + ESP32_PINMUX(39, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO40 \ + ESP32_PINMUX(40, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO41 \ + ESP32_PINMUX(41, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO42 \ + ESP32_PINMUX(42, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO43 \ + ESP32_PINMUX(43, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO44 \ + ESP32_PINMUX(44, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO45 \ + ESP32_PINMUX(45, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO46 \ + ESP32_PINMUX(46, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO47 \ + ESP32_PINMUX(47, ESP_NOSIG, ESP_U2TXD_OUT) + +#define UART2_TX_GPIO48 \ + ESP32_PINMUX(48, ESP_NOSIG, ESP_U2TXD_OUT) + + +#endif /* INC_DT_BINDS_PINCTRL_ESP32S3_PINCTRL_HAL_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index b2dcd7ae6c9..9d7f8c2312f 100644 --- a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h @@ -131,7 +131,6 @@ /** * @name nRF pinctrl output drive. - * @note Values match nrf_gpio_pin_drive_t constants. * @{ */ @@ -152,7 +151,7 @@ /** High drive '0', disconnect '1'. */ #define NRF_DRIVE_H0D1 7U /** Extra high drive '0', extra high drive '1'. */ -#define NRF_DRIVE_E0E1 11U +#define NRF_DRIVE_E0E1 8U /** @} */ diff --git a/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h new file mode 100644 index 00000000000..3fb83a3a7a4 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/pinctrl-zynqmp.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_ZYNQMP_PINCTRL_H_ + +/* + * The offset is defined at `pictrl_soc.h` for the ZynqMP platform + */ +#define FUNCTION_OFFSET 8 +#define UART_FUNCTION 0x1 + +/* + * For functions that can be selected for a subset of MIO pins, + * specific macro identifiers were generated to avoid complex checking + * logic at compile time. For more generalized applications existing on + * every pin (eg. GPIO), a generic macro function to generate a driver-compliant + * selector value can be used. + */ + +#define UART0_RX_2 (2U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_6 (6U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_10 (10U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_14 (14U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_18 (18U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_22 (22U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_26 (26U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_30 (30U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_34 (34U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_38 (38U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_42 (42U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_46 (46U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_50 (50U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_54 (54U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_58 (58U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_62 (62U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_66 (66U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_70 (70U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_RX_74 (74U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#define UART0_TX_3 (3U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_7 (7U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_11 (11U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_15 (15U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_19 (19U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_23 (23U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_27 (27U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_31 (31U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_35 (35U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_39 (39U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_43 (43U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_47 (47U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_51 (51U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_55 (55U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_59 (59U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_63 (63U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_67 (67U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_71 (71U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART0_TX_75 (75U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#define UART1_RX_1 (1U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_5 (5U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_9 (9U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_13 (13U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_17 (17U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_21 (21U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_25 (25U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_29 (29U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_33 (33U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_37 (37U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_41 (41U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_45 (45U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_49 (49U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_53 (53U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_57 (57U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_61 (61U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_65 (65U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_69 (69U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_RX_73 (73U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#define UART1_TX_0 (0U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_4 (4U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_8 (8U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_12 (12U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_16 (16U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_20 (20U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_24 (24U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_28 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_32 (32U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_36 (36U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_40 (40U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_44 (44U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_48 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_52 (52U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_56 (56U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_60 (60U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_64 (64U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_68 (28U | (UART_FUNCTION << FUNCTION_OFFSET)) +#define UART1_TX_72 (72U | (UART_FUNCTION << FUNCTION_OFFSET)) + +#endif diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h index dfe21b00183..e5466757653 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r7fa4m1xxxxxx.h @@ -28,21 +28,21 @@ #define P007_AMP3O RA_PINCFG_100(0, 7, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) #define P007_AN013 RA_PINCFG_100(0, 7, 0x01, RA_PINCFG_ANALOG) #define P008_AN014 RA_PINCFG_100(0, 8, 0x01, RA_PINCFG_ANALOG) -#define P010_AMP2M RA_PINCFG__40(0, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P010_AN005 RA_PINCFG__40(0, 0, 0x01, RA_PINCFG_ANALOG) -#define P010_TS30 RA_PINCFG__40(0, 0, 0x0C, RA_PINCFG_FUNC) -#define P010_VREFH0 RA_PINCFG__40(0, 0, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P011_AN006 RA_PINCFG__40(0, 1, 0x01, RA_PINCFG_ANALOG) -#define P011_TS31 RA_PINCFG__40(0, 1, 0x0C, RA_PINCFG_FUNC) -#define P011_VREFL0 RA_PINCFG__40(0, 1, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P012_AN007 RA_PINCFG__40(0, 2, 0x01, RA_PINCFG_ANALOG) -#define P012_VREFH RA_PINCFG__40(0, 2, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P013_AN008 RA_PINCFG__40(0, 3, 0x01, RA_PINCFG_ANALOG) -#define P013_VREFL RA_PINCFG__40(0, 3, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P014_AN009 RA_PINCFG__40(0, 4, 0x01, RA_PINCFG_ANALOG) -#define P014_DA0 RA_PINCFG__40(0, 4, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) -#define P015_AN010 RA_PINCFG__40(0, 5, 0x01, RA_PINCFG_ANALOG) -#define P015_TS28 RA_PINCFG__40(0, 5, 0x0C, RA_PINCFG_FUNC) +#define P010_AMP2M RA_PINCFG__40(0, 10, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P010_AN005 RA_PINCFG__40(0, 10, 0x01, RA_PINCFG_ANALOG) +#define P010_TS30 RA_PINCFG__40(0, 10, 0x0C, RA_PINCFG_FUNC) +#define P010_VREFH0 RA_PINCFG__40(0, 10, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P011_AN006 RA_PINCFG__40(0, 11, 0x01, RA_PINCFG_ANALOG) +#define P011_TS31 RA_PINCFG__40(0, 11, 0x0C, RA_PINCFG_FUNC) +#define P011_VREFL0 RA_PINCFG__40(0, 11, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P012_AN007 RA_PINCFG__40(0, 12, 0x01, RA_PINCFG_ANALOG) +#define P012_VREFH RA_PINCFG__40(0, 12, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P013_AN008 RA_PINCFG__40(0, 13, 0x01, RA_PINCFG_ANALOG) +#define P013_VREFL RA_PINCFG__40(0, 13, 0x03, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P014_AN009 RA_PINCFG__40(0, 14, 0x01, RA_PINCFG_ANALOG) +#define P014_DA0 RA_PINCFG__40(0, 14, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) +#define P015_AN010 RA_PINCFG__40(0, 15, 0x01, RA_PINCFG_ANALOG) +#define P015_TS28 RA_PINCFG__40(0, 15, 0x0C, RA_PINCFG_FUNC) #define P100_AGTIO0 RA_PINCFG__40(1, 0, 0x01, RA_PINCFG_FUNC) #define P100_AN022 RA_PINCFG__40(1, 0, 0x01, RA_PINCFG_ANALOG) #define P100_CMPIN0 RA_PINCFG__40(1, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) @@ -132,45 +132,45 @@ #define P109_SEG23 RA_PINCFG__40(1, 9, 0x0D, RA_PINCFG_FUNC) #define P109_TS10 RA_PINCFG__40(1, 9, 0x0C, RA_PINCFG_FUNC) #define P109_TXD9 RA_PINCFG__40(1, 9, 0x05, RA_PINCFG_FUNC) -#define P110_CRX0 RA_PINCFG__40(1, 0, 0x10, RA_PINCFG_FUNC) -#define P110_CTS2_RTS2 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) -#define P110_GTIOC1B RA_PINCFG__40(1, 0, 0x03, RA_PINCFG_FUNC) -#define P110_GTOVLO RA_PINCFG__40(1, 0, 0x02, RA_PINCFG_FUNC) -#define P110_MISO9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_MISOB RA_PINCFG__40(1, 0, 0x06, RA_PINCFG_FUNC) -#define P110_RXD9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_SCL9 RA_PINCFG__40(1, 0, 0x05, RA_PINCFG_FUNC) -#define P110_SEG24 RA_PINCFG__40(1, 0, 0x0D, RA_PINCFG_FUNC) -#define P110_SS2 RA_PINCFG__40(1, 0, 0x04, RA_PINCFG_FUNC) -#define P110_VCOUT RA_PINCFG__40(1, 0, 0x09, RA_PINCFG_FUNC) -#define P111_CAPH RA_PINCFG__40(1, 1, 0x0D, RA_PINCFG_FUNC) -#define P111_GTIOC3A RA_PINCFG__40(1, 1, 0x03, RA_PINCFG_FUNC) -#define P111_RSPCKB RA_PINCFG__40(1, 1, 0x06, RA_PINCFG_FUNC) -#define P111_SCK2 RA_PINCFG__40(1, 1, 0x04, RA_PINCFG_FUNC) -#define P111_SCK9 RA_PINCFG__40(1, 1, 0x05, RA_PINCFG_FUNC) -#define P111_TS12 RA_PINCFG__40(1, 1, 0x0C, RA_PINCFG_FUNC) -#define P112_CAPL RA_PINCFG__40(1, 2, 0x0D, RA_PINCFG_FUNC) -#define P112_GTIOC3B RA_PINCFG__40(1, 2, 0x03, RA_PINCFG_FUNC) -#define P112_MOSI2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P112_SCK1 RA_PINCFG__40(1, 2, 0x05, RA_PINCFG_FUNC) -#define P112_SDA2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P112_SSIBCK0 RA_PINCFG__40(1, 2, 0x12, RA_PINCFG_FUNC) -#define P112_SSLB0 RA_PINCFG__40(1, 2, 0x06, RA_PINCFG_FUNC) -#define P112_TSCAP RA_PINCFG__40(1, 2, 0x0C, RA_PINCFG_FUNC) -#define P112_TXD2 RA_PINCFG__40(1, 2, 0x04, RA_PINCFG_FUNC) -#define P113_GTIOC2A RA_PINCFG__64(1, 3, 0x03, RA_PINCFG_FUNC) -#define P113_SEG00COM4 RA_PINCFG__64(1, 3, 0x0D, RA_PINCFG_FUNC) -#define P113_SSIFS0 RA_PINCFG__64(1, 3, 0x12, RA_PINCFG_FUNC) -#define P113_SSILRCK0 RA_PINCFG__64(1, 3, 0x12, RA_PINCFG_FUNC) -#define P113_TS27 RA_PINCFG__64(1, 3, 0x0C, RA_PINCFG_FUNC) -#define P114_GTIOC2B RA_PINCFG_100(1, 4, 0x03, RA_PINCFG_FUNC) -#define P114_SEG25 RA_PINCFG_100(1, 4, 0x0D, RA_PINCFG_FUNC) -#define P114_SSIRXD0 RA_PINCFG_100(1, 4, 0x12, RA_PINCFG_FUNC) -#define P114_TS29 RA_PINCFG_100(1, 4, 0x0C, RA_PINCFG_FUNC) -#define P115_GTIOC4A RA_PINCFG_100(1, 5, 0x03, RA_PINCFG_FUNC) -#define P115_SEG26 RA_PINCFG_100(1, 5, 0x0D, RA_PINCFG_FUNC) -#define P115_SSITXD0 RA_PINCFG_100(1, 5, 0x12, RA_PINCFG_FUNC) -#define P115_TS35 RA_PINCFG_100(1, 5, 0x0C, RA_PINCFG_FUNC) +#define P110_CRX0 RA_PINCFG__40(1, 10, 0x10, RA_PINCFG_FUNC) +#define P110_CTS2_RTS2 RA_PINCFG__40(1, 10, 0x04, RA_PINCFG_FUNC) +#define P110_GTIOC1B RA_PINCFG__40(1, 10, 0x03, RA_PINCFG_FUNC) +#define P110_GTOVLO RA_PINCFG__40(1, 10, 0x02, RA_PINCFG_FUNC) +#define P110_MISO9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_MISOB RA_PINCFG__40(1, 10, 0x06, RA_PINCFG_FUNC) +#define P110_RXD9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_SCL9 RA_PINCFG__40(1, 10, 0x05, RA_PINCFG_FUNC) +#define P110_SEG24 RA_PINCFG__40(1, 10, 0x0D, RA_PINCFG_FUNC) +#define P110_SS2 RA_PINCFG__40(1, 10, 0x04, RA_PINCFG_FUNC) +#define P110_VCOUT RA_PINCFG__40(1, 10, 0x09, RA_PINCFG_FUNC) +#define P111_CAPH RA_PINCFG__40(1, 11, 0x0D, RA_PINCFG_FUNC) +#define P111_GTIOC3A RA_PINCFG__40(1, 11, 0x03, RA_PINCFG_FUNC) +#define P111_RSPCKB RA_PINCFG__40(1, 11, 0x06, RA_PINCFG_FUNC) +#define P111_SCK2 RA_PINCFG__40(1, 11, 0x04, RA_PINCFG_FUNC) +#define P111_SCK9 RA_PINCFG__40(1, 11, 0x05, RA_PINCFG_FUNC) +#define P111_TS12 RA_PINCFG__40(1, 11, 0x0C, RA_PINCFG_FUNC) +#define P112_CAPL RA_PINCFG__40(1, 12, 0x0D, RA_PINCFG_FUNC) +#define P112_GTIOC3B RA_PINCFG__40(1, 12, 0x03, RA_PINCFG_FUNC) +#define P112_MOSI2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P112_SCK1 RA_PINCFG__40(1, 12, 0x05, RA_PINCFG_FUNC) +#define P112_SDA2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P112_SSIBCK0 RA_PINCFG__40(1, 12, 0x12, RA_PINCFG_FUNC) +#define P112_SSLB0 RA_PINCFG__40(1, 12, 0x06, RA_PINCFG_FUNC) +#define P112_TSCAP RA_PINCFG__40(1, 12, 0x0C, RA_PINCFG_FUNC) +#define P112_TXD2 RA_PINCFG__40(1, 12, 0x04, RA_PINCFG_FUNC) +#define P113_GTIOC2A RA_PINCFG__64(1, 13, 0x03, RA_PINCFG_FUNC) +#define P113_SEG00COM4 RA_PINCFG__64(1, 13, 0x0D, RA_PINCFG_FUNC) +#define P113_SSIFS0 RA_PINCFG__64(1, 13, 0x12, RA_PINCFG_FUNC) +#define P113_SSILRCK0 RA_PINCFG__64(1, 13, 0x12, RA_PINCFG_FUNC) +#define P113_TS27 RA_PINCFG__64(1, 13, 0x0C, RA_PINCFG_FUNC) +#define P114_GTIOC2B RA_PINCFG_100(1, 14, 0x03, RA_PINCFG_FUNC) +#define P114_SEG25 RA_PINCFG_100(1, 14, 0x0D, RA_PINCFG_FUNC) +#define P114_SSIRXD0 RA_PINCFG_100(1, 14, 0x12, RA_PINCFG_FUNC) +#define P114_TS29 RA_PINCFG_100(1, 14, 0x0C, RA_PINCFG_FUNC) +#define P115_GTIOC4A RA_PINCFG_100(1, 15, 0x03, RA_PINCFG_FUNC) +#define P115_SEG26 RA_PINCFG_100(1, 15, 0x0D, RA_PINCFG_FUNC) +#define P115_SSITXD0 RA_PINCFG_100(1, 15, 0x12, RA_PINCFG_FUNC) +#define P115_TS35 RA_PINCFG_100(1, 15, 0x0C, RA_PINCFG_FUNC) #define P202_GTIOC5B RA_PINCFG_100(2, 2, 0x03, RA_PINCFG_FUNC) #define P202_MISO9 RA_PINCFG_100(2, 2, 0x05, RA_PINCFG_FUNC) #define P202_MISOB RA_PINCFG_100(2, 2, 0x06, RA_PINCFG_FUNC) @@ -221,17 +221,17 @@ #define P206_SSLB1 RA_PINCFG__48(2, 6, 0x06, RA_PINCFG_FUNC) #define P206_TS01 RA_PINCFG__48(2, 6, 0x0C, RA_PINCFG_FUNC) #define P206_USB_VBUSEN RA_PINCFG__48(2, 6, 0x13, RA_PINCFG_FUNC) -#define P212_AGTEE1 RA_PINCFG__40(2, 2, 0x01, RA_PINCFG_FUNC) -#define P212_GTETRGB RA_PINCFG__40(2, 2, 0x02, RA_PINCFG_FUNC) -#define P212_GTIOC0B RA_PINCFG__40(2, 2, 0x03, RA_PINCFG_FUNC) -#define P212_MISO1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P212_RXD1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P212_SCL1 RA_PINCFG__40(2, 2, 0x05, RA_PINCFG_FUNC) -#define P213_GTETRGA RA_PINCFG__40(2, 3, 0x02, RA_PINCFG_FUNC) -#define P213_GTIOC0A RA_PINCFG__40(2, 3, 0x03, RA_PINCFG_FUNC) -#define P213_MOSI1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) -#define P213_SDA1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) -#define P213_TXD1 RA_PINCFG__40(2, 3, 0x05, RA_PINCFG_FUNC) +#define P212_AGTEE1 RA_PINCFG__40(2, 12, 0x01, RA_PINCFG_FUNC) +#define P212_GTETRGB RA_PINCFG__40(2, 12, 0x02, RA_PINCFG_FUNC) +#define P212_GTIOC0B RA_PINCFG__40(2, 12, 0x03, RA_PINCFG_FUNC) +#define P212_MISO1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P212_RXD1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P212_SCL1 RA_PINCFG__40(2, 12, 0x05, RA_PINCFG_FUNC) +#define P213_GTETRGA RA_PINCFG__40(2, 13, 0x02, RA_PINCFG_FUNC) +#define P213_GTIOC0A RA_PINCFG__40(2, 13, 0x03, RA_PINCFG_FUNC) +#define P213_MOSI1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) +#define P213_SDA1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) +#define P213_TXD1 RA_PINCFG__40(2, 13, 0x05, RA_PINCFG_FUNC) #define P300_GTIOC0A RA_PINCFG__40(3, 0, 0x03, RA_PINCFG_FUNC) #define P300_GTOUUP RA_PINCFG__40(3, 0, 0x02, RA_PINCFG_FUNC) #define P300_SSLB1 RA_PINCFG__40(3, 0, 0x06, RA_PINCFG_FUNC) @@ -340,33 +340,33 @@ #define P409_TS05 RA_PINCFG__48(4, 9, 0x0C, RA_PINCFG_FUNC) #define P409_TXD9 RA_PINCFG__48(4, 9, 0x05, RA_PINCFG_FUNC) #define P409_USB_EXICEN RA_PINCFG__48(4, 9, 0x13, RA_PINCFG_FUNC) -#define P410_AGTOB1 RA_PINCFG__64(4, 0, 0x01, RA_PINCFG_FUNC) -#define P410_GTIOC6B RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_GTOVLO RA_PINCFG__64(4, 0, 0x03, RA_PINCFG_FUNC) -#define P410_MISO0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_MISOA RA_PINCFG__64(4, 0, 0x06, RA_PINCFG_FUNC) -#define P410_RXD0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_SCL0 RA_PINCFG__64(4, 0, 0x04, RA_PINCFG_FUNC) -#define P410_SEG08 RA_PINCFG__64(4, 0, 0x0D, RA_PINCFG_FUNC) -#define P410_TS06 RA_PINCFG__64(4, 0, 0x0C, RA_PINCFG_FUNC) -#define P411_AGTOA1 RA_PINCFG__64(4, 1, 0x01, RA_PINCFG_FUNC) -#define P411_GTIOC6A RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_GTOVUP RA_PINCFG__64(4, 1, 0x03, RA_PINCFG_FUNC) -#define P411_MOSI0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_MOSIA RA_PINCFG__64(4, 1, 0x06, RA_PINCFG_FUNC) -#define P411_SDA0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P411_SEG07 RA_PINCFG__64(4, 1, 0x0D, RA_PINCFG_FUNC) -#define P411_TS07 RA_PINCFG__64(4, 1, 0x0C, RA_PINCFG_FUNC) -#define P411_TXD0 RA_PINCFG__64(4, 1, 0x04, RA_PINCFG_FUNC) -#define P412_RSPCKA RA_PINCFG_100(4, 2, 0x06, RA_PINCFG_FUNC) -#define P412_SCK0 RA_PINCFG_100(4, 2, 0x04, RA_PINCFG_FUNC) -#define P413_CTS0_RTS0 RA_PINCFG_100(4, 3, 0x04, RA_PINCFG_FUNC) -#define P413_SS0 RA_PINCFG_100(4, 3, 0x04, RA_PINCFG_FUNC) -#define P413_SSLA0 RA_PINCFG_100(4, 3, 0x06, RA_PINCFG_FUNC) -#define P414_GTIOC0B RA_PINCFG_100(4, 4, 0x04, RA_PINCFG_FUNC) -#define P414_SSLA1 RA_PINCFG_100(4, 4, 0x06, RA_PINCFG_FUNC) -#define P415_GTIOC0A RA_PINCFG_100(4, 5, 0x04, RA_PINCFG_FUNC) -#define P415_SSLA2 RA_PINCFG_100(4, 5, 0x06, RA_PINCFG_FUNC) +#define P410_AGTOB1 RA_PINCFG__64(4, 10, 0x01, RA_PINCFG_FUNC) +#define P410_GTIOC6B RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_GTOVLO RA_PINCFG__64(4, 10, 0x03, RA_PINCFG_FUNC) +#define P410_MISO0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_MISOA RA_PINCFG__64(4, 10, 0x06, RA_PINCFG_FUNC) +#define P410_RXD0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_SCL0 RA_PINCFG__64(4, 10, 0x04, RA_PINCFG_FUNC) +#define P410_SEG08 RA_PINCFG__64(4, 10, 0x0D, RA_PINCFG_FUNC) +#define P410_TS06 RA_PINCFG__64(4, 10, 0x0C, RA_PINCFG_FUNC) +#define P411_AGTOA1 RA_PINCFG__64(4, 11, 0x01, RA_PINCFG_FUNC) +#define P411_GTIOC6A RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_GTOVUP RA_PINCFG__64(4, 11, 0x03, RA_PINCFG_FUNC) +#define P411_MOSI0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_MOSIA RA_PINCFG__64(4, 11, 0x06, RA_PINCFG_FUNC) +#define P411_SDA0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P411_SEG07 RA_PINCFG__64(4, 11, 0x0D, RA_PINCFG_FUNC) +#define P411_TS07 RA_PINCFG__64(4, 11, 0x0C, RA_PINCFG_FUNC) +#define P411_TXD0 RA_PINCFG__64(4, 11, 0x04, RA_PINCFG_FUNC) +#define P412_RSPCKA RA_PINCFG_100(4, 12, 0x06, RA_PINCFG_FUNC) +#define P412_SCK0 RA_PINCFG_100(4, 12, 0x04, RA_PINCFG_FUNC) +#define P413_CTS0_RTS0 RA_PINCFG_100(4, 13, 0x04, RA_PINCFG_FUNC) +#define P413_SS0 RA_PINCFG_100(4, 13, 0x04, RA_PINCFG_FUNC) +#define P413_SSLA0 RA_PINCFG_100(4, 13, 0x06, RA_PINCFG_FUNC) +#define P414_GTIOC0B RA_PINCFG_100(4, 14, 0x04, RA_PINCFG_FUNC) +#define P414_SSLA1 RA_PINCFG_100(4, 14, 0x06, RA_PINCFG_FUNC) +#define P415_GTIOC0A RA_PINCFG_100(4, 15, 0x04, RA_PINCFG_FUNC) +#define P415_SSLA2 RA_PINCFG_100(4, 15, 0x06, RA_PINCFG_FUNC) #define P500_AGTOA0 RA_PINCFG__48(5, 0, 0x01, RA_PINCFG_FUNC) #define P500_AN016 RA_PINCFG__48(5, 0, 0x01, RA_PINCFG_ANALOG) #define P500_CMPREF1 RA_PINCFG__48(5, 0, 0x02, RA_PINCFG_FUNC | RA_PINCFG_ANALOG) @@ -424,14 +424,14 @@ #define P608_SEG27 RA_PINCFG_100(6, 8, 0x0D, RA_PINCFG_FUNC) #define P609_GTIOC5A RA_PINCFG_100(6, 9, 0x01, RA_PINCFG_FUNC) #define P609_SEG28 RA_PINCFG_100(6, 9, 0x0D, RA_PINCFG_FUNC) -#define P610_GTIOC5B RA_PINCFG_100(6, 0, 0x01, RA_PINCFG_FUNC) -#define P610_SEG29 RA_PINCFG_100(6, 0, 0x0D, RA_PINCFG_FUNC) +#define P610_GTIOC5B RA_PINCFG_100(6, 10, 0x01, RA_PINCFG_FUNC) +#define P610_SEG29 RA_PINCFG_100(6, 10, 0x0D, RA_PINCFG_FUNC) #define P708_MISO1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_RXD1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_SCL1 RA_PINCFG_100(7, 8, 0x05, RA_PINCFG_FUNC) #define P708_SSLA3 RA_PINCFG_100(7, 8, 0x06, RA_PINCFG_FUNC) #define P808_SEG21 RA_PINCFG_100(8, 8, 0x0D, RA_PINCFG_FUNC) #define P809_SEG22 RA_PINCFG_100(8, 9, 0x0D, RA_PINCFG_FUNC) -#define P914_USB_DP RA_PINCFG__40(9, 4, 0x00, RA_PINCFG_GPIO) -#define P915_USB_DM RA_PINCFG__40(9, 5, 0x00, RA_PINCFG_GPIO) +#define P914_USB_DP RA_PINCFG__40(9, 14, 0x00, RA_PINCFG_GPIO) +#define P915_USB_DM RA_PINCFG__40(9, 15, 0x00, RA_PINCFG_GPIO) #endif diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h new file mode 100644 index 00000000000..50e8a358007 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-r8a779f0.h @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ + +#include "pinctrl-rcar-common.h" + +/* Pins declaration */ +#define PIN_NONE -1 +#define PIN_SCIF_CLK RCAR_GP_PIN(0, 0) +#define PIN_HSCK0 RCAR_GP_PIN(0, 1) +#define PIN_HRX0 RCAR_GP_PIN(0, 2) +#define PIN_HTX0 RCAR_GP_PIN(0, 3) +#define PIN_HCTS0_N RCAR_GP_PIN(0, 4) +#define PIN_HRTS0_N RCAR_GP_PIN(0, 5) +#define PIN_RX0 RCAR_GP_PIN(0, 6) +#define PIN_TX0 RCAR_GP_PIN(0, 7) +#define PIN_SCK0 RCAR_GP_PIN(0, 8) +#define PIN_RTS0_N RCAR_GP_PIN(0, 9) +#define PIN_CTS0_N RCAR_GP_PIN(0, 10) +#define PIN_MSIOF0_SYNC RCAR_GP_PIN(0, 11) +#define PIN_MSIOF0_RXD RCAR_GP_PIN(0, 12) +#define PIN_MSIOF0_TXD RCAR_GP_PIN(0, 13) +#define PIN_MSIOF0_SCK RCAR_GP_PIN(0, 14) +#define PIN_MSIOF0_SS1 RCAR_GP_PIN(0, 15) +#define PIN_MSIOF0_SS2 RCAR_GP_PIN(0, 16) +#define PIN_IRQ0 RCAR_GP_PIN(0, 17) +#define PIN_IRQ1 RCAR_GP_PIN(0, 18) +#define PIN_IRQ2 RCAR_GP_PIN(0, 19) +#define PIN_IRQ3 RCAR_GP_PIN(0, 20) +#define PIN_GP1_00 RCAR_GP_PIN(1, 0) +#define PIN_GP1_01 RCAR_GP_PIN(1, 1) +#define PIN_GP1_02 RCAR_GP_PIN(1, 2) +#define PIN_GP1_03 RCAR_GP_PIN(1, 3) +#define PIN_GP1_04 RCAR_GP_PIN(1, 4) +#define PIN_GP1_05 RCAR_GP_PIN(1, 5) +#define PIN_GP1_06 RCAR_GP_PIN(1, 6) +#define PIN_GP1_07 RCAR_GP_PIN(1, 7) +#define PIN_GP1_08 RCAR_GP_PIN(1, 8) +#define PIN_GP1_09 RCAR_GP_PIN(1, 9) +#define PIN_GP1_10 RCAR_GP_PIN(1, 10) +#define PIN_GP1_11 RCAR_GP_PIN(1, 11) +#define PIN_MMC_SD_CLK RCAR_GP_PIN(1, 12) +#define PIN_MMC_SD_D0 RCAR_GP_PIN(1, 13) +#define PIN_MMC_SD_D1 RCAR_GP_PIN(1, 14) +#define PIN_MMC_SD_D2 RCAR_GP_PIN(1, 15) +#define PIN_MMC_SD_D3 RCAR_GP_PIN(1, 16) +#define PIN_MMC_D5 RCAR_GP_PIN(1, 17) +#define PIN_MMC_D4 RCAR_GP_PIN(1, 18) +#define PIN_MMC_D6 RCAR_GP_PIN(1, 19) +#define PIN_MMC_DS RCAR_GP_PIN(1, 20) +#define PIN_MMC_D7 RCAR_GP_PIN(1, 21) +#define PIN_MMC_SD_CMD RCAR_GP_PIN(1, 22) +#define PIN_SD_CD RCAR_GP_PIN(1, 23) +#define PIN_SD_WP RCAR_GP_PIN(1, 24) +#define PIN_RPC_INT_N RCAR_GP_PIN(2, 0) +#define PIN_RPC_WP_N RCAR_GP_PIN(2, 1) +#define PIN_RPC_RESET_N RCAR_GP_PIN(2, 2) +#define PIN_QSPI1_SSL RCAR_GP_PIN(2, 3) +#define PIN_QSPI1_IO3 RCAR_GP_PIN(2, 4) +#define PIN_QSPI1_MISO_IO1 RCAR_GP_PIN(2, 5) +#define PIN_QSPI1_IO2 RCAR_GP_PIN(2, 6) +#define PIN_QSPI1_MOSI_IO0 RCAR_GP_PIN(2, 7) +#define PIN_QSPI1_SPCLK RCAR_GP_PIN(2, 8) +#define PIN_QSPI0_MOSI_IO0 RCAR_GP_PIN(2, 9) +#define PIN_QSPI0_SPCLK RCAR_GP_PIN(2, 10) +#define PIN_QSPI0_IO2 RCAR_GP_PIN(2, 11) +#define PIN_QSPI0_MISO_IO1 RCAR_GP_PIN(2, 12) +#define PIN_QSPI0_SSL RCAR_GP_PIN(2, 13) +#define PIN_QSPI0_IO3 RCAR_GP_PIN(2, 14) +#define PIN_PCIE0_CLKREQ_N RCAR_GP_PIN(2, 15) +#define PIN_PCIE1_CLKREQ_N RCAR_GP_PIN(2, 16) +#define PIN_TSN1_MDIO RCAR_GP_PIN(3, 0) +#define PIN_TSN2_MDIO RCAR_GP_PIN(3, 1) +#define PIN_TSN0_MDIO RCAR_GP_PIN(3, 2) +#define PIN_TSN2_MDC RCAR_GP_PIN(3, 3) +#define PIN_TSN0_MDC RCAR_GP_PIN(3, 4) +#define PIN_TSN1_MDC RCAR_GP_PIN(3, 5) +#define PIN_TSN1_LINK RCAR_GP_PIN(3, 6) +#define PIN_TSN2_LINK RCAR_GP_PIN(3, 7) +#define PIN_TSN0_LINK RCAR_GP_PIN(3, 8) +#define PIN_TSN2_PHY_INT RCAR_GP_PIN(3, 9) +#define PIN_TSN0_PHY_INT RCAR_GP_PIN(3, 10) +#define PIN_TSN1_PHY_INT RCAR_GP_PIN(3, 11) +#define PIN_TSN0_MAGIC RCAR_GP_PIN(3, 12) +#define PIN_TSN1_AVTP_PPS RCAR_GP_PIN(3, 13) +#define PIN_TSN1_AVTP_MATCH RCAR_GP_PIN(3, 14) +#define PIN_TSN1_AVTP_CAPTURE RCAR_GP_PIN(3, 15) +#define PIN_TSN0_AVTP_PPS RCAR_GP_PIN(3, 16) +#define PIN_TSN0_AVTP_MATCH RCAR_GP_PIN(3, 17) +#define PIN_TSN0_AVTP_CAPTURE RCAR_GP_PIN(3, 18) +#define PIN_GP4_00 RCAR_GP_PIN(4, 0) +#define PIN_GP4_01 RCAR_GP_PIN(4, 1) +#define PIN_GP4_02 RCAR_GP_PIN(4, 2) +#define PIN_GP4_03 RCAR_GP_PIN(4, 3) +#define PIN_GP4_04 RCAR_GP_PIN(4, 4) +#define PIN_GP4_05 RCAR_GP_PIN(4, 5) +#define PIN_GP4_06 RCAR_GP_PIN(4, 6) +#define PIN_GP4_07 RCAR_GP_PIN(4, 7) +#define PIN_GP4_08 RCAR_GP_PIN(4, 8) +#define PIN_GP4_09 RCAR_GP_PIN(4, 9) +#define PIN_GP4_10 RCAR_GP_PIN(4, 10) +#define PIN_GP4_11 RCAR_GP_PIN(4, 11) +#define PIN_GP4_12 RCAR_GP_PIN(4, 12) +#define PIN_GP4_13 RCAR_GP_PIN(4, 13) +#define PIN_GP4_14 RCAR_GP_PIN(4, 14) +#define PIN_GP4_15 RCAR_GP_PIN(4, 15) +#define PIN_GP4_16 RCAR_GP_PIN(4, 16) +#define PIN_GP4_17 RCAR_GP_PIN(4, 17) +#define PIN_GP4_18 RCAR_GP_PIN(4, 18) +#define PIN_GP4_19 RCAR_GP_PIN(4, 19) +#define PIN_MSPI0SC RCAR_GP_PIN(4, 20) +#define PIN_MSPI0SI RCAR_GP_PIN(4, 21) +#define PIN_MSPI0SO_MSPI0DCS RCAR_GP_PIN(4, 22) +#define PIN_MSPI0CSS1 RCAR_GP_PIN(4, 23) +#define PIN_MSPI0CSS0 RCAR_GP_PIN(4, 24) +#define PIN_MSPI1SI RCAR_GP_PIN(4, 25) +#define PIN_MSPI1SO_MSPI1DCS RCAR_GP_PIN(4, 26) +#define PIN_MSPI1CSS0 RCAR_GP_PIN(4, 27) +#define PIN_MSPI1SC RCAR_GP_PIN(4, 28) +#define PIN_MSPI1CSS2 RCAR_GP_PIN(4, 29) +#define PIN_MSPI1CSS1 RCAR_GP_PIN(4, 30) +#define PIN_RIIC0SCL RCAR_GP_PIN(5, 0) +#define PIN_RIIC0SDA RCAR_GP_PIN(5, 1) +#define PIN_ETNB0MD RCAR_GP_PIN(5, 2) +#define PIN_ETNB0WOL RCAR_GP_PIN(5, 3) +#define PIN_ETNB0LINKSTA RCAR_GP_PIN(5, 4) +#define PIN_ETNB0MDC RCAR_GP_PIN(5, 5) +#define PIN_ETNB0RXER RCAR_GP_PIN(5, 6) +#define PIN_ETNB0RXD3 RCAR_GP_PIN(5, 7) +#define PIN_ETNB0RXD1 RCAR_GP_PIN(5, 8) +#define PIN_ETNB0RXD2 RCAR_GP_PIN(5, 9) +#define PIN_ETNB0RXDV RCAR_GP_PIN(5, 10) +#define PIN_ETNB0RXD0 RCAR_GP_PIN(5, 11) +#define PIN_ETNB0RXCLK RCAR_GP_PIN(5, 12) +#define PIN_ETNB0TXER RCAR_GP_PIN(5, 13) +#define PIN_ETNB0TXD3 RCAR_GP_PIN(5, 14) +#define PIN_ETNB0TXCLK RCAR_GP_PIN(5, 15) +#define PIN_ETNB0TXD1 RCAR_GP_PIN(5, 16) +#define PIN_ETNB0TXD2 RCAR_GP_PIN(5, 17) +#define PIN_ETNB0TXEN RCAR_GP_PIN(5, 18) +#define PIN_ETNB0TXD0 RCAR_GP_PIN(5, 19) +#define PIN_RLIN37TX RCAR_GP_PIN(6, 0) +#define PIN_RLIN37RX_INTP23 RCAR_GP_PIN(6, 1) +#define PIN_RLIN36TX RCAR_GP_PIN(6, 2) +#define PIN_RLIN36RX_INTP22 RCAR_GP_PIN(6, 3) +#define PIN_RLIN35TX RCAR_GP_PIN(6, 4) +#define PIN_RLIN35RX_INTP21 RCAR_GP_PIN(6, 5) +#define PIN_RLIN34TX RCAR_GP_PIN(6, 6) +#define PIN_RLIN34RX_INTP20 RCAR_GP_PIN(6, 7) +#define PIN_RLIN33TX RCAR_GP_PIN(6, 8) +#define PIN_RLIN33RX_INTP19 RCAR_GP_PIN(6, 9) +#define PIN_RLIN32TX RCAR_GP_PIN(6, 10) +#define PIN_RLIN32RX_INTP18 RCAR_GP_PIN(6, 11) +#define PIN_RLIN31TX RCAR_GP_PIN(6, 12) +#define PIN_RLIN31RX_INTP17 RCAR_GP_PIN(6, 13) +#define PIN_RLIN30TX RCAR_GP_PIN(6, 14) +#define PIN_RLIN30RX_INTP16 RCAR_GP_PIN(6, 15) +#define PIN_INTP37 RCAR_GP_PIN(6, 16) +#define PIN_INTP36 RCAR_GP_PIN(6, 17) +#define PIN_INTP35 RCAR_GP_PIN(6, 18) +#define PIN_INTP34 RCAR_GP_PIN(6, 19) +#define PIN_INTP33 RCAR_GP_PIN(6, 20) +#define PIN_INTP32 RCAR_GP_PIN(6, 21) +#define PIN_NMI1 RCAR_GP_PIN(6, 22) +#define PIN_PRESETOUT1_N RCAR_GP_PIN(6, 31) +#define PIN_CAN0TX RCAR_GP_PIN(7, 0) +#define PIN_CAN0RX_INTP0 RCAR_GP_PIN(7, 1) +#define PIN_CAN1TX RCAR_GP_PIN(7, 2) +#define PIN_CAN1RX_INTP1 RCAR_GP_PIN(7, 3) +#define PIN_CAN2TX RCAR_GP_PIN(7, 4) +#define PIN_CAN2RX_INTP2 RCAR_GP_PIN(7, 5) +#define PIN_CAN3TX RCAR_GP_PIN(7, 6) +#define PIN_CAN3RX_INTP3 RCAR_GP_PIN(7, 7) +#define PIN_CAN4TX RCAR_GP_PIN(7, 8) +#define PIN_CAN4RX_INTP4 RCAR_GP_PIN(7, 9) +#define PIN_CAN5TX RCAR_GP_PIN(7, 10) +#define PIN_CAN5RX_INTP5 RCAR_GP_PIN(7, 11) +#define PIN_CAN6TX RCAR_GP_PIN(7, 12) +#define PIN_CAN6RX_INTP6 RCAR_GP_PIN(7, 13) +#define PIN_CAN7TX RCAR_GP_PIN(7, 14) +#define PIN_CAN7RX_INTP7 RCAR_GP_PIN(7, 15) +#define PIN_CAN8TX RCAR_GP_PIN(7, 16) +#define PIN_CAN8RX_INTP8 RCAR_GP_PIN(7, 17) +#define PIN_CAN9TX RCAR_GP_PIN(7, 18) +#define PIN_CAN9RX_INTP9 RCAR_GP_PIN(7, 19) +#define PIN_CAN10TX RCAR_GP_PIN(7, 20) +#define PIN_CAN10RX_INTP10 RCAR_GP_PIN(7, 21) +#define PIN_CAN11TX RCAR_GP_PIN(7, 22) +#define PIN_CAN11RX_INTP11 RCAR_GP_PIN(7, 23) +#define PIN_CAN12TX RCAR_GP_PIN(7, 24) +#define PIN_CAN12RX_INTP12 RCAR_GP_PIN(7, 25) +#define PIN_CAN13TX RCAR_GP_PIN(7, 26) +#define PIN_CAN13RX_INTP13 RCAR_GP_PIN(7, 27) +#define PIN_CAN14TX RCAR_GP_PIN(7, 28) +#define PIN_CAN14RX_INTP14 RCAR_GP_PIN(7, 29) +#define PIN_CAN15TX RCAR_GP_PIN(7, 30) +#define PIN_CAN15RX_INTP15 RCAR_GP_PIN(7, 31) + +/* Pinmux function declarations */ +#define FUNC_SCIF_CLK IP0SR0(0, 0) +#define FUNC_HSCK0 IP0SR0(4, 0) +#define FUNC_SCK3 IP0SR0(4, 1) +#define FUNC_MSIOF3_SCK IP0SR0(4, 2) +#define FUNC_TSN0_AVTP_CAPTURE_A IP0SR0(4, 5) +#define FUNC_HRX0 IP0SR0(8, 0) +#define FUNC_RX3 IP0SR0(8, 1) +#define FUNC_MSIOF3_RXD IP0SR0(8, 2) +#define FUNC_TSN0_AVTP_MATCH_A IP0SR0(8, 5) +#define FUNC_HTX0 IP0SR0(12, 0) +#define FUNC_TX3 IP0SR0(12, 1) +#define FUNC_MSIOF3_TXD IP0SR0(12, 2) +#define FUNC_HCTS0_N IP0SR0(16, 0) +#define FUNC_CTS3_N IP0SR0(16, 1) +#define FUNC_MSIOF3_SS1 IP0SR0(16, 2) +#define FUNC_TSN0_MDC_A IP0SR0(16, 5) +#define FUNC_HRTS0_N IP0SR0(20, 0) +#define FUNC_RTS3_N IP0SR0(20, 1) +#define FUNC_MSIOF3_SS2 IP0SR0(20, 2) +#define FUNC_TSN0_MDIO_A IP0SR0(20, 5) +#define FUNC_RX0 IP0SR0(24, 0) +#define FUNC_HRX1 IP0SR0(24, 1) +#define FUNC_MSIOF1_RXD IP0SR0(24, 3) +#define FUNC_TSN1_AVTP_MATCH_A IP0SR0(24, 5) +#define FUNC_TX0 IP0SR0(28, 0) +#define FUNC_HTX1 IP0SR0(28, 1) +#define FUNC_MSIOF1_TXD IP0SR0(28, 3) +#define FUNC_TSN1_AVTP_CAPTURE_A IP0SR0(28, 5) +#define FUNC_SCK0 IP1SR0(0, 0) +#define FUNC_HSCK1 IP1SR0(0, 1) +#define FUNC_MSIOF1_SCK IP1SR0(0, 3) +#define FUNC_RTS0_N IP1SR0(4, 0) +#define FUNC_HRTS1_N IP1SR0(4, 1) +#define FUNC_MSIOF3_SYNC IP1SR0(4, 2) +#define FUNC_TSN1_MDIO_A IP1SR0(4, 5) +#define FUNC_CTS0_N IP1SR0(8, 0) +#define FUNC_HCTS1_N IP1SR0(8, 1) +#define FUNC_MSIOF1_SYNC IP1SR0(8, 3) +#define FUNC_TSN1_MDC_A IP1SR0(8, 5) +#define FUNC_MSIOF0_SYNC IP1SR0(12, 0) +#define FUNC_HCTS3_N IP1SR0(12, 1) +#define FUNC_CTS1_N IP1SR0(12, 2) +#define FUNC_IRQ4 IP1SR0(12, 3) +#define FUNC_TSN0_LINK_A IP1SR0(12, 5) +#define FUNC_MSIOF0_RXD IP1SR0(16, 0) +#define FUNC_HRX3 IP1SR0(16, 1) +#define FUNC_RX1 IP1SR0(16, 2) +#define FUNC_MSIOF0_TXD IP1SR0(20, 0) +#define FUNC_HTX3 IP1SR0(20, 1) +#define FUNC_TX1 IP1SR0(20, 2) +#define FUNC_MSIOF0_SCK IP1SR0(24, 0) +#define FUNC_HSCK3 IP1SR0(24, 1) +#define FUNC_SCK1 IP1SR0(24, 2) +#define FUNC_MSIOF0_SS1 IP1SR0(28, 0) +#define FUNC_HRTS3_N IP1SR0(28, 1) +#define FUNC_RTS1_N IP1SR0(28, 2) +#define FUNC_IRQ5 IP1SR0(28, 3) +#define FUNC_TSN1_LINK_A IP1SR0(28, 5) +#define FUNC_MSIOF0_SS2 IP2SR0(0, 0) +#define FUNC_TSN2_LINK_A IP2SR0(0, 5) +#define FUNC_IRQ0 IP2SR0(4, 0) +#define FUNC_MSIOF1_SS1 IP2SR0(4, 3) +#define FUNC_TSN0_MAGIC_A IP2SR0(4, 5) +#define FUNC_IRQ1 IP2SR0(8, 0) +#define FUNC_MSIOF1_SS2 IP2SR0(8, 3) +#define FUNC_TSN0_PHY_INT_A IP2SR0(8, 5) +#define FUNC_IRQ2 IP2SR0(12, 0) +#define FUNC_TSN1_PHY_INT_A IP2SR0(12, 5) +#define FUNC_IRQ3 IP2SR0(16, 0) +#define FUNC_TSN2_PHY_INT_A IP2SR0(16, 5) +#define FUNC_GP1_00 IP0SR1(0, 0) +#define FUNC_TCLK1 IP0SR1(0, 1) +#define FUNC_HSCK2 IP0SR1(0, 2) +#define FUNC_GP1_01 IP0SR1(4, 0) +#define FUNC_TCLK4 IP0SR1(4, 1) +#define FUNC_HRX2 IP0SR1(4, 2) +#define FUNC_GP1_02 IP0SR1(8, 0) +#define FUNC_HTX2 IP0SR1(8, 2) +#define FUNC_MSIOF2_SS1 IP0SR1(8, 3) +#define FUNC_TSN2_MDC_A IP0SR1(8, 5) +#define FUNC_GP1_03 IP0SR1(12, 0) +#define FUNC_TCLK2 IP0SR1(12, 1) +#define FUNC_HCTS2_N IP0SR1(12, 2) +#define FUNC_MSIOF2_SS2 IP0SR1(12, 3) +#define FUNC_CTS4_N IP0SR1(12, 4) +#define FUNC_TSN2_MDIO_A IP0SR1(12, 5) +#define FUNC_GP1_04 IP0SR1(16, 0) +#define FUNC_TCLK3 IP0SR1(16, 1) +#define FUNC_HRTS2_N IP0SR1(16, 2) +#define FUNC_MSIOF2_SYNC IP0SR1(16, 3) +#define FUNC_RTS4_N IP0SR1(16, 4) +#define FUNC_GP1_05 IP0SR1(20, 0) +#define FUNC_MSIOF2_SCK IP0SR1(20, 1) +#define FUNC_SCK4 IP0SR1(20, 2) +#define FUNC_GP1_06 IP0SR1(24, 0) +#define FUNC_MSIOF2_RXD IP0SR1(24, 1) +#define FUNC_RX4 IP0SR1(24, 2) +#define FUNC_GP1_07 IP0SR1(28, 0) +#define FUNC_MSIOF2_TXD IP0SR1(28, 1) +#define FUNC_TX4 IP0SR1(28, 2) +#define FUNC_GP4_00 IP0SR4(0, 0) +#define FUNC_MSPI4SC IP0SR4(0, 1) +#define FUNC_TAUD0I2 IP0SR4(0, 3) +#define FUNC_TAUD0O2 IP0SR4(0, 4) +#define FUNC_GP4_01 IP0SR4(4, 0) +#define FUNC_MSPI4SI IP0SR4(4, 1) +#define FUNC_TAUD0I4 IP0SR4(4, 3) +#define FUNC_TAUD0O4 IP0SR4(4, 4) +#define FUNC_GP4_02 IP0SR4(8, 0) +#define FUNC_MSPI4SO_MSPI4DCS IP0SR4(8, 1) +#define FUNC_TAUD0I3 IP0SR4(8, 3) +#define FUNC_TAUD0O3 IP0SR4(8, 4) +#define FUNC_GP4_03 IP0SR4(12, 0) +#define FUNC_MSPI4CSS1 IP0SR4(12, 1) +#define FUNC_TAUD0I6 IP0SR4(12, 3) +#define FUNC_TAUD0O6 IP0SR4(12, 4) +#define FUNC_GP4_04 IP0SR4(16, 0) +#define FUNC_MSPI4CSS0 IP0SR4(16, 1) +#define FUNC_MSPI4SSI_N IP0SR4(16, 2) +#define FUNC_TAUD0I5 IP0SR4(16, 3) +#define FUNC_TAUD0O5 IP0SR4(16, 4) +#define FUNC_GP4_05 IP0SR4(20, 0) +#define FUNC_MSPI4CSS3 IP0SR4(20, 1) +#define FUNC_TAUD0I8 IP0SR4(20, 3) +#define FUNC_TAUD0O8 IP0SR4(20, 4) +#define FUNC_GP4_06 IP0SR4(24, 0) +#define FUNC_MSPI4CSS2 IP0SR4(24, 1) +#define FUNC_TAUD0I7 IP0SR4(24, 3) +#define FUNC_TAUD0O7 IP0SR4(24, 4) +#define FUNC_GP4_07 IP0SR4(28, 0) +#define FUNC_MSPI4CSS5 IP0SR4(28, 1) +#define FUNC_TAUD0I10 IP0SR4(28, 3) +#define FUNC_TAUD0O10 IP0SR4(28, 4) +#define FUNC_GP4_08 IP1SR4(0, 0) +#define FUNC_MSPI4CSS4 IP1SR4(0, 1) +#define FUNC_TAUD0I9 IP1SR4(0, 3) +#define FUNC_TAUD0O9 IP1SR4(0, 4) +#define FUNC_GP4_09 IP1SR4(4, 0) +#define FUNC_MSPI4CSS7 IP1SR4(4, 1) +#define FUNC_TAUD0I12 IP1SR4(4, 3) +#define FUNC_TAUD0O12 IP1SR4(4, 4) +#define FUNC_GP4_10 IP1SR4(8, 0) +#define FUNC_MSPI4CSS6 IP1SR4(8, 1) +#define FUNC_TAUD0I11 IP1SR4(8, 3) +#define FUNC_TAUD0O11 IP1SR4(8, 4) +#define FUNC_GP4_11 IP1SR4(12, 0) +#define FUNC_ERRORIN0_N IP1SR4(12, 1) +#define FUNC_TAUD0I14 IP1SR4(12, 3) +#define FUNC_TAUD0O14 IP1SR4(12, 4) +#define FUNC_GP4_12 IP1SR4(16, 0) +#define FUNC_ERROROUT_C_N IP1SR4(16, 1) +#define FUNC_TAUD0I13 IP1SR4(16, 3) +#define FUNC_TAUD0O13 IP1SR4(16, 4) +#define FUNC_GP4_13 IP1SR4(20, 0) +#define FUNC_GP4_14 IP1SR4(24, 0) +#define FUNC_ERRORIN1_N IP1SR4(24, 1) +#define FUNC_TAUD0I15 IP1SR4(24, 3) +#define FUNC_TAUD0O15 IP1SR4(24, 4) +#define FUNC_GP4_15 IP1SR4(28, 0) +#define FUNC_MSPI1CSS3 IP1SR4(28, 1) +#define FUNC_TAUD1I1 IP1SR4(28, 3) +#define FUNC_TAUD1O1 IP1SR4(28, 4) +#define FUNC_GP4_16 IP2SR4(0, 0) +#define FUNC_TAUD1I0 IP2SR4(0, 3) +#define FUNC_TAUD1O0 IP2SR4(0, 4) +#define FUNC_GP4_17 IP2SR4(4, 0) +#define FUNC_MSPI1CSS5 IP2SR4(4, 1) +#define FUNC_TAUD1I3 IP2SR4(4, 3) +#define FUNC_TAUD1O3 IP2SR4(4, 4) +#define FUNC_GP4_18 IP2SR4(8, 0) +#define FUNC_MSPI1CSS4 IP2SR4(8, 1) +#define FUNC_TAUD1I2 IP2SR4(8, 3) +#define FUNC_TAUD1O2 IP2SR4(8, 4) +#define FUNC_GP4_19 IP2SR4(12, 0) +#define FUNC_MSPI1CSS6 IP2SR4(12, 1) +#define FUNC_TAUD1I4 IP2SR4(12, 3) +#define FUNC_TAUD1O4 IP2SR4(12, 4) +#define FUNC_MSPI0SC IP2SR4(16, 0) +#define FUNC_MSPI1CSS7 IP2SR4(16, 1) +#define FUNC_TAUD1I5 IP2SR4(16, 3) +#define FUNC_TAUD1O5 IP2SR4(16, 4) +#define FUNC_MSPI0SI IP2SR4(20, 0) +#define FUNC_TAUD1I7 IP2SR4(20, 3) +#define FUNC_TAUD1O7 IP2SR4(20, 4) +#define FUNC_MSPI0SO_MSPI0DCS IP2SR4(24, 0) +#define FUNC_TAUD1I6 IP2SR4(24, 3) +#define FUNC_TAUD1O6 IP2SR4(24, 4) +#define FUNC_MSPI0CSS1 IP2SR4(28, 0) +#define FUNC_TAUD1I9 IP2SR4(28, 3) +#define FUNC_TAUD1O9 IP2SR4(28, 4) +#define FUNC_MSPI0CSS0 IP3SR4(0, 0) +#define FUNC_MSPI0SSI_N IP3SR4(0, 1) +#define FUNC_TAUD1I8 IP3SR4(0, 3) +#define FUNC_TAUD1O8 IP3SR4(0, 4) +#define FUNC_MSPI1SO_MSPI1DCS IP3SR4(8, 0) +#define FUNC_MSPI0CSS3 IP3SR4(8, 2) +#define FUNC_TAUD1I11 IP3SR4(8, 3) +#define FUNC_TAUD1O11 IP3SR4(8, 4) +#define FUNC_MSPI1SC IP3SR4(16, 0) +#define FUNC_MSPI0CSS2 IP3SR4(16, 2) +#define FUNC_TAUD1I10 IP3SR4(16, 3) +#define FUNC_TAUD1O10 IP3SR4(16, 4) +#define FUNC_RIIC0SCL IP0SR5(0, 0) +#define FUNC_TAUD0I0 IP0SR5(0, 3) +#define FUNC_TAUD0O0 IP0SR5(0, 4) +#define FUNC_RIIC0SDA IP0SR5(4, 0) +#define FUNC_TAUD0I1 IP0SR5(4, 3) +#define FUNC_TAUD0O1 IP0SR5(4, 4) +#define FUNC_ETNB0MD IP0SR5(8, 0) +#define FUNC_ETNB0WOL IP0SR5(12, 0) +#define FUNC_ETNB0LINKSTA IP0SR5(16, 0) +#define FUNC_ETNB0MDC IP0SR5(20, 0) +#define FUNC_ETNB0RXCLK IP0SR5(24, 0) +#define FUNC_ETNB0CRS_DV IP0SR5(24, 1) +#define FUNC_ETNB0TXCLK IP0SR5(28, 0) +#define FUNC_ETNB0REFCLK IP0SR5(28, 1) +#define FUNC_RLIN33TX IP1SR6(0, 0) +#define FUNC_TAUJ3O3 IP1SR6(0, 3) +#define FUNC_TAUJ3I3 IP1SR6(0, 4) +#define FUNC_NMI1 IP1SR6(0, 5) +#define FUNC_RLIN33RX_INTP19 IP1SR6(4, 0) +#define FUNC_TAUJ3O2 IP1SR6(4, 3) +#define FUNC_TAUJ3I2 IP1SR6(4, 4) +#define FUNC_RLIN32TX IP1SR6(8, 0) +#define FUNC_TAUJ3O1 IP1SR6(8, 3) +#define FUNC_TAUJ3I1 IP1SR6(8, 4) +#define FUNC_RLIN32RX_INTP18 IP1SR6(12, 0) +#define FUNC_TAUJ3O0 IP1SR6(12, 3) +#define FUNC_TAUJ3I0 IP1SR6(12, 4) +#define FUNC_INTP35 IP1SR6(12, 5) +#define FUNC_RLIN31TX IP1SR6(16, 0) +#define FUNC_TAUJ1I3 IP1SR6(16, 3) +#define FUNC_TAUJ1O3 IP1SR6(16, 4) +#define FUNC_INTP34 IP1SR6(16, 5) +#define FUNC_RLIN31RX_INTP17 IP1SR6(20, 0) +#define FUNC_TAUJ1I2 IP1SR6(20, 3) +#define FUNC_TAUJ1O2 IP1SR6(20, 4) +#define FUNC_INTP33 IP1SR6(20, 5) +#define FUNC_RLIN30TX IP1SR6(24, 0) +#define FUNC_TAUJ1I1 IP1SR6(24, 3) +#define FUNC_TAUJ1O1 IP1SR6(24, 4) +#define FUNC_RLIN30RX_INTP16 IP1SR6(28, 0) +#define FUNC_TAUJ1I0 IP1SR6(28, 3) +#define FUNC_TAUJ1O0 IP1SR6(28, 4) +#define FUNC_FLXA0STPWT IP2SR6(8, 2) +#define FUNC_CAN0TX IP0SR7(0, 0) +#define FUNC_RSENT0SPCO IP0SR7(0, 1) +#define FUNC_MSPI2SO_MSPI2DCS IP0SR7(0, 3) +#define FUNC_CAN0RX_INTP0 IP0SR7(4, 0) +#define FUNC_RSENT0RX IP0SR7(4, 1) +#define FUNC_RSENT0RX_RSENT0SPCO IP0SR7(4, 2) +#define FUNC_MSPI2SC IP0SR7(4, 3) +#define FUNC_CAN1TX IP0SR7(8, 0) +#define FUNC_RSENT1SPCO IP0SR7(8, 1) +#define FUNC_MSPI2SSI_N IP0SR7(8, 3) +#define FUNC_MSPI2CSS0 IP0SR7(8, 4) +#define FUNC_CAN1RX_INTP1 IP0SR7(12, 0) +#define FUNC_RSENT1RX IP0SR7(12, 1) +#define FUNC_RSENT1RX_RSENT1SPCO IP0SR7(12, 2) +#define FUNC_MSPI2SI IP0SR7(12, 3) +#define FUNC_CAN2TX IP0SR7(16, 0) +#define FUNC_RSENT2SPCO IP0SR7(16, 1) +#define FUNC_MSPI2CSS2 IP0SR7(16, 4) +#define FUNC_CAN2RX_INTP2 IP0SR7(20, 0) +#define FUNC_RSENT2RX IP0SR7(20, 1) +#define FUNC_RSENT2RX_RSENT2SPCO IP0SR7(20, 2) +#define FUNC_MSPI2CSS1 IP0SR7(20, 4) +#define FUNC_CAN3TX IP0SR7(24, 0) +#define FUNC_RSENT3SPCO IP0SR7(24, 1) +#define FUNC_MSPI2CSS4 IP0SR7(24, 4) +#define FUNC_CAN3RX_INTP3 IP0SR7(28, 0) +#define FUNC_RSENT3RX IP0SR7(28, 1) +#define FUNC_RSENT3RX_RSENT3SPCO IP0SR7(28, 2) +#define FUNC_MSPI2CSS3 IP0SR7(28, 4) +#define FUNC_CAN4TX IP1SR7(0, 0) +#define FUNC_RSENT4SPCO IP1SR7(0, 1) +#define FUNC_MSPI2CSS6 IP1SR7(0, 4) +#define FUNC_CAN4RX_INTP4 IP1SR7(4, 0) +#define FUNC_RSENT4RX IP1SR7(4, 1) +#define FUNC_RSENT4RX_RSENT4SPCO IP1SR7(4, 2) +#define FUNC_MSPI2CSS5 IP1SR7(4, 4) +#define FUNC_CAN5TX IP1SR7(8, 0) +#define FUNC_RSENT5SPCO IP1SR7(8, 1) +#define FUNC_CAN5RX_INTP5 IP1SR7(12, 0) +#define FUNC_RSENT5RX IP1SR7(12, 1) +#define FUNC_RSENT5RX_RSENT5SPCO IP1SR7(12, 2) +#define FUNC_MSPI2CSS7 IP1SR7(12, 4) +#define FUNC_CAN6TX IP1SR7(16, 0) +#define FUNC_RSENT6SPCO IP1SR7(16, 1) +#define FUNC_MSPI3SO_MSPI3DCS IP1SR7(16, 3) +#define FUNC_CAN6RX_INTP6 IP1SR7(20, 0) +#define FUNC_RSENT6RX IP1SR7(20, 1) +#define FUNC_RSENT6RX_RSENT6SPCO IP1SR7(20, 2) +#define FUNC_MSPI3SC IP1SR7(20, 3) +#define FUNC_CAN7TX IP1SR7(24, 0) +#define FUNC_RSENT7SPCO IP1SR7(24, 1) +#define FUNC_MSPI3SSI_N IP1SR7(24, 3) +#define FUNC_CAN7RX_INTP7 IP1SR7(28, 0) +#define FUNC_RSENT7RX IP1SR7(28, 1) +#define FUNC_RSENT7RX_RSENT7SPCO IP1SR7(28, 2) +#define FUNC_MSPI3SI IP1SR7(28, 3) +#define FUNC_CAN8TX IP2SR7(0, 0) +#define FUNC_RLIN38TX IP2SR7(0, 1) +#define FUNC_MSPI3CSS1 IP2SR7(0, 3) +#define FUNC_CAN8RX_INTP8 IP2SR7(4, 0) +#define FUNC_RLIN38RX_INTP24 IP2SR7(4, 1) +#define FUNC_MSPI3CSS0 IP2SR7(4, 3) +#define FUNC_CAN9TX IP2SR7(8, 0) +#define FUNC_RLIN39TX IP2SR7(8, 1) +#define FUNC_MSPI3CSS3 IP2SR7(8, 3) +#define FUNC_CAN9RX_INTP9 IP2SR7(12, 0) +#define FUNC_RLIN39RX_INTP25 IP2SR7(12, 1) +#define FUNC_MSPI3CSS2 IP2SR7(12, 3) +#define FUNC_CAN10TX IP2SR7(16, 0) +#define FUNC_RLIN310TX IP2SR7(16, 1) +#define FUNC_MSPI3CSS5 IP2SR7(16, 3) +#define FUNC_CAN10RX_INTP10 IP2SR7(20, 0) +#define FUNC_RLIN310RX_INTP26 IP2SR7(20, 1) +#define FUNC_MSPI3CSS4 IP2SR7(20, 3) +#define FUNC_CAN11TX IP2SR7(24, 0) +#define FUNC_RLIN311TX IP2SR7(24, 1) +#define FUNC_MSPI3CSS7 IP2SR7(24, 3) +#define FUNC_CAN11RX_INTP11 IP2SR7(28, 0) +#define FUNC_RLIN311RX_INTP27 IP2SR7(28, 1) +#define FUNC_MSPI3CSS6 IP2SR7(28, 3) +#define FUNC_FLXA0RXDB IP3SR7(8, 2) +#define FUNC_FLXA0RXDA IP3SR7(12, 2) +#define FUNC_FLXA0TXDB IP3SR7(16, 2) +#define FUNC_FLXA0TXDA IP3SR7(20, 2) +#define FUNC_FLXA0TXENB IP3SR7(24, 2) +#define FUNC_FLXA0TXENA IP3SR7(28, 2) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_R8A779F0_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h index 88ea7ece75d..a7969523a93 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra-common.h @@ -12,7 +12,7 @@ #define PSEL_POS 24 #define PSEL_MASK 0x5 #define PORT_POS 21 -#define PORT_MASK 0x3 +#define PORT_MASK 0x7 #define PIN_POS 17 #define PIN_MASK 0xF #define OPT_POS 0 diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h index fc8d5090e84..30a2afe1db1 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-rcar-common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,8 +17,10 @@ * @param func the 4 bits encoded alternate function. * * Function code [ 0 : 3 ] - * Function shift [ 4 : 9 ] - * IPSR bank [ 10 : 13 ] + * Function shift [ 4 : 8 ] + * Empty [ 9 ] + * IPSR bank [ 10 : 14 ] + * Register index [ 15 : 17 ] (S4 only) */ #define IPSR(bank, shift, func) (((bank) << 10U) | ((shift) << 4U) | (func)) @@ -40,4 +42,48 @@ */ #define RCAR_NOGP_PIN(pin) (PIN_NOGPSR_START + pin) +/* Renesas Gen4 has IPSR registers at different base address + * reg is here an index for the base address. + * Each base address has 4 IPSR banks. + */ +#define IPnSR(bank, reg, shift, func) \ + IPSR(((reg) << 5U) | (bank), shift, func) + +#define IP0SR0(shift, func) IPnSR(0, 0, shift, func) +#define IP1SR0(shift, func) IPnSR(1, 0, shift, func) +#define IP2SR0(shift, func) IPnSR(2, 0, shift, func) +#define IP3SR0(shift, func) IPnSR(3, 0, shift, func) +#define IP0SR1(shift, func) IPnSR(0, 1, shift, func) +#define IP1SR1(shift, func) IPnSR(1, 1, shift, func) +#define IP2SR1(shift, func) IPnSR(2, 1, shift, func) +#define IP3SR1(shift, func) IPnSR(3, 1, shift, func) +#define IP0SR2(shift, func) IPnSR(0, 2, shift, func) +#define IP1SR2(shift, func) IPnSR(1, 2, shift, func) +#define IP2SR2(shift, func) IPnSR(2, 2, shift, func) +#define IP3SR2(shift, func) IPnSR(3, 2, shift, func) +#define IP0SR3(shift, func) IPnSR(0, 3, shift, func) +#define IP1SR3(shift, func) IPnSR(1, 3, shift, func) +#define IP2SR3(shift, func) IPnSR(2, 3, shift, func) +#define IP3SR3(shift, func) IPnSR(3, 3, shift, func) +#define IP0SR4(shift, func) IPnSR(0, 4, shift, func) +#define IP1SR4(shift, func) IPnSR(1, 4, shift, func) +#define IP2SR4(shift, func) IPnSR(2, 4, shift, func) +#define IP3SR4(shift, func) IPnSR(3, 4, shift, func) +#define IP0SR5(shift, func) IPnSR(0, 5, shift, func) +#define IP1SR5(shift, func) IPnSR(1, 5, shift, func) +#define IP2SR5(shift, func) IPnSR(2, 5, shift, func) +#define IP3SR5(shift, func) IPnSR(3, 5, shift, func) +#define IP0SR6(shift, func) IPnSR(0, 6, shift, func) +#define IP1SR6(shift, func) IPnSR(1, 6, shift, func) +#define IP2SR6(shift, func) IPnSR(2, 6, shift, func) +#define IP3SR6(shift, func) IPnSR(3, 6, shift, func) +#define IP0SR7(shift, func) IPnSR(0, 7, shift, func) +#define IP1SR7(shift, func) IPnSR(1, 7, shift, func) +#define IP2SR7(shift, func) IPnSR(2, 7, shift, func) +#define IP3SR7(shift, func) IPnSR(3, 7, shift, func) + +#define PIN_VOLTAGE_NONE 0 +#define PIN_VOLTAGE_1P8V 1 +#define PIN_VOLTAGE_3P3V 2 + #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_RENESAS_PINCTRL_RCAR_COMMON_H_ */ diff --git a/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h index 4249fd24a3a..c7870a21082 100644 --- a/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/rpi-pico-rp2040-pinctrl.h @@ -219,4 +219,11 @@ #define PIO1_P28 RP2040_PINMUX(28, RP2_PINCTRL_GPIO_FUNC_PIO1) #define PIO1_P29 RP2040_PINMUX(29, RP2_PINCTRL_GPIO_FUNC_PIO1) +#define GPIN0_P20 RP2040_PINMUX(20, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPIN1_P22 RP2040_PINMUX(22, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT0_P21 RP2040_PINMUX(21, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT1_P23 RP2040_PINMUX(23, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT2_P24 RP2040_PINMUX(24, RP2_PINCTRL_GPIO_FUNC_GPCK) +#define GPOUT3_P25 RP2040_PINMUX(25, RP2_PINCTRL_GPIO_FUNC_GPCK) + #endif /* __RP2040_PINCTRL_H__ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2de12.h b/include/zephyr/dt-bindings/sensor/lis2de12.h new file mode 100644 index 00000000000..afc1b8ee931 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2de12.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ + +/* Accel range */ +#define LIS2DE12_DT_FS_2G 0 +#define LIS2DE12_DT_FS_4G 1 +#define LIS2DE12_DT_FS_8G 2 +#define LIS2DE12_DT_FS_16G 3 + +/* Accel rates */ +#define LIS2DE12_DT_ODR_OFF 0x00 /* Power-Down */ +#define LIS2DE12_DT_ODR_AT_1Hz 0x01 /* 1Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_10Hz 0x02 /* 10Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_25Hz 0x03 /* 25Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_50Hz 0x04 /* 50Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_100Hz 0x05 /* 100Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_200Hz 0x06 /* 200Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_400Hz 0x07 /* 400Hz (normal) */ +#define LIS2DE12_DT_ODR_AT_1kHz620 0x08 /* 1KHz620 (normal) */ +#define LIS2DE12_DT_ODR_AT_5kHz376 0x09 /* 5KHz376 (normal) */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DE12_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lis2du12.h b/include/zephyr/dt-bindings/sensor/lis2du12.h new file mode 100644 index 00000000000..99e4c520e3f --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lis2du12.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ + +/* Accel range */ +#define LIS2DU12_DT_FS_2G 0 +#define LIS2DU12_DT_FS_4G 1 +#define LIS2DU12_DT_FS_8G 2 +#define LIS2DU12_DT_FS_16G 3 + +/* Accel rates */ +#define LIS2DU12_DT_ODR_OFF 0x00 /* Power-Down */ +#define LIS2DU12_DT_ODR_AT_1Hz6_ULP 0x01 /* 1Hz6 (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_3Hz_ULP 0x02 /* 3Hz (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_6Hz_ULP 0x03 /* 6Hz (ultra low power) */ +#define LIS2DU12_DT_ODR_AT_6Hz 0x04 /* 6Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_12Hz 0x05 /* 12Hz5 (normal) */ +#define LIS2DU12_DT_ODR_AT_25Hz 0x06 /* 25Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_50Hz 0x07 /* 50Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_100Hz 0x08 /* 100Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_200Hz 0x09 /* 200Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_400Hz 0x0a /* 400Hz (normal) */ +#define LIS2DU12_DT_ODR_AT_800Hz 0x0b /* 800Hz (normal) */ +#define LIS2DU12_DT_ODR_TRIG_PIN 0x0e /* Single-shot high latency by INT2 */ +#define LIS2DU12_DT_ODR_TRIG_SW 0x0f /* Single-shot high latency by IF */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LIS2DU12_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lps22df.h b/include/zephyr/dt-bindings/sensor/lps22df.h deleted file mode 100644 index 95668ae6390..00000000000 --- a/include/zephyr/dt-bindings/sensor/lps22df.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 STMicroelectronics - * - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ -#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ - -/* Data rate */ -#define LPS22DF_DT_ODR_POWER_DOWN 0 -#define LPS22DF_DT_ODR_1HZ 1 -#define LPS22DF_DT_ODR_4HZ 2 -#define LPS22DF_DT_ODR_10HZ 3 -#define LPS22DF_DT_ODR_25HZ 4 -#define LPS22DF_DT_ODR_50HZ 5 -#define LPS22DF_DT_ODR_75HZ 6 -#define LPS22DF_DT_ODR_100HZ 7 -#define LPS22DF_DT_ODR_200HZ 8 - -/* Low Pass filter */ -#define LPS22DF_DT_LP_FILTER_OFF 0 -#define LPS22DF_DT_LP_FILTER_ODR_4 1 -#define LPS22DF_DT_LP_FILTER_ODR_9 3 - -/* Average (number of samples) filter */ -#define LPS22DF_DT_AVG_4_SAMPLES 0 -#define LPS22DF_DT_AVG_8_SAMPLES 1 -#define LPS22DF_DT_AVG_16_SAMPLES 2 -#define LPS22DF_DT_AVG_32_SAMPLES 3 -#define LPS22DF_DT_AVG_64_SAMPLES 4 -#define LPS22DF_DT_AVG_128_SAMPLES 5 -#define LPS22DF_DT_AVG_256_SAMPLES 6 -#define LPS22DF_DT_AVG_512_SAMPLES 7 - -#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/lps2xdf.h b/include/zephyr/dt-bindings/sensor/lps2xdf.h new file mode 100644 index 00000000000..bcbb831bae5 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/lps2xdf.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * Copyright (c) 2023 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS2xDF_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS2xDF_H_ + +/* Data rate */ +#define LPS2xDF_DT_ODR_POWER_DOWN 0 +#define LPS2xDF_DT_ODR_1HZ 1 +#define LPS2xDF_DT_ODR_4HZ 2 +#define LPS2xDF_DT_ODR_10HZ 3 +#define LPS2xDF_DT_ODR_25HZ 4 +#define LPS2xDF_DT_ODR_50HZ 5 +#define LPS2xDF_DT_ODR_75HZ 6 +#define LPS2xDF_DT_ODR_100HZ 7 +#define LPS2xDF_DT_ODR_200HZ 8 + +/* Low Pass filter */ +#define LPS2xDF_DT_LP_FILTER_OFF 0 +#define LPS2xDF_DT_LP_FILTER_ODR_4 1 +#define LPS2xDF_DT_LP_FILTER_ODR_9 3 + +/* Average (number of samples) filter */ +#define LPS2xDF_DT_AVG_4_SAMPLES 0 +#define LPS2xDF_DT_AVG_8_SAMPLES 1 +#define LPS2xDF_DT_AVG_16_SAMPLES 2 +#define LPS2xDF_DT_AVG_32_SAMPLES 3 +#define LPS2xDF_DT_AVG_64_SAMPLES 4 +#define LPS2xDF_DT_AVG_128_SAMPLES 5 +#define LPS2xDF_DT_AVG_256_SAMPLES 6 +#define LPS2xDF_DT_AVG_512_SAMPLES 7 + +/* Full Scale Pressure Mode */ +#define LPS28DFW_DT_FS_MODE_1_1260 0 +#define LPS28DFW_DT_FS_MODE_2_4060 1 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_ST_LPS22DF_H_ */ diff --git a/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h b/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h new file mode 100644 index 00000000000..c7df471d929 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/qdec_nxp_s32.h @@ -0,0 +1,107 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Logic Trigger Numbers. See Trgmux_Ip_Init_PBcfg.h */ +#define TRGMUX_LOGIC_GROUP_0_TRIGGER_0 (0) /* Logic Trigger 0 */ +#define TRGMUX_LOGIC_GROUP_0_TRIGGER_1 (1) /* Logic Trigger 1 */ +#define TRGMUX_LOGIC_GROUP_1_TRIGGER_0 (2) /* Logic Trigger 2 */ +#define TRGMUX_LOGIC_GROUP_1_TRIGGER_1 (3) /* Logic Trigger 3 */ + +/*----------------------------------------------- + * TRGMUX HARDWARE TRIGGER INPUT + * See Trgmux_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define TRGMUX_IP_INPUT_SIUL2_IN0 (60) +#define TRGMUX_IP_INPUT_SIUL2_IN1 (61) +#define TRGMUX_IP_INPUT_SIUL2_IN2 (62) +#define TRGMUX_IP_INPUT_SIUL2_IN3 (63) +#define TRGMUX_IP_INPUT_SIUL2_IN4 (64) +#define TRGMUX_IP_INPUT_SIUL2_IN5 (65) +#define TRGMUX_IP_INPUT_SIUL2_IN6 (66) +#define TRGMUX_IP_INPUT_SIUL2_IN7 (67) +#define TRGMUX_IP_INPUT_SIUL2_IN8 (68) +#define TRGMUX_IP_INPUT_SIUL2_IN9 (69) +#define TRGMUX_IP_INPUT_SIUL2_IN10 (70) +#define TRGMUX_IP_INPUT_SIUL2_IN11 (71) +#define TRGMUX_IP_INPUT_SIUL2_IN12 (72) +#define TRGMUX_IP_INPUT_SIUL2_IN13 (73) +#define TRGMUX_IP_INPUT_SIUL2_IN14 (74) +#define TRGMUX_IP_INPUT_SIUL2_IN15 (75) + +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I0 (105) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I1 (106) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I2 (107) +#define TRGMUX_IP_INPUT_LCU1_LC0_OUT_I3 (108) + +/*----------------------------------------------- + * TRGMUX HARDWARE TRIGGER OUTPUT + * See Trgmux_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I0 (144) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I1 (145) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I2 (146) +#define TRGMUX_IP_OUTPUT_LCU1_0_INP_I3 (147) + +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH1 (32) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH2 (33) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH3 (34) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH1_4_IPP_IND_CH4 (35) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH5 (36) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH6 (37) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH7 (38) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH5_9_IPP_IND_CH9 (39) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH10 (40) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH11 (41) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH12 (42) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH10_13_IPP_IND_CH13 (43) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH14_15_IPP_IND_CH14 (44) +#define TRGMUX_IP_OUTPUT_EMIOS0_CH14_15_IPP_IND_CH15 (45) + +/*----------------------------------------------- + * LCU SOURCE MUX SELECT + * See Lcu_Ip_Cfg_Defines.h + *----------------------------------------------- + */ +#define LCU_IP_MUX_SEL_LOGIC_0 (0) +#define LCU_IP_MUX_SEL_LU_IN_0 (1) +#define LCU_IP_MUX_SEL_LU_IN_1 (2) +#define LCU_IP_MUX_SEL_LU_IN_2 (3) +#define LCU_IP_MUX_SEL_LU_IN_3 (4) +#define LCU_IP_MUX_SEL_LU_IN_4 (5) +#define LCU_IP_MUX_SEL_LU_IN_5 (6) +#define LCU_IP_MUX_SEL_LU_IN_6 (7) +#define LCU_IP_MUX_SEL_LU_IN_7 (8) +#define LCU_IP_MUX_SEL_LU_IN_8 (9) +#define LCU_IP_MUX_SEL_LU_IN_9 (10) +#define LCU_IP_MUX_SEL_LU_IN_10 (11) +#define LCU_IP_MUX_SEL_LU_IN_11 (12) +#define LCU_IP_MUX_SEL_LU_OUT_0 (13) +#define LCU_IP_MUX_SEL_LU_OUT_1 (14) +#define LCU_IP_MUX_SEL_LU_OUT_2 (15) +#define LCU_IP_MUX_SEL_LU_OUT_3 (16) +#define LCU_IP_MUX_SEL_LU_OUT_4 (17) +#define LCU_IP_MUX_SEL_LU_OUT_5 (18) +#define LCU_IP_MUX_SEL_LU_OUT_6 (19) +#define LCU_IP_MUX_SEL_LU_OUT_7 (20) +#define LCU_IP_MUX_SEL_LU_OUT_8 (21) +#define LCU_IP_MUX_SEL_LU_OUT_9 (22) +#define LCU_IP_MUX_SEL_LU_OUT_10 (23) +#define LCU_IP_MUX_SEL_LU_OUT_11 (24) + +#define LCU_IP_IN_0 (0) +#define LCU_IP_IN_1 (1) +#define LCU_IP_IN_2 (2) +#define LCU_IP_IN_3 (3) +#define LCU_IP_IN_4 (4) +#define LCU_IP_IN_5 (5) +#define LCU_IP_IN_6 (6) +#define LCU_IP_IN_7 (7) +#define LCU_IP_IN_8 (8) +#define LCU_IP_IN_9 (9) +#define LCU_IP_IN_10 (10) +#define LCU_IP_IN_11 (11) diff --git a/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h b/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h new file mode 100644 index 00000000000..e25db0a1431 --- /dev/null +++ b/include/zephyr/dt-bindings/usb-c/nxp_nx20p3483.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Values used to define the sink overvoltage and source overcurrent protections thresholds. + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ + +/** Voltage limit of 6.0V */ +#define NX20P3483_U_THRESHOLD_6_0 0 +/** Voltage limit of 6.8V */ +#define NX20P3483_U_THRESHOLD_6_8 1 /* <-- default */ +/** Voltage limit of 10.0V */ +#define NX20P3483_U_THRESHOLD_10_0 2 +/** Voltage limit of 11.5V */ +#define NX20P3483_U_THRESHOLD_11_5 3 +/** Voltage limit of 14.0V */ +#define NX20P3483_U_THRESHOLD_14_0 4 +/** Voltage limit of 17.0V */ +#define NX20P3483_U_THRESHOLD_17_0 5 +/** Voltage limit of 23.0V */ +#define NX20P3483_U_THRESHOLD_23_0 6 + +/** Current limit of 400mA */ +#define NX20P3483_I_THRESHOLD_0_400 0 +/** Current limit of 600mA */ +#define NX20P3483_I_THRESHOLD_0_600 1 +/** Current limit of 800mA */ +#define NX20P3483_I_THRESHOLD_0_800 2 +/** Current limit of 1000mA */ +#define NX20P3483_I_THRESHOLD_1_000 3 +/** Current limit of 1200mA */ +#define NX20P3483_I_THRESHOLD_1_200 4 +/** Current limit of 1400mA */ +#define NX20P3483_I_THRESHOLD_1_400 5 +/** Current limit of 1600mA */ +#define NX20P3483_I_THRESHOLD_1_600 6 /* <-- default */ +/** Current limit of 1800mA */ +#define NX20P3483_I_THRESHOLD_1_800 7 +/** Current limit of 2000mA */ +#define NX20P3483_I_THRESHOLD_2_000 8 +/** Current limit of 2200mA */ +#define NX20P3483_I_THRESHOLD_2_200 9 +/** Current limit of 2400mA */ +#define NX20P3483_I_THRESHOLD_2_400 10 +/** Current limit of 2600mA */ +#define NX20P3483_I_THRESHOLD_2_600 11 +/** Current limit of 2800mA */ +#define NX20P3483_I_THRESHOLD_2_800 12 +/** Current limit of 3000mA */ +#define NX20P3483_I_THRESHOLD_3_000 13 +/** Current limit of 3200mA */ +#define NX20P3483_I_THRESHOLD_3_200 14 +/** Current limit of 3400mA */ +#define NX20P3483_I_THRESHOLD_3_400 15 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_USBC_NXP_NX20P3483_H_ */ diff --git a/include/zephyr/dt-bindings/usb/audio.h b/include/zephyr/dt-bindings/usb/audio.h new file mode 100644 index 00000000000..4bc8c591457 --- /dev/null +++ b/include/zephyr/dt-bindings/usb/audio.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H +#define ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H + +/* USB Device Class Definition for Audio Devices Release 2.0 May 31, 2006 + * A.7 Audio Function Category Codes + */ +#define AUDIO_FUNCTION_SUBCLASS_UNDEFINED 0x00 +#define AUDIO_FUNCTION_DESKTOP_SPEAKER 0x01 +#define AUDIO_FUNCTION_HOME_THEATER 0x02 +#define AUDIO_FUNCTION_MICROPHONE 0x03 +#define AUDIO_FUNCTION_HEADSET 0x04 +#define AUDIO_FUNCTION_TELEPHONE 0x05 +#define AUDIO_FUNCTION_CONVERTER 0x06 +#define AUDIO_FUNCTION_VOICE_SOUND_RECORDER 0x07 +#define AUDIO_FUNCTION_IO_BOX 0x08 +#define AUDIO_FUNCTION_MUSICAL_INSTRUMENT 0x09 +#define AUDIO_FUNCTION_PRO_AUDIO 0x0A +#define AUDIO_FUNCTION_AUDIO_VIDEO 0x0B +#define AUDIO_FUNCTION_CONTROL_PANEL 0x0C +#define AUDIO_FUNCTION_OTHER 0xFF + + +/* USB Device Class Definition for Terminal Types + * Both "Universal Serial Bus Device Class Definition for Terminal Types" + * Release 2.0 May 31, 2006 and Release 3.0 September 22, 2016 contain exactly + * the same terminal types and values. + */ + +/* 2.1 USB Terminal Types */ +#define USB_TERMINAL_UNDEFINED 0x0100 +#define USB_TERMINAL_STREAMING 0x0101 +#define USB_TERMINAL_VENDOR_SPECIFIC 0x01FF + +/* 2.2 Input Terminal Types */ +#define INPUT_TERMINAL_UNDEFINED 0x0200 +#define INPUT_TERMINAL_MICROPHONE 0x0201 +#define INPUT_TERMINAL_DESKTOP_MICROPHONE 0x0202 +#define INPUT_TERMINAL_PERSONAL_MICROPHONE 0x0203 +#define INPUT_TERMINAL_OMNI_DIRECTIONAL_MICROPHONE 0x0204 +#define INPUT_TERMINAL_MICROPHONE_ARRAY 0x0205 +#define INPUT_TERMINAL_PROCESSING_MICROPHONE_ARRAY 0x0206 + +/* 2.3 Output Terminal Types */ +#define OUTPUT_TERMINAL_UNDEFINED 0x0300 +#define OUTPUT_TERMINAL_SPEAKER 0x0301 +#define OUTPUT_TERMINAL_HEADPHONES 0x0302 +#define OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO 0x0303 +#define OUTPUT_TERMINAL_DESKTOP_SPEAKER 0x0304 +#define OUTPUT_TERMINAL_ROOM_SPEAKER 0x0305 +#define OUTPUT_TERMINAL_COMMUNICATION_SPEAKER 0x0306 +#define OUTPUT_TERMINAL_LOW_FREQUENCY_EFFECTS_SPEAKER 0x0307 + +/* 2.4 Bi-directional Terminal Types */ +#define BIDIRECTIONAL_TERMINAL_UNDEFINED 0x0400 +#define BIDIRECTIONAL_TERMINAL_HANDSET 0x0401 +#define BIDIRECTIONAL_TERMINAL_HEADSET 0x0402 +#define BIDIRECTIONAL_TERMINAL_SPEAKERPHONE_NO_ECHO_REDUCTION 0x0403 +#define BIDIRECTIONAL_TERMINAL_ECHO_SUPPRESSING_SPEAKERPHONE 0x0404 +#define BIDIRECTIONAL_TERMINAL_ECHO_CANCELLING_SPEAKERPHONE 0x0405 + +/* 2.5 Telephony Terminal Types */ +#define TELEPHONY_TERMINAL_UNDEFINED 0x0500 +#define TELEPHONY_TERMINAL_PHONE_LINE 0x0501 +#define TELEPHONY_TERMINAL_TELEPHONE 0x0502 +#define TELEPHONY_TERMINAL_DOWN_LINE_PHONE 0x0503 + +/* 2.6 External Terminal Types */ +#define EXTERNAL_TERMINAL_UNDEFINED 0x0600 +#define EXTERNAL_TERMINAL_ANALOG_CONNECTOR 0x0601 +#define EXTERNAL_TERMINAL_DIGITAL_AUDIO_INTERFACE 0x0602 +#define EXTERNAL_TERMINAL_LINE_CONNECTOR 0x0603 +#define EXTERNAL_TERMINAL_LEGACY_AUDIO_CONNECTOR 0x0604 +#define EXTERNAL_TERMINAL_SPDIF_INTERFACE 0x0605 +#define EXTERNAL_TERMINAL_1394_DA_STREAM 0x0606 +#define EXTERNAL_TERMINAL_1394_DV_STREAM_SOUNDTRACK 0x0607 +#define EXTERNAL_TERMINAL_ADAT_LIGHTPIPE 0x0608 +#define EXTERNAL_TERMINAL_TDIF 0x0609 +#define EXTERNAL_TERMINAL_MADI 0x060A + +/* 2.7 Embedded Function Terminal Types */ +#define EMBEDDED_TERMINAL_UNDEFINED 0x0700 +#define EMBEDDED_TERMINAL_LEVEL_CALIBRATION_NOISE_SOURCE 0x0701 +#define EMBEDDED_TERMINAL_EQUALIZATION_NOISE 0x0702 +#define EMBEDDED_TERMINAL_CD_PLAYER 0x0703 +#define EMBEDDED_TERMINAL_DAT 0x0704 +#define EMBEDDED_TERMINAL_DCC 0x0705 +#define EMBEDDED_TERMINAL_COMPRESSED_AUDIO_PLAYER 0x0706 +#define EMBEDDED_TERMINAL_ANALOG_TAPE 0x0707 +#define EMBEDDED_TERMINAL_PHONOGRAPH 0x0708 +#define EMBEDDED_TERMINAL_VCR_AUDIO 0x0709 +#define EMBEDDED_TERMINAL_VIDEO_DISC_AUDIO 0x070A +#define EMBEDDED_TERMINAL_DVD_AUDIO 0x070B +#define EMBEDDED_TERMINAL_TV_TUNER_AUDIO 0x070C +#define EMBEDDED_TERMINAL_SATELLITE_RECEIVER_AUDIO 0x070D +#define EMBEDDED_TERMINAL_CABLE_TUNER_AUDIO 0x070E +#define EMBEDDED_TERMINAL_DSS_AUDIO 0x070F +#define EMBEDDED_TERMINAL_RADIO_RECEIVER 0x0710 +#define EMBEDDED_TERMINAL_RADIO_TRANSMITTER 0x0711 +#define EMBEDDED_TERMINAL_MULTI_TRACK_RECORDER 0x0712 +#define EMBEDDED_TERMINAL_SYNTHESIZER 0x0713 +#define EMBEDDED_TERMINAL_PIANO 0x0714 +#define EMBEDDED_TERMINAL_GUITAR 0x0715 +#define EMBEDDED_TERMINAL_DRUMS_RHYTHM 0x0716 +#define EMBEDDED_TERMINAL_OTHER_MUSICAL_INSTRUMENT 0x0717 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_USB_AUDIO_H */ diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 9b0d2993d62..2788dc01afd 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -73,6 +73,17 @@ union init_function { * @retval -errno If device initialization fails. */ int (*dev)(const struct device *dev); +#ifdef CONFIG_DEVICE_MUTABLE + /** + * Device initialization function (rw). + * + * @param dev Device instance. + * + * @retval 0 On success + * @retval -errno If device initialization fails. + */ + int (*dev_rw)(struct device *dev); +#endif }; /** @@ -96,7 +107,12 @@ struct init_entry { * If the init entry belongs to a device, this fields stores a * reference to it, otherwise it is set to NULL. */ - const struct device *dev; + union { + const struct device *dev; +#ifdef CONFIG_DEVICE_MUTABLE + struct device *dev_rw; +#endif + }; }; /** @cond INTERNAL_HIDDEN */ @@ -186,13 +202,10 @@ struct init_entry { * * @see SYS_INIT() */ -#define SYS_INIT_NAMED(name, init_fn_, level, prio) \ - static const Z_DECL_ALIGN(struct init_entry) \ - Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = { \ - .init_fn = {.sys = (init_fn_)}, \ - .dev = NULL, \ - } +#define SYS_INIT_NAMED(name, init_fn_, level, prio) \ + static const Z_DECL_ALIGN(struct init_entry) \ + Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ + Z_INIT_ENTRY_NAME(name) = {{ (init_fn_) }, { NULL } } /** @} */ diff --git a/include/zephyr/input/input_analog_axis.h b/include/zephyr/input/input_analog_axis.h new file mode 100644 index 00000000000..14492156d9c --- /dev/null +++ b/include/zephyr/input/input_analog_axis.h @@ -0,0 +1,97 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ +#define ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ + +#include +#include + +/** + * @brief Analog axis API + * @defgroup input_analog_axis Analog axis API + * @ingroup io_interfaces + * @{ + */ + +/** + * @brief Analog axis calibration data structure. + * + * Holds the calibration data for a single analog axis. Initial values are set + * from the devicetree and can be changed by the applicatoin in runtime using + * @ref analog_axis_calibration_set and @ref analog_axis_calibration_get. + */ +struct analog_axis_calibration { + /** Input value that corresponds to the minimum output value. */ + int16_t in_min; + /** Input value that corresponds to the maximum output value. */ + int16_t in_max; + /** Output value deadzone relative to the output range. */ + uint16_t out_deadzone; +}; + +/** + * @brief Analog axis raw data callback. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param raw_val Raw value for the channel. + */ +typedef void (*analog_axis_raw_data_t)(const struct device *dev, + int channel, int16_t raw_val); + +/** + * @brief Set a raw data callback. + * + * Set a callback to receive raw data for the specified analog axis device. + * This is meant to be use in the application to acquire the data to use for + * calibration. Set cb to NULL to disable the callback. + * + * @param dev Analog axis device. + * @param cb An analog_axis_raw_data_t callback to use, NULL disable. + */ +void analog_axis_set_raw_data_cb(const struct device *dev, analog_axis_raw_data_t cb); + +/** + * @brief Get the number of defined axes. + * + * @retval n The number of defined axes for dev. + */ +int analog_axis_num_axes(const struct device *dev); + +/** + * @brief Get the axis calibration data. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param cal Pointer to an analog_axis_calibration structure that is going to + * get set with the current calibration data. + * + * @retval 0 If successful. + * @retval -EINVAL If the specified channel is not valid. + */ +int analog_axis_calibration_get(const struct device *dev, + int channel, + struct analog_axis_calibration *cal); + +/** + * @brief Set the axis calibration data. + * + * @param dev Analog axis device. + * @param channel Channel number. + * @param cal Pointer to an analog_axis_calibration structure with the new + * calibration data + * + * @retval 0 If successful. + * @retval -EINVAL If the specified channel is not valid. + */ +int analog_axis_calibration_set(const struct device *dev, + int channel, + struct analog_axis_calibration *cal); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_H_ */ diff --git a/include/zephyr/input/input_analog_axis_settings.h b/include/zephyr/input/input_analog_axis_settings.h new file mode 100644 index 00000000000..da8ad0ddfa3 --- /dev/null +++ b/include/zephyr/input/input_analog_axis_settings.h @@ -0,0 +1,33 @@ +/* + * Copyright 2023 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ +#define ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ + +#include +#include + +/** + * @addtogroup input_analog_axis + * @{ + */ + +/** + * @brief Save the calibration data. + * + * Save the calibration data permanently on the specifided device, requires the + * the @ref settings subsystem to be configured and initialized. + * + * @param dev Analog axis device. + * + * @retval 0 If successful. + * @retval -errno In case of any other error. + */ +int analog_axis_calibration_save(const struct device *dev); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_ANALOG_AXIS_SETTINGS_H_ */ diff --git a/include/zephyr/input/input_hid.h b/include/zephyr/input/input_hid.h new file mode 100644 index 00000000000..2a89dde0530 --- /dev/null +++ b/include/zephyr/input/input_hid.h @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_HID_H_ +#define ZEPHYR_INCLUDE_INPUT_HID_H_ + +/** + * @addtogroup input_interface + * @{ + */ + +/** + * @brief Convert an input code to HID code. + * + * Takes an input code as input and returns the corresponding HID code as + * output. The return value is -1 if the code is not found, if found it can + * safely be casted to a uint8_t type. + * + * @param input_code Event code (see @ref INPUT_KEY_CODES). + * @retval the HID code corresponding to the input code. + * @retval -1 if there's no HID code for the specified input code. + */ +int16_t input_to_hid_code(uint16_t input_code); + +/** + * @brief Convert an input code to HID modifier. + * + * Takes an input code as input and returns the corresponding HID modifier as + * output or 0. + * + * @param input_code Event code (see @ref INPUT_KEY_CODES). + * @retval the HID modifier corresponding to the input code. + * @retval 0 if there's no HID modifier for the specified input code. + */ +uint8_t input_to_hid_modifier(uint16_t input_code); + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_INPUT_HID_H_ */ diff --git a/include/zephyr/input/input_kbd_matrix.h b/include/zephyr/input/input_kbd_matrix.h index 0566f14d2cd..7d3f4f37c43 100644 --- a/include/zephyr/input/input_kbd_matrix.h +++ b/include/zephyr/input/input_kbd_matrix.h @@ -29,6 +29,44 @@ /** Number of tracked scan cycles */ #define INPUT_KBD_MATRIX_SCAN_OCURRENCES 30U +/** Row entry data type */ +#if CONFIG_INPUT_KBD_MATRIX_16_BIT_ROW +typedef uint16_t kbd_row_t; +#define PRIkbdrow "%04x" +#else +typedef uint8_t kbd_row_t; +#define PRIkbdrow "%02x" +#endif + +#if defined(CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC) || defined(__DOXYGEN__) +#define INPUT_KBD_ACTUAL_KEY_MASK_CONST +/** + * @brief Enables or disables a specific row, column combination in the actual + * key mask. + * + * This allows enabling or disabling spcific row, column combination in the + * actual key mask in runtime. It can be useful if some of the keys are not + * present in some configuration, and the specific configuration is determined + * in runtime. Requires @kconfig{CONFIG_INPUT_KBD_ACTUAL_KEY_MASK_DYNAMIC} to + * be enabled. + * + * @param dev Pointer to the keyboard matrix device. + * @param row The matrix row to enable or disable. + * @param col The matrix column to enable or disable. + * @param enabled Whether the specificied row, col has to be enabled or disabled. + * + * @retval 0 If the change is successful. + * @retval -errno Negative errno if row or col are out of range for the device. + */ +int input_kbd_matrix_actual_key_mask_set(const struct device *dev, + uint8_t row, uint8_t col, bool enabled); +#else +#define INPUT_KBD_ACTUAL_KEY_MASK_CONST const +#endif + +/** Maximum number of rows */ +#define INPUT_KBD_MATRIX_ROW_BITS NUM_BITS(kbd_row_t) + /** * @brief Keyboard matrix internal APIs. */ @@ -49,7 +87,7 @@ struct input_kbd_matrix_api { * * @param dev Pointer to the keyboard matrix device. */ - int (*read_row)(const struct device *dev); + kbd_row_t (*read_row)(const struct device *dev); /** * @brief Request to put the matrix in detection mode. * @@ -74,16 +112,17 @@ struct input_kbd_matrix_common_config { uint8_t col_size; uint32_t poll_period_us; uint32_t poll_timeout_ms; - uint32_t debounce_down_ms; - uint32_t debounce_up_ms; + uint32_t debounce_down_us; + uint32_t debounce_up_us; uint32_t settle_time_us; bool ghostkey_check; + INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t *actual_key_mask; /* extra data pointers */ - uint8_t *matrix_stable_state; - uint8_t *matrix_unstable_state; - uint8_t *matrix_previous_state; - uint8_t *matrix_new_state; + kbd_row_t *matrix_stable_state; + kbd_row_t *matrix_unstable_state; + kbd_row_t *matrix_previous_state; + kbd_row_t *matrix_new_state; uint8_t *scan_cycle_idx; }; @@ -96,12 +135,19 @@ struct input_kbd_matrix_common_config { * specify row and col count. */ #define INPUT_KBD_MATRIX_DT_DEFINE_ROW_COL(node_id, _row_size, _col_size) \ - BUILD_ASSERT(IN_RANGE(_row_size, 1, 8), "invalid row-size"); \ + BUILD_ASSERT(IN_RANGE(_row_size, 1, INPUT_KBD_MATRIX_ROW_BITS), "invalid row-size"); \ BUILD_ASSERT(IN_RANGE(_col_size, 1, UINT8_MAX), "invalid col-size"); \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ - static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \ + BUILD_ASSERT(DT_PROP_LEN(node_id, actual_key_mask) == _col_size, \ + "actual-key-mask size does not match the number of columns"); \ + static INPUT_KBD_ACTUAL_KEY_MASK_CONST kbd_row_t \ + INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask)[_col_size] = \ + DT_PROP(node_id, actual_key_mask); \ + )) \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, previous_state)[_col_size]; \ + static kbd_row_t INPUT_KBD_MATRIX_DATA_NAME(node_id, new_state)[_col_size]; \ static uint8_t INPUT_KBD_MATRIX_DATA_NAME(node_id, scan_cycle_idx)[_row_size * _col_size]; /** @@ -145,10 +191,13 @@ struct input_kbd_matrix_common_config { .col_size = _col_size, \ .poll_period_us = DT_PROP(node_id, poll_period_ms) * USEC_PER_MSEC, \ .poll_timeout_ms = DT_PROP(node_id, poll_timeout_ms), \ - .debounce_down_ms = DT_PROP(node_id, debounce_down_ms), \ - .debounce_up_ms = DT_PROP(node_id, debounce_up_ms), \ + .debounce_down_us = DT_PROP(node_id, debounce_down_ms) * USEC_PER_MSEC, \ + .debounce_up_us = DT_PROP(node_id, debounce_up_ms) * USEC_PER_MSEC, \ .settle_time_us = DT_PROP(node_id, settle_time_us), \ .ghostkey_check = !DT_PROP(node_id, no_ghostkey_check), \ + IF_ENABLED(DT_NODE_HAS_PROP(node_id, actual_key_mask), ( \ + .actual_key_mask = INPUT_KBD_MATRIX_DATA_NAME(node_id, actual_key_mask), \ + )) \ \ .matrix_stable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, stable_state), \ .matrix_unstable_state = INPUT_KBD_MATRIX_DATA_NAME(node_id, unstable_state), \ @@ -195,7 +244,7 @@ struct input_kbd_matrix_common_config { */ struct input_kbd_matrix_common_data { /* Track previous cycles, used for debouncing. */ - uint8_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; + uint32_t scan_clk_cycle[INPUT_KBD_MATRIX_SCAN_OCURRENCES]; uint8_t scan_cycles_idx; struct k_sem poll_lock; @@ -228,6 +277,22 @@ struct input_kbd_matrix_common_data { */ void input_kbd_matrix_poll_start(const struct device *dev); +#if defined(CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK) || defined(__DOXYGEN__) +/** + * @brief Drive column hook + * + * This can be implemented by the application to handle column selection + * quirks. Called after the driver specific drive_column function. Requires + * @kconfig{CONFIG_INPUT_KBD_DRIVE_COLUMN_HOOK} to be enabled. + * + * @param dev Keyboard matrix device instance. + * @param col The column to drive, or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE or + * @ref INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL. + */ +void input_kbd_matrix_drive_column_hook(const struct device *dev, int col); +#endif + /** * @brief Common function to initialize a keyboard matrix device at init time. * diff --git a/include/zephyr/input/input_keymap.h b/include/zephyr/input/input_keymap.h new file mode 100644 index 00000000000..a3d3534b2ba --- /dev/null +++ b/include/zephyr/input/input_keymap.h @@ -0,0 +1,13 @@ +/* + * Copyright 2024 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ +#define ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ + +#define MATRIX_ROW(keymap_entry) (((keymap_entry) >> 24) & 0xff) +#define MATRIX_COL(keymap_entry) (((keymap_entry) >> 16) & 0xff) + +#endif /* ZEPHYR_INCLUDE_INPUT_INPUT_KEYMAP_H_ */ diff --git a/include/zephyr/internal/syscall_handler.h b/include/zephyr/internal/syscall_handler.h index f692c17dc1f..a9b9a642c76 100644 --- a/include/zephyr/internal/syscall_handler.h +++ b/include/zephyr/internal/syscall_handler.h @@ -394,6 +394,22 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); */ #define K_SYSCALL_VERIFY(expr) K_SYSCALL_VERIFY_MSG(expr, #expr) +/** + * @brief Macro to check if size is negative + * + * K_SYSCALL_MEMORY can be called with signed/unsigned types + * and because of that if we check if size is greater or equal to + * zero, many static analyzers complain about no effect expression. + * + * @param ptr Memory area to examine + * @param size Size of the memory area + * @return true if size is valid, false otherwise + * @note This is an internal API. Do not use unless you are extending + * functionality in the Zephyr tree. + */ +#define K_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \ + (((uintptr_t)(ptr) + (size)) >= (uintptr_t)(ptr)) + /** * @brief Runtime check that a user thread has read and/or write permission to * a memory area @@ -413,8 +429,10 @@ int k_usermode_string_copy(char *dst, const char *src, size_t maxlen); * functionality in the Zephyr tree. */ #define K_SYSCALL_MEMORY(ptr, size, write) \ - K_SYSCALL_VERIFY_MSG(arch_buffer_validate((void *)ptr, size, write) \ - == 0, \ + K_SYSCALL_VERIFY_MSG(K_SYSCALL_MEMORY_SIZE_CHECK(ptr, size) \ + && !Z_DETECT_POINTER_OVERFLOW(ptr, size) \ + && (arch_buffer_validate((void *)ptr, size, write) \ + == 0), \ "Memory region %p (size %zu) %s access denied", \ (void *)(ptr), (size_t)(size), \ write ? "write" : "read") diff --git a/include/zephyr/irq_multilevel.h b/include/zephyr/irq_multilevel.h index 3a2b5116602..25daa030249 100644 --- a/include/zephyr/irq_multilevel.h +++ b/include/zephyr/irq_multilevel.h @@ -19,6 +19,7 @@ extern "C" { #endif +#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__) /** * @brief Return IRQ level * This routine returns the interrupt level number of the provided interrupt. @@ -165,6 +166,7 @@ static inline unsigned int irq_parent_level_3(unsigned int irq) BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); } +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ #ifdef __cplusplus } #endif diff --git a/include/zephyr/irq_nextlevel.h b/include/zephyr/irq_nextlevel.h index 20533cdf6e0..e5ab4ffdd8a 100644 --- a/include/zephyr/irq_nextlevel.h +++ b/include/zephyr/irq_nextlevel.h @@ -15,6 +15,7 @@ extern "C" { #endif +#if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__) /** * @cond INTERNAL_HIDDEN * @@ -134,6 +135,7 @@ static inline unsigned int irq_line_is_enabled_next_level(const struct device *d return api->intr_get_line_state(dev, irq); } +#endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ #ifdef __cplusplus } #endif diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h index fac7df01904..9f2b750d166 100644 --- a/include/zephyr/kernel.h +++ b/include/zephyr/kernel.h @@ -171,7 +171,6 @@ void k_thread_foreach_unlocked( * */ #define K_ESSENTIAL (BIT(0)) -#if defined(CONFIG_FPU_SHARING) /** * @brief FPU registers are managed by context switch * @@ -183,7 +182,6 @@ void k_thread_foreach_unlocked( */ #define K_FP_IDX 1 #define K_FP_REGS (BIT(K_FP_IDX)) -#endif /** * @brief user mode thread @@ -214,10 +212,6 @@ void k_thread_foreach_unlocked( */ #define K_CALLBACK_STATE (BIT(4)) -#ifdef CONFIG_ARC -/* ARC processor Bitmask definitions for threads user options */ - -#if defined(CONFIG_ARC_DSP_SHARING) /** * @brief DSP registers are managed by context switch * @@ -225,13 +219,11 @@ void k_thread_foreach_unlocked( * This option indicates that the thread uses the CPU's DSP registers. * This instructs the kernel to take additional steps to save and * restore the contents of these registers when scheduling the thread. - * No effect if @kconfig{CONFIG_ARC_DSP_SHARING} is not enabled. + * No effect if @kconfig{CONFIG_DSP_SHARING} is not enabled. */ #define K_DSP_IDX 6 -#define K_ARC_DSP_REGS (BIT(K_DSP_IDX)) -#endif +#define K_DSP_REGS (BIT(K_DSP_IDX)) -#if defined(CONFIG_ARC_AGU_SHARING) /** * @brief AGU registers are managed by context switch * @@ -241,14 +233,8 @@ void k_thread_foreach_unlocked( * No effect if @kconfig{CONFIG_ARC_AGU_SHARING} is not enabled. */ #define K_AGU_IDX 7 -#define K_ARC_AGU_REGS (BIT(K_AGU_IDX)) -#endif -#endif - -#ifdef CONFIG_X86 -/* x86 Bitmask definitions for threads user options */ +#define K_AGU_REGS (BIT(K_AGU_IDX)) -#if defined(CONFIG_FPU_SHARING) && defined(CONFIG_X86_SSE) /** * @brief FP and SSE registers are managed by context switch on x86 * @@ -259,8 +245,6 @@ void k_thread_foreach_unlocked( * the thread. No effect if @kconfig{CONFIG_X86_SSE} is not enabled. */ #define K_SSE_REGS (BIT(7)) -#endif -#endif /* end - thread options */ @@ -436,7 +420,7 @@ __syscall int k_thread_stack_space_get(const struct k_thread *thread, size_t *unused_ptr); #endif -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) /** * @brief Assign the system heap as a thread's resource pool * @@ -450,7 +434,7 @@ __syscall int k_thread_stack_space_get(const struct k_thread *thread, * */ void k_thread_system_pool_assign(struct k_thread *thread); -#endif /* (CONFIG_HEAP_MEM_POOL_SIZE > 0) */ +#endif /* (K_HEAP_MEM_POOL_SIZE > 0) */ /** * @brief Sleep until a thread exits @@ -483,8 +467,9 @@ __syscall int k_thread_join(struct k_thread *thread, k_timeout_t timeout); * * @param timeout Desired duration of sleep. * - * @return Zero if the requested time has elapsed or the number of milliseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * millisecond. */ __syscall int32_t k_sleep(k_timeout_t timeout); @@ -495,8 +480,9 @@ __syscall int32_t k_sleep(k_timeout_t timeout); * * @param ms Number of milliseconds to sleep. * - * @return Zero if the requested time has elapsed or the number of milliseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * millisecond. */ static inline int32_t k_msleep(int32_t ms) { @@ -515,8 +501,9 @@ static inline int32_t k_msleep(int32_t ms) * * @param us Number of microseconds to sleep. * - * @return Zero if the requested time has elapsed or the number of microseconds - * left to sleep, if thread was woken up by \ref k_wakeup call. + * @return Zero if the requested time has elapsed or if the thread was woken up + * by the \ref k_wakeup call, the time left to sleep rounded up to the nearest + * microsecond. */ __syscall int32_t k_usleep(int32_t us); @@ -596,7 +583,8 @@ __syscall k_tid_t k_sched_current_thread_query(void); __attribute_const__ static inline k_tid_t k_current_get(void) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS + /* Thread-local cache of current thread ID, set in z_thread_entry() */ extern __thread k_tid_t z_tls_current; @@ -3301,7 +3289,7 @@ void k_work_init(struct k_work *work, * @param work pointer to the work item. * * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, - * K_WORK_RUNNING, and K_WORK_CANCELING. + * K_WORK_RUNNING, K_WORK_CANCELING, and K_WORK_FLUSHING. */ int k_work_busy_get(const struct k_work *work); @@ -3557,9 +3545,9 @@ k_work_delayable_from_work(struct k_work *work); * * @param dwork pointer to the delayable work item. * - * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, K_WORK_RUNNING, and - * K_WORK_CANCELING. A zero return value indicates the work item appears to - * be idle. + * @return a mask of flags K_WORK_DELAYED, K_WORK_QUEUED, K_WORK_RUNNING, + * K_WORK_CANCELING, and K_WORK_FLUSHING. A zero return value indicates the + * work item appears to be idle. */ int k_work_delayable_busy_get(const struct k_work_delayable *dwork); @@ -3807,9 +3795,10 @@ enum { K_WORK_CANCELING_BIT = 1, K_WORK_QUEUED_BIT = 2, K_WORK_DELAYED_BIT = 3, + K_WORK_FLUSHING_BIT = 4, K_WORK_MASK = BIT(K_WORK_DELAYED_BIT) | BIT(K_WORK_QUEUED_BIT) - | BIT(K_WORK_RUNNING_BIT) | BIT(K_WORK_CANCELING_BIT), + | BIT(K_WORK_RUNNING_BIT) | BIT(K_WORK_CANCELING_BIT) | BIT(K_WORK_FLUSHING_BIT), /* Static work flags */ K_WORK_DELAYABLE_BIT = 8, @@ -3860,6 +3849,12 @@ enum { * Accessed via k_work_busy_get(). May co-occur with other flags. */ K_WORK_DELAYED = BIT(K_WORK_DELAYED_BIT), + + /** @brief Flag indicating a synced work item that is being flushed. + * + * Accessed via k_work_busy_get(). May co-occur with other flags. + */ + K_WORK_FLUSHING = BIT(K_WORK_FLUSHING_BIT), }; /** @brief A structure used to submit work. */ @@ -4697,8 +4692,6 @@ static inline uint32_t z_impl_k_msgq_num_used_get(struct k_msgq *msgq) * */ struct k_mbox_msg { - /** internal use only - needed for legacy API support */ - uint32_t _mailbox; /** size of message (in bytes) */ size_t size; /** application-defined information value */ @@ -4980,7 +4973,7 @@ __syscall int k_pipe_alloc_init(struct k_pipe *pipe, size_t size); * @retval -EAGAIN Waiting period timed out; between zero and @a min_xfer * minus one data bytes were written. */ -__syscall int k_pipe_put(struct k_pipe *pipe, void *data, +__syscall int k_pipe_put(struct k_pipe *pipe, const void *data, size_t bytes_to_write, size_t *bytes_written, size_t min_xfer, k_timeout_t timeout); @@ -5976,6 +5969,12 @@ void z_timer_expiration_handler(struct _timeout *t); __syscall void k_str_out(char *c, size_t n); #endif +/** + * @defgroup float_apis Floating Point APIs + * @ingroup kernel_apis + * @{ + */ + /** * @brief Disable preservation of floating point context information. * @@ -6038,6 +6037,10 @@ __syscall int k_float_disable(struct k_thread *thread); */ __syscall int k_float_enable(struct k_thread *thread, unsigned int options); +/** + * @} + */ + /** * @brief Get the runtime statistics of a thread * diff --git a/include/zephyr/kernel/internal/mm.h b/include/zephyr/kernel/internal/mm.h index c859e939234..b6bcd1aa3b1 100644 --- a/include/zephyr/kernel/internal/mm.h +++ b/include/zephyr/kernel/internal/mm.h @@ -56,6 +56,7 @@ #include #include #include +#include /* Just like Z_MEM_PHYS_ADDR() but with type safety and assertions */ static inline uintptr_t z_mem_phys_addr(void *virt) @@ -167,10 +168,10 @@ extern "C" { * This API is part of infrastructure still under development and may * change. * - * @param virt [out] Output virtual address storage location - * @param phys Physical address base of the memory region - * @param size Size of the memory region - * @param flags Caching mode and access flags, see K_MAP_* macros + * @param[out] virt Output virtual address storage location + * @param[in] phys Physical address base of the memory region + * @param[in] size Size of the memory region + * @param[in] flags Caching mode and access flags, see K_MAP_* macros */ void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, uint32_t flags); diff --git a/include/zephyr/kernel/internal/smp.h b/include/zephyr/kernel/internal/smp.h index d4f70d3c07b..e2b3ae15aec 100644 --- a/include/zephyr/kernel/internal/smp.h +++ b/include/zephyr/kernel/internal/smp.h @@ -6,18 +6,6 @@ #ifndef ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ #define ZEPHYR_INCLUDE_KERNEL_INTERNAL_SMP_H_ -struct k_thread; - -/** - * @internal - */ -#ifdef CONFIG_SOF -void z_smp_thread_init(void *arg, struct k_thread *thread); -void z_smp_thread_swap(void); -#endif - -void z_init_cpu(int id); void z_sched_ipi(void); -void z_smp_start_cpu(int id); #endif diff --git a/include/zephyr/kernel/mm.h b/include/zephyr/kernel/mm.h index 392dc4b7cde..715bc94021f 100644 --- a/include/zephyr/kernel/mm.h +++ b/include/zephyr/kernel/mm.h @@ -14,7 +14,6 @@ #endif #include -#include /** * @brief Kernel Memory Management @@ -192,11 +191,11 @@ void k_mem_unmap(void *addr, size_t size); * The returned region will have both its base address and size aligned * to the provided alignment value. * - * @param aligned_addr [out] Aligned address - * @param aligned_size [out] Aligned region size - * @param addr Region base address - * @param size Region size - * @param align What to align the address and size to + * @param[out] aligned_addr Aligned address + * @param[out] aligned_size Aligned region size + * @param[in] addr Region base address + * @param[in] size Region size + * @param[in] align What to align the address and size to * @retval offset between aligned_addr and addr */ size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, diff --git a/include/zephyr/kernel/smp.h b/include/zephyr/kernel/smp.h new file mode 100644 index 00000000000..883f4820a74 --- /dev/null +++ b/include/zephyr/kernel/smp.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_KERNEL_SMP_H_ +#define ZEPHYR_INCLUDE_KERNEL_SMP_H_ + +#include + +typedef void (*smp_init_fn)(void *arg); + +/** + * @brief Start a CPU. + * + * This routine is used to manually start the CPU specified + * by @a id. It may be called to restart a CPU that had been + * stopped or powered down, as well as some other scenario. + * After the CPU has finished initialization, the CPU will be + * ready to participate in thread scheduling and execution. + * + * @note This function must not be used on currently running + * CPU. The target CPU must be in off state, or in + * certain architectural state(s) where the CPU is + * permitted to go through the power up process. + * Detection of such state(s) must be provided by + * the platform layers. + * + * @note This initializes per-CPU kernel structs and also + * initializes timers needed for MP operations. + * Use @ref k_smp_cpu_resume if these are not + * desired. + * + * @param id ID of target CPU. + * @param fn Function to be called before letting scheduler + * run. + * @param arg Argument to @a fn. + */ +void k_smp_cpu_start(int id, smp_init_fn fn, void *arg); + +/** + * @brief Resume a previously suspended CPU. + * + * This function works like @ref k_smp_cpu_start, but does not + * re-initialize the kernel's internal tracking data for + * the target CPU. Therefore, @ref k_smp_cpu_start must have + * previously been called for the target CPU, and it must have + * verifiably reached an idle/off state (detection of which + * must be provided by the platform layers). It may be used + * in cases where platform layers require, for example, that + * data on the interrupt or idle stack be preserved. + * + * @note This function must not be used on currently running + * CPU. The target CPU must be in suspended state, or + * in certain architectural state(s) where the CPU is + * permitted to go through the resume process. + * Detection of such state(s) must be provided by + * the platform layers. + * + * @param id ID of target CPU. + * @param fn Function to be called before resuming context. + * @param arg Argument to @a fn. + * @param reinit_timer True if timer needs to be re-initialized. + * @param invoke_sched True if scheduler is invoked after the CPU + * has started. + */ +void k_smp_cpu_resume(int id, smp_init_fn fn, void *arg, + bool reinit_timer, bool invoke_sched); + +#endif /* ZEPHYR_INCLUDE_KERNEL_SMP_H_ */ diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index b152dfb909a..91cf710e870 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -8,7 +8,7 @@ #define ZEPHYR_INCLUDE_KERNEL_THREAD_H_ #ifdef CONFIG_DEMAND_PAGING_THREAD_STATS -#include +#include #endif #include diff --git a/include/zephyr/linker/common-ram.ld b/include/zephyr/linker/common-ram.ld index c03351abf98..df70b13ca73 100644 --- a/include/zephyr/linker/common-ram.ld +++ b/include/zephyr/linker/common-ram.ld @@ -133,10 +133,13 @@ #endif /* CONFIG_SENSING */ #if defined(CONFIG_ZBUS) - ITERABLE_SECTION_RAM(zbus_observer, 4) ITERABLE_SECTION_RAM(zbus_channel_observation_mask, 1) #endif /* CONFIG_ZBUS */ +#if defined(CONFIG_DEVICE_MUTABLE) + ITERABLE_SECTION_RAM(device_mutable, 4) +#endif + #ifdef CONFIG_USERSPACE _static_kernel_objects_end = .; #endif diff --git a/include/zephyr/linker/common-rom/common-rom-misc.ld b/include/zephyr/linker/common-rom/common-rom-misc.ld index 1fbf777ba55..189a9e31885 100644 --- a/include/zephyr/linker/common-rom/common-rom-misc.ld +++ b/include/zephyr/linker/common-rom/common-rom-misc.ld @@ -36,6 +36,7 @@ #if defined(CONFIG_ZBUS) ITERABLE_SECTION_ROM(zbus_channel, 4) + ITERABLE_SECTION_ROM(zbus_observer, 4) ITERABLE_SECTION_ROM(zbus_channel_observation, 4) #endif /* CONFIG_ZBUS */ diff --git a/include/zephyr/linker/common-rom/common-rom-net.ld b/include/zephyr/linker/common-rom/common-rom-net.ld index 2aa46dfecf5..e73addfd166 100644 --- a/include/zephyr/linker/common-rom/common-rom-net.ld +++ b/include/zephyr/linker/common-rom/common-rom-net.ld @@ -22,6 +22,10 @@ ITERABLE_SECTION_ROM(coap_service, 4) #endif +#if defined(CONFIG_NET_MGMT_EVENT) + ITERABLE_SECTION_ROM(net_mgmt_event_static_handler, 4) +#endif + #if defined(CONFIG_NET_SOCKETS_SERVICE) ITERABLE_SECTION_ROM(net_socket_service_desc, 4) #endif diff --git a/include/zephyr/linker/irq-vector-table-section.ld b/include/zephyr/linker/irq-vector-table-section.ld index 17c483db98f..141eee4d28d 100644 --- a/include/zephyr/linker/irq-vector-table-section.ld +++ b/include/zephyr/linker/irq-vector-table-section.ld @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: Apache-2.0 */ +#if !(LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION) . = ALIGN(CONFIG_ARCH_IRQ_VECTOR_TABLE_ALIGN); KEEP(*(_IRQ_VECTOR_TABLE_SECTION_SYMS)) +#endif /* * Some ARM platforms require this symbol to be placed after the IRQ vector diff --git a/include/zephyr/linker/isr-local-drop-unused.ld b/include/zephyr/linker/isr-local-drop-unused.ld new file mode 100644 index 00000000000..9b6e1272413 --- /dev/null +++ b/include/zephyr/linker/isr-local-drop-unused.ld @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#if LINKER_ZEPHYR_FINAL && CONFIG_ISR_TABLES_LOCAL_DECLARATION +/DISCARD/ : +{ + KEEP(*(.vectors)) + KEEP(*(_IRQ_VECTOR_TABLE_SECTION_SYMS)) +} +#endif diff --git a/include/zephyr/llext/elf.h b/include/zephyr/llext/elf.h index 6dc3cc4e5c8..a9fd8f86a94 100644 --- a/include/zephyr/llext/elf.h +++ b/include/zephyr/llext/elf.h @@ -231,16 +231,16 @@ struct elf32_sym { struct elf64_sym { /** Name of the symbol as an index into the symbol string table */ elf64_word st_name; - /** Value or location of the symbol */ - elf64_addr st_value; - /** Size of the symbol */ - elf64_xword st_size; /** Symbol binding and type information */ unsigned char st_info; /** Symbol visibility */ unsigned char st_other; /** Symbols related section given by section header index */ elf64_half st_shndx; + /** Value or location of the symbol */ + elf64_addr st_value; + /** Size of the symbol */ + elf64_xword st_size; }; #define SHN_UNDEF 0 diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index a4458a05468..0a006dc53b7 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -26,13 +26,14 @@ extern "C" { */ /** - * @brief Enum of memory regions for lookup tables + * @brief List of ELF regions that are stored or referenced in the llext */ enum llext_mem { LLEXT_MEM_TEXT, LLEXT_MEM_DATA, LLEXT_MEM_RODATA, LLEXT_MEM_BSS, + LLEXT_MEM_EXPORT, LLEXT_MEM_SYMTAB, LLEXT_MEM_STRTAB, LLEXT_MEM_SHSTRTAB, @@ -40,12 +41,22 @@ enum llext_mem { LLEXT_MEM_COUNT, }; +#define LLEXT_MEM_PARTITIONS (LLEXT_MEM_BSS+1) + +struct llext_loader; + /** * @brief Linkable loadable extension */ struct llext { /** @cond ignore */ sys_snode_t _llext_list; + +#ifdef CONFIG_USERSPACE + struct k_mem_partition mem_parts[LLEXT_MEM_PARTITIONS]; + struct k_mem_domain mem_domain; +#endif + /** @endcond */ /** Name of the llext */ @@ -54,20 +65,30 @@ struct llext { /** Lookup table of llext memory regions */ void *mem[LLEXT_MEM_COUNT]; - /** Memory allocated on heap */ + /** Is the memory for this section allocated on heap? */ bool mem_on_heap[LLEXT_MEM_COUNT]; - /** Total size of the llext memory usage */ - size_t mem_size; + /** Size of each stored section */ + size_t mem_size[LLEXT_MEM_COUNT]; - /** Exported symbols from the llext, may be linked against by other llext */ + /** Total llext allocation size */ + size_t alloc_size; + + /* + * These are all global symbols in the extension, all of them don't + * have to be exported to other extensions, but this table is needed for + * faster internal linking, e.g. if the extension is built out of + * several files, if any symbols are referenced between files, this + * table will be used to link them. + */ struct llext_symtable sym_tab; -}; -/** - * @brief List head of loaded extensions - */ -sys_slist_t *llext_list(void); + /** Exported symbols from the llext, may be linked against by other llext */ + struct llext_symtable exp_tab; + + /** Extension use counter, prevents unloading while in use */ + unsigned int use_count; +}; /** * @brief Find an llext by name @@ -78,6 +99,32 @@ sys_slist_t *llext_list(void); */ struct llext *llext_by_name(const char *name); +/** + * @brief Iterate overall registered llext instances + * + * Calls a provided callback function for each registered extension or until the + * callback function returns a non-0 value. + * + * @param[in] fn callback function + * @param[in] arg a private argument to be provided to the callback function + * @retval 0 if no extensions are registered + * @retval value returned by the most recent callback invocation + */ +int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg); + +/** + * @brief llext loader parameters + * + * These are parameters, not saved in the permanent llext context, needed only + * for the loader + */ +struct llext_load_param { + /** Should local relocation be performed */ + bool relocate_local; +}; + +#define LLEXT_LOAD_PARAM_DEFAULT {.relocate_local = true,} + /** * @brief Load and link an extension * @@ -87,20 +134,22 @@ struct llext *llext_by_name(const char *name); * * @param[in] loader An extension loader that provides input data and context * @param[in] name A string identifier for the extension - * @param[out] ext A pointer to a statically allocated llext struct + * @param[out] ext This will hold the pointer to the llext struct + * @param[in] ldr_parm Loader parameters * * @retval 0 Success * @retval -ENOMEM Not enough memory * @retval -EINVAL Invalid ELF stream */ -int llext_load(struct llext_loader *loader, const char *name, struct llext **ext); +int llext_load(struct llext_loader *loader, const char *name, struct llext **ext, + struct llext_load_param *ldr_parm); /** * @brief Unload an extension * * @param[in] ext Extension to unload */ -void llext_unload(struct llext *ext); +int llext_unload(struct llext **ext); /** * @brief Find the address for an arbitrary symbol name. @@ -127,6 +176,20 @@ const void * const llext_find_sym(const struct llext_symtable *sym_table, const */ int llext_call_fn(struct llext *ext, const char *sym_name); +/** + * @brief Add the known memory partitions of the extension to a memory domain + * + * Allows an extension to be executed in supervisor or user mode threads when + * memory protection hardware is enabled. + * + * @param[in] ext Extension to add to a domain + * @param[in] domain Memory domain to add partitions to + * + * @retval 0 success + * @retval -errno error + */ +int llext_add_domain(struct llext *ext, struct k_mem_domain *domain); + /** * @brief Architecture specific function for updating op codes given a relocation * @@ -142,6 +205,26 @@ int llext_call_fn(struct llext *ext, const char *sym_name); */ void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval); +/** + * @brief Find an ELF section + * + * @param loader Extension loader data and context + * @param search_name Section name to search for + * @retval Section offset or a negative error code + */ +ssize_t llext_find_section(struct llext_loader *loader, const char *search_name); + +/** + * @brief Architecture specific function for updating addresses via relocation table + * + * @param[in] loader Extension loader data and context + * @param[in] ext Extension to call function in + * @param[in] rel Relocation data provided by elf + * @param[in] got_offset Offset within a relocation table + */ +void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, + elf_rela_t *rel, size_t got_offset); + /** * @} */ diff --git a/include/zephyr/llext/loader.h b/include/zephyr/llext/loader.h index 3102f17cf1a..7eb49d611be 100644 --- a/include/zephyr/llext/loader.h +++ b/include/zephyr/llext/loader.h @@ -21,28 +21,7 @@ extern "C" { * @{ */ -/** - * @brief Enum of sections for lookup tables - */ -enum llext_section { - LLEXT_SECT_TEXT, - LLEXT_SECT_DATA, - LLEXT_SECT_RODATA, - LLEXT_SECT_BSS, - - LLEXT_SECT_REL_TEXT, - LLEXT_SECT_REL_DATA, - LLEXT_SECT_REL_RODATA, - LLEXT_SECT_REL_BSS, - - LLEXT_SECT_SYMTAB, - LLEXT_SECT_STRTAB, - LLEXT_SECT_SHSTRTAB, - - LLEXT_SECT_COUNT, -}; - -enum llext_mem; +#include /** * @brief Linkable loadable extension loader context @@ -91,7 +70,7 @@ struct llext_loader { /** @cond ignore */ elf_ehdr_t hdr; - elf_shdr_t sects[LLEXT_SECT_COUNT]; + elf_shdr_t sects[LLEXT_MEM_COUNT]; enum llext_mem *sect_map; uint32_t sect_cnt; /** @endcond */ diff --git a/include/zephyr/llext/symbol.h b/include/zephyr/llext/symbol.h index 84e43d22b5b..19f34649026 100644 --- a/include/zephyr/llext/symbol.h +++ b/include/zephyr/llext/symbol.h @@ -8,6 +8,7 @@ #define ZEPHYR_LLEXT_SYMBOL_H #include +#include #include #ifdef __cplusplus @@ -78,6 +79,10 @@ struct llext_symtable { .name = STRINGIFY(x), .addr = &x, \ } +#define LL_EXTENSION_SYMBOL(x) \ + struct llext_symbol Z_GENERIC_SECTION(".exported_sym") __used \ + symbol_##x = {STRINGIFY(x), &x} + /** * @brief Export a system call to a table of symbols * diff --git a/include/zephyr/logging/log_backend_net.h b/include/zephyr/logging/log_backend_net.h index 9141b481b8d..cde5ff3ea28 100644 --- a/include/zephyr/logging/log_backend_net.h +++ b/include/zephyr/logging/log_backend_net.h @@ -27,6 +27,25 @@ extern "C" { */ bool log_backend_net_set_addr(const char *addr); +/** + * @brief update the hostname + * + * @details This function allows to update the hostname displayed by the logging backend. It will be + * called by the network stack if the hostname is set with net_hostname_set(). + * + * @param hostname new hostname as char array. + * @param len Length of the hostname array. + */ +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +void log_backend_net_hostname_set(char *hostname, size_t len); +#else +static inline void log_backend_net_hostname_set(const char *hostname, size_t len) +{ + ARG_UNUSED(hostname); + ARG_UNUSED(len); +} +#endif + #ifdef __cplusplus } #endif diff --git a/include/zephyr/logging/log_core.h b/include/zephyr/logging/log_core.h index bc4cb2d8f36..7321b569f34 100644 --- a/include/zephyr/logging/log_core.h +++ b/include/zephyr/logging/log_core.h @@ -190,6 +190,30 @@ static inline char z_log_minimal_level_to_char(int level) #define Z_LOG_INST(_inst) COND_CODE_1(CONFIG_LOG, (_inst), NULL) +/* If strings are removed from the binary then there is a risk of creating invalid + * cbprintf package if %p is used with character pointer which is interpreted as + * string. A compile time check is performed (since format string is known at + * compile time) and check fails logging message is not created but error is + * emitted instead. String check may increase compilation time so it is not + * always performed (could significantly increase CI time). + */ +#if CONFIG_LOG_FMT_STRING_VALIDATE +#define LOG_STRING_WARNING(_mode, _src, ...) \ + Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ + Z_LOG_LOCAL_DOMAIN_ID, _src, LOG_LEVEL_ERR, NULL, 0, \ + "char pointer used for %%p, cast to void *:\"%s\"", \ + GET_ARG_N(1, __VA_ARGS__)) + +#define LOG_POINTERS_VALIDATE(string_ok, ...) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \ + string_ok = Z_CBPRINTF_POINTERS_VALIDATE(__VA_ARGS__); \ + _Pragma("GCC diagnostic pop") +#else +#define LOG_POINTERS_VALIDATE(string_ok, ...) string_ok = true +#define LOG_STRING_WARNING(_mode, _src, ...) +#endif + /*****************************************************************************/ /****************** Macros for standard logging ******************************/ /*****************************************************************************/ @@ -234,6 +258,12 @@ static inline char z_log_minimal_level_to_char(int level) int _mode; \ void *_src = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? \ (void *)_dsource : (void *)_source; \ + bool string_ok; \ + LOG_POINTERS_VALIDATE(string_ok, __VA_ARGS__); \ + if (!string_ok) { \ + LOG_STRING_WARNING(_mode, _src, __VA_ARGS__); \ + break; \ + } \ Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \ Z_LOG_LOCAL_DOMAIN_ID, _src, _level, NULL,\ 0, __VA_ARGS__); \ @@ -348,6 +378,13 @@ static inline char z_log_minimal_level_to_char(int level) /** @brief Number of slots in one word. */ #define LOG_FILTERS_NUM_OF_SLOTS (32 / LOG_FILTER_SLOT_SIZE) +/** @brief Maximum number of backends supported when runtime filtering is enabled. */ +#define LOG_FILTERS_MAX_BACKENDS \ + (LOG_FILTERS_NUM_OF_SLOTS - (1 + IS_ENABLED(CONFIG_LOG_FRONTEND))) + +/** @brief Slot reserved for the frontend. Last slot is used. */ +#define LOG_FRONTEND_SLOT_ID (LOG_FILTERS_NUM_OF_SLOTS - 1) + /** @brief Slot mask. */ #define LOG_FILTER_SLOT_MASK (BIT(LOG_FILTER_SLOT_SIZE) - 1U) diff --git a/include/zephyr/logging/log_ctrl.h b/include/zephyr/logging/log_ctrl.h index dc5f39a2e7d..9e5e3e3c077 100644 --- a/include/zephyr/logging/log_ctrl.h +++ b/include/zephyr/logging/log_ctrl.h @@ -82,7 +82,7 @@ __syscall void log_panic(void); /** * @brief Process one pending log message. * - * @retval true There is more messages pending to be processed. + * @retval true There are more messages pending to be processed. * @retval false No messages pending. */ __syscall bool log_process(void); @@ -156,7 +156,7 @@ uint32_t log_filter_get(struct log_backend const *const backend, /** * @brief Set filter on given source for the provided backend. * - * @param backend Backend instance. NULL for all backends. + * @param backend Backend instance. NULL for all backends (and frontend). * @param domain_id ID of the domain. * @param source_id Source (module or instance) ID. * @param level Severity level. @@ -168,6 +168,26 @@ __syscall uint32_t log_filter_set(struct log_backend const *const backend, uint32_t domain_id, int16_t source_id, uint32_t level); +/** + * @brief Get source filter for the frontend. + * + * @param source_id Source (module or instance) ID. + * @param runtime True for runtime filter or false for compiled in. + * + * @return Severity level. + */ +uint32_t log_frontend_filter_get(int16_t source_id, bool runtime); + +/** + * @brief Set filter on given source for the frontend. + * + * @param source_id Source (module or instance) ID. + * @param level Severity level. + * + * @return Actual level set which may be limited by compiled level. + */ +__syscall uint32_t log_frontend_filter_set(int16_t source_id, uint32_t level); + /** * * @brief Enable backend with initial maximum filtering level. diff --git a/include/zephyr/logging/log_output.h b/include/zephyr/logging/log_output.h index dff4ff81dcd..e28d1015aa4 100644 --- a/include/zephyr/logging/log_output.h +++ b/include/zephyr/logging/log_output.h @@ -54,6 +54,9 @@ extern "C" { /** @brief Flag thread id or name prefix. */ #define LOG_OUTPUT_FLAG_THREAD BIT(7) +/** @brief Flag forcing to skip logging the source. */ +#define LOG_OUTPUT_FLAG_SKIP_SOURCE BIT(8) + /**@} */ /** @brief Supported backend logging format types for use diff --git a/include/zephyr/lorawan/lorawan.h b/include/zephyr/lorawan/lorawan.h index 2e07e99d694..b0f0117d91d 100644 --- a/include/zephyr/lorawan/lorawan.h +++ b/include/zephyr/lorawan/lorawan.h @@ -26,63 +26,63 @@ extern "C" { * @brief LoRaWAN class types. */ enum lorawan_class { - LORAWAN_CLASS_A = 0x00, - LORAWAN_CLASS_B = 0x01, - LORAWAN_CLASS_C = 0x02, + LORAWAN_CLASS_A = 0x00, /**< Class A device */ + LORAWAN_CLASS_B = 0x01, /**< Class B device */ + LORAWAN_CLASS_C = 0x02, /**< Class C device */ }; /** * @brief LoRaWAN activation types. */ enum lorawan_act_type { - LORAWAN_ACT_OTAA = 0, - LORAWAN_ACT_ABP, + LORAWAN_ACT_OTAA = 0, /**< Over-the-Air Activation (OTAA) */ + LORAWAN_ACT_ABP, /**< Activation by Personalization (ABP) */ }; /** * @brief LoRaWAN datarate types. */ enum lorawan_datarate { - LORAWAN_DR_0 = 0, - LORAWAN_DR_1, - LORAWAN_DR_2, - LORAWAN_DR_3, - LORAWAN_DR_4, - LORAWAN_DR_5, - LORAWAN_DR_6, - LORAWAN_DR_7, - LORAWAN_DR_8, - LORAWAN_DR_9, - LORAWAN_DR_10, - LORAWAN_DR_11, - LORAWAN_DR_12, - LORAWAN_DR_13, - LORAWAN_DR_14, - LORAWAN_DR_15, + LORAWAN_DR_0 = 0, /**< DR0 data rate */ + LORAWAN_DR_1, /**< DR1 data rate */ + LORAWAN_DR_2, /**< DR2 data rate */ + LORAWAN_DR_3, /**< DR3 data rate */ + LORAWAN_DR_4, /**< DR4 data rate */ + LORAWAN_DR_5, /**< DR5 data rate */ + LORAWAN_DR_6, /**< DR6 data rate */ + LORAWAN_DR_7, /**< DR7 data rate */ + LORAWAN_DR_8, /**< DR8 data rate */ + LORAWAN_DR_9, /**< DR9 data rate */ + LORAWAN_DR_10, /**< DR10 data rate */ + LORAWAN_DR_11, /**< DR11 data rate */ + LORAWAN_DR_12, /**< DR12 data rate */ + LORAWAN_DR_13, /**< DR13 data rate */ + LORAWAN_DR_14, /**< DR14 data rate */ + LORAWAN_DR_15, /**< DR15 data rate */ }; /** * @brief LoRaWAN region types. */ enum lorawan_region { - LORAWAN_REGION_AS923, - LORAWAN_REGION_AU915, - LORAWAN_REGION_CN470, - LORAWAN_REGION_CN779, - LORAWAN_REGION_EU433, - LORAWAN_REGION_EU868, - LORAWAN_REGION_KR920, - LORAWAN_REGION_IN865, - LORAWAN_REGION_US915, - LORAWAN_REGION_RU864, + LORAWAN_REGION_AS923, /**< Asia 923 MHz frequency band */ + LORAWAN_REGION_AU915, /**< Australia 915 MHz frequency band */ + LORAWAN_REGION_CN470, /**< China 470 MHz frequency band */ + LORAWAN_REGION_CN779, /**< China 779 MHz frequency band */ + LORAWAN_REGION_EU433, /**< Europe 433 MHz frequency band */ + LORAWAN_REGION_EU868, /**< Europe 868 MHz frequency band */ + LORAWAN_REGION_KR920, /**< South Korea 920 MHz frequency band */ + LORAWAN_REGION_IN865, /**< India 865 MHz frequency band */ + LORAWAN_REGION_US915, /**< United States 915 MHz frequency band */ + LORAWAN_REGION_RU864, /**< Russia 864 MHz frequency band */ }; /** * @brief LoRaWAN message types. */ enum lorawan_message_type { - LORAWAN_MSG_UNCONFIRMED = 0, - LORAWAN_MSG_CONFIRMED, + LORAWAN_MSG_UNCONFIRMED = 0, /**< Unconfirmed message */ + LORAWAN_MSG_CONFIRMED, /**< Confirmed message */ }; /** @@ -128,9 +128,10 @@ struct lorawan_join_abp { * @brief LoRaWAN join parameters */ struct lorawan_join_config { + /** Join parameters */ union { - struct lorawan_join_otaa otaa; - struct lorawan_join_abp abp; + struct lorawan_join_otaa otaa; /**< OTAA join parameters */ + struct lorawan_join_abp abp; /**< ABP join parameters */ }; /** Device EUI. Optional if a secure element is present. */ @@ -140,6 +141,7 @@ struct lorawan_join_config { enum lorawan_act_type mode; }; +/** Flag to indicate receiving on any port */ #define LW_RECV_PORT_ANY UINT16_MAX /** diff --git a/include/zephyr/mem_mgmt/mem_attr_heap.h b/include/zephyr/mem_mgmt/mem_attr_heap.h new file mode 100644 index 00000000000..60cf183dd49 --- /dev/null +++ b/include/zephyr/mem_mgmt/mem_attr_heap.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 Carlo Caione, + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ +#define ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ + +/** + * @brief Memory heaps based on memory attributes + * @defgroup memory_attr_heap Memory heaps based on memory attributes + * @ingroup mem_mgmt + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Init the memory pool + * + * This must be the first function to be called to initialize the memory pools + * from all the memory regions with the a software attribute. + * + * @retval 0 on success. + * @retval -EALREADY if the pool was already initialized. + * @retval -ENOMEM too many regions already allocated. + */ +int mem_attr_heap_pool_init(void); + +/** + * @brief Allocate memory with a specified attribute and size. + * + * Allocates a block of memory of the specified size in bytes and with a + * specified capability / attribute. The attribute is used to select the + * correct memory heap to allocate memory from. + * + * @param attr capability / attribute requested for the memory block. + * @param bytes requested size of the allocation in bytes. + * + * @retval ptr a valid pointer to the allocated memory. + * @retval NULL if no memory is available with that attribute and size. + */ +void *mem_attr_heap_alloc(uint32_t attr, size_t bytes); + +/** + * @brief Allocate aligned memory with a specified attribute, size and alignment. + * + * Allocates a block of memory of the specified size in bytes and with a + * specified capability / attribute. Takes an additional parameter specifying a + * power of two alignment in bytes. + * + * @param attr capability / attribute requested for the memory block. + * @param align power of two alignment for the returned pointer in bytes. + * @param bytes requested size of the allocation in bytes. + * + * @retval ptr a valid pointer to the allocated memory. + * @retval NULL if no memory is available with that attribute and size. + */ +void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes); + +/** + * @brief Free the allocated memory + * + * Used to free the passed block of memory that must be the return value of a + * previously call to @ref mem_attr_heap_alloc or @ref + * mem_attr_heap_aligned_alloc. + * + * @param block block to free, must be a pointer to a block allocated by + * @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc. + */ +void mem_attr_heap_free(void *block); + +/** + * @brief Get a specific memory region descriptor for a provided address + * + * Finds the memory region descriptor struct controlling the provided pointer. + * + * @param addr address to be found, must be a pointer to a block allocated by + * @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc. + * + * @retval str pointer to a memory region structure the address belongs to. + */ +const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ */ diff --git a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h index 018aa60e980..cc0127938e3 100644 --- a/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h +++ b/include/zephyr/mgmt/ec_host_cmd/ec_host_cmd.h @@ -79,6 +79,7 @@ enum ec_host_cmd_log_level { }; typedef void (*ec_host_cmd_user_cb_t)(const struct ec_host_cmd_rx_ctx *rx_ctx, void *user_data); +typedef enum ec_host_cmd_status (*ec_host_cmd_in_progress_cb_t)(void *user_data); struct ec_host_cmd { struct ec_host_cmd_rx_ctx rx_ctx; @@ -281,7 +282,7 @@ int ec_host_cmd_init(struct ec_host_cmd_backend *backend); * @retval 0 if successful. */ int ec_host_cmd_send_response(enum ec_host_cmd_status status, - const struct ec_host_cmd_handler_args *args); + const struct ec_host_cmd_handler_args *args); /** * @brief Signal a new host command @@ -346,6 +347,23 @@ bool ec_host_cmd_send_in_progress_ended(void); * @retval The final status or EC_HOST_CMD_UNAVAILABLE if not available. */ enum ec_host_cmd_status ec_host_cmd_send_in_progress_status(void); + +/** + * @brief Continue processing a handler in callback after returning EC_HOST_CMD_IN_PROGRESS. + * + * A Host Command handler may return the EC_HOST_CMD_IN_PROGRESS, but needs to continue work. + * This function should be called before returning EC_HOST_CMD_IN_PROGRESS with a callback that + * will be executed. The return status of the callback will be stored and can be get with the + * ec_host_cmd_send_in_progress_status function. The ec_host_cmd_send_in_progress_ended function + * can be used to check if the callback has ended. + * + * @param[in] cb A callback to be called after returning from a command handler. + * @param[in] user_data User data to be passed to the callback. + * + * @retval EC_HOST_CMD_BUSY if any command is already in progress, EC_HOST_CMD_SUCCESS otherwise + */ +enum ec_host_cmd_status ec_host_cmd_send_in_progress_continue(ec_host_cmd_in_progress_cb_t cb, + void *user_data); #endif /* CONFIG_EC_HOST_CMD_IN_PROGRESS_STATUS */ /** diff --git a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h index 55c226d217c..c11e423e26d 100644 --- a/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h @@ -162,6 +162,9 @@ enum img_mgmt_err_code_t { /** Setting test to active slot is not allowed */ IMG_MGMT_ERR_IMAGE_SETTING_TEST_TO_ACTIVE_DENIED, + + /** Current active slot for image cannot be determined */ + IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN, }; /** diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h index 0b12ccdb684..ba63c136f50 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_client.h @@ -45,11 +45,12 @@ void os_mgmt_client_init(struct os_mgmt_client *client, struct smp_client_object * * @param client OS mgmt client object * @param echo_string Echo string + * @param max_len Max length of @p echo_string * * @return 0 on success. * @return @ref mcumgr_err_t code on failure. */ -int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string); +int os_mgmt_client_echo(struct os_mgmt_client *client, const char *echo_string, size_t max_len); /** * @brief Send SMP Reset command. diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index 43ee5ed6f95..7678a70fdf9 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -251,6 +251,9 @@ struct mgmt_evt_op_cmd_arg { uint8_t id; union { + /** #mcumgr_op_t used in #MGMT_EVT_OP_CMD_RECV */ + uint8_t op; + /** #mcumgr_err_t, used in #MGMT_EVT_OP_CMD_DONE */ int err; diff --git a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h index ed84b037633..7699dd57cc6 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/mgmt.h @@ -67,6 +67,7 @@ typedef int (*mgmt_handler_fn)(struct smp_streamer *ctxt); /** * @brief Read handler and write handler for a single command ID. + * Set use_custom_payload to true when using a user defined payload type */ struct mgmt_handler { mgmt_handler_fn mh_read; @@ -96,6 +97,11 @@ struct mgmt_group { */ smp_translate_error_fn mg_translate_error; #endif + +#if defined(CONFIG_MCUMGR_MGMT_CUSTOM_PAYLOAD) + /** Should be true when using user defined payload */ + bool custom_payload; +#endif }; /** @@ -126,13 +132,24 @@ const struct mgmt_handler *mgmt_find_handler(uint16_t group_id, uint16_t command /** * @brief Finds a registered command group. * - * @param group_id The command group id to find. + * @param group_id The group id of the command group to find. * - * @return The requested command group on success; + * @return The requested group on success; * NULL on failure. */ const struct mgmt_group *mgmt_find_group(uint16_t group_id); +/** + * @brief Finds a registered command handler. + * + * @param group The group of the command to find. + * @param command_id The ID of the command to find. + * + * @return The requested command handler on success; + * NULL on failure. + */ +const struct mgmt_handler *mgmt_get_handler(const struct mgmt_group *group, uint16_t command_id); + #if IS_ENABLED(CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL) /** * @brief Finds a registered error translation function for converting from SMP diff --git a/include/zephyr/mgmt/osdp.h b/include/zephyr/mgmt/osdp.h index 14080821239..b73314aece2 100644 --- a/include/zephyr/mgmt/osdp.h +++ b/include/zephyr/mgmt/osdp.h @@ -4,6 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Open Supervised Device Protocol (OSDP) public API header file. + */ + #ifndef _OSDP_H_ #define _OSDP_H_ @@ -16,27 +21,35 @@ extern "C" { #endif -#define OSDP_CMD_TEXT_MAX_LEN 32 -#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32 -#define OSDP_EVENT_MAX_DATALEN 64 +#define OSDP_CMD_TEXT_MAX_LEN 32 /**< Max length of text for text command */ +#define OSDP_CMD_KEYSET_KEY_MAX_LEN 32 /**< Max length of key data for keyset command */ +#define OSDP_EVENT_MAX_DATALEN 64 /**< Max length of event data */ /** * @brief Command sent from CP to Control digital output of PD. - * - * @param output_no 0 = First Output, 1 = Second Output, etc. - * @param control_code One of the following: - * 0 - NOP – do not alter this output - * 1 - set the permanent state to OFF, abort timed operation (if any) - * 2 - set the permanent state to ON, abort timed operation (if any) - * 3 - set the permanent state to OFF, allow timed operation to complete - * 4 - set the permanent state to ON, allow timed operation to complete - * 5 - set the temporary state to ON, resume perm state on timeout - * 6 - set the temporary state to OFF, resume permanent state on timeout - * @param timer_count Time in units of 100 ms */ struct osdp_cmd_output { + /** + * Output number. + * + * 0 = First Output, 1 = Second Output, etc. + */ uint8_t output_no; + /** + * Control code. + * + * - 0 - NOP – do not alter this output + * - 1 - set the permanent state to OFF, abort timed operation (if any) + * - 2 - set the permanent state to ON, abort timed operation (if any) + * - 3 - set the permanent state to OFF, allow timed operation to complete + * - 4 - set the permanent state to ON, allow timed operation to complete + * - 5 - set the temporary state to ON, resume perm state on timeout + * - 6 - set the temporary state to OFF, resume permanent state on timeout + */ uint8_t control_code; + /** + * Time in units of 100 ms + */ uint16_t timer_count; }; @@ -44,108 +57,156 @@ struct osdp_cmd_output { * @brief LED Colors as specified in OSDP for the on_color/off_color parameters. */ enum osdp_led_color_e { - OSDP_LED_COLOR_NONE, - OSDP_LED_COLOR_RED, - OSDP_LED_COLOR_GREEN, - OSDP_LED_COLOR_AMBER, - OSDP_LED_COLOR_BLUE, - OSDP_LED_COLOR_SENTINEL + OSDP_LED_COLOR_NONE, /**< No color */ + OSDP_LED_COLOR_RED, /**< Red */ + OSDP_LED_COLOR_GREEN, /**< Green */ + OSDP_LED_COLOR_AMBER, /**< Amber */ + OSDP_LED_COLOR_BLUE, /**< Blue */ + OSDP_LED_COLOR_SENTINEL /**< Max value */ }; /** - * @brief LED params sub-structure. Part of LED command. See struct osdp_cmd_led - * - * @param control_code One of the following: - * Temporary Control Code: - * 0 - NOP - do not alter this LED's temporary settings - * 1 - Cancel any temporary operation and display this LED's permanent state - * immediately - * 2 - Set the temporary state as given and start timer immediately - * Permanent Control Code: - * 0 - NOP - do not alter this LED's permanent settings - * 1 - Set the permanent state as given - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param on_color Color to set during the ON timer (enum osdp_led_color_e) - * @param off_color Color to set during the OFF timer (enum osdp_led_color_e) - * @param timer_count Time in units of 100 ms (only for temporary mode) + * @brief LED params sub-structure. Part of LED command. See @ref osdp_cmd_led. */ struct osdp_cmd_led_params { + /** Control code. + * + * Temporary Control Code: + * - 0 - NOP - do not alter this LED's temporary settings. + * - 1 - Cancel any temporary operation and display this LED's permanent state immediately. + * - 2 - Set the temporary state as given and start timer immediately. + * + * Permanent Control Code: + * - 0 - NOP - do not alter this LED's permanent settings. + * - 1 - Set the permanent state as given. + */ uint8_t control_code; + /** + * The ON duration of the flash, in units of 100 ms. + */ uint8_t on_count; + /** + * The OFF duration of the flash, in units of 100 ms. + */ uint8_t off_count; + /** + * Color to set during the ON timer (see @ref osdp_led_color_e). + */ uint8_t on_color; + /** + * Color to set during the OFF timer (see @ref osdp_led_color_e). + */ uint8_t off_color; + /** + * Time in units of 100 ms (only for temporary mode). + */ uint16_t timer_count; }; /** * @brief Sent from CP to PD to control the behaviour of it's on-board LEDs - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param led_number 0 = first LED, 1 = second LED, etc. - * @param temporary ephemeral LED status descriptor - * @param permanent permanent LED status descriptor */ struct osdp_cmd_led { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * LED number. 0 = first LED, 1 = second LED, etc. + */ uint8_t led_number; + /** + * Ephemeral LED status descriptor. + */ struct osdp_cmd_led_params temporary; + /** + * Permanent LED status descriptor. + */ struct osdp_cmd_led_params permanent; }; /** * @brief Sent from CP to control the behaviour of a buzzer in the PD. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code 0: no tone, 1: off, 2: default tone, 3+ is TBD. - * @param on_count The ON duration of the flash, in units of 100 ms - * @param off_count The OFF duration of the flash, in units of 100 ms - * @param rep_count The number of times to repeat the ON/OFF cycle; 0: forever */ struct osdp_cmd_buzzer { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * Control code. + * - 0 - no tone + * - 1 - off + * - 2 - default tone + * - 3+ - TBD + */ uint8_t control_code; + /** + * The ON duration of the sound, in units of 100 ms. + */ uint8_t on_count; + /** + * The OFF duration of the sound, in units of 100 ms. + */ uint8_t off_count; + /** + * The number of times to repeat the ON/OFF cycle; 0: forever. + */ uint8_t rep_count; }; /** * @brief Command to manipulate any display units that the PD supports. - * - * @param reader 0 = First Reader, 1 = Second Reader, etc. - * @param control_code One of the following: - * 1 - permanent text, no wrap - * 2 - permanent text, with wrap - * 3 - temp text, no wrap - * 4 - temp text, with wrap - * @param temp_time duration to display temporary text, in seconds - * @param offset_row row to display the first character (1 indexed) - * @param offset_col column to display the first character (1 indexed) - * @param length Number of characters in the string - * @param data The string to display */ struct osdp_cmd_text { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ uint8_t reader; + /** + * Control code. + * - 1 - permanent text, no wrap + * - 2 - permanent text, with wrap + * - 3 - temp text, no wrap + * - 4 - temp text, with wrap + */ uint8_t control_code; + /** + * Duration to display temporary text, in seconds + */ uint8_t temp_time; + /** + * Row to display the first character (1-indexed) + */ uint8_t offset_row; + /** + * Column to display the first character (1-indexed) + */ uint8_t offset_col; + /** + * Number of characters in the string + */ uint8_t length; + /** + * The string to display + */ uint8_t data[OSDP_CMD_TEXT_MAX_LEN]; }; /** * @brief Sent in response to a COMSET command. Set communication parameters to * PD. Must be stored in PD non-volatile memory. - * - * @param address Unit ID to which this PD will respond after the change takes - * effect. - * @param baud_rate baud rate value 9600/38400/115200 */ struct osdp_cmd_comset { + /** + * Unit ID to which this PD will respond after the change takes effect. + */ uint8_t address; + /** + * Baud rate. + * + * Valid values: 9600, 19200, 38400, 115200, 230400. + */ uint32_t baud_rate; }; @@ -158,8 +219,18 @@ struct osdp_cmd_comset { * @param data Key data */ struct osdp_cmd_keyset { + /** + * Type of keys: + * - 0x01 – Secure Channel Base Key + */ uint8_t type; + /** + * Number of bytes of key data - (Key Length in bits + 7) / 8 + */ uint8_t length; + /** + * Key data + */ uint8_t data[OSDP_CMD_KEYSET_KEY_MAX_LEN]; }; @@ -167,37 +238,36 @@ struct osdp_cmd_keyset { * @brief OSDP application exposed commands */ enum osdp_cmd_e { - OSDP_CMD_OUTPUT = 1, - OSDP_CMD_LED, - OSDP_CMD_BUZZER, - OSDP_CMD_TEXT, - OSDP_CMD_KEYSET, - OSDP_CMD_COMSET, - OSDP_CMD_SENTINEL + OSDP_CMD_OUTPUT = 1, /**< Output control command */ + OSDP_CMD_LED, /**< Reader LED control command */ + OSDP_CMD_BUZZER, /**< Reader buzzer control command */ + OSDP_CMD_TEXT, /**< Reader text output command */ + OSDP_CMD_KEYSET, /**< Encryption Key Set Command */ + OSDP_CMD_COMSET, /**< PD Communication Configuration Command */ + OSDP_CMD_SENTINEL /**< Max command value */ }; /** * @brief OSDP Command Structure. This is a wrapper for all individual OSDP * commands. - * - * @param id used to select specific commands in union. Type: enum osdp_cmd_e - * @param led LED command structure - * @param buzzer buzzer command structure - * @param text text command structure - * @param output output command structure - * @param comset comset command structure - * @param keyset keyset command structure */ struct osdp_cmd { + /** @cond INTERNAL_HIDDEN */ sys_snode_t node; + /** @endcond */ + /** + * Command ID. + * Used to select specific commands in union. + */ enum osdp_cmd_e id; + /** Command */ union { - struct osdp_cmd_led led; - struct osdp_cmd_buzzer buzzer; - struct osdp_cmd_text text; - struct osdp_cmd_output output; - struct osdp_cmd_comset comset; - struct osdp_cmd_keyset keyset; + struct osdp_cmd_led led; /**< LED command structure */ + struct osdp_cmd_buzzer buzzer; /**< Buzzer command structure */ + struct osdp_cmd_text text; /**< Text command structure */ + struct osdp_cmd_output output; /**< Output command structure */ + struct osdp_cmd_comset comset; /**< Comset command structure */ + struct osdp_cmd_keyset keyset; /**< Keyset command structure */ }; }; @@ -206,49 +276,62 @@ struct osdp_cmd { * when a PD must report a card read. */ enum osdp_event_cardread_format_e { - OSDP_CARD_FMT_RAW_UNSPECIFIED, - OSDP_CARD_FMT_RAW_WIEGAND, - OSDP_CARD_FMT_ASCII, - OSDP_CARD_FMT_SENTINEL + OSDP_CARD_FMT_RAW_UNSPECIFIED, /**< Unspecified card format */ + OSDP_CARD_FMT_RAW_WIEGAND, /**< Wiegand card format */ + OSDP_CARD_FMT_ASCII, /**< ASCII card format */ + OSDP_CARD_FMT_SENTINEL /**< Max card format value */ }; /** * @brief OSDP event cardread * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param format Format of the card being read. - * see `enum osdp_event_cardread_format_e` - * @param direction Card read direction of PD 0 - Forward; 1 - Backward - * @param length Length of card data in bytes or bits depending on `format` - * (see note). - * @param data Card data of `length` bytes or bits bits depending on `format` - * (see note). - * - * @note When `format` is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or + * @note When @a format is set to OSDP_CARD_FMT_RAW_UNSPECIFIED or * OSDP_CARD_FMT_RAW_WIEGAND, the length is expressed in bits. OTOH, when it is * set to OSDP_CARD_FMT_ASCII, the length is in bytes. The number of bytes to - * read from the `data` field must be interpreted accordingly. + * read from the @a data field must be interpreted accordingly. */ struct osdp_event_cardread { + /** + * Reader number. 0 = First Reader, 1 = Second Reader, etc. + */ int reader_no; + /** + * Format of the card being read. + */ enum osdp_event_cardread_format_e format; + /** + * Direction of data in @a data array. + * - 0 - Forward + * - 1 - Backward + */ int direction; + /** + * Length of card data in bytes or bits depending on @a format + */ int length; + /** + * Card data of @a length bytes or bits bits depending on @a format + */ uint8_t data[OSDP_EVENT_MAX_DATALEN]; }; /** * @brief OSDP Event Keypad - * - * @param reader_no In context of readers attached to current PD, this number - * indicated this number. This is not supported by LibOSDP. - * @param length Length of keypress data in bytes - * @param data keypress data of `length` bytes */ struct osdp_event_keypress { + /** + * Reader number. + * In context of readers attached to current PD, this number indicated this number. This is + * not supported by LibOSDP. + */ int reader_no; + /** + * Length of keypress data in bytes + */ int length; + /** + * Keypress data of @a length bytes + */ uint8_t data[OSDP_EVENT_MAX_DATALEN]; }; @@ -256,24 +339,27 @@ struct osdp_event_keypress { * @brief OSDP PD Events */ enum osdp_event_type { - OSDP_EVENT_CARDREAD, - OSDP_EVENT_KEYPRESS, - OSDP_EVENT_SENTINEL + OSDP_EVENT_CARDREAD, /**< Card read event */ + OSDP_EVENT_KEYPRESS, /**< Keypad press event */ + OSDP_EVENT_SENTINEL /**< Max event value */ }; /** * @brief OSDP Event structure. - * - * @param type used to select specific event in union. See: enum osdp_event_type - * @param keypress keypress event structure - * @param cardread cardread event structure */ struct osdp_event { + /** @cond INTERNAL_HIDDEN */ sys_snode_t node; + /** @endcond */ + /** + * Event type. + * Used to select specific event in union. + */ enum osdp_event_type type; + /** Event */ union { - struct osdp_event_keypress keypress; - struct osdp_event_cardread cardread; + struct osdp_event_keypress keypress; /**< Keypress event structure */ + struct osdp_event_cardread cardread; /**< Card read event structure */ }; }; @@ -309,7 +395,13 @@ typedef int (*pd_command_callback_t)(void *arg, struct osdp_cmd *cmd); */ typedef int (*cp_event_callback_t)(void *arg, int pd, struct osdp_event *ev); -#ifdef CONFIG_OSDP_MODE_PD +#if defined(CONFIG_OSDP_MODE_PD) || defined(__DOXYGEN__) + +/** + * @name Peripheral Device mode APIs + * @note These are only available when @kconfig{CONFIG_OSDP_MODE_PD} is enabled. + * @{ + */ /** * @brief Set callback method for PD command notification. This callback is @@ -331,6 +423,10 @@ void osdp_pd_set_command_callback(pd_command_callback_t cb, void *arg); */ int osdp_pd_notify_event(const struct osdp_event *event); +/** + * @} + */ + #else /* CONFIG_OSDP_MODE_PD */ /** @@ -359,10 +455,25 @@ void osdp_cp_set_event_callback(cp_event_callback_t cb, void *arg); #endif /* CONFIG_OSDP_MODE_PD */ -#ifdef CONFIG_OSDP_SC_ENABLED +#if defined(CONFIG_OSDP_SC_ENABLED) || defined(__DOXYGEN__) +/** + * @name OSDP Secure Channel APIs + * @note These are only available when @kconfig{CONFIG_OSDP_SC_ENABLED} is + * enabled. + * @{ + */ + +/** + * Get the current SC status mask. + * @return SC status mask + */ uint32_t osdp_get_sc_status_mask(void); +/** + * @} + */ + #endif #ifdef __cplusplus diff --git a/include/zephyr/modbus/modbus.h b/include/zephyr/modbus/modbus.h index 1fba0ac669d..7043594b8ec 100644 --- a/include/zephyr/modbus/modbus.h +++ b/include/zephyr/modbus/modbus.h @@ -44,16 +44,25 @@ extern "C" { /** @name Modbus exception codes * @{ */ -/* Modbus exception codes */ +/** No exception */ #define MODBUS_EXC_NONE 0 +/** Illegal function code */ #define MODBUS_EXC_ILLEGAL_FC 1 +/** Illegal data address */ #define MODBUS_EXC_ILLEGAL_DATA_ADDR 2 +/** Illegal data value */ #define MODBUS_EXC_ILLEGAL_DATA_VAL 3 +/** Server device failure */ #define MODBUS_EXC_SERVER_DEVICE_FAILURE 4 +/** Acknowledge */ #define MODBUS_EXC_ACK 5 +/** Server device busy */ #define MODBUS_EXC_SERVER_DEVICE_BUSY 6 +/** Memory parity error */ #define MODBUS_EXC_MEM_PARITY_ERROR 8 +/** Gateway path unavailable */ #define MODBUS_EXC_GW_PATH_UNAVAILABLE 10 +/** Gateway target device failed to respond */ #define MODBUS_EXC_GW_TARGET_FAILED_TO_RESP 11 /** @} */ diff --git a/include/zephyr/modem/backend/uart.h b/include/zephyr/modem/backend/uart.h index 0ddef4df734..5f9f99370a0 100644 --- a/include/zephyr/modem/backend/uart.h +++ b/include/zephyr/modem/backend/uart.h @@ -43,6 +43,7 @@ struct modem_backend_uart { const struct device *uart; struct modem_pipe pipe; struct k_work receive_ready_work; + struct k_work transmit_idle_work; union { struct modem_backend_uart_isr isr; diff --git a/include/zephyr/modem/chat.h b/include/zephyr/modem/chat.h index d46ffc7c24a..28a2bc6bf9f 100644 --- a/include/zephyr/modem/chat.h +++ b/include/zephyr/modem/chat.h @@ -240,9 +240,9 @@ struct modem_chat { struct k_sem script_stopped_sem; /* Script sending */ - uint16_t script_send_request_pos; - uint16_t script_send_delimiter_pos; - struct k_work_delayable script_send_work; + enum modem_chat_script_send_state script_send_state; + uint16_t script_send_pos; + struct k_work script_send_work; struct k_work_delayable script_send_timeout_work; /* Match parsing */ @@ -252,8 +252,7 @@ struct modem_chat { uint16_t parse_match_type; /* Process received data */ - struct k_work_delayable process_work; - k_timeout_t process_timeout; + struct k_work receive_work; }; /** @@ -282,8 +281,6 @@ struct modem_chat_config { const struct modem_chat_match *unsol_matches; /** Elements in array of unsolicited matches */ uint16_t unsol_matches_size; - /** Delay from receive ready event to pipe receive occurs */ - k_timeout_t process_timeout; }; /** diff --git a/include/zephyr/modem/cmux.h b/include/zephyr/modem/cmux.h index 4562cb544d9..58959d6136b 100644 --- a/include/zephyr/modem/cmux.h +++ b/include/zephyr/modem/cmux.h @@ -63,10 +63,7 @@ enum modem_cmux_state { enum modem_cmux_receive_state { MODEM_CMUX_RECEIVE_STATE_SOF = 0, - MODEM_CMUX_RECEIVE_STATE_RESYNC_0, - MODEM_CMUX_RECEIVE_STATE_RESYNC_1, - MODEM_CMUX_RECEIVE_STATE_RESYNC_2, - MODEM_CMUX_RECEIVE_STATE_RESYNC_3, + MODEM_CMUX_RECEIVE_STATE_RESYNC, MODEM_CMUX_RECEIVE_STATE_ADDRESS, MODEM_CMUX_RECEIVE_STATE_ADDRESS_CONT, MODEM_CMUX_RECEIVE_STATE_CONTROL, diff --git a/include/zephyr/modem/pipe.h b/include/zephyr/modem/pipe.h index abf8d74918e..a741a94a34c 100644 --- a/include/zephyr/modem/pipe.h +++ b/include/zephyr/modem/pipe.h @@ -25,6 +25,7 @@ extern "C" { enum modem_pipe_event { MODEM_PIPE_EVENT_OPENED = 0, MODEM_PIPE_EVENT_RECEIVE_READY, + MODEM_PIPE_EVENT_TRANSMIT_IDLE, MODEM_PIPE_EVENT_CLOSED, }; @@ -73,7 +74,8 @@ struct modem_pipe { enum modem_pipe_state state; struct k_mutex lock; struct k_condvar condvar; - bool receive_ready_pending; + uint8_t receive_ready_pending : 1; + uint8_t transmit_idle_pending : 1; }; /** @@ -213,6 +215,15 @@ void modem_pipe_notify_closed(struct modem_pipe *pipe); */ void modem_pipe_notify_receive_ready(struct modem_pipe *pipe); +/** + * @brief Notify user of pipe that pipe has no more data to transmit + * + * @param pipe Pipe instance + * + * @note Invoked from instance which initialized the pipe instance + */ +void modem_pipe_notify_transmit_idle(struct modem_pipe *pipe); + /** * @endcond */ diff --git a/include/zephyr/net/buf.h b/include/zephyr/net/buf.h index f7378fc3962..6e7f8b5b2a8 100644 --- a/include/zephyr/net/buf.h +++ b/include/zephyr/net/buf.h @@ -28,7 +28,11 @@ extern "C" { */ /* Alignment needed for various parts of the buffer definition */ +#if CONFIG_NET_BUF_ALIGNMENT == 0 #define __net_buf_align __aligned(sizeof(void *)) +#else +#define __net_buf_align __aligned(CONFIG_NET_BUF_ALIGNMENT) +#endif /** * @brief Define a net_buf_simple stack variable. @@ -1006,21 +1010,10 @@ struct net_buf_pool { }; /** @cond INTERNAL_HIDDEN */ -#if defined(CONFIG_NET_BUF_POOL_USAGE) -#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \ - { \ - .free = Z_LIFO_INITIALIZER(_pool.free), \ - .lock = { }, \ - .buf_count = _count, \ - .uninit_count = _count, \ - .user_data_size = _ud_size, \ - .avail_count = ATOMIC_INIT(_count), \ - .name = STRINGIFY(_pool), \ - .destroy = _destroy, \ - .alloc = _alloc, \ - .__bufs = (struct net_buf *)_bufs, \ - } -#else +#define NET_BUF_POOL_USAGE_INIT(_pool, _count) \ + IF_ENABLED(CONFIG_NET_BUF_POOL_USAGE, (.avail_count = ATOMIC_INIT(_count),)) \ + IF_ENABLED(CONFIG_NET_BUF_POOL_USAGE, (.name = STRINGIFY(_pool),)) + #define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \ { \ .free = Z_LIFO_INITIALIZER(_pool.free), \ @@ -1028,11 +1021,11 @@ struct net_buf_pool { .buf_count = _count, \ .uninit_count = _count, \ .user_data_size = _ud_size, \ + NET_BUF_POOL_USAGE_INIT(_pool, _count) \ .destroy = _destroy, \ .alloc = _alloc, \ .__bufs = (struct net_buf *)_bufs, \ } -#endif /* CONFIG_NET_BUF_POOL_USAGE */ #define _NET_BUF_ARRAY_DEFINE(_name, _count, _ud_size) \ struct _net_buf_##_name { uint8_t b[sizeof(struct net_buf)]; \ @@ -2421,6 +2414,22 @@ size_t net_buf_append_bytes(struct net_buf *buf, size_t len, const void *value, k_timeout_t timeout, net_buf_allocator_cb allocate_cb, void *user_data); +/** + * @brief Match data with a net_buf's content + * + * @details Compare data with a content of a net_buf. Provide information about + * the number of bytes matching between both. If needed, traverse + * through multiple buffer fragments. + * + * @param buf Network buffer + * @param offset Starting offset to compare from + * @param data Data buffer for comparison + * @param len Number of bytes to compare + * + * @return The number of bytes compared before the first difference. + */ +size_t net_buf_data_match(const struct net_buf *buf, size_t offset, const void *data, size_t len); + /** * @brief Skip N number of bytes in a net_buf * diff --git a/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h b/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h new file mode 100644 index 00000000000..88ef775ad1e --- /dev/null +++ b/include/zephyr/net/conn_mgr/connectivity_wifi_mgmt.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 CSIRO + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Connectivity implementation for drivers exposing the wifi_mgmt API + */ + +#ifndef ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ +#define ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context type for generic WIFI_MGMT connectivity backend. + */ +#define CONNECTIVITY_WIFI_MGMT_CTX_TYPE void * + +/** + * @brief Associate the generic WIFI_MGMT implementation with a network device + * + * @param dev_id Network device id. + */ +#define CONNECTIVITY_WIFI_MGMT_BIND(dev_id) \ + IF_ENABLED(CONFIG_NET_CONNECTION_MANAGER_CONNECTIVITY_WIFI_MGMT, \ + (CONN_MGR_CONN_DECLARE_PUBLIC(CONNECTIVITY_WIFI_MGMT); \ + CONN_MGR_BIND_CONN(dev_id, CONNECTIVITY_WIFI_MGMT))) + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_CONN_MGR_CONNECTIVITY_WIFI_MGMT_H_ */ diff --git a/include/zephyr/net/dns_resolve.h b/include/zephyr/net/dns_resolve.h index 50e6501a730..46e5ad8e4df 100644 --- a/include/zephyr/net/dns_resolve.h +++ b/include/zephyr/net/dns_resolve.h @@ -277,6 +277,15 @@ int dns_resolve_init(struct dns_resolve_context *ctx, const char *dns_servers_str[], const struct sockaddr *dns_servers_sa[]); +/** + * @brief Init DNS resolving context with default Kconfig options. + * + * @param ctx DNS context. + * + * @return 0 if ok, <0 if error. + */ +int dns_resolve_init_default(struct dns_resolve_context *ctx); + /** * @brief Close DNS resolving context. * @@ -455,12 +464,12 @@ static inline int dns_cancel_addr_info(uint16_t dns_id) /** * @brief Initialize DNS subsystem. */ -#if defined(CONFIG_DNS_RESOLVER) +#if defined(CONFIG_DNS_RESOLVER_AUTO_INIT) void dns_init_resolver(void); #else #define dns_init_resolver(...) -#endif /* CONFIG_DNS_RESOLVER */ +#endif /* CONFIG_DNS_RESOLVER_AUTO_INIT */ /** @endcond */ diff --git a/include/zephyr/net/dummy.h b/include/zephyr/net/dummy.h index d291f93d508..0be84c80191 100644 --- a/include/zephyr/net/dummy.h +++ b/include/zephyr/net/dummy.h @@ -31,6 +31,12 @@ struct dummy_api { /** Send a network packet */ int (*send)(const struct device *dev, struct net_pkt *pkt); + + /** Start the device. Called when the bound network interface is brought up. */ + int (*start)(const struct device *dev); + + /** Stop the device. Called when the bound network interface is taken down. */ + int (*stop)(const struct device *dev); }; /* Make sure that the network interface API is properly setup inside diff --git a/include/zephyr/net/hostname.h b/include/zephyr/net/hostname.h index e34c1df31ac..196e9ab18e7 100644 --- a/include/zephyr/net/hostname.h +++ b/include/zephyr/net/hostname.h @@ -22,10 +22,22 @@ extern "C" { * @{ */ -#define NET_HOSTNAME_MAX_LEN \ - (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ - (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? \ - sizeof("0011223344556677") - 1 : 0)) +#if defined(CONFIG_NET_HOSTNAME_MAX_LEN) +#define NET_HOSTNAME_MAX_LEN \ + MAX(CONFIG_NET_HOSTNAME_MAX_LEN, \ + (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ + (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0))) +#else +#define NET_HOSTNAME_MAX_LEN \ + (sizeof(CONFIG_NET_HOSTNAME) - 1 + \ + (IS_ENABLED(CONFIG_NET_HOSTNAME_UNIQUE) ? sizeof("0011223344556677") - 1 : 0)) +#endif + +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +#define NET_HOSTNAME_SIZE NET_HOSTNAME_MAX_LEN + 1 +#else +#define NET_HOSTNAME_SIZE 1 +#endif /** * @brief Get the device hostname @@ -43,6 +55,23 @@ static inline const char *net_hostname_get(void) } #endif /* CONFIG_NET_HOSTNAME_ENABLE */ +/** + * @brief Set the device hostname + * + * @param host new hostname as char array. + * @param len Length of the hostname array. + * + * @return 0 if ok, <0 on error + */ +#if defined(CONFIG_NET_HOSTNAME_DYNAMIC) +int net_hostname_set(char *host, size_t len); +#else +static inline int net_hostname_set(char *host, size_t len) +{ + return -ENOTSUP; +} +#endif + /** * @brief Initialize and set the device hostname. * diff --git a/include/zephyr/net/igmp.h b/include/zephyr/net/igmp.h index 7119676f237..ed39a31359f 100644 --- a/include/zephyr/net/igmp.h +++ b/include/zephyr/net/igmp.h @@ -27,22 +27,31 @@ extern "C" { #endif +struct igmp_param { + struct in_addr *source_list; /* List of sources to include or exclude */ + size_t sources_len; /* Length of source list */ + bool include; /* Source list filter type */ +}; + /** * @brief Join a given multicast group. * * @param iface Network interface where join message is sent * @param addr Multicast group to join + * @param param Optional parameters * * @return Return 0 if joining was done, <0 otherwise. */ #if defined(CONFIG_NET_IPV4_IGMP) -int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr); +int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param); #else -static inline int net_ipv4_igmp_join(struct net_if *iface, - const struct in_addr *addr) +static inline int net_ipv4_igmp_join(struct net_if *iface, const struct in_addr *addr, + const struct igmp_param *param) { ARG_UNUSED(iface); ARG_UNUSED(addr); + ARG_UNUSED(param); return -ENOSYS; } diff --git a/include/zephyr/net/mdio.h b/include/zephyr/net/mdio.h index e7161a7a766..8d1998f7cec 100644 --- a/include/zephyr/net/mdio.h +++ b/include/zephyr/net/mdio.h @@ -110,6 +110,8 @@ enum mdio_opcode { #define MDIO_AN_T1_ADV_M 0x0203U /** BASE-T1 Auto-negotiation advertisement register [47:32] */ #define MDIO_AN_T1_ADV_H 0x0204U +/* BASE-T1 PMA/PMD control register */ +#define MDIO_PMA_PMD_BT1_CTRL 0x0834U /* BASE-T1 Auto-negotiation Control register */ /** Auto-negotiation Restart */ @@ -155,6 +157,10 @@ enum mdio_opcode { /* 10BASE-T1L High Level Transmit Operating Mode Ability */ #define MDIO_AN_T1_ADV_H_10L_TX_HI BIT(13) +/* BASE-T1 PMA/PMD control register */ +/** BASE-T1 master/slave configuration */ +#define MDIO_PMA_PMD_BT1_CTRL_CFG_MST BIT(14) + /* 10BASE-T1L registers */ /** 10BASE-T1L PMA control */ diff --git a/include/zephyr/net/mqtt_sn.h b/include/zephyr/net/mqtt_sn.h index 7700558f1fe..cb1a6d33731 100644 --- a/include/zephyr/net/mqtt_sn.h +++ b/include/zephyr/net/mqtt_sn.h @@ -397,6 +397,19 @@ int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos, */ int mqtt_sn_input(struct mqtt_sn_client *client); +/** + * @brief Get topic name by topic ID. + * + * @param[in] client The MQTT-SN client that uses this topic. + * @param[in] id Topic identifier. + * @param[out] topic_name Will be assigned to topic name. + * + * @return 0 on success, -ENOENT if topic ID doesn't exist, + * or -EINVAL on invalid arguments. + */ +int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id, + struct mqtt_sn_data *topic_name); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/net_context.h b/include/zephyr/net/net_context.h index ea116a24846..55548917c45 100644 --- a/include/zephyr/net/net_context.h +++ b/include/zephyr/net/net_context.h @@ -300,37 +300,54 @@ __net_socket struct net_context { uint8_t priority; #endif #if defined(CONFIG_NET_CONTEXT_TXTIME) + /** When to send the packet out */ bool txtime; #endif #if defined(CONFIG_SOCKS) + /** Socks proxy address */ struct { struct sockaddr addr; socklen_t addrlen; } proxy; #endif #if defined(CONFIG_NET_CONTEXT_RCVTIMEO) + /** Receive timeout */ k_timeout_t rcvtimeo; #endif #if defined(CONFIG_NET_CONTEXT_SNDTIMEO) + /** Send timeout */ k_timeout_t sndtimeo; #endif #if defined(CONFIG_NET_CONTEXT_RCVBUF) + /** Receive buffer maximum size */ uint16_t rcvbuf; #endif #if defined(CONFIG_NET_CONTEXT_SNDBUF) + /** Send buffer maximum size */ uint16_t sndbuf; #endif #if defined(CONFIG_NET_CONTEXT_DSCP_ECN) + /** + * DSCP (Differentiated Services Code point) and + * ECN (Explicit Congestion Notification) values. + */ uint8_t dscp_ecn; #endif #if defined(CONFIG_NET_CONTEXT_REUSEADDR) + /** Re-use address (SO_REUSEADDR) flag on a socket. */ bool reuseaddr; #endif #if defined(CONFIG_NET_CONTEXT_REUSEPORT) + /** Re-use port (SO_REUSEPORT) flag on a socket. */ bool reuseport; #endif #if defined(CONFIG_NET_IPV4_MAPPING_TO_IPV6) + /** Support v4-mapped-on-v6 addresses */ bool ipv6_v6only; +#endif +#if defined(CONFIG_NET_CONTEXT_RECV_PKTINFO) + /** Receive network packet information in recvmsg() call */ + bool recv_pktinfo; #endif } options; @@ -345,16 +362,30 @@ __net_socket struct net_context { /** IPv6 hop limit or IPv4 ttl for packets sent via this context. */ union { - uint8_t ipv6_hop_limit; - uint8_t ipv4_ttl; + struct { + uint8_t ipv6_hop_limit; /**< IPv6 hop limit */ + uint8_t ipv6_mcast_hop_limit; /**< IPv6 multicast hop limit */ + }; + struct { + uint8_t ipv4_ttl; /**< IPv4 TTL */ + uint8_t ipv4_mcast_ttl; /**< IPv4 multicast TTL */ + }; }; #if defined(CONFIG_SOCKS) + /** Is socks proxy enabled */ bool proxy_enabled; #endif }; +/** + * @brief Is this context used or not. + * + * @param context Network context. + * + * @return True if the context is currently in use, False otherwise. + */ static inline bool net_context_is_used(struct net_context *context) { NET_ASSERT(context); @@ -362,6 +393,13 @@ static inline bool net_context_is_used(struct net_context *context) return context->flags & NET_CONTEXT_IN_USE; } +/** + * @brief Is this context bound to a network interface. + * + * @param context Network context. + * + * @return True if the context is bound to network interface, False otherwise. + */ static inline bool net_context_is_bound_to_iface(struct net_context *context) { NET_ASSERT(context); @@ -689,39 +727,140 @@ static inline void net_context_bind_iface(struct net_context *context, net_context_set_iface(context, iface); } +/** + * @brief Get IPv4 TTL (time-to-live) value for this context. + * + * @details This function returns the IPv4 TTL (time-to-live) value that is + * set to this context. + * + * @param context Network context. + * + * @return IPv4 TTL value + */ static inline uint8_t net_context_get_ipv4_ttl(struct net_context *context) { return context->ipv4_ttl; } +/** + * @brief Set IPv4 TTL (time-to-live) value for this context. + * + * @details This function sets the IPv4 TTL (time-to-live) value for + * this context. + * + * @param context Network context. + * @param ttl IPv4 time-to-live value. + */ static inline void net_context_set_ipv4_ttl(struct net_context *context, uint8_t ttl) { context->ipv4_ttl = ttl; } +/** + * @brief Get IPv4 multicast TTL (time-to-live) value for this context. + * + * @details This function returns the IPv4 multicast TTL (time-to-live) value + * that is set to this context. + * + * @param context Network context. + * + * @return IPv4 multicast TTL value + */ +static inline uint8_t net_context_get_ipv4_mcast_ttl(struct net_context *context) +{ + return context->ipv4_mcast_ttl; +} + +/** + * @brief Set IPv4 multicast TTL (time-to-live) value for this context. + * + * @details This function sets the IPv4 multicast TTL (time-to-live) value for + * this context. + * + * @param context Network context. + * @param ttl IPv4 multicast time-to-live value. + */ +static inline void net_context_set_ipv4_mcast_ttl(struct net_context *context, + uint8_t ttl) +{ + context->ipv4_mcast_ttl = ttl; +} + +/** + * @brief Get IPv6 hop limit value for this context. + * + * @details This function returns the IPv6 hop limit value that is set to this + * context. + * + * @param context Network context. + * + * @return IPv6 hop limit value + */ static inline uint8_t net_context_get_ipv6_hop_limit(struct net_context *context) { return context->ipv6_hop_limit; } +/** + * @brief Set IPv6 hop limit value for this context. + * + * @details This function sets the IPv6 hop limit value for this context. + * + * @param context Network context. + * @param hop_limit IPv6 hop limit value. + */ static inline void net_context_set_ipv6_hop_limit(struct net_context *context, uint8_t hop_limit) { context->ipv6_hop_limit = hop_limit; } +/** + * @brief Get IPv6 multicast hop limit value for this context. + * + * @details This function returns the IPv6 multicast hop limit value + * that is set to this context. + * + * @param context Network context. + * + * @return IPv6 multicast hop limit value + */ +static inline uint8_t net_context_get_ipv6_mcast_hop_limit(struct net_context *context) +{ + return context->ipv6_mcast_hop_limit; +} + +/** + * @brief Set IPv6 multicast hop limit value for this context. + * + * @details This function sets the IPv6 multicast hop limit value for + * this context. + * + * @param context Network context. + * @param hop_limit IPv6 multicast hop limit value. + */ +static inline void net_context_set_ipv6_mcast_hop_limit(struct net_context *context, + uint8_t hop_limit) +{ + context->ipv6_mcast_hop_limit = hop_limit; +} + +/** + * @brief Enable or disable socks proxy support for this context. + * + * @details This function either enables or disables socks proxy support for + * this context. + * + * @param context Network context. + * @param enable Enable socks proxy or disable it. + */ #if defined(CONFIG_SOCKS) static inline void net_context_set_proxy_enabled(struct net_context *context, bool enable) { context->proxy_enabled = enable; } - -static inline bool net_context_is_proxy_enabled(struct net_context *context) -{ - return context->proxy_enabled; -} #else static inline void net_context_set_proxy_enabled(struct net_context *context, bool enable) @@ -729,7 +868,24 @@ static inline void net_context_set_proxy_enabled(struct net_context *context, ARG_UNUSED(context); ARG_UNUSED(enable); } +#endif +/** + * @brief Is socks proxy support enabled or disabled for this context. + * + * @details This function returns current socks proxy status for + * this context. + * + * @param context Network context. + * + * @return True if socks proxy is enabled for this context, False otherwise + */ +#if defined(CONFIG_SOCKS) +static inline bool net_context_is_proxy_enabled(struct net_context *context) +{ + return context->proxy_enabled; +} +#else static inline bool net_context_is_proxy_enabled(struct net_context *context) { return false; @@ -1091,17 +1247,22 @@ int net_context_update_recv_wnd(struct net_context *context, int32_t delta); enum net_context_option { - NET_OPT_PRIORITY = 1, - NET_OPT_TXTIME = 2, - NET_OPT_SOCKS5 = 3, - NET_OPT_RCVTIMEO = 4, - NET_OPT_SNDTIMEO = 5, - NET_OPT_RCVBUF = 6, - NET_OPT_SNDBUF = 7, - NET_OPT_DSCP_ECN = 8, - NET_OPT_REUSEADDR = 9, - NET_OPT_REUSEPORT = 10, - NET_OPT_IPV6_V6ONLY = 11, + NET_OPT_PRIORITY = 1, + NET_OPT_TXTIME = 2, + NET_OPT_SOCKS5 = 3, + NET_OPT_RCVTIMEO = 4, + NET_OPT_SNDTIMEO = 5, + NET_OPT_RCVBUF = 6, + NET_OPT_SNDBUF = 7, + NET_OPT_DSCP_ECN = 8, + NET_OPT_REUSEADDR = 9, + NET_OPT_REUSEPORT = 10, + NET_OPT_IPV6_V6ONLY = 11, + NET_OPT_RECV_PKTINFO = 12, + NET_OPT_MCAST_TTL = 13, + NET_OPT_MCAST_HOP_LIMIT = 14, + NET_OPT_UNICAST_HOP_LIMIT = 15, + NET_OPT_TTL = 16, }; /** diff --git a/include/zephyr/net/net_event.h b/include/zephyr/net/net_event.h index 34856aec6af..b717c2eec45 100644 --- a/include/zephyr/net/net_event.h +++ b/include/zephyr/net/net_event.h @@ -13,6 +13,7 @@ #define ZEPHYR_INCLUDE_NET_NET_EVENT_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -38,7 +39,6 @@ enum net_event_if_cmd { NET_EVENT_IF_CMD_UP, NET_EVENT_IF_CMD_ADMIN_DOWN, NET_EVENT_IF_CMD_ADMIN_UP, - }; #define NET_EVENT_IF_DOWN \ @@ -53,7 +53,6 @@ enum net_event_if_cmd { #define NET_EVENT_IF_ADMIN_UP \ (_NET_EVENT_IF_BASE | NET_EVENT_IF_CMD_ADMIN_UP) - /* IPv6 Events */ #define _NET_IPV6_LAYER NET_MGMT_LAYER_L3 #define _NET_IPV6_CORE_CODE 0x060 @@ -210,6 +209,7 @@ enum net_event_l4_cmd { NET_EVENT_L4_CMD_DISCONNECTED, NET_EVENT_L4_CMD_DNS_SERVER_ADD, NET_EVENT_L4_CMD_DNS_SERVER_DEL, + NET_EVENT_L4_CMD_HOSTNAME_CHANGED, }; #define NET_EVENT_L4_CONNECTED \ @@ -224,6 +224,9 @@ enum net_event_l4_cmd { #define NET_EVENT_DNS_SERVER_DEL \ (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DNS_SERVER_DEL) +#define NET_EVENT_HOSTNAME_CHANGED \ + (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_HOSTNAME_CHANGED) + /** @endcond */ /** @@ -282,6 +285,16 @@ struct net_event_ipv6_prefix { uint32_t lifetime; }; +/** + * @brief Network Management event information structure + * Used to pass information on NET_EVENT_HOSTNAME_CHANGED event when + * CONFIG_NET_MGMT_EVENT_INFO is enabled and event generator pass the + * information. + */ +struct net_event_l4_hostname { + char hostname[NET_HOSTNAME_SIZE]; +}; + #ifdef __cplusplus } #endif diff --git a/include/zephyr/net/net_if.h b/include/zephyr/net/net_if.h index f1e5be67cf7..d849451d0c2 100644 --- a/include/zephyr/net/net_if.h +++ b/include/zephyr/net/net_if.h @@ -94,6 +94,17 @@ struct net_if_mcast_addr { /** IP address */ struct net_addr address; +#if defined(CONFIG_NET_IPV4_IGMPV3) + /** Sources to filter on */ + struct net_addr sources[CONFIG_NET_IF_MCAST_IPV4_SOURCE_COUNT]; + + /** Number of sources to be used by the filter */ + uint16_t sources_len; + + /** Filter mode (used in IGMPV3) */ + uint8_t record_type; +#endif + /** Is this multicast IP address used or not */ uint8_t is_used : 1; @@ -279,6 +290,9 @@ struct net_if_ipv6 { /** IPv6 hop limit */ uint8_t hop_limit; + + /** IPv6 multicast hop limit */ + uint8_t mcast_hop_limit; }; #if defined(CONFIG_NET_DHCPV6) && defined(CONFIG_NET_NATIVE_IPV6) @@ -369,6 +383,9 @@ struct net_if_ipv4 { /** IPv4 time-to-live */ uint8_t ttl; + + /** IPv4 time-to-live for multicast packets */ + uint8_t mcast_ttl; }; #if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4) @@ -1383,13 +1400,12 @@ struct net_if_mcast_addr *net_if_ipv6_maddr_lookup(const struct in6_addr *addr, /** * @typedef net_if_mcast_callback_t - * @brief Define callback that is called whenever IPv6 multicast address group - * is joined or left. - + * @brief Define a callback that is called whenever a IPv6 or IPv4 multicast + * address group is joined or left. * @param iface A pointer to a struct net_if to which the multicast address is * attached. * @param addr IP multicast address. - * @param is_joined True if the address is joined, false if left. + * @param is_joined True if the multicast group is joined, false if group is left. */ typedef void (*net_if_mcast_callback_t)(struct net_if *iface, const struct net_addr *addr, @@ -1438,7 +1454,7 @@ void net_if_mcast_mon_unregister(struct net_if_mcast_monitor *mon); * * @param iface Network interface * @param addr Multicast address - * @param is_joined Is this multicast address joined (true) or not (false) + * @param is_joined Is this multicast address group joined (true) or not (false) */ void net_if_mcast_monitor(struct net_if *iface, const struct net_addr *addr, bool is_joined); @@ -1661,7 +1677,36 @@ uint8_t net_if_ipv6_get_hop_limit(struct net_if *iface); * @param iface Network interface * @param hop_limit New hop limit */ -void net_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); +void net_if_ipv6_set_hop_limit(struct net_if *iface, uint8_t hop_limit); + +/* The old hop limit setter function is deprecated because the naming + * of it was incorrect. The API name was missing "_if_" so this function + * should not be used. + */ +__deprecated +static inline void net_ipv6_set_hop_limit(struct net_if *iface, + uint8_t hop_limit) +{ + net_if_ipv6_set_hop_limit(iface, hop_limit); +} + +/** + * @brief Get IPv6 multicast hop limit specified for a given interface. This is the + * default value but can be overridden by the user. + * + * @param iface Network interface + * + * @return Hop limit + */ +uint8_t net_if_ipv6_get_mcast_hop_limit(struct net_if *iface); + +/** + * @brief Set the default IPv6 multicast hop limit of a given interface. + * + * @param iface Network interface + * @param hop_limit New hop limit + */ +void net_if_ipv6_set_mcast_hop_limit(struct net_if *iface, uint8_t hop_limit); /** * @brief Set IPv6 reachable time for a given interface @@ -1905,6 +1950,23 @@ uint8_t net_if_ipv4_get_ttl(struct net_if *iface); */ void net_if_ipv4_set_ttl(struct net_if *iface, uint8_t ttl); +/** + * @brief Get IPv4 multicast time-to-live value specified for a given interface + * + * @param iface Network interface + * + * @return Time-to-live + */ +uint8_t net_if_ipv4_get_mcast_ttl(struct net_if *iface); + +/** + * @brief Set IPv4 multicast time-to-live value specified to a given interface + * + * @param iface Network interface + * @param ttl Time-to-live value + */ +void net_if_ipv4_set_mcast_ttl(struct net_if *iface, uint8_t ttl); + /** * @brief Check if this IPv4 address belongs to one of the interfaces. * @@ -2746,22 +2808,21 @@ struct net_if_api { void (*init)(struct net_if *iface); }; -#if defined(CONFIG_NET_IP) -#define NET_IF_IP_INIT .ip = {}, -#else -#define NET_IF_IP_INIT -#endif +#define NET_IF_DHCPV4_INIT \ + IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_NET_DHCPV4), \ + IS_ENABLED(CONFIG_NET_NATIVE_IPV4)), \ + (.dhcpv4.state = NET_DHCPV4_DISABLED,)) -#if defined(CONFIG_NET_DHCPV4) && defined(CONFIG_NET_NATIVE_IPV4) -#define NET_IF_DHCPV4_INIT .dhcpv4.state = NET_DHCPV4_DISABLED, -#else -#define NET_IF_DHCPV4_INIT -#endif +#define NET_IF_DHCPV6_INIT \ + IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_NET_DHCPV6), \ + IS_ENABLED(CONFIG_NET_NATIVE_IPV6)), \ + (.dhcpv6.state = NET_DHCPV6_DISABLED,)) #define NET_IF_CONFIG_INIT \ .config = { \ - NET_IF_IP_INIT \ + IF_ENABLED(CONFIG_NET_IP, (.ip = {},)) \ NET_IF_DHCPV4_INIT \ + NET_IF_DHCPV6_INIT \ } #define NET_IF_GET_NAME(dev_id, sfx) __net_if_##dev_id##_##sfx diff --git a/include/zephyr/net/net_ip.h b/include/zephyr/net/net_ip.h index b392184a815..75f75aa1f42 100644 --- a/include/zephyr/net/net_ip.h +++ b/include/zephyr/net/net_ip.h @@ -841,6 +841,19 @@ static inline bool net_ipv6_is_ll_addr(const struct in6_addr *addr) return UNALIGNED_GET(&addr->s6_addr16[0]) == htons(0xFE80); } +/** + * @brief Check if the given IPv6 address is a site local address. + * + * @param addr A valid pointer on an IPv6 address + * + * @return True if it is, false otherwise. + */ +static inline bool net_ipv6_is_sl_addr(const struct in6_addr *addr) +{ + return UNALIGNED_GET(&addr->s6_addr16[0]) == htons(0xFEC0); +} + + /** * @brief Check if the given IPv6 address is a unique local address. * @@ -853,6 +866,18 @@ static inline bool net_ipv6_is_ula_addr(const struct in6_addr *addr) return addr->s6_addr[0] == 0xFD; } +/** + * @brief Check if the given IPv6 address is a global address. + * + * @param addr A valid pointer on an IPv6 address + * + * @return True if it is, false otherwise. + */ +static inline bool net_ipv6_is_global_addr(const struct in6_addr *addr) +{ + return (addr->s6_addr[0] & 0xE0) == 0x20; +} + /** * @brief Return pointer to any (all bits zeros) IPv6 address. * diff --git a/include/zephyr/net/net_mgmt.h b/include/zephyr/net/net_mgmt.h index 8d8710edd26..f90bc8e1836 100644 --- a/include/zephyr/net/net_mgmt.h +++ b/include/zephyr/net/net_mgmt.h @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -107,7 +108,7 @@ struct net_mgmt_event_callback; * @brief Define the user's callback handler function signature * @param cb Original struct net_mgmt_event_callback owning this handler. * @param mgmt_event The network event being notified. - * @param iface A pointer on a struct net_if to which the the event belongs to, + * @param iface A pointer on a struct net_if to which the event belongs to, * if it's an event on an iface. NULL otherwise. */ typedef void (*net_mgmt_event_handler_t)(struct net_mgmt_event_callback *cb, @@ -163,6 +164,53 @@ struct net_mgmt_event_callback { }; }; +/** + * @typedef net_mgmt_event_static_handler_t + * @brief Define the user's callback handler function signature + * @param mgmt_event The network event being notified. + * @param iface A pointer on a struct net_if to which the event belongs to, + * if it's an event on an iface. NULL otherwise. + * @param info A valid pointer on a data understood by the handler. + * NULL otherwise. + * @param info_length Length in bytes of the memory pointed by @p info. + * @param user_data Data provided by the user to the handler. + */ +typedef void (*net_mgmt_event_static_handler_t)(uint32_t mgmt_event, + struct net_if *iface, + void *info, size_t info_length, + void *user_data); + +/** @cond INTERNAL_HIDDEN */ + +/* Structure for event handler registered at compile time */ +struct net_mgmt_event_static_handler { + uint32_t event_mask; + net_mgmt_event_static_handler_t handler; + void *user_data; +}; + +/** @endcond */ + +/** + * @brief Define a static network event handler. + * @param _name Name of the event handler. + * @param _event_mask A mask of network events on which the passed handler should + * be called in case those events come. + * Note that only the command part is treated as a mask, + * matching one to several commands. Layer and layer code will + * be made of an exact match. This means that in order to + * receive events from multiple layers, one must have multiple + * listeners registered, one for each layer being listened. + * @param _func The function to be called upon network events being emitted. + * @param _user_data User data passed to the handler being called on network events. + */ +#define NET_MGMT_REGISTER_EVENT_HANDLER(_name, _event_mask, _func, _user_data) \ + const STRUCT_SECTION_ITERABLE(net_mgmt_event_static_handler, _name) = { \ + .event_mask = _event_mask, \ + .handler = _func, \ + .user_data = (void *)_user_data, \ + } + /** * @brief Helper to initialize a struct net_mgmt_event_callback properly * @param cb A valid application's callback structure pointer. diff --git a/include/zephyr/net/net_pkt.h b/include/zephyr/net/net_pkt.h index c5878213a02..c3ef9418085 100644 --- a/include/zephyr/net/net_pkt.h +++ b/include/zephyr/net/net_pkt.h @@ -290,6 +290,13 @@ struct net_pkt { */ uint8_t priority; +#if defined(CONFIG_NET_OFFLOAD) + /* Remote address of the recived packet. This is only used by + * network interfaces with an offloaded TCP/IP stack. + */ + struct sockaddr remote; +#endif /* CONFIG_NET_OFFLOAD */ + /* @endcond */ }; diff --git a/include/zephyr/net/phy.h b/include/zephyr/net/phy.h index 40de7137276..38c6d1f5bbe 100644 --- a/include/zephyr/net/phy.h +++ b/include/zephyr/net/phy.h @@ -110,11 +110,8 @@ __subsystem struct ethphy_driver_api { * @retval -EIO If communication with PHY failed. * @retval -ENOTSUP If not supported. */ -__syscall int phy_configure_link(const struct device *dev, - enum phy_link_speed speeds); - -static inline int z_impl_phy_configure_link(const struct device *dev, - enum phy_link_speed speeds) +static inline int phy_configure_link(const struct device *dev, + enum phy_link_speed speeds) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -135,11 +132,8 @@ static inline int z_impl_phy_configure_link(const struct device *dev, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_get_link_state(const struct device *dev, - struct phy_link_state *state); - -static inline int z_impl_phy_get_link_state(const struct device *dev, - struct phy_link_state *state) +static inline int phy_get_link_state(const struct device *dev, + struct phy_link_state *state) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -161,13 +155,9 @@ static inline int z_impl_phy_get_link_state(const struct device *dev, * @retval 0 If successful. * @retval -ENOTSUP If not supported. */ -__syscall int phy_link_callback_set(const struct device *dev, - phy_callback_t callback, - void *user_data); - -static inline int z_impl_phy_link_callback_set(const struct device *dev, - phy_callback_t callback, - void *user_data) +static inline int phy_link_callback_set(const struct device *dev, + phy_callback_t callback, + void *user_data) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -187,11 +177,8 @@ static inline int z_impl_phy_link_callback_set(const struct device *dev, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_read(const struct device *dev, uint16_t reg_addr, - uint32_t *value); - -static inline int z_impl_phy_read(const struct device *dev, uint16_t reg_addr, - uint32_t *value) +static inline int phy_read(const struct device *dev, uint16_t reg_addr, + uint32_t *value) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -211,11 +198,8 @@ static inline int z_impl_phy_read(const struct device *dev, uint16_t reg_addr, * @retval 0 If successful. * @retval -EIO If communication with PHY failed. */ -__syscall int phy_write(const struct device *dev, uint16_t reg_addr, - uint32_t value); - -static inline int z_impl_phy_write(const struct device *dev, uint16_t reg_addr, - uint32_t value) +static inline int phy_write(const struct device *dev, uint16_t reg_addr, + uint32_t value) { const struct ethphy_driver_api *api = (const struct ethphy_driver_api *)dev->api; @@ -232,6 +216,4 @@ static inline int z_impl_phy_write(const struct device *dev, uint16_t reg_addr, * @} */ -#include - #endif /* ZEPHYR_INCLUDE_DRIVERS_PHY_H_ */ diff --git a/include/zephyr/net/ppp.h b/include/zephyr/net/ppp.h index a72d4f1feac..36c6bf64eeb 100644 --- a/include/zephyr/net/ppp.h +++ b/include/zephyr/net/ppp.h @@ -474,6 +474,12 @@ struct ppp_context { /** Current phase of PPP link */ enum ppp_phase phase; + /** Signal when PPP link is terminated */ + struct k_sem wait_ppp_link_terminated; + + /** Signal when PPP link is down */ + struct k_sem wait_ppp_link_down; + /** This tells what features the PPP supports. */ enum net_l2_flags ppp_l2_flags; diff --git a/include/zephyr/net/sntp.h b/include/zephyr/net/sntp.h index cb83675a3cd..c03c3a11206 100644 --- a/include/zephyr/net/sntp.h +++ b/include/zephyr/net/sntp.h @@ -21,6 +21,16 @@ extern "C" { * @{ */ +/** Time as returned by SNTP API, fractional seconds since 1 Jan 1970 */ +struct sntp_time { + uint64_t seconds; + uint32_t fraction; +#if defined(CONFIG_SNTP_UNCERTAINTY) + uint64_t uptime_us; + uint32_t uncertainty_us; +#endif +}; + /** SNTP context */ struct sntp_ctx { struct { @@ -33,13 +43,7 @@ struct sntp_ctx { * This is used to check if the originated timestamp in the server * reply matches the one in client request. */ - uint32_t expected_orig_ts; -}; - -/** Time as returned by SNTP API, fractional seconds since 1 Jan 1970 */ -struct sntp_time { - uint64_t seconds; - uint32_t fraction; + struct sntp_time expected_orig_ts; }; /** diff --git a/include/zephyr/net/socket.h b/include/zephyr/net/socket.h index f32753a7952..56bbc037bde 100644 --- a/include/zephyr/net/socket.h +++ b/include/zephyr/net/socket.h @@ -36,16 +36,25 @@ extern "C" { #endif +/** + * @brief Definition of the monitored socket/file descriptor. + * + * An array of these descriptors is passed as an argument to poll(). + */ struct zsock_pollfd { - int fd; - short events; - short revents; + int fd; /**< Socket descriptor */ + short events; /**< Requested events */ + short revents; /**< Returned events */ }; +/** + * @name Options for poll() + * @{ + */ /* ZSOCK_POLL* values are compatible with Linux */ /** zsock_poll: Poll for readability */ #define ZSOCK_POLLIN 1 -/** zsock_poll: Compatibility value, ignored */ +/** zsock_poll: Poll for exceptional condition */ #define ZSOCK_POLLPRI 2 /** zsock_poll: Poll for writability */ #define ZSOCK_POLLOUT 4 @@ -55,9 +64,17 @@ struct zsock_pollfd { #define ZSOCK_POLLHUP 0x10 /** zsock_poll: Invalid socket (output value only) */ #define ZSOCK_POLLNVAL 0x20 +/** @} */ +/** + * @name Options for sending and receiving data + * @{ + */ /** zsock_recv: Read data without removing it from socket input queue */ #define ZSOCK_MSG_PEEK 0x02 +/** zsock_recvmsg: Control data buffer too small. + */ +#define ZSOCK_MSG_CTRUNC 0x08 /** zsock_recv: return the real length of the datagram, even when it was longer * than the passed buffer */ @@ -66,7 +83,12 @@ struct zsock_pollfd { #define ZSOCK_MSG_DONTWAIT 0x40 /** zsock_recv: block until the full amount of data can be returned */ #define ZSOCK_MSG_WAITALL 0x100 +/** @} */ +/** + * @name Options for shutdown() function + * @{ + */ /* Well-known values, e.g. from Linux man 2 shutdown: * "The constants SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, * respectively". Some software uses numeric values. @@ -77,16 +99,21 @@ struct zsock_pollfd { #define ZSOCK_SHUT_WR 1 /** zsock_shutdown: Shut down for both reading and writing */ #define ZSOCK_SHUT_RDWR 2 - -/** Protocol level for TLS. - * Here, the same socket protocol level for TLS as in Linux was used. - */ -#define SOL_TLS 282 +/** @} */ /** * @defgroup secure_sockets_options Socket options for TLS * @{ */ +/** + * @name Socket options for TLS + * @{ + */ + +/** Protocol level for TLS. + * Here, the same socket protocol level for TLS as in Linux was used. + */ +#define SOL_TLS 282 /** Socket option to select TLS credentials to use. It accepts and returns an * array of sec_tag_t that indicate which TLS credentials should be used with @@ -135,11 +162,16 @@ struct zsock_pollfd { * the TLS handshake. */ #define TLS_ALPN_LIST 7 -/** Socket option to set DTLS handshake timeout. The timeout starts at min, +/** Socket option to set DTLS min handshake timeout. The timeout starts at min, * and upon retransmission the timeout is doubled util max is reached. * Min and max arguments are separate options. The time unit is ms. */ #define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8 + +/** Socket option to set DTLS max handshake timeout. The timeout starts at min, + * and upon retransmission the timeout is doubled util max is reached. + * Min and max arguments are separate options. The time unit is ms. + */ #define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9 /** Socket option for preventing certificates from being copied to the mbedTLS @@ -201,48 +233,65 @@ struct zsock_pollfd { * connection ID, otherwise will contain the length of the CID value. */ #define TLS_DTLS_PEER_CID_VALUE 17 -/** @} */ +/** Socket option to configure DTLS socket behavior on connect(). + * If set, DTLS connect() will execute the handshake with the configured peer. + * This is the default behavior. + * Otherwise, DTLS connect() will only configure peer address (as with regular + * UDP socket) and will not attempt to execute DTLS handshake. The handshake + * will take place in consecutive send()/recv() call. + */ +#define TLS_DTLS_HANDSHAKE_ON_CONNECT 18 -/* Valid values for TLS_PEER_VERIFY option */ +/* Valid values for @ref TLS_PEER_VERIFY option */ #define TLS_PEER_VERIFY_NONE 0 /**< Peer verification disabled. */ #define TLS_PEER_VERIFY_OPTIONAL 1 /**< Peer verification optional. */ #define TLS_PEER_VERIFY_REQUIRED 2 /**< Peer verification required. */ -/* Valid values for TLS_DTLS_ROLE option */ +/* Valid values for @ref TLS_DTLS_ROLE option */ #define TLS_DTLS_ROLE_CLIENT 0 /**< Client role in a DTLS session. */ #define TLS_DTLS_ROLE_SERVER 1 /**< Server role in a DTLS session. */ -/* Valid values for TLS_CERT_NOCOPY option */ +/* Valid values for @ref TLS_CERT_NOCOPY option */ #define TLS_CERT_NOCOPY_NONE 0 /**< Cert duplicated in heap */ #define TLS_CERT_NOCOPY_OPTIONAL 1 /**< Cert not copied in heap if DER */ -/* Valid values for TLS_SESSION_CACHE option */ +/* Valid values for @ref TLS_SESSION_CACHE option */ #define TLS_SESSION_CACHE_DISABLED 0 /**< Disable TLS session caching. */ #define TLS_SESSION_CACHE_ENABLED 1 /**< Enable TLS session caching. */ -/* Valid values for TLS_DTLS_CID option */ -#define TLS_DTLS_CID_DISABLED 0 -#define TLS_DTLS_CID_SUPPORTED 1 -#define TLS_DTLS_CID_ENABLED 2 +/* Valid values for @ref TLS_DTLS_CID (Connection ID) option */ +#define TLS_DTLS_CID_DISABLED 0 /**< CID is disabled */ +#define TLS_DTLS_CID_SUPPORTED 1 /**< CID is supported */ +#define TLS_DTLS_CID_ENABLED 2 /**< CID is enabled */ -/* Valid values for TLS_DTLS_CID_STATUS option */ -#define TLS_DTLS_CID_STATUS_DISABLED 0 -#define TLS_DTLS_CID_STATUS_DOWNLINK 1 -#define TLS_DTLS_CID_STATUS_UPLINK 2 -#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3 +/* Valid values for @ref TLS_DTLS_CID_STATUS option */ +#define TLS_DTLS_CID_STATUS_DISABLED 0 /**< CID is disabled */ +#define TLS_DTLS_CID_STATUS_DOWNLINK 1 /**< CID is in use by us */ +#define TLS_DTLS_CID_STATUS_UPLINK 2 /**< CID is in use by peer */ +#define TLS_DTLS_CID_STATUS_BIDIRECTIONAL 3 /**< CID is in use by us and peer */ +/** @} */ /* for @name */ +/** @} */ /* for @defgroup */ +/** + * @brief Definition used when querying address information. + * + * A linked list of these descriptors is returned by getaddrinfo(). The struct + * is also passed as hints when calling the getaddrinfo() function. + */ struct zsock_addrinfo { - struct zsock_addrinfo *ai_next; - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; + struct zsock_addrinfo *ai_next; /**< Pointer to next address entry */ + int ai_flags; /**< Additional options */ + int ai_family; /**< Address family of the returned addresses */ + int ai_socktype; /**< Socket type, for example SOCK_STREAM or SOCK_DGRAM */ + int ai_protocol; /**< Protocol for addresses, 0 means any protocol */ + socklen_t ai_addrlen; /**< Length of the socket address */ + struct sockaddr *ai_addr; /**< Pointer to the address */ + char *ai_canonname; /**< Optional official name of the host */ +/** @cond INTERNAL_HIDDEN */ struct sockaddr _ai_addr; char _ai_canonname[DNS_MAX_NAME_SIZE + 1]; +/** @endcond */ }; /** @@ -467,6 +516,20 @@ __syscall ssize_t zsock_recvfrom(int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +/** + * @brief Receive a message from an arbitrary network address + * + * @details + * @rst + * See `POSIX.1-2017 article + * `__ + * for normative description. + * This function is also exposed as ``recvmsg()`` + * if :kconfig:option:`CONFIG_NET_SOCKETS_POSIX_NAMES` is defined. + * @endrst + */ +__syscall ssize_t zsock_recvmsg(int sock, struct msghdr *msg, int flags); + /** * @brief Receive data from a connected peer * @@ -654,6 +717,10 @@ __syscall int z_zsock_getaddrinfo_internal(const char *host, /* Flags for getaddrinfo() hints. */ +/** + * @name Flags for getaddrinfo() hints + * @{ + */ /** Address for bind() (vs for connect()) */ #define AI_PASSIVE 0x1 /** Fill in ai_canonname */ @@ -668,6 +735,7 @@ __syscall int z_zsock_getaddrinfo_internal(const char *host, #define AI_ADDRCONFIG 0x20 /** Assume service (port) is numeric */ #define AI_NUMERICSERV 0x400 +/** @} */ /** * @brief Resolve a domain name to one or more network addresses @@ -713,6 +781,10 @@ void zsock_freeaddrinfo(struct zsock_addrinfo *ai); */ const char *zsock_gai_strerror(int errcode); +/** + * @name Flags for getnameinfo() + * @{ + */ /** zsock_getnameinfo(): Resolve to numeric address. */ #define NI_NUMERICHOST 1 /** zsock_getnameinfo(): Resolve to numeric port number. */ @@ -730,6 +802,7 @@ const char *zsock_gai_strerror(int errcode); #ifndef NI_MAXHOST #define NI_MAXHOST 64 #endif +/** @} */ /** * @brief Resolve a network address to a domain name or ASCII address @@ -749,6 +822,12 @@ int zsock_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, #if defined(CONFIG_NET_SOCKETS_POSIX_NAMES) +/** + * @name Socket APIs available if CONFIG_NET_SOCKETS_POSIX_NAMES is enabled + * @{ + */ + +/** POSIX wrapper for @ref zsock_pollfd */ #define pollfd zsock_pollfd /** POSIX wrapper for @ref zsock_socket */ @@ -812,6 +891,7 @@ static inline ssize_t recv(int sock, void *buf, size_t max_len, int flags) return zsock_recv(sock, buf, max_len, flags); } +/** @cond INTERNAL_HIDDEN */ /* * Need this wrapper because newer GCC versions got too smart and "typecheck" * even macros, so '#define fcntl zsock_fcntl' leads to error. @@ -828,7 +908,9 @@ static inline int zsock_fcntl_wrapper(int sock, int cmd, ...) } #define fcntl zsock_fcntl_wrapper +/** @endcond */ +/** POSIX wrapper for @ref zsock_ioctl */ static inline int ioctl(int sock, unsigned long request, ...) { int ret; @@ -863,6 +945,12 @@ static inline ssize_t recvfrom(int sock, void *buf, size_t max_len, int flags, return zsock_recvfrom(sock, buf, max_len, flags, src_addr, addrlen); } +/** POSIX wrapper for @ref zsock_recvmsg */ +static inline ssize_t recvmsg(int sock, struct msghdr *msg, int flags) +{ + return zsock_recvmsg(sock, msg, flags); +} + /** POSIX wrapper for @ref zsock_poll */ static inline int poll(struct zsock_pollfd *fds, int nfds, int timeout) { @@ -926,6 +1014,7 @@ static inline int getnameinfo(const struct sockaddr *addr, socklen_t addrlen, serv, servlen, flags); } +/** POSIX wrapper for @ref zsock_addrinfo */ #define addrinfo zsock_addrinfo /** POSIX wrapper for @ref zsock_gethostname */ @@ -960,6 +1049,8 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, /** POSIX wrapper for @ref ZSOCK_MSG_PEEK */ #define MSG_PEEK ZSOCK_MSG_PEEK +/** POSIX wrapper for @ref ZSOCK_MSG_CTRUNC */ +#define MSG_CTRUNC ZSOCK_MSG_CTRUNC /** POSIX wrapper for @ref ZSOCK_MSG_TRUNC */ #define MSG_TRUNC ZSOCK_MSG_TRUNC /** POSIX wrapper for @ref ZSOCK_MSG_DONTWAIT */ @@ -994,8 +1085,14 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, #define EAI_SOCKTYPE DNS_EAI_SOCKTYPE /** POSIX wrapper for @ref DNS_EAI_FAMILY */ #define EAI_FAMILY DNS_EAI_FAMILY +/** @} */ #endif /* defined(CONFIG_NET_SOCKETS_POSIX_NAMES) */ +/** + * @name Network interface name description + * @{ + */ +/** Network interface name length */ #if defined(CONFIG_NET_INTERFACE_NAME) #define IFNAMSIZ CONFIG_NET_INTERFACE_NAME_LEN #else @@ -1004,98 +1101,207 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst, /** Interface description structure */ struct ifreq { - char ifr_name[IFNAMSIZ]; /* Interface name */ + char ifr_name[IFNAMSIZ]; /**< Network interface name */ }; +/** @} */ -/** sockopt: Socket-level option */ +/** + * @name Socket level options (SOL_SOCKET) + * @{ + */ +/** Socket-level option */ #define SOL_SOCKET 1 /* Socket options for SOL_SOCKET level */ -/** sockopt: Recording debugging information (ignored, for compatibility) */ +/** Recording debugging information (ignored, for compatibility) */ #define SO_DEBUG 1 -/** sockopt: address reuse */ +/** address reuse */ #define SO_REUSEADDR 2 -/** sockopt: Type of the socket */ +/** Type of the socket */ #define SO_TYPE 3 -/** sockopt: Async error (ignored, for compatibility) */ +/** Async error */ #define SO_ERROR 4 -/** sockopt: Bypass normal routing and send directly to host (ignored, for compatibility) */ +/** Bypass normal routing and send directly to host (ignored, for compatibility) */ #define SO_DONTROUTE 5 -/** sockopt: Transmission of broadcast messages is supported (ignored, for compatibility) */ +/** Transmission of broadcast messages is supported (ignored, for compatibility) */ #define SO_BROADCAST 6 -/** sockopt: Size of socket send buffer */ +/** Size of socket send buffer */ #define SO_SNDBUF 7 -/** sockopt: Size of socket recv buffer */ +/** Size of socket recv buffer */ #define SO_RCVBUF 8 -/** sockopt: Enable sending keep-alive messages on connections (ignored, for compatibility) */ +/** Enable sending keep-alive messages on connections */ #define SO_KEEPALIVE 9 -/** sockopt: Place out-of-band data into receive stream (ignored, for compatibility) */ +/** Place out-of-band data into receive stream (ignored, for compatibility) */ #define SO_OOBINLINE 10 -/** sockopt: Socket lingers on close (ignored, for compatibility) */ +/** Socket priority */ +#define SO_PRIORITY 12 +/** Socket lingers on close (ignored, for compatibility) */ #define SO_LINGER 13 -/** sockopt: Allow multiple sockets to reuse a single port */ +/** Allow multiple sockets to reuse a single port */ #define SO_REUSEPORT 15 -/** sockopt: Receive low watermark (ignored, for compatibility) */ +/** Receive low watermark (ignored, for compatibility) */ #define SO_RCVLOWAT 18 -/** sockopt: Send low watermark (ignored, for compatibility) */ +/** Send low watermark (ignored, for compatibility) */ #define SO_SNDLOWAT 19 /** - * sockopt: Receive timeout + * Receive timeout * Applies to receive functions like recv(), but not to connect() */ #define SO_RCVTIMEO 20 -/** sockopt: Send timeout */ +/** Send timeout */ #define SO_SNDTIMEO 21 -/** sockopt: Bind a socket to an interface */ +/** Bind a socket to an interface */ #define SO_BINDTODEVICE 25 -/** sockopt: Socket accepts incoming connections (ignored, for compatibility) */ +/** Socket accepts incoming connections (ignored, for compatibility) */ #define SO_ACCEPTCONN 30 -/** sockopt: Timestamp TX packets */ +/** Timestamp TX packets */ #define SO_TIMESTAMPING 37 -/** sockopt: Protocol used with the socket */ +/** Protocol used with the socket */ #define SO_PROTOCOL 38 -/** sockopt: Domain used with SOCKET (ignored, for compatibility) */ +/** Domain used with SOCKET */ #define SO_DOMAIN 39 -/** End Socket options for SOL_SOCKET level */ +/** Enable SOCKS5 for Socket */ +#define SO_SOCKS5 60 + +/** Socket TX time (when the data should be sent) */ +#define SO_TXTIME 61 +/** Socket TX time (same as SO_TXTIME) */ +#define SCM_TXTIME SO_TXTIME +/** @} */ + +/** + * @name TCP level options (IPPROTO_TCP) + * @{ + */ /* Socket options for IPPROTO_TCP level */ -/** sockopt: Disable TCP buffering (ignored, for compatibility) */ +/** Disable TCP buffering (ignored, for compatibility) */ #define TCP_NODELAY 1 +/** Start keepalives after this period (seconds) */ +#define TCP_KEEPIDLE 2 +/** Interval between keepalives (seconds) */ +#define TCP_KEEPINTVL 3 +/** Number of keepalives before dropping connection */ +#define TCP_KEEPCNT 4 + +/** @} */ +/** + * @name IPv4 level options (IPPROTO_IP) + * @{ + */ /* Socket options for IPPROTO_IP level */ -/** sockopt: Set or receive the Type-Of-Service value for an outgoing packet. */ +/** Set or receive the Type-Of-Service value for an outgoing packet. */ #define IP_TOS 1 +/** Set or receive the Time-To-Live value for an outgoing packet. */ +#define IP_TTL 2 + +/** Pass an IP_PKTINFO ancillary message that contains a + * pktinfo structure that supplies some information about the + * incoming packet. + */ +#define IP_PKTINFO 8 + +/** + * @brief Incoming IPv4 packet information. + * + * Used as ancillary data when calling recvmsg() and IP_PKTINFO socket + * option is set. + */ +struct in_pktinfo { + unsigned int ipi_ifindex; /**< Network interface index */ + struct in_addr ipi_spec_dst; /**< Local address */ + struct in_addr ipi_addr; /**< Header Destination address */ +}; + +/** Set IPv4 multicast TTL value. */ +#define IP_MULTICAST_TTL 33 +/** Join IPv4 multicast group. */ +#define IP_ADD_MEMBERSHIP 35 +/** Leave IPv4 multicast group. */ +#define IP_DROP_MEMBERSHIP 36 + +/** + * @brief Struct used when joining or leaving a IPv4 multicast group. + */ +struct ip_mreqn { + struct in_addr imr_multiaddr; /**< IP multicast group address */ + struct in_addr imr_address; /**< IP address of local interface */ + int imr_ifindex; /**< Network interface index */ +}; + +/** @} */ + +/** + * @name IPv6 level options (IPPROTO_IPV6) + * @{ + */ /* Socket options for IPPROTO_IPV6 level */ -/** sockopt: Don't support IPv4 access (ignored, for compatibility) */ -#define IPV6_V6ONLY 26 +/** Set the unicast hop limit for the socket. */ +#define IPV6_UNICAST_HOPS 16 -/** sockopt: Set or receive the traffic class value for an outgoing packet. */ -#define IPV6_TCLASS 67 +/** Set the multicast hop limit for the socket. */ +#define IPV6_MULTICAST_HOPS 18 -/** sockopt: Socket priority */ -#define SO_PRIORITY 12 +/** Join IPv6 multicast group. */ +#define IPV6_ADD_MEMBERSHIP 20 -/** sockopt: Socket TX time (when the data should be sent) */ -#define SO_TXTIME 61 -#define SCM_TXTIME SO_TXTIME +/** Leave IPv6 multicast group. */ +#define IPV6_DROP_MEMBERSHIP 21 -/* Socket options for SOCKS5 proxy */ -/** sockopt: Enable SOCKS5 for Socket */ -#define SO_SOCKS5 60 +/** + * @brief Struct used when joining or leaving a IPv6 multicast group. + */ +struct ipv6_mreq { + /** IPv6 multicast address of group */ + struct in6_addr ipv6mr_multiaddr; + + /** Network interface index of the local IPv6 address */ + int ipv6mr_ifindex; +}; -/** listen: The maximum backlog queue length (ignored, for compatibility) */ +/** Don't support IPv4 access */ +#define IPV6_V6ONLY 26 + +/** Pass an IPV6_RECVPKTINFO ancillary message that contains a + * in6_pktinfo structure that supplies some information about the + * incoming packet. See RFC 3542. + */ +#define IPV6_RECVPKTINFO 49 + +/** + * @brief Incoming IPv6 packet information. + * + * Used as ancillary data when calling recvmsg() and IPV6_RECVPKTINFO socket + * option is set. + */ +struct in6_pktinfo { + struct in6_addr ipi6_addr; /**< Destination IPv6 address */ + unsigned int ipi6_ifindex; /**< Receive interface index */ +}; + +/** Set or receive the traffic class value for an outgoing packet. */ +#define IPV6_TCLASS 67 +/** @} */ + +/** + * @name Backlog size for listen() + * @{ + */ +/** listen: The maximum backlog queue length */ #define SOMAXCONN 128 +/** @} */ /** @cond INTERNAL_HIDDEN */ /** diff --git a/include/zephyr/net/socketcan_utils.h b/include/zephyr/net/socketcan_utils.h index 22364cd328b..7db287ff847 100644 --- a/include/zephyr/net/socketcan_utils.h +++ b/include/zephyr/net/socketcan_utils.h @@ -95,15 +95,6 @@ static inline void socketcan_to_can_filter(const struct socketcan_filter *sfilte zfilter->flags |= (sfilter->can_id & BIT(31)) != 0 ? CAN_FILTER_IDE : 0; zfilter->id = sfilter->can_id & BIT_MASK(29); zfilter->mask = sfilter->can_mask & BIT_MASK(29); - zfilter->flags |= (sfilter->flags & CANFD_FDF) != 0 ? CAN_FILTER_FDF : 0; - - if ((sfilter->can_mask & BIT(30)) == 0) { - zfilter->flags |= CAN_FILTER_DATA | CAN_FILTER_RTR; - } else if ((sfilter->can_id & BIT(30)) == 0) { - zfilter->flags |= CAN_FILTER_DATA; - } else { - zfilter->flags |= CAN_FILTER_RTR; - } } /** @@ -119,19 +110,13 @@ static inline void socketcan_from_can_filter(const struct can_filter *zfilter, sfilter->can_id = zfilter->id; sfilter->can_id |= (zfilter->flags & CAN_FILTER_IDE) != 0 ? BIT(31) : 0; - sfilter->can_id |= (zfilter->flags & CAN_FILTER_RTR) != 0 ? BIT(30) : 0; sfilter->can_mask = zfilter->mask; sfilter->can_mask |= (zfilter->flags & CAN_FILTER_IDE) != 0 ? BIT(31) : 0; - if ((zfilter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) != - (CAN_FILTER_DATA | CAN_FILTER_RTR)) { + if (!IS_ENABLED(CONFIG_CAN_ACCEPT_RTR)) { sfilter->can_mask |= BIT(30); } - - if ((zfilter->flags & CAN_FILTER_FDF) != 0) { - sfilter->flags |= CANFD_FDF; - } } /** diff --git a/include/zephyr/net/wifi.h b/include/zephyr/net/wifi.h index c49d6ad0f66..0f19d7c4c18 100644 --- a/include/zephyr/net/wifi.h +++ b/include/zephyr/net/wifi.h @@ -12,7 +12,7 @@ /** * @defgroup wifi_mgmt Wi-Fi Management - * Wi-Fi Management API. + * @brief Wi-Fi Management API. * @ingroup networking * @{ */ diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index bd8cba81d28..e0930d2f106 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -83,6 +83,8 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_CHANNEL, /** Disconnect a STA from AP */ NET_REQUEST_WIFI_CMD_AP_STA_DISCONNECT, + /** Get Wi-Fi driver and Firmware versions */ + NET_REQUEST_WIFI_CMD_VERSION, NET_REQUEST_WIFI_CMD_MAX }; @@ -165,6 +167,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_CHANNEL); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_AP_STA_DISCONNECT); +#define NET_REQUEST_WIFI_VERSION \ + (_NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_VERSION) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_VERSION); + /** Wi-Fi management events */ enum net_event_wifi_cmd { /** Scan results available */ @@ -236,6 +243,14 @@ enum net_event_wifi_cmd { #define NET_EVENT_WIFI_AP_STA_DISCONNECTED \ (_NET_WIFI_EVENT | NET_EVENT_WIFI_CMD_AP_STA_DISCONNECTED) +/** Wi-Fi version */ +struct wifi_version { + /** Driver version */ + const char *drv_version; + /** Firmware version */ + const char *fw_version; +}; + /** * @brief Wi-Fi structure to uniquely identify a band-channel pair */ @@ -498,6 +513,12 @@ struct wifi_twt_params { bool announce; /** Wake up time */ uint32_t twt_wake_interval; + /* Wake ahead notification is sent earlier than + * TWT Service period (SP) start based on this duration. + * This should give applications ample time to + * prepare the data before TWT SP starts. + */ + uint32_t twt_wake_ahead_duration; } setup; /** Teardown specific parameters */ struct { @@ -514,6 +535,7 @@ struct wifi_twt_params { #define WIFI_MAX_TWT_INTERVAL_US (LONG_MAX - 1) /* 256 (u8) * 1TU */ #define WIFI_MAX_TWT_WAKE_INTERVAL_US 262144 +#define WIFI_MAX_TWT_WAKE_AHEAD_DURATION_US (LONG_MAX - 1) /** Wi-Fi TWT flow information */ struct wifi_twt_flow_info { @@ -535,6 +557,8 @@ struct wifi_twt_flow_info { bool announce; /** Wake up time */ uint32_t twt_wake_interval; + /* wake ahead duration */ + uint32_t twt_wake_ahead_duration; }; /** Wi-Fi power save configuration */ @@ -815,6 +839,19 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*channel)(const struct device *dev, struct wifi_channel_info *channel); + /** Get Version of WiFi driver and Firmware + * + * The driver that implements the get_version function must not use stack to allocate the + * version information pointers that are returned as params struct members. + * The version pointer parameters should point to a static memory either in ROM (preferred) + * or in RAM. + * + * @param dev Pointer to the device structure for the driver instance + * @param params Version parameters + * + * @return 0 if ok, < 0 if error + */ + int (*get_version)(const struct device *dev, struct wifi_version *params); }; /** Wi-Fi management offload API */ @@ -834,8 +871,19 @@ struct net_wifi_mgmt_offload { #endif /** Wi-Fi management API */ const struct wifi_mgmt_ops *const wifi_mgmt_api; + +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT) || defined(__DOXYGEN__) + /** Wi-Fi supplicant driver API */ + void *wifi_drv_ops; +#endif }; +#if defined(CONFIG_WIFI_NM_WPA_SUPPLICANT) +/* Make sure wifi_drv_ops is after wifi_mgmt_api */ +BUILD_ASSERT(offsetof(struct net_wifi_mgmt_offload, wifi_mgmt_api) < + offsetof(struct net_wifi_mgmt_offload, wifi_drv_ops)); +#endif + /* Make sure that the network interface API is properly setup inside * Wifi mgmt offload API struct (it is the first one). */ diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index cbfbf6f5f46..5b6cf0cb33c 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -50,10 +50,22 @@ enum pm_device_flag { PM_DEVICE_FLAG_PD, /** Indicates if device runtime PM should be automatically enabled */ PM_DEVICE_FLAG_RUNTIME_AUTO, + /** Indicates that device runtime PM supports suspending and resuming from any context. */ + PM_DEVICE_FLAG_ISR_SAFE, }; /** @endcond */ +/** @brief Flag indicating that runtime PM API for the device can be called from any context. + * + * If @ref PM_DEVICE_ISR_SAFE flag is used for device definition, it indicates that PM actions + * are synchronous and can be executed from any context. This approach can be used for cases where + * suspending and resuming is short as it is executed in the critical section. This mode requires + * less resources (~80 byte less RAM) and allows to use device runtime PM from any context + * (including interrupts). + */ +#define PM_DEVICE_ISR_SAFE 1 + /** @brief Device power states. */ enum pm_device_state { /** Device is in active or regular state. */ @@ -122,8 +134,37 @@ typedef bool (*pm_device_action_failed_cb_t)(const struct device *dev, /** * @brief Device PM info + * + * Structure holds fields which are common for two PM devices: generic and + * synchronous. + */ +struct pm_device_base { + /** Device PM status flags. */ + atomic_t flags; + /** Device power state */ + enum pm_device_state state; + /** Device PM action callback */ + pm_device_action_cb_t action_cb; +#if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) + /** Device usage count */ + uint32_t usage; +#endif /* CONFIG_PM_DEVICE_RUNTIME */ +#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN + /** Power Domain it belongs */ + const struct device *domain; +#endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ +}; + +/** + * @brief Runtime PM info for device with generic PM. + * + * Generic PM involves suspending and resuming operations which can be blocking, + * long lasting or asynchronous. Runtime PM API is limited when used from + * interrupt context. */ struct pm_device { + /** Base info. */ + struct pm_device_base base; #if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) /** Pointer to the device */ const struct device *dev; @@ -131,23 +172,31 @@ struct pm_device { struct k_sem lock; /** Event var to listen to the sync request events */ struct k_event event; - /** Device usage count */ - uint32_t usage; /** Work object for asynchronous calls */ struct k_work_delayable work; #endif /* CONFIG_PM_DEVICE_RUNTIME */ -#ifdef CONFIG_PM_DEVICE_POWER_DOMAIN - /** Power Domain it belongs */ - const struct device *domain; -#endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ - /* Device PM status flags. */ - atomic_t flags; - /** Device power state */ - enum pm_device_state state; - /** Device PM action callback */ - pm_device_action_cb_t action_cb; }; +/** + * @brief Runtime PM info for device with synchronous PM. + * + * Synchronous PM can be used with devices which suspend and resume operations can + * be performed in the critical section as they are short and non-blocking. + * Runtime PM API can be used from any context in that case. + */ +struct pm_device_isr { + /** Base info. */ + struct pm_device_base base; +#if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) + /** Lock to synchronize the synchronous get/put operations */ + struct k_spinlock lock; +#endif +}; + +/* Base part must be the first element. */ +BUILD_ASSERT(offsetof(struct pm_device, base) == 0); +BUILD_ASSERT(offsetof(struct pm_device_isr, base) == 0); + /** @cond INTERNAL_HIDDEN */ #ifdef CONFIG_PM_DEVICE_RUNTIME @@ -167,7 +216,7 @@ struct pm_device { #endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */ /** - * @brief Utility macro to initialize #pm_device flags + * @brief Utility macro to initialize #pm_device_base flags * * @param node_id Devicetree node for the initialized device (can be invalid). */ @@ -188,17 +237,34 @@ struct pm_device { * @note #DT_PROP_OR is used to retrieve the wakeup_source property because * it may not be defined on all devices. * - * @param obj Name of the #pm_device structure being initialized. + * @param obj Name of the #pm_device_base structure being initialized. + * @param node_id Devicetree node for the initialized device (can be invalid). + * @param pm_action_cb Device PM control callback function. + * @param _flags Additional flags passed to the structure. + */ +#define Z_PM_DEVICE_BASE_INIT(obj, node_id, pm_action_cb, _flags) \ + { \ + .action_cb = pm_action_cb, \ + .state = PM_DEVICE_STATE_ACTIVE, \ + .flags = ATOMIC_INIT(Z_PM_DEVICE_FLAGS(node_id) | (_flags)), \ + Z_PM_DEVICE_POWER_DOMAIN_INIT(node_id) \ + } + +/** + * @brief Utility macro to initialize #pm_device_rt. + * + * @note #DT_PROP_OR is used to retrieve the wakeup_source property because + * it may not be defined on all devices. + * + * @param obj Name of the #pm_device_base structure being initialized. * @param node_id Devicetree node for the initialized device (can be invalid). * @param pm_action_cb Device PM control callback function. */ -#define Z_PM_DEVICE_INIT(obj, node_id, pm_action_cb) \ - { \ - Z_PM_DEVICE_RUNTIME_INIT(obj) \ - .action_cb = pm_action_cb, \ - .state = PM_DEVICE_STATE_ACTIVE, \ - .flags = ATOMIC_INIT(Z_PM_DEVICE_FLAGS(node_id)), \ - Z_PM_DEVICE_POWER_DOMAIN_INIT(node_id) \ +#define Z_PM_DEVICE_INIT(obj, node_id, pm_action_cb, isr_safe) \ + { \ + .base = Z_PM_DEVICE_BASE_INIT(obj, node_id, pm_action_cb, \ + isr_safe ? BIT(PM_DEVICE_FLAG_ISR_SAFE) : 0), \ + COND_CODE_1(isr_safe, (), (Z_PM_DEVICE_RUNTIME_INIT(obj))) \ } /** @@ -220,7 +286,7 @@ struct pm_device { * @param dev_id Device id. */ #define Z_PM_DEVICE_DEFINE_SLOT(dev_id) \ - static const STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ + static STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \ _CONCAT(__pm_slot_, dev_id)) #ifdef CONFIG_PM_DEVICE @@ -231,21 +297,22 @@ struct pm_device { * @param dev_id Device id. * @param pm_action_cb PM control callback. */ -#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE_SLOT(dev_id); \ - static struct pm_device Z_PM_DEVICE_NAME(dev_id) = \ - Z_PM_DEVICE_INIT(Z_PM_DEVICE_NAME(dev_id), node_id, \ - pm_action_cb) +#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb, isr_safe) \ + Z_PM_DEVICE_DEFINE_SLOT(dev_id); \ + static struct COND_CODE_1(isr_safe, (pm_device_isr), (pm_device)) \ + Z_PM_DEVICE_NAME(dev_id) = \ + Z_PM_DEVICE_INIT(Z_PM_DEVICE_NAME(dev_id), node_id, \ + pm_action_cb, isr_safe) /** * Get a reference to the device PM resources. * * @param dev_id Device id. */ -#define Z_PM_DEVICE_GET(dev_id) (&Z_PM_DEVICE_NAME(dev_id)) +#define Z_PM_DEVICE_GET(dev_id) ((struct pm_device_base *)&Z_PM_DEVICE_NAME(dev_id)) #else -#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb) +#define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb, isr_safe) #define Z_PM_DEVICE_GET(dev_id) NULL #endif /* CONFIG_PM_DEVICE */ @@ -258,11 +325,13 @@ struct pm_device { * * @param dev_id Device id. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that ISR safe. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE */ -#define PM_DEVICE_DEFINE(dev_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb) +#define PM_DEVICE_DEFINE(dev_id, pm_action_cb, ...) \ + Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * Define device PM resources for the given node identifier. @@ -271,12 +340,13 @@ struct pm_device { * * @param node_id Node identifier. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that device is isr_ok. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE */ -#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb) \ - Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \ - pm_action_cb) +#define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb, ...) \ + Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * Define device PM resources for the given instance. @@ -285,13 +355,15 @@ struct pm_device { * * @param idx Instance index. * @param pm_action_cb PM control callback. + * @param ... Optional flag to indicate that device is isr_ok. Use @ref PM_DEVICE_ISR_SAFE or 0. * * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DEFINE */ -#define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb) \ +#define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb, ...) \ Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \ Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \ - pm_action_cb) + pm_action_cb, \ + COND_CODE_1(IS_EMPTY(__VA_ARGS__), (0), (__VA_ARGS__))) /** * @brief Obtain a reference to the device PM resources for the given device. @@ -393,7 +465,7 @@ int pm_device_state_get(const struct device *dev, */ static inline void pm_device_init_suspended(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; pm->state = PM_DEVICE_STATE_SUSPENDED; } @@ -413,7 +485,7 @@ static inline void pm_device_init_suspended(const struct device *dev) */ static inline void pm_device_init_off(const struct device *dev) { - struct pm_device *pm = dev->pm; + struct pm_device_base *pm = dev->pm_base; pm->state = PM_DEVICE_STATE_OFF; } diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index 09bf0c04278..3510a910f3a 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -9,6 +9,7 @@ #define ZEPHYR_INCLUDE_PM_DEVICE_RUNTIME_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -131,6 +132,7 @@ int pm_device_runtime_put(const struct device *dev); * @funcprops \pre_kernel_ok, \async, \isr_ok * * @param dev Device instance. + * @param delay Minimum amount of time before triggering the action. * * @retval 0 If it succeeds. In case device runtime PM is not enabled or not * available this function will be a no-op and will also return 0. @@ -140,7 +142,7 @@ int pm_device_runtime_put(const struct device *dev); * * @see pm_device_runtime_put() */ -int pm_device_runtime_put_async(const struct device *dev); +int pm_device_runtime_put_async(const struct device *dev, k_timeout_t delay); /** * @brief Check if device runtime is enabled for a given device. @@ -188,9 +190,11 @@ static inline int pm_device_runtime_put(const struct device *dev) return 0; } -static inline int pm_device_runtime_put_async(const struct device *dev) +static inline int pm_device_runtime_put_async(const struct device *dev, + k_timeout_t delay) { ARG_UNUSED(dev); + ARG_UNUSED(delay); return 0; } diff --git a/include/zephyr/posix/mqueue.h b/include/zephyr/posix/mqueue.h index 29f67607e2c..dbaa6d42a53 100644 --- a/include/zephyr/posix/mqueue.h +++ b/include/zephyr/posix/mqueue.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "posix_types.h" @@ -40,6 +41,7 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abstime); int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abstime); +int mq_notify(mqd_t mqdes, const struct sigevent *notification); #ifdef __cplusplus } diff --git a/include/zephyr/posix/posix_types.h b/include/zephyr/posix/posix_types.h index 73a7485f000..52621656569 100644 --- a/include/zephyr/posix/posix_types.h +++ b/include/zephyr/posix/posix_types.h @@ -21,6 +21,8 @@ extern "C" { #endif +typedef int pid_t; + #ifndef __useconds_t_defined typedef unsigned long useconds_t; #endif @@ -37,15 +39,10 @@ typedef unsigned long timer_t; /* Thread attributes */ struct pthread_attr { - int priority; void *stack; - uint32_t stacksize; - uint32_t flags; - uint32_t delayedstart; - uint32_t schedpolicy; - int32_t detachstate; - uint32_t initialized; + uint32_t details[2]; }; + #if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ || defined(CONFIG_ARCMWDT_LIBC) typedef struct pthread_attr pthread_attr_t; @@ -93,13 +90,20 @@ typedef struct pthread_barrierattr { typedef uint32_t pthread_rwlockattr_t; -typedef struct pthread_rwlock_obj { - struct k_sem rd_sem; - struct k_sem wr_sem; - struct k_sem reader_active;/* blocks WR till reader has acquired lock */ - int32_t status; - k_tid_t wr_owner; -} pthread_rwlock_t; +typedef uint32_t pthread_rwlock_t; + +struct pthread_once { + bool flag; +}; + +#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ + || defined(CONFIG_ARCMWDT_LIBC) +typedef uint32_t pthread_key_t; +typedef struct pthread_once pthread_once_t; +#endif + +/* Newlib typedefs pthread_once_t as a struct with two ints */ +BUILD_ASSERT(sizeof(pthread_once_t) >= sizeof(struct pthread_once)); #ifdef __cplusplus } diff --git a/include/zephyr/posix/pthread.h b/include/zephyr/posix/pthread.h index d978e914a5e..9b34c319b57 100644 --- a/include/zephyr/posix/pthread.h +++ b/include/zephyr/posix/pthread.h @@ -7,8 +7,6 @@ #ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ #define ZEPHYR_INCLUDE_POSIX_PTHREAD_H_ -#include "pthread_key.h" - #include #include @@ -21,24 +19,28 @@ extern "C" { #endif -/* Pthread detach/joinable */ -#define PTHREAD_CREATE_DETACHED 0 -#define PTHREAD_CREATE_JOINABLE 1 +/* + * Pthread detach/joinable + * Undefine possibly predefined values by external toolchain headers + */ +#undef PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED 1 +#undef PTHREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_JOINABLE 0 /* Pthread resource visibility */ #define PTHREAD_PROCESS_PRIVATE 0 #define PTHREAD_PROCESS_SHARED 1 /* Pthread cancellation */ -#define _PTHREAD_CANCEL_POS 0 -#define PTHREAD_CANCEL_ENABLE (0U << _PTHREAD_CANCEL_POS) -#define PTHREAD_CANCEL_DISABLE BIT(_PTHREAD_CANCEL_POS) +#define PTHREAD_CANCELED ((void *)-1) +#define PTHREAD_CANCEL_ENABLE 0 +#define PTHREAD_CANCEL_DISABLE 1 +#define PTHREAD_CANCEL_DEFERRED 0 +#define PTHREAD_CANCEL_ASYNCHRONOUS 1 /* Passed to pthread_once */ -#define PTHREAD_ONCE_INIT \ - { \ - 1, 0 \ - } +#define PTHREAD_ONCE_INIT {0} /* The minimum allowable stack size */ #define PTHREAD_STACK_MIN Z_KERNEL_STACK_SIZE_ADJUST(0) @@ -50,18 +52,6 @@ extern "C" { */ #define PTHREAD_COND_INITIALIZER (-1) -/** - * @brief Declare a pthread condition variable - * - * Declaration API for a pthread condition variable. This is not a - * POSIX API, it's provided to better conform with Zephyr's allocation - * strategies for kernel objects. - * - * @param name Symbol name of the condition variable - * @deprecated Use @c PTHREAD_COND_INITIALIZER instead. - */ -#define PTHREAD_COND_DEFINE(name) pthread_cond_t name = PTHREAD_COND_INITIALIZER - /** * @brief POSIX threading compatibility API * @@ -147,16 +137,11 @@ int pthread_condattr_setclock(pthread_condattr_t *att, clockid_t clock_id); #define PTHREAD_MUTEX_INITIALIZER (-1) /** - * @brief Declare a pthread mutex - * - * Declaration API for a pthread mutex. This is not a POSIX API, it's - * provided to better conform with Zephyr's allocation strategies for - * kernel objects. + * @brief Declare a rwlock as initialized * - * @param name Symbol name of the mutex - * @deprecated Use @c PTHREAD_MUTEX_INITIALIZER instead. + * Initialize a rwlock with the default rwlock attributes. */ -#define PTHREAD_MUTEX_DEFINE(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER +#define PTHREAD_RWLOCK_INITIALIZER (-1) /* * Mutex attributes - type @@ -426,7 +411,9 @@ static inline int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) return 0; } +int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT attr, size_t *ZRESTRICT guardsize); int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); @@ -452,6 +439,8 @@ int pthread_detach(pthread_t thread); int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*threadroutine)(void *), void *arg); int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); +void pthread_testcancel(void); int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *schedparam); int pthread_setschedparam(pthread_t pthread, int policy, @@ -473,6 +462,21 @@ int pthread_key_create(pthread_key_t *key, int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +int pthread_getconcurrency(void); +int pthread_setconcurrency(int new_level); + +void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg); +void __z_pthread_cleanup_pop(int execute); + +#define pthread_cleanup_push(_rtn, _arg) \ + do /* enforce '{'-like behaviour */ { \ + void *_z_pthread_cleanup[3]; \ + __z_pthread_cleanup_push(_z_pthread_cleanup, _rtn, _arg) + +#define pthread_cleanup_pop(_ex) \ + __z_pthread_cleanup_pop(_ex); \ + } /* enforce '}'-like behaviour */ while (0) /* Glibc / Oracle Extension Functions */ diff --git a/include/zephyr/posix/pthread_key.h b/include/zephyr/posix/pthread_key.h deleted file mode 100644 index 6b89c8f9818..00000000000 --- a/include/zephyr/posix/pthread_key.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ -#define ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(CONFIG_MINIMAL_LIBC) || defined(CONFIG_PICOLIBC) || defined(CONFIG_ARMCLANG_STD_LIBC) \ - || defined(CONFIG_ARCMWDT_LIBC) - -#ifdef CONFIG_PTHREAD_IPC - -typedef struct { - int is_initialized; - int init_executed; -} pthread_once_t; -#endif - -/* pthread_key */ -typedef uint32_t pthread_key_t; - -#endif /* CONFIG_PTHREAD_IPC */ - -#ifdef __cplusplus -} -#endif - -#endif /* ZEPHYR_INCLUDE_POSIX_PTHREAD_KEY_H_*/ diff --git a/include/zephyr/posix/sched.h b/include/zephyr/posix/sched.h index 10cfc666c66..b337cc2c022 100644 --- a/include/zephyr/posix/sched.h +++ b/include/zephyr/posix/sched.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2018-2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,10 @@ #include +#include "posix_types.h" + +#include + #ifdef __cplusplus extern "C" { #endif @@ -46,6 +50,13 @@ static inline int sched_yield(void) int sched_get_priority_min(int policy); int sched_get_priority_max(int policy); +int sched_getparam(pid_t pid, struct sched_param *param); +int sched_getscheduler(pid_t pid); + +int sched_setparam(pid_t pid, const struct sched_param *param); +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param); +int sched_rr_get_interval(pid_t pid, struct timespec *interval); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/posix/semaphore.h b/include/zephyr/posix/semaphore.h index 943218ee08e..3b0f53b0712 100644 --- a/include/zephyr/posix/semaphore.h +++ b/include/zephyr/posix/semaphore.h @@ -13,6 +13,8 @@ extern "C" { #endif +#define SEM_FAILED ((sem_t *) 0) + int sem_destroy(sem_t *semaphore); int sem_getvalue(sem_t *ZRESTRICT semaphore, int *ZRESTRICT value); int sem_init(sem_t *semaphore, int pshared, unsigned int value); @@ -20,6 +22,9 @@ int sem_post(sem_t *semaphore); int sem_timedwait(sem_t *ZRESTRICT semaphore, struct timespec *ZRESTRICT abstime); int sem_trywait(sem_t *semaphore); int sem_wait(sem_t *semaphore); +sem_t *sem_open(const char *name, int oflags, ...); +int sem_unlink(const char *name); +int sem_close(sem_t *sem); #ifdef __cplusplus } diff --git a/include/zephyr/posix/signal.h b/include/zephyr/posix/signal.h index b31147306c2..3bbdee7317a 100644 --- a/include/zephyr/posix/signal.h +++ b/include/zephyr/posix/signal.h @@ -12,7 +12,6 @@ extern "C" { #endif -#ifdef CONFIG_POSIX_SIGNAL #define SIGHUP 1 /**< Hangup */ #define SIGINT 2 /**< Interrupt */ #define SIGQUIT 3 /**< Quit */ @@ -45,24 +44,17 @@ extern "C" { /* 30 not used */ #define SIGSYS 31 /**< Bad system call */ +#define RTSIG_MAX CONFIG_POSIX_RTSIG_MAX #define SIGRTMIN 32 -#define SIGRTMAX (SIGRTMIN + CONFIG_POSIX_RTSIG_MAX) +#define SIGRTMAX (SIGRTMIN + RTSIG_MAX) #define _NSIG (SIGRTMAX + 1) -BUILD_ASSERT(CONFIG_POSIX_RTSIG_MAX >= 0); +BUILD_ASSERT(RTSIG_MAX >= 0); typedef struct { unsigned long sig[DIV_ROUND_UP(_NSIG, BITS_PER_LONG)]; } sigset_t; -char *strsignal(int signum); -int sigemptyset(sigset_t *set); -int sigfillset(sigset_t *set); -int sigaddset(sigset_t *set, int signo); -int sigdelset(sigset_t *set, int signo); -int sigismember(const sigset_t *set, int signo); -#endif /* CONFIG_POSIX_SIGNAL */ - #ifndef SIGEV_NONE #define SIGEV_NONE 1 #endif @@ -75,21 +67,43 @@ int sigismember(const sigset_t *set, int signo); #define SIGEV_THREAD 3 #endif +#ifndef SIG_BLOCK +#define SIG_BLOCK 0 +#endif +#ifndef SIG_SETMASK +#define SIG_SETMASK 1 +#endif +#ifndef SIG_UNBLOCK +#define SIG_UNBLOCK 2 +#endif + typedef int sig_atomic_t; /* Atomic entity type (ANSI) */ union sigval { - int sival_int; void *sival_ptr; + int sival_int; }; struct sigevent { - int sigev_notify; - int sigev_signo; - union sigval sigev_value; void (*sigev_notify_function)(union sigval val); pthread_attr_t *sigev_notify_attributes; + union sigval sigev_value; + int sigev_notify; + int sigev_signo; }; +#ifdef CONFIG_POSIX_SIGNAL +char *strsignal(int signum); +int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); +int sigaddset(sigset_t *set, int signo); +int sigdelset(sigset_t *set, int signo); +int sigismember(const sigset_t *set, int signo); +int sigprocmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset); + +int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset); +#endif /* CONFIG_POSIX_SIGNAL */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/posix/stropts.h b/include/zephyr/posix/stropts.h new file mode 100644 index 00000000000..9474c36edb2 --- /dev/null +++ b/include/zephyr/posix/stropts.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_POSIX_STROPTS_H_ +#define ZEPHYR_INCLUDE_POSIX_STROPTS_H_ +#define RS_HIPRI BIT(0) + +#ifdef __cplusplus +extern "C" { +#endif + +struct strbuf { + int maxlen; + int len; + char *buf; +}; + +int putmsg(int fildes, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_POSIX_STROPTS_H_ */ diff --git a/include/zephyr/posix/sys/select.h b/include/zephyr/posix/sys/select.h index 0fd2b5de9e6..4420b69eaba 100644 --- a/include/zephyr/posix/sys/select.h +++ b/include/zephyr/posix/sys/select.h @@ -6,8 +6,8 @@ #ifndef ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ #define ZEPHYR_INCLUDE_POSIX_SYS_SELECT_H_ +#include #include -#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 85cb7f8ae42..417923c4377 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -69,6 +69,10 @@ extern "C" { #define CLOCK_REALTIME 1 #endif +#ifndef CLOCK_PROCESS_CPUTIME_ID +#define CLOCK_PROCESS_CPUTIME_ID 2 +#endif + #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC 4 #endif @@ -82,12 +86,9 @@ static inline int32_t _ts_to_ms(const struct timespec *to) return (to->tv_sec * MSEC_PER_SEC) + (to->tv_nsec / NSEC_PER_MSEC); } -#if defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC) int clock_gettime(clockid_t clock_id, struct timespec *ts); -#else -__syscall int clock_gettime(clockid_t clock_id, struct timespec *ts); -#endif /* CONFIG_ARCH_POSIX */ int clock_settime(clockid_t clock_id, const struct timespec *ts); +int clock_getcpuclockid(pid_t pid, clockid_t *clock_id); /* Timer APIs */ int timer_create(clockid_t clockId, struct sigevent *evp, timer_t *timerid); int timer_delete(timer_t timerid); @@ -103,10 +104,6 @@ int clock_nanosleep(clockid_t clock_id, int flags, } #endif -#if !(defined(CONFIG_ARCH_POSIX) && defined(CONFIG_EXTERNAL_LIBC)) -#include -#endif /* CONFIG_ARCH_POSIX */ - #else /* ZEPHYR_INCLUDE_POSIX_TIME_H_ */ /* Read the toolchain header when finds itself on the * first attempt. diff --git a/include/zephyr/posix/unistd.h b/include/zephyr/posix/unistd.h index b55cf702fec..36918c56365 100644 --- a/include/zephyr/posix/unistd.h +++ b/include/zephyr/posix/unistd.h @@ -11,16 +11,219 @@ #ifdef CONFIG_NETWORKING /* For zsock_gethostname() */ #include +#include #endif #ifdef CONFIG_POSIX_API #include #endif +#ifdef CONFIG_POSIX_SYSCONF +#include +#endif + #ifdef __cplusplus extern "C" { #endif +/* Version test macros */ +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION (-1L) +#define _XOPEN_VERSION (-1L) + +/* Internal helper macro to set constant if required Kconfig symbol is enabled */ +#define Z_SC_VAL_IFDEF(_def, _val) COND_CODE_1(_def, (_val), (-1L)) + +/* Constants for Opitions and Option Groups */ +#define _POSIX_ADVISORY_INFO (-1L) +#define _POSIX_ASYNCHRONOUS_IO (-1L) +#define _POSIX_BARRIERS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_CHOWN_RESTRICTED (-1L) +#define _POSIX_CLOCK_SELECTION Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_CPUTIME (-1L) +#define _POSIX_FSYNC (-1L) +#define _POSIX_IPV6 Z_SC_VAL_IFDEF(CONFIG_NET_IPV6, _POSIX_VERSION) +#define _POSIX_JOB_CONTROL (-1L) +#define _POSIX_MAPPED_FILES _POSIX_VERSION +#define _POSIX_MEMLOCK (-1L) +#define _POSIX_MEMLOCK_RANGE (-1L) +#define _POSIX_MEMORY_PROTECTION (-1L) +#define _POSIX_MESSAGE_PASSING Z_SC_VAL_IFDEF(CONFIG_POSIX_MQUEUE, _POSIX_VERSION) +#define _POSIX_MONOTONIC_CLOCK Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_NO_TRUNC (-1L) +#define _POSIX_PRIORITIZED_IO (-1L) +#define _POSIX_PRIORITY_SCHEDULING (-1L) +#define _POSIX_RAW_SOCKETS Z_SC_VAL_IFDEF(CONFIG_NET_SOCKETS_PACKET, _POSIX_VERSION) +#define _POSIX_READER_WRITER_LOCKS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_REALTIME_SIGNALS (-1L) +#define _POSIX_REGEXP (-1L) +#define _POSIX_SAVED_IDS (-1L) +#define _POSIX_SEMAPHORES Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_SHARED_MEMORY_OBJECTS (-1L) +#define _POSIX_SHELL (-1L) +#define _POSIX_SPAWN (-1L) +#define _POSIX_SPIN_LOCKS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_SPINLOCK, _POSIX_VERSION) +#define _POSIX_SPORADIC_SERVER (-1L) +#define _POSIX_SYNCHRONIZED_IO (-1L) +#define _POSIX_THREAD_ATTR_STACKADDR Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_ATTR_STACKSIZE Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_CPUTIME (-1L) +#define _POSIX_THREAD_PRIO_INHERIT _POSIX_VERSION +#define _POSIX_THREAD_PRIO_PROTECT (-1L) +#define _POSIX_THREAD_PRIORITY_SCHEDULING Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_PROCESS_SHARED (-1L) +#define _POSIX_THREAD_ROBUST_PRIO_INHERIT (-1L) +#define _POSIX_THREAD_ROBUST_PRIO_PROTECT (-1L) +#define _POSIX_THREAD_SAFE_FUNCTIONS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#define _POSIX_THREAD_SPORADIC_SERVER (-1L) + +#ifndef _POSIX_THREADS +#define _POSIX_THREADS Z_SC_VAL_IFDEF(CONFIG_PTHREAD_IPC, _POSIX_VERSION) +#endif + +#define _POSIX_TIMEOUTS Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_TIMERS Z_SC_VAL_IFDEF(CONFIG_POSIX_CLOCK, _POSIX_VERSION) +#define _POSIX_TRACE (-1L) +#define _POSIX_TRACE_EVENT_FILTER (-1L) +#define _POSIX_TRACE_INHERIT (-1L) +#define _POSIX_TRACE_LOG (-1L) +#define _POSIX_TYPED_MEMORY_OBJECTS (-1L) +#define _POSIX_V6_ILP32_OFF32 (-1L) +#define _POSIX_V6_ILP32_OFFBIG (-1L) +#define _POSIX_V6_LP64_OFF64 (-1L) +#define _POSIX_V6_LPBIG_OFFBIG (-1L) +#define _POSIX_V7_ILP32_OFF32 (-1L) +#define _POSIX_V7_ILP32_OFFBIG (-1L) +#define _POSIX_V7_LP64_OFF64 (-1L) +#define _POSIX_V7_LPBIG_OFFBIG (-1L) +#define _POSIX2_C_BIND _POSIX_VERSION +#define _POSIX2_C_DEV (-1L) +#define _POSIX2_CHAR_TERM (-1L) +#define _POSIX2_FORT_DEV (-1L) +#define _POSIX2_FORT_RUN (-1L) +#define _POSIX2_LOCALEDEF (-1L) +#define _POSIX2_PBS (-1L) +#define _POSIX2_PBS_ACCOUNTING (-1L) +#define _POSIX2_PBS_CHECKPOINT (-1L) +#define _POSIX2_PBS_LOCATE (-1L) +#define _POSIX2_PBS_MESSAGE (-1L) +#define _POSIX2_PBS_TRACK (-1L) +#define _POSIX2_SW_DEV (-1L) +#define _POSIX2_UPE (-1L) +#define _XOPEN_CRYPT (-1L) +#define _XOPEN_ENH_I18N (-1L) +#define _XOPEN_REALTIME (-1L) +#define _XOPEN_REALTIME_THREADS (-1L) +#define _XOPEN_SHM (-1L) +#define _XOPEN_STREAMS (-1L) +#define _XOPEN_UNIX (-1L) +#define _XOPEN_UUCP (-1L) + +/* Maximum values */ +#define _POSIX_CLOCKRES_MIN (20000000L) + +/* Minimum values */ +#define _POSIX_AIO_LISTIO_MAX (2) +#define _POSIX_AIO_MAX (1) +#define _POSIX_ARG_MAX (4096) +#define _POSIX_CHILD_MAX (25) +#define _POSIX_DELAYTIMER_MAX (32) +#define _POSIX_HOST_NAME_MAX (255) +#define _POSIX_LINK_MAX (8) +#define _POSIX_LOGIN_NAME_MAX (9) +#define _POSIX_MAX_CANON (255) +#define _POSIX_MAX_INPUT (255) +#define _POSIX_MQ_OPEN_MAX CONFIG_MSG_COUNT_MAX +#define _POSIX_MQ_PRIO_MAX (32) +#define _POSIX_NAME_MAX (14) +#define _POSIX_NGROUPS_MAX (8) +#define _POSIX_OPEN_MAX CONFIG_POSIX_MAX_FDS +#define _POSIX_PATH_MAX (256) +#define _POSIX_PIPE_BUF (512) +#define _POSIX_RE_DUP_MAX (255) +#define _POSIX_RTSIG_MAX CONFIG_POSIX_RTSIG_MAX +#define _POSIX_SEM_NSEMS_MAX CONFIG_SEM_NAMELEN_MAX +#define _POSIX_SEM_VALUE_MAX CONFIG_SEM_VALUE_MAX +#define _POSIX_SIGQUEUE_MAX (32) +#define _POSIX_SSIZE_MAX (32767) +#define _POSIX_SS_REPL_MAX (4) +#define _POSIX_STREAM_MAX (8) +#define _POSIX_SYMLINK_MAX (255) +#define _POSIX_SYMLOOP_MAX (8) +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS (4) +#define _POSIX_THREAD_KEYS_MAX (128) +#define _POSIX_THREAD_THREADS_MAX (64) +#define _POSIX_TIMER_MAX (32) +#define _POSIX_TRACE_EVENT_NAME_MAX (30) +#define _POSIX_TRACE_NAME_MAX (8) +#define _POSIX_TRACE_SYS_MAX (8) +#define _POSIX_TRACE_USER_EVENT_MAX (32) +#define _POSIX_TTY_NAME_MAX (9) +#define _POSIX_TZNAME_MAX (6) +#define _POSIX2_BC_BASE_MAX (99) +#define _POSIX2_BC_DIM_MAX (2048) +#define _POSIX2_BC_SCALE_MAX (99) +#define _POSIX2_BC_STRING_MAX (1000) +#define _POSIX2_CHARCLASS_NAME_MAX (14) +#define _POSIX2_COLL_WEIGHTS_MAX (2) +#define _POSIX2_EXPR_NEST_MAX (32) +#define _POSIX2_LINE_MAX (2048) +#define _XOPEN_IOV_MAX (16) +#define _XOPEN_NAME_MAX (255) +#define _XOPEN_PATH_MAX (1024) + +/* Other invariant values */ +#define NL_LANGMAX (14) +#define NL_MSGMAX (32767) +#define NL_SETMAX (255) +#define NL_TEXTMAX (_POSIX2_LINE_MAX) +#define NZERO (20) + +/* Runtime invariant values */ +#define AIO_LISTIO_MAX _POSIX_AIO_LISTIO_MAX +#define AIO_MAX _POSIX_AIO_MAX +#define AIO_PRIO_DELTA_MAX (0) +#define DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX +#define HOST_NAME_MAX COND_CODE_1(CONFIG_NETWORKING, \ + (NET_HOSTNAME_MAX_LEN), \ + (_POSIX_HOST_NAME_MAX)) +#define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX +#define MQ_OPEN_MAX _POSIX_MQ_OPEN_MAX +#define MQ_PRIO_MAX _POSIX_MQ_PRIO_MAX + +#ifndef PAGE_SIZE +#define PAGE_SIZE BIT(CONFIG_POSIX_PAGE_SIZE_BITS) +#endif + +#ifndef PAGESIZE +#define PAGESIZE PAGE_SIZE +#endif + +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_KEYS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, \ + (CONFIG_MAX_PTHREAD_KEY_COUNT), \ + (_POSIX_THREAD_KEYS_MAX)) +#define PTHREAD_THREADS_MAX COND_CODE_1(CONFIG_PTHREAD_IPC, \ + (CONFIG_MAX_PTHREAD_COUNT), \ + (0)) +#define SEM_NSEMS_MAX _POSIX_SEM_NSEMS_MAX +#define SEM_VALUE_MAX CONFIG_SEM_VALUE_MAX +#define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX +#define STREAM_MAX _POSIX_STREAM_MAX +#define SYMLOOP_MAX _POSIX_SYMLOOP_MAX +#define TIMER_MAX CONFIG_MAX_TIMER_COUNT +#define TTY_NAME_MAX _POSIX_TTY_NAME_MAX +#define TZNAME_MAX _POSIX_TZNAME_MAX + +/* Pathname variable values */ +#define FILESIZEBITS (32) +#define POSIX_ALLOC_SIZE_MIN (256) +#define POSIX_REC_INCR_XFER_SIZE (1024) +#define POSIX_REC_MAX_XFER_SIZE (32767) +#define POSIX_REC_MIN_XFER_SIZE (1) +#define POSIX_REC_XFER_ALIGN (4) +#define SYMLINK_MAX _POSIX_SYMLINK_MAX + #ifdef CONFIG_POSIX_API /* File related operations */ int close(int file); @@ -51,9 +254,141 @@ extern char *optarg; extern int opterr, optind, optopt; #endif +pid_t getpid(void); unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); +#ifdef CONFIG_POSIX_SYSCONF +#define __z_posix_sysconf_SC_ADVISORY_INFO _POSIX_ADVISORY_INFO +#define __z_posix_sysconf_SC_ASYNCHRONOUS_IO _POSIX_ASYNCHRONOUS_IO +#define __z_posix_sysconf_SC_BARRIERS _POSIX_BARRIERS +#define __z_posix_sysconf_SC_CLOCK_SELECTION _POSIX_CLOCK_SELECTION +#define __z_posix_sysconf_SC_CPUTIME _POSIX_CPUTIME +#define __z_posix_sysconf_SC_FSYNC _POSIX_FSYNC +#define __z_posix_sysconf_SC_IPV6 _POSIX_IPV6 +#define __z_posix_sysconf_SC_JOB_CONTROL _POSIX_JOB_CONTROL +#define __z_posix_sysconf_SC_MAPPED_FILE _POSIX_MAPPED_FILES +#define __z_posix_sysconf_SC_MEMLOCK _POSIX_MEMLOCK +#define __z_posix_sysconf_SC_MEMLOCK_RANGE _POSIX_MEMLOCK_RANGE +#define __z_posix_sysconf_SC_MEMORY_PROTECTION _POSIX_MEMORY_PROTECTION +#define __z_posix_sysconf_SC_MESSAGE_PASSING _POSIX_MESSAGE_PASSING +#define __z_posix_sysconf_SC_MONOTONIC_CLOCK _POSIX_MONOTONIC_CLOCK +#define __z_posix_sysconf_SC_PRIORITIZED_IO _POSIX_PRIORITIZED_IO +#define __z_posix_sysconf_SC_PRIORITY_SCHEDULING _POSIX_PRIORITY_SCHEDULING +#define __z_posix_sysconf_SC_RAW_SOCKETS _POSIX_RAW_SOCKETS +#define __z_posix_sysconf_SC_RE_DUP_MAX _POSIX_RE_DUP_MAX +#define __z_posix_sysconf_SC_READER_WRITER_LOCKS _POSIX_READER_WRITER_LOCKS +#define __z_posix_sysconf_SC_REALTIME_SIGNALS _POSIX_REALTIME_SIGNALS +#define __z_posix_sysconf_SC_REGEXP _POSIX_REGEXP +#define __z_posix_sysconf_SC_SAVED_IDS _POSIX_SAVED_IDS +#define __z_posix_sysconf_SC_SEMAPHORES _POSIX_SEMAPHORES +#define __z_posix_sysconf_SC_SHARED_MEMORY_OBJECTS _POSIX_SHARED_MEMORY_OBJECTS +#define __z_posix_sysconf_SC_SHELL _POSIX_SHELL +#define __z_posix_sysconf_SC_SPAWN _POSIX_SPAWN +#define __z_posix_sysconf_SC_SPIN_LOCKS _POSIX_SPIN_LOCKS +#define __z_posix_sysconf_SC_SPORADIC_SERVER _POSIX_SPORADIC_SERVER +#define __z_posix_sysconf_SC_SS_REPL_MAX _POSIX_SS_REPL_MAX +#define __z_posix_sysconf_SC_SYNCHRONIZED_IO _POSIX_SYNCHRONIZED_IO +#define __z_posix_sysconf_SC_THREAD_ATTR_STACKADDR _POSIX_THREAD_ATTR_STACKADDR +#define __z_posix_sysconf_SC_THREAD_ATTR_STACKSIZE _POSIX_THREAD_ATTR_STACKSIZE +#define __z_posix_sysconf_SC_THREAD_CPUTIME _POSIX_THREAD_CPUTIME +#define __z_posix_sysconf_SC_THREAD_PRIO_INHERIT _POSIX_THREAD_PRIO_INHERIT +#define __z_posix_sysconf_SC_THREAD_PRIO_PROTECT _POSIX_THREAD_PRIO_PROTECT +#define __z_posix_sysconf_SC_THREAD_PRIORITY_SCHEDULING _POSIX_THREAD_PRIORITY_SCHEDULING +#define __z_posix_sysconf_SC_THREAD_PROCESS_SHARED _POSIX_THREAD_PROCESS_SHARED +#define __z_posix_sysconf_SC_THREAD_ROBUST_PRIO_INHERIT _POSIX_THREAD_ROBUST_PRIO_INHERIT +#define __z_posix_sysconf_SC_THREAD_ROBUST_PRIO_PROTECT _POSIX_THREAD_ROBUST_PRIO_PROTECT +#define __z_posix_sysconf_SC_THREAD_SAFE_FUNCTIONS _POSIX_THREAD_SAFE_FUNCTIONS +#define __z_posix_sysconf_SC_THREAD_SPORADIC_SERVER _POSIX_THREAD_SPORADIC_SERVER +#define __z_posix_sysconf_SC_THREADS _POSIX_THREADS +#define __z_posix_sysconf_SC_TIMEOUTS _POSIX_TIMEOUTS +#define __z_posix_sysconf_SC_TIMERS _POSIX_TIMERS +#define __z_posix_sysconf_SC_TRACE _POSIX_TRACE +#define __z_posix_sysconf_SC_TRACE_EVENT_FILTER _POSIX_TRACE_EVENT_FILTER +#define __z_posix_sysconf_SC_TRACE_EVENT_NAME_MAX _POSIX_TRACE_EVENT_NAME_MAX +#define __z_posix_sysconf_SC_TRACE_INHERIT _POSIX_TRACE_INHERIT +#define __z_posix_sysconf_SC_TRACE_LOG _POSIX_TRACE_LOG +#define __z_posix_sysconf_SC_TRACE_NAME_MAX _POSIX_TRACE_NAME_MAX +#define __z_posix_sysconf_SC_TRACE_SYS_MAX _POSIX_TRACE_SYS_MAX +#define __z_posix_sysconf_SC_TRACE_USER_EVENT_MAX _POSIX_TRACE_USER_EVENT_MAX +#define __z_posix_sysconf_SC_TYPED_MEMORY_OBJECTS _POSIX_TYPED_MEMORY_OBJECTS +#define __z_posix_sysconf_SC_VERSION _POSIX_VERSION +#define __z_posix_sysconf_SC_V7_ILP32_OFF32 _POSIX_V7_ILP32_OFF32 +#define __z_posix_sysconf_SC_V7_ILP32_OFFBIG _POSIX_V7_ILP32_OFFBIG +#define __z_posix_sysconf_SC_V7_LP64_OFF64 _POSIX_V7_LP64_OFF64 +#define __z_posix_sysconf_SC_V7_LPBIG_OFFBIG _POSIX_V7_LPBIG_OFFBIG +#define __z_posix_sysconf_SC_V6_ILP32_OFF32 _POSIX_V6_ILP32_OFF32 +#define __z_posix_sysconf_SC_V6_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG +#define __z_posix_sysconf_SC_V6_LP64_OFF64 _POSIX_V6_LP64_OFF64 +#define __z_posix_sysconf_SC_V6_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG +#define __z_posix_sysconf_SC_BC_BASE_MAX _POSIX2_BC_BASE_MAX +#define __z_posix_sysconf_SC_BC_DIM_MAX _POSIX2_BC_DIM_MAX +#define __z_posix_sysconf_SC_BC_SCALE_MAX _POSIX2_BC_SCALE_MAX +#define __z_posix_sysconf_SC_BC_STRING_MAX _POSIX2_BC_STRING_MAX +#define __z_posix_sysconf_SC_2_C_BIND _POSIX2_C_BIND +#define __z_posix_sysconf_SC_2_C_DEV _POSIX2_C_DEV +#define __z_posix_sysconf_SC_2_CHAR_TERM _POSIX2_CHAR_TERM +#define __z_posix_sysconf_SC_COLL_WEIGHTS_MAX _POSIX2_COLL_WEIGHTS_MAX +#define __z_posix_sysconf_SC_DELAYTIMER_MAX _POSIX2_DELAYTIMER_MAX +#define __z_posix_sysconf_SC_EXPR_NEST_MAX _POSIX2_EXPR_NEST_MAX +#define __z_posix_sysconf_SC_2_FORT_DEV _POSIX2_FORT_DEV +#define __z_posix_sysconf_SC_2_FORT_RUN _POSIX2_FORT_RUN +#define __z_posix_sysconf_SC_LINE_MAX _POSIX2_LINE_MAX +#define __z_posix_sysconf_SC_2_LOCALEDEF _POSIX2_LOCALEDEF +#define __z_posix_sysconf_SC_2_PBS _POSIX2_PBS +#define __z_posix_sysconf_SC_2_PBS_ACCOUNTING _POSIX2_PBS_ACCOUNTING +#define __z_posix_sysconf_SC_2_PBS_CHECKPOINT _POSIX2_PBS_CHECKPOINT +#define __z_posix_sysconf_SC_2_PBS_LOCATE _POSIX2_PBS_LOCATE +#define __z_posix_sysconf_SC_2_PBS_MESSAGE _POSIX2_PBS_MESSAGE +#define __z_posix_sysconf_SC_2_PBS_TRACK _POSIX2_PBS_TRACK +#define __z_posix_sysconf_SC_2_SW_DEV _POSIX2_SW_DEV +#define __z_posix_sysconf_SC_2_UPE _POSIX2_UPE +#define __z_posix_sysconf_SC_2_VERSION _POSIX2_VERSION +#define __z_posix_sysconf_SC_XOPEN_CRYPT _XOPEN_CRYPT +#define __z_posix_sysconf_SC_XOPEN_ENH_I18N _XOPEN_ENH_I18N +#define __z_posix_sysconf_SC_XOPEN_REALTIME _XOPEN_REALTIME +#define __z_posix_sysconf_SC_XOPEN_REALTIME_THREADS _XOPEN_REALTIME_THREADS +#define __z_posix_sysconf_SC_XOPEN_SHM _XOPEN_SHM +#define __z_posix_sysconf_SC_XOPEN_STREAMS _XOPEN_STREAMS +#define __z_posix_sysconf_SC_XOPEN_UNIX _XOPEN_UNIX +#define __z_posix_sysconf_SC_XOPEN_UUCP _XOPEN_UUCP +#define __z_posix_sysconf_SC_XOPEN_VERSION _XOPEN_VERSION +#define __z_posix_sysconf_SC_CLK_TCK (100L) +#define __z_posix_sysconf_SC_GETGR_R_SIZE_MAX (0L) +#define __z_posix_sysconf_SC_GETPW_R_SIZE_MAX (0L) +#define __z_posix_sysconf_SC_AIO_LISTIO_MAX AIO_LISTIO_MAX +#define __z_posix_sysconf_SC_AIO_MAX AIO_MAX +#define __z_posix_sysconf_SC_AIO_PRIO_DELTA_MAX AIO_PRIO_DELTA_MAX +#define __z_posix_sysconf_SC_ARG_MAX ARG_MAX +#define __z_posix_sysconf_SC_ATEXIT_MAX ATEXIT_MAX +#define __z_posix_sysconf_SC_CHILD_MAX CHILD_MAX +#define __z_posix_sysconf_SC_HOST_NAME_MAX HOST_NAME_MAX +#define __z_posix_sysconf_SC_IOV_MAX IOV_MAX +#define __z_posix_sysconf_SC_LOGIN_NAME_MAX LOGIN_NAME_MAX +#define __z_posix_sysconf_SC_NGROUPS_MAX _POSIX_NGROUPS_MAX +#define __z_posix_sysconf_SC_MQ_OPEN_MAX MQ_OPEN_MAX +#define __z_posix_sysconf_SC_MQ_PRIO_MAX MQ_PRIO_MAX +#define __z_posix_sysconf_SC_OPEN_MAX CONFIG_POSIX_MAX_FDS +#define __z_posix_sysconf_SC_PAGE_SIZE PAGE_SIZE +#define __z_posix_sysconf_SC_PAGESIZE PAGESIZE +#define __z_posix_sysconf_SC_THREAD_DESTRUCTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS +#define __z_posix_sysconf_SC_THREAD_KEYS_MAX PTHREAD_KEYS_MAX +#define __z_posix_sysconf_SC_THREAD_STACK_MIN PTHREAD_STACK_MIN +#define __z_posix_sysconf_SC_THREAD_THREADS_MAX PTHREAD_THREADS_MAX +#define __z_posix_sysconf_SC_RTSIG_MAX RTSIG_MAX +#define __z_posix_sysconf_SC_SEM_NSEMS_MAX SEM_NSEMS_MAX +#define __z_posix_sysconf_SC_SEM_VALUE_MAX SEM_VALUE_MAX +#define __z_posix_sysconf_SC_SIGQUEUE_MAX SIGQUEUE_MAX +#define __z_posix_sysconf_SC_STREAM_MAX STREAM_MAX +#define __z_posix_sysconf_SC_SYMLOOP_MAX SYMLOOP_MAX +#define __z_posix_sysconf_SC_TIMER_MAX TIMER_MAX +#define __z_posix_sysconf_SC_TTY_NAME_MAX TTY_NAME_MAX +#define __z_posix_sysconf_SC_TZNAME_MAX TZNAME_MAX + +#define sysconf(x) (long)CONCAT(__z_posix_sysconf, x) + +#endif /* CONFIG_POSIX_SYSCONF */ + #ifdef __cplusplus } #endif diff --git a/include/zephyr/rtio/rtio.h b/include/zephyr/rtio/rtio.h index fe0f5b72c97..79ab78dc58c 100644 --- a/include/zephyr/rtio/rtio.h +++ b/include/zephyr/rtio/rtio.h @@ -699,7 +699,11 @@ static inline int rtio_block_pool_alloc(struct rtio *r, size_t min_sz, static inline void rtio_block_pool_free(struct rtio *r, void *buf, uint32_t buf_len) { -#ifdef CONFIG_RTIO_SYS_MEM_BLOCKS +#ifndef CONFIG_RTIO_SYS_MEM_BLOCKS + ARG_UNUSED(r); + ARG_UNUSED(buf); + ARG_UNUSED(buf_len); +#else size_t num_blks = buf_len >> r->block_pool->info.blk_sz_shift; sys_mem_blocks_free_contiguous(r->block_pool, buf, num_blks); diff --git a/include/zephyr/sd/sd.h b/include/zephyr/sd/sd.h index 69d3057e8ad..b23fa2c260c 100644 --- a/include/zephyr/sd/sd.h +++ b/include/zephyr/sd/sd.h @@ -80,8 +80,14 @@ struct sd_card { uint8_t bus_width; /*!< Desired bus width */ uint32_t cccr_flags; /*!< SDIO CCCR data */ struct sdio_func func0; /*!< Function 0 common card data */ + + /* NOTE: The buffer is accessed as a uint32_t* by the SD subsystem, so must be + * aligned to 4 bytes for platforms that don't support unaligned access... + * Systems where the buffer is accessed by DMA may require wider alignment, in + * which case, use CONFIG_SDHC_BUFFER_ALIGNMENT. + */ uint8_t card_buffer[CONFIG_SD_BUFFER_SIZE] - __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT); /* Card internal buffer */ + __aligned(MAX(4, CONFIG_SDHC_BUFFER_ALIGNMENT)); /* Card internal buffer */ }; /** diff --git a/include/zephyr/sensing/sensing.h b/include/zephyr/sensing/sensing.h index e29b1aa7624..4491874fc84 100644 --- a/include/zephyr/sensing/sensing.h +++ b/include/zephyr/sensing/sensing.h @@ -72,6 +72,11 @@ struct sensing_sensor_version { */ #define SENSING_SENSOR_FLAG_REPORT_ON_CHANGE BIT(1) +/** + * @brief SENSING_SENSITIVITY_INDEX_ALL indicating sensitivity of each data field should be set + * + */ +#define SENSING_SENSITIVITY_INDEX_ALL -1 /** * @brief Sensing subsystem sensor state. @@ -110,7 +115,8 @@ typedef void *sensing_sensor_handle_t; */ typedef void (*sensing_data_event_t)( sensing_sensor_handle_t handle, - const void *buf); + const void *buf, + void *context); /** * @struct sensing_sensor_info @@ -144,6 +150,7 @@ struct sensing_sensor_info { */ struct sensing_callback_list { sensing_data_event_t on_data_event; + void *context; }; /** * @struct sensing_sensor_config @@ -152,7 +159,10 @@ struct sensing_callback_list { */ struct sensing_sensor_config { enum sensing_sensor_attribute attri; + + /** \ref SENSING_SENSITIVITY_INDEX_ALL */ int8_t data_field; + union { uint32_t interval; uint32_t sensitivity; @@ -186,7 +196,8 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf * * @param info The sensor info got from \ref sensing_get_sensors * - * @param cb_list callback list to be registered to sensing. + * @param cb_list callback list to be registered to sensing, must have a static + * lifetime. * * @param handle The opened instance handle, if failed will be set to NULL. * @@ -194,7 +205,7 @@ int sensing_get_sensors(int *num_sensors, const struct sensing_sensor_info **inf */ int sensing_open_sensor( const struct sensing_sensor_info *info, - const struct sensing_callback_list *cb_list, + struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle); /** @@ -207,14 +218,15 @@ int sensing_open_sensor( * * @param dev pointer device get from device tree. * - * @param cb_list callback list to be registered to sensing. + * @param cb_list callback list to be registered to sensing, must have a static + * lifetime. * * @param handle The opened instance handle, if failed will be set to NULL. * * @return 0 on success or negative error value on failure. */ int sensing_open_sensor_by_dt( - const struct device *dev, const struct sensing_callback_list *cb_list, + const struct device *dev, struct sensing_callback_list *cb_list, sensing_sensor_handle_t *handle); /** diff --git a/include/zephyr/sensing/sensing_datatypes.h b/include/zephyr/sensing/sensing_datatypes.h index 3549aab4bdb..a5abcc3c8f8 100644 --- a/include/zephyr/sensing/sensing_datatypes.h +++ b/include/zephyr/sensing/sensing_datatypes.h @@ -99,8 +99,8 @@ struct sensing_sensor_value_uint32 { * q31 version */ struct sensing_sensor_value_q31 { - int8_t shift; struct sensing_sensor_value_header header; + int8_t shift; struct { uint32_t timestamp_delta; q31_t v; diff --git a/include/zephyr/sensing/sensing_sensor.h b/include/zephyr/sensing/sensing_sensor.h index 8c9e0c83811..434c13b9052 100644 --- a/include/zephyr/sensing/sensing_sensor.h +++ b/include/zephyr/sensing/sensing_sensor.h @@ -7,10 +7,10 @@ #ifndef ZEPHYR_INCLUDE_SENSING_SENSOR_H_ #define ZEPHYR_INCLUDE_SENSING_SENSOR_H_ -#include -#include #include +#include #include +#include /** * @defgroup sensing_sensor Sensing Sensor API @@ -34,7 +34,6 @@ extern "C" { * */ struct sensing_sensor_register_info { - /** * Sensor flags */ @@ -58,105 +57,198 @@ struct sensing_sensor_register_info { struct sensing_sensor_version version; }; +enum { + EVENT_CONFIG_READY, +}; + +enum { + SENSOR_LATER_CFG_BIT, +}; + /** - * @brief Sensor context data structure + * @brief Connection between a source and sink of sensor data + */ +struct sensing_connection { + sys_snode_t snode; + struct sensing_sensor *source; + struct sensing_sensor *sink; + /* interval and sensitivity set from client(sink) to reporter(source) */ + uint32_t interval; + int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; + /* copy sensor data to connection data buf from reporter */ + void *data; + /* client(sink) next consume time */ + uint64_t next_consume_time; + /* post data to application */ + struct sensing_callback_list *callback_list; +}; + +/** + * @brief Internal sensor instance data structure. + * + * Each sensor instance will have its unique data structure for storing all + * it's related information. * + * Sensor management will enumerate all these instance data structures, + * build report relationship model base on them, etc. */ -struct sensing_sensor_ctx { - - /** - * For sensing runtime internal private data, sensor should not see and touch - */ - void *priv_ptr; - - /** - * Pointer to the sensor register information. - */ +struct sensing_sensor { + const struct device *dev; + const struct sensing_sensor_info *info; const struct sensing_sensor_register_info *register_info; - - /** - * For sensor private context data, registered by sensor with \ref SENSING_SENSOR_DT_DEFINE. - * Sensor could use \ref sensing_sensor_get_ctx_data to fetch out this filed with - * struct device. - */ - void *const sensor_ctx_ptr; + const uint16_t reporter_num; + sys_slist_t client_list; + uint32_t interval; + uint8_t sensitivity_count; + int sensitivity[CONFIG_SENSING_MAX_SENSITIVITY_COUNT]; + enum sensing_sensor_state state; + /* runtime info */ + struct rtio_iodev *iodev; + struct k_timer timer; + struct rtio_sqe *stream_sqe; + atomic_t flag; + struct sensing_connection *conns; }; -static inline int sensing_sensor_dev_init( - const struct device *dev) -{ - /** - * Nothing need to do in system auto initialization. - * Sensor subsystem runtime will call each sensor instance's initialization - * function via API callback according sensor reporting dependency sequences. - * Sensor subsystem can make sure the depends sensor instances always initialized before - * client sensors. - */ - return 0; +#define SENSING_SENSOR_INFO_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_sensor_info_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_INFO_DEFINE(node, idx) \ + const static STRUCT_SECTION_ITERABLE(sensing_sensor_info, \ + SENSING_SENSOR_INFO_NAME(node, idx)) = { \ + .type = DT_PROP_BY_IDX(node, sensor_types, idx), \ + .name = DT_NODE_FULL_NAME(node), \ + .friendly_name = DT_PROP(node, friendly_name), \ + .vendor = DT_NODE_VENDOR_OR(node, NULL), \ + .model = DT_NODE_MODEL_OR(node, NULL), \ + .minimal_interval = DT_PROP(node, minimal_interval),\ + }; + +#define SENSING_CONNECTIONS_NAME(node) \ + _CONCAT(__sensing_connections_, DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_SOURCE_NAME(idx, node) \ + SENSING_SENSOR_NAME(DT_PHANDLE_BY_IDX(node, reporters, idx), \ + DT_PROP_BY_IDX(node, reporters_index, idx)) + +#define SENSING_SENSOR_SOURCE_EXTERN(idx, node) \ +extern struct sensing_sensor SENSING_SENSOR_SOURCE_NAME(idx, node); \ + +#define SENSING_CONNECTION_INITIALIZER(source_name, cb_list_ptr) \ +{ \ + .callback_list = cb_list_ptr, \ + .source = &source_name, \ } +#define SENSING_CONNECTION_DEFINE(idx, node, cb_list_ptr) \ + SENSING_CONNECTION_INITIALIZER(SENSING_SENSOR_SOURCE_NAME(idx, node), \ + cb_list_ptr) + +#define SENSING_CONNECTIONS_DEFINE(node, num, cb_list_ptr) \ + LISTIFY(num, SENSING_SENSOR_SOURCE_EXTERN, \ + (), node) \ + static struct sensing_connection \ + SENSING_CONNECTIONS_NAME(node)[(num)] = { \ + LISTIFY(num, SENSING_CONNECTION_DEFINE, \ + (,), node, cb_list_ptr) \ + }; + +struct sensing_submit_config { + enum sensor_channel chan; + const int info_index; + const bool is_streaming; +}; + +extern const struct rtio_iodev_api __sensing_iodev_api; + +#define SENSING_SUBMIT_CFG_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_submit_cfg_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_IODEV_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_iodev_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_IODEV_DEFINE(node, idx) \ + static struct sensing_submit_config SENSING_SUBMIT_CFG_NAME(node, idx) = { \ + .is_streaming = DT_PROP(node, stream_mode), \ + .info_index = idx, \ + }; \ + RTIO_IODEV_DEFINE(SENSING_SENSOR_IODEV_NAME(node, idx), \ + &__sensing_iodev_api, \ + &SENSING_SUBMIT_CFG_NAME(node, idx)); + +#define SENSING_SENSOR_NAME(node, idx) \ + _CONCAT(_CONCAT(__sensing_sensor_, idx), DEVICE_DT_NAME_GET(node)) + +#define SENSING_SENSOR_DEFINE(node, prop, idx, reg_ptr, cb_list_ptr) \ + SENSING_SENSOR_INFO_DEFINE(node, idx) \ + SENSING_SENSOR_IODEV_DEFINE(node, idx) \ + STRUCT_SECTION_ITERABLE(sensing_sensor, \ + SENSING_SENSOR_NAME(node, idx)) = { \ + .dev = DEVICE_DT_GET(node), \ + .info = &SENSING_SENSOR_INFO_NAME(node, idx), \ + .register_info = reg_ptr, \ + .reporter_num = DT_PROP_LEN_OR(node, reporters, 0), \ + .conns = SENSING_CONNECTIONS_NAME(node), \ + .iodev = &SENSING_SENSOR_IODEV_NAME(node, idx), \ + }; + +#define SENSING_SENSORS_DEFINE(node, reg_ptr, cb_list_ptr) \ + DT_FOREACH_PROP_ELEM_VARGS(node, sensor_types, \ + SENSING_SENSOR_DEFINE, reg_ptr, cb_list_ptr) /** - * @brief Macro for define a sensor instance from device tree node id + * @brief Like SENSOR_DEVICE_DT_DEFINE() with sensing specifics. * - * This macro also defined a struct device for this sensor instance, and registered sensors' - * private context data, configuration data structure and API. + * @details Defines a sensor which implements the sensor API. May define an + * element in the sensing sensor iterable section used to enumerate all sensing + * sensors. * - * sensing_init will enumerate all sensor instances from device tree, and initialize each sensor - * instance defined by this macro. + * @param node The devicetree node identifier. * - */ - -#define SENSING_SENSOR_DT_DEFINE(node_id, reg_ptr, ctx_ptr, api_ptr) \ - static struct sensing_sensor_ctx \ - _CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)) = { \ - .register_info = reg_ptr, \ - .sensor_ctx_ptr = ctx_ptr, \ - }; \ - DEVICE_DT_DEFINE(node_id, sensing_sensor_dev_init, NULL, \ - &_CONCAT(__sensing_sensor_ctx_, Z_DEVICE_DT_DEV_ID(node_id)), \ - NULL, POST_KERNEL, 99, api_ptr) - -/** - * @brief Get registered context data pointer for a sensor instance. + * @param reg_ptr Pointer to the device's sensing_sensor_register_info. * - * Used by a sensor instance to get its registered context data pointer with its struct device. + * @param cb_list_ptr Pointer to devices callback list. * - * @param dev The sensor instance device structure. - */ -static inline void *sensing_sensor_get_ctx_data( - const struct device *dev) -{ - struct sensing_sensor_ctx *data = dev->data; - - return data->sensor_ctx_ptr; -} - -/** - * @brief Post sensor data, sensor subsystem runtime will deliver to it's - * clients. + * @param init_fn Name of the init function of the driver. * - * Unblocked function, returned immediately. + * @param pm_device PM device resources reference (NULL if device does not use + * PM). * - * Used by a virtual sensor to post data to it's clients. + * @param data_ptr Pointer to the device's private data. * - * A reporter sensor can use this API to post data to it's clients. - * For example, when a virtual sensor computed a data, then can use this API - * to deliver the data to it's clients. - * Please note, this API just for reporter post data to the sensor subsystem - * runtime, the runtime will help delivered the data to it's all clients - * according clients' configurations such as reporter interval, data change sensitivity. + * @param cfg_ptr The address to the structure containing the configuration + * information for this instance of the driver. * - * @param dev The sensor instance device structure. + * @param level The initialization level. See SYS_INIT() for details. + * + * @param prio Priority within the selected initialization level. See + * SYS_INIT() for details. * - * @param buf The data buffer. + * @param api_ptr Provides an initial pointer to the API function struct used + * by the driver. Can be NULL. + */ +#define SENSING_SENSORS_DT_DEFINE(node, reg_ptr, cb_list_ptr, \ + init_fn, pm_device, \ + data_ptr, cfg_ptr, level, prio, \ + api_ptr, ...) \ + SENSOR_DEVICE_DT_DEFINE(node, init_fn, pm_device, \ + data_ptr, cfg_ptr, level, prio, \ + api_ptr, __VA_ARGS__); \ + SENSING_CONNECTIONS_DEFINE(node, \ + DT_PROP_LEN_OR(node, reporters, 0), \ + cb_list_ptr); \ + SENSING_SENSORS_DEFINE(node, reg_ptr, cb_list_ptr); + +/** + * @brief Like SENSING_SENSORS_DT_DEFINE() for an instance of a DT_DRV_COMPAT + * compatible * - * @param size The buffer size in bytes. + * @param inst instance number. This is replaced by + * DT_DRV_COMPAT(inst) in the call to SENSING_SENSORS_DT_DEFINE(). * - * @return 0 on success or negative error value on failure. + * @param ... other parameters as expected by SENSING_SENSORS_DT_DEFINE(). */ -int sensing_sensor_post_data( - const struct device *dev, - void *buf, int size); +#define SENSING_SENSORS_DT_INST_DEFINE(inst, ...) \ + SENSING_SENSORS_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__) /** * @brief Get reporter handles of a given sensor instance by sensor type. @@ -176,7 +268,7 @@ int sensing_sensor_post_data( */ int sensing_sensor_get_reporters( const struct device *dev, int type, - const int *reporter_handles, int max_handles); + sensing_sensor_handle_t *reporter_handles, int max_handles); /** * @brief Get reporters count of a given sensor instance by sensor type. @@ -203,386 +295,6 @@ int sensing_sensor_get_state( const struct device *dev, enum sensing_sensor_state *state); -/** - * @brief Trigger the data ready event to sensing - * - * @param dev Pointer to the sensor device - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_notify_data_ready( - const struct device *dev); - -/** - * @brief Set the data ready mode of the sensor - * - * @param dev Pointer to the sensor device - * - * @param data_ready Enable/disable the data ready mode. Default:disabled - * - * @return 0 on success or negative error value on failure. - */ -int sensing_sensor_set_data_ready( - const struct device *dev, bool data_ready); - -/** - * @} - */ - -/** - * @brief Sensor Callbacks - * @addtogroup sensing_sensor_callbacks - * \{ - */ - -/** - * @brief Sensor initialize. - * - * Sensor can initialize it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @param info The sensor instance's constant information. - * - * @param reporter_handles The reporters handles for this sensor, NULL for physical sensors. - * - * @param reporters_count The number of reporters, zero for physical sensors. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_init_t)( - const struct device *dev, const struct sensing_sensor_info *info, - const sensing_sensor_handle_t *reporter_handles, int reporters_count); - -/** - * @brief Sensor's de-initialize. - * - * Sensor can release it's runtime context in this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_deinit_t)( - const struct device *dev); - -/** - * @brief Sensor reset. - * - * Sensor can reset its runtime context in this callback to default values without resources - * release and re-allocation. - * - * Its very useful for a virtual sensor to quickly reset its runtime context to a default state. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_reset_t)( - const struct device *dev); - -/** - * @brief Sensor read sample. - * - * Only physical sensor need implement this callback. - * Physical sensor can fetch sample data from sensor device in this callback - * - * @param dev The sensor instance device structure. - * - * @param buf Sensor subsystem runtime allocated buffer, and passed its pointer - * to this sensor for store fetched sample. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_read_sample_t)( - const struct device *dev, - void *buf, int size); - -/** - * @brief Sensor process data. - * - * Only virtual sensor need implement this callback. - * Virtual sensor can receive reporter's data and do fusion computing - * in this callback. - * - * @param dev The sensor instance device structure. - * - * @param reporter The reporter handle who delivered this sensor data - * - * @param buf The buffer stored the reporter's sensor data. - * - * @param size The size of the buffer in bytes. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_process_t)( - const struct device *dev, - int reporter, - void *buf, int size); - -/** - * @brief Trigger a sensor to do self calibration - * - * If not support self calibration, can not implement this callback. - * - * @param dev The sensor instance device structure. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_self_calibration_t)( - const struct device *dev); - -/** - * @brief Sensitivity arbitration. - * - * This callback API provides a chance for sensor to do customized arbitration on data change - * sensitivity. - * The sensor can check two sequential samples with client's sensitivity value (passed with - * parameters in this callback) and decide if can pass the sensor sample to its client. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param sensitivity The sensitivity value. - * - * @param last_sample_buf The buffer stored last sample data. - * - * @param last_sample_size The size of last sample's data buffer in bytes - * - * @param current_sample_buf The buffer stored current sample data. - * - * @param current_sample_size The size of current sample's data buffer in bytes - * - * @return 0 on test passed or negative error value on failure. - * - */ -typedef int (*sensing_sensor_sensitivity_test_t)( - const struct device *dev, - int index, uint32_t sensitivity, - void *last_sample_buf, int last_sample_size, - void *current_sample_buf, int current_sample_size); - -/** - * @brief Set current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_interval_t)( - const struct device *dev, - uint32_t value); - -/** - * @brief Get current report interval. - * - * @param dev The sensor instance device structure. - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_get_interval_t)( - const struct device *dev, - uint32_t *value); - -/** - * @brief Set data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure. - * - */ -typedef int (*sensing_sensor_set_sensitivity_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data change sensitivity. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated sensitivity for each data field, or global - * sensitivity for all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_sensitivity_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_range_t)( - const struct device *dev, - int index, uint32_t value); - -/** - * @brief Get current data range. - * - * Some sensors especially for physical sensors, support data range - * configuration, this may change data resolution. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated range for each data field, or global range for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_range_t)( - const struct device *dev, - int index, uint32_t *value); - -/** - * @brief Set current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support hardware fifo, this API can - * configure the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The sample number to set for fifo. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_fifo_t)( - const struct device *dev, - uint32_t samples); - -/** - * @brief Get current sensor's hardware fifo size - * - * Some sensors especially for physical sensors, support fifo, this API can - * get the current fifo size. - * - * @param dev The sensor instance device structure. - * - * @param samples The data buffer to receive the fifo sample number. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_fifo_t)( - const struct device *dev, - uint32_t *samples); - -/** - * @brief Set current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support set separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The offset value to be set. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_set_offset_t)( - const struct device *dev, - int index, int32_t value); - -/** - * @brief Get current sensor data offset - * - * Some sensors especially for physical sensors, such as accelerometer senors, - * as data drift, need configure offset calibration. - * - * Since each sensor type may have multiple data fields for it's value, this - * API support get separated offset for each data field, or global offset for - * all data fields. - * - * @param dev The sensor instance device structure. - * - * @param index The value fields index to be set, -1 for all fields (global). - * - * @param value The data buffer to receive the offset value. - * - * @return 0 on success or negative error value on failure, not support etc. - */ -typedef int (*sensing_sensor_get_offset_t)( - const struct device *dev, - int index, int32_t *value); -/** - * @struct sensing_sensor_api - * @brief Sensor callback api - * - * A sensor must register this callback API during sensor registration. - */ -struct sensing_sensor_api { - sensing_sensor_init_t init; - sensing_sensor_reset_t reset; - sensing_sensor_deinit_t deinit; - sensing_sensor_set_interval_t set_interval; - sensing_sensor_get_interval_t get_interval; - sensing_sensor_set_range_t set_range; - sensing_sensor_get_range_t get_range; - sensing_sensor_set_offset_t set_offset; - sensing_sensor_get_offset_t get_offset; - sensing_sensor_get_fifo_t get_fifo; - sensing_sensor_set_fifo_t set_fifo; - sensing_sensor_set_sensitivity_t set_sensitivity; - sensing_sensor_get_sensitivity_t get_sensitivity; - sensing_sensor_read_sample_t read_sample; - sensing_sensor_process_t process; - sensing_sensor_sensitivity_test_t sensitivity_test; - sensing_sensor_self_calibration_t self_calibration; -}; - /** * @} */ diff --git a/include/zephyr/shared_irq.h b/include/zephyr/shared_irq.h index d95d727076d..575ef119d3a 100644 --- a/include/zephyr/shared_irq.h +++ b/include/zephyr/shared_irq.h @@ -1,7 +1,7 @@ /* shared_irq - Shared interrupt driver */ /* - * Copyright (c) 2015 Intel corporation + * Copyright (c) 2015 - 2023 Intel corporation * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ extern "C" { #endif -typedef int (*isr_t)(const struct device *dev); +typedef int (*isr_t)(const struct device *dev, unsigned int irq_number); /* driver API definition */ typedef int (*shared_irq_register_t)(const struct device *dev, diff --git a/include/zephyr/shell/shell.h b/include/zephyr/shell/shell.h index 8382dc8290a..0bcb831c90d 100644 --- a/include/zephyr/shell/shell.h +++ b/include/zephyr/shell/shell.h @@ -743,6 +743,7 @@ struct shell_backend_ctx_flags { uint32_t cmd_ctx :1; /*!< Shell is executing command */ uint32_t print_noinit :1; /*!< Print request from not initialized shell */ uint32_t sync_mode :1; /*!< Shell in synchronous mode */ + uint32_t handle_log :1; /*!< Shell is handling logger backend */ }; BUILD_ASSERT((sizeof(struct shell_backend_ctx_flags) == sizeof(uint32_t)), @@ -798,6 +799,9 @@ struct shell_ctx { /** When bypass is set, all incoming data is passed to the callback. */ shell_bypass_cb_t bypass; + /*!< Logging level for a backend. */ + uint32_t log_level; + #if defined CONFIG_SHELL_GETOPT /*!< getopt context for a shell backend. */ struct getopt_state getopt; diff --git a/include/zephyr/shell/shell_uart.h b/include/zephyr/shell/shell_uart.h index 5032c56f65e..e424a185768 100644 --- a/include/zephyr/shell/shell_uart.h +++ b/include/zephyr/shell/shell_uart.h @@ -7,6 +7,7 @@ #ifndef SHELL_UART_H__ #define SHELL_UART_H__ +#include #include #include @@ -14,6 +15,85 @@ extern "C" { #endif +extern const struct shell_transport_api shell_uart_transport_api; + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT 0 +#endif + +#ifndef CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE +#define CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE 0 +#endif + +#define ASYNC_RX_BUF_SIZE (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_COUNT * \ + (CONFIG_SHELL_BACKEND_SERIAL_ASYNC_RX_BUFFER_SIZE + \ + UART_ASYNC_RX_BUF_OVERHEAD)) + +struct shell_uart_common { + const struct device *dev; + shell_transport_handler_t handler; + void *context; + bool blocking_tx; +#ifdef CONFIG_MCUMGR_TRANSPORT_SHELL + struct smp_shell_data smp; +#endif /* CONFIG_MCUMGR_TRANSPORT_SHELL */ +}; + +struct shell_uart_int_driven { + struct shell_uart_common common; + struct ring_buf tx_ringbuf; + struct ring_buf rx_ringbuf; + uint8_t tx_buf[CONFIG_SHELL_BACKEND_SERIAL_TX_RING_BUFFER_SIZE]; + uint8_t rx_buf[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; + struct k_timer dtr_timer; + atomic_t tx_busy; +}; + +struct shell_uart_async { + struct shell_uart_common common; + struct k_sem tx_sem; + struct uart_async_rx async_rx; + struct uart_async_rx_config async_rx_config; + atomic_t pending_rx_req; + uint8_t rx_data[ASYNC_RX_BUF_SIZE]; +}; + +struct shell_uart_polling { + struct shell_uart_common common; + struct ring_buf rx_ringbuf; + uint8_t rx_buf[CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE]; + struct k_timer rx_timer; +}; + +#ifdef CONFIG_SHELL_BACKEND_SERIAL_API_POLLING +#define SHELL_UART_STRUCT struct shell_uart_polling +#elif defined(CONFIG_SHELL_BACKEND_SERIAL_API_ASYNC) +#define SHELL_UART_STRUCT struct shell_uart_async +#else +#define SHELL_UART_STRUCT struct shell_uart_int_driven +#endif + +/** + * @brief Macro for creating shell UART transport instance named @p _name + * + * @note Additional arguments are accepted (but ignored) for compatibility with + * previous Zephyr version, it will be removed in future release. + */ +#define SHELL_UART_DEFINE(_name, ...) \ + static SHELL_UART_STRUCT _name##_shell_uart; \ + struct shell_transport _name = { \ + .api = &shell_uart_transport_api, \ + .ctx = (struct shell_telnet *)&_name##_shell_uart, \ + } + /** * @brief This function provides pointer to the shell UART backend instance. * diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index cc4a246105d..ffe386d6b7a 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2024 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * Copyright (c) 2023 Sensorfy B.V. * @@ -275,21 +275,6 @@ uint8_t flash_area_erased_val(const struct flash_area *fa); #include #else -#define FLASH_AREA_LABEL_EXISTS(label) __DEPRECATED_MACRO \ - DT_HAS_FIXED_PARTITION_LABEL(label) - -#define FLASH_AREA_LABEL_STR(lbl) __DEPRECATED_MACRO \ - DT_PROP(DT_NODE_BY_FIXED_PARTITION_LABEL(lbl), label) - -#define FLASH_AREA_ID(label) __DEPRECATED_MACRO \ - DT_FIXED_PARTITION_ID(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - -#define FLASH_AREA_OFFSET(label) __DEPRECATED_MACRO \ - DT_REG_ADDR(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - -#define FLASH_AREA_SIZE(label) __DEPRECATED_MACRO \ - DT_REG_SIZE(DT_NODE_BY_FIXED_PARTITION_LABEL(label)) - /** * Returns non-0 value if fixed-partition of given DTS node label exists. * diff --git a/include/zephyr/sw_isr_table.h b/include/zephyr/sw_isr_table.h index f43efafad49..7b1bfddb2cb 100644 --- a/include/zephyr/sw_isr_table.h +++ b/include/zephyr/sw_isr_table.h @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -56,6 +57,9 @@ struct _irq_parent_entry { * uses it to create the IRQ vector table and the _sw_isr_table. * * More discussion in include/linker/intlist.ld + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is disabled. + * See _isr_list_sname used otherwise. */ struct _isr_list { /** IRQ line number */ @@ -68,14 +72,27 @@ struct _isr_list { const void *param; }; -#ifdef CONFIG_SHARED_INTERRUPTS -struct z_shared_isr_client { - void (*isr)(const void *arg); - const void *arg; +/* + * Data structure created in a special binary .intlist section for each + * configured interrupt. gen_isr_tables.py pulls this out of the binary and + * uses it to create linker script chunks that would place interrupt table entries + * in the right place in the memory. + * + * This is a version used when CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. + * See _isr_list used otherwise. + */ +struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; }; +#ifdef CONFIG_SHARED_INTERRUPTS struct z_shared_isr_table_entry { - struct z_shared_isr_client clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; + struct _isr_table_entry clients[CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS]; size_t client_num; }; @@ -90,6 +107,90 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; #define _MK_ISR_NAME(x, y) __MK_ISR_NAME(x, y) #define __MK_ISR_NAME(x, y) __isr_ ## x ## _irq_ ## y + +#if IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) + +#define _MK_ISR_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_ISR_ELEMENT_NAME(func, id) __isr_table_entry_ ## func ## _irq_ ## id + +#define _MK_IRQ_ELEMENT_NAME(func, id) __MK_ISR_ELEMENT_NAME(func, id) +#define __MK_IRQ_ELEMENT_NAME(func, id) __irq_table_entry_ ## func ## _irq_ ## id + +#define _MK_ISR_SECTION_NAME(prefix, file, counter) \ + "." Z_STRINGIFY(prefix)"."file"." Z_STRINGIFY(counter) + +#define _MK_ISR_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(irq, __FILE__, counter) +#define _MK_IRQ_ELEMENT_SECTION(counter) _MK_ISR_SECTION_NAME(isr, __FILE__, counter) + +/* Separated macro to create ISR table entry only. + * Used by Z_ISR_DECLARE and ISR tables generation script. + */ +#define _Z_ISR_TABLE_ENTRY(irq, func, param, sect) \ + static Z_DECL_ALIGN(struct _isr_table_entry) \ + __attribute__((section(sect))) \ + __used _MK_ISR_ELEMENT_NAME(func, __COUNTER__) = { \ + .arg = (const void *)(param), \ + .isr = (void (*)(const void *))(void *)(func) \ + } + +#define Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_DECLARE_C(irq, flags, func, param, counter) + +#define _Z_ISR_DECLARE_C(irq, flags, func, param, counter) \ + _Z_ISR_TABLE_ENTRY(irq, func, param, _MK_ISR_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = \ + {irq, flags, _MK_ISR_ELEMENT_SECTION(counter)} + +/* Create an entry for _isr_table to be then placed by the linker. + * An instance of struct _isr_list which gets put in the .intList + * section is created with the name of the section where _isr_table entry is placed to be then + * used by isr generation script to create linker script chunk. + */ +#define Z_ISR_DECLARE(irq, flags, func, param) \ + BUILD_ASSERT(((flags) & ISR_FLAG_DIRECT) == 0, "Use Z_ISR_DECLARE_DIRECT macro"); \ + Z_ISR_DECLARE_C(irq, flags, func, param, __COUNTER__) + + +/* Separated macro to create ISR Direct table entry only. + * Used by Z_ISR_DECLARE_DIRECT and ISR tables generation script. + */ +#define _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, sect) \ + COND_CODE_1(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS, ( \ + static Z_DECL_ALIGN(uintptr_t) \ + __attribute__((section(sect))) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__) = ((uintptr_t)(func)); \ + ), ( \ + static void __attribute__((section(sect))) __attribute__((naked)) \ + __used _MK_IRQ_ELEMENT_NAME(func, __COUNTER__)(void) { \ + __asm(ARCH_IRQ_VECTOR_JUMP_CODE(func)); \ + } \ + )) + +#define Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) + +#define _Z_ISR_DECLARE_DIRECT_C(irq, flags, func, counter) \ + _Z_ISR_DIRECT_TABLE_ENTRY(irq, func, _MK_IRQ_ELEMENT_SECTION(counter)); \ + static struct _isr_list_sname Z_GENERIC_SECTION(.intList) \ + __used _MK_ISR_NAME(func, counter) = { \ + irq, \ + ISR_FLAG_DIRECT | (flags), \ + _MK_IRQ_ELEMENT_SECTION(counter)} + +/* Create an entry to irq table and place it in specific section which name is then placed + * in an instance of struct _isr_list to be then used by the isr generation script to create + * the linker script chunks. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + BUILD_ASSERT(IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS) || \ + IS_ENABLED(CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE), \ + "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set"); \ + Z_ISR_DECLARE_DIRECT_C(irq, flags, func, __COUNTER__) + + +#else /* IS_ENABLED(CONFIG_ISR_TABLES_LOCAL_DECLARATION) */ + /* Create an instance of struct _isr_list which gets put in the .intList * section. This gets consumed by gen_isr_tables.py which creates the vector * and/or SW ISR tables. @@ -99,6 +200,14 @@ extern struct z_shared_isr_table_entry z_shared_sw_isr_table[]; __used _MK_ISR_NAME(func, __COUNTER__) = \ {irq, flags, (void *)&func, (const void *)param} +/* The version of the Z_ISR_DECLARE that should be used for direct ISR declaration. + * It is here for the API match the version with CONFIG_ISR_TABLES_LOCAL_DECLARATION enabled. + */ +#define Z_ISR_DECLARE_DIRECT(irq, flags, func) \ + Z_ISR_DECLARE(irq, ISR_FLAG_DIRECT | (flags), func, NULL) + +#endif + #define IRQ_TABLE_SIZE (CONFIG_NUM_IRQS - CONFIG_GEN_IRQ_START_VECTOR) #ifdef CONFIG_DYNAMIC_INTERRUPTS diff --git a/include/zephyr/sys/arch_interface.h b/include/zephyr/sys/arch_interface.h index e694bce55cc..0ffc95c663b 100644 --- a/include/zephyr/sys/arch_interface.h +++ b/include/zephyr/sys/arch_interface.h @@ -216,7 +216,7 @@ void arch_cpu_atomic_idle(unsigned int key); * * @param data context parameter, implementation specific */ -typedef FUNC_NORETURN void (*arch_cpustart_t)(void *data); +typedef void (*arch_cpustart_t)(void *data); /** * @brief Start a numbered CPU on a MP-capable system @@ -495,6 +495,9 @@ static inline uint32_t arch_proc_id(void); */ void arch_sched_ipi(void); + +int arch_smp_init(void); + #endif /* CONFIG_SMP */ /** @@ -517,6 +520,8 @@ static inline unsigned int arch_num_cpus(void); */ #ifdef CONFIG_USERSPACE +#include + /** * Invoke a system call with 0 arguments. * @@ -798,7 +803,7 @@ int arch_buffer_validate(void *addr, size_t size, int write); size_t arch_virt_region_align(uintptr_t phys, size_t size); /** - * Perform a one-way transition from supervisor to kernel mode. + * Perform a one-way transition from supervisor to user mode. * * Implementations of this function must do the following: * @@ -1055,7 +1060,13 @@ int arch_gdb_remove_breakpoint(struct gdb_ctx *ctx, uint8_t type, #include /** - * @ingroup arch-timing + * @brief Arch specific Timing Measurement APIs + * @defgroup timing_api_arch Arch specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using architecture specific timing measurement mechanism. + * * @{ */ @@ -1099,17 +1110,25 @@ void arch_timing_stop(void); /** * @brief Return timing counter. * + * @parblock + * * @note Any call to arch_timing_counter_get() must be done between * calls to arch_timing_start() and arch_timing_stop(), and on the * same CPU core. * - * @note Not all platforms have a timing counter with 64 bit precision. It - * is possible to see this value "go backwards" due to internal + * @endparblock + * + * @parblock + * + * @note Not all architectures have a timing counter with 64 bit precision. + * It is possible to see this value "go backwards" due to internal * rollover. Timing code must be prepared to address the rollover * (with platform-dependent code, e.g. by casting to a uint32_t before * subtraction) or by using arch_timing_cycles_get() which is required * to understand the distinction. * + * @endparblock + * * @return Timing counter. * * @see timing_counter_get() @@ -1119,7 +1138,7 @@ timing_t arch_timing_counter_get(void); /** * @brief Get number of cycles between @p start and @p end. * - * For some architectures or SoCs, the raw numbers from counter need + * @note For some architectures, the raw numbers from counter need * to be scaled to obtain actual number of cycles, or may roll over * internally. This function computes a positive-definite interval * between two returned cycle values. diff --git a/include/zephyr/sys/atomic.h b/include/zephyr/sys/atomic.h index bcb122bf38a..3982e428038 100644 --- a/include/zephyr/sys/atomic.h +++ b/include/zephyr/sys/atomic.h @@ -1,6 +1,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,7 @@ #include #include +#include /* IWYU pragma: export */ #include #include @@ -19,11 +21,6 @@ extern "C" { #endif -typedef long atomic_t; -typedef atomic_t atomic_val_t; -typedef void *atomic_ptr_t; -typedef atomic_ptr_t atomic_ptr_val_t; - /* Low-level primitives come in several styles: */ #if defined(CONFIG_ATOMIC_OPERATIONS_C) @@ -90,7 +87,7 @@ typedef atomic_ptr_t atomic_ptr_val_t; * * @param num_bits Number of bits. */ -#define ATOMIC_BITMAP_SIZE(num_bits) (1 + ((num_bits) - 1) / ATOMIC_BITS) +#define ATOMIC_BITMAP_SIZE(num_bits) (ROUND_UP(num_bits, ATOMIC_BITS) / ATOMIC_BITS) /** * @brief Define an array of atomic variables. @@ -120,8 +117,7 @@ typedef atomic_ptr_t atomic_ptr_val_t; * This routine tests whether bit number @a bit of @a target is set or not. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -141,8 +137,7 @@ static inline bool atomic_test_bit(const atomic_t *target, int bit) * Atomically clear bit number @a bit of @a target and return its old value. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -165,8 +160,7 @@ static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target and return its old value. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -189,8 +183,7 @@ static inline bool atomic_test_and_set_bit(atomic_t *target, int bit) * Atomically clear bit number @a bit of @a target. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -208,8 +201,7 @@ static inline void atomic_clear_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -227,8 +219,7 @@ static inline void atomic_set_bit(atomic_t *target, int bit) * Atomically set bit number @a bit of @a target to value @a val. * The target may be a single atomic variable or an array of them. * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). + * @note @atomic_api * * @param target Address of atomic variable or array. * @param bit Bit number (starting from 0). @@ -245,6 +236,239 @@ static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) } } +/** + * @brief Atomic compare-and-set. + * + * This routine performs an atomic compare-and-set on @a target. If the current + * value of @a target equals @a old_value, @a target is set to @a new_value. + * If the current value of @a target does not equal @a old_value, @a target + * is left unchanged. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param old_value Original value to compare against. + * @param new_value New value to store. + * @return true if @a new_value is written, false otherwise. + */ +bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value); + +/** + * @brief Atomic compare-and-set with pointer values + * + * This routine performs an atomic compare-and-set on @a target. If the current + * value of @a target equals @a old_value, @a target is set to @a new_value. + * If the current value of @a target does not equal @a old_value, @a target + * is left unchanged. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param old_value Original value to compare against. + * @param new_value New value to store. + * @return true if @a new_value is written, false otherwise. + */ +bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, + atomic_ptr_val_t new_value); + +/** + * @brief Atomic addition. + * + * This routine performs an atomic addition on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to add. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_add(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic subtraction. + * + * This routine performs an atomic subtraction on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to subtract. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic increment. + * + * This routine performs an atomic increment by 1 on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_inc(atomic_t *target); + +/** + * @brief Atomic decrement. + * + * This routine performs an atomic decrement by 1 on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_dec(atomic_t *target); + +/** + * @brief Atomic get. + * + * This routine performs an atomic read on @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Value of @a target. + */ +atomic_val_t atomic_get(const atomic_t *target); + +/** + * @brief Atomic get a pointer value + * + * This routine performs an atomic read on @a target. + * + * @note @atomic_api + * + * @param target Address of pointer variable. + * + * @return Value of @a target. + */ +atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target); + +/** + * @brief Atomic get-and-set. + * + * This routine atomically sets @a target to @a value and returns + * the previous value of @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to write to @a target. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_set(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic get-and-set for pointer values + * + * This routine atomically sets @a target to @a value and returns + * the previous value of @a target. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to write to @a target. + * + * @return Previous value of @a target. + */ +atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value); + +/** + * @brief Atomic clear. + * + * This routine atomically sets @a target to zero and returns its previous + * value. (Hence, it is equivalent to atomic_set(target, 0).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_clear(atomic_t *target); + +/** + * @brief Atomic clear of a pointer value + * + * This routine atomically sets @a target to zero and returns its previous + * value. (Hence, it is equivalent to atomic_set(target, 0).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * + * @return Previous value of @a target. + */ +atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target); + +/** + * @brief Atomic bitwise inclusive OR. + * + * This routine atomically sets @a target to the bitwise inclusive OR of + * @a target and @a value. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to OR. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_or(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise exclusive OR (XOR). + * + * @note @atomic_api + * + * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of + * @a target and @a value. + * + * @param target Address of atomic variable. + * @param value Value to XOR + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise AND. + * + * This routine atomically sets @a target to the bitwise AND of @a target + * and @a value. + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to AND. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_and(atomic_t *target, atomic_val_t value); + +/** + * @brief Atomic bitwise NAND. + * + * This routine atomically sets @a target to the bitwise NAND of @a target + * and @a value. (This operation is equivalent to target = ~(target & value).) + * + * @note @atomic_api + * + * @param target Address of atomic variable. + * @param value Value to NAND. + * + * @return Previous value of @a target. + */ +atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); + /** * @} */ diff --git a/include/zephyr/sys/atomic_arch.h b/include/zephyr/sys/atomic_arch.h index 7305743c4fb..1225a2e0970 100644 --- a/include/zephyr/sys/atomic_arch.h +++ b/include/zephyr/sys/atomic_arch.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021 Demant A/S + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +8,9 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_ARCH_H_ +#include +#include + /* Included from */ /* Arch specific atomic primitives */ diff --git a/include/zephyr/sys/atomic_builtin.h b/include/zephyr/sys/atomic_builtin.h index 43b40e8bed4..5b81a76f050 100644 --- a/include/zephyr/sys/atomic_builtin.h +++ b/include/zephyr/sys/atomic_builtin.h @@ -2,6 +2,7 @@ /* * Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,34 +10,15 @@ #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ #define ZEPHYR_INCLUDE_SYS_ATOMIC_BUILTIN_H_ +#include +#include + #ifdef __cplusplus extern "C" { #endif /* Included from */ -/** - * @addtogroup atomic_apis Atomic Services APIs - * @ingroup kernel_apis - * @{ - */ - -/** - * @brief Atomic compare-and-set. - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return true if @a new_value is written, false otherwise. - */ static inline bool atomic_cas(atomic_t *target, atomic_val_t old_value, atomic_val_t new_value) { @@ -45,22 +27,6 @@ static inline bool atomic_cas(atomic_t *target, atomic_val_t old_value, __ATOMIC_SEQ_CST); } -/** - * @brief Atomic compare-and-set with pointer values - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return true if @a new_value is written, false otherwise. - */ static inline bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_value, atomic_ptr_val_t new_value) { @@ -69,131 +35,36 @@ static inline bool atomic_ptr_cas(atomic_ptr_t *target, atomic_ptr_val_t old_val __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic addition. - * - * This routine performs an atomic addition on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to add. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) { return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic subtraction. - * - * This routine performs an atomic subtraction on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to subtract. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) { return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic increment. - * - * This routine performs an atomic increment by 1 on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_inc(atomic_t *target) { return atomic_add(target, 1); } -/** - * - * @brief Atomic decrement. - * - * This routine performs an atomic decrement by 1 on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_dec(atomic_t *target) { return atomic_sub(target, 1); } -/** - * - * @brief Atomic get. - * - * This routine performs an atomic read on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Value of @a target. - */ static inline atomic_val_t atomic_get(const atomic_t *target) { return __atomic_load_n(target, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get a pointer value - * - * This routine performs an atomic read on @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of pointer variable. - * - * @return Value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_get(const atomic_ptr_t *target) { return __atomic_load_n(target, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get-and-set. - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) { /* This builtin, as described by Intel, is not a traditional @@ -203,147 +74,41 @@ static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic get-and-set for pointer values - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_set(atomic_ptr_t *target, atomic_ptr_val_t value) { return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic clear. - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_clear(atomic_t *target) { return atomic_set(target, 0); } -/** - * - * @brief Atomic clear of a pointer value - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ static inline atomic_ptr_val_t atomic_ptr_clear(atomic_ptr_t *target) { return atomic_ptr_set(target, NULL); } -/** - * - * @brief Atomic bitwise inclusive OR. - * - * This routine atomically sets @a target to the bitwise inclusive OR of - * @a target and @a value. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to OR. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) { return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise exclusive OR (XOR). - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to XOR - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) { return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise AND. - * - * This routine atomically sets @a target to the bitwise AND of @a target - * and @a value. - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to AND. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) { return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); } -/** - * - * @brief Atomic bitwise NAND. - * - * This routine atomically sets @a target to the bitwise NAND of @a target - * and @a value. (This operation is equivalent to target = ~(target & value).) - * - * @note As for all atomic APIs, includes a - * full/sequentially-consistent memory barrier (where applicable). - * - * @param target Address of atomic variable. - * @param value Value to NAND. - * - * @return Previous value of @a target. - */ static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) { return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST); } -/** @} */ - - #ifdef __cplusplus } #endif diff --git a/include/zephyr/sys/atomic_c.h b/include/zephyr/sys/atomic_c.h index 0ea6e6dfa34..f1e23caf362 100644 --- a/include/zephyr/sys/atomic_c.h +++ b/include/zephyr/sys/atomic_c.h @@ -72,7 +72,26 @@ __syscall atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value); #endif #ifdef CONFIG_ATOMIC_OPERATIONS_C + +#ifndef DISABLE_SYSCALL_TRACING +/* Skip defining macros of atomic_*() for syscall tracing. + * Compiler does not like "({ ... tracing code ... })" and complains + * + * error: expected identifier or '(' before '{' token + * + * ... even though there is a '(' before '{'. + */ +#define DISABLE_SYSCALL_TRACING +#define _REMOVE_DISABLE_SYSCALL_TRACING +#endif + #include + +#ifdef _REMOVE_DISABLE_SYSCALL_TRACING +#undef DISABLE_SYSCALL_TRACING +#undef _REMOVE_DISABLE_SYSCALL_TRACING +#endif + #endif #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_C_H_ */ diff --git a/include/zephyr/sys/atomic_types.h b/include/zephyr/sys/atomic_types.h new file mode 100644 index 00000000000..33935971f50 --- /dev/null +++ b/include/zephyr/sys/atomic_types.h @@ -0,0 +1,24 @@ +/* Copyright (c) 1997-2015, Wind River Systems, Inc. + * Copyright (c) 2021 Intel Corporation + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ +#define ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long atomic_t; +typedef atomic_t atomic_val_t; +typedef void *atomic_ptr_t; +typedef atomic_ptr_t atomic_ptr_val_t; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_TYPES_H_ */ diff --git a/include/zephyr/sys/byteorder.h b/include/zephyr/sys/byteorder.h index 978255fd02d..d1f839f5188 100644 --- a/include/zephyr/sys/byteorder.h +++ b/include/zephyr/sys/byteorder.h @@ -16,22 +16,21 @@ #include #include -/* Internal helpers only used by the sys_* APIs further below */ -#define __bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) -#define __bswap_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \ +#define BSWAP_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))) +#define BSWAP_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \ (((x)) & 0xff00) | \ (((x) & 0xff) << 16))) -#define __bswap_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \ +#define BSWAP_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \ (((x) >> 8) & 0xff00) | \ (((x) & 0xff00) << 8) | \ (((x) & 0xff) << 24))) -#define __bswap_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \ +#define BSWAP_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \ (((x) >> 24) & 0xff00) | \ (((x) >> 8) & 0xff0000) | \ (((x) & 0xff0000) << 8) | \ (((x) & 0xff00) << 24) | \ (((x) & 0xff) << 40))) -#define __bswap_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \ +#define BSWAP_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \ (((x) >> 40) & 0xff00) | \ (((x) >> 24) & 0xff0000) | \ (((x) >> 8) & 0xff000000) | \ @@ -222,16 +221,16 @@ #define sys_cpu_to_le48(val) (val) #define sys_le64_to_cpu(val) (val) #define sys_cpu_to_le64(val) (val) -#define sys_be16_to_cpu(val) __bswap_16(val) -#define sys_cpu_to_be16(val) __bswap_16(val) -#define sys_be24_to_cpu(val) __bswap_24(val) -#define sys_cpu_to_be24(val) __bswap_24(val) -#define sys_be32_to_cpu(val) __bswap_32(val) -#define sys_cpu_to_be32(val) __bswap_32(val) -#define sys_be48_to_cpu(val) __bswap_48(val) -#define sys_cpu_to_be48(val) __bswap_48(val) -#define sys_be64_to_cpu(val) __bswap_64(val) -#define sys_cpu_to_be64(val) __bswap_64(val) +#define sys_be16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_be16(val) BSWAP_16(val) +#define sys_be24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_be24(val) BSWAP_24(val) +#define sys_be32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_be32(val) BSWAP_32(val) +#define sys_be48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_be48(val) BSWAP_48(val) +#define sys_be64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_be64(val) BSWAP_64(val) #define sys_uint16_to_array(val) { \ ((val) & 0xff), \ @@ -254,16 +253,16 @@ (((val) >> 56) & 0xff)} #else -#define sys_le16_to_cpu(val) __bswap_16(val) -#define sys_cpu_to_le16(val) __bswap_16(val) -#define sys_le24_to_cpu(val) __bswap_24(val) -#define sys_cpu_to_le24(val) __bswap_24(val) -#define sys_le32_to_cpu(val) __bswap_32(val) -#define sys_cpu_to_le32(val) __bswap_32(val) -#define sys_le48_to_cpu(val) __bswap_48(val) -#define sys_cpu_to_le48(val) __bswap_48(val) -#define sys_le64_to_cpu(val) __bswap_64(val) -#define sys_cpu_to_le64(val) __bswap_64(val) +#define sys_le16_to_cpu(val) BSWAP_16(val) +#define sys_cpu_to_le16(val) BSWAP_16(val) +#define sys_le24_to_cpu(val) BSWAP_24(val) +#define sys_cpu_to_le24(val) BSWAP_24(val) +#define sys_le32_to_cpu(val) BSWAP_32(val) +#define sys_cpu_to_le32(val) BSWAP_32(val) +#define sys_le48_to_cpu(val) BSWAP_48(val) +#define sys_cpu_to_le48(val) BSWAP_48(val) +#define sys_le64_to_cpu(val) BSWAP_64(val) +#define sys_cpu_to_le64(val) BSWAP_64(val) #define sys_be16_to_cpu(val) (val) #define sys_cpu_to_be16(val) (val) #define sys_be24_to_cpu(val) (val) diff --git a/include/zephyr/sys/cbprintf_cxx.h b/include/zephyr/sys/cbprintf_cxx.h index 3b65b229517..1930e18b7d4 100644 --- a/include/zephyr/sys/cbprintf_cxx.h +++ b/include/zephyr/sys/cbprintf_cxx.h @@ -139,6 +139,115 @@ static inline int z_cbprintf_cxx_is_word_num(T arg) _Pragma("GCC diagnostic pop") } +/* C++ version for determining if argument is a none character pointer. */ +static inline int z_cbprintf_cxx_is_none_char_ptr(char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned short) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned int) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned long long) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(float) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(double) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(volatile unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const unsigned char *) +{ + return 0; +} + +static inline int z_cbprintf_cxx_is_none_char_ptr(const volatile unsigned char *) +{ + return 0; +} + +template < typename T > +static inline int z_cbprintf_cxx_is_none_char_ptr(T arg) +{ + ARG_UNUSED(arg); + + return 1; +} + /* C++ version for calculating argument size. */ static inline size_t z_cbprintf_cxx_arg_size(float f) { diff --git a/include/zephyr/sys/cbprintf_internal.h b/include/zephyr/sys/cbprintf_internal.h index eed2bbc3944..51b99494b96 100644 --- a/include/zephyr/sys/cbprintf_internal.h +++ b/include/zephyr/sys/cbprintf_internal.h @@ -138,6 +138,356 @@ extern "C" { 0) #endif +/** @brief Check if argument is a none character pointer. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param x Input argument. + * + * @retval 1 if variable is a none character pointer. + * @retval 0 if variable is of different type. + */ +#ifdef __cplusplus +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) z_cbprintf_cxx_is_none_char_ptr(x) +#else +#define Z_CBPRINTF_IS_NONE_CHAR_PTR(x) \ + _Generic((x) + 0, \ + char * : 0, \ + volatile char * : 0, \ + const char * : 0, \ + const volatile char * : 0, \ + unsigned char * : 0, \ + volatile unsigned char * : 0, \ + const unsigned char * : 0, \ + const volatile unsigned char * : 0, \ + char: 0, \ + unsigned char: 0, \ + short: 0, \ + unsigned short: 0, \ + int: 0, \ + unsigned int: 0,\ + long: 0, \ + unsigned long: 0,\ + long long: 0, \ + unsigned long long: 0, \ + float: 0, \ + double: 0, \ + default : \ + 1) +#endif + +/** @brief Get number of none character pointers in the string with at least 1 argument. + * + * @param ... String with at least 1 argument. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_ARGS(...) \ + (FOR_EACH(Z_CBPRINTF_IS_NONE_CHAR_PTR, (+), __VA_ARGS__)) \ + +/** @brief Get number of none character pointers in the string argument list. + * + * @param ... Format string with arguments. + * + * @return Number of none character pointer arguments. + */ +#define Z_CBPRINTF_NONE_CHAR_PTR_COUNT(...) \ + COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \ + (0), \ + (Z_CBPRINTF_NONE_CHAR_PTR_ARGS(GET_ARGS_LESS_N(1, __VA_ARGS__)))) + +/** @brief Calculate number of pointer format specifiers in the string. + * + * If constant string is provided then result is calculated at compile time + * however for it is not consider constant by the compiler, e.g. can not be + * used in the static assert. + * + * String length is limited to 256. + * + * @param fmt Format string. + * @param ... String arguments. + * + * @return Number of %p format specifiers in the string. + */ +#define Z_CBPRINTF_P_COUNT(fmt, ...) \ + ((sizeof(fmt) >= 2 && fmt[0] == '%' && fmt[1] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 3 && fmt[0] != '%' && fmt[1] == '%' && fmt[2] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 4 && fmt[1] != '%' && fmt[2] == '%' && fmt[3] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 5 && fmt[2] != '%' && fmt[3] == '%' && fmt[4] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 6 && fmt[3] != '%' && fmt[4] == '%' && fmt[5] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 7 && fmt[4] != '%' && fmt[5] == '%' && fmt[6] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 8 && fmt[5] != '%' && fmt[6] == '%' && fmt[7] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 9 && fmt[6] != '%' && fmt[7] == '%' && fmt[8] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 10 && fmt[7] != '%' && fmt[8] == '%' && fmt[9] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 11 && fmt[8] != '%' && fmt[9] == '%' && fmt[10] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 12 && fmt[9] != '%' && fmt[10] == '%' && fmt[11] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 13 && fmt[10] != '%' && fmt[11] == '%' && fmt[12] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 14 && fmt[11] != '%' && fmt[12] == '%' && fmt[13] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 15 && fmt[12] != '%' && fmt[13] == '%' && fmt[14] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 16 && fmt[13] != '%' && fmt[14] == '%' && fmt[15] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 17 && fmt[14] != '%' && fmt[15] == '%' && fmt[16] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 18 && fmt[15] != '%' && fmt[16] == '%' && fmt[17] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 19 && fmt[16] != '%' && fmt[17] == '%' && fmt[18] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 20 && fmt[17] != '%' && fmt[18] == '%' && fmt[19] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 21 && fmt[18] != '%' && fmt[19] == '%' && fmt[20] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 22 && fmt[19] != '%' && fmt[20] == '%' && fmt[21] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 23 && fmt[20] != '%' && fmt[21] == '%' && fmt[22] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 24 && fmt[21] != '%' && fmt[22] == '%' && fmt[23] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 25 && fmt[22] != '%' && fmt[23] == '%' && fmt[24] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 26 && fmt[23] != '%' && fmt[24] == '%' && fmt[25] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 27 && fmt[24] != '%' && fmt[25] == '%' && fmt[26] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 28 && fmt[25] != '%' && fmt[26] == '%' && fmt[27] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 29 && fmt[26] != '%' && fmt[27] == '%' && fmt[28] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 30 && fmt[27] != '%' && fmt[28] == '%' && fmt[29] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 31 && fmt[28] != '%' && fmt[29] == '%' && fmt[30] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 32 && fmt[29] != '%' && fmt[30] == '%' && fmt[31] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 33 && fmt[30] != '%' && fmt[31] == '%' && fmt[32] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 34 && fmt[31] != '%' && fmt[32] == '%' && fmt[33] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 35 && fmt[32] != '%' && fmt[33] == '%' && fmt[34] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 36 && fmt[33] != '%' && fmt[34] == '%' && fmt[35] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 37 && fmt[34] != '%' && fmt[35] == '%' && fmt[36] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 38 && fmt[35] != '%' && fmt[36] == '%' && fmt[37] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 39 && fmt[36] != '%' && fmt[37] == '%' && fmt[38] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 40 && fmt[37] != '%' && fmt[38] == '%' && fmt[39] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 41 && fmt[38] != '%' && fmt[39] == '%' && fmt[40] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 42 && fmt[39] != '%' && fmt[40] == '%' && fmt[41] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 43 && fmt[40] != '%' && fmt[41] == '%' && fmt[42] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 44 && fmt[41] != '%' && fmt[42] == '%' && fmt[43] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 45 && fmt[42] != '%' && fmt[43] == '%' && fmt[44] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 46 && fmt[43] != '%' && fmt[44] == '%' && fmt[45] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 47 && fmt[44] != '%' && fmt[45] == '%' && fmt[46] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 48 && fmt[45] != '%' && fmt[46] == '%' && fmt[47] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 49 && fmt[46] != '%' && fmt[47] == '%' && fmt[48] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 50 && fmt[47] != '%' && fmt[48] == '%' && fmt[49] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 51 && fmt[48] != '%' && fmt[49] == '%' && fmt[50] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 52 && fmt[49] != '%' && fmt[50] == '%' && fmt[51] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 53 && fmt[50] != '%' && fmt[51] == '%' && fmt[52] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 54 && fmt[51] != '%' && fmt[52] == '%' && fmt[53] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 55 && fmt[52] != '%' && fmt[53] == '%' && fmt[54] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 56 && fmt[53] != '%' && fmt[54] == '%' && fmt[55] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 57 && fmt[54] != '%' && fmt[55] == '%' && fmt[56] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 58 && fmt[55] != '%' && fmt[56] == '%' && fmt[57] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 59 && fmt[56] != '%' && fmt[57] == '%' && fmt[58] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 60 && fmt[57] != '%' && fmt[58] == '%' && fmt[59] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 61 && fmt[58] != '%' && fmt[59] == '%' && fmt[60] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 62 && fmt[59] != '%' && fmt[60] == '%' && fmt[61] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 63 && fmt[60] != '%' && fmt[61] == '%' && fmt[62] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 64 && fmt[61] != '%' && fmt[62] == '%' && fmt[63] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 65 && fmt[62] != '%' && fmt[63] == '%' && fmt[64] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 66 && fmt[63] != '%' && fmt[64] == '%' && fmt[65] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 67 && fmt[64] != '%' && fmt[65] == '%' && fmt[66] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 68 && fmt[65] != '%' && fmt[66] == '%' && fmt[67] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 69 && fmt[66] != '%' && fmt[67] == '%' && fmt[68] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 70 && fmt[67] != '%' && fmt[68] == '%' && fmt[69] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 71 && fmt[68] != '%' && fmt[69] == '%' && fmt[70] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 72 && fmt[69] != '%' && fmt[70] == '%' && fmt[71] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 73 && fmt[70] != '%' && fmt[71] == '%' && fmt[72] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 74 && fmt[71] != '%' && fmt[72] == '%' && fmt[73] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 75 && fmt[72] != '%' && fmt[73] == '%' && fmt[74] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 76 && fmt[73] != '%' && fmt[74] == '%' && fmt[75] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 77 && fmt[74] != '%' && fmt[75] == '%' && fmt[76] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 78 && fmt[75] != '%' && fmt[76] == '%' && fmt[77] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 79 && fmt[76] != '%' && fmt[77] == '%' && fmt[78] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 80 && fmt[77] != '%' && fmt[78] == '%' && fmt[79] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 81 && fmt[78] != '%' && fmt[79] == '%' && fmt[80] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 82 && fmt[79] != '%' && fmt[80] == '%' && fmt[81] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 83 && fmt[80] != '%' && fmt[81] == '%' && fmt[82] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 84 && fmt[81] != '%' && fmt[82] == '%' && fmt[83] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 85 && fmt[82] != '%' && fmt[83] == '%' && fmt[84] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 86 && fmt[83] != '%' && fmt[84] == '%' && fmt[85] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 87 && fmt[84] != '%' && fmt[85] == '%' && fmt[86] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 88 && fmt[85] != '%' && fmt[86] == '%' && fmt[87] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 89 && fmt[86] != '%' && fmt[87] == '%' && fmt[88] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 90 && fmt[87] != '%' && fmt[88] == '%' && fmt[89] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 91 && fmt[88] != '%' && fmt[89] == '%' && fmt[90] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 92 && fmt[89] != '%' && fmt[90] == '%' && fmt[91] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 93 && fmt[90] != '%' && fmt[91] == '%' && fmt[92] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 94 && fmt[91] != '%' && fmt[92] == '%' && fmt[93] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 95 && fmt[92] != '%' && fmt[93] == '%' && fmt[94] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 96 && fmt[93] != '%' && fmt[94] == '%' && fmt[95] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 97 && fmt[94] != '%' && fmt[95] == '%' && fmt[96] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 98 && fmt[95] != '%' && fmt[96] == '%' && fmt[97] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 99 && fmt[96] != '%' && fmt[97] == '%' && fmt[98] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 100 && fmt[97] != '%' && fmt[98] == '%' && fmt[99] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 101 && fmt[98] != '%' && fmt[99] == '%' && fmt[100] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 102 && fmt[99] != '%' && fmt[100] == '%' && fmt[101] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 103 && fmt[100] != '%' && fmt[101] == '%' && fmt[102] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 104 && fmt[101] != '%' && fmt[102] == '%' && fmt[103] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 105 && fmt[102] != '%' && fmt[103] == '%' && fmt[104] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 106 && fmt[103] != '%' && fmt[104] == '%' && fmt[105] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 107 && fmt[104] != '%' && fmt[105] == '%' && fmt[106] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 108 && fmt[105] != '%' && fmt[106] == '%' && fmt[107] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 109 && fmt[106] != '%' && fmt[107] == '%' && fmt[108] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 110 && fmt[107] != '%' && fmt[108] == '%' && fmt[109] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 111 && fmt[108] != '%' && fmt[109] == '%' && fmt[110] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 112 && fmt[109] != '%' && fmt[110] == '%' && fmt[111] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 113 && fmt[110] != '%' && fmt[111] == '%' && fmt[112] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 114 && fmt[111] != '%' && fmt[112] == '%' && fmt[113] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 115 && fmt[112] != '%' && fmt[113] == '%' && fmt[114] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 116 && fmt[113] != '%' && fmt[114] == '%' && fmt[115] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 117 && fmt[114] != '%' && fmt[115] == '%' && fmt[116] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 118 && fmt[115] != '%' && fmt[116] == '%' && fmt[117] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 119 && fmt[116] != '%' && fmt[117] == '%' && fmt[118] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 120 && fmt[117] != '%' && fmt[118] == '%' && fmt[119] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 121 && fmt[118] != '%' && fmt[119] == '%' && fmt[120] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 122 && fmt[119] != '%' && fmt[120] == '%' && fmt[121] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 123 && fmt[120] != '%' && fmt[121] == '%' && fmt[122] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 124 && fmt[121] != '%' && fmt[122] == '%' && fmt[123] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 125 && fmt[122] != '%' && fmt[123] == '%' && fmt[124] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 126 && fmt[123] != '%' && fmt[124] == '%' && fmt[125] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 127 && fmt[124] != '%' && fmt[125] == '%' && fmt[126] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 128 && fmt[125] != '%' && fmt[126] == '%' && fmt[127] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 129 && fmt[126] != '%' && fmt[127] == '%' && fmt[128] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 130 && fmt[127] != '%' && fmt[128] == '%' && fmt[129] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 131 && fmt[128] != '%' && fmt[129] == '%' && fmt[130] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 132 && fmt[129] != '%' && fmt[130] == '%' && fmt[131] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 133 && fmt[130] != '%' && fmt[131] == '%' && fmt[132] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 134 && fmt[131] != '%' && fmt[132] == '%' && fmt[133] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 135 && fmt[132] != '%' && fmt[133] == '%' && fmt[134] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 136 && fmt[133] != '%' && fmt[134] == '%' && fmt[135] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 137 && fmt[134] != '%' && fmt[135] == '%' && fmt[136] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 138 && fmt[135] != '%' && fmt[136] == '%' && fmt[137] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 139 && fmt[136] != '%' && fmt[137] == '%' && fmt[138] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 140 && fmt[137] != '%' && fmt[138] == '%' && fmt[139] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 141 && fmt[138] != '%' && fmt[139] == '%' && fmt[140] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 142 && fmt[139] != '%' && fmt[140] == '%' && fmt[141] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 143 && fmt[140] != '%' && fmt[141] == '%' && fmt[142] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 144 && fmt[141] != '%' && fmt[142] == '%' && fmt[143] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 145 && fmt[142] != '%' && fmt[143] == '%' && fmt[144] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 146 && fmt[143] != '%' && fmt[144] == '%' && fmt[145] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 147 && fmt[144] != '%' && fmt[145] == '%' && fmt[146] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 148 && fmt[145] != '%' && fmt[146] == '%' && fmt[147] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 149 && fmt[146] != '%' && fmt[147] == '%' && fmt[148] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 150 && fmt[147] != '%' && fmt[148] == '%' && fmt[149] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 151 && fmt[148] != '%' && fmt[149] == '%' && fmt[150] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 152 && fmt[149] != '%' && fmt[150] == '%' && fmt[151] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 153 && fmt[150] != '%' && fmt[151] == '%' && fmt[152] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 154 && fmt[151] != '%' && fmt[152] == '%' && fmt[153] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 155 && fmt[152] != '%' && fmt[153] == '%' && fmt[154] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 156 && fmt[153] != '%' && fmt[154] == '%' && fmt[155] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 157 && fmt[154] != '%' && fmt[155] == '%' && fmt[156] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 158 && fmt[155] != '%' && fmt[156] == '%' && fmt[157] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 159 && fmt[156] != '%' && fmt[157] == '%' && fmt[158] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 160 && fmt[157] != '%' && fmt[158] == '%' && fmt[159] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 161 && fmt[158] != '%' && fmt[159] == '%' && fmt[160] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 162 && fmt[159] != '%' && fmt[160] == '%' && fmt[161] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 163 && fmt[160] != '%' && fmt[161] == '%' && fmt[162] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 164 && fmt[161] != '%' && fmt[162] == '%' && fmt[163] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 165 && fmt[162] != '%' && fmt[163] == '%' && fmt[164] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 166 && fmt[163] != '%' && fmt[164] == '%' && fmt[165] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 167 && fmt[164] != '%' && fmt[165] == '%' && fmt[166] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 168 && fmt[165] != '%' && fmt[166] == '%' && fmt[167] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 169 && fmt[166] != '%' && fmt[167] == '%' && fmt[168] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 170 && fmt[167] != '%' && fmt[168] == '%' && fmt[169] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 171 && fmt[168] != '%' && fmt[169] == '%' && fmt[170] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 172 && fmt[169] != '%' && fmt[170] == '%' && fmt[171] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 173 && fmt[170] != '%' && fmt[171] == '%' && fmt[172] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 174 && fmt[171] != '%' && fmt[172] == '%' && fmt[173] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 175 && fmt[172] != '%' && fmt[173] == '%' && fmt[174] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 176 && fmt[173] != '%' && fmt[174] == '%' && fmt[175] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 177 && fmt[174] != '%' && fmt[175] == '%' && fmt[176] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 178 && fmt[175] != '%' && fmt[176] == '%' && fmt[177] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 179 && fmt[176] != '%' && fmt[177] == '%' && fmt[178] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 180 && fmt[177] != '%' && fmt[178] == '%' && fmt[179] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 181 && fmt[178] != '%' && fmt[179] == '%' && fmt[180] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 182 && fmt[179] != '%' && fmt[180] == '%' && fmt[181] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 183 && fmt[180] != '%' && fmt[181] == '%' && fmt[182] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 184 && fmt[181] != '%' && fmt[182] == '%' && fmt[183] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 185 && fmt[182] != '%' && fmt[183] == '%' && fmt[184] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 186 && fmt[183] != '%' && fmt[184] == '%' && fmt[185] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 187 && fmt[184] != '%' && fmt[185] == '%' && fmt[186] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 188 && fmt[185] != '%' && fmt[186] == '%' && fmt[187] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 189 && fmt[186] != '%' && fmt[187] == '%' && fmt[188] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 190 && fmt[187] != '%' && fmt[188] == '%' && fmt[189] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 191 && fmt[188] != '%' && fmt[189] == '%' && fmt[190] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 192 && fmt[189] != '%' && fmt[190] == '%' && fmt[191] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 193 && fmt[190] != '%' && fmt[191] == '%' && fmt[192] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 194 && fmt[191] != '%' && fmt[192] == '%' && fmt[193] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 195 && fmt[192] != '%' && fmt[193] == '%' && fmt[194] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 196 && fmt[193] != '%' && fmt[194] == '%' && fmt[195] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 197 && fmt[194] != '%' && fmt[195] == '%' && fmt[196] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 198 && fmt[195] != '%' && fmt[196] == '%' && fmt[197] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 199 && fmt[196] != '%' && fmt[197] == '%' && fmt[198] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 200 && fmt[197] != '%' && fmt[198] == '%' && fmt[199] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 201 && fmt[198] != '%' && fmt[199] == '%' && fmt[200] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 202 && fmt[199] != '%' && fmt[200] == '%' && fmt[201] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 203 && fmt[200] != '%' && fmt[201] == '%' && fmt[202] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 204 && fmt[201] != '%' && fmt[202] == '%' && fmt[203] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 205 && fmt[202] != '%' && fmt[203] == '%' && fmt[204] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 206 && fmt[203] != '%' && fmt[204] == '%' && fmt[205] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 207 && fmt[204] != '%' && fmt[205] == '%' && fmt[206] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 208 && fmt[205] != '%' && fmt[206] == '%' && fmt[207] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 209 && fmt[206] != '%' && fmt[207] == '%' && fmt[208] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 210 && fmt[207] != '%' && fmt[208] == '%' && fmt[209] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 211 && fmt[208] != '%' && fmt[209] == '%' && fmt[210] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 212 && fmt[209] != '%' && fmt[210] == '%' && fmt[211] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 213 && fmt[210] != '%' && fmt[211] == '%' && fmt[212] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 214 && fmt[211] != '%' && fmt[212] == '%' && fmt[213] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 215 && fmt[212] != '%' && fmt[213] == '%' && fmt[214] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 216 && fmt[213] != '%' && fmt[214] == '%' && fmt[215] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 217 && fmt[214] != '%' && fmt[215] == '%' && fmt[216] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 218 && fmt[215] != '%' && fmt[216] == '%' && fmt[217] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 219 && fmt[216] != '%' && fmt[217] == '%' && fmt[218] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 220 && fmt[217] != '%' && fmt[218] == '%' && fmt[219] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 221 && fmt[218] != '%' && fmt[219] == '%' && fmt[220] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 222 && fmt[219] != '%' && fmt[220] == '%' && fmt[221] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 223 && fmt[220] != '%' && fmt[221] == '%' && fmt[222] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 224 && fmt[221] != '%' && fmt[222] == '%' && fmt[223] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 225 && fmt[222] != '%' && fmt[223] == '%' && fmt[224] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 226 && fmt[223] != '%' && fmt[224] == '%' && fmt[225] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 227 && fmt[224] != '%' && fmt[225] == '%' && fmt[226] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 228 && fmt[225] != '%' && fmt[226] == '%' && fmt[227] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 229 && fmt[226] != '%' && fmt[227] == '%' && fmt[228] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 230 && fmt[227] != '%' && fmt[228] == '%' && fmt[229] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 231 && fmt[228] != '%' && fmt[229] == '%' && fmt[230] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 232 && fmt[229] != '%' && fmt[230] == '%' && fmt[231] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 233 && fmt[230] != '%' && fmt[231] == '%' && fmt[232] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 234 && fmt[231] != '%' && fmt[232] == '%' && fmt[233] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 235 && fmt[232] != '%' && fmt[233] == '%' && fmt[234] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 236 && fmt[233] != '%' && fmt[234] == '%' && fmt[235] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 237 && fmt[234] != '%' && fmt[235] == '%' && fmt[236] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 238 && fmt[235] != '%' && fmt[236] == '%' && fmt[237] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 239 && fmt[236] != '%' && fmt[237] == '%' && fmt[238] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 240 && fmt[237] != '%' && fmt[238] == '%' && fmt[239] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 241 && fmt[238] != '%' && fmt[239] == '%' && fmt[240] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 242 && fmt[239] != '%' && fmt[240] == '%' && fmt[241] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 243 && fmt[240] != '%' && fmt[241] == '%' && fmt[242] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 244 && fmt[241] != '%' && fmt[242] == '%' && fmt[243] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 245 && fmt[242] != '%' && fmt[243] == '%' && fmt[244] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 246 && fmt[243] != '%' && fmt[244] == '%' && fmt[245] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 247 && fmt[244] != '%' && fmt[245] == '%' && fmt[246] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 248 && fmt[245] != '%' && fmt[246] == '%' && fmt[247] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 249 && fmt[246] != '%' && fmt[247] == '%' && fmt[248] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 250 && fmt[247] != '%' && fmt[248] == '%' && fmt[249] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 251 && fmt[248] != '%' && fmt[249] == '%' && fmt[250] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 252 && fmt[249] != '%' && fmt[250] == '%' && fmt[251] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 253 && fmt[250] != '%' && fmt[251] == '%' && fmt[252] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 254 && fmt[251] != '%' && fmt[252] == '%' && fmt[253] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 255 && fmt[252] != '%' && fmt[253] == '%' && fmt[254] == 'p') ? 1 : 0) + \ + ((sizeof(fmt) >= 256 && fmt[253] != '%' && fmt[254] == '%' && fmt[255] == 'p') ? 1 : 0) + +/** @brief Determine if all %p arguments are none character pointer arguments. + * + * Static package creation relies on the assumption that character pointers are + * only using %s arguments. To not confuse it with %p, any character pointer + * that is used with %p should be casted to a pointer of a different type, e.g. + * void *. This macro can be used to determine, at compile time, if such casting + * is missing. It is determined at compile time but cannot be used for static + * assertion so only runtime error reporting can be added. + * + * @note Macro triggers a pointer arithmetic warning and usage shall be wrapped in + * the pragma that suppresses this warning. + * + * @param ... Format string with arguments. + * + * @retval True if string is okay. + * @retval False if casting is missing. + */ +#define Z_CBPRINTF_POINTERS_VALIDATE(...) \ + (Z_CBPRINTF_NONE_CHAR_PTR_COUNT(__VA_ARGS__) == \ + Z_CBPRINTF_P_COUNT(GET_ARG_N(1, __VA_ARGS__))) + /* @brief Check if argument is a certain type of char pointer. What exectly is checked * depends on @p flags. If flags is 0 then 1 is returned if @p x is a char pointer. * diff --git a/include/zephyr/sys/iterable_sections.h b/include/zephyr/sys/iterable_sections.h index fe1976363ca..3ec4af5e9a0 100644 --- a/include/zephyr/sys/iterable_sections.h +++ b/include/zephyr/sys/iterable_sections.h @@ -234,6 +234,16 @@ extern "C" { #define STRUCT_SECTION_ITERABLE_NAMED(struct_type, name, varname) \ TYPE_SECTION_ITERABLE(struct struct_type, varname, struct_type, name) +/** + * @brief Defines a new element for an iterable section with a custom name, + * placed in a custom section. + * + * The name can be used to customize how iterable section entries are sorted. + * @see STRUCT_SECTION_ITERABLE_NAMED() + */ +#define STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(struct_type, secname, name, varname) \ + TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, name) + /** * @brief Iterate over a specified iterable section (alternate). * diff --git a/include/zephyr/sys/kobject.h b/include/zephyr/sys/kobject.h index 628bb967551..50577ac7c02 100644 --- a/include/zephyr/sys/kobject.h +++ b/include/zephyr/sys/kobject.h @@ -195,7 +195,7 @@ static inline bool k_object_is_valid(const void *obj, enum k_objects otype) /* LCOV_EXCL_STOP */ #endif /* !CONFIG_USERSPACE */ -#ifdef CONFIG_DYNAMIC_OBJECTS +#if defined(CONFIG_DYNAMIC_OBJECTS) || defined(__DOXYGEN__) /** * Allocate a kernel object of a designated type * @@ -204,6 +204,9 @@ static inline bool k_object_is_valid(const void *obj, enum k_objects otype) * state, with the calling thread being granted permission on it. The memory * for the object will be allocated out of the calling thread's resource pool. * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @note Thread stack object has to use k_object_alloc_size() since stacks may * have different sizes. * @@ -224,6 +227,9 @@ __syscall void *k_object_alloc(enum k_objects otype); * This function is specially helpful for thread stack objects because * their sizes can vary. Other objects should probably look k_object_alloc(). * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @param otype Requested kernel object type * @param size Requested kernel object size * @return A pointer to the allocated kernel object, or NULL if memory wasn't @@ -238,6 +244,9 @@ __syscall void *k_object_alloc_size(enum k_objects otype, size_t size); * allocated from. Care must be exercised that the object will not be used * during or after when this call is made. * + * @note This function is available only if @kconfig{CONFIG_DYNAMIC_OBJECTS} + * is selected. + * * @param obj Pointer to the kernel object memory address. */ void k_object_free(void *obj); diff --git a/include/zephyr/sys/mem_manage.h b/include/zephyr/sys/mem_manage.h index 850a1376eaf..a05b72d3886 100644 --- a/include/zephyr/sys/mem_manage.h +++ b/include/zephyr/sys/mem_manage.h @@ -7,8 +7,6 @@ #ifndef ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H #define ZEPHYR_INCLUDE_SYS_MEM_MANAGE_H -#include - /** * @brief Memory Management * @defgroup memory_management Memory Management diff --git a/include/zephyr/sys/multi_heap.h b/include/zephyr/sys/multi_heap.h index 1eebc1c150e..0b8c56bdbe0 100644 --- a/include/zephyr/sys/multi_heap.h +++ b/include/zephyr/sys/multi_heap.h @@ -58,7 +58,7 @@ struct sys_multi_heap_rec { }; struct sys_multi_heap { - int nheaps; + unsigned int nheaps; sys_multi_heap_fn_t choice; struct sys_multi_heap_rec heaps[MAX_MULTI_HEAPS]; }; diff --git a/include/zephyr/sys/time_units.h b/include/zephyr/sys/time_units.h index 7f2db1a1f55..62c199bc488 100644 --- a/include/zephyr/sys/time_units.h +++ b/include/zephyr/sys/time_units.h @@ -135,15 +135,26 @@ static inline int z_impl_sys_clock_hw_cycles_per_sec_runtime_get(void) (__round_up) ? ((__from_hz) / (__to_hz)) - 1 : \ 0) -/* Clang emits a divide-by-zero warning even though the int_div macro - * results are only used when the divisor will not be zero. Work - * around this by substituting 1 to make the compiler happy. +/* + * All users of this macro MUST ensure its output is never used when a/b + * is zero because it incorrectly but by design never returns zero. + * + * Some compiler versions emit a divide-by-zero warning for this code: + * "false ? 42/0 : 43". Dealing with (generated) dead code is hard: + * https://github.com/zephyrproject-rtos/zephyr/issues/63564 + * https://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html + * + * To silence such divide-by-zero warnings, "cheat" and never return + * zero. Return 1 instead. Use octal "01u" as a breadcrumb to ease a + * little bit the huge pain of "reverse-engineering" pre-processor + * output. + * + * The "Elvis" operator "a/b ?: 1" is tempting because it avoids + * evaluating the same expression twice. However: 1. it's a non-standard + * GNU extension; 2. everything in this file is designed to be computed + * at compile time anyway. */ -#ifdef __clang__ -#define z_tmcvt_divisor(a, b) ((a) / (b) ?: 1) -#else -#define z_tmcvt_divisor(a, b) ((a) / (b)) -#endif +#define z_tmcvt_divisor(a, b) ((a)/(b) ? (a)/(b) : 01u) /* * Compute the offset needed to round the result correctly when diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index a812ee4d37e..71ed1f7f45d 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -202,6 +202,24 @@ extern "C" { (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) / sizeof((array)[0]); \ }) +/** + * @brief Iterate over members of an array using an index variable + * + * @param array the array in question + * @param idx name of array index variable + */ +#define ARRAY_FOR_EACH(array, idx) for (size_t idx = 0; (idx) < ARRAY_SIZE(array); ++(idx)) + +/** + * @brief Iterate over members of an array using a pointer + * + * @param array the array in question + * @param ptr pointer to an element of @p array + */ +#define ARRAY_FOR_EACH_PTR(array, ptr) \ + for (__typeof__(*(array)) *ptr = (array); (size_t)((ptr) - (array)) < ARRAY_SIZE(array); \ + ++(ptr)) + /** * @brief Validate if two entities have a compatible type * @@ -251,13 +269,18 @@ extern "C" { }) /** - * @brief Concatenate two tokens into one + * @brief Concatenate input arguments * - * Concatenate two tokens, @p x and @p y, into a combined token during the preprocessor pass. - * This can be used to, for ex., build an identifier out of two parts, + * Concatenate provided tokens into a combined token during the preprocessor pass. + * This can be used to, for ex., build an identifier out of multiple parts, * where one of those parts may be, for ex, a number, another macro, or a macro argument. + * + * @param ... Tokens to concatencate + * + * @return Concatenated token. */ -#define CONCAT(x, y) _DO_CONCAT(x, y) +#define CONCAT(...) \ + UTIL_CAT(_CONCAT_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__) /** * @brief Value of @p x rounded up to the next multiple of @p align. @@ -639,6 +662,45 @@ char *utf8_lcpy(char *dst, const char *src, size_t n); (((buflen) != 0) && \ ((UINTPTR_MAX - (uintptr_t)(addr)) <= ((uintptr_t)((buflen) - 1)))) +/** + * @brief XOR n bytes + * + * @param dst Destination of where to store result. Shall be @p len bytes. + * @param src1 First source. Shall be @p len bytes. + * @param src2 Second source. Shall be @p len bytes. + * @param len Number of bytes to XOR. + */ +static inline void mem_xor_n(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, size_t len) +{ + while (len--) { + *dst++ = *src1++ ^ *src2++; + } +} + +/** + * @brief XOR 32 bits + * + * @param dst Destination of where to store result. Shall be 32 bits. + * @param src1 First source. Shall be 32 bits. + * @param src2 Second source. Shall be 32 bits. + */ +static inline void mem_xor_32(uint8_t dst[4], const uint8_t src1[4], const uint8_t src2[4]) +{ + mem_xor_n(dst, src1, src2, 4U); +} + +/** + * @brief XOR 128 bits + * + * @param dst Destination of where to store result. Shall be 128 bits. + * @param src1 First source. Shall be 128 bits. + * @param src2 Second source. Shall be 128 bits. + */ +static inline void mem_xor_128(uint8_t dst[16], const uint8_t src1[16], const uint8_t src2[16]) +{ + mem_xor_n(dst, src1, src2, 16); +} + #ifdef __cplusplus } #endif diff --git a/include/zephyr/sys/util_internal.h b/include/zephyr/sys/util_internal.h index 2cde08332e2..d3adca60640 100644 --- a/include/zephyr/sys/util_internal.h +++ b/include/zephyr/sys/util_internal.h @@ -116,6 +116,15 @@ #define UTIL_EXPAND(...) __VA_ARGS__ #define UTIL_REPEAT(...) UTIL_LISTIFY(__VA_ARGS__) +#define _CONCAT_0(arg, ...) arg +#define _CONCAT_1(arg, ...) UTIL_CAT(arg, _CONCAT_0(__VA_ARGS__)) +#define _CONCAT_2(arg, ...) UTIL_CAT(arg, _CONCAT_1(__VA_ARGS__)) +#define _CONCAT_3(arg, ...) UTIL_CAT(arg, _CONCAT_2(__VA_ARGS__)) +#define _CONCAT_4(arg, ...) UTIL_CAT(arg, _CONCAT_3(__VA_ARGS__)) +#define _CONCAT_5(arg, ...) UTIL_CAT(arg, _CONCAT_4(__VA_ARGS__)) +#define _CONCAT_6(arg, ...) UTIL_CAT(arg, _CONCAT_5(__VA_ARGS__)) +#define _CONCAT_7(arg, ...) UTIL_CAT(arg, _CONCAT_6(__VA_ARGS__)) + /* Implementation details for NUM_VA_ARGS_LESS_1 */ #define NUM_VA_ARGS_LESS_1_IMPL( \ _ignored, \ diff --git a/include/zephyr/sys/util_loops.h b/include/zephyr/sys/util_loops.h index ff64e7b1ef9..8c71edd16f3 100644 --- a/include/zephyr/sys/util_loops.h +++ b/include/zephyr/sys/util_loops.h @@ -408,7 +408,7 @@ Z_FOR_LOOP_3, \ Z_FOR_LOOP_2, \ Z_FOR_LOOP_1, \ - Z_FOR_LOOP_0)(x, sep, fixed_arg0, fixed_arg1, ##__VA_ARGS__) + Z_FOR_LOOP_0)(x, sep, fixed_arg0, fixed_arg1, __VA_ARGS__) #define Z_GET_ARG_1(_0, ...) _0 diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index 02d0e9885a6..81df23f9150 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -223,6 +223,30 @@ extern "C" { #define IF_ENABLED(_flag, _code) \ COND_CODE_1(_flag, _code, ()) +/** + * @brief Insert code if @p _flag is not defined as 1. + * + * This expands to nothing if @p _flag is defined and equal to 1; + * it expands to @p _code otherwise. + * + * Example: + * + * IF_DISABLED(CONFIG_FLAG, (uint32_t foo;)) + * + * If @p CONFIG_FLAG isn't defined or different than 1, this expands to: + * + * uint32_t foo; + * + * and to nothing otherwise. + * + * IF_DISABLED does the opposite of IF_ENABLED. + * + * @param _flag evaluated flag + * @param _code result if @p _flag does not expand to 1; must be in parentheses + */ +#define IF_DISABLED(_flag, _code) \ + COND_CODE_1(_flag, (), _code) + /** * @brief Check if a macro has a replacement expression * diff --git a/include/zephyr/timing/timing.h b/include/zephyr/timing/timing.h index bf9ee9033e9..a0c4a644abb 100644 --- a/include/zephyr/timing/timing.h +++ b/include/zephyr/timing/timing.h @@ -14,33 +14,253 @@ extern "C" { #endif +/** + * @brief Timing Measurement APIs + * @defgroup timing_api Timing Measurement APIs + * @ingroup os_services + * + * The timing measurement APIs can be used to obtain execution + * time of a section of code to aid in analysis and optimization. + * + * Please note that the timing functions may use a different timer + * than the default kernel timer, where the timer being used is + * specified by architecture, SoC or board configuration. + */ + +/** + * @brief SoC specific Timing Measurement APIs + * @defgroup timing_api_soc SoC specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using SoC specific timing measurement mechanism. + * + * @{ + */ + +/** + * @brief Initialize the timing subsystem on SoC. + * + * Perform the necessary steps to initialize the timing subsystem. + * + * @see timing_init() + */ void soc_timing_init(void); + +/** + * @brief Signal the start of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * will be gathered from this point forward. + * + * @see timing_start() + */ void soc_timing_start(void); + +/** + * @brief Signal the end of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * is no longer being gathered from this point forward. + * + * @see timing_stop() + */ void soc_timing_stop(void); + +/** + * @brief Return timing counter. + * + * @note Not all SoCs have timing counters with 64 bit precision. It + * is possible to see this value "go backwards" due to internal + * rollover. Timing code must be prepared to address the rollover + * (with SoC dependent code, e.g. by casting to a uint32_t before + * subtraction) or by using soc_timing_cycles_get() which is required + * to understand the distinction. + * + * @return Timing counter. + * + * @see timing_counter_get() + */ timing_t soc_timing_counter_get(void); + +/** + * @brief Get number of cycles between @p start and @p end. + * + * @note The raw numbers from counter need to be scaled to + * obtain actual number of cycles, or may roll over internally. + * This function computes a positive-definite interval between two + * returned cycle values. + * + * @param start Pointer to counter at start of a measured execution. + * @param end Pointer to counter at stop of a measured execution. + * @return Number of cycles between start and end. + * + * @see timing_cycles_get() + */ uint64_t soc_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end); + +/** + * @brief Get frequency of counter used (in Hz). + * + * @return Frequency of counter used for timing in Hz. + * + * @see timing_freq_get() + */ uint64_t soc_timing_freq_get(void); + +/** + * @brief Convert number of @p cycles into nanoseconds. + * + * @param cycles Number of cycles + * @return Converted time value + * + * @see timing_cycles_to_ns() + */ uint64_t soc_timing_cycles_to_ns(uint64_t cycles); + +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + * + * @see timing_cycles_to_ns_avg() + */ uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); + +/** + * @brief Get frequency of counter used (in MHz). + * + * @return Frequency of counter used for timing in MHz. + * + * @see timing_freq_get_mhz() + */ uint32_t soc_timing_freq_get_mhz(void); +/** + * @} + */ + +/** + * @brief Board specific Timing Measurement APIs + * @defgroup timing_api_board Board specific Timing Measurement APIs + * @ingroup timing_api + * + * Implements the necessary bits to support timing measurement + * using board specific timing measurement mechanism. + * + * @{ + */ + +/** + * @brief Initialize the timing subsystem. + * + * Perform the necessary steps to initialize the timing subsystem. + * + * @see timing_init() + */ void board_timing_init(void); + +/** + * @brief Signal the start of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * will be gathered from this point forward. + * + * @see timing_start() + */ void board_timing_start(void); + +/** + * @brief Signal the end of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * is no longer being gathered from this point forward. + * + * @see timing_stop() + */ void board_timing_stop(void); + +/** + * @brief Return timing counter. + * + * @note Not all timing counters have 64 bit precision. It is + * possible to see this value "go backwards" due to internal + * rollover. Timing code must be prepared to address the rollover + * (with board dependent code, e.g. by casting to a uint32_t before + * subtraction) or by using board_timing_cycles_get() which is required + * to understand the distinction. + * + * @return Timing counter. + * + * @see timing_counter_get() + */ timing_t board_timing_counter_get(void); + +/** + * @brief Get number of cycles between @p start and @p end. + * + * @note The raw numbers from counter need to be scaled to + * obtain actual number of cycles, or may roll over internally. + * This function computes a positive-definite interval between two + * returned cycle values. + * + * @param start Pointer to counter at start of a measured execution. + * @param end Pointer to counter at stop of a measured execution. + * @return Number of cycles between start and end. + * + * @see timing_cycles_get() + */ uint64_t board_timing_cycles_get(volatile timing_t *const start, volatile timing_t *const end); + +/** + * @brief Get frequency of counter used (in Hz). + * + * @return Frequency of counter used for timing in Hz. + * + * @see timing_freq_get() + */ uint64_t board_timing_freq_get(void); + +/** + * @brief Convert number of @p cycles into nanoseconds. + * + * @param cycles Number of cycles + * @return Converted time value + * + * @see timing_cycles_to_ns() + */ uint64_t board_timing_cycles_to_ns(uint64_t cycles); + +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + * + * @see timing_cycles_to_ns_avg() + */ uint64_t board_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); + +/** + * @brief Get frequency of counter used (in MHz). + * + * @return Frequency of counter used for timing in MHz. + * + * @see timing_freq_get_mhz() + */ uint32_t board_timing_freq_get_mhz(void); +/** + * @} + */ /** - * @brief Timing Measurement APIs - * @defgroup timing_api Timing APIs - * @ingroup os_services + * @addtogroup timing_api * @{ */ diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index d3dce3b253f..e086c644e87 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -648,7 +648,8 @@ do { \ * * @note Only supported for GCC >= 11.0.0 or Clang >= 7. */ -#if (TOOLCHAIN_GCC_VERSION >= 110000) || (TOOLCHAIN_CLANG_VERSION >= 70000) +#if (TOOLCHAIN_GCC_VERSION >= 110000) || \ + (defined(TOOLCHAIN_CLANG_VERSION) && (TOOLCHAIN_CLANG_VERSION >= 70000)) #define FUNC_NO_STACK_PROTECTOR __attribute__((no_stack_protector)) #else #define FUNC_NO_STACK_PROTECTOR diff --git a/include/zephyr/tracing/tracing.h b/include/zephyr/tracing/tracing.h index baf9632a30d..f1bbddeec51 100644 --- a/include/zephyr/tracing/tracing.h +++ b/include/zephyr/tracing/tracing.h @@ -1954,15 +1954,17 @@ /** * @brief Trace putting a device (asynchronously) call entry. * @param dev Device instance. + * @param delay Time to delay the operation */ -#define sys_port_trace_pm_device_runtime_put_async_enter(dev) +#define sys_port_trace_pm_device_runtime_put_async_enter(dev, delay) /** * @brief Trace putting a device (asynchronously) call exit. * @param dev Device instance. + * @param delay Time to delay the operation. * @param ret Return value. */ -#define sys_port_trace_pm_device_runtime_put_async_exit(dev, ret) +#define sys_port_trace_pm_device_runtime_put_async_exit(dev, delay, ret) /** * @brief Trace enabling device runtime PM call entry. diff --git a/include/zephyr/usb/class/usb_hid.h b/include/zephyr/usb/class/usb_hid.h index 8cc21e7a573..8fc380b970e 100644 --- a/include/zephyr/usb/class/usb_hid.h +++ b/include/zephyr/usb/class/usb_hid.h @@ -14,6 +14,7 @@ #define ZEPHYR_INCLUDE_USB_HID_CLASS_DEVICE_H_ #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/zephyr/usb/class/usbd_uac2.h b/include/zephyr/usb/class/usbd_uac2.h new file mode 100644 index 00000000000..477f8465266 --- /dev/null +++ b/include/zephyr/usb/class/usbd_uac2.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB Audio Class 2 device public header + * + * This header describes only class API interaction with application. + * The audio device itself is modelled with devicetree zephyr,uac2 compatible. + * + * This API is currently considered experimental. + */ + +#ifndef ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ +#define ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ + +#include + +#define UAC2_ENTITY_ID(node) \ + ({ \ + BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_PARENT(node), zephyr_uac2)); \ + UTIL_INC(DT_NODE_CHILD_IDX(node)); \ + }) + +/** + * @brief USB Audio 2 application event handlers + */ +struct uac2_ops { + /** + * @brief Start of Frame callback + * + * Notifies application about SOF event on the bus. + * + * @param dev USB Audio 2 device + * @param user_data Opaque user data pointer + */ + void (*sof_cb)(const struct device *dev, void *user_data); + /** + * @brief Terminal update callback + * + * Notifies application that host has enabled or disabled a terminal. + * + * @param dev USB Audio 2 device + * @param terminal Terminal ID linked to AudioStreaming interface + * @param enabled True if host enabled terminal, False otherwise + * @param microframes True if USB connection speed uses microframes + * @param user_data Opaque user data pointer + */ + void (*terminal_update_cb)(const struct device *dev, uint8_t terminal, + bool enabled, bool microframes, + void *user_data); + /** + * @brief Get receive buffer address + * + * USB stack calls this function to obtain receive buffer address for + * AudioStreaming interface. The buffer is owned by USB stack until + * @ref data_recv_cb callback is called. The buffer must be sufficiently + * aligned for use by UDC driver. + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID linked to AudioStreaming interface + * @param size Maximum number of bytes USB stack will write to buffer. + * @param user_data Opaque user data pointer + */ + void *(*get_recv_buf)(const struct device *dev, uint8_t terminal, + uint16_t size, void *user_data); + /** + * @brief Data received + * + * This function releases buffer obtained in @ref get_recv_buf after USB + * has written data to the buffer and/or no longer needs it. + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID linked to AudioStreaming interface + * @param buf Buffer previously obtained via @ref get_recv_buf + * @param size Number of bytes written to buffer + * @param user_data Opaque user data pointer + */ + void (*data_recv_cb)(const struct device *dev, uint8_t terminal, + void *buf, uint16_t size, void *user_data); + /** + * @brief Transmit buffer release callback + * + * This function releases buffer provided in @ref usbd_uac2_send when + * the class no longer needs it. + * + * @param dev USB Audio 2 device + * @param terminal Output Terminal ID linked to AudioStreaming interface + * @param buf Buffer previously provided via @ref usbd_uac2_send + * @param user_data Opaque user data pointer + */ + void (*buf_release_cb)(const struct device *dev, uint8_t terminal, + void *buf, void *user_data); + /** + * @brief Get Explicit Feedback value + * + * Explicit feedback value format depends terminal connection speed. + * If device is High-Speed capable, it must use Q16.16 format if and + * only if the @ref terminal_update_cb was called with microframes + * parameter set to true. On Full-Speed only devices, or if High-Speed + * capable device is operating at Full-Speed (microframes was false), + * the format is Q10.14 stored on 24 least significant bits (i.e. 8 most + * significant bits are ignored). + * + * @param dev USB Audio 2 device + * @param terminal Input Terminal ID whose feedback should be returned + * @param user_data Opaque user data pointer + */ + uint32_t (*feedback_cb)(const struct device *dev, uint8_t terminal, + void *user_data); +}; + +/** + * @brief Register USB Audio 2 application callbacks. + * + * @param dev USB Audio 2 device instance + * @param ops USB Audio 2 callback structure + * @param user_data Opaque user data to pass to ops callbacks + */ +void usbd_uac2_set_ops(const struct device *dev, + const struct uac2_ops *ops, void *user_data); + +/** + * @brief Send audio data to output terminal + * + * @param dev USB Audio 2 device + * @param terminal Output Terminal ID linked to AudioStreaming interface + * @param data Buffer containing outgoing data + * @param size Number of bytes to send + * + * @return 0 on success, negative value on error + */ +int usbd_uac2_send(const struct device *dev, uint8_t terminal, + void *data, uint16_t size); + +#endif /* ZEPHYR_INCLUDE_USB_CLASS_USBD_UAC2_H_ */ diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index aad53b47550..7d9798b90fb 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -134,8 +134,8 @@ struct usbd_ch9_data { uint32_t ep_halt; /** USB device stack selected configuration */ uint8_t configuration; - /** Indicate new device address */ - bool new_address; + /** Post status stage work required, e.g. set new device address */ + bool post_status; /** Array to track interfaces alternate settings */ uint8_t alternate[USBD_NUMOF_INTERFACES_MAX]; }; @@ -226,6 +226,9 @@ struct usbd_class_api { /** USB power management handler resumed */ void (*resumed)(struct usbd_class_node *const node); + /** Start of Frame */ + void (*sof)(struct usbd_class_node *const node); + /** Class associated configuration is selected */ void (*enable)(struct usbd_class_node *const node); @@ -701,37 +704,18 @@ int usbd_device_set_pid(struct usbd_contex *const uds_ctx, const uint16_t pid); /** - * @brief Set USB device descriptor value bDeviceClass - * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceClass value - * - * @return 0 on success, other values on fail. - */ -int usbd_device_set_class(struct usbd_contex *const uds_ctx, - const uint8_t value); - -/** - * @brief Set USB device descriptor value bDeviceSubClass + * @brief Set USB device descriptor code triple Base Class, SubClass, and Protocol * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceSubClass value - * - * @return 0 on success, other values on fail. - */ -int usbd_device_set_subclass(struct usbd_contex *const uds_ctx, - const uint8_t value); - -/** - * @brief Set USB device descriptor value bDeviceProtocol - * - * @param[in] uds_ctx Pointer to USB device support context - * @param[in] value bDeviceProtocol value + * @param[in] uds_ctx Pointer to USB device support context + * @param[in] base_class bDeviceClass value + * @param[in] subclass bDeviceSubClass value + * @param[in] protocol bDeviceProtocol value * * @return 0 on success, other values on fail. */ -int usbd_device_set_proto(struct usbd_contex *const uds_ctx, - const uint8_t value); +int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, + const uint8_t base_class, + const uint8_t subclass, const uint8_t protocol); /** * @brief Setup USB device configuration attribute Remote Wakeup diff --git a/include/zephyr/zbus/zbus.h b/include/zephyr/zbus/zbus.h index 285338d4732..2c0c0622aed 100644 --- a/include/zephyr/zbus/zbus.h +++ b/include/zephyr/zbus/zbus.h @@ -38,10 +38,17 @@ struct zbus_channel_data { */ int16_t observers_end_idx; - /** Access control mutex. Points to the mutex used to avoid race conditions + /** Access control semaphore. Points to the semaphore used to avoid race conditions * for accessing the channel. */ - struct k_mutex mutex; + struct k_sem sem; + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + /** Highest observer priority. Indicates the priority that the VDED will use to boost the + * notification process avoiding preemptions. + */ + int highest_observer_priority; +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ #if defined(CONFIG_ZBUS_RUNTIME_OBSERVERS) || defined(__DOXYGEN__) /** Channel observer list. Represents the channel's observers list, it can be empty @@ -96,6 +103,16 @@ enum __packed zbus_observer_type { ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, }; +struct zbus_observer_data { + /** Enabled flag. Indicates if observer is receiving notification. */ + bool enabled; + +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) + /** Subscriber attached thread priority. */ + int priority; +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ +}; + /** * @brief Type used to represent an observer. * @@ -119,8 +136,8 @@ struct zbus_observer { /** Type indication. */ enum zbus_observer_type type; - /** Enabled flag. Indicates if observer is receiving notification. */ - bool enabled; + /** Mutable observer data struct. */ + struct zbus_observer_data *const data; union { /** Observer message queue. It turns the observer into a subscriber. */ @@ -154,6 +171,8 @@ struct zbus_channel_observation { #define _ZBUS_CPP_EXTERN #endif /* __cplusplus */ +#define ZBUS_MIN_THREAD_PRIORITY (CONFIG_NUM_PREEMPT_PRIORITIES - 1) + #if defined(CONFIG_ZBUS_ASSERT_MOCK) #define _ZBUS_ASSERT(_cond, _fmt, ...) \ do { \ @@ -233,6 +252,7 @@ struct zbus_channel_observation { /** @endcond */ +/* clang-format off */ /** * @brief Add a static channel observervation. * @@ -246,11 +266,15 @@ struct zbus_channel_observation { */ #define ZBUS_CHAN_ADD_OBS_WITH_MASK(_chan, _obs, _masked, _prio) \ const STRUCT_SECTION_ITERABLE(zbus_channel_observation, \ - _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \ - .chan = &_chan, .obs = &_obs}; \ + _CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs))) = { \ + .chan = &_chan, \ + .obs = &_obs, \ + }; \ STRUCT_SECTION_ITERABLE(zbus_channel_observation_mask, \ _CONCAT(_CONCAT(_CONCAT(_chan, zz), _CONCAT(_prio, _obs)), \ _mask)) = {.enabled = _masked} +/* clang-format on */ + /** * @brief Add a static channel observervation. * @@ -290,6 +314,7 @@ struct zbus_channel_observation { */ #define ZBUS_OBSERVERS(...) __VA_ARGS__ +/* clang-format off */ /** * @brief Zbus channel definition. * @@ -305,20 +330,29 @@ struct zbus_channel_observation { * first the highest priority. * @param _init_val The message initialization. */ -#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ - static _type _CONCAT(_zbus_message_, _name) = _init_val; \ - static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ - .observers_start_idx = -1, .observers_end_idx = -1}; \ - static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ - _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ - ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ - .message = &_CONCAT(_zbus_message_, _name), \ - .message_size = sizeof(_type), .user_data = _user_data, .validator = (_validator), \ - .data = &_CONCAT(_zbus_chan_data_, _name)}; \ - /* Extern declaration of observers */ \ - ZBUS_OBS_DECLARE(_observers); \ - /* Create all channel observations from observers list */ \ +#define ZBUS_CHAN_DEFINE(_name, _type, _validator, _user_data, _observers, _init_val) \ + static _type _CONCAT(_zbus_message_, _name) = _init_val; \ + static struct zbus_channel_data _CONCAT(_zbus_chan_data_, _name) = { \ + .observers_start_idx = -1, \ + .observers_end_idx = -1, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .highest_observer_priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + static K_MUTEX_DEFINE(_CONCAT(_zbus_mutex_, _name)); \ + _ZBUS_CPP_EXTERN const STRUCT_SECTION_ITERABLE(zbus_channel, _name) = { \ + ZBUS_CHANNEL_NAME_INIT(_name) /* Maybe removed */ \ + .message = &_CONCAT(_zbus_message_, _name), \ + .message_size = sizeof(_type), \ + .user_data = _user_data, \ + .validator = _validator, \ + .data = &_CONCAT(_zbus_chan_data_, _name), \ + }; \ + /* Extern declaration of observers */ \ + ZBUS_OBS_DECLARE(_observers); \ + /* Create all channel observations from observers list */ \ FOR_EACH_FIXED_ARG_NONEMPTY_TERM(_ZBUS_CHAN_OBSERVATION, (;), _name, _observers) +/* clang-format on */ /** * @brief Initialize a message. @@ -334,6 +368,7 @@ struct zbus_channel_observation { _val, ##__VA_ARGS__ \ } +/* clang-format off */ /** * @brief Define and initialize a subscriber. * @@ -345,13 +380,25 @@ struct zbus_channel_observation { * @param[in] _queue_size The notification queue's size. * @param[in] _enable The subscriber initial enable state. */ -#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \ - K_MSGQ_DEFINE(_zbus_observer_queue_##_name, sizeof(const struct zbus_channel *), \ - _queue_size, sizeof(const struct zbus_channel *)); \ - STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ - ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \ - .enabled = _enable, .queue = &_zbus_observer_queue_##_name} +#define ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, _enable) \ + K_MSGQ_DEFINE(_zbus_observer_queue_##_name, \ + sizeof(const struct zbus_channel *), \ + _queue_size, sizeof(const struct zbus_channel *) \ + ); \ + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_SUBSCRIBER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .queue = &_zbus_observer_queue_##_name, \ + } +/* clang-format on */ + /** * @brief Define and initialize a subscriber. * @@ -366,6 +413,7 @@ struct zbus_channel_observation { #define ZBUS_SUBSCRIBER_DEFINE(_name, _queue_size) \ ZBUS_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _queue_size, true) +/* clang-format off */ /** * @brief Define and initialize a listener. * @@ -378,10 +426,20 @@ struct zbus_channel_observation { * @param[in] _enable The listener initial enable state. */ #define ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, _enable) \ - STRUCT_SECTION_ITERABLE(zbus_observer, \ - _name) = {ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_LISTENER_TYPE, \ - .enabled = _enable, .callback = (_cb)} + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_LISTENER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .callback = (_cb) \ + } +/* clang-format on */ + /** * @brief Define and initialize a listener. * @@ -394,6 +452,7 @@ struct zbus_channel_observation { */ #define ZBUS_LISTENER_DEFINE(_name, _cb) ZBUS_LISTENER_DEFINE_WITH_ENABLE(_name, _cb, true) +/* clang-format off */ /** * @brief Define and initialize a message subscriber. * @@ -404,14 +463,21 @@ struct zbus_channel_observation { * @param[in] _name The subscriber's name. * @param[in] _enable The subscriber's initial state. */ -#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \ - static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \ - STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ - ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ - .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \ - .enabled = _enable, \ - .message_fifo = &_zbus_observer_fifo_##_name, \ +#define ZBUS_MSG_SUBSCRIBER_DEFINE_WITH_ENABLE(_name, _enable) \ + static K_FIFO_DEFINE(_zbus_observer_fifo_##_name); \ + static struct zbus_observer_data _CONCAT(_zbus_obs_data_, _name) = { \ + .enabled = _enable, \ + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, ( \ + .priority = ZBUS_MIN_THREAD_PRIORITY, \ + )) \ + }; \ + STRUCT_SECTION_ITERABLE(zbus_observer, _name) = { \ + ZBUS_OBSERVER_NAME_INIT(_name) /* Name field */ \ + .type = ZBUS_OBSERVER_MSG_SUBSCRIBER_TYPE, \ + .data = &_CONCAT(_zbus_obs_data_, _name), \ + .message_fifo = &_zbus_observer_fifo_##_name, \ } +/* clang-format on */ /** * @brief Define and initialize an enabled message subscriber. @@ -501,8 +567,6 @@ int zbus_chan_claim(const struct zbus_channel *chan, k_timeout_t timeout); * @param chan The channel's reference. * * @retval 0 Channel finished. - * @retval -EPERM The channel was claimed by other thread. - * @retval -EINVAL The channel's mutex is not locked. * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. */ @@ -519,9 +583,9 @@ int zbus_chan_finish(const struct zbus_channel *chan); * or one of the special values K_NO_WAIT and K_FOREVER. * * @retval 0 Channel notified. - * @retval -EPERM The current thread does not own the channel. - * @retval -EBUSY The channel's mutex returned without waiting. - * @retval -EAGAIN Timeout to acquiring the channel's mutex. + * @retval -EBUSY The channel's semaphore returned without waiting. + * @retval -EAGAIN Timeout to take the channel's semaphore. + * @retval -ENOMEM There is not more buffer on the messgage buffers pool. * @retval -EFAULT A parameter is incorrect, the notification could not be sent to one or more * observer, or the function context is invalid (inside an ISR). The function only returns this * value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. @@ -553,7 +617,7 @@ static inline const char *zbus_chan_name(const struct zbus_channel *chan) * * This routine returns the reference of a channel message. * - * @warning This function must only be used directly for acquired (locked by mutex) channels. This + * @warning This function must only be used directly for already locked channels. This * can be done inside a listener for the receiving channel or after claim a channel. * * @param chan The channel's reference. @@ -574,7 +638,7 @@ static inline void *zbus_chan_msg(const struct zbus_channel *chan) * inside listeners to access the message directly. In this way zbus prevents the listener of * changing the notifying channel's message during the notification process. * - * @warning This function must only be used directly for acquired (locked by mutex) channels. This + * @warning This function must only be used directly for already locked channels. This * can be done inside a listener for the receiving channel or after claim a channel. * * @param chan The channel's constant reference. @@ -685,14 +749,7 @@ struct zbus_observer_node { * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. */ -static inline int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled) -{ - _ZBUS_ASSERT(obs != NULL, "obs is required"); - - obs->enabled = enabled; - - return 0; -} +int zbus_obs_set_enable(struct zbus_observer *obs, bool enabled); /** * @brief Get the observer state. @@ -709,7 +766,7 @@ static inline int zbus_obs_is_enabled(struct zbus_observer *obs, bool *enable) _ZBUS_ASSERT(obs != NULL, "obs is required"); _ZBUS_ASSERT(enable != NULL, "enable is required"); - *enable = obs->enabled; + *enable = obs->data->enabled; return 0; } @@ -766,6 +823,32 @@ static inline const char *zbus_obs_name(const struct zbus_observer *obs) #endif +#if defined(CONFIG_ZBUS_PRIORITY_BOOST) || defined(__DOXYGEN__) + +/** + * @brief Set the observer thread priority by attaching it to a thread. + * + * @param[in] obs The observer's reference. + * + * @retval 0 Observer detached from the thread. + * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The + * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. + */ +int zbus_obs_attach_to_thread(const struct zbus_observer *obs); + +/** + * @brief Clear the observer thread priority by detaching it from a thread. + * + * @param[in] obs The observer's reference. + * + * @retval 0 Observer detached from the thread. + * @retval -EFAULT A parameter is incorrect, or the function context is invalid (inside an ISR). The + * function only returns this value when the CONFIG_ZBUS_ASSERT_MOCK is enabled. + */ +int zbus_obs_detach_from_thread(const struct zbus_observer *obs); + +#endif /* CONFIG_ZBUS_PRIORITY_BOOST */ + /** * @brief Wait for a channel notification. * diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index bec410968cc..cd9f39c9558 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -59,6 +59,7 @@ list(APPEND kernel_files mem_slab.c thread.c version.c + sched.c ) if(CONFIG_MULTITHREADING) @@ -72,7 +73,6 @@ list(APPEND kernel_files stack.c system_work_q.c work.c - sched.c condvar.c ) @@ -117,8 +117,38 @@ target_sources_ifdef(CONFIG_OBJ_CORE kernel PRIVATE obj_core.c) if(${CONFIG_KERNEL_MEM_POOL}) target_sources(kernel PRIVATE mempool.c) -endif() + if(CONFIG_HEAP_MEM_POOL_IGNORE_MIN) + set(final_heap_size ${CONFIG_HEAP_MEM_POOL_SIZE}) + else() + # Import all custom HEAP_MEM_POOL size requirements + import_kconfig(CONFIG_HEAP_MEM_POOL_ADD_SIZE_ ${DOTCONFIG} add_size_keys) + + # Calculate the sum of all "ADD_SIZE" requirements + set(add_size_sum 0) + foreach(add_size ${add_size_keys}) + math(EXPR add_size_sum "${add_size_sum} + ${${add_size}}") + endforeach() + + if(CONFIG_HEAP_MEM_POOL_SIZE LESS "${add_size_sum}") + # Only warn if default value 0 has been modified + if(NOT CONFIG_HEAP_MEM_POOL_SIZE EQUAL 0) + message(WARNING " + CONFIG_HEAP_MEM_POOL_SIZE is less than requested minimum: + ${CONFIG_HEAP_MEM_POOL_SIZE} < ${add_size_sum} + Setting the system heap size to ${add_size_sum}") + endif() + + set(final_heap_size ${add_size_sum}) + else() + # CONFIG_HEAP_MEM_POOL_SIZE was greater than the sum of the requirements + set(final_heap_size ${CONFIG_HEAP_MEM_POOL_SIZE}) + endif() + + endif() + + zephyr_compile_definitions(K_HEAP_MEM_POOL_SIZE=${final_heap_size}) +endif() # The last 2 files inside the target_sources_ifdef should be # userspace_handler.c and userspace.c. If not the linker would complain. diff --git a/kernel/Kconfig b/kernel/Kconfig index 6280e80a400..1620a3c9aa4 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -288,6 +288,20 @@ config ERRNO_IN_TLS Use thread local storage to store errno instead of storing it in the kernel thread struct. This avoids a syscall if userspace is enabled. +config CURRENT_THREAD_USE_NO_TLS + bool + help + Hidden symbol to not use thread local storage to store current + thread. + +config CURRENT_THREAD_USE_TLS + bool "Store current thread in thread local storage (TLS)" + depends on THREAD_LOCAL_STORAGE && !CURRENT_THREAD_USE_NO_TLS + default y + help + Use thread local storage to store the current thread. This avoids a + syscall if userspace is enabled. + choice SCHED_ALGORITHM prompt "Scheduler priority queue algorithm" default SCHED_DUMB @@ -821,13 +835,28 @@ if KERNEL_MEM_POOL config HEAP_MEM_POOL_SIZE int "Heap memory pool size (in bytes)" - default 0 if !POSIX_MQUEUE - default 1024 if POSIX_MQUEUE + default 0 help This option specifies the size of the heap memory pool used when dynamically allocating memory using k_malloc(). The maximum size of - the memory pool is only limited to available memory. A size of zero - means that no heap memory pool is defined. + the memory pool is only limited to available memory. If subsystems + specify HEAP_MEM_POOL_ADD_SIZE_* options, these will be added together + and the sum will be compared to the HEAP_MEM_POOL_SIZE value. + If the sum is greater than the HEAP_MEM_POOL_SIZE option (even if this + has the default 0 value), then the actual heap size will be rounded up + to the sum of the individual requirements (unless the + HEAP_MEM_POOL_IGNORE_MIN option is enabled). If the final value, after + considering both this option as well as sum of the custom + requirements, ends up being zero, then no system heap will be + available. + +config HEAP_MEM_POOL_IGNORE_MIN + bool "Ignore the minimum heap memory pool requirement" + help + This option can be set to force setting a smaller heap memory pool + size than what's specified by enabled subsystems. This can be useful + when optimizing memory usage and a more precise minimum heap size + is known for a given application. endif # KERNEL_MEM_POOL @@ -1148,8 +1177,9 @@ config SMP_BOOT_DELAY depends on SMP help By default Zephyr will boot all available CPUs during start up. - Select this option to skip this and allow architecture code boot - secondary CPUs at a later time. + Select this option to skip this and allow custom code + (architecture/SoC/board/application) to boot secondary CPUs at + a later time. config MP_NUM_CPUS int "Number of CPUs/cores [DEPRECATED]" @@ -1260,6 +1290,13 @@ config DEVICE_DEPS_DYNAMIC Option that makes it possible to manipulate device dependencies at runtime. +config DEVICE_MUTABLE + bool "Mutable devices [EXPERIMENTAL]" + select EXPERIMENTAL + help + Support mutable devices. Mutable devices are instantiated in SRAM + instead of Flash and are runtime modifiable in kernel mode. + endmenu rsource "Kconfig.vm" diff --git a/kernel/busy_wait.c b/kernel/busy_wait.c index 4bb94ca04d5..cb7c993437d 100644 --- a/kernel/busy_wait.c +++ b/kernel/busy_wait.c @@ -21,13 +21,7 @@ void z_impl_k_busy_wait(uint32_t usec_to_wait) arch_busy_wait(usec_to_wait); #elif defined(CONFIG_SYS_CLOCK_EXISTS) uint32_t start_cycles = k_cycle_get_32(); - - /* use 64-bit math to prevent overflow when multiplying */ - uint32_t cycles_to_wait = (uint32_t)( - (uint64_t)usec_to_wait * - (uint64_t)sys_clock_hw_cycles_per_sec() / - (uint64_t)USEC_PER_SEC - ); + uint32_t cycles_to_wait = k_us_to_cyc_ceil32(usec_to_wait); for (;;) { uint32_t current_cycles = k_cycle_get_32(); diff --git a/kernel/dynamic.c b/kernel/dynamic.c index d30dba8ac02..b9d34cbb52c 100644 --- a/kernel/dynamic.c +++ b/kernel/dynamic.c @@ -7,6 +7,7 @@ #include "kernel_internal.h" #include +#include #include #include #include @@ -120,20 +121,14 @@ static void dyn_cb(const struct k_thread *thread, void *user_data) int z_impl_k_thread_stack_free(k_thread_stack_t *stack) { - char state_buf[16] = {0}; struct dyn_cb_data data = {.stack = stack}; /* Get a possible tid associated with stack */ k_thread_foreach(dyn_cb, &data); if (data.tid != NULL) { - /* Check if thread is in use */ - if (k_thread_state_str(data.tid, state_buf, sizeof(state_buf)) != state_buf) { - LOG_ERR("tid %p is invalid!", data.tid); - return -EINVAL; - } - - if (!(strcmp("dummy", state_buf) == 0) || (strcmp("dead", state_buf) == 0)) { + if (!(z_is_thread_state_set(data.tid, _THREAD_DUMMY) || + z_is_thread_state_set(data.tid, _THREAD_DEAD))) { LOG_ERR("tid %p is in use!", data.tid); return -EBUSY; } @@ -161,7 +156,7 @@ int z_impl_k_thread_stack_free(k_thread_stack_t *stack) k_free(stack); #endif } else { - LOG_ERR("Invalid stack %p", stack); + LOG_DBG("Invalid stack %p", stack); return -EINVAL; } diff --git a/kernel/fatal.c b/kernel/fatal.c index 7a3733cbfef..dae2eb60950 100644 --- a/kernel/fatal.c +++ b/kernel/fatal.c @@ -13,9 +13,7 @@ #include #include #include -#ifndef CONFIG_XTENSA #include -#endif LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); @@ -44,7 +42,7 @@ __weak void k_sys_fatal_error_handler(unsigned int reason, LOG_PANIC(); LOG_ERR("Halting system"); arch_system_halt(reason); - CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ + CODE_UNREACHABLE; } /* LCOV_EXCL_STOP */ @@ -115,9 +113,7 @@ void z_fatal_error(unsigned int reason, const z_arch_esf_t *esf) LOG_ERR("Current thread: %p (%s)", thread, thread_name_get(thread)); -#ifndef CONFIG_XTENSA coredump(reason, esf, thread); -#endif k_sys_fatal_error_handler(reason, esf); diff --git a/kernel/include/kernel_arch_interface.h b/kernel/include/kernel_arch_interface.h index 0173a4ae398..5d11521ab8b 100644 --- a/kernel/include/kernel_arch_interface.h +++ b/kernel/include/kernel_arch_interface.h @@ -560,7 +560,7 @@ int arch_printk_char_out(int c); /** * Architecture-specific kernel initialization hook * - * This function is invoked near the top of _Cstart, for additional + * This function is invoked near the top of z_cstart, for additional * architecture-specific setup before the rest of the kernel is brought up. */ static inline void arch_kernel_init(void); diff --git a/kernel/include/kernel_internal.h b/kernel/include/kernel_internal.h index 711313b5ce7..16efb3b54e8 100644 --- a/kernel/include/kernel_internal.h +++ b/kernel/include/kernel_internal.h @@ -24,6 +24,9 @@ extern "C" { #endif +/* Initialize per-CPU kernel data */ +void z_init_cpu(int id); + /* Initialize a thread */ void z_init_thread_base(struct _thread_base *thread_base, int priority, uint32_t initial_state, unsigned int options); diff --git a/kernel/include/kernel_offsets.h b/kernel/include/kernel_offsets.h index f7676438d9e..5644dbb1575 100644 --- a/kernel/include/kernel_offsets.h +++ b/kernel/include/kernel_offsets.h @@ -86,7 +86,7 @@ GEN_ABSOLUTE_SYM(_DEVICE_STRUCT_PM_OFFSET, /* member offsets in the pm_device structure. Used in image post-processing */ GEN_ABSOLUTE_SYM(_PM_DEVICE_STRUCT_FLAGS_OFFSET, - offsetof(struct pm_device, flags)); + offsetof(struct pm_device_base, flags)); GEN_ABSOLUTE_SYM(_PM_DEVICE_FLAG_PD, PM_DEVICE_FLAG_PD); diff --git a/kernel/include/kswap.h b/kernel/include/kswap.h index fa1e538b8e8..01a72744b00 100644 --- a/kernel/include/kswap.h +++ b/kernel/include/kswap.h @@ -250,7 +250,7 @@ static inline void z_dummy_thread_init(struct k_thread *dummy_thread) #ifdef CONFIG_USERSPACE dummy_thread->mem_domain_info.mem_domain = &k_mem_domain_default; #endif -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) k_thread_system_pool_assign(dummy_thread); #else dummy_thread->resource_pool = NULL; diff --git a/kernel/include/mmu.h b/kernel/include/mmu.h index cd290100e40..88795560e4c 100644 --- a/kernel/include/mmu.h +++ b/kernel/include/mmu.h @@ -186,7 +186,8 @@ static inline void *z_page_frame_to_virt(struct z_page_frame *pf) static inline bool z_is_page_frame(uintptr_t phys) { z_assert_phys_aligned(phys); - return (phys >= Z_PHYS_RAM_START) && (phys < Z_PHYS_RAM_END); + return IN_RANGE(phys, (uintptr_t)Z_PHYS_RAM_START, + (uintptr_t)(Z_PHYS_RAM_END - 1)); } static inline struct z_page_frame *z_phys_to_page_frame(uintptr_t phys) @@ -206,7 +207,12 @@ static inline void z_mem_assert_virtual_region(uint8_t *addr, size_t size) "unaligned size %zu", size); __ASSERT(!Z_DETECT_POINTER_OVERFLOW(addr, size), "region %p size %zu zero or wraps around", addr, size); - __ASSERT(addr >= Z_VIRT_RAM_START && addr + size < Z_VIRT_RAM_END, + __ASSERT(IN_RANGE((uintptr_t)addr, + (uintptr_t)Z_VIRT_RAM_START, + ((uintptr_t)Z_VIRT_RAM_END - 1)) && + IN_RANGE(((uintptr_t)addr + size - 1), + (uintptr_t)Z_VIRT_RAM_START, + ((uintptr_t)Z_VIRT_RAM_END - 1)), "invalid virtual address region %p (%zu)", addr, size); } @@ -215,9 +221,6 @@ static inline void z_mem_assert_virtual_region(uint8_t *addr, size_t size) */ void z_page_frames_dump(void); -/* Number of free page frames. This information may go stale immediately */ -extern size_t z_free_page_count; - /* Convenience macro for iterating over all page frames */ #define Z_PAGE_FRAME_FOREACH(_phys, _pageframe) \ for (_phys = Z_PHYS_RAM_START, _pageframe = z_page_frames; \ diff --git a/kernel/mempool.c b/kernel/mempool.c index 3cbfa201222..b3943b52728 100644 --- a/kernel/mempool.c +++ b/kernel/mempool.c @@ -56,9 +56,9 @@ void k_free(void *ptr) } } -#if (CONFIG_HEAP_MEM_POOL_SIZE > 0) +#if (K_HEAP_MEM_POOL_SIZE > 0) -K_HEAP_DEFINE(_system_heap, CONFIG_HEAP_MEM_POOL_SIZE); +K_HEAP_DEFINE(_system_heap, K_HEAP_MEM_POOL_SIZE); #define _SYSTEM_HEAP (&_system_heap) void *k_aligned_alloc(size_t align, size_t size) diff --git a/kernel/mmu.c b/kernel/mmu.c index 6abd9349dd6..cef9b5c18d2 100644 --- a/kernel/mmu.c +++ b/kernel/mmu.c @@ -20,6 +20,10 @@ #include LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL); +#ifdef CONFIG_DEMAND_PAGING +#include +#endif + /* * General terminology: * - A page frame is a page-sized physical memory region in RAM. It is a @@ -238,7 +242,7 @@ static void virt_region_free(void *vaddr, size_t size) } #ifndef CONFIG_KERNEL_DIRECT_MAP - /* Without the need to support K_DIRECT_MAP, the region must be + /* Without the need to support K_MEM_DIRECT_MAP, the region must be * able to be represented in the bitmap. So this case is * simple. */ @@ -255,7 +259,7 @@ static void virt_region_free(void *vaddr, size_t size) num_bits = size / CONFIG_MMU_PAGE_SIZE; (void)sys_bitarray_free(&virt_region_bitmap, num_bits, offset); #else /* !CONFIG_KERNEL_DIRECT_MAP */ - /* With K_DIRECT_MAP, the region can be outside of the virtual + /* With K_MEM_DIRECT_MAP, the region can be outside of the virtual * memory space, wholly within it, or overlap partially. * So additional processing is needed to make sure we only * mark the pages within the bitmap. @@ -377,8 +381,10 @@ static void *virt_region_alloc(size_t size, size_t align) */ static sys_slist_t free_page_frame_list; -/* Number of unused and available free page frames */ -size_t z_free_page_count; +/* Number of unused and available free page frames. + * This information may go stale immediately. + */ +static size_t z_free_page_count; #define PF_ASSERT(pf, expr, fmt, ...) \ __ASSERT(expr, "page frame 0x%lx: " fmt, z_page_frame_to_phys(pf), \ @@ -777,10 +783,13 @@ void z_phys_map(uint8_t **virt_ptr, uintptr_t phys, size_t size, uint32_t flags) * Basically if either end of region is within * virtual memory space, we need to mark the bits. */ - if (((dest_addr >= Z_VIRT_RAM_START) && - (dest_addr < Z_VIRT_RAM_END)) || - (((dest_addr + aligned_size) >= Z_VIRT_RAM_START) && - ((dest_addr + aligned_size) < Z_VIRT_RAM_END))) { + + if (IN_RANGE(aligned_phys, + (uintptr_t)Z_VIRT_RAM_START, + (uintptr_t)(Z_VIRT_RAM_END - 1)) || + IN_RANGE(aligned_phys + aligned_size - 1, + (uintptr_t)Z_VIRT_RAM_START, + (uintptr_t)(Z_VIRT_RAM_END - 1))) { uint8_t *adjusted_start = MAX(dest_addr, Z_VIRT_RAM_START); uint8_t *adjusted_end = MIN(dest_addr + aligned_size, Z_VIRT_RAM_END); diff --git a/kernel/paging/statistics.c b/kernel/paging/statistics.c index e8972738135..06e867cd218 100644 --- a/kernel/paging/statistics.c +++ b/kernel/paging/statistics.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include extern struct k_mem_paging_stats_t paging_stats; diff --git a/kernel/pipes.c b/kernel/pipes.c index 3fa1c72036d..355377c2a79 100644 --- a/kernel/pipes.c +++ b/kernel/pipes.c @@ -377,9 +377,9 @@ static size_t pipe_write(struct k_pipe *pipe, sys_dlist_t *src_list, return num_bytes_written; } -int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, - size_t *bytes_written, size_t min_xfer, - k_timeout_t timeout) +int z_impl_k_pipe_put(struct k_pipe *pipe, const void *data, + size_t bytes_to_write, size_t *bytes_written, + size_t min_xfer, k_timeout_t timeout) { struct _pipe_desc pipe_desc[2]; struct _pipe_desc isr_desc; @@ -445,7 +445,7 @@ int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, src_desc = k_is_in_isr() ? &isr_desc : &_current->pipe_desc; - src_desc->buffer = data; + src_desc->buffer = (unsigned char *)data; src_desc->bytes_to_xfer = bytes_to_write; src_desc->thread = _current; sys_dlist_append(&src_list, &src_desc->node); @@ -513,17 +513,17 @@ int z_impl_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, } #ifdef CONFIG_USERSPACE -int z_vrfy_k_pipe_put(struct k_pipe *pipe, void *data, size_t bytes_to_write, - size_t *bytes_written, size_t min_xfer, - k_timeout_t timeout) +int z_vrfy_k_pipe_put(struct k_pipe *pipe, const void *data, + size_t bytes_to_write, size_t *bytes_written, + size_t min_xfer, k_timeout_t timeout) { K_OOPS(K_SYSCALL_OBJ(pipe, K_OBJ_PIPE)); K_OOPS(K_SYSCALL_MEMORY_WRITE(bytes_written, sizeof(*bytes_written))); K_OOPS(K_SYSCALL_MEMORY_READ((void *)data, bytes_to_write)); - return z_impl_k_pipe_put((struct k_pipe *)pipe, (void *)data, - bytes_to_write, bytes_written, min_xfer, - timeout); + return z_impl_k_pipe_put((struct k_pipe *)pipe, data, + bytes_to_write, bytes_written, min_xfer, + timeout); } #include #endif diff --git a/kernel/sched.c b/kernel/sched.c index 7dd782c9490..bb009238d5d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1094,7 +1094,7 @@ void z_reschedule(struct k_spinlock *lock, k_spinlock_key_t key) void z_reschedule_irqlock(uint32_t key) { - if (resched(key)) { + if (resched(key) && need_swap()) { z_swap_irqlock(key); } else { irq_unlock(key); @@ -1527,26 +1527,28 @@ static inline void z_vrfy_k_yield(void) static int32_t z_tick_sleep(k_ticks_t ticks) { -#ifdef CONFIG_MULTITHREADING uint32_t expected_wakeup_ticks; __ASSERT(!arch_is_in_isr(), ""); LOG_DBG("thread %p for %lu ticks", _current, (unsigned long)ticks); +#ifdef CONFIG_MULTITHREADING /* wait of 0 ms is treated as a 'yield' */ if (ticks == 0) { k_yield(); return 0; } +#endif - k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks); if (Z_TICK_ABS(ticks) <= 0) { expected_wakeup_ticks = ticks + sys_clock_tick_get_32(); } else { expected_wakeup_ticks = Z_TICK_ABS(ticks); } +#ifdef CONFIG_MULTITHREADING + k_timeout_t timeout = Z_TIMEOUT_TICKS(ticks); k_spinlock_key_t key = k_spin_lock(&sched_spinlock); #if defined(CONFIG_TIMESLICING) && defined(CONFIG_SWAP_NONATOMIC) @@ -1564,6 +1566,9 @@ static int32_t z_tick_sleep(k_ticks_t ticks) if (ticks > 0) { return ticks; } +#else + /* busy wait to be time coherent since subsystems may depend on it */ + z_impl_k_busy_wait(k_ticks_to_us_ceil32(expected_wakeup_ticks)); #endif return 0; @@ -1579,8 +1584,12 @@ int32_t z_impl_k_sleep(k_timeout_t timeout) /* in case of K_FOREVER, we suspend */ if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { +#ifdef CONFIG_MULTITHREADING k_thread_suspend(_current); - +#else + /* In Single Thread, just wait for an interrupt saving power */ + k_cpu_idle(); +#endif SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, (int32_t) K_TICKS_FOREVER); return (int32_t) K_TICKS_FOREVER; @@ -1590,7 +1599,7 @@ int32_t z_impl_k_sleep(k_timeout_t timeout) ticks = z_tick_sleep(ticks); - int32_t ret = k_ticks_to_ms_floor64(ticks); + int32_t ret = k_ticks_to_ms_ceil64(ticks); SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ret); @@ -1614,9 +1623,11 @@ int32_t z_impl_k_usleep(int us) ticks = k_us_to_ticks_ceil64(us); ticks = z_tick_sleep(ticks); - SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, k_ticks_to_us_floor64(ticks)); + int32_t ret = k_ticks_to_us_ceil64(ticks); + + SYS_PORT_TRACING_FUNC_EXIT(k_thread, usleep, us, ret); - return k_ticks_to_us_floor64(ticks); + return ret; } #ifdef CONFIG_USERSPACE diff --git a/kernel/smp.c b/kernel/smp.c index dc30bd5f9ed..177362c6a7c 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -4,14 +4,56 @@ #include #include +#include #include #include #include static atomic_t global_lock; + +/** + * Flag to tell recently powered up CPU to start + * initialization routine. + * + * 0 to tell powered up CPU to wait. + * 1 to tell powered up CPU to continue initialization. + */ static atomic_t cpu_start_flag; + +/** + * Flag to tell caller that the target CPU is now + * powered up and ready to be initialized. + * + * 0 if target CPU is not yet ready. + * 1 if target CPU has powered up and ready to be initialized. + */ static atomic_t ready_flag; +/** + * Struct holding the function to be called before handing off + * to schedule and its argument. + */ +static struct cpu_start_cb { + /** + * Function to be called before handing off to scheduler. + * Can be NULL. + */ + smp_init_fn fn; + + /** Argument to @ref cpu_start_fn.fn. */ + void *arg; + + /** Invoke scheduler after CPU has started if true. */ + bool invoke_sched; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + /** True if smp_timer_init() needs to be called. */ + bool reinit_timer; +#endif +} cpu_start_fn; + +static struct k_spinlock cpu_start_lock; + unsigned int z_smp_global_lock(void) { unsigned int key = arch_irq_lock(); @@ -64,62 +106,137 @@ static void wait_for_start_signal(atomic_t *start_flag) } } -/* Legacy interfaces for early-version SOF CPU bringup. To be removed */ -#ifdef CONFIG_SOF -void z_smp_thread_init(void *arg, struct k_thread *thread) -{ - z_dummy_thread_init(thread); - wait_for_start_signal(arg); -} -void z_smp_thread_swap(void) -{ - z_swap_unlocked(); -} -#endif - -static inline FUNC_NORETURN void smp_init_top(void *arg) +static inline void smp_init_top(void *arg) { struct k_thread dummy_thread; + struct cpu_start_cb *csc = arg; + /* Let start_cpu() know that this CPU has powered up. */ (void)atomic_set(&ready_flag, 1); - wait_for_start_signal(arg); - z_dummy_thread_init(&dummy_thread); + /* Wait for the CPU start caller to signal that + * we can start initialization. + */ + wait_for_start_signal(&cpu_start_flag); + + if ((csc == NULL) || csc->invoke_sched) { + /* Initialize the dummy thread struct so that + * the scheduler can schedule actual threads to run. + */ + z_dummy_thread_init(&dummy_thread); + } + #ifdef CONFIG_SYS_CLOCK_EXISTS - smp_timer_init(); + if ((csc == NULL) || csc->reinit_timer) { + smp_timer_init(); + } #endif + /* Do additional initialization steps if needed. */ + if ((csc != NULL) && (csc->fn != NULL)) { + csc->fn(csc->arg); + } + + if ((csc != NULL) && !csc->invoke_sched) { + /* Don't invoke scheduler. */ + return; + } + + /* Let scheduler decide what thread to run next. */ z_swap_unlocked(); CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ } -static void start_cpu(int id, atomic_t *start_flag) +static void start_cpu(int id, struct cpu_start_cb *csc) { - z_init_cpu(id); + /* Clear the ready flag so the newly powered up CPU can + * signal that it has powered up. + */ (void)atomic_clear(&ready_flag); + + /* Power up the CPU */ arch_start_cpu(id, z_interrupt_stacks[id], CONFIG_ISR_STACK_SIZE, - smp_init_top, start_flag); + smp_init_top, csc); + + /* Wait until the newly powered up CPU to signal that + * it has powered up. + */ while (!atomic_get(&ready_flag)) { local_delay(); } } -void z_smp_start_cpu(int id) +void k_smp_cpu_start(int id, smp_init_fn fn, void *arg) { + k_spinlock_key_t key = k_spin_lock(&cpu_start_lock); + + cpu_start_fn.fn = fn; + cpu_start_fn.arg = arg; + cpu_start_fn.invoke_sched = true; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + cpu_start_fn.reinit_timer = true; +#endif + + /* We are only starting one CPU so we do not need to synchronize + * across all CPUs using the start_flag. So just set it to 1. + */ (void)atomic_set(&cpu_start_flag, 1); /* async, don't care */ - start_cpu(id, &cpu_start_flag); + + /* Initialize various CPU structs related to this CPU. */ + z_init_cpu(id); + + /* Start the CPU! */ + start_cpu(id, &cpu_start_fn); + + k_spin_unlock(&cpu_start_lock, key); +} + +void k_smp_cpu_resume(int id, smp_init_fn fn, void *arg, + bool reinit_timer, bool invoke_sched) +{ + k_spinlock_key_t key = k_spin_lock(&cpu_start_lock); + + cpu_start_fn.fn = fn; + cpu_start_fn.arg = arg; + cpu_start_fn.invoke_sched = invoke_sched; + +#ifdef CONFIG_SYS_CLOCK_EXISTS + cpu_start_fn.reinit_timer = reinit_timer; +#else + ARG_UNUSED(reinit_timer); +#endif + + /* We are only starting one CPU so we do not need to synchronize + * across all CPUs using the start_flag. So just set it to 1. + */ + (void)atomic_set(&cpu_start_flag, 1); + + /* Start the CPU! */ + start_cpu(id, &cpu_start_fn); + + k_spin_unlock(&cpu_start_lock, key); } void z_smp_init(void) { + /* We are powering up all CPUs and we want to synchronize their + * entry into scheduler. So set the start flag to 0 here. + */ (void)atomic_clear(&cpu_start_flag); + /* Just start CPUs one by one. */ unsigned int num_cpus = arch_num_cpus(); for (int i = 1; i < num_cpus; i++) { - start_cpu(i, &cpu_start_flag); + z_init_cpu(i); + start_cpu(i, NULL); } + + /* Let loose those CPUs so they can start scheduling + * threads to run. + */ (void)atomic_set(&cpu_start_flag, 1); } diff --git a/kernel/thread.c b/kernel/thread.c index fc31f4b36d8..51803c87f42 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -530,6 +530,15 @@ static char *setup_thread_stack(struct k_thread *new_thread, stack_obj_size = Z_KERNEL_STACK_SIZE_ADJUST(stack_size); stack_buf_start = Z_KERNEL_STACK_BUFFER(stack); stack_buf_size = stack_obj_size - K_KERNEL_STACK_RESERVED; + + /* Zephyr treats stack overflow as an app bug. But + * this particular overflow can be seen by static + * analysis so needs to be handled somehow. + */ + if (K_KERNEL_STACK_RESERVED > stack_obj_size) { + k_panic(); + } + } /* Initial stack pointer at the high end of the stack object, may diff --git a/kernel/timeout.c b/kernel/timeout.c index 16429bbba20..29f15898035 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -190,7 +190,7 @@ k_ticks_t z_timeout_expires(const struct _timeout *timeout) k_ticks_t ticks = 0; K_SPINLOCK(&timeout_lock) { - ticks = curr_tick + timeout_rem(timeout); + ticks = curr_tick + timeout_rem(timeout) + elapsed(); } return ticks; diff --git a/kernel/work.c b/kernel/work.c index c5d7c9b5bb8..a56aa67829c 100644 --- a/kernel/work.c +++ b/kernel/work.c @@ -63,18 +63,14 @@ static inline uint32_t flags_get(const uint32_t *flagp) static struct k_spinlock lock; /* Invoked by work thread */ -static void handle_flush(struct k_work *work) -{ - struct z_work_flusher *flusher - = CONTAINER_OF(work, struct z_work_flusher, work); - - k_sem_give(&flusher->sem); -} +static void handle_flush(struct k_work *work) { } static inline void init_flusher(struct z_work_flusher *flusher) { + struct k_work *work = &flusher->work; k_sem_init(&flusher->sem, 0, 1); k_work_init(&flusher->work, handle_flush); + flag_set(&work->flags, K_WORK_FLUSHING_BIT); } /* List of pending cancellations. */ @@ -96,6 +92,26 @@ static inline void init_work_cancel(struct z_work_canceller *canceler, sys_slist_append(&pending_cancels, &canceler->node); } +/* Comeplete flushing of a work item. + * + * Invoked with work lock held. + * + * Invoked from a work queue thread. + * + * Reschedules. + * + * @param work the work structure that has completed flushing. + */ +static void finalize_flush_locked(struct k_work *work) +{ + struct z_work_flusher *flusher + = CONTAINER_OF(work, struct z_work_flusher, work); + + flag_clear(&work->flags, K_WORK_FLUSHING_BIT); + + k_sem_give(&flusher->sem); +}; + /* Complete cancellation of a work item and unlock held lock. * * Invoked with work lock held. @@ -672,13 +688,16 @@ static void work_queue_main(void *workq_ptr, void *p2, void *p3) handler(work); /* Mark the work item as no longer running and deal - * with any cancellation issued while it was running. - * Clear the BUSY flag and optionally yield to prevent - * starving other threads. + * with any cancellation and flushing issued while it + * was running. Clear the BUSY flag and optionally + * yield to prevent starving other threads. */ key = k_spin_lock(&lock); flag_clear(&work->flags, K_WORK_RUNNING_BIT); + if (flag_test(&work->flags, K_WORK_FLUSHING_BIT)) { + finalize_flush_locked(work); + } if (flag_test(&work->flags, K_WORK_CANCELING_BIT)) { finalize_cancel_locked(work); } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 6fe18f63992..7a0ee04e4ac 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -6,11 +6,16 @@ add_compile_options($) add_subdirectory(crc) if(NOT CONFIG_EXTERNAL_LIBC) add_subdirectory(libc) +endif() +if(NOT CONFIG_NATIVE_LIBC) add_subdirectory(posix) endif() add_subdirectory_ifdef(CONFIG_CPP cpp) add_subdirectory(hash) +add_subdirectory(heap) +add_subdirectory(mem_blocks) add_subdirectory(os) +add_subdirectory(utils) add_subdirectory_ifdef(CONFIG_SMF smf) add_subdirectory_ifdef(CONFIG_OPENAMP open-amp) add_subdirectory_ifdef(CONFIG_ACPI acpi) diff --git a/lib/Kconfig b/lib/Kconfig index 97ee3f6002d..af6717bc22e 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -11,6 +11,10 @@ menu "Additional libraries" source "lib/hash/Kconfig" +source "lib/heap/Kconfig" + +source "lib/mem_blocks/Kconfig" + source "lib/os/Kconfig" source "lib/posix/Kconfig" @@ -22,4 +26,6 @@ source "lib/smf/Kconfig" source "lib/acpi/Kconfig" source "lib/runtime/Kconfig" + +source "lib/utils/Kconfig" endmenu diff --git a/lib/acpi/Kconfig b/lib/acpi/Kconfig index 42b35725c70..34710aad92c 100644 --- a/lib/acpi/Kconfig +++ b/lib/acpi/Kconfig @@ -16,12 +16,6 @@ source "subsys/logging/Kconfig.template.log_config" if PCIE_PRT -config ACPI_PRT_BUS_NAME - string "ACPI name of PCI bus" - default "_SB.PCI0" - help - ACPI name of PCI bus. - config ACPI_MAX_PRT_ENTRY int "Size of PRT buffer" default 4096 @@ -30,6 +24,10 @@ config ACPI_MAX_PRT_ENTRY endif # PCIE_PRT +# Default minimum system heap required by ACPI +config HEAP_MEM_POOL_ADD_SIZE_ACPI + def_int 1048576 # 1MB + config ACPI_SHELL bool "ACPI command Shell" depends on SHELL @@ -42,10 +40,16 @@ config ACPI_DEV_MAX help maximum acpi child devices. -endif # ACPI +config ACPI_IRQ_VECTOR_MAX + int "Interrupt vectors per device" + default 32 + help + Maximum interrupt vectors per device. -config ACPI_HID_LEN_MAX - int "Size of HID name" - default 12 +config ACPI_MMIO_ENTRIES_MAX + int "MMIO entries per device" + default 32 help - Size of HID string. + Maximum MMIO entries per device. + +endif # ACPI diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index 7d84b4e5d29..b3c1d717971 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -34,12 +34,12 @@ static int check_init_status(void) acpi.status = acpi_init(); } - if (ACPI_SUCCESS(acpi.status)) { - return 0; - } else { + if (ACPI_FAILURE(acpi.status)) { LOG_ERR("ACPI init was not success"); return -EIO; } + + return 0; } static void notify_handler(ACPI_HANDLE device, UINT32 value, void *ctx) @@ -216,6 +216,10 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev return AE_NO_MEMORY; } + if (!(dev_info->Valid & ACPI_VALID_HID)) { + goto exit; + } + child_dev = (struct acpi_dev *)&acpi.child_dev[acpi.num_dev++]; child_dev->handle = obj_handle; child_dev->dev_info = dev_info; @@ -241,7 +245,7 @@ static ACPI_STATUS dev_resource_enum_callback(ACPI_HANDLE obj_handle, UINT32 lev exit: - return status; + return AE_OK; } static int acpi_enum_devices(void) @@ -302,10 +306,10 @@ int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res) if (ACPI_FAILURE(status)) { LOG_ERR("AcpiGetCurrentResources failed: %s", AcpiFormatException(status)); return -ENOTSUP; - } else { - *res = rt_buffer.Pointer; } + *res = rt_buffer.Pointer; + return 0; } @@ -345,41 +349,69 @@ int acpi_current_resource_free(ACPI_RESOURCE *res) } #ifdef CONFIG_PCIE_PRT -static int acpi_get_irq_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, uint32_t rt_size) +uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf) { + uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin; + + LOG_DBG(""); + + if (check_init_status()) { + return UINT_MAX; + } + + pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3; + + LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin); + + for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { + if (((acpi.pci_prt_table[i].Address >> 16) & 0xffff) == slot && + acpi.pci_prt_table[i].Pin + 1 == pin) { + LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, + acpi.pci_prt_table[i].SourceIndex); + return acpi.pci_prt_table[i].SourceIndex; + } + } + + return UINT_MAX; +} + +int acpi_legacy_irq_init(const char *hid, const char *uid) +{ + struct acpi_dev *child_dev = acpi_device_get(hid, uid); + ACPI_PCI_ROUTING_TABLE *rt_table = acpi.pci_prt_table; ACPI_BUFFER rt_buffer; ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; - LOG_DBG("%s", bus_name); + if (!child_dev) { + LOG_ERR("no such PCI bus device %s %s", hid, uid); + return -ENODEV; + } - node = acpi_evaluate_method(bus_name, METHOD_NAME__PRT); + node = acpi_evaluate_method(child_dev->path, METHOD_NAME__PRT); if (!node) { - LOG_ERR("Evaluation failed for given device: %s", bus_name); + LOG_ERR("Evaluation failed for given device: %s", child_dev->path); return -ENODEV; } rt_buffer.Pointer = rt_table; - rt_buffer.Length = rt_size * sizeof(ACPI_PCI_ROUTING_TABLE); + rt_buffer.Length = ARRAY_SIZE(acpi.pci_prt_table) * sizeof(ACPI_PCI_ROUTING_TABLE); status = AcpiGetIrqRoutingTable(node, &rt_buffer); if (ACPI_FAILURE(status)) { - LOG_ERR("unable to retrieve IRQ Routing Table: %s", bus_name); + LOG_ERR("unable to retrieve IRQ Routing Table: %s", child_dev->path); return -EIO; } - return 0; -} - -static int acpi_retrieve_legacy_irq(void) -{ - int ret; - - /* TODO: assume platform have only one PCH with single PCI bus (bus 0). */ - ret = acpi_get_irq_table(CONFIG_ACPI_PRT_BUS_NAME, - acpi.pci_prt_table, ARRAY_SIZE(acpi.pci_prt_table)); - if (ret) { - return ret; + if (rt_table->Source[0]) { + /* + * If Name path exist then PCI interrupts are configurable and are not hardwired to + * any specific interrupt inputs on the interrupt controller. OSPM can uses + * _PRS/_CRS/_SRS to configure interrupts. But currently leave existing PCI bus + * driver with arch_irq_allocate() menthod for allocate and configure interrupts + * without conflicting. + */ + return -ENOENT; } for (size_t i = 0; i < ARRAY_SIZE(acpi.pci_prt_table); i++) { @@ -393,66 +425,125 @@ static int acpi_retrieve_legacy_irq(void) } return 0; - } +#endif /* CONFIG_PCIE_PRT */ -int acpi_get_irq_routing_table(char *bus_name, - ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size) +ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) { - int ret; + do { + if (!res->Length) { + LOG_DBG("zero length found!"); + break; + } else if (res->Type == res_type) { + break; + } + res = ACPI_NEXT_RESOURCE(res); + } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); - ret = check_init_status(); - if (ret) { - return ret; + if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { + return NULL; } - return acpi_get_irq_table(bus_name, rt_table, rt_size); + return res; } -uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf) +int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res) { - uint32_t slot = PCIE_BDF_TO_DEV(bdf), pin; + ACPI_RESOURCE *res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_IRQ); - LOG_DBG(""); + if (!res) { + res = acpi_resource_parse(child_dev->res_lst, ACPI_RESOURCE_TYPE_EXTENDED_IRQ); + if (!res) { + return -ENODEV; + } - if (check_init_status()) { - return UINT_MAX; - } + if (res->Data.ExtendedIrq.InterruptCount > CONFIG_ACPI_IRQ_VECTOR_MAX) { + return -ENOMEM; + } - pin = (pcie_conf_read(bdf, PCIE_CONF_INTR) >> 8) & 0x3; + memset(irq_res, 0, sizeof(struct acpi_irq_resource)); + irq_res->irq_vector_max = res->Data.ExtendedIrq.InterruptCount; + for (int i = 0; i < irq_res->irq_vector_max; i++) { + irq_res->irqs[i] = (uint16_t)res->Data.ExtendedIrq.Interrupts[i]; + } - LOG_DBG("Device irq info: slot:%d pin:%d", slot, pin); + irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity, + res->Data.ExtendedIrq.Triggering); + } else { + if (res->Data.Irq.InterruptCount > CONFIG_ACPI_IRQ_VECTOR_MAX) { + return -ENOMEM; + } - for (int i = 0; i < CONFIG_ACPI_MAX_PRT_ENTRY; i++) { - if (((acpi.pci_prt_table[i].Address >> 16) & 0xffff) == slot && - acpi.pci_prt_table[i].Pin + 1 == pin) { - LOG_DBG("[%d]Device irq info: slot:%d pin:%d irq:%d", i, slot, pin, - acpi.pci_prt_table[i].SourceIndex); - return acpi.pci_prt_table[i].SourceIndex; + irq_res->irq_vector_max = res->Data.Irq.InterruptCount; + for (int i = 0; i < irq_res->irq_vector_max; i++) { + irq_res->irqs[i] = (uint16_t)res->Data.Irq.Interrupts[i]; } + + irq_res->flags = arch_acpi_encode_irq_flags(res->Data.ExtendedIrq.Polarity, + res->Data.ExtendedIrq.Triggering); } - return UINT_MAX; + return 0; } -#endif /* CONFIG_PCIE_PRT */ -ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type) +int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res) { + ACPI_RESOURCE *res = child_dev->res_lst; + struct acpi_reg_base *reg_base = mmio_res->reg_base; + int mmio_cnt = 0; + do { if (!res->Length) { - LOG_DBG("Error: zero length found!"); + LOG_DBG("Found Acpi resource with zero length!"); break; - } else if (res->Type == res_type) { + } + + switch (res->Type) { + case ACPI_RESOURCE_TYPE_IO: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO; + reg_base[mmio_cnt].port = (uint32_t)res->Data.Io.Minimum; + reg_base[mmio_cnt++].length = res->Data.Io.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_FIXED_IO: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_IO; + reg_base[mmio_cnt].port = (uint32_t)res->Data.FixedIo.Address; + reg_base[mmio_cnt++].length = res->Data.FixedIo.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_MEMORY24: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory24.Minimum; + reg_base[mmio_cnt++].length = res->Data.Memory24.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_MEMORY32: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.Memory32.Minimum; + reg_base[mmio_cnt++].length = res->Data.Memory32.AddressLength; + break; + + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + reg_base[mmio_cnt].type = ACPI_RES_TYPE_MEM; + reg_base[mmio_cnt].mmio = (uintptr_t)res->Data.FixedMemory32.Address; + reg_base[mmio_cnt++].length = res->Data.FixedMemory32.AddressLength; break; } + res = ACPI_NEXT_RESOURCE(res); + if (mmio_cnt >= CONFIG_ACPI_MMIO_ENTRIES_MAX && + res->Type != ACPI_RESOURCE_TYPE_END_TAG) { + return -ENOMEM; + } } while (res->Type != ACPI_RESOURCE_TYPE_END_TAG); - if (res->Type == ACPI_RESOURCE_TYPE_END_TAG) { - return NULL; + if (!mmio_cnt) { + return -ENODEV; } - return res; + mmio_res->mmio_max = mmio_cnt; + + return 0; } static int acpi_res_type(ACPI_RESOURCE *res) @@ -513,10 +604,10 @@ int acpi_device_type_get(ACPI_RESOURCE *res) return type; } -struct acpi_dev *acpi_device_get(char *hid, int inst) +struct acpi_dev *acpi_device_get(const char *hid, const char *uid) { struct acpi_dev *child_dev; - int i = 0, inst_id; + int i = 0; LOG_DBG(""); @@ -537,9 +628,8 @@ struct acpi_dev *acpi_device_get(char *hid, int inst) } if (!strcmp(hid, child_dev->dev_info->HardwareId.String)) { - if (child_dev->dev_info->UniqueId.Length) { - inst_id = atoi(child_dev->dev_info->UniqueId.String); - if (inst_id == inst) { + if (uid && child_dev->dev_info->UniqueId.Length) { + if (!strcmp(child_dev->dev_info->UniqueId.String, uid)) { return child_dev; } } else { @@ -651,6 +741,93 @@ int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables) return -ENODEV; } +void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, + dmar_foreach_subtable_func_t func, void *arg) +{ + uint16_t length = dmar->Header.Length; + uintptr_t offset = sizeof(ACPI_TABLE_DMAR); + + while (offset < length) { + ACPI_DMAR_HEADER *subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, dmar, offset); + + __ASSERT_NO_MSG(subtable->Length > sizeof(*subtable)); + + func(subtable, arg); + + offset += subtable->Length; + } +} + +void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu, + dmar_foreach_devscope_func_t func, void *arg) +{ + uint16_t length = hu->Header.Length; + uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT); + + while (offset < length) { + ACPI_DMAR_DEVICE_SCOPE *devscope = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, + hu, offset); + + __ASSERT_NO_MSG(devscope->Length > sizeof(*devscope)); + + func(devscope, arg); + + offset += devscope->Length; + } +} + +static void devscope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg) +{ + ACPI_DMAR_PCI_PATH *dev_path; + union acpi_dmar_id pci_path; + + ARG_UNUSED(arg); /* may be unused */ + + if (devscope->EntryType == ACPI_DMAR_SCOPE_TYPE_IOAPIC) { + uint16_t *ioapic_id = arg; + + dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope, + sizeof(ACPI_DMAR_DEVICE_SCOPE)); + + /* Get first entry */ + pci_path.bits.bus = devscope->Bus; + pci_path.bits.device = dev_path->Device; + pci_path.bits.function = dev_path->Function; + + *ioapic_id = pci_path.raw; + } +} + +static void subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg) +{ + ARG_UNUSED(arg); /* may be unused */ + + if (subtable->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT) { + ACPI_DMAR_HARDWARE_UNIT *hu; + + hu = CONTAINER_OF(subtable, ACPI_DMAR_HARDWARE_UNIT, Header); + acpi_dmar_foreach_devscope(hu, devscope_handler, arg); + } +} + +int acpi_dmar_ioapic_get(uint16_t *ioapic_id) +{ + ACPI_TABLE_DMAR *dmar = acpi_table_get("DMAR", 0); + uint16_t found_ioapic = USHRT_MAX; + + if (dmar == NULL) { + return -ENODEV; + } + + acpi_dmar_foreach_subtable(dmar, subtable_handler, &found_ioapic); + if (found_ioapic != USHRT_MAX) { + *ioapic_id = found_ioapic; + return 0; + } + + return -ENOENT; +} + int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope, union acpi_dmar_id *dmar_id, int *num_inst, int max_inst) { @@ -749,6 +926,23 @@ ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num) return NULL; } +int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj) +{ + ACPI_STATUS status; + ACPI_BUFFER ret_buff; + + ret_buff.Length = sizeof(*ret_obj); + ret_buff.Pointer = ret_obj; + + status = AcpiEvaluateObject(NULL, path, arg_list, &ret_buff); + if (ACPI_FAILURE(status)) { + LOG_ERR("error While executing %s method: %d", path, status); + return -EIO; + } + + return 0; +} + static int acpi_init(void) { ACPI_STATUS status; @@ -770,16 +964,6 @@ static int acpi_init(void) LOG_WRN("Error in enable pic mode acpi method:%d", status); } -#ifdef CONFIG_PCIE_PRT - int ret = acpi_retrieve_legacy_irq(); - - if (ret) { - LOG_ERR("Error in retrieve legacy interrupt info:%d", ret); - status = AE_ERROR; - goto exit; - } -#endif - acpi_enum_devices(); exit: diff --git a/lib/acpi/acpi_shell.c b/lib/acpi/acpi_shell.c index e2db3aaa30e..aae237232da 100644 --- a/lib/acpi/acpi_shell.c +++ b/lib/acpi/acpi_shell.c @@ -103,9 +103,17 @@ static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst) case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64"); break; - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: { + ACPI_RESOURCE_EXTENDED_IRQ *ext_irq_res = &res->Data.ExtendedIrq; + shell_print(sh, "ACPI_RESOURCE_TYPE_EXTENDED_IRQ"); + shell_print(sh, "\tTriggering: %x", ext_irq_res->Triggering); + shell_print(sh, "\tPolarity: %x", ext_irq_res->Polarity); + shell_print(sh, "\tShareable: %s", ext_irq_res->Shareable ? "YES":"NO"); + shell_print(sh, "\tInterruptCount: %d", ext_irq_res->InterruptCount); + shell_print(sh, "\tInterrupts[0]: %d", ext_irq_res->Interrupts[0]); break; + } case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: shell_print(sh, "ACPI_RESOURCE_TYPE_GENERIC_REGISTER"); break; @@ -148,7 +156,7 @@ static int dump_dev_crs(const struct shell *sh, size_t argc, char **argv) ACPI_RESOURCE *res_lst; if (argc < 2) { - shell_error(sh, "invalid arugment"); + shell_error(sh, "invalid argument"); return -EINVAL; } @@ -171,7 +179,7 @@ static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) ACPI_RESOURCE *res_lst; if (argc < 2) { - shell_error(sh, "invalid arugment"); + shell_error(sh, "invalid argument"); return -EINVAL; } @@ -189,28 +197,26 @@ static int dump_dev_prs(const struct shell *sh, size_t argc, char **argv) static int dump_prt(const struct shell *sh, size_t argc, char **argv) { IF_ENABLED(CONFIG_PCIE_PRT, ({ - static ACPI_PCI_ROUTING_TABLE irq_prt_table[CONFIG_ACPI_MAX_PRT_ENTRY]; - int status, cnt; - ACPI_PCI_ROUTING_TABLE *prt; + int irq, bus, dev_num, func; + pcie_bdf_t bdf; - if (argc < 2) { - shell_error(sh, "invalid arugment"); + if (argc < 4) { + shell_error(sh, "invalid arguments [Eg: acpi prt ]"); return -EINVAL; } - status = acpi_get_irq_routing_table(argv[1], - irq_prt_table, ARRAY_SIZE(irq_prt_table)); - if (status) { - return status; - } - - prt = irq_prt_table; - for (cnt = 0; prt->Length; cnt++) { - shell_print(sh, "[%02X] PCI IRQ Routing Table Package", cnt); - shell_print(sh, "\tDevNum: %lld Pin: %d IRQ: %d", - (prt->Address >> 16) & 0xFFFF, prt->Pin, prt->SourceIndex); - - prt = ACPI_ADD_PTR(ACPI_PCI_ROUTING_TABLE, prt, prt->Length); + bus = atoi(argv[1]); + dev_num = atoi(argv[2]); + func = atoi(argv[3]); + + bdf = PCIE_BDF(bus, dev_num, func); + irq = acpi_legacy_irq_get(bdf); + if (irq != UINT_MAX) { + shell_print(sh, "PCI Legacy IRQ for bus %d dev %d func %d is: %d", + bus, dev_num, func, irq); + } else { + shell_print(sh, "PCI Legacy IRQ for bus %d dev %d func %d Not found", + bus, dev_num, func); } })); /* IF_ENABLED(CONFIG_PCIE_PRT) */ @@ -220,19 +226,93 @@ static int dump_prt(const struct shell *sh, size_t argc, char **argv) static int enum_dev(const struct shell *sh, size_t argc, char **argv) { struct acpi_dev *dev; + ACPI_RESOURCE *res_lst; - if (argc < 2) { + if (argc < 3) { + shell_error(sh, "Invalid arguments [Eg: acpi enum PNP0103 0]"); return -EINVAL; } - dev = acpi_device_get(argv[1], 0); + dev = acpi_device_get(argv[1], argv[2]); if (!dev || !dev->res_lst) { shell_error(sh, "acpi get device failed for HID: %s", argv[1]); return -EIO; } shell_print(sh, "Name: %s", dev->path ? dev->path : "None"); - dump_dev_res(sh, dev->res_lst); + + if (dev->path) { + if (!acpi_current_resource_get(dev->path, &res_lst)) { + dump_dev_res(sh, res_lst); + acpi_current_resource_free(res_lst); + } + } + + return 0; +} + +static int enum_all_dev(const struct shell *sh, size_t argc, char **argv) +{ + struct acpi_dev *dev; + + for (int i = 0; i < CONFIG_ACPI_DEV_MAX; i++) { + dev = acpi_device_by_index_get(i); + if (!dev) { + shell_print(sh, "No more ACPI device found!"); + break; + } + + if (!dev->dev_info) { + continue; + } + + shell_print(sh, "%d) Name: %s, HID: %s", i, dev->path ? dev->path : "None", + dev->dev_info->HardwareId.String ? dev->dev_info->HardwareId.String + : "None"); + } + + return 0; +} + +static int get_acpi_dev_resource(const struct shell *sh, size_t argc, char **argv) +{ + struct acpi_dev *dev; + struct acpi_irq_resource irq_res; + struct acpi_mmio_resource mmio_res; + + if (argc < 3) { + return -EINVAL; + } + + dev = acpi_device_get(argv[1], argv[2]); + if (!dev) { + shell_error(sh, "acpi get device failed for HID: %s", argv[1]); + return -EIO; + } + + if (dev->path) { + shell_print(sh, "Device Path: %s", dev->path); + + if (!acpi_device_mmio_get(dev, &mmio_res)) { + + shell_print(sh, "Device MMIO resources"); + for (int i = 0; i < ACPI_RESOURCE_COUNT_GET(&mmio_res); i++) { + shell_print(sh, "\tType: %x, Address: %p, Size: %d", + ACPI_MULTI_RESOURCE_TYPE_GET(&mmio_res, i), + (void *)ACPI_MULTI_MMIO_GET(&mmio_res, i), + ACPI_MULTI_RESOURCE_SIZE_GET(&mmio_res, i)); + } + } + + if (!acpi_device_irq_get(dev, &irq_res)) { + + shell_print(sh, "Device IRQ resources"); + for (int i = 0; i < irq_res.irq_vector_max; i++) { + shell_print(sh, "\tIRQ Num: %x, Flags: %x", irq_res.irqs[i], + irq_res.flags); + } + } + } return 0; } @@ -274,8 +354,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD(enum, NULL, "enumerate device using hid (for enum HPET timer device,eg:acpi enum PNP0103)", enum_dev), - SHELL_CMD(rd_table, NULL, - "read acpi table (for read mad table, eg:acpi read_table APIC)", + SHELL_CMD(enum_all, NULL, "enumerate all device in acpi name space (eg:acpi enum_all)", + enum_all_dev), + SHELL_CMD(dev_res, NULL, "retrieve device resource (eg: acpi dev_res PNP0501 2)", + get_acpi_dev_resource), + SHELL_CMD(rd_table, NULL, "read ACPI table (eg: acpi read_table APIC)", read_table), SHELL_SUBCMD_SET_END /* Array terminated. */ ); diff --git a/lib/crc/crc_shell.c b/lib/crc/crc_shell.c index e75d88623e1..32393ff6f6e 100644 --- a/lib/crc/crc_shell.c +++ b/lib/crc/crc_shell.c @@ -19,9 +19,11 @@ #include static const char *const crc_types[] = { + [CRC4] = "4", + [CRC4_TI] = "4_ti", [CRC7_BE] = "7_be", [CRC8] = "8", - [CRC8_CCITT] "8_ccitt", + [CRC8_CCITT] = "8_ccitt", [CRC16] = "16", [CRC16_ANSI] = "16_ansi", [CRC16_CCITT] = "16_ccitt", diff --git a/lib/heap/CMakeLists.txt b/lib/heap/CMakeLists.txt new file mode 100644 index 00000000000..f3853fc5b7d --- /dev/null +++ b/lib/heap/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + heap.c + ) + +zephyr_sources_ifdef(CONFIG_SYS_HEAP_RUNTIME_STATS heap_stats.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_INFO heap_info.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_VALIDATE heap_validate.c) +zephyr_sources_ifdef(CONFIG_SYS_HEAP_STRESS heap_stress.c) +zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) +zephyr_sources_ifdef(CONFIG_MULTI_HEAP multi_heap.c) +zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) diff --git a/lib/heap/Kconfig b/lib/heap/Kconfig new file mode 100644 index 00000000000..68476eb735c --- /dev/null +++ b/lib/heap/Kconfig @@ -0,0 +1,135 @@ +# Copyright (c) 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Heap and Memory Allocation" + +config SYS_HEAP_VALIDATE + bool "Internal heap validity checking" + help + The sys_heap implementation is instrumented for extensive + internal validation. Leave this off by default, unless + modifying the heap code or (maybe) when running in + environments that require sensitive detection of memory + corruption. + + Use for testing and validation only. + +config SYS_HEAP_STRESS + bool "General purpose heap stress test" + help + Stresses the heap. + + Use for testing and validation only. + +config SYS_HEAP_INFO + bool "Heap internal structure information" + help + Enables support for printing heap internal structure + information to the console. + + Use for debugging only. + +config SYS_HEAP_ALLOC_LOOPS + int "Number of tries in the inner heap allocation loop" + default 3 + help + The sys_heap allocator bounds the number of tries from the + smallest chunk level (the one that might not fit the + requested allocation) to maintain constant time performance. + Setting this to a high level will cause the heap to return + more successful allocations in situations of high + fragmentation, at the cost of potentially significant + (linear time) searching of the free list. The default is + three, which results in an allocator with good statistical + properties ("most" allocations that fit will succeed) but + keeps the maximum runtime at a tight bound so that the heap + is useful in locked or ISR contexts. + +config SYS_HEAP_RUNTIME_STATS + bool "System heap runtime statistics" + help + Gather system heap runtime statistics. + +config SYS_HEAP_LISTENER + bool "sys_heap event notifications" + select HEAP_LISTENER + help + This allows application to listen for sys_heap events, + such as memory allocation and de-allocation. + +config HEAP_LISTENER + bool + help + Hidden option to enable API for registering and notifying + listeners of certain events related to a heap usage, + such as the heap resize. + +choice + prompt "Supported heap sizes" + depends on !64BIT + default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) && !PARTITION_MANAGER_ENABLED + default SYS_HEAP_AUTO + help + Heaps using reduced-size chunk headers can accommodate so called + "small" heaps with a total size of 262136 bytes or less. + + Heaps using full-size chunk headers can have a total size up to + 16383 megabytes. The overhead is of course bigger. + + On 32-bit system the tradeoff is selectable between: + + - "small" heaps with low memory and runtime overhead; + + - "big" heaps with bigger memory overhead even for small heaps; + + - "auto" providing optimal memory overhead in all cases but with + a higher runtime overhead and somewhat bigger code footprint. + + On 64-bit systems the "big" chunk header size conveniently provides + the needed alignment on returned memory allocations. Small chunk + headers would require alignment padding up to the big header size + anyway so "big" heap is the only option in that case. + +config SYS_HEAP_SMALL_ONLY + bool "Support for small heaps only" + help + Select this to optimize the code and memory usage if all your + heaps are 262136 bytes or less. + +config SYS_HEAP_BIG_ONLY + bool "Support for big heaps only" + help + Select this to optimize the code for big heaps only. This can + accommodate any heap size but memory usage won't be as + efficient with small sized heaps. + +config SYS_HEAP_AUTO + bool "Support for both small and big heaps at run time" + help + This option optimizes memory usage for each heap according to + their size albeit with some overhead in code size and execution. + +endchoice + +config MULTI_HEAP + bool "Multi-heap manager" + help + Allows multiple sys_heap regions to be unified under a single + allocation API. Sometimes apps need the ability to share multiple + discontiguous regions in a single "heap", or + to have memory of different "types" be allocated heuristically based + on usage (e.g. cacheability, latency, power...). This allows a + user-specified function to select the underlying memory to use for + each application. + +config SHARED_MULTI_HEAP + bool "Shared multi-heap manager" + select MULTI_HEAP + help + Enable support for a shared multi-heap manager that uses the + multi-heap allocator to manage a set of reserved memory regions with + different capabilities / attributes (cacheable, non-cacheable, + etc...) defined in the DT. + +endmenu diff --git a/lib/os/heap.c b/lib/heap/heap.c similarity index 100% rename from lib/os/heap.c rename to lib/heap/heap.c diff --git a/lib/os/heap.h b/lib/heap/heap.h similarity index 94% rename from lib/os/heap.h rename to lib/heap/heap.h index a29f4adfbd6..df11f18b9e0 100644 --- a/lib/os/heap.h +++ b/lib/heap/heap.h @@ -262,7 +262,21 @@ static inline bool size_too_big(struct z_heap *h, size_t bytes) return (bytes / CHUNK_UNIT) >= h->end_chunk; } -/* For debugging */ -void heap_print_info(struct z_heap *h, bool dump_chunks); +static inline void get_alloc_info(struct z_heap *h, size_t *alloc_bytes, + size_t *free_bytes) +{ + chunkid_t c; + + *alloc_bytes = 0; + *free_bytes = 0; + + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { + if (chunk_used(h, c)) { + *alloc_bytes += chunksz_to_bytes(h, chunk_size(h, c)); + } else if (!solo_free_header(h, c)) { + *free_bytes += chunksz_to_bytes(h, chunk_size(h, c)); + } + } +} #endif /* ZEPHYR_INCLUDE_LIB_OS_HEAP_H_ */ diff --git a/lib/heap/heap_info.c b/lib/heap/heap_info.c new file mode 100644 index 00000000000..80640da2fd4 --- /dev/null +++ b/lib/heap/heap_info.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +/* + * Print heap info for debugging / analysis purpose + */ +static void heap_print_info(struct z_heap *h, bool dump_chunks) +{ + int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1; + size_t free_bytes, allocated_bytes, total, overhead; + + printk("Heap at %p contains %d units in %d buckets\n\n", + chunk_buf(h), h->end_chunk, nb_buckets); + + printk(" bucket# min units total largest largest\n" + " threshold chunks (units) (bytes)\n" + " -----------------------------------------------------------\n"); + for (i = 0; i < nb_buckets; i++) { + chunkid_t first = h->buckets[i].next; + chunksz_t largest = 0; + int count = 0; + + if (first) { + chunkid_t curr = first; + + do { + count++; + largest = MAX(largest, chunk_size(h, curr)); + curr = next_free_chunk(h, curr); + } while (curr != first); + } + if (count) { + printk("%9d %12d %12d %12d %12zd\n", + i, (1 << i) - 1 + min_chunk_size(h), count, + largest, chunksz_to_bytes(h, largest)); + } + } + + if (dump_chunks) { + printk("\nChunk dump:\n"); + for (chunkid_t c = 0; ; c = right_chunk(h, c)) { + printk("chunk %4d: [%c] size=%-4d left=%-4d right=%d\n", + c, + chunk_used(h, c) ? '*' + : solo_free_header(h, c) ? '.' + : '-', + chunk_size(h, c), + left_chunk(h, c), + right_chunk(h, c)); + if (c == h->end_chunk) { + break; + } + } + } + + get_alloc_info(h, &allocated_bytes, &free_bytes); + /* The end marker chunk has a header. It is part of the overhead. */ + total = h->end_chunk * CHUNK_UNIT + chunk_header_bytes(h); + overhead = total - free_bytes - allocated_bytes; + printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n", + free_bytes, allocated_bytes, overhead, + (1000 * overhead + total/2) / total / 10, + (1000 * overhead + total/2) / total % 10); +} + +void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks) +{ + heap_print_info(heap->heap, dump_chunks); +} diff --git a/lib/os/heap_listener.c b/lib/heap/heap_listener.c similarity index 100% rename from lib/os/heap_listener.c rename to lib/heap/heap_listener.c diff --git a/lib/heap/heap_stats.c b/lib/heap/heap_stats.c new file mode 100644 index 00000000000..e9c28b96d2f --- /dev/null +++ b/lib/heap/heap_stats.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019,2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +int sys_heap_runtime_stats_get(struct sys_heap *heap, + struct sys_memory_stats *stats) +{ + if ((heap == NULL) || (stats == NULL)) { + return -EINVAL; + } + + stats->free_bytes = heap->heap->free_bytes; + stats->allocated_bytes = heap->heap->allocated_bytes; + stats->max_allocated_bytes = heap->heap->max_allocated_bytes; + + return 0; +} + +int sys_heap_runtime_stats_reset_max(struct sys_heap *heap) +{ + if (heap == NULL) { + return -EINVAL; + } + + heap->heap->max_allocated_bytes = heap->heap->allocated_bytes; + + return 0; +} diff --git a/lib/heap/heap_stress.c b/lib/heap/heap_stress.c new file mode 100644 index 00000000000..443ffc9e7eb --- /dev/null +++ b/lib/heap/heap_stress.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +struct z_heap_stress_rec { + void *(*alloc_fn)(void *arg, size_t bytes); + void (*free_fn)(void *arg, void *p); + void *arg; + size_t total_bytes; + struct z_heap_stress_block *blocks; + size_t nblocks; + size_t blocks_alloced; + size_t bytes_alloced; + uint32_t target_percent; +}; + +struct z_heap_stress_block { + void *ptr; + size_t sz; +}; + +/* Very simple LCRNG (from https://nuclear.llnl.gov/CNP/rng/rngman/node4.html) + * + * Here to guarantee cross-platform test repeatability. + */ +static uint32_t rand32(void) +{ + static uint64_t state = 123456789; /* seed */ + + state = state * 2862933555777941757UL + 3037000493UL; + + return (uint32_t)(state >> 32); +} + +static bool rand_alloc_choice(struct z_heap_stress_rec *sr) +{ + /* Edge cases: no blocks allocated, and no space for a new one */ + if (sr->blocks_alloced == 0) { + return true; + } else if (sr->blocks_alloced >= sr->nblocks) { + return false; + } else { + + /* The way this works is to scale the chance of choosing to + * allocate vs. free such that it's even odds when the heap is + * at the target percent, with linear tapering on the low + * slope (i.e. we choose to always allocate with an empty + * heap, allocate 50% of the time when the heap is exactly at + * the target, and always free when above the target). In + * practice, the operations aren't quite symmetric (you can + * always free, but your allocation might fail), and the units + * aren't matched (we're doing math based on bytes allocated + * and ignoring the overhead) but this is close enough. And + * yes, the math here is coarse (in units of percent), but + * that's good enough and fits well inside 32 bit quantities. + * (Note precision issue when heap size is above 40MB + * though!). + */ + __ASSERT(sr->total_bytes < 0xffffffffU / 100, "too big for u32!"); + uint32_t full_pct = (100 * sr->bytes_alloced) / sr->total_bytes; + uint32_t target = sr->target_percent ? sr->target_percent : 1; + uint32_t free_chance = 0xffffffffU; + + if (full_pct < sr->target_percent) { + free_chance = full_pct * (0x80000000U / target); + } + + return rand32() > free_chance; + } +} + +/* Chooses a size of block to allocate, logarithmically favoring + * smaller blocks (i.e. blocks twice as large are half as frequent + */ +static size_t rand_alloc_size(struct z_heap_stress_rec *sr) +{ + ARG_UNUSED(sr); + + /* Min scale of 4 means that the half of the requests in the + * smallest size have an average size of 8 + */ + int scale = 4 + __builtin_clz(rand32()); + + return rand32() & BIT_MASK(scale); +} + +/* Returns the index of a randomly chosen block to free */ +static size_t rand_free_choice(struct z_heap_stress_rec *sr) +{ + return rand32() % sr->blocks_alloced; +} + +/* General purpose heap stress test. Takes function pointers to allow + * for testing multiple heap APIs with the same rig. The alloc and + * free functions are passed back the argument as a context pointer. + * The "log" function is for readable user output. The total_bytes + * argument should reflect the size of the heap being tested. The + * scratch array is used to store temporary state and should be sized + * about half as large as the heap itself. Returns true on success. + */ +void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), + void (*free_fn)(void *arg, void *p), + void *arg, size_t total_bytes, + uint32_t op_count, + void *scratch_mem, size_t scratch_bytes, + int target_percent, + struct z_heap_stress_result *result) +{ + struct z_heap_stress_rec sr = { + .alloc_fn = alloc_fn, + .free_fn = free_fn, + .arg = arg, + .total_bytes = total_bytes, + .blocks = scratch_mem, + .nblocks = scratch_bytes / sizeof(struct z_heap_stress_block), + .target_percent = target_percent, + }; + + *result = (struct z_heap_stress_result) {0}; + + for (uint32_t i = 0; i < op_count; i++) { + if (rand_alloc_choice(&sr)) { + size_t sz = rand_alloc_size(&sr); + void *p = sr.alloc_fn(sr.arg, sz); + + result->total_allocs++; + if (p != NULL) { + result->successful_allocs++; + sr.blocks[sr.blocks_alloced].ptr = p; + sr.blocks[sr.blocks_alloced].sz = sz; + sr.blocks_alloced++; + sr.bytes_alloced += sz; + } + } else { + int b = rand_free_choice(&sr); + void *p = sr.blocks[b].ptr; + size_t sz = sr.blocks[b].sz; + + result->total_frees++; + sr.blocks[b] = sr.blocks[sr.blocks_alloced - 1]; + sr.blocks_alloced--; + sr.bytes_alloced -= sz; + sr.free_fn(sr.arg, p); + } + result->accumulated_in_use_bytes += sr.bytes_alloced; + } +} diff --git a/lib/heap/heap_validate.c b/lib/heap/heap_validate.c new file mode 100644 index 00000000000..af63c8cdd8c --- /dev/null +++ b/lib/heap/heap_validate.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "heap.h" + +/* White-box sys_heap validation code. Uses internal data structures. + * Not expected to be useful in production apps. This checks every + * header field of every chunk and returns true if the totality of the + * data structure is a valid heap. It doesn't necessarily tell you + * that it is the CORRECT heap given the history of alloc/free calls + * that it can't inspect. In a pathological case, you can imagine + * something scribbling a copy of a previously-valid heap on top of a + * running one and corrupting it. YMMV. + */ + +#define VALIDATE(cond) do { if (!(cond)) { return false; } } while (0) + +static bool in_bounds(struct z_heap *h, chunkid_t c) +{ + VALIDATE(c >= right_chunk(h, 0)); + VALIDATE(c < h->end_chunk); + VALIDATE(chunk_size(h, c) < h->end_chunk); + return true; +} + +static bool valid_chunk(struct z_heap *h, chunkid_t c) +{ + VALIDATE(chunk_size(h, c) > 0); + VALIDATE(c + chunk_size(h, c) <= h->end_chunk); + VALIDATE(in_bounds(h, c)); + VALIDATE(right_chunk(h, left_chunk(h, c)) == c); + VALIDATE(left_chunk(h, right_chunk(h, c)) == c); + if (chunk_used(h, c)) { + VALIDATE(!solo_free_header(h, c)); + } else { + VALIDATE(chunk_used(h, left_chunk(h, c))); + VALIDATE(chunk_used(h, right_chunk(h, c))); + if (!solo_free_header(h, c)) { + VALIDATE(in_bounds(h, prev_free_chunk(h, c))); + VALIDATE(in_bounds(h, next_free_chunk(h, c))); + } + } + return true; +} + +/* Validate multiple state dimensions for the bucket "next" pointer + * and see that they match. Probably should unify the design a + * bit... + */ +static inline void check_nexts(struct z_heap *h, int bidx) +{ + struct z_heap_bucket *b = &h->buckets[bidx]; + + bool emptybit = (h->avail_buckets & BIT(bidx)) == 0; + bool emptylist = b->next == 0; + bool empties_match = emptybit == emptylist; + + (void)empties_match; + CHECK(empties_match); + + if (b->next != 0) { + CHECK(valid_chunk(h, b->next)); + } +} + +bool sys_heap_validate(struct sys_heap *heap) +{ + struct z_heap *h = heap->heap; + chunkid_t c; + + /* + * Walk through the chunks linearly, verifying sizes and end pointer. + */ + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { + if (!valid_chunk(h, c)) { + return false; + } + } + if (c != h->end_chunk) { + return false; /* Should have exactly consumed the buffer */ + } + +#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS + /* + * Validate sys_heap_runtime_stats_get API. + * Iterate all chunks in sys_heap to get total allocated bytes and + * free bytes, then compare with the results of + * sys_heap_runtime_stats_get function. + */ + size_t allocated_bytes, free_bytes; + struct sys_memory_stats stat; + + get_alloc_info(h, &allocated_bytes, &free_bytes); + sys_heap_runtime_stats_get(heap, &stat); + if ((stat.allocated_bytes != allocated_bytes) || + (stat.free_bytes != free_bytes)) { + return false; + } +#endif + + /* Check the free lists: entry count should match, empty bit + * should be correct, and all chunk entries should point into + * valid unused chunks. Mark those chunks USED, temporarily. + */ + for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) { + chunkid_t c0 = h->buckets[b].next; + uint32_t n = 0; + + check_nexts(h, b); + + for (c = c0; c != 0 && (n == 0 || c != c0); + n++, c = next_free_chunk(h, c)) { + if (!valid_chunk(h, c)) { + return false; + } + set_chunk_used(h, c, true); + } + + bool empty = (h->avail_buckets & BIT(b)) == 0; + bool zero = n == 0; + + if (empty != zero) { + return false; + } + + if (empty && h->buckets[b].next != 0) { + return false; + } + } + + /* + * Walk through the chunks linearly again, verifying that all chunks + * but solo headers are now USED (i.e. all free blocks were found + * during enumeration). Mark all such blocks UNUSED and solo headers + * USED. + */ + chunkid_t prev_chunk = 0; + + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { + if (!chunk_used(h, c) && !solo_free_header(h, c)) { + return false; + } + if (left_chunk(h, c) != prev_chunk) { + return false; + } + prev_chunk = c; + + set_chunk_used(h, c, solo_free_header(h, c)); + } + if (c != h->end_chunk) { + return false; /* Should have exactly consumed the buffer */ + } + + /* Go through the free lists again checking that the linear + * pass caught all the blocks and that they now show UNUSED. + * Mark them USED. + */ + for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) { + chunkid_t c0 = h->buckets[b].next; + int n = 0; + + if (c0 == 0) { + continue; + } + + for (c = c0; n == 0 || c != c0; n++, c = next_free_chunk(h, c)) { + if (chunk_used(h, c)) { + return false; + } + set_chunk_used(h, c, true); + } + } + + /* Now we are valid, but have managed to invert all the in-use + * fields. One more linear pass to fix them up + */ + for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { + set_chunk_used(h, c, !chunk_used(h, c)); + } + return true; +} diff --git a/lib/os/multi_heap.c b/lib/heap/multi_heap.c similarity index 100% rename from lib/os/multi_heap.c rename to lib/heap/multi_heap.c diff --git a/lib/os/shared_multi_heap.c b/lib/heap/shared_multi_heap.c similarity index 100% rename from lib/os/shared_multi_heap.c rename to lib/heap/shared_multi_heap.c diff --git a/lib/libc/arcmwdt/include/errno.h b/lib/libc/arcmwdt/include/errno.h new file mode 100644 index 00000000000..c69da58b167 --- /dev/null +++ b/lib/libc/arcmwdt/include/errno.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 1984-1999, 2012 Wind River Systems, Inc. + * Copyright (c) 2023 Synopsys + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System error numbers + */ + +#ifndef LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ +#define LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +/* MWDT supports range of error codes (ref. $(METAWARE_ROOT)/arc/lib/src/inc/errno.h) + * Add unsupported only + */ +#ifndef ENODATA +#define ENODATA 86 +#endif + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* LIB_LIBC_ARCMWDT_INCLUDE_ERRNO_H_ */ diff --git a/lib/libc/arcmwdt/include/limits.h b/lib/libc/arcmwdt/include/limits.h new file mode 100644 index 00000000000..822e66f24d2 --- /dev/null +++ b/lib/libc/arcmwdt/include/limits.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Synopsys + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ +#define LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATH_MAX 256 + +#ifdef __cplusplus +} +#endif + +#endif /* LIB_LIBC_ARCMWDT_INCLUDE_LIMITS_H_ */ diff --git a/lib/libc/common/include/machine/_threads.h b/lib/libc/common/include/machine/_threads.h index 578536ca5c6..cebce717c73 100644 --- a/lib/libc/common/include/machine/_threads.h +++ b/lib/libc/common/include/machine/_threads.h @@ -11,18 +11,14 @@ extern "C" { #endif -#define ONCE_FLAG_INIT \ - { \ - 1, 0 \ - } +#define ONCE_FLAG_INIT {0} typedef int cnd_t; typedef int mtx_t; typedef int thrd_t; typedef int tss_t; typedef struct { - int is_initialized; - int init_executed; + char flag; } once_flag; #ifdef __cplusplus diff --git a/lib/libc/minimal/source/string/strerror.c b/lib/libc/minimal/source/string/strerror.c index 624e8922b7f..77dfd8b477a 100644 --- a/lib/libc/minimal/source/string/strerror.c +++ b/lib/libc/minimal/source/string/strerror.c @@ -28,7 +28,7 @@ char *strerror(int errnum) return (char *)sys_errlist[errnum]; } - return ""; + return (char *) ""; } /* diff --git a/lib/libc/newlib/include/string.h b/lib/libc/newlib/include/string.h new file mode 100644 index 00000000000..74ba3ccdd9e --- /dev/null +++ b/lib/libc/newlib/include/string.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2024 Keith Packard + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ +#define ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ + +/* This should work on GCC and clang. + * + * If we need to support a toolchain without #include_next the CMake + * infrastructure should be used to identify it and provide an + * alternative solution. + */ +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Define these two Zephyr APIs when _POSIX_C_SOURCE is not set to expose + * them from newlib + */ +#if !__MISC_VISIBLE && !__POSIX_VISIBLE +char *strtok_r(char *__restrict, const char *__restrict, char **__restrict); +#endif +#if __POSIX_VISIBLE < 200809L +size_t strnlen(const char *, size_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_NEWLIB_INCLUDE_STRING_H_ */ diff --git a/lib/libc/picolibc/CMakeLists.txt b/lib/libc/picolibc/CMakeLists.txt index 232e4ba8fc1..23e84231e2a 100644 --- a/lib/libc/picolibc/CMakeLists.txt +++ b/lib/libc/picolibc/CMakeLists.txt @@ -9,10 +9,11 @@ zephyr_compile_definitions(__LINUX_ERRNO_EXTENSIONS__) if(NOT CONFIG_PICOLIBC_USE_MODULE) - # Use picolibc provided with the toolchain + # Use picolibc provided with the toolchain. This requires a new enough + # toolchain so that the version of picolibc supports auto-detecting a + # Zephyr build (via the __ZEPHYR__ macro) to expose the Zephyr C API zephyr_compile_options(--specs=picolibc.specs) - zephyr_compile_definitions(_POSIX_C_SOURCE=200809) zephyr_libc_link_libraries(--specs=picolibc.specs c -lgcc) if(CONFIG_PICOLIBC_IO_FLOAT) zephyr_compile_definitions(PICOLIBC_DOUBLE_PRINTF_SCANF) diff --git a/lib/mem_blocks/CMakeLists.txt b/lib/mem_blocks/CMakeLists.txt new file mode 100644 index 00000000000..9bf33924172 --- /dev/null +++ b/lib/mem_blocks/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) diff --git a/lib/mem_blocks/Kconfig b/lib/mem_blocks/Kconfig new file mode 100644 index 00000000000..ea04f8be97b --- /dev/null +++ b/lib/mem_blocks/Kconfig @@ -0,0 +1,54 @@ +# Copyright (c) 2021,2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Memory Blocks" + +config SYS_MEM_BLOCKS + bool "(Yet Another) Memory Blocks Allocator" + help + This enables support for memory block allocator where: + () All memory blocks have a single fixed size. + () Multiple blocks can be allocated or freed at the same time. + () A group of blocks allocated together may not be contiguous. + This is useful for operations such as scatter-gather DMA + transfers. + () Bookkeeping of allocated blocks is done outside of + the associated buffer (unlike memory slab). This allows + the buffer to reside in memory regions where these can be + powered down to conserve energy. + +config SYS_MEM_BLOCKS_LISTENER + bool "Memory Blocks Allocator event notifications" + depends on SYS_MEM_BLOCKS + select HEAP_LISTENER + help + This allows application to listen for memory blocks allocator + events, such as memory allocation and de-allocation. + +config SYS_MEM_BLOCKS_RUNTIME_STATS + bool "Memory blocks runtime statistics" + depends on SYS_MEM_BLOCKS + help + This option enables the tracking and reporting of the memory + blocks statistics related to the current and maximum number + of allocations in a given memory block. + +config OBJ_CORE_SYS_MEM_BLOCKS + bool "Kernel object for memory blocks" + depends on SYS_MEM_BLOCKS && OBJ_CORE + default y if SYS_MEM_BLOCKS && OBJ_CORE + help + This option allows object cores to be integrated into memory block + objects. + +config OBJ_CORE_STATS_SYS_MEM_BLOCKS + bool "Object core statistics for memory blocks" + depends on SYS_MEM_BLOCKS && OBJ_CORE_STATS + default y if SYS_MEM_BLOCKS && OBJ_CORE_STATS + select SYS_MEM_BLOCKS_RUNTIME_STATS + help + This option integrates the object core statistics framework into + the memory blocks. + +endmenu diff --git a/lib/os/mem_blocks.c b/lib/mem_blocks/mem_blocks.c similarity index 100% rename from lib/os/mem_blocks.c rename to lib/mem_blocks/mem_blocks.c diff --git a/lib/os/CMakeLists.txt b/lib/os/CMakeLists.txt index 4f082716c48..3a52bebab04 100644 --- a/lib/os/CMakeLists.txt +++ b/lib/os/CMakeLists.txt @@ -4,26 +4,14 @@ zephyr_syscall_header( ${ZEPHYR_BASE}/include/zephyr/sys/mutex.h ) -zephyr_sources_ifdef(CONFIG_BASE64 base64.c) - zephyr_sources( cbprintf_packaged.c - dec.c - hex.c printk.c - rb.c sem.c thread_entry.c - timeutil.c - heap.c - heap-validate.c - bitarray.c - multi_heap.c ) zephyr_sources_ifdef(CONFIG_FDTABLE fdtable.c) -zephyr_sources_ifdef(CONFIG_ONOFF onoff.c) -zephyr_sources_ifdef(CONFIG_NOTIFY notify.c) zephyr_sources_ifdef(CONFIG_CBPRINTF_COMPLETE cbprintf_complete.c) zephyr_sources_ifdef(CONFIG_CBPRINTF_NANO cbprintf_nano.c) @@ -32,10 +20,6 @@ if(NOT CONFIG_PICOLIBC) zephyr_sources(cbprintf.c) endif() -zephyr_sources_ifdef(CONFIG_JSON_LIBRARY json.c) - -zephyr_sources_ifdef(CONFIG_RING_BUFFER ring_buffer.c) - if (CONFIG_ASSERT OR CONFIG_ASSERT_VERBOSE) zephyr_sources(assert.c) endif() @@ -50,16 +34,6 @@ zephyr_sources_ifdef(CONFIG_SCHED_DEADLINE p4wq.c) zephyr_sources_ifdef(CONFIG_REBOOT reboot.c) -zephyr_sources_ifdef(CONFIG_SHARED_MULTI_HEAP shared_multi_heap.c) - -zephyr_sources_ifdef(CONFIG_HEAP_LISTENER heap_listener.c) - -zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) - -zephyr_sources_ifdef(CONFIG_SYS_MEM_BLOCKS mem_blocks.c) - -zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) - zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_library_include_directories( diff --git a/lib/os/Kconfig b/lib/os/Kconfig index e6b25ade5a5..14b6241b72c 100644 --- a/lib/os/Kconfig +++ b/lib/os/Kconfig @@ -10,29 +10,6 @@ config FDTABLE for any I/O object implementing POSIX I/O semantics (i.e. read/write + aux operations). -config JSON_LIBRARY - bool "Build JSON library" - help - Build a minimal JSON parsing/encoding library. Used by sample - applications such as the NATS client. - -config RING_BUFFER - bool "Ring buffers" - help - Enable usage of ring buffers. This is similar to kernel FIFOs but ring - buffers manage their own buffer memory and can store arbitrary data. - For optimal performance, use buffer sizes that are a power of 2. - -config NOTIFY - bool "Asynchronous Notifications" - help - Use this API to support async transactions. - -config BASE64 - bool "Base64 encoding and decoding" - help - Enable base64 encoding and decoding functionality - config PRINTK_SYNC bool "Serialize printk() calls" default y if SMP && MP_MAX_NUM_CPUS > 1 && !(EFI_CONSOLE && LOG) @@ -50,14 +27,6 @@ config MPSC_PBUF storing variable length packets in a circular way and operate directly on the buffer memory. -config ONOFF - bool "On-Off Manager" - select NOTIFY - help - An on-off manager supports an arbitrary number of clients of a - service which has a binary state. Example applications are power - rails, clocks, and binary device power management. - config SPSC_PBUF bool "Single producer, single consumer packet buffer" help @@ -119,31 +88,6 @@ config SPSC_PBUF_UTILIZATION endif # SPSC_PBUF -config SHARED_MULTI_HEAP - bool "Shared multi-heap manager" - help - Enable support for a shared multi-heap manager that uses the - multi-heap allocator to manage a set of reserved memory regions with - different capabilities / attributes (cacheable, non-cacheable, - etc...) defined in the DT. - -config WINSTREAM - bool "Lockless shared memory window byte stream" - help - Winstream is a byte stream IPC for use in shared memory - "windows", generally for transmit to non-Zephyr contexts that - can't share Zephyr APIs or data structures. - -if WINSTREAM -config WINSTREAM_STDLIB_MEMCOPY - bool "Use standard memcpy() in winstream" - help - The sys_winstream utility is sometimes used in early boot - environments before the standard library is usable. By - default it uses a simple internal bytewise memcpy(). Set - this to use the one from the standard library. -endif - if MPSC_PBUF config MPSC_CLEAR_ALLOCATED bool "Clear allocated packet" @@ -169,14 +113,6 @@ config POWEROFF help Enable support for system power off. -config UTF8 - bool "UTF-8 string operation supported" - help - Enable the utf8 API. The API implements functions to specifically - handle UTF-8 encoded strings. - rsource "Kconfig.cbprintf" -rsource "Kconfig.heap" - endmenu diff --git a/lib/os/Kconfig.heap b/lib/os/Kconfig.heap deleted file mode 100644 index f6e8d93ae50..00000000000 --- a/lib/os/Kconfig.heap +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (c) 2021 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -menu "Heap and Memory Allocation" - -config SYS_HEAP_VALIDATE - bool "Internal heap validity checking" - help - The sys_heap implementation is instrumented for extensive - internal validation. Leave this off by default, unless - modifying the heap code or (maybe) when running in - environments that require sensitive detection of memory - corruption. - -config SYS_HEAP_ALLOC_LOOPS - int "Number of tries in the inner heap allocation loop" - default 3 - help - The sys_heap allocator bounds the number of tries from the - smallest chunk level (the one that might not fit the - requested allocation) to maintain constant time performance. - Setting this to a high level will cause the heap to return - more successful allocations in situations of high - fragmentation, at the cost of potentially significant - (linear time) searching of the free list. The default is - three, which results in an allocator with good statistical - properties ("most" allocations that fit will succeed) but - keeps the maximum runtime at a tight bound so that the heap - is useful in locked or ISR contexts. - -config SYS_HEAP_RUNTIME_STATS - bool "System heap runtime statistics" - help - Gather system heap runtime statistics. - -config SYS_HEAP_LISTENER - bool "sys_heap event notifications" - select HEAP_LISTENER - help - This allows application to listen for sys_heap events, - such as memory allocation and de-allocation. - -config HEAP_LISTENER - bool - help - Hidden option to enable API for registering and notifying - listeners of certain events related to a heap usage, - such as the heap resize. - -choice - prompt "Supported heap sizes" - depends on !64BIT - default SYS_HEAP_SMALL_ONLY if (SRAM_SIZE <= 256) && !PARTITION_MANAGER_ENABLED - default SYS_HEAP_AUTO - help - Heaps using reduced-size chunk headers can accommodate so called - "small" heaps with a total size of 262136 bytes or less. - - Heaps using full-size chunk headers can have a total size up to - 16383 megabytes. The overhead is of course bigger. - - On 32-bit system the tradeoff is selectable between: - - - "small" heaps with low memory and runtime overhead; - - - "big" heaps with bigger memory overhead even for small heaps; - - - "auto" providing optimal memory overhead in all cases but with - a higher runtime overhead and somewhat bigger code footprint. - - On 64-bit systems the "big" chunk header size conveniently provides - the needed alignment on returned memory allocations. Small chunk - headers would require alignment padding up to the big header size - anyway so "big" heap is the only option in that case. - -config SYS_HEAP_SMALL_ONLY - bool "Support for small heaps only" - help - Select this to optimize the code and memory usage if all your - heaps are 262136 bytes or less. - -config SYS_HEAP_BIG_ONLY - bool "Support for big heaps only" - help - Select this to optimize the code for big heaps only. This can - accommodate any heap size but memory usage won't be as - efficient with small sized heaps. - -config SYS_HEAP_AUTO - bool "Support for both small and big heaps at run time" - help - This option optimizes memory usage for each heap according to - their size albeit with some overhead in code size and execution. - -endchoice - -config SHARED_MULTI_HEAP - bool "Shared multi-heap manager" - help - Enable support for a shared multi-heap manager that uses the - multi-heap allocator to manage a set of reserved memory regions with - different capabilities / attributes (cacheable, non-cacheable, - etc...) defined in the DT. - -config SYS_MEM_BLOCKS - bool "(Yet Another) Memory Blocks Allocator" - help - This enables support for memory block allocator where: - () All memory blocks have a single fixed size. - () Multiple blocks can be allocated or freed at the same time. - () A group of blocks allocated together may not be contiguous. - This is useful for operations such as scatter-gather DMA - transfers. - () Bookkeeping of allocated blocks is done outside of - the associated buffer (unlike memory slab). This allows - the buffer to reside in memory regions where these can be - powered down to conserve energy. - -config SYS_MEM_BLOCKS_LISTENER - bool "Memory Blocks Allocator event notifications" - depends on SYS_MEM_BLOCKS - select HEAP_LISTENER - help - This allows application to listen for memory blocks allocator - events, such as memory allocation and de-allocation. - -config SYS_MEM_BLOCKS_RUNTIME_STATS - bool "Memory blocks runtime statistics" - depends on SYS_MEM_BLOCKS - help - This option enables the tracking and reporting of the memory - blocks statistics related to the current and maximum number - of allocations in a given memory block. - -config OBJ_CORE_SYS_MEM_BLOCKS - bool "Kernel object for memory blocks" - depends on SYS_MEM_BLOCKS && OBJ_CORE - default y if SYS_MEM_BLOCKS && OBJ_CORE - help - This option allows object cores to be integrated into memory block - objects. - -config OBJ_CORE_STATS_SYS_MEM_BLOCKS - bool "Object core statistics for memory blocks" - depends on SYS_MEM_BLOCKS && OBJ_CORE_STATS - default y if SYS_MEM_BLOCKS && OBJ_CORE_STATS - select SYS_MEM_BLOCKS_RUNTIME_STATS - help - This option integrates the object core statistics framework into - the memory blocks. - -endmenu diff --git a/lib/os/cbprintf_packaged.c b/lib/os/cbprintf_packaged.c index 3e71034f316..1c208c42e67 100644 --- a/lib/os/cbprintf_packaged.c +++ b/lib/os/cbprintf_packaged.c @@ -982,9 +982,7 @@ int cbprintf_package_convert(void *in_packaged, str_pos++; } } else { - if (ros_nbr && flags & CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR) { - str_pos += ros_nbr; - } + str_pos += ros_nbr; } bool drop_ro_str_pos = !(flags & diff --git a/lib/os/heap-validate.c b/lib/os/heap-validate.c deleted file mode 100644 index 18aafe71804..00000000000 --- a/lib/os/heap-validate.c +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include "heap.h" - -/* White-box sys_heap validation code. Uses internal data structures. - * Not expected to be useful in production apps. This checks every - * header field of every chunk and returns true if the totality of the - * data structure is a valid heap. It doesn't necessarily tell you - * that it is the CORRECT heap given the history of alloc/free calls - * that it can't inspect. In a pathological case, you can imagine - * something scribbling a copy of a previously-valid heap on top of a - * running one and corrupting it. YMMV. - */ - -#define VALIDATE(cond) do { if (!(cond)) { return false; } } while (0) - -static bool in_bounds(struct z_heap *h, chunkid_t c) -{ - VALIDATE(c >= right_chunk(h, 0)); - VALIDATE(c < h->end_chunk); - VALIDATE(chunk_size(h, c) < h->end_chunk); - return true; -} - -static bool valid_chunk(struct z_heap *h, chunkid_t c) -{ - VALIDATE(chunk_size(h, c) > 0); - VALIDATE(c + chunk_size(h, c) <= h->end_chunk); - VALIDATE(in_bounds(h, c)); - VALIDATE(right_chunk(h, left_chunk(h, c)) == c); - VALIDATE(left_chunk(h, right_chunk(h, c)) == c); - if (chunk_used(h, c)) { - VALIDATE(!solo_free_header(h, c)); - } else { - VALIDATE(chunk_used(h, left_chunk(h, c))); - VALIDATE(chunk_used(h, right_chunk(h, c))); - if (!solo_free_header(h, c)) { - VALIDATE(in_bounds(h, prev_free_chunk(h, c))); - VALIDATE(in_bounds(h, next_free_chunk(h, c))); - } - } - return true; -} - -/* Validate multiple state dimensions for the bucket "next" pointer - * and see that they match. Probably should unify the design a - * bit... - */ -static inline void check_nexts(struct z_heap *h, int bidx) -{ - struct z_heap_bucket *b = &h->buckets[bidx]; - - bool emptybit = (h->avail_buckets & BIT(bidx)) == 0; - bool emptylist = b->next == 0; - bool empties_match = emptybit == emptylist; - - (void)empties_match; - CHECK(empties_match); - - if (b->next != 0) { - CHECK(valid_chunk(h, b->next)); - } -} - -static void get_alloc_info(struct z_heap *h, size_t *alloc_bytes, - size_t *free_bytes) -{ - chunkid_t c; - - *alloc_bytes = 0; - *free_bytes = 0; - - for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { - if (chunk_used(h, c)) { - *alloc_bytes += chunksz_to_bytes(h, chunk_size(h, c)); - } else if (!solo_free_header(h, c)) { - *free_bytes += chunksz_to_bytes(h, chunk_size(h, c)); - } - } -} - -bool sys_heap_validate(struct sys_heap *heap) -{ - struct z_heap *h = heap->heap; - chunkid_t c; - - /* - * Walk through the chunks linearly, verifying sizes and end pointer. - */ - for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { - if (!valid_chunk(h, c)) { - return false; - } - } - if (c != h->end_chunk) { - return false; /* Should have exactly consumed the buffer */ - } - -#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS - /* - * Validate sys_heap_runtime_stats_get API. - * Iterate all chunks in sys_heap to get total allocated bytes and - * free bytes, then compare with the results of - * sys_heap_runtime_stats_get function. - */ - size_t allocated_bytes, free_bytes; - struct sys_memory_stats stat; - - get_alloc_info(h, &allocated_bytes, &free_bytes); - sys_heap_runtime_stats_get(heap, &stat); - if ((stat.allocated_bytes != allocated_bytes) || - (stat.free_bytes != free_bytes)) { - return false; - } -#endif - - /* Check the free lists: entry count should match, empty bit - * should be correct, and all chunk entries should point into - * valid unused chunks. Mark those chunks USED, temporarily. - */ - for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) { - chunkid_t c0 = h->buckets[b].next; - uint32_t n = 0; - - check_nexts(h, b); - - for (c = c0; c != 0 && (n == 0 || c != c0); - n++, c = next_free_chunk(h, c)) { - if (!valid_chunk(h, c)) { - return false; - } - set_chunk_used(h, c, true); - } - - bool empty = (h->avail_buckets & BIT(b)) == 0; - bool zero = n == 0; - - if (empty != zero) { - return false; - } - - if (empty && h->buckets[b].next != 0) { - return false; - } - } - - /* - * Walk through the chunks linearly again, verifying that all chunks - * but solo headers are now USED (i.e. all free blocks were found - * during enumeration). Mark all such blocks UNUSED and solo headers - * USED. - */ - chunkid_t prev_chunk = 0; - for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { - if (!chunk_used(h, c) && !solo_free_header(h, c)) { - return false; - } - if (left_chunk(h, c) != prev_chunk) { - return false; - } - prev_chunk = c; - - set_chunk_used(h, c, solo_free_header(h, c)); - } - if (c != h->end_chunk) { - return false; /* Should have exactly consumed the buffer */ - } - - /* Go through the free lists again checking that the linear - * pass caught all the blocks and that they now show UNUSED. - * Mark them USED. - */ - for (int b = 0; b <= bucket_idx(h, h->end_chunk); b++) { - chunkid_t c0 = h->buckets[b].next; - int n = 0; - - if (c0 == 0) { - continue; - } - - for (c = c0; n == 0 || c != c0; n++, c = next_free_chunk(h, c)) { - if (chunk_used(h, c)) { - return false; - } - set_chunk_used(h, c, true); - } - } - - /* Now we are valid, but have managed to invert all the in-use - * fields. One more linear pass to fix them up - */ - for (c = right_chunk(h, 0); c < h->end_chunk; c = right_chunk(h, c)) { - set_chunk_used(h, c, !chunk_used(h, c)); - } - return true; -} - -struct z_heap_stress_rec { - void *(*alloc_fn)(void *arg, size_t bytes); - void (*free_fn)(void *arg, void *p); - void *arg; - size_t total_bytes; - struct z_heap_stress_block *blocks; - size_t nblocks; - size_t blocks_alloced; - size_t bytes_alloced; - uint32_t target_percent; -}; - -struct z_heap_stress_block { - void *ptr; - size_t sz; -}; - -/* Very simple LCRNG (from https://nuclear.llnl.gov/CNP/rng/rngman/node4.html) - * - * Here to guarantee cross-platform test repeatability. - */ -static uint32_t rand32(void) -{ - static uint64_t state = 123456789; /* seed */ - - state = state * 2862933555777941757UL + 3037000493UL; - - return (uint32_t)(state >> 32); -} - -static bool rand_alloc_choice(struct z_heap_stress_rec *sr) -{ - /* Edge cases: no blocks allocated, and no space for a new one */ - if (sr->blocks_alloced == 0) { - return true; - } else if (sr->blocks_alloced >= sr->nblocks) { - return false; - } else { - - /* The way this works is to scale the chance of choosing to - * allocate vs. free such that it's even odds when the heap is - * at the target percent, with linear tapering on the low - * slope (i.e. we choose to always allocate with an empty - * heap, allocate 50% of the time when the heap is exactly at - * the target, and always free when above the target). In - * practice, the operations aren't quite symmetric (you can - * always free, but your allocation might fail), and the units - * aren't matched (we're doing math based on bytes allocated - * and ignoring the overhead) but this is close enough. And - * yes, the math here is coarse (in units of percent), but - * that's good enough and fits well inside 32 bit quantities. - * (Note precision issue when heap size is above 40MB - * though!). - */ - __ASSERT(sr->total_bytes < 0xffffffffU / 100, "too big for u32!"); - uint32_t full_pct = (100 * sr->bytes_alloced) / sr->total_bytes; - uint32_t target = sr->target_percent ? sr->target_percent : 1; - uint32_t free_chance = 0xffffffffU; - - if (full_pct < sr->target_percent) { - free_chance = full_pct * (0x80000000U / target); - } - - return rand32() > free_chance; - } -} - -/* Chooses a size of block to allocate, logarithmically favoring - * smaller blocks (i.e. blocks twice as large are half as frequent - */ -static size_t rand_alloc_size(struct z_heap_stress_rec *sr) -{ - ARG_UNUSED(sr); - - /* Min scale of 4 means that the half of the requests in the - * smallest size have an average size of 8 - */ - int scale = 4 + __builtin_clz(rand32()); - - return rand32() & BIT_MASK(scale); -} - -/* Returns the index of a randomly chosen block to free */ -static size_t rand_free_choice(struct z_heap_stress_rec *sr) -{ - return rand32() % sr->blocks_alloced; -} - -/* General purpose heap stress test. Takes function pointers to allow - * for testing multiple heap APIs with the same rig. The alloc and - * free functions are passed back the argument as a context pointer. - * The "log" function is for readable user output. The total_bytes - * argument should reflect the size of the heap being tested. The - * scratch array is used to store temporary state and should be sized - * about half as large as the heap itself. Returns true on success. - */ -void sys_heap_stress(void *(*alloc_fn)(void *arg, size_t bytes), - void (*free_fn)(void *arg, void *p), - void *arg, size_t total_bytes, - uint32_t op_count, - void *scratch_mem, size_t scratch_bytes, - int target_percent, - struct z_heap_stress_result *result) -{ - struct z_heap_stress_rec sr = { - .alloc_fn = alloc_fn, - .free_fn = free_fn, - .arg = arg, - .total_bytes = total_bytes, - .blocks = scratch_mem, - .nblocks = scratch_bytes / sizeof(struct z_heap_stress_block), - .target_percent = target_percent, - }; - - *result = (struct z_heap_stress_result) {0}; - - for (uint32_t i = 0; i < op_count; i++) { - if (rand_alloc_choice(&sr)) { - size_t sz = rand_alloc_size(&sr); - void *p = sr.alloc_fn(sr.arg, sz); - - result->total_allocs++; - if (p != NULL) { - result->successful_allocs++; - sr.blocks[sr.blocks_alloced].ptr = p; - sr.blocks[sr.blocks_alloced].sz = sz; - sr.blocks_alloced++; - sr.bytes_alloced += sz; - } - } else { - int b = rand_free_choice(&sr); - void *p = sr.blocks[b].ptr; - size_t sz = sr.blocks[b].sz; - - result->total_frees++; - sr.blocks[b] = sr.blocks[sr.blocks_alloced - 1]; - sr.blocks_alloced--; - sr.bytes_alloced -= sz; - sr.free_fn(sr.arg, p); - } - result->accumulated_in_use_bytes += sr.bytes_alloced; - } -} - -/* - * Print heap info for debugging / analysis purpose - */ -void heap_print_info(struct z_heap *h, bool dump_chunks) -{ - int i, nb_buckets = bucket_idx(h, h->end_chunk) + 1; - size_t free_bytes, allocated_bytes, total, overhead; - - printk("Heap at %p contains %d units in %d buckets\n\n", - chunk_buf(h), h->end_chunk, nb_buckets); - - printk(" bucket# min units total largest largest\n" - " threshold chunks (units) (bytes)\n" - " -----------------------------------------------------------\n"); - for (i = 0; i < nb_buckets; i++) { - chunkid_t first = h->buckets[i].next; - chunksz_t largest = 0; - int count = 0; - - if (first) { - chunkid_t curr = first; - do { - count++; - largest = MAX(largest, chunk_size(h, curr)); - curr = next_free_chunk(h, curr); - } while (curr != first); - } - if (count) { - printk("%9d %12d %12d %12d %12zd\n", - i, (1 << i) - 1 + min_chunk_size(h), count, - largest, chunksz_to_bytes(h, largest)); - } - } - - if (dump_chunks) { - printk("\nChunk dump:\n"); - for (chunkid_t c = 0; ; c = right_chunk(h, c)) { - printk("chunk %4d: [%c] size=%-4d left=%-4d right=%d\n", - c, - chunk_used(h, c) ? '*' - : solo_free_header(h, c) ? '.' - : '-', - chunk_size(h, c), - left_chunk(h, c), - right_chunk(h, c)); - if (c == h->end_chunk) { - break; - } - } - } - - get_alloc_info(h, &allocated_bytes, &free_bytes); - /* The end marker chunk has a header. It is part of the overhead. */ - total = h->end_chunk * CHUNK_UNIT + chunk_header_bytes(h); - overhead = total - free_bytes - allocated_bytes; - printk("\n%zd free bytes, %zd allocated bytes, overhead = %zd bytes (%zd.%zd%%)\n", - free_bytes, allocated_bytes, overhead, - (1000 * overhead + total/2) / total / 10, - (1000 * overhead + total/2) / total % 10); -} - -void sys_heap_print_info(struct sys_heap *heap, bool dump_chunks) -{ - heap_print_info(heap->heap, dump_chunks); -} - -#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS - -int sys_heap_runtime_stats_get(struct sys_heap *heap, - struct sys_memory_stats *stats) -{ - if ((heap == NULL) || (stats == NULL)) { - return -EINVAL; - } - - stats->free_bytes = heap->heap->free_bytes; - stats->allocated_bytes = heap->heap->allocated_bytes; - stats->max_allocated_bytes = heap->heap->max_allocated_bytes; - - return 0; -} - -int sys_heap_runtime_stats_reset_max(struct sys_heap *heap) -{ - if (heap == NULL) { - return -EINVAL; - } - - heap->heap->max_allocated_bytes = heap->heap->allocated_bytes; - - return 0; -} - -#endif diff --git a/lib/os/printk.c b/lib/os/printk.c index f46b950ffe4..ac19e9e38fc 100644 --- a/lib/os/printk.c +++ b/lib/os/printk.c @@ -154,6 +154,7 @@ void vprintk(const char *fmt, va_list ap) #endif } } +EXPORT_SYMBOL(vprintk); void z_impl_k_str_out(char *c, size_t n) { diff --git a/lib/os/spsc_pbuf.c b/lib/os/spsc_pbuf.c index 50e63c639ed..748be9fc1be 100644 --- a/lib/os/spsc_pbuf.c +++ b/lib/os/spsc_pbuf.c @@ -327,21 +327,21 @@ void spsc_pbuf_free(struct spsc_pbuf *pb, uint16_t len) uint8_t *data_loc = get_data_loc(pb, flags); rd_idx = ROUND_UP(rd_idx, sizeof(uint32_t)); - cache_inv(&data_loc[rd_idx], sizeof(uint8_t), flags); /* Handle wrapping or the fact that next packet is a padding. */ - if (rd_idx == pblen) { - rd_idx = 0; - } else if (data_loc[rd_idx] == PADDING_MARK) { - cache_inv(wr_idx_loc, sizeof(*wr_idx_loc), flags); - /* We may hit the case when producer is in the middle of adding - * a padding (which happens in 2 steps: writing padding, resetting - * write index) and in that case we cannot consume this padding. - */ - if (rd_idx != *wr_idx_loc) { - rd_idx = 0; + if (rd_idx != pblen) { + cache_inv(&data_loc[rd_idx], sizeof(uint8_t), flags); + if (data_loc[rd_idx] == PADDING_MARK) { + cache_inv(wr_idx_loc, sizeof(*wr_idx_loc), flags); + /* We may hit the case when producer is in the middle of adding + * a padding (which happens in 2 steps: writing padding, resetting + * write index) and in that case we cannot consume this padding. + */ + if (rd_idx != *wr_idx_loc) { + rd_idx = 0; + } } } else { - /* empty */ + rd_idx = 0; } *rd_idx_loc = rd_idx; diff --git a/lib/os/thread_entry.c b/lib/os/thread_entry.c index 89eb2fe7b4b..ed6ca142d99 100644 --- a/lib/os/thread_entry.c +++ b/lib/os/thread_entry.c @@ -12,7 +12,7 @@ */ #include -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS #include __thread k_tid_t z_tls_current; @@ -35,7 +35,7 @@ extern __thread volatile uintptr_t __stack_chk_guard; FUNC_NORETURN void z_thread_entry(k_thread_entry_t entry, void *p1, void *p2, void *p3) { -#ifdef CONFIG_THREAD_LOCAL_STORAGE +#ifdef CONFIG_CURRENT_THREAD_USE_TLS z_tls_current = k_sched_current_thread_query(); #endif #ifdef CONFIG_STACK_CANARIES_TLS diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index c6b3a88aeab..fed728c17ba 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -1,67 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 -set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) - -zephyr_syscall_header( - ${ZEPHYR_BASE}/include/zephyr/posix/time.h -) - -zephyr_interface_library_named(posix_subsys) - -if(CONFIG_POSIX_API) - zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) -endif() - -if(CONFIG_POSIX_SIGNAL) - set(STRSIGNAL_TABLE_H ${GEN_DIR}/posix/strsignal_table.h) - - add_custom_command( - OUTPUT ${STRSIGNAL_TABLE_H} - COMMAND - ${PYTHON_EXECUTABLE} - ${ZEPHYR_BASE}/scripts/build/gen_strsignal_table.py - -i ${ZEPHYR_BASE}/include/zephyr/posix/signal.h - -o ${STRSIGNAL_TABLE_H} - DEPENDS ${ZEPHYR_BASE}/include/zephyr/posix/signal.h - ) -endif() - -if(CONFIG_POSIX_API OR CONFIG_PTHREAD_IPC OR CONFIG_POSIX_CLOCK OR - CONFIG_POSIX_MQUEUE OR CONFIG_POSIX_FS OR CONFIG_EVENTFD OR CONFIG_GETOPT) - # This is a temporary workaround so that Newlib declares the appropriate - # types for us. POSIX features to be formalized as part of #51211 - zephyr_compile_options($<$:-D_POSIX_THREADS>) - zephyr_compile_options($<$:-D_POSIX_THREADS>) -endif() - -zephyr_library() -add_subdirectory_ifdef(CONFIG_GETOPT getopt) -zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) -zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK timer.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) -zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) -zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_BARRIER barrier.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_COND cond.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC rwlock.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC sched.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) -zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ARCH_DIR}/${ARCH}/include -) - -zephyr_library_link_libraries(posix_subsys) -zephyr_library_property(ALLOW_EMPTY TRUE) +add_subdirectory(options) +add_subdirectory(shell) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index 3fd01313474..534baf08cd2 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -1,56 +1,10 @@ -# Copyright (c) 2018 Intel Corporation -# Copyright (c) 2023 Meta +# Copyright (c) 2024 Meta # # SPDX-License-Identifier: Apache-2.0 -config POSIX_MAX_FDS - int "Maximum number of open file descriptors" - default 16 if WIFI_NM_WPA_SUPPLICANT - default 16 if POSIX_API - default 4 - help - Maximum number of open file descriptors, this includes - files, sockets, special devices, etc. +menu "POSIX API Support" -config POSIX_API - depends on !NATIVE_APPLICATION - bool "POSIX APIs" - help - Enable mostly-standards-compliant implementations of - various POSIX (IEEE 1003.1) APIs. +rsource "options/Kconfig" +rsource "shell/Kconfig" -# The name of this option is mandated by zephyr_interface_library_named -# cmake directive. -config APP_LINK_WITH_POSIX_SUBSYS - bool "Make POSIX headers available to application" - default y - depends on POSIX_API - help - Add POSIX subsystem header files to the 'app' include path. - -config PTHREAD_IPC - bool "POSIX pthread IPC API" - default y if POSIX_API - depends on POSIX_CLOCK - help - This enables a mostly-standards-compliant implementation of - the pthread mutex, condition variable and barrier IPC - mechanisms. - -source "lib/posix/Kconfig.barrier" -source "lib/posix/Kconfig.clock" -source "lib/posix/Kconfig.cond" -source "lib/posix/Kconfig.eventfd" -source "lib/posix/Kconfig.fnmatch" -source "lib/posix/Kconfig.fs" -source "lib/posix/Kconfig.getopt" -source "lib/posix/Kconfig.key" -source "lib/posix/Kconfig.limits" -source "lib/posix/Kconfig.mqueue" -source "lib/posix/Kconfig.mutex" -source "lib/posix/Kconfig.pthread" -source "lib/posix/Kconfig.semaphore" -source "lib/posix/Kconfig.signal" -source "lib/posix/Kconfig.spinlock" -source "lib/posix/Kconfig.timer" -source "lib/posix/Kconfig.uname" +endmenu # "POSIX API Support" diff --git a/lib/posix/Kconfig.clock b/lib/posix/Kconfig.clock deleted file mode 100644 index 95c88769d73..00000000000 --- a/lib/posix/Kconfig.clock +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2018 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -config POSIX_CLOCK - bool "POSIX clock, timer, and sleep APIs" - default y if POSIX_API - depends on !(ARCH_POSIX && EXTERNAL_LIBC) - help - This enables POSIX clock\_\*(), timer\_\*(), and \*sleep() - functions. diff --git a/lib/posix/Kconfig.getopt b/lib/posix/Kconfig.getopt deleted file mode 100644 index ccd2c37ed56..00000000000 --- a/lib/posix/Kconfig.getopt +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2021 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 - -source "lib/posix/getopt/Kconfig" diff --git a/lib/posix/Kconfig.limits b/lib/posix/Kconfig.limits deleted file mode 100644 index cc651203961..00000000000 --- a/lib/posix/Kconfig.limits +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -if POSIX_SIGNAL -config POSIX_LIMITS_RTSIG_MAX - int "_POSIX_RTSIG_MAX value in limits.h" - default 8 - help - Define the _POSIX_RTSIG_MAX value in limits.h. - IEEE 1003.1 defines this to be 8. - -endif diff --git a/lib/posix/Kconfig.pthread b/lib/posix/Kconfig.pthread deleted file mode 100644 index 388a30c5fa4..00000000000 --- a/lib/posix/Kconfig.pthread +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2017 Intel Corporation -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -TYPE = PTHREAD -type = pthread_t -type-function = pthread_create -source "lib/posix/Kconfig.template.pooled_ipc_type" - -if PTHREAD - -config PTHREAD_RECYCLER_DELAY_MS - int "Delay for reclaiming dynamic pthread stacks (ms)" - default 100 - help - Prior to a POSIX thread terminating via k_thread_abort(), scheduled - work is added to the system workqueue (SWQ) so that any resources - allocated by the thread (e.g. thread stack from a pool or the heap) - can be released back to the system. Because resources are also freed - on calls to pthread_create() there is no need to worry about resource - starvation. - - This option sets the number of milliseconds by which to defer - scheduled work. - - Note: this option should be considered temporary and will likely be - removed once a more synchronous solution is available. - -endif diff --git a/lib/posix/Kconfig.semaphore b/lib/posix/Kconfig.semaphore deleted file mode 100644 index d9b9b47a508..00000000000 --- a/lib/posix/Kconfig.semaphore +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2018 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -config SEM_VALUE_MAX - int "Maximum semaphore limit" - default 32767 - range 1 32767 - help - Maximum semaphore count in POSIX compliant Application. diff --git a/lib/posix/Kconfig.signal b/lib/posix/Kconfig.signal deleted file mode 100644 index c51e68f1f36..00000000000 --- a/lib/posix/Kconfig.signal +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -config POSIX_SIGNAL - bool "Support for POSIX signal APIs" - default y if POSIX_API - help - Enable support for POSIX signal APIs. - -if POSIX_SIGNAL -config POSIX_RTSIG_MAX - int "Maximum number of realtime signals" - default 31 - help - Define the maximum number of realtime signals (RTSIG_MAX). - The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] - -config POSIX_SIGNAL_STRING_DESC - bool "Use full description for the strsignal API" - default y - help - Use full description for the strsignal API. - Will use 256 bytes of ROM. - -endif diff --git a/lib/posix/Kconfig.spinlock b/lib/posix/Kconfig.spinlock deleted file mode 100644 index 83a95d77ed0..00000000000 --- a/lib/posix/Kconfig.spinlock +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -TYPE = PTHREAD_SPINLOCK -type = pthread_spinlock_t -type-function = pthread_spin_lock -source "lib/posix/Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.template.pooled_ipc_type b/lib/posix/Kconfig.template.pooled_ipc_type deleted file mode 100644 index d28ed345b6a..00000000000 --- a/lib/posix/Kconfig.template.pooled_ipc_type +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -source "lib/posix/Kconfig.template.with_url" -source "lib/posix/Kconfig.template.with_logging" - -# Not user configurable (i.e. private for now) -config $(TYPE) - bool "POSIX $(type) support" - depends on PTHREAD_IPC - default y - help - Support for $(TYPE) - For more info, see - $(posix-url-base)/$(type-function).html - -# eventually, this size should be defaulted to 0 -config MAX_$(TYPE)_COUNT - int "Maximum simultaneously active $(type) in POSIX application" - default 5 - depends on $(TYPE) - help - Maximum simultaneously active $(type) in a POSIX application. diff --git a/lib/posix/Kconfig.template.pooled_type b/lib/posix/Kconfig.template.pooled_type deleted file mode 100644 index a30686043a1..00000000000 --- a/lib/posix/Kconfig.template.pooled_type +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -source "lib/posix/Kconfig.template.with_url" -source "lib/posix/Kconfig.template.with_logging" - -# This is mainly for TIMER currently. -config $(TYPE) - bool "POSIX $(type) support" - help - For more info, see - $(posix-url-base)/$(type-function).html - -# eventually, this size should be defaulted to 0 as a safe value -config MAX_$(TYPE)_COUNT - int "Maximum simultaneously active $(type) in POSIX application" - default 5 - help - Maximum simultaneously active $(type) in a POSIX application. diff --git a/lib/posix/Kconfig.uname b/lib/posix/Kconfig.uname deleted file mode 100644 index d8c29479986..00000000000 --- a/lib/posix/Kconfig.uname +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2023 Meta -# -# SPDX-License-Identifier: Apache-2.0 - -config POSIX_UNAME - bool "Support for uname" - default y if POSIX_API - help - The uname() function shall store information identifying the current - system in the structure pointed to by name. - -if POSIX_UNAME -config POSIX_UNAME_VERSION_LEN - int "uname version string length" - default 60 - help - Defines the maximum string length of uname version. - -config POSIX_UNAME_NODENAME_LEN - int "uname nodename string length" - default 6 if !NET_HOSTNAME_UNIQUE - default 22 if NET_HOSTNAME_UNIQUE - help - Defines the maximum string length of nodename version. - -endif # POSIX_UNAME diff --git a/lib/posix/clock.c b/lib/posix/clock.c deleted file mode 100644 index d7ca3969aa8..00000000000 --- a/lib/posix/clock.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include - -/* - * `k_uptime_get` returns a timestamp based on an always increasing - * value from the system start. To support the `CLOCK_REALTIME` - * clock, this `rt_clock_base` records the time that the system was - * started. This can either be set via 'clock_settime', or could be - * set from a real time clock, if such hardware is present. - */ -static struct timespec rt_clock_base; -static struct k_spinlock rt_clock_base_lock; - -/** - * @brief Get clock time specified by clock_id. - * - * See IEEE 1003.1 - */ -int z_impl_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - struct timespec base; - k_spinlock_key_t key; - - switch (clock_id) { - case CLOCK_MONOTONIC: - base.tv_sec = 0; - base.tv_nsec = 0; - break; - - case CLOCK_REALTIME: - key = k_spin_lock(&rt_clock_base_lock); - base = rt_clock_base; - k_spin_unlock(&rt_clock_base_lock, key); - break; - - default: - errno = EINVAL; - return -1; - } - - uint64_t ticks = k_uptime_ticks(); - uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC; - uint64_t nremainder = ticks - elapsed_secs * CONFIG_SYS_CLOCK_TICKS_PER_SEC; - - ts->tv_sec = (time_t) elapsed_secs; - /* For ns 32 bit conversion can be used since its smaller than 1sec. */ - ts->tv_nsec = (int32_t) k_ticks_to_ns_floor32(nremainder); - - ts->tv_sec += base.tv_sec; - ts->tv_nsec += base.tv_nsec; - if (ts->tv_nsec >= NSEC_PER_SEC) { - ts->tv_sec++; - ts->tv_nsec -= NSEC_PER_SEC; - } - - return 0; -} - -#ifdef CONFIG_USERSPACE -int z_vrfy_clock_gettime(clockid_t clock_id, struct timespec *ts) -{ - K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); - return z_impl_clock_gettime(clock_id, ts); -} -#include -#endif - -/** - * @brief Set the time of the specified clock. - * - * See IEEE 1003.1. - * - * Note that only the `CLOCK_REALTIME` clock can be set using this - * call. - */ -int clock_settime(clockid_t clock_id, const struct timespec *tp) -{ - struct timespec base; - k_spinlock_key_t key; - - if (clock_id != CLOCK_REALTIME) { - errno = EINVAL; - return -1; - } - - uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks()); - int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec - - elapsed_nsecs; - - base.tv_sec = delta / NSEC_PER_SEC; - base.tv_nsec = delta % NSEC_PER_SEC; - - key = k_spin_lock(&rt_clock_base_lock); - rt_clock_base = base; - k_spin_unlock(&rt_clock_base_lock, key); - - return 0; -} - -/** - * @brief Suspend execution for a nanosecond interval, or - * until some absolute time relative to the specified clock. - * - * See IEEE 1003.1 - */ -int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, - struct timespec *rmtp) -{ - uint64_t ns; - uint64_t us; - uint64_t uptime_ns; - k_spinlock_key_t key; - const bool update_rmtp = rmtp != NULL; - - if (!(clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC)) { - errno = EINVAL; - return -1; - } - - if (rqtp == NULL) { - errno = EFAULT; - return -1; - } - - if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NSEC_PER_SEC) { - errno = EINVAL; - return -1; - } - - if ((flags & TIMER_ABSTIME) == 0 && - unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { - - ns = rqtp->tv_nsec + NSEC_PER_SEC - + k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC; - } else { - ns = rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; - } - - uptime_ns = k_cyc_to_ns_ceil64(k_cycle_get_32()); - - if (flags & TIMER_ABSTIME && clock_id == CLOCK_REALTIME) { - key = k_spin_lock(&rt_clock_base_lock); - ns -= rt_clock_base.tv_sec * NSEC_PER_SEC + rt_clock_base.tv_nsec; - k_spin_unlock(&rt_clock_base_lock, key); - } - - if ((flags & TIMER_ABSTIME) == 0) { - ns += uptime_ns; - } - - if (ns <= uptime_ns) { - goto do_rmtp_update; - } - - us = DIV_ROUND_UP(ns, NSEC_PER_USEC); - do { - us = k_sleep(K_TIMEOUT_ABS_US(us)) * 1000; - } while (us != 0); - -do_rmtp_update: - if (update_rmtp) { - rmtp->tv_sec = 0; - rmtp->tv_nsec = 0; - } - - return 0; -} - -/** - * @brief Get current real time. - * - * See IEEE 1003.1 - */ -int gettimeofday(struct timeval *tv, void *tz) -{ - struct timespec ts; - int res; - - /* As per POSIX, "if tzp is not a null pointer, the behavior - * is unspecified." "tzp" is the "tz" parameter above. */ - ARG_UNUSED(tz); - - res = clock_gettime(CLOCK_REALTIME, &ts); - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; - - return res; -} diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt new file mode 100644 index 00000000000..a0c1722df6a --- /dev/null +++ b/lib/posix/options/CMakeLists.txt @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: Apache-2.0 + +set(GEN_DIR ${ZEPHYR_BINARY_DIR}/include/generated) + +zephyr_syscall_header( + posix_clock.h +) + +if(CONFIG_POSIX_API) + zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/posix) +endif() + +if(CONFIG_POSIX_SIGNAL) + set(STRSIGNAL_TABLE_H ${GEN_DIR}/posix/strsignal_table.h) + + add_custom_command( + OUTPUT ${STRSIGNAL_TABLE_H} + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/gen_strsignal_table.py + -i ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + -o ${STRSIGNAL_TABLE_H} + DEPENDS ${ZEPHYR_BASE}/include/zephyr/posix/signal.h + ) +endif() + +if(CONFIG_POSIX_API OR CONFIG_PTHREAD_IPC OR CONFIG_POSIX_CLOCK OR + CONFIG_POSIX_MQUEUE OR CONFIG_POSIX_FS OR CONFIG_EVENTFD OR CONFIG_GETOPT) + # This is a temporary workaround so that Newlib declares the appropriate + # types for us. POSIX features to be formalized as part of #51211 + zephyr_compile_options($<$:-D_POSIX_THREADS>) + zephyr_compile_options($<$:-D_POSIX_THREADS>) +endif() + +zephyr_library() +add_subdirectory_ifdef(CONFIG_GETOPT getopt) +zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) +zephyr_library_sources_ifdef(CONFIG_FNMATCH fnmatch.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_API perror.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK clock.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK nanosleep.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_CLOCK sleep.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PUTMSG stropts.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_SIGNAL signal.c ${STRSIGNAL_TABLE_H}) +zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME uname.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC _common.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_BARRIER barrier.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_COND cond.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_KEY key.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_MUTEX mutex.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD pthread.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_RWLOCK rwlock.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_PRIORITY_SCHEDULING sched.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_IPC semaphore.c) +zephyr_library_sources_ifdef(CONFIG_PTHREAD_SPINLOCK spinlock.c) +zephyr_library_sources_ifdef(CONFIG_TIMER timer.c) + +zephyr_library_include_directories( + ${ZEPHYR_BASE}/kernel/include + ${ARCH_DIR}/${ARCH}/include +) diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig new file mode 100644 index 00000000000..c2673e164dd --- /dev/null +++ b/lib/posix/options/Kconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2018 Intel Corporation +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +menu "POSIX Options" + +config POSIX_API + depends on !NATIVE_APPLICATION + bool "POSIX APIs" + help + Enable mostly-standards-compliant implementations of + various POSIX (IEEE 1003.1) APIs. + +if POSIX_CLOCK + +config PTHREAD_IPC + bool "POSIX pthread IPC API" + default y if POSIX_API + help + This enables a mostly-standards-compliant implementation of + the pthread mutex, condition variable and barrier IPC + mechanisms. + +endif # POSIX_CLOCK + +rsource "Kconfig.barrier" +rsource "Kconfig.clock" +rsource "Kconfig.cond" +rsource "Kconfig.eventfd" +rsource "Kconfig.fdtable" +rsource "Kconfig.fnmatch" +rsource "Kconfig.fs" +rsource "Kconfig.getopt" +rsource "Kconfig.key" +rsource "Kconfig.mqueue" +rsource "Kconfig.mutex" +rsource "Kconfig.pthread" +rsource "Kconfig.rwlock" +rsource "Kconfig.sched" +rsource "Kconfig.semaphore" +rsource "Kconfig.signal" +rsource "Kconfig.spinlock" +rsource "Kconfig.stropts" +rsource "Kconfig.sysconf" +rsource "Kconfig.timer" +rsource "Kconfig.uname" + +endmenu # "POSIX Options" diff --git a/lib/posix/Kconfig.barrier b/lib/posix/options/Kconfig.barrier similarity index 92% rename from lib/posix/Kconfig.barrier rename to lib/posix/options/Kconfig.barrier index e14b39c5b08..72dd8148277 100644 --- a/lib/posix/Kconfig.barrier +++ b/lib/posix/options/Kconfig.barrier @@ -6,7 +6,7 @@ TYPE = PTHREAD_BARRIER type = pthread_barrier_t type-function = pthread_barrier_wait -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" if PTHREAD_BARRIER diff --git a/lib/posix/options/Kconfig.clock b/lib/posix/options/Kconfig.clock new file mode 100644 index 00000000000..0d541c9f32f --- /dev/null +++ b/lib/posix/options/Kconfig.clock @@ -0,0 +1,11 @@ +# Copyright (c) 2018 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_CLOCK + bool "clock and sleep APIs" + default y if POSIX_API + imply TIMER + depends on !NATIVE_LIBC + help + This enables POSIX clock\_\*() and \*sleep() functions. diff --git a/lib/posix/Kconfig.cond b/lib/posix/options/Kconfig.cond similarity index 77% rename from lib/posix/Kconfig.cond rename to lib/posix/options/Kconfig.cond index fcdf842a602..b69b35dece6 100644 --- a/lib/posix/Kconfig.cond +++ b/lib/posix/options/Kconfig.cond @@ -6,4 +6,4 @@ TYPE = PTHREAD_COND type = pthread_cond_t type-function = pthread_cond_wait -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.eventfd b/lib/posix/options/Kconfig.eventfd similarity index 96% rename from lib/posix/Kconfig.eventfd rename to lib/posix/options/Kconfig.eventfd index 0b6fa171741..eadf8f80916 100644 --- a/lib/posix/Kconfig.eventfd +++ b/lib/posix/options/Kconfig.eventfd @@ -3,7 +3,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config EVENTFD +menuconfig EVENTFD bool "Support for eventfd" depends on !NATIVE_APPLICATION select POLL diff --git a/lib/posix/options/Kconfig.fdtable b/lib/posix/options/Kconfig.fdtable new file mode 100644 index 00000000000..214e4a04ae9 --- /dev/null +++ b/lib/posix/options/Kconfig.fdtable @@ -0,0 +1,16 @@ +# Copyright (c) 2018 Linaro +# +# SPDX-License-Identifier: Apache-2.0 + +menu "File descriptor table options" + +config POSIX_MAX_FDS + int "Maximum number of open file descriptors" + default 16 if WIFI_NM_WPA_SUPPLICANT + default 16 if POSIX_API + default 4 + help + Maximum number of open file descriptors, this includes + files, sockets, special devices, etc. + +endmenu # "File descriptor table options" diff --git a/lib/posix/Kconfig.fnmatch b/lib/posix/options/Kconfig.fnmatch similarity index 100% rename from lib/posix/Kconfig.fnmatch rename to lib/posix/options/Kconfig.fnmatch diff --git a/lib/posix/Kconfig.fs b/lib/posix/options/Kconfig.fs similarity index 95% rename from lib/posix/Kconfig.fs rename to lib/posix/options/Kconfig.fs index 1d032910539..e4d5f1dea6e 100644 --- a/lib/posix/Kconfig.fs +++ b/lib/posix/options/Kconfig.fs @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -config POSIX_FS +menuconfig POSIX_FS bool "POSIX file system API support" default y if POSIX_API depends on FILE_SYSTEM diff --git a/lib/posix/options/Kconfig.getopt b/lib/posix/options/Kconfig.getopt new file mode 100644 index 00000000000..4d3559cd855 --- /dev/null +++ b/lib/posix/options/Kconfig.getopt @@ -0,0 +1,5 @@ +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +rsource "getopt/Kconfig" diff --git a/lib/posix/Kconfig.key b/lib/posix/options/Kconfig.key similarity index 77% rename from lib/posix/Kconfig.key rename to lib/posix/options/Kconfig.key index 6e8538233eb..671cce10373 100644 --- a/lib/posix/Kconfig.key +++ b/lib/posix/options/Kconfig.key @@ -6,4 +6,4 @@ TYPE = PTHREAD_KEY type = pthread_key_t type-function = pthread_setspecific -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/Kconfig.mqueue b/lib/posix/options/Kconfig.mqueue similarity index 85% rename from lib/posix/Kconfig.mqueue rename to lib/posix/options/Kconfig.mqueue index 58e04d21faf..3688455d781 100644 --- a/lib/posix/Kconfig.mqueue +++ b/lib/posix/options/Kconfig.mqueue @@ -2,8 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 -config POSIX_MQUEUE - bool "POSIX message queue" +menuconfig POSIX_MQUEUE + bool "Message queue support" default y if POSIX_API help This enabled POSIX message queue related APIs. @@ -30,4 +30,7 @@ config MQUEUE_NAMELEN_MAX help Mention length of message queue name in number of characters. +config HEAP_MEM_POOL_ADD_SIZE_MQUEUE + def_int 1024 + endif diff --git a/lib/posix/Kconfig.mutex b/lib/posix/options/Kconfig.mutex similarity index 78% rename from lib/posix/Kconfig.mutex rename to lib/posix/options/Kconfig.mutex index c34881017e5..6d5729e80aa 100644 --- a/lib/posix/Kconfig.mutex +++ b/lib/posix/options/Kconfig.mutex @@ -6,4 +6,4 @@ TYPE = PTHREAD_MUTEX type = pthread_mutex_t type-function = pthread_mutex_lock -source "lib/posix/Kconfig.template.pooled_ipc_type" +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/options/Kconfig.pthread b/lib/posix/options/Kconfig.pthread new file mode 100644 index 00000000000..f0c65836b60 --- /dev/null +++ b/lib/posix/options/Kconfig.pthread @@ -0,0 +1,62 @@ +# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +TYPE = PTHREAD +type = pthread_t +type-function = pthread_create +rsource "Kconfig.template.pooled_ipc_type" + +if PTHREAD + +config PTHREAD_RECYCLER_DELAY_MS + int "Delay for reclaiming dynamic pthread stacks (ms)" + default 100 + help + Prior to a POSIX thread terminating via k_thread_abort(), scheduled + work is added to the system workqueue (SWQ) so that any resources + allocated by the thread (e.g. thread stack from a pool or the heap) + can be released back to the system. Because resources are also freed + on calls to pthread_create() there is no need to worry about resource + starvation. + + This option sets the number of milliseconds by which to defer + scheduled work. + + Note: this option should be considered temporary and will likely be + removed once a more synchronous solution is available. + +config POSIX_PTHREAD_ATTR_STACKSIZE_BITS + int "Significant bits for pthread_attr_t stacksize" + range 8 31 + default 23 + help + This value plays a part in determining the maximum supported + pthread_attr_t stacksize. Valid stacksizes are in the range + [1, N], where N = 1 << M, and M is this configuration value. + +config POSIX_PTHREAD_ATTR_GUARDSIZE_BITS + int "Significant bits for pthread_attr_t guardsize" + range 1 31 + default 9 + help + This value plays a part in determining the maximum supported + pthread_attr_t guardsize. Valid guardsizes are in the range + [0, N-1], where N = 1 << M, and M is this configuration value. + + Actual guardsize values may be rounded-up. + +config POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT + int "Default size of stack guard area" + default 0 + help + This is the default amount of space to reserve at the overflow end of a + pthread stack. Since Zephyr already supports both software-based stack + protection (canaries) and hardware-based stack protection (MMU or MPU), + this is set to 0 by default. However, a conforming application would be + required to set this to PAGESIZE. Eventually, this option might + facilitate a more dynamic approach to guard areas (via software or + hardware) but for now it simply increases the size of thread stacks. + +endif diff --git a/lib/posix/options/Kconfig.rwlock b/lib/posix/options/Kconfig.rwlock new file mode 100644 index 00000000000..fea61551ec3 --- /dev/null +++ b/lib/posix/options/Kconfig.rwlock @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +TYPE = PTHREAD_RWLOCK +type = pthread_rwlock_t +type-function = pthread_rwlock_timedrdlock +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/options/Kconfig.sched b/lib/posix/options/Kconfig.sched new file mode 100644 index 00000000000..b5fb3a5dcb1 --- /dev/null +++ b/lib/posix/options/Kconfig.sched @@ -0,0 +1,11 @@ +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_PRIORITY_SCHEDULING + bool "Priority scheduling" + default y if PTHREAD + default y if POSIX_API + depends on PTHREAD + help + This enables POSIX scheduling APIs (_POSIX_PRIORITY_SCHEDULING). diff --git a/lib/posix/options/Kconfig.semaphore b/lib/posix/options/Kconfig.semaphore new file mode 100644 index 00000000000..53fb030736b --- /dev/null +++ b/lib/posix/options/Kconfig.semaphore @@ -0,0 +1,22 @@ +# Copyright (c) 2018 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menu "sem_t support" + +config SEM_VALUE_MAX + int "Maximum semaphore limit" + default 32767 + range 1 32767 + help + Maximum semaphore count in POSIX compliant Application. + +config SEM_NAMELEN_MAX + int "Maximum name length" + default 16 + range 2 255 + help + Maximum length of name for a named semaphore. + The max value of 255 corresponds to {NAME_MAX}. + +endmenu # "sem_t support" diff --git a/lib/posix/options/Kconfig.signal b/lib/posix/options/Kconfig.signal new file mode 100644 index 00000000000..99c225564c7 --- /dev/null +++ b/lib/posix/options/Kconfig.signal @@ -0,0 +1,40 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Signal support" + +# needed outside of if clause above to define constants & types in signal.h +config POSIX_RTSIG_MAX + int "Maximum number of realtime signals" + default 31 if POSIX_SIGNAL + default 0 + help + Define the maximum number of realtime signals (RTSIG_MAX). + The range of realtime signals is [SIGRTMIN .. (SIGRTMIN+RTSIG_MAX)] + +config POSIX_SIGNAL + bool "Support for POSIX signal APIs" + default y if POSIX_API + help + Enable support for POSIX signal APIs. + +if POSIX_SIGNAL + +config POSIX_SIGNAL_STRING_DESC + bool "Use full description for the strsignal API" + default y + help + Use full description for the strsignal API. + Will use 256 bytes of ROM. + +config POSIX_LIMITS_RTSIG_MAX + int "_POSIX_RTSIG_MAX value in limits.h" + default 8 + help + Define the _POSIX_RTSIG_MAX value in limits.h. + IEEE 1003.1 defines this to be 8. + +endif + +endmenu # "Signal support" diff --git a/lib/posix/options/Kconfig.spinlock b/lib/posix/options/Kconfig.spinlock new file mode 100644 index 00000000000..8374aadfd6d --- /dev/null +++ b/lib/posix/options/Kconfig.spinlock @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +TYPE = PTHREAD_SPINLOCK +type = pthread_spinlock_t +type-function = pthread_spin_lock +rsource "Kconfig.template.pooled_ipc_type" diff --git a/lib/posix/options/Kconfig.stropts b/lib/posix/options/Kconfig.stropts new file mode 100644 index 00000000000..347f0f33c15 --- /dev/null +++ b/lib/posix/options/Kconfig.stropts @@ -0,0 +1,9 @@ +# copyright (c) 2024 Abhinav Srivastava +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_PUTMSG + bool "Support for putmsg function" + default y if POSIX_API + help + This option provides support for the putmsg function used in message passing. diff --git a/lib/posix/options/Kconfig.sysconf b/lib/posix/options/Kconfig.sysconf new file mode 100644 index 00000000000..32f37f1c29d --- /dev/null +++ b/lib/posix/options/Kconfig.sysconf @@ -0,0 +1,24 @@ +# Copyright (c) 2024 BayLibre SAS +# +# SPDX-License-Identifier: Apache-2.0 + +menu "Sysconf support" + +config POSIX_SYSCONF + bool "Support for sysconf" + default y if POSIX_API + help + The sysconf() function provides a method for the application to determine + the current value of a configurable system limit or option (variable). + +config POSIX_PAGE_SIZE_BITS + int "Number of bits to use for PAGE_SIZE" + range 6 16 + default 12 if POSIX_API + default 6 + help + Define PAGE_SIZE as BIT(n), where n is the value configured here. + PAGE_SIZE is supported in the range [64, 65536] + If CONFIG_POSIX_API=y, PAGE_SIZE defaults to 4096, otherwise, it is 64 bytes. + +endmenu # "Sysconf support" diff --git a/lib/posix/options/Kconfig.template.pooled_ipc_type b/lib/posix/options/Kconfig.template.pooled_ipc_type new file mode 100644 index 00000000000..08d804382e8 --- /dev/null +++ b/lib/posix/options/Kconfig.template.pooled_ipc_type @@ -0,0 +1,29 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +rsource "Kconfig.template.with_url" + +# Not user configurable (i.e. private for now) +menuconfig $(TYPE) + bool "$(type) support" + depends on PTHREAD_IPC + default y + help + Support for $(TYPE) + For more info, see + $(posix-url-base)/$(type-function).html + +if $(TYPE) + +# eventually, this size should be defaulted to 0 +config MAX_$(TYPE)_COUNT + int "Maximum number of $(type)" + default 5 + depends on $(TYPE) + help + Maximum simultaneously active $(type) in a POSIX application. + +rsource "Kconfig.template.with_logging" + +endif # $(TYPE) diff --git a/lib/posix/options/Kconfig.template.pooled_type b/lib/posix/options/Kconfig.template.pooled_type new file mode 100644 index 00000000000..5a75c2ee890 --- /dev/null +++ b/lib/posix/options/Kconfig.template.pooled_type @@ -0,0 +1,25 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +rsource "Kconfig.template.with_url" + +# This is mainly for TIMER currently. +menuconfig $(TYPE) + bool "$(type) support" + help + For more info, see + $(posix-url-base)/$(type-function).html + +if $(TYPE) + +# eventually, this size should be defaulted to 0 as a safe value +config MAX_$(TYPE)_COUNT + int "Maximum number of $(type)" + default 5 + help + Maximum simultaneously active $(type) in a POSIX application. + +rsource "Kconfig.template.with_logging" + +endif # $(TYPE) diff --git a/lib/posix/Kconfig.template.with_logging b/lib/posix/options/Kconfig.template.with_logging similarity index 100% rename from lib/posix/Kconfig.template.with_logging rename to lib/posix/options/Kconfig.template.with_logging diff --git a/lib/posix/Kconfig.template.with_url b/lib/posix/options/Kconfig.template.with_url similarity index 100% rename from lib/posix/Kconfig.template.with_url rename to lib/posix/options/Kconfig.template.with_url diff --git a/lib/posix/Kconfig.timer b/lib/posix/options/Kconfig.timer similarity index 90% rename from lib/posix/Kconfig.timer rename to lib/posix/options/Kconfig.timer index 28173692e0c..10905e9c21d 100644 --- a/lib/posix/Kconfig.timer +++ b/lib/posix/options/Kconfig.timer @@ -5,7 +5,9 @@ TYPE = TIMER type = timer_t type-function = timer_create -source "lib/posix/Kconfig.template.pooled_type" +rsource "Kconfig.template.pooled_type" + +if TIMER config TIMER_CREATE_WAIT int "Time to wait for timer availability (in msec) in POSIX application" @@ -21,3 +23,5 @@ config TIMER_DELAYTIMER_MAX help This controls the maximum number of times a timer can overrun before timer_getoverrun() in POSIX compliant application. + +endif # TIMER diff --git a/lib/posix/options/Kconfig.uname b/lib/posix/options/Kconfig.uname new file mode 100644 index 00000000000..09b52602db1 --- /dev/null +++ b/lib/posix/options/Kconfig.uname @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Meta +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig POSIX_UNAME + bool "Support for uname" + default y if POSIX_API + help + The uname() function shall store information identifying the current + system in the structure pointed to by name. + +if POSIX_UNAME +config POSIX_UNAME_VERSION_LEN + int "uname version string length" + default 60 + help + Defines the maximum string length of uname version. + +config POSIX_UNAME_NODENAME_LEN + int "uname nodename string length" + default 6 if !NET_HOSTNAME_UNIQUE + default 22 if NET_HOSTNAME_UNIQUE + help + Defines the maximum string length of nodename version. + +endif # POSIX_UNAME diff --git a/lib/posix/_common.c b/lib/posix/options/_common.c similarity index 100% rename from lib/posix/_common.c rename to lib/posix/options/_common.c diff --git a/lib/posix/barrier.c b/lib/posix/options/barrier.c similarity index 100% rename from lib/posix/barrier.c rename to lib/posix/options/barrier.c diff --git a/lib/posix/options/clock.c b/lib/posix/options/clock.c new file mode 100644 index 00000000000..a8835a44248 --- /dev/null +++ b/lib/posix/options/clock.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_clock.h" + +#include +#include +#include +#include +#include +#include +#include + +/* + * `k_uptime_get` returns a timestamp based on an always increasing + * value from the system start. To support the `CLOCK_REALTIME` + * clock, this `rt_clock_base` records the time that the system was + * started. This can either be set via 'clock_settime', or could be + * set from a real time clock, if such hardware is present. + */ +static struct timespec rt_clock_base; +static struct k_spinlock rt_clock_base_lock; + +/** + * @brief Get clock time specified by clock_id. + * + * See IEEE 1003.1 + */ +int z_impl___posix_clock_get_base(clockid_t clock_id, struct timespec *base) +{ + switch (clock_id) { + case CLOCK_MONOTONIC: + base->tv_sec = 0; + base->tv_nsec = 0; + break; + + case CLOCK_REALTIME: + K_SPINLOCK(&rt_clock_base_lock) { + *base = rt_clock_base; + } + break; + + default: + errno = EINVAL; + return -1; + } + + return 0; +} + +#ifdef CONFIG_USERSPACE +int z_vrfy___posix_clock_get_base(clockid_t clock_id, struct timespec *ts) +{ + K_OOPS(K_SYSCALL_MEMORY_WRITE(ts, sizeof(*ts))); + return z_impl___posix_clock_get_base(clock_id, ts); +} +#include +#endif + +int clock_gettime(clockid_t clock_id, struct timespec *ts) +{ + struct timespec base; + + switch (clock_id) { + case CLOCK_MONOTONIC: + base.tv_sec = 0; + base.tv_nsec = 0; + break; + + case CLOCK_REALTIME: + (void)__posix_clock_get_base(clock_id, &base); + break; + + default: + errno = EINVAL; + return -1; + } + + uint64_t ticks = k_uptime_ticks(); + uint64_t elapsed_secs = ticks / CONFIG_SYS_CLOCK_TICKS_PER_SEC; + uint64_t nremainder = ticks - elapsed_secs * CONFIG_SYS_CLOCK_TICKS_PER_SEC; + + ts->tv_sec = (time_t) elapsed_secs; + /* For ns 32 bit conversion can be used since its smaller than 1sec. */ + ts->tv_nsec = (int32_t) k_ticks_to_ns_floor32(nremainder); + + ts->tv_sec += base.tv_sec; + ts->tv_nsec += base.tv_nsec; + if (ts->tv_nsec >= NSEC_PER_SEC) { + ts->tv_sec++; + ts->tv_nsec -= NSEC_PER_SEC; + } + + return 0; +} + +/** + * @brief Set the time of the specified clock. + * + * See IEEE 1003.1. + * + * Note that only the `CLOCK_REALTIME` clock can be set using this + * call. + */ +int clock_settime(clockid_t clock_id, const struct timespec *tp) +{ + struct timespec base; + k_spinlock_key_t key; + + if (clock_id != CLOCK_REALTIME) { + errno = EINVAL; + return -1; + } + + if (tp->tv_nsec < 0 || tp->tv_nsec >= NSEC_PER_SEC) { + errno = EINVAL; + return -1; + } + + uint64_t elapsed_nsecs = k_ticks_to_ns_floor64(k_uptime_ticks()); + int64_t delta = (int64_t)NSEC_PER_SEC * tp->tv_sec + tp->tv_nsec + - elapsed_nsecs; + + base.tv_sec = delta / NSEC_PER_SEC; + base.tv_nsec = delta % NSEC_PER_SEC; + + key = k_spin_lock(&rt_clock_base_lock); + rt_clock_base = base; + k_spin_unlock(&rt_clock_base_lock, key); + + return 0; +} + +/** + * @brief Suspend execution for a nanosecond interval, or + * until some absolute time relative to the specified clock. + * + * See IEEE 1003.1 + */ +int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, + struct timespec *rmtp) +{ + uint64_t ns; + uint64_t us; + uint64_t uptime_ns; + k_spinlock_key_t key; + const bool update_rmtp = rmtp != NULL; + + if (!(clock_id == CLOCK_REALTIME || clock_id == CLOCK_MONOTONIC)) { + errno = EINVAL; + return -1; + } + + if (rqtp == NULL) { + errno = EFAULT; + return -1; + } + + if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NSEC_PER_SEC) { + errno = EINVAL; + return -1; + } + + if ((flags & TIMER_ABSTIME) == 0 && + unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { + + ns = rqtp->tv_nsec + NSEC_PER_SEC + + k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC; + } else { + ns = rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; + } + + uptime_ns = k_cyc_to_ns_ceil64(k_cycle_get_32()); + + if (flags & TIMER_ABSTIME && clock_id == CLOCK_REALTIME) { + key = k_spin_lock(&rt_clock_base_lock); + ns -= rt_clock_base.tv_sec * NSEC_PER_SEC + rt_clock_base.tv_nsec; + k_spin_unlock(&rt_clock_base_lock, key); + } + + if ((flags & TIMER_ABSTIME) == 0) { + ns += uptime_ns; + } + + if (ns <= uptime_ns) { + goto do_rmtp_update; + } + + us = DIV_ROUND_UP(ns, NSEC_PER_USEC); + do { + us = k_sleep(K_TIMEOUT_ABS_US(us)) * 1000; + } while (us != 0); + +do_rmtp_update: + if (update_rmtp) { + rmtp->tv_sec = 0; + rmtp->tv_nsec = 0; + } + + return 0; +} + +/** + * @brief Get current real time. + * + * See IEEE 1003.1 + */ +int gettimeofday(struct timeval *tv, void *tz) +{ + struct timespec ts; + int res; + + /* As per POSIX, "if tzp is not a null pointer, the behavior + * is unspecified." "tzp" is the "tz" parameter above. */ + ARG_UNUSED(tz); + + res = clock_gettime(CLOCK_REALTIME, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + + return res; +} + +int clock_getcpuclockid(pid_t pid, clockid_t *clock_id) +{ + /* We don't allow any process ID but our own. */ + if (pid != 0 && pid != getpid()) { + return EPERM; + } + + *clock_id = CLOCK_PROCESS_CPUTIME_ID; + + return 0; +} + +#ifdef CONFIG_ZTEST +#include +static void reset_clock_base(void) +{ + K_SPINLOCK(&rt_clock_base_lock) { + rt_clock_base = (struct timespec){0}; + } +} + +static void clock_base_reset_rule_after(const struct ztest_unit_test *test, void *data) +{ + ARG_UNUSED(test); + ARG_UNUSED(data); + + reset_clock_base(); +} + +ZTEST_RULE(clock_base_reset_rule, NULL, clock_base_reset_rule_after); +#endif /* CONFIG_ZTEST */ diff --git a/lib/posix/cond.c b/lib/posix/options/cond.c similarity index 100% rename from lib/posix/cond.c rename to lib/posix/options/cond.c diff --git a/lib/posix/eventfd.c b/lib/posix/options/eventfd.c similarity index 100% rename from lib/posix/eventfd.c rename to lib/posix/options/eventfd.c diff --git a/lib/posix/fnmatch.c b/lib/posix/options/fnmatch.c similarity index 99% rename from lib/posix/fnmatch.c rename to lib/posix/options/fnmatch.c index 338891fd9b3..b5285851359 100644 --- a/lib/posix/fnmatch.c +++ b/lib/posix/options/fnmatch.c @@ -44,6 +44,7 @@ #include #include +#include #define EOS '\0' @@ -243,7 +244,7 @@ static int fnmatchx(const char *pattern, const char *string, int flags, size_t r --pattern; } } - /* FALLTHROUGH */ + __fallthrough; default: if (c != FOLDCASE(*string++, flags)) { return FNM_NOMATCH; @@ -252,7 +253,6 @@ static int fnmatchx(const char *pattern, const char *string, int flags, size_t r break; } } - /* NOTREACHED */ } int fnmatch(const char *pattern, const char *string, int flags) diff --git a/lib/posix/fs.c b/lib/posix/options/fs.c similarity index 100% rename from lib/posix/fs.c rename to lib/posix/options/fs.c diff --git a/lib/posix/getopt/CMakeLists.txt b/lib/posix/options/getopt/CMakeLists.txt similarity index 100% rename from lib/posix/getopt/CMakeLists.txt rename to lib/posix/options/getopt/CMakeLists.txt diff --git a/lib/posix/getopt/Kconfig b/lib/posix/options/getopt/Kconfig similarity index 100% rename from lib/posix/getopt/Kconfig rename to lib/posix/options/getopt/Kconfig diff --git a/lib/posix/getopt/README b/lib/posix/options/getopt/README similarity index 100% rename from lib/posix/getopt/README rename to lib/posix/options/getopt/README diff --git a/lib/posix/getopt/getopt.c b/lib/posix/options/getopt/getopt.c similarity index 99% rename from lib/posix/getopt/getopt.c rename to lib/posix/options/getopt/getopt.c index 514af721cb5..c17a0ff04c2 100644 --- a/lib/posix/getopt/getopt.c +++ b/lib/posix/options/getopt/getopt.c @@ -30,7 +30,7 @@ */ #include -#ifdef CONFIG_ARCH_POSIX +#ifdef CONFIG_NATIVE_LIBC #include #else #include diff --git a/lib/posix/getopt/getopt.h b/lib/posix/options/getopt/getopt.h similarity index 100% rename from lib/posix/getopt/getopt.h rename to lib/posix/options/getopt/getopt.h diff --git a/lib/posix/getopt/getopt_common.c b/lib/posix/options/getopt/getopt_common.c similarity index 100% rename from lib/posix/getopt/getopt_common.c rename to lib/posix/options/getopt/getopt_common.c diff --git a/lib/posix/getopt/getopt_common.h b/lib/posix/options/getopt/getopt_common.h similarity index 100% rename from lib/posix/getopt/getopt_common.h rename to lib/posix/options/getopt/getopt_common.h diff --git a/lib/posix/getopt/getopt_long.c b/lib/posix/options/getopt/getopt_long.c similarity index 100% rename from lib/posix/getopt/getopt_long.c rename to lib/posix/options/getopt/getopt_long.c diff --git a/lib/posix/key.c b/lib/posix/options/key.c similarity index 77% rename from lib/posix/key.c rename to lib/posix/options/key.c index 03d03eed84a..20237f36712 100644 --- a/lib/posix/key.c +++ b/lib/posix/options/key.c @@ -7,15 +7,18 @@ #include "posix_internal.h" #include +#include #include -#include #include +#include struct pthread_key_data { sys_snode_t node; pthread_thread_data thread_data; }; +LOG_MODULE_REGISTER(pthread_key, CONFIG_PTHREAD_KEY_LOG_LEVEL); + static struct k_spinlock pthread_key_lock; /* This is non-standard (i.e. an implementation detail) */ @@ -49,16 +52,19 @@ static pthread_key_obj *get_posix_key(pthread_key_t key) /* if the provided cond does not claim to be initialized, its invalid */ if (!is_pthread_obj_initialized(key)) { + LOG_ERR("Key is uninitialized (%x)", key); return NULL; } /* Mask off the MSB to get the actual bit index */ if (sys_bitarray_test_bit(&posix_key_bitarray, bit, &actually_initialized) < 0) { + LOG_ERR("Key is invalid (%x)", key); return NULL; } if (actually_initialized == 0) { /* The cond claims to be initialized but is actually not */ + LOG_ERR("Key claims to be initialized (%x)", key); return NULL; } @@ -109,6 +115,7 @@ int pthread_key_create(pthread_key_t *key, sys_slist_init(&(new_key->key_data_l)); new_key->destructor = destructor; + LOG_DBG("Initialized key %p (%x)", new_key, *key); return 0; } @@ -120,6 +127,8 @@ int pthread_key_create(pthread_key_t *key, */ int pthread_key_delete(pthread_key_t key) { + size_t bit; + __unused int ret; pthread_key_obj *key_obj; struct pthread_key_data *key_data; sys_snode_t *node_l, *next_node_l; @@ -143,12 +152,17 @@ int pthread_key_delete(pthread_key_t key) /* Deallocate the object's memory */ k_free((void *)key_data); + LOG_DBG("Freed key data %p for key %x in thread %x", key_data, key, pthread_self()); } - (void)sys_bitarray_free(&posix_key_bitarray, 1, 0); + bit = posix_key_to_offset(key_obj); + ret = sys_bitarray_free(&posix_key_bitarray, 1, bit); + __ASSERT_NO_MSG(ret == 0); k_spin_unlock(&pthread_key_lock, key_key); + LOG_DBG("Deleted key %p (%x)", key_obj, key); + return 0; } @@ -160,13 +174,18 @@ int pthread_key_delete(pthread_key_t key) int pthread_setspecific(pthread_key_t key, const void *value) { pthread_key_obj *key_obj; - struct posix_thread *thread = to_posix_thread(pthread_self()); + struct posix_thread *thread; struct pthread_key_data *key_data; pthread_thread_data *thread_spec_data; k_spinlock_key_t key_key; sys_snode_t *node_l; int retval = 0; + thread = to_posix_thread(pthread_self()); + if (thread == NULL) { + return EINVAL; + } + /* Traverse the list of keys set by the thread, looking for key. * If the key is already in the list, re-assign its value. * Else add the key to the thread's list. @@ -189,6 +208,8 @@ int pthread_setspecific(pthread_key_t key, const void *value) * associate thread specific data */ thread_spec_data->spec_data = (void *)value; + LOG_DBG("Paired key %x to value %p for thread %x", key, value, + pthread_self()); goto out; } } @@ -197,22 +218,25 @@ int pthread_setspecific(pthread_key_t key, const void *value) key_data = k_malloc(sizeof(struct pthread_key_data)); if (key_data == NULL) { + LOG_ERR("Failed to allocate key data for key %x", key); retval = ENOMEM; goto out; + } - } else { - /* Associate thread specific data, initialize new key */ - key_data->thread_data.key = key_obj; - key_data->thread_data.spec_data = (void *)value; + LOG_DBG("Allocated key data %p for key %x in thread %x", key_data, key, + pthread_self()); - /* Append new thread key data to thread's key list */ - sys_slist_append((&thread->key_list), - (sys_snode_t *)(&key_data->thread_data)); + /* Associate thread specific data, initialize new key */ + key_data->thread_data.key = key_obj; + key_data->thread_data.spec_data = (void *)value; - /* Append new key data to the key object's list */ - sys_slist_append(&(key_obj->key_data_l), - (sys_snode_t *)key_data); - } + /* Append new thread key data to thread's key list */ + sys_slist_append((&thread->key_list), (sys_snode_t *)(&key_data->thread_data)); + + /* Append new key data to the key object's list */ + sys_slist_append(&(key_obj->key_data_l), (sys_snode_t *)key_data); + + LOG_DBG("Paired key %x to value %p for thread %x", key, value, pthread_self()); } out: @@ -229,12 +253,17 @@ int pthread_setspecific(pthread_key_t key, const void *value) void *pthread_getspecific(pthread_key_t key) { pthread_key_obj *key_obj; - struct posix_thread *thread = to_posix_thread(pthread_self()); + struct posix_thread *thread; pthread_thread_data *thread_spec_data; void *value = NULL; sys_snode_t *node_l; k_spinlock_key_t key_key; + thread = to_posix_thread(pthread_self()); + if (thread == NULL) { + return NULL; + } + key_key = k_spin_lock(&pthread_key_lock); key_obj = get_posix_key(key); @@ -243,8 +272,6 @@ void *pthread_getspecific(pthread_key_t key) return NULL; } - node_l = sys_slist_peek_head(&(thread->key_list)); - /* Traverse the list of keys set by the thread, looking for key */ SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) { diff --git a/lib/posix/mqueue.c b/lib/posix/options/mqueue.c similarity index 79% rename from lib/posix/mqueue.c rename to lib/posix/options/mqueue.c index 5c3d5e5e5d9..042b40910a8 100644 --- a/lib/posix/mqueue.c +++ b/lib/posix/options/mqueue.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024 BayLibre, SAS * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +8,10 @@ #include #include #include -#include #include +#include + +#define SIGEV_MASK (SIGEV_NONE | SIGEV_SIGNAL | SIGEV_THREAD) typedef struct mqueue_object { sys_snode_t snode; @@ -17,6 +20,7 @@ typedef struct mqueue_object { struct k_msgq queue; atomic_t ref_count; char *name; + struct sigevent not; } mqueue_object; typedef struct mqueue_desc { @@ -34,20 +38,11 @@ int64_t timespec_to_timeoutms(const struct timespec *abstime); static mqueue_object *find_in_list(const char *name); static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_len, k_timeout_t timeout); -static int receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len, +static int32_t receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len, k_timeout_t timeout); +static void remove_notification(mqueue_object *msg_queue); static void remove_mq(mqueue_object *msg_queue); - -#if defined(__sparc__) -/* - * mode_t is defined as "unsigned short" on SPARC newlib. This type is promoted - * to "int" when passed through '...' so we should pass the promoted type to - * va_arg(). - */ -#define PROMOTED_MODE_T int -#else -#define PROMOTED_MODE_T mode_t -#endif +static void *mq_notify_thread(void *arg); /** * @brief Open a message queue. @@ -69,7 +64,8 @@ mqd_t mq_open(const char *name, int oflags, ...) va_start(va, oflags); if ((oflags & O_CREAT) != 0) { - mode = va_arg(va, PROMOTED_MODE_T); + BUILD_ASSERT(sizeof(mode_t) <= sizeof(int)); + mode = va_arg(va, unsigned int); attrs = va_arg(va, struct mq_attr*); } va_end(va); @@ -351,6 +347,74 @@ int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, return 0; } +/** + * @brief Notify process that a message is available. + * + * See IEEE 1003.1 + */ +int mq_notify(mqd_t mqdes, const struct sigevent *notification) +{ + mqueue_desc *mqd = (mqueue_desc *)mqdes; + + if (mqd == NULL) { + errno = EBADF; + return -1; + } + + mqueue_object *msg_queue = mqd->mqueue; + + if (notification == NULL) { + if ((msg_queue->not.sigev_notify & SIGEV_MASK) == 0) { + errno = EINVAL; + return -1; + } + remove_notification(msg_queue); + return 0; + } + + if ((msg_queue->not.sigev_notify & SIGEV_MASK) != 0) { + errno = EBUSY; + return -1; + } + if (notification->sigev_notify == SIGEV_SIGNAL) { + errno = ENOSYS; + return -1; + } + if (notification->sigev_notify_attributes != NULL) { + int ret = pthread_attr_setdetachstate(notification->sigev_notify_attributes, + PTHREAD_CREATE_DETACHED); + if (ret != 0) { + errno = ret; + return -1; + } + } + + k_sem_take(&mq_sem, K_FOREVER); + memcpy(&msg_queue->not, notification, sizeof(struct sigevent)); + k_sem_give(&mq_sem); + + return 0; +} + +static void *mq_notify_thread(void *arg) +{ + mqueue_object *mqueue = (mqueue_object *)arg; + struct sigevent *sevp = &mqueue->not; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + if (sevp->sigev_notify_attributes == NULL) { + pthread_detach(pthread_self()); + } + + sevp->sigev_notify_function(sevp->sigev_value); + + remove_notification(mqueue); + + pthread_exit(NULL); + return NULL; +} + /* Internal functions */ static mqueue_object *find_in_list(const char *name) { @@ -390,11 +454,28 @@ static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_le return ret; } + uint32_t msgq_num = k_msgq_num_used_get(&mqd->mqueue->queue); + if (k_msgq_put(&mqd->mqueue->queue, (void *)msg_ptr, timeout) != 0) { errno = K_TIMEOUT_EQ(timeout, K_NO_WAIT) ? EAGAIN : ETIMEDOUT; return ret; } + if (k_msgq_num_used_get(&mqd->mqueue->queue) - msgq_num > 0) { + struct sigevent *sevp = &mqd->mqueue->not; + + if (sevp->sigev_notify == SIGEV_NONE) { + sevp->sigev_notify_function(sevp->sigev_value); + } else if (sevp->sigev_notify == SIGEV_THREAD) { + pthread_t th; + + ret = pthread_create(&th, + sevp->sigev_notify_attributes, + mq_notify_thread, + mqd->mqueue); + } + } + return 0; } @@ -438,3 +519,10 @@ static void remove_mq(mqueue_object *msg_queue) k_free(msg_queue->mem_obj); } } + +static void remove_notification(mqueue_object *msg_queue) +{ + k_sem_take(&mq_sem, K_FOREVER); + memset(&msg_queue->not, 0, sizeof(struct sigevent)); + k_sem_give(&mq_sem); +} diff --git a/lib/posix/mutex.c b/lib/posix/options/mutex.c similarity index 100% rename from lib/posix/mutex.c rename to lib/posix/options/mutex.c diff --git a/lib/posix/nanosleep.c b/lib/posix/options/nanosleep.c similarity index 100% rename from lib/posix/nanosleep.c rename to lib/posix/options/nanosleep.c diff --git a/lib/posix/perror.c b/lib/posix/options/perror.c similarity index 100% rename from lib/posix/perror.c rename to lib/posix/options/perror.c diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h new file mode 100644 index 00000000000..a665f4ce06d --- /dev/null +++ b/lib/posix/options/posix_clock.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ +#define ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ + +#include + +#include +#include + +__syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); + +#include + +#endif diff --git a/lib/posix/options/posix_internal.h b/lib/posix/options/posix_internal.h new file mode 100644 index 00000000000..17d8c29d438 --- /dev/null +++ b/lib/posix/options/posix_internal.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ +#define ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ + +#include +#include + +#include +#include +#include +#include +#include + +/* + * Bit used to mark a pthread object as initialized. Initialization status is + * verified (against internal status) in lock / unlock / destroy functions. + */ +#define PTHREAD_OBJ_MASK_INIT 0x80000000 + +struct posix_thread_attr { + void *stack; + /* the following two bitfields should combine to be 32-bits in size */ + uint32_t stacksize : CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS; + uint16_t guardsize : CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS; + int8_t priority; + uint8_t schedpolicy: 2; + union { + bool caller_destroys: 1; + bool initialized: 1; + }; + bool cancelpending: 1; + bool cancelstate: 1; + bool canceltype: 1; + bool detachstate: 1; +}; + +struct posix_thread { + struct k_thread thread; + + /* List nodes for pthread_cleanup_push() / pthread_cleanup_pop() */ + sys_slist_t cleanup_list; + + /* List node for ready_q, run_q, or done_q */ + sys_dnode_t q_node; + + /* List of keys that thread has called pthread_setspecific() on */ + sys_slist_t key_list; + + /* pthread_attr_t */ + struct posix_thread_attr attr; + + /* Exit status */ + void *retval; + + /* Signal mask */ + sigset_t sigset; + + /* Queue ID (internal-only) */ + uint8_t qid; +}; + +typedef struct pthread_key_obj { + /* List of pthread_key_data objects that contain thread + * specific data for the key + */ + sys_slist_t key_data_l; + + /* Optional destructor that is passed to pthread_key_create() */ + void (*destructor)(void *value); +} pthread_key_obj; + +typedef struct pthread_thread_data { + sys_snode_t node; + + /* Key and thread specific data passed to pthread_setspecific() */ + pthread_key_obj *key; + void *spec_data; +} pthread_thread_data; + +static inline bool is_pthread_obj_initialized(uint32_t obj) +{ + return (obj & PTHREAD_OBJ_MASK_INIT) != 0; +} + +static inline uint32_t mark_pthread_obj_initialized(uint32_t obj) +{ + return obj | PTHREAD_OBJ_MASK_INIT; +} + +static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj) +{ + return obj & ~PTHREAD_OBJ_MASK_INIT; +} + +struct posix_thread *to_posix_thread(pthread_t pth); + +/* get and possibly initialize a posix_mutex */ +struct k_mutex *to_posix_mutex(pthread_mutex_t *mu); + +int posix_to_zephyr_priority(int priority, int policy); +int zephyr_to_posix_priority(int priority, int *policy); + +#endif diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c new file mode 100644 index 00000000000..98761f74064 --- /dev/null +++ b/lib/posix/options/pthread.c @@ -0,0 +1,1353 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_internal.h" +#include "pthread_sched.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZEPHYR_TO_POSIX_PRIORITY(_zprio) \ + (((_zprio) < 0) ? (-1 * ((_zprio) + 1)) : (CONFIG_NUM_PREEMPT_PRIORITIES - (_zprio)-1)) + +#define POSIX_TO_ZEPHYR_PRIORITY(_prio, _pol) \ + (((_pol) == SCHED_FIFO) ? (-1 * ((_prio) + 1)) \ + : (CONFIG_NUM_PREEMPT_PRIORITIES - (_prio)-1)) + +#define DEFAULT_PTHREAD_PRIORITY \ + POSIX_TO_ZEPHYR_PRIORITY(K_LOWEST_APPLICATION_THREAD_PRIO, DEFAULT_PTHREAD_POLICY) +#define DEFAULT_PTHREAD_POLICY (IS_ENABLED(CONFIG_PREEMPT_ENABLED) ? SCHED_RR : SCHED_FIFO) + +#define PTHREAD_STACK_MAX BIT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS) +#define PTHREAD_GUARD_MAX BIT_MASK(CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS) + +LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); + +#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE +#define DYNAMIC_STACK_SIZE CONFIG_DYNAMIC_THREAD_STACK_SIZE +#else +#define DYNAMIC_STACK_SIZE 0 +#endif + +static inline size_t __get_attr_stacksize(const struct posix_thread_attr *attr) +{ + return attr->stacksize + 1; +} + +static inline void __set_attr_stacksize(struct posix_thread_attr *attr, size_t stacksize) +{ + attr->stacksize = stacksize - 1; +} + +struct __pthread_cleanup { + void (*routine)(void *arg); + void *arg; + sys_snode_t node; +}; + +enum posix_thread_qid { + /* ready to be started via pthread_create() */ + POSIX_THREAD_READY_Q, + /* running */ + POSIX_THREAD_RUN_Q, + /* exited (either joinable or detached) */ + POSIX_THREAD_DONE_Q, + /* invalid */ + POSIX_THREAD_INVALID_Q, +}; + +/* only 2 bits in struct posix_thread_attr for schedpolicy */ +BUILD_ASSERT(SCHED_OTHER < BIT(2) && SCHED_FIFO < BIT(2) && SCHED_RR < BIT(2)); + +BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && + (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1)); + +BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) && + (PTHREAD_CANCEL_ENABLE == 1 || PTHREAD_CANCEL_DISABLE == 1)); + +BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS <= + 32); + +static void posix_thread_recycle(void); +static sys_dlist_t posix_thread_q[] = { + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_READY_Q]), + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_RUN_Q]), + SYS_DLIST_STATIC_INIT(&posix_thread_q[POSIX_THREAD_DONE_Q]), +}; +static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; +static struct k_spinlock pthread_pool_lock; +static int pthread_concurrency; + +static inline void posix_thread_q_set(struct posix_thread *t, enum posix_thread_qid qid) +{ + switch (qid) { + case POSIX_THREAD_READY_Q: + case POSIX_THREAD_RUN_Q: + case POSIX_THREAD_DONE_Q: + sys_dlist_append(&posix_thread_q[qid], &t->q_node); + t->qid = qid; + break; + default: + __ASSERT(false, "cannot set invalid qid %d for posix thread %p", qid, t); + break; + } +} + +static inline enum posix_thread_qid posix_thread_q_get(struct posix_thread *t) +{ + switch (t->qid) { + case POSIX_THREAD_READY_Q: + case POSIX_THREAD_RUN_Q: + case POSIX_THREAD_DONE_Q: + return t->qid; + default: + __ASSERT(false, "posix thread %p has invalid qid: %d", t, t->qid); + return POSIX_THREAD_INVALID_Q; + } +} + +/* + * We reserve the MSB to mark a pthread_t as initialized (from the + * perspective of the application). With a linear space, this means that + * the theoretical pthread_t range is [0,2147483647]. + */ +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT < PTHREAD_OBJ_MASK_INIT, + "CONFIG_MAX_PTHREAD_COUNT is too high"); + +static inline size_t posix_thread_to_offset(struct posix_thread *t) +{ + return t - posix_thread_pool; +} + +static inline size_t get_posix_thread_idx(pthread_t pth) +{ + return mark_pthread_obj_uninitialized(pth); +} + +struct posix_thread *to_posix_thread(pthread_t pthread) +{ + struct posix_thread *t; + bool actually_initialized; + size_t bit = get_posix_thread_idx(pthread); + + /* if the provided thread does not claim to be initialized, its invalid */ + if (!is_pthread_obj_initialized(pthread)) { + LOG_ERR("pthread is not initialized (%x)", pthread); + return NULL; + } + + if (bit >= CONFIG_MAX_PTHREAD_COUNT) { + LOG_ERR("Invalid pthread (%x)", pthread); + return NULL; + } + + t = &posix_thread_pool[bit]; + + /* + * Denote a pthread as "initialized" (i.e. allocated) if it is not in ready_q. + * This differs from other posix object allocation strategies because they use + * a bitarray to indicate whether an object has been allocated. + */ + actually_initialized = !(posix_thread_q_get(t) == POSIX_THREAD_READY_Q || + (posix_thread_q_get(t) == POSIX_THREAD_DONE_Q && + t->attr.detachstate == PTHREAD_CREATE_DETACHED)); + + if (!actually_initialized) { + LOG_ERR("Pthread claims to be initialized (%x)", pthread); + return NULL; + } + + return &posix_thread_pool[bit]; +} + +pthread_t pthread_self(void) +{ + size_t bit; + struct posix_thread *t; + + t = (struct posix_thread *)CONTAINER_OF(k_current_get(), struct posix_thread, thread); + bit = posix_thread_to_offset(t); + + return mark_pthread_obj_initialized(bit); +} + +int pthread_equal(pthread_t pt1, pthread_t pt2) +{ + return (pt1 == pt2); +} + +pid_t getpid(void) +{ + /* + * To maintain compatibility with some other POSIX operating systems, + * a PID of zero is used to indicate that the process exists in another namespace. + * PID zero is also used by the scheduler in some cases. + * PID one is usually reserved for the init process. + * Also note, that negative PIDs may be used by kill() + * to send signals to process groups in some implementations. + * + * At the moment, getpid just returns an arbitrary number >= 2 + */ + + return 42; +} + +static inline void __z_pthread_cleanup_init(struct __pthread_cleanup *c, void (*routine)(void *arg), + void *arg) +{ + *c = (struct __pthread_cleanup){ + .routine = routine, + .arg = arg, + .node = {0}, + }; +} + +void __z_pthread_cleanup_push(void *cleanup[3], void (*routine)(void *arg), void *arg) +{ + struct posix_thread *t = NULL; + struct __pthread_cleanup *const c = (struct __pthread_cleanup *)cleanup; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + BUILD_ASSERT(3 * sizeof(void *) == sizeof(*c)); + __ASSERT_NO_MSG(t != NULL); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(routine != NULL); + __z_pthread_cleanup_init(c, routine, arg); + sys_slist_prepend(&t->cleanup_list, &c->node); + } +} + +void __z_pthread_cleanup_pop(int execute) +{ + sys_snode_t *node; + struct __pthread_cleanup *c = NULL; + struct posix_thread *t = NULL; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + __ASSERT_NO_MSG(t != NULL); + node = sys_slist_get(&t->cleanup_list); + __ASSERT_NO_MSG(node != NULL); + c = CONTAINER_OF(node, struct __pthread_cleanup, node); + __ASSERT_NO_MSG(c != NULL); + __ASSERT_NO_MSG(c->routine != NULL); + } + if (execute) { + c->routine(c->arg); + } +} + +static bool is_posix_policy_prio_valid(int priority, int policy) +{ + if (priority >= sched_get_priority_min(policy) && + priority <= sched_get_priority_max(policy)) { + return true; + } + + LOG_ERR("Invalid priority %d and / or policy %d", priority, policy); + + return false; +} + +/* Non-static so that they can be tested in ztest */ +int zephyr_to_posix_priority(int z_prio, int *policy) +{ + int priority; + + if (z_prio < 0) { + __ASSERT_NO_MSG(-z_prio <= CONFIG_NUM_COOP_PRIORITIES); + } else { + __ASSERT_NO_MSG(z_prio < CONFIG_NUM_PREEMPT_PRIORITIES); + } + + *policy = (z_prio < 0) ? SCHED_FIFO : SCHED_RR; + priority = ZEPHYR_TO_POSIX_PRIORITY(z_prio); + __ASSERT_NO_MSG(is_posix_policy_prio_valid(priority, *policy)); + + return priority; +} + +/* Non-static so that they can be tested in ztest */ +int posix_to_zephyr_priority(int priority, int policy) +{ + __ASSERT_NO_MSG(is_posix_policy_prio_valid(priority, policy)); + + return POSIX_TO_ZEPHYR_PRIORITY(priority, policy); +} + +static bool __attr_is_runnable(const struct posix_thread_attr *attr) +{ + size_t stacksize; + + if (attr == NULL || attr->stack == NULL) { + LOG_DBG("attr %p is not initialized", attr); + return false; + } + + stacksize = __get_attr_stacksize(attr); + if (stacksize < PTHREAD_STACK_MIN) { + LOG_DBG("attr %p has stacksize %zu is smaller than PTHREAD_STACK_MIN (%zu)", attr, + stacksize, (size_t)PTHREAD_STACK_MIN); + return false; + } + + /* require a valid scheduler policy */ + if (!valid_posix_policy(attr->schedpolicy)) { + LOG_ERR("Invalid scheduler policy %d", attr->schedpolicy); + return false; + } + + return true; +} + +static bool __attr_is_initialized(const struct posix_thread_attr *attr) +{ + if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { + return __attr_is_runnable(attr); + } + + if (attr == NULL || !attr->initialized) { + LOG_DBG("attr %p is not initialized", attr); + return false; + } + + return true; +} + +/** + * @brief Set scheduling parameter attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *schedparam) +{ + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || schedparam == NULL || + !is_posix_policy_prio_valid(schedparam->sched_priority, attr->schedpolicy)) { + LOG_ERR("Invalid pthread_attr_t or sched_param"); + return EINVAL; + } + + attr->priority = schedparam->sched_priority; + return 0; +} + +/** + * @brief Set stack attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize) +{ + int ret; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (stackaddr == NULL) { + LOG_ERR("NULL stack address"); + return EACCES; + } + + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { + LOG_ERR("Invalid stacksize %zu", stacksize); + return EINVAL; + } + + if (attr->stack != NULL) { + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, + __get_attr_stacksize(attr), attr->stack); + } + } + + attr->stack = stackaddr; + __set_attr_stacksize(attr, stacksize); + + LOG_DBG("Assigned thread stack %zu@%p to attr %p", __get_attr_stacksize(attr), attr->stack, + _attr); + + return 0; +} + +static void posix_thread_recycle_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + posix_thread_recycle(); +} +static K_WORK_DELAYABLE_DEFINE(posix_thread_recycle_work, posix_thread_recycle_work_handler); + +static void posix_thread_finalize(struct posix_thread *t, void *retval) +{ + sys_snode_t *node_l; + k_spinlock_key_t key; + pthread_key_obj *key_obj; + pthread_thread_data *thread_spec_data; + + SYS_SLIST_FOR_EACH_NODE(&t->key_list, node_l) { + thread_spec_data = (pthread_thread_data *)node_l; + if (thread_spec_data != NULL) { + key_obj = thread_spec_data->key; + if (key_obj->destructor != NULL) { + (key_obj->destructor)(thread_spec_data->spec_data); + } + } + } + + /* move thread from run_q to done_q */ + key = k_spin_lock(&pthread_pool_lock); + sys_dlist_remove(&t->q_node); + posix_thread_q_set(t, POSIX_THREAD_DONE_Q); + t->retval = retval; + k_spin_unlock(&pthread_pool_lock, key); + + /* trigger recycle work */ + (void)k_work_schedule(&posix_thread_recycle_work, K_MSEC(CONFIG_PTHREAD_RECYCLER_DELAY_MS)); + + /* abort the underlying k_thread */ + k_thread_abort(&t->thread); +} + +FUNC_NORETURN +static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) +{ + int err; + int barrier; + void *(*fun_ptr)(void *arg) = arg2; + struct posix_thread *t = CONTAINER_OF(k_current_get(), struct posix_thread, thread); + + if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + /* cross the barrier so that pthread_create() can continue */ + barrier = POINTER_TO_UINT(arg3); + err = pthread_barrier_wait(&barrier); + __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); + } + + posix_thread_finalize(t, fun_ptr(arg1)); + + CODE_UNREACHABLE; +} + +static void posix_thread_recycle(void) +{ + k_spinlock_key_t key; + struct posix_thread *t; + struct posix_thread *safe_t; + sys_dlist_t recyclables = SYS_DLIST_STATIC_INIT(&recyclables); + + key = k_spin_lock(&pthread_pool_lock); + SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&posix_thread_q[POSIX_THREAD_DONE_Q], t, safe_t, q_node) { + if (t->attr.detachstate == PTHREAD_CREATE_JOINABLE) { + /* thread has not been joined yet */ + continue; + } + + sys_dlist_remove(&t->q_node); + sys_dlist_append(&recyclables, &t->q_node); + } + k_spin_unlock(&pthread_pool_lock, key); + + if (sys_dlist_is_empty(&recyclables)) { + return; + } + + LOG_DBG("Recycling %zu threads", sys_dlist_len(&recyclables)); + + SYS_DLIST_FOR_EACH_CONTAINER(&recyclables, t, q_node) { + if (t->attr.caller_destroys) { + t->attr = (struct posix_thread_attr){0}; + } else { + (void)pthread_attr_destroy((pthread_attr_t *)&t->attr); + } + } + + key = k_spin_lock(&pthread_pool_lock); + while (!sys_dlist_is_empty(&recyclables)) { + t = CONTAINER_OF(sys_dlist_get(&recyclables), struct posix_thread, q_node); + posix_thread_q_set(t, POSIX_THREAD_READY_Q); + } + k_spin_unlock(&pthread_pool_lock, key); +} + +/** + * @brief Create a new thread. + * + * Pthread attribute should not be NULL. API will return Error on NULL + * attribute value. + * + * See IEEE 1003.1 + */ +int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadroutine)(void *), + void *arg) +{ + int err; + pthread_barrier_t barrier; + struct posix_thread *t = NULL; + + if (!(_attr == NULL || __attr_is_runnable((struct posix_thread_attr *)_attr))) { + return EINVAL; + } + + /* reclaim resources greedily */ + posix_thread_recycle(); + + K_SPINLOCK(&pthread_pool_lock) { + if (!sys_dlist_is_empty(&posix_thread_q[POSIX_THREAD_READY_Q])) { + t = CONTAINER_OF(sys_dlist_get(&posix_thread_q[POSIX_THREAD_READY_Q]), + struct posix_thread, q_node); + + /* initialize thread state */ + posix_thread_q_set(t, POSIX_THREAD_RUN_Q); + sys_slist_init(&t->key_list); + sys_slist_init(&t->cleanup_list); + } + } + + if (t != NULL && IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + err = pthread_barrier_init(&barrier, NULL, 2); + if (err != 0) { + /* cannot allocate barrier. move thread back to ready_q */ + K_SPINLOCK(&pthread_pool_lock) { + sys_dlist_remove(&t->q_node); + posix_thread_q_set(t, POSIX_THREAD_READY_Q); + } + t = NULL; + } + } + + if (t == NULL) { + /* no threads are ready */ + LOG_ERR("No threads are ready"); + return EAGAIN; + } + + if (_attr == NULL) { + err = pthread_attr_init((pthread_attr_t *)&t->attr); + if (err == 0 && !__attr_is_runnable(&t->attr)) { + (void)pthread_attr_destroy((pthread_attr_t *)&t->attr); + err = EINVAL; + } + if (err != 0) { + /* cannot allocate pthread attributes (e.g. stack) */ + K_SPINLOCK(&pthread_pool_lock) { + sys_dlist_remove(&t->q_node); + posix_thread_q_set(t, POSIX_THREAD_READY_Q); + } + return err; + } + /* caller not responsible for destroying attr */ + t->attr.caller_destroys = false; + } else { + /* copy user-provided attr into thread, caller must destroy attr at a later time */ + t->attr = *(struct posix_thread_attr *)_attr; + } + + /* spawn the thread */ + k_thread_create( + &t->thread, t->attr.stack, __get_attr_stacksize(&t->attr) + t->attr.guardsize, + zephyr_thread_wrapper, (void *)arg, threadroutine, + IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) : NULL, + posix_to_zephyr_priority(t->attr.priority, t->attr.schedpolicy), 0, K_NO_WAIT); + + if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { + /* wait for the spawned thread to cross our barrier */ + err = pthread_barrier_wait(&barrier); + __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); + err = pthread_barrier_destroy(&barrier); + __ASSERT_NO_MSG(err == 0); + } + + /* finally provide the initialized thread to the caller */ + *th = mark_pthread_obj_initialized(posix_thread_to_offset(t)); + + LOG_DBG("Created pthread %p", &t->thread); + + return 0; +} + +int pthread_getconcurrency(void) +{ + int ret = 0; + + K_SPINLOCK(&pthread_pool_lock) { + ret = pthread_concurrency; + } + + return ret; +} + +int pthread_setconcurrency(int new_level) +{ + if (new_level < 0) { + return EINVAL; + } + + if (new_level > CONFIG_MP_MAX_NUM_CPUS) { + return EAGAIN; + } + + K_SPINLOCK(&pthread_pool_lock) { + pthread_concurrency = new_level; + } + + return 0; +} + +/** + * @brief Set cancelability State. + * + * See IEEE 1003.1 + */ +int pthread_setcancelstate(int state, int *oldstate) +{ + int ret = 0; + struct posix_thread *t; + bool cancel_pending = false; + bool cancel_type = PTHREAD_CANCEL_ENABLE; + + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) { + LOG_ERR("Invalid pthread state %d", state); + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } + + if (oldstate != NULL) { + *oldstate = t->attr.cancelstate; + } + + t->attr.cancelstate = state; + cancel_pending = t->attr.cancelpending; + cancel_type = t->attr.canceltype; + } + + if (state == PTHREAD_CANCEL_ENABLE && cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS && + cancel_pending) { + posix_thread_finalize(t, PTHREAD_CANCELED); + } + + return 0; +} + +/** + * @brief Set cancelability Type. + * + * See IEEE 1003.1 + */ +int pthread_setcanceltype(int type, int *oldtype) +{ + int ret = 0; + struct posix_thread *t; + + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) { + LOG_ERR("Invalid pthread cancel type %d", type); + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = EINVAL; + K_SPINLOCK_BREAK; + } + + if (oldtype != NULL) { + *oldtype = t->attr.canceltype; + } + t->attr.canceltype = type; + } + + return ret; +} + +/** + * @brief Create a cancellation point in the calling thread. + * + * See IEEE 1003.1 + */ +void pthread_testcancel(void) +{ + struct posix_thread *t; + bool cancel_pended = false; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + K_SPINLOCK_BREAK; + } + if (t->attr.cancelstate != PTHREAD_CANCEL_ENABLE) { + K_SPINLOCK_BREAK; + } + if (t->attr.cancelpending) { + cancel_pended = true; + t->attr.cancelstate = PTHREAD_CANCEL_DISABLE; + } + } + + if (cancel_pended) { + posix_thread_finalize(t, PTHREAD_CANCELED); + } +} + +/** + * @brief Cancel execution of a thread. + * + * See IEEE 1003.1 + */ +int pthread_cancel(pthread_t pthread) +{ + int ret = 0; + bool cancel_state = PTHREAD_CANCEL_ENABLE; + bool cancel_type = PTHREAD_CANCEL_DEFERRED; + struct posix_thread *t = NULL; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (!__attr_is_initialized(&t->attr)) { + /* thread has already terminated */ + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + t->attr.cancelpending = true; + cancel_state = t->attr.cancelstate; + cancel_type = t->attr.canceltype; + } + + if (ret == 0 && cancel_state == PTHREAD_CANCEL_ENABLE && + cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS) { + posix_thread_finalize(t, PTHREAD_CANCELED); + } + + return ret; +} + +/** + * @brief Set thread scheduling policy and parameters. + * + * See IEEE 1003.1 + */ +int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) +{ + int ret = 0; + int new_prio = K_LOWEST_APPLICATION_THREAD_PRIO; + struct posix_thread *t = NULL; + + if (param == NULL || !valid_posix_policy(policy) || + !is_posix_policy_prio_valid(param->sched_priority, policy)) { + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + new_prio = posix_to_zephyr_priority(param->sched_priority, policy); + } + + if (ret == 0) { + k_thread_priority_set(&t->thread, new_prio); + } + + return ret; +} + +/** + * @brief Initialise threads attribute object + * + * See IEEE 1003.1 + */ +int pthread_attr_init(pthread_attr_t *_attr) +{ + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; + + if (attr == NULL) { + LOG_ERR("Invalid attr pointer"); + return ENOMEM; + } + + BUILD_ASSERT(DYNAMIC_STACK_SIZE <= PTHREAD_STACK_MAX); + + *attr = (struct posix_thread_attr){0}; + attr->guardsize = CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_DEFAULT; + + if (DYNAMIC_STACK_SIZE > 0) { + attr->stack = k_thread_stack_alloc(DYNAMIC_STACK_SIZE + attr->guardsize, + k_is_user_context() ? K_USER : 0); + if (attr->stack == NULL) { + LOG_DBG("Did not auto-allocate thread stack"); + } else { + __set_attr_stacksize(attr, DYNAMIC_STACK_SIZE); + __ASSERT_NO_MSG(__attr_is_initialized(attr)); + LOG_DBG("Allocated thread stack %zu@%p", __get_attr_stacksize(attr), + attr->stack); + } + } + + /* caller responsible for destroying attr */ + attr->initialized = true; + + LOG_DBG("Initialized attr %p", _attr); + + return 0; +} + +/** + * @brief Get thread scheduling policy and parameters + * + * See IEEE 1003.1 + */ +int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) +{ + int ret = 0; + struct posix_thread *t; + + if (policy == NULL || param == NULL) { + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (!__attr_is_initialized(&t->attr)) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + param->sched_priority = + zephyr_to_posix_priority(k_thread_priority_get(&t->thread), policy); + } + + return ret; +} + +/** + * @brief Dynamic package initialization + * + * See IEEE 1003.1 + */ +int pthread_once(pthread_once_t *once, void (*init_func)(void)) +{ + __unused int ret; + bool run_init_func = false; + struct pthread_once *const _once = (struct pthread_once *)once; + + if (init_func == NULL) { + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + if (!_once->flag) { + run_init_func = true; + _once->flag = true; + } + } + + if (run_init_func) { + init_func(); + } + + return 0; +} + +/** + * @brief Terminate calling thread. + * + * See IEEE 1003.1 + */ +FUNC_NORETURN +void pthread_exit(void *retval) +{ + struct posix_thread *self = NULL; + + K_SPINLOCK(&pthread_pool_lock) { + self = to_posix_thread(pthread_self()); + if (self == NULL) { + K_SPINLOCK_BREAK; + } + + /* Mark a thread as cancellable before exiting */ + self->attr.cancelstate = PTHREAD_CANCEL_ENABLE; + } + + if (self == NULL) { + /* not a valid posix_thread */ + LOG_DBG("Aborting non-pthread %p", k_current_get()); + k_thread_abort(k_current_get()); + + CODE_UNREACHABLE; + } + + posix_thread_finalize(self, retval); + CODE_UNREACHABLE; +} + +/** + * @brief Wait for a thread termination. + * + * See IEEE 1003.1 + */ +int pthread_join(pthread_t pthread, void **status) +{ + int ret = 0; + struct posix_thread *t = NULL; + + if (pthread == pthread_self()) { + LOG_ERR("Pthread attempted to join itself (%x)", pthread); + return EDEADLK; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + LOG_DBG("Pthread %p joining..", &t->thread); + + if (t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { + /* undefined behaviour */ + ret = EINVAL; + K_SPINLOCK_BREAK; + } + + if (posix_thread_q_get(t) == POSIX_THREAD_READY_Q) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + /* + * thread is joinable and is in run_q or done_q. + * let's ensure that the thread cannot be joined again after this point. + */ + t->attr.detachstate = PTHREAD_CREATE_DETACHED; + } + + switch (ret) { + case ESRCH: + LOG_ERR("Pthread %p has already been joined", &t->thread); + return ret; + case EINVAL: + LOG_ERR("Pthread %p is not a joinable", &t->thread); + return ret; + case 0: + break; + } + + ret = k_thread_join(&t->thread, K_FOREVER); + /* other possibilities? */ + __ASSERT_NO_MSG(ret == 0); + + LOG_DBG("Joined pthread %p", &t->thread); + + if (status != NULL) { + LOG_DBG("Writing status to %p", status); + *status = t->retval; + } + + posix_thread_recycle(); + + return 0; +} + +/** + * @brief Detach a thread. + * + * See IEEE 1003.1 + */ +int pthread_detach(pthread_t pthread) +{ + int ret = 0; + struct posix_thread *t; + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (posix_thread_q_get(t) == POSIX_THREAD_READY_Q || + t->attr.detachstate != PTHREAD_CREATE_JOINABLE) { + LOG_ERR("Pthread %p cannot be detached", &t->thread); + ret = EINVAL; + K_SPINLOCK_BREAK; + } + + t->attr.detachstate = PTHREAD_CREATE_DETACHED; + } + + if (ret == 0) { + LOG_DBG("Pthread %p detached", &t->thread); + } + + return ret; +} + +/** + * @brief Get detach state attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) +{ + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || (detachstate == NULL)) { + return EINVAL; + } + + *detachstate = attr->detachstate; + return 0; +} + +/** + * @brief Set detach state attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) +{ + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || ((detachstate != PTHREAD_CREATE_DETACHED) && + (detachstate != PTHREAD_CREATE_JOINABLE))) { + return EINVAL; + } + + attr->detachstate = detachstate; + return 0; +} + +/** + * @brief Get scheduling policy attribute in Thread attributes. + * + * See IEEE 1003.1 + */ +int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) +{ + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || (policy == NULL)) { + return EINVAL; + } + + *policy = attr->schedpolicy; + return 0; +} + +/** + * @brief Set scheduling policy attribute in Thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) +{ + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || !valid_posix_policy(policy)) { + return EINVAL; + } + + attr->schedpolicy = policy; + return 0; +} + +/** + * @brief Get stack size attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) +{ + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || (stacksize == NULL)) { + return EINVAL; + } + + *stacksize = __get_attr_stacksize(attr); + return 0; +} + +/** + * @brief Set stack size attribute in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) +{ + int ret; + void *new_stack; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || stacksize == 0 || stacksize < PTHREAD_STACK_MIN || + stacksize > PTHREAD_STACK_MAX) { + return EINVAL; + } + + if (__get_attr_stacksize(attr) == stacksize) { + return 0; + } + + new_stack = + k_thread_stack_alloc(stacksize + attr->guardsize, k_is_user_context() ? K_USER : 0); + if (new_stack == NULL) { + if (stacksize < __get_attr_stacksize(attr)) { + __set_attr_stacksize(attr, stacksize); + return 0; + } + + LOG_DBG("k_thread_stack_alloc(%zu) failed", + __get_attr_stacksize(attr) + attr->guardsize); + return ENOMEM; + } + LOG_DBG("Allocated thread stack %zu@%p", stacksize + attr->guardsize, attr->stack); + + if (attr->stack != NULL) { + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, + __get_attr_stacksize(attr), attr->stack); + } + } + + __set_attr_stacksize(attr, stacksize); + attr->stack = new_stack; + + return 0; +} + +/** + * @brief Get stack attributes in thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t *stacksize) +{ + const struct posix_thread_attr *attr = (const struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || (stackaddr == NULL) || (stacksize == NULL)) { + return EINVAL; + } + + *stackaddr = attr->stack; + *stacksize = __get_attr_stacksize(attr); + return 0; +} + +int pthread_attr_getguardsize(const pthread_attr_t *ZRESTRICT _attr, size_t *ZRESTRICT guardsize) +{ + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || guardsize == NULL) { + return EINVAL; + } + + *guardsize = attr->guardsize; + + return 0; +} + +int pthread_attr_setguardsize(pthread_attr_t *_attr, size_t guardsize) +{ + struct posix_thread_attr *const attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || guardsize > PTHREAD_GUARD_MAX) { + return EINVAL; + } + + attr->guardsize = guardsize; + + return 0; +} + +/** + * @brief Get thread attributes object scheduling parameters. + * + * See IEEE 1003.1 + */ +int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *schedparam) +{ + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr) || (schedparam == NULL)) { + return EINVAL; + } + + schedparam->sched_priority = attr->priority; + return 0; +} + +/** + * @brief Destroy thread attributes object. + * + * See IEEE 1003.1 + */ +int pthread_attr_destroy(pthread_attr_t *_attr) +{ + int ret; + struct posix_thread_attr *attr = (struct posix_thread_attr *)_attr; + + if (!__attr_is_initialized(attr)) { + return EINVAL; + } + + ret = k_thread_stack_free(attr->stack); + if (ret == 0) { + LOG_DBG("Freed attr %p thread stack %zu@%p", _attr, __get_attr_stacksize(attr), + attr->stack); + } + + *attr = (struct posix_thread_attr){0}; + LOG_DBG("Destroyed attr %p", _attr); + + return 0; +} + +int pthread_setname_np(pthread_t thread, const char *name) +{ +#ifdef CONFIG_THREAD_NAME + k_tid_t kthread; + + thread = get_posix_thread_idx(thread); + if (thread >= CONFIG_MAX_PTHREAD_COUNT) { + return ESRCH; + } + + kthread = &posix_thread_pool[thread].thread; + + if (name == NULL) { + return EINVAL; + } + + return k_thread_name_set(kthread, name); +#else + ARG_UNUSED(thread); + ARG_UNUSED(name); + return 0; +#endif +} + +int pthread_getname_np(pthread_t thread, char *name, size_t len) +{ +#ifdef CONFIG_THREAD_NAME + k_tid_t kthread; + + thread = get_posix_thread_idx(thread); + if (thread >= CONFIG_MAX_PTHREAD_COUNT) { + return ESRCH; + } + + if (name == NULL) { + return EINVAL; + } + + memset(name, '\0', len); + kthread = &posix_thread_pool[thread].thread; + return k_thread_name_copy(kthread, name, len - 1); +#else + ARG_UNUSED(thread); + ARG_UNUSED(name); + ARG_UNUSED(len); + return 0; +#endif +} + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + ARG_UNUSED(prepare); + ARG_UNUSED(parent); + ARG_UNUSED(child); + + return ENOSYS; +} + +/* this should probably go into signal.c but we need access to the lock */ +int pthread_sigmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset) +{ + int ret = 0; + struct posix_thread *t; + + if (!(how == SIG_BLOCK || how == SIG_SETMASK || how == SIG_UNBLOCK)) { + return EINVAL; + } + + K_SPINLOCK(&pthread_pool_lock) { + t = to_posix_thread(pthread_self()); + if (t == NULL) { + ret = ESRCH; + K_SPINLOCK_BREAK; + } + + if (oset != NULL) { + *oset = t->sigset; + } + + if (set == NULL) { + K_SPINLOCK_BREAK; + } + + switch (how) { + case SIG_BLOCK: + for (size_t i = 0; i < ARRAY_SIZE(set->sig); ++i) { + t->sigset.sig[i] |= set->sig[i]; + } + break; + case SIG_SETMASK: + t->sigset = *set; + break; + case SIG_UNBLOCK: + for (size_t i = 0; i < ARRAY_SIZE(set->sig); ++i) { + t->sigset.sig[i] &= ~set->sig[i]; + } + break; + } + } + + return ret; +} + +static int posix_thread_pool_init(void) +{ + size_t i; + + for (i = 0; i < CONFIG_MAX_PTHREAD_COUNT; ++i) { + posix_thread_q_set(&posix_thread_pool[i], POSIX_THREAD_READY_Q); + } + + return 0; +} +SYS_INIT(posix_thread_pool_init, PRE_KERNEL_1, 0); diff --git a/lib/posix/pthread_sched.h b/lib/posix/options/pthread_sched.h similarity index 100% rename from lib/posix/pthread_sched.h rename to lib/posix/options/pthread_sched.h diff --git a/lib/posix/options/rwlock.c b/lib/posix/options/rwlock.c new file mode 100644 index 00000000000..a380b5d5693 --- /dev/null +++ b/lib/posix/options/rwlock.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_internal.h" + +#include +#include +#include +#include +#include + +#define CONCURRENT_READER_LIMIT (CONFIG_MAX_PTHREAD_COUNT + 1) + +struct posix_rwlock { + struct k_sem rd_sem; + struct k_sem wr_sem; + struct k_sem reader_active; /* blocks WR till reader has acquired lock */ + k_tid_t wr_owner; +}; + +int64_t timespec_to_timeoutms(const struct timespec *abstime); +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); + +LOG_MODULE_REGISTER(pthread_rwlock, CONFIG_PTHREAD_RWLOCK_LOG_LEVEL); + +static struct k_spinlock posix_rwlock_spinlock; + +static struct posix_rwlock posix_rwlock_pool[CONFIG_MAX_PTHREAD_RWLOCK_COUNT]; +SYS_BITARRAY_DEFINE_STATIC(posix_rwlock_bitarray, CONFIG_MAX_PTHREAD_RWLOCK_COUNT); + +/* + * We reserve the MSB to mark a pthread_rwlock_t as initialized (from the + * perspective of the application). With a linear space, this means that + * the theoretical pthread_rwlock_t range is [0,2147483647]. + */ +BUILD_ASSERT(CONFIG_MAX_PTHREAD_RWLOCK_COUNT < PTHREAD_OBJ_MASK_INIT, + "CONFIG_MAX_PTHREAD_RWLOCK_COUNT is too high"); + +static inline size_t posix_rwlock_to_offset(struct posix_rwlock *rwl) +{ + return rwl - posix_rwlock_pool; +} + +static inline size_t to_posix_rwlock_idx(pthread_rwlock_t rwlock) +{ + return mark_pthread_obj_uninitialized(rwlock); +} + +static struct posix_rwlock *get_posix_rwlock(pthread_rwlock_t rwlock) +{ + int actually_initialized; + size_t bit = to_posix_rwlock_idx(rwlock); + + /* if the provided rwlock does not claim to be initialized, its invalid */ + if (!is_pthread_obj_initialized(rwlock)) { + LOG_ERR("RWlock is uninitialized (%x)", rwlock); + return NULL; + } + + /* Mask off the MSB to get the actual bit index */ + if (sys_bitarray_test_bit(&posix_rwlock_bitarray, bit, &actually_initialized) < 0) { + LOG_ERR("RWlock is invalid (%x)", rwlock); + return NULL; + } + + if (actually_initialized == 0) { + /* The rwlock claims to be initialized but is actually not */ + LOG_ERR("RWlock claims to be initialized (%x)", rwlock); + return NULL; + } + + return &posix_rwlock_pool[bit]; +} + +struct posix_rwlock *to_posix_rwlock(pthread_rwlock_t *rwlock) +{ + size_t bit; + struct posix_rwlock *rwl; + + if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) { + return get_posix_rwlock(*rwlock); + } + + /* Try and automatically associate a posix_rwlock */ + if (sys_bitarray_alloc(&posix_rwlock_bitarray, 1, &bit) < 0) { + LOG_ERR("Unable to allocate pthread_rwlock_t"); + return NULL; + } + + /* Record the associated posix_rwlock in rwl and mark as initialized */ + *rwlock = mark_pthread_obj_initialized(bit); + + /* Initialize the posix_rwlock */ + rwl = &posix_rwlock_pool[bit]; + + return rwl; +} + +/** + * @brief Initialize read-write lock object. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_init(pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + struct posix_rwlock *rwl; + + ARG_UNUSED(attr); + *rwlock = PTHREAD_RWLOCK_INITIALIZER; + + rwl = to_posix_rwlock(rwlock); + if (rwl == NULL) { + return ENOMEM; + } + + k_sem_init(&rwl->rd_sem, CONCURRENT_READER_LIMIT, CONCURRENT_READER_LIMIT); + k_sem_init(&rwl->wr_sem, 1, 1); + k_sem_init(&rwl->reader_active, 1, 1); + rwl->wr_owner = NULL; + + LOG_DBG("Initialized rwlock %p", rwl); + + return 0; +} + +/** + * @brief Destroy read-write lock object. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) +{ + int ret = 0; + int err; + size_t bit; + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + K_SPINLOCK(&posix_rwlock_spinlock) { + if (rwl->wr_owner != NULL) { + ret = EBUSY; + K_SPINLOCK_BREAK; + } + + bit = posix_rwlock_to_offset(rwl); + err = sys_bitarray_free(&posix_rwlock_bitarray, 1, bit); + __ASSERT_NO_MSG(err == 0); + } + + return ret; +} + +/** + * @brief Lock a read-write lock object for reading. + * + * API behaviour is unpredictable if number of concurrent reader + * lock held is greater than CONCURRENT_READER_LIMIT. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + return read_lock_acquire(rwl, SYS_FOREVER_MS); +} + +/** + * @brief Lock a read-write lock object for reading within specific time. + * + * API behaviour is unpredictable if number of concurrent reader + * lock held is greater than CONCURRENT_READER_LIMIT. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int32_t timeout; + uint32_t ret = 0U; + struct posix_rwlock *rwl; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { + return EINVAL; + } + + timeout = (int32_t) timespec_to_timeoutms(abstime); + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (read_lock_acquire(rwl, timeout) != 0U) { + ret = ETIMEDOUT; + } + + return ret; +} + +/** + * @brief Lock a read-write lock object for reading immediately. + * + * API behaviour is unpredictable if number of concurrent reader + * lock held is greater than CONCURRENT_READER_LIMIT. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + return read_lock_acquire(rwl, 0); +} + +/** + * @brief Lock a read-write lock object for writing. + * + * Write lock does not have priority over reader lock, + * threads get lock based on priority. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + return write_lock_acquire(rwl, SYS_FOREVER_MS); +} + +/** + * @brief Lock a read-write lock object for writing within specific time. + * + * Write lock does not have priority over reader lock, + * threads get lock based on priority. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int32_t timeout; + uint32_t ret = 0U; + struct posix_rwlock *rwl; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { + return EINVAL; + } + + timeout = (int32_t) timespec_to_timeoutms(abstime); + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (write_lock_acquire(rwl, timeout) != 0U) { + ret = ETIMEDOUT; + } + + return ret; +} + +/** + * @brief Lock a read-write lock object for writing immediately. + * + * Write lock does not have priority over reader lock, + * threads get lock based on priority. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + return write_lock_acquire(rwl, 0); +} + +/** + * + * @brief Unlock a read-write lock object. + * + * See IEEE 1003.1 + */ +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + struct posix_rwlock *rwl; + + rwl = get_posix_rwlock(*rwlock); + if (rwl == NULL) { + return EINVAL; + } + + if (k_current_get() == rwl->wr_owner) { + /* Write unlock */ + rwl->wr_owner = NULL; + k_sem_give(&rwl->reader_active); + k_sem_give(&rwl->wr_sem); + } else { + /* Read unlock */ + k_sem_give(&rwl->rd_sem); + + if (k_sem_count_get(&rwl->rd_sem) == CONCURRENT_READER_LIMIT) { + /* Last read lock, unlock writer */ + k_sem_give(&rwl->reader_active); + } + } + return 0; +} + +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) +{ + uint32_t ret = 0U; + + if (k_sem_take(&rwl->wr_sem, SYS_TIMEOUT_MS(timeout)) == 0) { + k_sem_take(&rwl->reader_active, K_NO_WAIT); + k_sem_take(&rwl->rd_sem, K_NO_WAIT); + k_sem_give(&rwl->wr_sem); + } else { + ret = EBUSY; + } + + return ret; +} + +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) +{ + uint32_t ret = 0U; + int64_t elapsed_time, st_time = k_uptime_get(); + k_timeout_t k_timeout; + + k_timeout = SYS_TIMEOUT_MS(timeout); + + /* waiting for release of write lock */ + if (k_sem_take(&rwl->wr_sem, k_timeout) == 0) { + /* update remaining timeout time for 2nd sem */ + if (timeout != SYS_FOREVER_MS) { + elapsed_time = k_uptime_get() - st_time; + timeout = timeout <= elapsed_time ? 0 : + timeout - elapsed_time; + } + + k_timeout = SYS_TIMEOUT_MS(timeout); + + /* waiting for reader to complete operation */ + if (k_sem_take(&rwl->reader_active, k_timeout) == 0) { + rwl->wr_owner = k_current_get(); + } else { + k_sem_give(&rwl->wr_sem); + ret = EBUSY; + } + + } else { + ret = EBUSY; + } + return ret; +} diff --git a/lib/posix/options/sched.c b/lib/posix/options/sched.c new file mode 100644 index 00000000000..be174d92cd6 --- /dev/null +++ b/lib/posix/options/sched.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018-2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "pthread_sched.h" + +#include +#include + +/** + * @brief Get minimum priority value for a given policy + * + * See IEEE 1003.1 + */ +int sched_get_priority_min(int policy) +{ + if (!valid_posix_policy(policy)) { + errno = EINVAL; + return -1; + } + + return 0; +} + +/** + * @brief Get maximum priority value for a given policy + * + * See IEEE 1003.1 + */ +int sched_get_priority_max(int policy) +{ + if (IS_ENABLED(CONFIG_COOP_ENABLED) && policy == SCHED_FIFO) { + return CONFIG_NUM_COOP_PRIORITIES - 1; + } else if (IS_ENABLED(CONFIG_PREEMPT_ENABLED) && + (policy == SCHED_RR || policy == SCHED_OTHER)) { + return CONFIG_NUM_PREEMPT_PRIORITIES - 1; + } + + errno = EINVAL; + return -1; +} + +/** + * @brief Get scheduling parameters + * + * See IEEE 1003.1 + */ +int sched_getparam(pid_t pid, struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} + +/** + * @brief Get scheduling policy + * + * See IEEE 1003.1 + */ +int sched_getscheduler(pid_t pid) +{ + ARG_UNUSED(pid); + + errno = ENOSYS; + + return -1; +} + +/** + * @brief Set scheduling parameters + * + * See IEEE 1003.1 + */ +int sched_setparam(pid_t pid, const struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} + +/** + * @brief Set scheduling policy + * + * See IEEE 1003.1 + */ +int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) +{ + ARG_UNUSED(pid); + ARG_UNUSED(policy); + ARG_UNUSED(param); + + errno = ENOSYS; + + return -1; +} + +int sched_rr_get_interval(pid_t pid, struct timespec *interval) +{ + ARG_UNUSED(pid); + ARG_UNUSED(interval); + + errno = ENOSYS; + + return -1; +} diff --git a/lib/posix/options/semaphore.c b/lib/posix/options/semaphore.c new file mode 100644 index 00000000000..07ec11add4e --- /dev/null +++ b/lib/posix/options/semaphore.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2023 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +struct nsem_obj { + sys_snode_t snode; + sem_t sem; + int ref_count; + char *name; +}; + +/* Initialize the list */ +static sys_slist_t nsem_list = SYS_SLIST_STATIC_INIT(&nsem_list); + +static K_MUTEX_DEFINE(nsem_mutex); + +static inline void nsem_list_lock(void) +{ + k_mutex_lock(&nsem_mutex, K_FOREVER); +} + +static inline void nsem_list_unlock(void) +{ + k_mutex_unlock(&nsem_mutex); +} + +static struct nsem_obj *nsem_find(const char *name) +{ + struct nsem_obj *nsem; + + SYS_SLIST_FOR_EACH_CONTAINER(&nsem_list, nsem, snode) { + if ((nsem->name != NULL) && (strcmp(nsem->name, name) == 0)) { + return nsem; + } + } + + return NULL; +} + +/* Clean up a named semaphore object completely (incl its `name` buffer) */ +static void nsem_cleanup(struct nsem_obj *nsem) +{ + if (nsem != NULL) { + if (nsem->name != NULL) { + k_free(nsem->name); + } + k_free(nsem); + } +} + +/* Remove a named semaphore if it isn't unsed */ +static void nsem_unref(struct nsem_obj *nsem) +{ + nsem->ref_count -= 1; + __ASSERT(nsem->ref_count >= 0, "ref_count may not be negative"); + + if (nsem->ref_count == 0) { + __ASSERT(nsem->name == NULL, "ref_count is 0 but sem is not unlinked"); + + sys_slist_find_and_remove(&nsem_list, (sys_snode_t *) nsem); + + /* Free nsem */ + nsem_cleanup(nsem); + } +} + +/** + * @brief Destroy semaphore. + * + * see IEEE 1003.1 + */ +int sem_destroy(sem_t *semaphore) +{ + if (semaphore == NULL) { + errno = EINVAL; + return -1; + } + + if (k_sem_count_get(semaphore)) { + errno = EBUSY; + return -1; + } + + k_sem_reset(semaphore); + return 0; +} + +/** + * @brief Get value of semaphore. + * + * See IEEE 1003.1 + */ +int sem_getvalue(sem_t *semaphore, int *value) +{ + if (semaphore == NULL) { + errno = EINVAL; + return -1; + } + + *value = (int) k_sem_count_get(semaphore); + + return 0; +} +/** + * @brief Initialize semaphore. + * + * See IEEE 1003.1 + */ +int sem_init(sem_t *semaphore, int pshared, unsigned int value) +{ + if (value > CONFIG_SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + + /* + * Zephyr has no concept of process, so only thread shared + * semaphore makes sense in here. + */ + __ASSERT(pshared == 0, "pshared should be 0"); + + k_sem_init(semaphore, value, CONFIG_SEM_VALUE_MAX); + + return 0; +} + +/** + * @brief Unlock a semaphore. + * + * See IEEE 1003.1 + */ +int sem_post(sem_t *semaphore) +{ + if (semaphore == NULL) { + errno = EINVAL; + return -1; + } + + k_sem_give(semaphore); + return 0; +} + +/** + * @brief Try time limited locking a semaphore. + * + * See IEEE 1003.1 + */ +int sem_timedwait(sem_t *semaphore, struct timespec *abstime) +{ + int32_t timeout; + struct timespec current; + int64_t current_ms, abstime_ms; + + __ASSERT(abstime, "abstime pointer NULL"); + + if ((abstime->tv_sec < 0) || (abstime->tv_nsec >= NSEC_PER_SEC)) { + errno = EINVAL; + return -1; + } + + if (clock_gettime(CLOCK_REALTIME, ¤t) < 0) { + return -1; + } + + abstime_ms = (int64_t)_ts_to_ms(abstime); + current_ms = (int64_t)_ts_to_ms(¤t); + + if (abstime_ms <= current_ms) { + timeout = 0; + } else { + timeout = (int32_t)(abstime_ms - current_ms); + } + + if (k_sem_take(semaphore, K_MSEC(timeout))) { + errno = ETIMEDOUT; + return -1; + } + + return 0; +} + +/** + * @brief Lock a semaphore if not taken. + * + * See IEEE 1003.1 + */ +int sem_trywait(sem_t *semaphore) +{ + if (k_sem_take(semaphore, K_NO_WAIT) == -EBUSY) { + errno = EAGAIN; + return -1; + } else { + return 0; + } +} + +/** + * @brief Lock a semaphore. + * + * See IEEE 1003.1 + */ +int sem_wait(sem_t *semaphore) +{ + /* With K_FOREVER, may return only success. */ + (void)k_sem_take(semaphore, K_FOREVER); + return 0; +} + +sem_t *sem_open(const char *name, int oflags, ...) +{ + va_list va; + mode_t mode; + unsigned int value; + struct nsem_obj *nsem = NULL; + size_t namelen; + + va_start(va, oflags); + BUILD_ASSERT(sizeof(mode_t) <= sizeof(int)); + mode = va_arg(va, int); + value = va_arg(va, unsigned int); + va_end(va); + + if (value > CONFIG_SEM_VALUE_MAX) { + errno = EINVAL; + return (sem_t *)SEM_FAILED; + } + + if (name == NULL) { + errno = EINVAL; + return (sem_t *)SEM_FAILED; + } + + namelen = strlen(name); + if ((namelen + 1) > CONFIG_SEM_NAMELEN_MAX) { + errno = ENAMETOOLONG; + return (sem_t *)SEM_FAILED; + } + + /* Lock before checking to make sure that the call is atomic */ + nsem_list_lock(); + + /* Check if the named semaphore exists */ + nsem = nsem_find(name); + + if (nsem != NULL) { /* Named semaphore exists */ + if (((oflags & O_CREAT) != 0) && ((oflags & O_EXCL) != 0)) { + errno = EEXIST; + goto error_unlock; + } + + __ASSERT_NO_MSG(nsem->ref_count != INT_MAX); + nsem->ref_count++; + goto unlock; + } + + /* Named sempahore doesn't exist, try to create new one */ + + if ((oflags & O_CREAT) == 0) { + errno = ENOENT; + goto error_unlock; + } + + nsem = k_calloc(1, sizeof(struct nsem_obj)); + if (nsem == NULL) { + errno = ENOSPC; + goto error_unlock; + } + + /* goto `cleanup_error_unlock` past this point to avoid memory leak */ + + nsem->name = k_calloc(namelen + 1, sizeof(uint8_t)); + if (nsem->name == NULL) { + errno = ENOSPC; + goto cleanup_error_unlock; + } + + strcpy(nsem->name, name); + + /* 1 for this open instance, +1 for the linked name */ + nsem->ref_count = 2; + + (void)k_sem_init(&nsem->sem, value, CONFIG_SEM_VALUE_MAX); + + sys_slist_append(&nsem_list, (sys_snode_t *)&(nsem->snode)); + + goto unlock; + +cleanup_error_unlock: + nsem_cleanup(nsem); + +error_unlock: + nsem = NULL; + +unlock: + nsem_list_unlock(); + return nsem == NULL ? SEM_FAILED : &nsem->sem; +} + +int sem_unlink(const char *name) +{ + int ret = 0; + struct nsem_obj *nsem; + + if (name == NULL) { + errno = EINVAL; + return -1; + } + + if ((strlen(name) + 1) > CONFIG_SEM_NAMELEN_MAX) { + errno = ENAMETOOLONG; + return -1; + } + + nsem_list_lock(); + + /* Check if queue already exists */ + nsem = nsem_find(name); + if (nsem == NULL) { + ret = -1; + errno = ENOENT; + goto unlock; + } + + k_free(nsem->name); + nsem->name = NULL; + nsem_unref(nsem); + +unlock: + nsem_list_unlock(); + return ret; +} + +int sem_close(sem_t *sem) +{ + struct nsem_obj *nsem = CONTAINER_OF(sem, struct nsem_obj, sem); + + if (sem == NULL) { + errno = EINVAL; + return -1; + } + + nsem_list_lock(); + nsem_unref(nsem); + nsem_list_unlock(); + return 0; +} + +#ifdef CONFIG_ZTEST +/* Used by ztest to get the ref count of a named semaphore */ +int nsem_get_ref_count(sem_t *sem) +{ + struct nsem_obj *nsem = CONTAINER_OF(sem, struct nsem_obj, sem); + int ref_count; + + __ASSERT_NO_MSG(sem != NULL); + __ASSERT_NO_MSG(nsem != NULL); + + nsem_list_lock(); + ref_count = nsem->ref_count; + nsem_list_unlock(); + + return ref_count; +} + +/* Used by ztest to get the length of the named semaphore */ +size_t nsem_get_list_len(void) +{ + size_t len; + + nsem_list_lock(); + len = sys_slist_len(&nsem_list); + nsem_list_unlock(); + + return len; +} +#endif diff --git a/lib/posix/signal.c b/lib/posix/options/signal.c similarity index 78% rename from lib/posix/signal.c rename to lib/posix/options/signal.c index d2153238ff8..f14ef7fe614 100644 --- a/lib/posix/signal.c +++ b/lib/posix/options/signal.c @@ -100,3 +100,21 @@ char *strsignal(int signum) return buf; } + +int sigprocmask(int how, const sigset_t *ZRESTRICT set, sigset_t *ZRESTRICT oset) +{ + if (!IS_ENABLED(CONFIG_MULTITHREADING)) { + return pthread_sigmask(how, set, oset); + } + + /* + * Until Zephyr supports processes and specifically querying the number of active threads in + * a process For more information, see + * https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html + */ + __ASSERT(false, "In multi-threaded environments, please use pthread_sigmask() instead of " + "%s()", __func__); + + errno = ENOSYS; + return -1; +} diff --git a/lib/posix/sleep.c b/lib/posix/options/sleep.c similarity index 100% rename from lib/posix/sleep.c rename to lib/posix/options/sleep.c diff --git a/lib/posix/spinlock.c b/lib/posix/options/spinlock.c similarity index 100% rename from lib/posix/spinlock.c rename to lib/posix/options/spinlock.c diff --git a/lib/posix/options/stropts.c b/lib/posix/options/stropts.c new file mode 100644 index 00000000000..54fca00cc9f --- /dev/null +++ b/lib/posix/options/stropts.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024 Abhinav Srivastava + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int putmsg(int fildes, const struct strbuf *ctlptr, const struct strbuf *dataptr, int flags) +{ + ARG_UNUSED(fildes); + ARG_UNUSED(ctlptr); + ARG_UNUSED(dataptr); + ARG_UNUSED(flags); + + errno = ENOSYS; + return -1; +} diff --git a/lib/posix/options/timer.c b/lib/posix/options/timer.c new file mode 100644 index 00000000000..7caecc180a1 --- /dev/null +++ b/lib/posix/options/timer.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2018 Intel Corporation + * Copyright (c) 2024, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include +#include +#include +#include + +#define ACTIVE 1 +#define NOT_ACTIVE 0 + +LOG_MODULE_REGISTER(posix_timer); + +static void zephyr_timer_wrapper(struct k_timer *ztimer); + +struct timer_obj { + struct k_timer ztimer; + struct sigevent evp; + struct k_sem sem_cond; + pthread_t thread; + struct timespec interval; /* Reload value */ + uint32_t reload; /* Reload value in ms */ + uint32_t status; +}; + +K_MEM_SLAB_DEFINE(posix_timer_slab, sizeof(struct timer_obj), + CONFIG_MAX_TIMER_COUNT, __alignof__(struct timer_obj)); + +static void zephyr_timer_wrapper(struct k_timer *ztimer) +{ + struct timer_obj *timer; + + timer = (struct timer_obj *)ztimer; + + if (timer->reload == 0U) { + timer->status = NOT_ACTIVE; + LOG_DBG("timer %p not active", timer); + return; + } + + if (timer->evp.sigev_notify == SIGEV_NONE) { + LOG_DBG("SIGEV_NONE"); + return; + } + + if (timer->evp.sigev_notify_function == NULL) { + LOG_DBG("NULL sigev_notify_function"); + return; + } + + LOG_DBG("calling sigev_notify_function %p", timer->evp.sigev_notify_function); + (timer->evp.sigev_notify_function)(timer->evp.sigev_value); +} + +static void *zephyr_thread_wrapper(void *arg) +{ + int ret; + struct timer_obj *timer = (struct timer_obj *)arg; + + ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + __ASSERT(ret == 0, "pthread_setcanceltype() failed: %d", ret); + + if (timer->evp.sigev_notify_attributes == NULL) { + ret = pthread_detach(pthread_self()); + __ASSERT(ret == 0, "pthread_detach() failed: %d", ret); + } + + while (1) { + if (timer->reload == 0U) { + timer->status = NOT_ACTIVE; + LOG_DBG("timer %p not active", timer); + } + + ret = k_sem_take(&timer->sem_cond, K_FOREVER); + __ASSERT(ret == 0, "k_sem_take() failed: %d", ret); + + if (timer->evp.sigev_notify_function == NULL) { + LOG_DBG("NULL sigev_notify_function"); + continue; + } + + LOG_DBG("calling sigev_notify_function %p", timer->evp.sigev_notify_function); + (timer->evp.sigev_notify_function)(timer->evp.sigev_value); + } + + return NULL; +} + +static void zephyr_timer_interrupt(struct k_timer *ztimer) +{ + struct timer_obj *timer; + + timer = (struct timer_obj *)ztimer; + k_sem_give(&timer->sem_cond); +} + +/** + * @brief Create a per-process timer. + * + * This API does not accept SIGEV_THREAD as valid signal event notification + * type. + * + * See IEEE 1003.1 + */ +int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) +{ + int ret = 0; + int detachstate; + struct timer_obj *timer; + const k_timeout_t alloc_timeout = K_MSEC(CONFIG_TIMER_CREATE_WAIT); + + if (evp == NULL || timerid == NULL) { + errno = EINVAL; + return -1; + } + + if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, alloc_timeout) != 0) { + LOG_DBG("k_mem_slab_alloc() failed: %d", ret); + errno = ENOMEM; + return -1; + } + + *timer = (struct timer_obj){0}; + timer->evp = *evp; + evp = &timer->evp; + + switch (evp->sigev_notify) { + case SIGEV_NONE: + k_timer_init(&timer->ztimer, NULL, NULL); + break; + case SIGEV_SIGNAL: + k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL); + break; + case SIGEV_THREAD: + if (evp->sigev_notify_attributes != NULL) { + ret = pthread_attr_getdetachstate(evp->sigev_notify_attributes, + &detachstate); + if (ret != 0) { + LOG_DBG("pthread_attr_getdetachstate() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; + } + + if (detachstate != PTHREAD_CREATE_DETACHED) { + ret = pthread_attr_setdetachstate(evp->sigev_notify_attributes, + PTHREAD_CREATE_DETACHED); + if (ret != 0) { + LOG_DBG("pthread_attr_setdetachstate() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; + } + } + } + + ret = k_sem_init(&timer->sem_cond, 0, 1); + if (ret != 0) { + LOG_DBG("k_sem_init() failed: %d", ret); + errno = -ret; + ret = -1; + goto free_timer; + } + + ret = pthread_create(&timer->thread, evp->sigev_notify_attributes, + zephyr_thread_wrapper, timer); + if (ret != 0) { + LOG_DBG("pthread_create() failed: %d", ret); + errno = ret; + ret = -1; + goto free_timer; + } + + k_timer_init(&timer->ztimer, zephyr_timer_interrupt, NULL); + break; + default: + ret = -1; + errno = EINVAL; + goto free_timer; + } + + *timerid = (timer_t)timer; + goto out; + +free_timer: + k_mem_slab_free(&posix_timer_slab, (void *)&timer); + +out: + return ret; +} + +/** + * @brief Get amount of time left for expiration on a per-process timer. + * + * See IEEE 1003.1 + */ +int timer_gettime(timer_t timerid, struct itimerspec *its) +{ + struct timer_obj *timer = (struct timer_obj *)timerid; + int32_t remaining, leftover; + int64_t nsecs, secs; + + if (timer == NULL) { + errno = EINVAL; + return -1; + } + + if (timer->status == ACTIVE) { + remaining = k_timer_remaining_get(&timer->ztimer); + secs = remaining / MSEC_PER_SEC; + leftover = remaining - (secs * MSEC_PER_SEC); + nsecs = (int64_t)leftover * NSEC_PER_MSEC; + its->it_value.tv_sec = (int32_t) secs; + its->it_value.tv_nsec = (int32_t) nsecs; + } else { + /* Timer is disarmed */ + its->it_value.tv_sec = 0; + its->it_value.tv_nsec = 0; + } + + /* The interval last set by timer_settime() */ + its->it_interval = timer->interval; + return 0; +} + +/** + * @brief Sets expiration time of per-process timer. + * + * See IEEE 1003.1 + */ +int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, + struct itimerspec *ovalue) +{ + struct timer_obj *timer = (struct timer_obj *) timerid; + uint32_t duration, current; + + if (timer == NULL || + value->it_interval.tv_nsec < 0 || + value->it_interval.tv_nsec >= NSEC_PER_SEC || + value->it_value.tv_nsec < 0 || + value->it_value.tv_nsec >= NSEC_PER_SEC) { + errno = EINVAL; + return -1; + } + + /* Save time to expire and old reload value. */ + if (ovalue != NULL) { + timer_gettime(timerid, ovalue); + } + + /* Stop the timer if the value is 0 */ + if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) { + if (timer->status == ACTIVE) { + k_timer_stop(&timer->ztimer); + } + + timer->status = NOT_ACTIVE; + return 0; + } + + /* Calculate timer period */ + timer->reload = _ts_to_ms(&value->it_interval); + timer->interval.tv_sec = value->it_interval.tv_sec; + timer->interval.tv_nsec = value->it_interval.tv_nsec; + + /* Calculate timer duration */ + duration = _ts_to_ms(&(value->it_value)); + if ((flags & TIMER_ABSTIME) != 0) { + current = k_timer_remaining_get(&timer->ztimer); + + if (current >= duration) { + duration = 0U; + } else { + duration -= current; + } + } + + if (timer->status == ACTIVE) { + k_timer_stop(&timer->ztimer); + } + + timer->status = ACTIVE; + k_timer_start(&timer->ztimer, K_MSEC(duration), K_MSEC(timer->reload)); + return 0; +} + +/** + * @brief Returns the timer expiration overrun count. + * + * See IEEE 1003.1 + */ +int timer_getoverrun(timer_t timerid) +{ + struct timer_obj *timer = (struct timer_obj *) timerid; + + if (timer == NULL) { + errno = EINVAL; + return -1; + } + + int overruns = k_timer_status_get(&timer->ztimer) - 1; + + if (overruns > CONFIG_TIMER_DELAYTIMER_MAX) { + overruns = CONFIG_TIMER_DELAYTIMER_MAX; + } + + return overruns; +} + +/** + * @brief Delete a per-process timer. + * + * See IEEE 1003.1 + */ +int timer_delete(timer_t timerid) +{ + struct timer_obj *timer = (struct timer_obj *) timerid; + + if (timer == NULL) { + errno = EINVAL; + return -1; + } + + if (timer->status == ACTIVE) { + timer->status = NOT_ACTIVE; + k_timer_stop(&timer->ztimer); + } + + if (timer->evp.sigev_notify == SIGEV_THREAD) { + (void)pthread_cancel(timer->thread); + } + + k_mem_slab_free(&posix_timer_slab, (void *)timer); + + return 0; +} diff --git a/lib/posix/uname.c b/lib/posix/options/uname.c similarity index 100% rename from lib/posix/uname.c rename to lib/posix/options/uname.c diff --git a/lib/posix/posix_internal.h b/lib/posix/posix_internal.h deleted file mode 100644 index 39c64c53331..00000000000 --- a/lib/posix/posix_internal.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2022 Meta - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ -#define ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_ - -#include -#include - -#include -#include -#include -#include - -/* - * Bit used to mark a pthread object as initialized. Initialization status is - * verified (against internal status) in lock / unlock / destroy functions. - */ -#define PTHREAD_OBJ_MASK_INIT 0x80000000 - -struct posix_thread { - struct k_thread thread; - - /* List node for ready_q, run_q, or done_q */ - sys_dnode_t q_node; - - /* List of keys that thread has called pthread_setspecific() on */ - sys_slist_t key_list; - - /* Dynamic stack */ - k_thread_stack_t *dynamic_stack; - - /* Exit status */ - void *retval; - - /* Pthread cancellation */ - uint8_t cancel_state; - bool cancel_pending; - - /* Detach state */ - uint8_t detachstate; - - /* Queue ID (internal-only) */ - uint8_t qid; -}; - -typedef struct pthread_key_obj { - /* List of pthread_key_data objects that contain thread - * specific data for the key - */ - sys_slist_t key_data_l; - - /* Optional destructor that is passed to pthread_key_create() */ - void (*destructor)(void *value); -} pthread_key_obj; - -typedef struct pthread_thread_data { - sys_snode_t node; - - /* Key and thread specific data passed to pthread_setspecific() */ - pthread_key_obj *key; - void *spec_data; -} pthread_thread_data; - -static inline bool is_pthread_obj_initialized(uint32_t obj) -{ - return (obj & PTHREAD_OBJ_MASK_INIT) != 0; -} - -static inline uint32_t mark_pthread_obj_initialized(uint32_t obj) -{ - return obj | PTHREAD_OBJ_MASK_INIT; -} - -static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj) -{ - return obj & ~PTHREAD_OBJ_MASK_INIT; -} - -struct posix_thread *to_posix_thread(pthread_t pth); - -/* get and possibly initialize a posix_mutex */ -struct k_mutex *to_posix_mutex(pthread_mutex_t *mu); - -#endif diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c deleted file mode 100644 index f2bbc07ae9a..00000000000 --- a/lib/posix/pthread.c +++ /dev/null @@ -1,973 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * Copyright (c) 2023 Meta - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "posix_internal.h" -#include "pthread_sched.h" - -#include - -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(pthread, CONFIG_PTHREAD_LOG_LEVEL); - -#ifdef CONFIG_DYNAMIC_THREAD_STACK_SIZE -#define DYNAMIC_STACK_SIZE CONFIG_DYNAMIC_THREAD_STACK_SIZE -#else -#define DYNAMIC_STACK_SIZE 0 -#endif - -#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE -#define PTHREAD_CANCELED ((void *) -1) - -enum posix_thread_qid { - /* ready to be started via pthread_create() */ - POSIX_THREAD_READY_Q, - /* running */ - POSIX_THREAD_RUN_Q, - /* exited (either joinable or detached) */ - POSIX_THREAD_DONE_Q, -}; - -BUILD_ASSERT((PTHREAD_CREATE_DETACHED == 0 || PTHREAD_CREATE_JOINABLE == 0) && - (PTHREAD_CREATE_DETACHED == 1 || PTHREAD_CREATE_JOINABLE == 1)); - -BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) && - (PTHREAD_CANCEL_ENABLE == 1 || PTHREAD_CANCEL_DISABLE == 1)); - -static void posix_thread_recycle(void); -static sys_dlist_t ready_q = SYS_DLIST_STATIC_INIT(&ready_q); -static sys_dlist_t run_q = SYS_DLIST_STATIC_INIT(&run_q); -static sys_dlist_t done_q = SYS_DLIST_STATIC_INIT(&done_q); -static struct posix_thread posix_thread_pool[CONFIG_MAX_PTHREAD_COUNT]; -static struct k_spinlock pthread_pool_lock; - -static K_MUTEX_DEFINE(pthread_once_lock); - -static const struct pthread_attr init_pthread_attrs = { - .priority = 0, - .stack = NULL, - .stacksize = 0, - .flags = PTHREAD_INIT_FLAGS, - .delayedstart = 0, -#if defined(CONFIG_PREEMPT_ENABLED) - .schedpolicy = SCHED_RR, -#else - .schedpolicy = SCHED_FIFO, -#endif - .detachstate = PTHREAD_CREATE_JOINABLE, - .initialized = true, -}; - -/* - * We reserve the MSB to mark a pthread_t as initialized (from the - * perspective of the application). With a linear space, this means that - * the theoretical pthread_t range is [0,2147483647]. - */ -BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT < PTHREAD_OBJ_MASK_INIT, - "CONFIG_MAX_PTHREAD_COUNT is too high"); - -static inline size_t posix_thread_to_offset(struct posix_thread *t) -{ - return t - posix_thread_pool; -} - -static inline size_t get_posix_thread_idx(pthread_t pth) -{ - return mark_pthread_obj_uninitialized(pth); -} - -struct posix_thread *to_posix_thread(pthread_t pthread) -{ - k_spinlock_key_t key; - struct posix_thread *t; - bool actually_initialized; - size_t bit = get_posix_thread_idx(pthread); - - /* if the provided thread does not claim to be initialized, its invalid */ - if (!is_pthread_obj_initialized(pthread)) { - LOG_ERR("pthread is not initialized (%x)", pthread); - return NULL; - } - - if (bit >= CONFIG_MAX_PTHREAD_COUNT) { - LOG_ERR("Invalid pthread (%x)", pthread); - return NULL; - } - - t = &posix_thread_pool[bit]; - - key = k_spin_lock(&pthread_pool_lock); - /* - * Denote a pthread as "initialized" (i.e. allocated) if it is not in ready_q. - * This differs from other posix object allocation strategies because they use - * a bitarray to indicate whether an object has been allocated. - */ - actually_initialized = - !(t->qid == POSIX_THREAD_READY_Q || - (t->qid == POSIX_THREAD_DONE_Q && t->detachstate == PTHREAD_CREATE_DETACHED)); - k_spin_unlock(&pthread_pool_lock, key); - - if (!actually_initialized) { - LOG_ERR("Pthread claims to be initialized (%x)", pthread); - return NULL; - } - - return &posix_thread_pool[bit]; -} - -pthread_t pthread_self(void) -{ - size_t bit; - struct posix_thread *t; - - t = (struct posix_thread *)CONTAINER_OF(k_current_get(), struct posix_thread, thread); - bit = posix_thread_to_offset(t); - - return mark_pthread_obj_initialized(bit); -} - -static bool is_posix_policy_prio_valid(uint32_t priority, int policy) -{ - if (priority >= sched_get_priority_min(policy) && - priority <= sched_get_priority_max(policy)) { - return true; - } - - LOG_ERR("Invalid piority %d and / or policy %d", priority, policy); - - return false; -} - -static uint32_t zephyr_to_posix_priority(int32_t z_prio, int *policy) -{ - uint32_t prio; - - if (z_prio < 0) { - *policy = SCHED_FIFO; - prio = -1 * (z_prio + 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_COOP_PRIORITIES); - } else { - *policy = SCHED_RR; - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - z_prio - 1); - __ASSERT_NO_MSG(prio < CONFIG_NUM_PREEMPT_PRIORITIES); - } - - return prio; -} - -static int32_t posix_to_zephyr_priority(uint32_t priority, int policy) -{ - int32_t prio; - - if (policy == SCHED_FIFO) { - /* Zephyr COOP priority starts from -1 */ - __ASSERT_NO_MSG(priority < CONFIG_NUM_COOP_PRIORITIES); - prio = -1 * (priority + 1); - } else { - __ASSERT_NO_MSG(priority < CONFIG_NUM_PREEMPT_PRIORITIES); - prio = (CONFIG_NUM_PREEMPT_PRIORITIES - priority - 1); - } - - return prio; -} - -/** - * @brief Set scheduling parameter attributes in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_setschedparam(pthread_attr_t *_attr, const struct sched_param *schedparam) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - int priority = schedparam->sched_priority; - - if ((attr == NULL) || (attr->initialized == 0U) || - (is_posix_policy_prio_valid(priority, attr->schedpolicy) == false)) { - LOG_ERR("Invalid pthread_attr_t or sched_param"); - return EINVAL; - } - - attr->priority = priority; - return 0; -} - -/** - * @brief Set stack attributes in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_setstack(pthread_attr_t *_attr, void *stackaddr, size_t stacksize) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if (stackaddr == NULL) { - LOG_ERR("NULL stack address"); - return EACCES; - } - - attr->stack = stackaddr; - attr->stacksize = stacksize; - return 0; -} - -static bool pthread_attr_is_valid(const struct pthread_attr *attr) -{ - /* auto-alloc thread stack */ - if (attr == NULL) { - return true; - } - - /* caller-provided thread stack */ - if (attr->initialized == 0U || attr->stack == NULL || attr->stacksize == 0) { - LOG_ERR("pthread_attr_t is not initialized, has a NULL stack, or is of size 0"); - return false; - } - - /* require a valid scheduler policy */ - if (!valid_posix_policy(attr->schedpolicy)) { - LOG_ERR("Invalid scheduler policy %d", attr->schedpolicy); - return false; - } - - /* require a valid detachstate */ - if (!(attr->detachstate == PTHREAD_CREATE_JOINABLE || - attr->detachstate == PTHREAD_CREATE_DETACHED)) { - LOG_ERR("Invalid detachstate %d", attr->detachstate); - return false; - } - - /* we cannot create an essential thread (i.e. one that may not abort) */ - if ((attr->flags & K_ESSENTIAL) != 0) { - LOG_ERR("Cannot create an essential thread"); - return false; - } - - return true; -} - -static void posix_thread_recycle_work_handler(struct k_work *work) -{ - ARG_UNUSED(work); - posix_thread_recycle(); -} -static K_WORK_DELAYABLE_DEFINE(posix_thread_recycle_work, posix_thread_recycle_work_handler); - -static void posix_thread_finalize(struct posix_thread *t, void *retval) -{ - sys_snode_t *node_l; - k_spinlock_key_t key; - pthread_key_obj *key_obj; - pthread_thread_data *thread_spec_data; - - SYS_SLIST_FOR_EACH_NODE(&t->key_list, node_l) { - thread_spec_data = (pthread_thread_data *)node_l; - if (thread_spec_data != NULL) { - key_obj = thread_spec_data->key; - if (key_obj->destructor != NULL) { - (key_obj->destructor)(thread_spec_data->spec_data); - } - } - } - - /* move thread from run_q to done_q */ - key = k_spin_lock(&pthread_pool_lock); - sys_dlist_remove(&t->q_node); - sys_dlist_append(&done_q, &t->q_node); - t->qid = POSIX_THREAD_DONE_Q; - t->retval = retval; - k_spin_unlock(&pthread_pool_lock, key); - - /* trigger recycle work */ - (void)k_work_schedule(&posix_thread_recycle_work, K_MSEC(CONFIG_PTHREAD_RECYCLER_DELAY_MS)); - - /* abort the underlying k_thread */ - k_thread_abort(&t->thread); -} - -FUNC_NORETURN -static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3) -{ - int err; - int barrier; - void *(*fun_ptr)(void *arg) = arg2; - struct posix_thread *t = CONTAINER_OF(k_current_get(), struct posix_thread, thread); - - if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { - /* cross the barrier so that pthread_create() can continue */ - barrier = POINTER_TO_UINT(arg3); - err = pthread_barrier_wait(&barrier); - __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); - } - - posix_thread_finalize(t, fun_ptr(arg1)); - - CODE_UNREACHABLE; -} - -static void posix_thread_recycle(void) -{ - k_spinlock_key_t key; - struct posix_thread *t; - struct posix_thread *safe_t; - sys_dlist_t recyclables = SYS_DLIST_STATIC_INIT(&recyclables); - - key = k_spin_lock(&pthread_pool_lock); - SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&done_q, t, safe_t, q_node) { - if (t->detachstate == PTHREAD_CREATE_JOINABLE) { - /* thread has not been joined yet */ - continue; - } - - sys_dlist_remove(&t->q_node); - sys_dlist_append(&recyclables, &t->q_node); - } - k_spin_unlock(&pthread_pool_lock, key); - - if (sys_dlist_is_empty(&recyclables)) { - return; - } - - LOG_DBG("Recycling %zu threads", sys_dlist_len(&recyclables)); - - if (IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { - SYS_DLIST_FOR_EACH_CONTAINER(&recyclables, t, q_node) { - if (t->dynamic_stack != NULL) { - LOG_DBG("Freeing thread stack %p", t->dynamic_stack); - (void)k_thread_stack_free(t->dynamic_stack); - t->dynamic_stack = NULL; - } - } - } - - key = k_spin_lock(&pthread_pool_lock); - while (!sys_dlist_is_empty(&recyclables)) { - sys_dlist_append(&ready_q, sys_dlist_get(&recyclables)); - } - k_spin_unlock(&pthread_pool_lock, key); -} - -/** - * @brief Create a new thread. - * - * Pthread attribute should not be NULL. API will return Error on NULL - * attribute value. - * - * See IEEE 1003.1 - */ -int pthread_create(pthread_t *th, const pthread_attr_t *_attr, void *(*threadroutine)(void *), - void *arg) -{ - int err; - k_spinlock_key_t key; - pthread_barrier_t barrier; - struct posix_thread *t = NULL; - struct pthread_attr attr_storage = init_pthread_attrs; - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if (!pthread_attr_is_valid(attr)) { - return EINVAL; - } - - if (attr == NULL) { - attr = &attr_storage; - attr->stacksize = DYNAMIC_STACK_SIZE; - attr->stack = - k_thread_stack_alloc(attr->stacksize, k_is_user_context() ? K_USER : 0); - if (attr->stack == NULL) { - LOG_ERR("Unable to allocate stack of size %u", attr->stacksize); - return EAGAIN; - } - LOG_DBG("Allocated thread stack %p", attr->stack); - } else { - __ASSERT_NO_MSG(attr != &attr_storage); - } - - /* reclaim resources greedily */ - posix_thread_recycle(); - - key = k_spin_lock(&pthread_pool_lock); - if (!sys_dlist_is_empty(&ready_q)) { - t = CONTAINER_OF(sys_dlist_get(&ready_q), struct posix_thread, q_node); - - /* initialize thread state */ - sys_dlist_append(&run_q, &t->q_node); - t->qid = POSIX_THREAD_RUN_Q; - t->detachstate = attr->detachstate; - if ((BIT(_PTHREAD_CANCEL_POS) & attr->flags) != 0) { - t->cancel_state = PTHREAD_CANCEL_ENABLE; - } - t->cancel_pending = false; - sys_slist_init(&t->key_list); - t->dynamic_stack = _attr == NULL ? attr->stack : NULL; - } - k_spin_unlock(&pthread_pool_lock, key); - - if (t == NULL) { - /* no threads are ready */ - LOG_ERR("No threads are ready"); - return EAGAIN; - } - - if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { - err = pthread_barrier_init(&barrier, NULL, 2); - if (err != 0) { - if (t->dynamic_stack != NULL) { - LOG_DBG("freeing thread stack at %p", attr->stack); - (void)k_thread_stack_free(attr->stack); - } - - /* cannot allocate barrier. move thread back to ready_q */ - key = k_spin_lock(&pthread_pool_lock); - sys_dlist_remove(&t->q_node); - sys_dlist_append(&ready_q, &t->q_node); - t->qid = POSIX_THREAD_READY_Q; - k_spin_unlock(&pthread_pool_lock, key); - t = NULL; - } - } - - /* spawn the thread */ - k_thread_create(&t->thread, attr->stack, attr->stacksize, zephyr_thread_wrapper, - (void *)arg, threadroutine, - IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER) ? UINT_TO_POINTER(barrier) - : NULL, - posix_to_zephyr_priority(attr->priority, attr->schedpolicy), attr->flags, - K_MSEC(attr->delayedstart)); - - if (IS_ENABLED(CONFIG_PTHREAD_CREATE_BARRIER)) { - /* wait for the spawned thread to cross our barrier */ - err = pthread_barrier_wait(&barrier); - __ASSERT_NO_MSG(err == 0 || err == PTHREAD_BARRIER_SERIAL_THREAD); - err = pthread_barrier_destroy(&barrier); - __ASSERT_NO_MSG(err == 0); - } - - /* finally provide the initialized thread to the caller */ - *th = mark_pthread_obj_initialized(posix_thread_to_offset(t)); - - LOG_DBG("Created pthread %p", &t->thread); - - return 0; -} - -/** - * @brief Set cancelability State. - * - * See IEEE 1003.1 - */ -int pthread_setcancelstate(int state, int *oldstate) -{ - bool cancel_pending; - k_spinlock_key_t key; - struct posix_thread *t; - - if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) { - LOG_ERR("Invalid pthread state %d", state); - return EINVAL; - } - - t = to_posix_thread(pthread_self()); - if (t == NULL) { - return EINVAL; - } - - key = k_spin_lock(&pthread_pool_lock); - *oldstate = t->cancel_state; - t->cancel_state = state; - cancel_pending = t->cancel_pending; - k_spin_unlock(&pthread_pool_lock, key); - - if (state == PTHREAD_CANCEL_ENABLE && cancel_pending) { - posix_thread_finalize(t, PTHREAD_CANCELED); - } - - return 0; -} - -/** - * @brief Cancel execution of a thread. - * - * See IEEE 1003.1 - */ -int pthread_cancel(pthread_t pthread) -{ - int cancel_state; - k_spinlock_key_t key; - struct posix_thread *t; - - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } - - key = k_spin_lock(&pthread_pool_lock); - t->cancel_pending = true; - cancel_state = t->cancel_state; - k_spin_unlock(&pthread_pool_lock, key); - - if (cancel_state == PTHREAD_CANCEL_ENABLE) { - posix_thread_finalize(t, PTHREAD_CANCELED); - } - - return 0; -} - -/** - * @brief Set thread scheduling policy and parameters. - * - * See IEEE 1003.1 - */ -int pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) -{ - struct posix_thread *t = to_posix_thread(pthread); - int new_prio; - - if (t == NULL) { - return ESRCH; - } - - if (!valid_posix_policy(policy)) { - LOG_ERR("Invalid scheduler policy %d", policy); - return EINVAL; - } - - if (is_posix_policy_prio_valid(param->sched_priority, policy) == false) { - return EINVAL; - } - - new_prio = posix_to_zephyr_priority(param->sched_priority, policy); - - k_thread_priority_set(&t->thread, new_prio); - return 0; -} - -/** - * @brief Initialise threads attribute object - * - * See IEEE 1003.1 - */ -int pthread_attr_init(pthread_attr_t *attr) -{ - - if (attr == NULL) { - LOG_ERR("Invalid attr pointer"); - return ENOMEM; - } - - (void)memcpy(attr, &init_pthread_attrs, sizeof(pthread_attr_t)); - - return 0; -} - -/** - * @brief Get thread scheduling policy and parameters - * - * See IEEE 1003.1 - */ -int pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) -{ - uint32_t priority; - struct posix_thread *t; - - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } - - priority = k_thread_priority_get(&t->thread); - - param->sched_priority = zephyr_to_posix_priority(priority, policy); - return 0; -} - -/** - * @brief Dynamic package initialization - * - * See IEEE 1003.1 - */ -int pthread_once(pthread_once_t *once, void (*init_func)(void)) -{ - __unused int ret; - - ret = k_mutex_lock(&pthread_once_lock, K_FOREVER); - __ASSERT_NO_MSG(ret == 0); - - if (once->is_initialized != 0 && once->init_executed == 0) { - init_func(); - once->init_executed = 1; - } - - ret = k_mutex_unlock(&pthread_once_lock); - __ASSERT_NO_MSG(ret == 0); - - return 0; -} - -/** - * @brief Terminate calling thread. - * - * See IEEE 1003.1 - */ -FUNC_NORETURN -void pthread_exit(void *retval) -{ - k_spinlock_key_t key; - struct posix_thread *self; - - self = to_posix_thread(pthread_self()); - if (self == NULL) { - /* not a valid posix_thread */ - LOG_DBG("Aborting non-pthread %p", k_current_get()); - k_thread_abort(k_current_get()); - - CODE_UNREACHABLE; - } - - /* Make a thread as cancelable before exiting */ - key = k_spin_lock(&pthread_pool_lock); - self->cancel_state = PTHREAD_CANCEL_ENABLE; - k_spin_unlock(&pthread_pool_lock, key); - - posix_thread_finalize(self, retval); - CODE_UNREACHABLE; -} - -/** - * @brief Wait for a thread termination. - * - * See IEEE 1003.1 - */ -int pthread_join(pthread_t pthread, void **status) -{ - struct posix_thread *t; - int ret; - - if (pthread == pthread_self()) { - LOG_ERR("Pthread attempted to join itself (%x)", pthread); - return EDEADLK; - } - - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } - - LOG_DBG("Pthread %p joining..", &t->thread); - - ret = 0; - K_SPINLOCK(&pthread_pool_lock) - { - if (t->detachstate != PTHREAD_CREATE_JOINABLE) { - ret = EINVAL; - K_SPINLOCK_BREAK; - } - - if (t->qid == POSIX_THREAD_READY_Q) { - /* in case thread has moved to ready_q between to_posix_thread() and here */ - ret = ESRCH; - K_SPINLOCK_BREAK; - } - - /* - * thread is joinable and is in run_q or done_q. - * let's ensure that the thread cannot be joined again after this point. - */ - t->detachstate = PTHREAD_CREATE_DETACHED; - } - - switch (ret) { - case ESRCH: - LOG_ERR("Pthread %p has already been joined", &t->thread); - return ret; - case EINVAL: - LOG_ERR("Pthread %p is not a joinable", &t->thread); - return ret; - case 0: - break; - } - - ret = k_thread_join(&t->thread, K_FOREVER); - /* other possibilities? */ - __ASSERT_NO_MSG(ret == 0); - - LOG_DBG("Joined pthread %p", &t->thread); - - if (status != NULL) { - LOG_DBG("Writing status to %p", status); - *status = t->retval; - } - - posix_thread_recycle(); - - return 0; -} - -/** - * @brief Detach a thread. - * - * See IEEE 1003.1 - */ -int pthread_detach(pthread_t pthread) -{ - int ret; - k_spinlock_key_t key; - struct posix_thread *t; - enum posix_thread_qid qid; - - t = to_posix_thread(pthread); - if (t == NULL) { - return ESRCH; - } - - key = k_spin_lock(&pthread_pool_lock); - qid = t->qid; - if (qid == POSIX_THREAD_READY_Q || t->detachstate != PTHREAD_CREATE_JOINABLE) { - LOG_ERR("Pthread %p cannot be detached", &t->thread); - ret = EINVAL; - } else { - ret = 0; - t->detachstate = PTHREAD_CREATE_DETACHED; - } - k_spin_unlock(&pthread_pool_lock, key); - - if (ret == 0) { - LOG_DBG("Pthread %p detached", &t->thread); - } - - return ret; -} - -/** - * @brief Get detach state attribute in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_getdetachstate(const pthread_attr_t *_attr, int *detachstate) -{ - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - *detachstate = attr->detachstate; - return 0; -} - -/** - * @brief Set detach state attribute in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_setdetachstate(pthread_attr_t *_attr, int detachstate) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U) || - (detachstate != PTHREAD_CREATE_DETACHED && detachstate != PTHREAD_CREATE_JOINABLE)) { - return EINVAL; - } - - attr->detachstate = detachstate; - return 0; -} - -/** - * @brief Get scheduling policy attribute in Thread attributes. - * - * See IEEE 1003.1 - */ -int pthread_attr_getschedpolicy(const pthread_attr_t *_attr, int *policy) -{ - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - *policy = attr->schedpolicy; - return 0; -} - -/** - * @brief Set scheduling policy attribute in Thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_setschedpolicy(pthread_attr_t *_attr, int policy) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U) || !valid_posix_policy(policy)) { - return EINVAL; - } - - attr->schedpolicy = policy; - return 0; -} - -/** - * @brief Get stack size attribute in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_getstacksize(const pthread_attr_t *_attr, size_t *stacksize) -{ - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - *stacksize = attr->stacksize; - return 0; -} - -/** - * @brief Set stack size attribute in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - if (stacksize < PTHREAD_STACK_MIN) { - return EINVAL; - } - - attr->stacksize = stacksize; - return 0; -} - -/** - * @brief Get stack attributes in thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_getstack(const pthread_attr_t *_attr, void **stackaddr, size_t *stacksize) -{ - const struct pthread_attr *attr = (const struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - *stackaddr = attr->stack; - *stacksize = attr->stacksize; - return 0; -} - -/** - * @brief Get thread attributes object scheduling parameters. - * - * See IEEE 1003.1 - */ -int pthread_attr_getschedparam(const pthread_attr_t *_attr, struct sched_param *schedparam) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if ((attr == NULL) || (attr->initialized == 0U)) { - return EINVAL; - } - - schedparam->sched_priority = attr->priority; - return 0; -} - -/** - * @brief Destroy thread attributes object. - * - * See IEEE 1003.1 - */ -int pthread_attr_destroy(pthread_attr_t *_attr) -{ - struct pthread_attr *attr = (struct pthread_attr *)_attr; - - if ((attr != NULL) && (attr->initialized != 0U)) { - attr->initialized = false; - return 0; - } - - return EINVAL; -} - -int pthread_setname_np(pthread_t thread, const char *name) -{ -#ifdef CONFIG_THREAD_NAME - k_tid_t kthread; - - thread = get_posix_thread_idx(thread); - if (thread >= CONFIG_MAX_PTHREAD_COUNT) { - return ESRCH; - } - - kthread = &posix_thread_pool[thread].thread; - - if (name == NULL) { - return EINVAL; - } - - return k_thread_name_set(kthread, name); -#else - ARG_UNUSED(thread); - ARG_UNUSED(name); - return 0; -#endif -} - -int pthread_getname_np(pthread_t thread, char *name, size_t len) -{ -#ifdef CONFIG_THREAD_NAME - k_tid_t kthread; - - thread = get_posix_thread_idx(thread); - if (thread >= CONFIG_MAX_PTHREAD_COUNT) { - return ESRCH; - } - - if (name == NULL) { - return EINVAL; - } - - memset(name, '\0', len); - kthread = &posix_thread_pool[thread].thread; - return k_thread_name_copy(kthread, name, len - 1); -#else - ARG_UNUSED(thread); - ARG_UNUSED(name); - ARG_UNUSED(len); - return 0; -#endif -} - -static int posix_thread_pool_init(void) -{ - size_t i; - - for (i = 0; i < CONFIG_MAX_PTHREAD_COUNT; ++i) { - sys_dlist_append(&ready_q, &posix_thread_pool[i].q_node); - } - - return 0; -} - -int pthread_equal(pthread_t pt1, pthread_t pt2) -{ - return (pt1 == pt2); -} - -SYS_INIT(posix_thread_pool_init, PRE_KERNEL_1, 0); diff --git a/lib/posix/rwlock.c b/lib/posix/rwlock.c deleted file mode 100644 index 60039fb088a..00000000000 --- a/lib/posix/rwlock.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include - -#define INITIALIZED 1 -#define NOT_INITIALIZED 0 - -#define CONCURRENT_READER_LIMIT (CONFIG_MAX_PTHREAD_COUNT + 1) - -int64_t timespec_to_timeoutms(const struct timespec *abstime); -static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout); - -/** - * @brief Initialize read-write lock object. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_init(pthread_rwlock_t *rwlock, - const pthread_rwlockattr_t *attr) -{ - k_sem_init(&rwlock->rd_sem, CONCURRENT_READER_LIMIT, - CONCURRENT_READER_LIMIT); - k_sem_init(&rwlock->wr_sem, 1, 1); - k_sem_init(&rwlock->reader_active, 1, 1); - rwlock->wr_owner = NULL; - rwlock->status = INITIALIZED; - return 0; -} - -/** - * @brief Destroy read-write lock object. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - if (rwlock->wr_owner != NULL) { - return EBUSY; - } - - if (rwlock->status == INITIALIZED) { - rwlock->status = NOT_INITIALIZED; - return 0; - } - - return EINVAL; -} - -/** - * @brief Lock a read-write lock object for reading. - * - * API behaviour is unpredictable if number of concurrent reader - * lock held is greater than CONCURRENT_READER_LIMIT. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - return read_lock_acquire(rwlock, SYS_FOREVER_MS); -} - -/** - * @brief Lock a read-write lock object for reading within specific time. - * - * API behaviour is unpredictable if number of concurrent reader - * lock held is greater than CONCURRENT_READER_LIMIT. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, - const struct timespec *abstime) -{ - int32_t timeout; - uint32_t ret = 0U; - - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { - return EINVAL; - } - - timeout = (int32_t) timespec_to_timeoutms(abstime); - - if (read_lock_acquire(rwlock, timeout) != 0U) { - ret = ETIMEDOUT; - } - - return ret; -} - -/** - * @brief Lock a read-write lock object for reading immediately. - * - * API behaviour is unpredictable if number of concurrent reader - * lock held is greater than CONCURRENT_READER_LIMIT. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - return read_lock_acquire(rwlock, 0); -} - -/** - * @brief Lock a read-write lock object for writing. - * - * Write lock does not have priority over reader lock, - * threads get lock based on priority. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - return write_lock_acquire(rwlock, SYS_FOREVER_MS); -} - -/** - * @brief Lock a read-write lock object for writing within specific time. - * - * Write lock does not have priority over reader lock, - * threads get lock based on priority. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, - const struct timespec *abstime) -{ - int32_t timeout; - uint32_t ret = 0U; - - if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 || - abstime->tv_nsec > NSEC_PER_SEC) { - return EINVAL; - } - - timeout = (int32_t) timespec_to_timeoutms(abstime); - - if (write_lock_acquire(rwlock, timeout) != 0U) { - ret = ETIMEDOUT; - } - - return ret; -} - -/** - * @brief Lock a read-write lock object for writing immediately. - * - * Write lock does not have priority over reader lock, - * threads get lock based on priority. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - return write_lock_acquire(rwlock, 0); -} - -/** - * - * @brief Unlock a read-write lock object. - * - * See IEEE 1003.1 - */ -int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) -{ - if (rwlock->status == NOT_INITIALIZED) { - return EINVAL; - } - - if (k_current_get() == rwlock->wr_owner) { - /* Write unlock */ - rwlock->wr_owner = NULL; - k_sem_give(&rwlock->reader_active); - k_sem_give(&rwlock->wr_sem); - } else { - /* Read unlock */ - k_sem_give(&rwlock->rd_sem); - - if (k_sem_count_get(&rwlock->rd_sem) == - CONCURRENT_READER_LIMIT) { - /* Last read lock, unlock writer */ - k_sem_give(&rwlock->reader_active); - } - } - return 0; -} - - -static uint32_t read_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) -{ - uint32_t ret = 0U; - - if (k_sem_take(&rwlock->wr_sem, SYS_TIMEOUT_MS(timeout)) == 0) { - k_sem_take(&rwlock->reader_active, K_NO_WAIT); - k_sem_take(&rwlock->rd_sem, K_NO_WAIT); - k_sem_give(&rwlock->wr_sem); - } else { - ret = EBUSY; - } - - return ret; -} - -static uint32_t write_lock_acquire(pthread_rwlock_t *rwlock, int32_t timeout) -{ - uint32_t ret = 0U; - int64_t elapsed_time, st_time = k_uptime_get(); - k_timeout_t k_timeout; - - k_timeout = SYS_TIMEOUT_MS(timeout); - - /* waiting for release of write lock */ - if (k_sem_take(&rwlock->wr_sem, k_timeout) == 0) { - /* update remaining timeout time for 2nd sem */ - if (timeout != SYS_FOREVER_MS) { - elapsed_time = k_uptime_get() - st_time; - timeout = timeout <= elapsed_time ? 0 : - timeout - elapsed_time; - } - - k_timeout = SYS_TIMEOUT_MS(timeout); - - /* waiting for reader to complete operation */ - if (k_sem_take(&rwlock->reader_active, k_timeout) == 0) { - rwlock->wr_owner = k_current_get(); - } else { - k_sem_give(&rwlock->wr_sem); - ret = EBUSY; - } - - } else { - ret = EBUSY; - } - return ret; -} diff --git a/lib/posix/sched.c b/lib/posix/sched.c deleted file mode 100644 index 4f71badded9..00000000000 --- a/lib/posix/sched.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "pthread_sched.h" - -#include -#include - -/** - * @brief Get minimum priority value for a given policy - * - * See IEEE 1003.1 - */ -int sched_get_priority_min(int policy) -{ - if (!valid_posix_policy(policy)) { - errno = EINVAL; - return -1; - } - - return 0; -} - -/** - * @brief Get maximum priority value for a given policy - * - * See IEEE 1003.1 - */ -int sched_get_priority_max(int policy) -{ - if (IS_ENABLED(CONFIG_COOP_ENABLED) && policy == SCHED_FIFO) { - return CONFIG_NUM_COOP_PRIORITIES - 1; - } else if (IS_ENABLED(CONFIG_PREEMPT_ENABLED) && - (policy == SCHED_RR || policy == SCHED_OTHER)) { - return CONFIG_NUM_PREEMPT_PRIORITIES - 1; - } - - errno = EINVAL; - return -1; -} diff --git a/lib/posix/semaphore.c b/lib/posix/semaphore.c deleted file mode 100644 index 7a1392cd521..00000000000 --- a/lib/posix/semaphore.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -/** - * @brief Destroy semaphore. - * - * see IEEE 1003.1 - */ -int sem_destroy(sem_t *semaphore) -{ - if (semaphore == NULL) { - errno = EINVAL; - return -1; - } - - if (k_sem_count_get(semaphore)) { - errno = EBUSY; - return -1; - } - - k_sem_reset(semaphore); - return 0; -} - -/** - * @brief Get value of semaphore. - * - * See IEEE 1003.1 - */ -int sem_getvalue(sem_t *semaphore, int *value) -{ - if (semaphore == NULL) { - errno = EINVAL; - return -1; - } - - *value = (int) k_sem_count_get(semaphore); - - return 0; -} -/** - * @brief Initialize semaphore. - * - * See IEEE 1003.1 - */ -int sem_init(sem_t *semaphore, int pshared, unsigned int value) -{ - if (value > CONFIG_SEM_VALUE_MAX) { - errno = EINVAL; - return -1; - } - - /* - * Zephyr has no concept of process, so only thread shared - * semaphore makes sense in here. - */ - __ASSERT(pshared == 0, "pshared should be 0"); - - k_sem_init(semaphore, value, CONFIG_SEM_VALUE_MAX); - - return 0; -} - -/** - * @brief Unlock a semaphore. - * - * See IEEE 1003.1 - */ -int sem_post(sem_t *semaphore) -{ - if (semaphore == NULL) { - errno = EINVAL; - return -1; - } - - k_sem_give(semaphore); - return 0; -} - -/** - * @brief Try time limited locking a semaphore. - * - * See IEEE 1003.1 - */ -int sem_timedwait(sem_t *semaphore, struct timespec *abstime) -{ - int32_t timeout; - struct timespec current; - int64_t current_ms, abstime_ms; - - __ASSERT(abstime, "abstime pointer NULL"); - - if ((abstime->tv_sec < 0) || (abstime->tv_nsec >= NSEC_PER_SEC)) { - errno = EINVAL; - return -1; - } - - if (clock_gettime(CLOCK_REALTIME, ¤t) < 0) { - return -1; - } - - abstime_ms = (int64_t)_ts_to_ms(abstime); - current_ms = (int64_t)_ts_to_ms(¤t); - - if (abstime_ms <= current_ms) { - timeout = 0; - } else { - timeout = (int32_t)(abstime_ms - current_ms); - } - - if (k_sem_take(semaphore, K_MSEC(timeout))) { - errno = ETIMEDOUT; - return -1; - } - - return 0; -} - -/** - * @brief Lock a semaphore if not taken. - * - * See IEEE 1003.1 - */ -int sem_trywait(sem_t *semaphore) -{ - if (k_sem_take(semaphore, K_NO_WAIT) == -EBUSY) { - errno = EAGAIN; - return -1; - } else { - return 0; - } -} - -/** - * @brief Lock a semaphore. - * - * See IEEE 1003.1 - */ -int sem_wait(sem_t *semaphore) -{ - /* With K_FOREVER, may return only success. */ - (void)k_sem_take(semaphore, K_FOREVER); - return 0; -} diff --git a/lib/posix/shell/CMakeLists.txt b/lib/posix/shell/CMakeLists.txt new file mode 100644 index 00000000000..b6dfe6a565f --- /dev/null +++ b/lib/posix/shell/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_POSIX_SHELL posix_shell.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME_SHELL uname.c) diff --git a/lib/posix/shell/Kconfig b/lib/posix/shell/Kconfig new file mode 100644 index 00000000000..d7116b492a8 --- /dev/null +++ b/lib/posix/shell/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +menu "POSIX Shell Utilities" + +if SHELL + +config POSIX_SHELL + bool + help + Compile the parent `posix` shell command. + +rsource "Kconfig.uname" + +endif # SHELL + +endmenu # "POSIX Shell Utilities" diff --git a/lib/posix/shell/Kconfig.uname b/lib/posix/shell/Kconfig.uname new file mode 100644 index 00000000000..11ea1166433 --- /dev/null +++ b/lib/posix/shell/Kconfig.uname @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +if POSIX_UNAME + +config POSIX_UNAME_SHELL + bool "Support for `uname` command" + select SHELL_GETOPT + select POSIX_SHELL + help + Support for `uname` command in the terminal. + +endif # POSIX_UNAME diff --git a/lib/posix/shell/posix_shell.c b/lib/posix/shell/posix_shell.c new file mode 100644 index 00000000000..95fdd4ef5a0 --- /dev/null +++ b/lib/posix/shell/posix_shell.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +SHELL_SUBCMD_SET_CREATE(posix_cmds, (posix)); +SHELL_CMD_ARG_REGISTER(posix, &posix_cmds, "POSIX shell commands", NULL, 2, 0); diff --git a/lib/posix/shell/posix_shell.h b/lib/posix/shell/posix_shell.h new file mode 100644 index 00000000000..cb17d613b18 --- /dev/null +++ b/lib/posix/shell/posix_shell.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ +#define ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ + +#include + +/* Add command to the set of POSIX subcommands, see `SHELL_SUBCMD_ADD` */ +#define POSIX_CMD_ADD(_syntax, _subcmd, _help, _handler, _mand, _opt) \ + SHELL_SUBCMD_ADD((posix), _syntax, _subcmd, _help, _handler, _mand, _opt); + +#endif /* ZEPHYR_LIB_POSIX_SHELL_POSIX_SHELL_H_ */ diff --git a/lib/posix/shell/uname.c b/lib/posix/shell/uname.c new file mode 100644 index 00000000000..54e12de9a59 --- /dev/null +++ b/lib/posix/shell/uname.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024 Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "posix_shell.h" + +#include +#include + +#define UNAME_KERNEL BIT(0) +#define UNAME_NODE BIT(1) +#define UNAME_RELEASE BIT(2) +#define UNAME_VERSION BIT(3) +#define UNAME_MACHINE BIT(4) +#define UNAME_PLATFORM BIT(5) +#define UNAME_UNKNOWN BIT(6) +#define UNAME_ALL \ + (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM) + +#define HELP_USAGE \ + "Usage: uname [OPTION]\n" \ + "Print system information\n" \ + "\n" \ + " -a, all informationn\n" \ + " -s, kernel name\n" \ + " -o, operating system\n" \ + " -n, network node hostname\n" \ + " -r, kernel release\n" \ + " -v, kernel version\n" \ + " -m, machine hardware name\n" \ + " -p, processor type\n" \ + " -i, hardware platform\n" + +static void uname_print_usage(const struct shell *sh) +{ + shell_print(sh, HELP_USAGE); +} + +static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) +{ + struct getopt_state *state = getopt_state_get(); + struct utsname info; + unsigned int set; + int option; + char badarg = 0; + int ret; + + set = 0; + + /* Get the uname options */ + + optind = 1; + while ((option = getopt(argc, argv, "asonrvmpi")) != -1) { + switch (option) { + case 'a': + set = UNAME_ALL; + break; + + case 'o': + case 's': + set |= UNAME_KERNEL; + break; + + case 'n': + set |= UNAME_NODE; + break; + + case 'r': + set |= UNAME_RELEASE; + break; + + case 'v': + set |= UNAME_VERSION; + break; + + case 'm': + set |= UNAME_MACHINE; + break; + + case 'p': + if (set != UNAME_ALL) { + set |= UNAME_UNKNOWN; + } + break; + + case 'i': + set |= UNAME_PLATFORM; + break; + + case '?': + default: + badarg = (char)state->optopt; + break; + } + } + + if (argc != optind) { + shell_error(sh, "uname: extra operand %s", argv[optind]); + uname_print_usage(sh); + return -1; + } + + /* If a bad argument was encountered, then return without processing the + * command + */ + + if (badarg != 0) { + shell_error(sh, "uname: illegal option -- %c", badarg); + uname_print_usage(sh); + return -1; + } + + /* If nothing is provided on the command line, the default is -s */ + + if (set == 0) { + set = UNAME_KERNEL; + } + + /* Get uname data */ + + ret = uname(&info); + if (ret < 0) { + shell_error(sh, "cannot get system name"); + return -1; + } + + /* Process each option */ + + /* print the kernel/operating system name */ + if (set & UNAME_KERNEL) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.sysname); + } + + /* Print nodename */ + if (set & UNAME_NODE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.nodename); + } + + /* Print the kernel release */ + if (set & UNAME_RELEASE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.release); + } + + /* Print the kernel version */ + if (set & UNAME_VERSION) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.version); + } + + /* Print the machine hardware name */ + if (set & UNAME_MACHINE) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", info.machine); + } + + /* Print the machine platform name */ + if (set & UNAME_PLATFORM) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", CONFIG_BOARD); + } + + /* Print "unknown" */ + if (set & UNAME_UNKNOWN) { + shell_fprintf(sh, SHELL_NORMAL, "%s ", "unknown"); + } + + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + return 0; +} + +POSIX_CMD_ADD(uname, NULL, "Print system information", uname_cmd_handler, 1, 1); diff --git a/lib/posix/timer.c b/lib/posix/timer.c deleted file mode 100644 index 39668a1c402..00000000000 --- a/lib/posix/timer.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2018 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include -#include -#include -#include - -#define ACTIVE 1 -#define NOT_ACTIVE 0 - -static void zephyr_timer_wrapper(struct k_timer *ztimer); - -struct timer_obj { - struct k_timer ztimer; - void (*sigev_notify_function)(union sigval val); - union sigval val; - int sigev_notify; - struct k_sem sem_cond; - pthread_t thread; - struct timespec interval; /* Reload value */ - uint32_t reload; /* Reload value in ms */ - uint32_t status; -}; - -K_MEM_SLAB_DEFINE(posix_timer_slab, sizeof(struct timer_obj), - CONFIG_MAX_TIMER_COUNT, 4); - -static void zephyr_timer_wrapper(struct k_timer *ztimer) -{ - struct timer_obj *timer; - - timer = (struct timer_obj *)ztimer; - - if (timer->reload == 0U) { - timer->status = NOT_ACTIVE; - } - - (timer->sigev_notify_function)(timer->val); -} - -static void *zephyr_thread_wrapper(void *arg) -{ - struct timer_obj *timer = (struct timer_obj *)arg; - - while (1) { - if (timer->reload == 0U) { - timer->status = NOT_ACTIVE; - } - - k_sem_take(&timer->sem_cond, K_FOREVER); - - (timer->sigev_notify_function)(timer->val); - } - - return NULL; -} - -static void zephyr_timer_interrupt(struct k_timer *ztimer) -{ - struct timer_obj *timer; - - timer = (struct timer_obj *)ztimer; - k_sem_give(&timer->sem_cond); -} - -/** - * @brief Create a per-process timer. - * - * This API does not accept SIGEV_THREAD as valid signal event notification - * type. - * - * See IEEE 1003.1 - */ -int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) -{ - struct timer_obj *timer; - const k_timeout_t alloc_timeout = K_MSEC(CONFIG_TIMER_CREATE_WAIT); - - if (clockid != CLOCK_MONOTONIC || evp == NULL || - (evp->sigev_notify != SIGEV_NONE && - evp->sigev_notify != SIGEV_SIGNAL && - evp->sigev_notify != SIGEV_THREAD)) { - errno = EINVAL; - return -1; - } - - if (k_mem_slab_alloc(&posix_timer_slab, (void **)&timer, alloc_timeout) == 0) { - (void)memset(timer, 0, sizeof(struct timer_obj)); - } else { - errno = ENOMEM; - return -1; - } - - timer->sigev_notify_function = evp->sigev_notify_function; - timer->val = evp->sigev_value; - timer->interval.tv_sec = 0; - timer->interval.tv_nsec = 0; - timer->reload = 0U; - timer->status = NOT_ACTIVE; - - if (evp->sigev_notify == SIGEV_NONE) { - k_timer_init(&timer->ztimer, NULL, NULL); - } else if (evp->sigev_notify == SIGEV_THREAD) { - int ret; - - timer->sigev_notify = SIGEV_THREAD; - k_sem_init(&timer->sem_cond, 0, 1); - ret = pthread_create(&timer->thread, evp->sigev_notify_attributes, - zephyr_thread_wrapper, timer); - if (ret != 0) { - k_mem_slab_free(&posix_timer_slab, (void *) &timer); - return ret; - } - - pthread_detach(timer->thread); - k_timer_init(&timer->ztimer, zephyr_timer_interrupt, NULL); - } else { - k_timer_init(&timer->ztimer, zephyr_timer_wrapper, NULL); - } - - *timerid = (timer_t)timer; - - return 0; -} - -/** - * @brief Get amount of time left for expiration on a per-process timer. - * - * See IEEE 1003.1 - */ -int timer_gettime(timer_t timerid, struct itimerspec *its) -{ - struct timer_obj *timer = (struct timer_obj *)timerid; - int32_t remaining, leftover; - int64_t nsecs, secs; - - if (timer == NULL) { - errno = EINVAL; - return -1; - } - - if (timer->status == ACTIVE) { - remaining = k_timer_remaining_get(&timer->ztimer); - secs = remaining / MSEC_PER_SEC; - leftover = remaining - (secs * MSEC_PER_SEC); - nsecs = (int64_t)leftover * NSEC_PER_MSEC; - its->it_value.tv_sec = (int32_t) secs; - its->it_value.tv_nsec = (int32_t) nsecs; - } else { - /* Timer is disarmed */ - its->it_value.tv_sec = 0; - its->it_value.tv_nsec = 0; - } - - /* The interval last set by timer_settime() */ - its->it_interval = timer->interval; - return 0; -} - -/** - * @brief Sets expiration time of per-process timer. - * - * See IEEE 1003.1 - */ -int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, - struct itimerspec *ovalue) -{ - struct timer_obj *timer = (struct timer_obj *) timerid; - uint32_t duration, current; - - if (timer == NULL || - value->it_interval.tv_nsec < 0 || - value->it_interval.tv_nsec >= NSEC_PER_SEC || - value->it_value.tv_nsec < 0 || - value->it_value.tv_nsec >= NSEC_PER_SEC) { - errno = EINVAL; - return -1; - } - - /* Save time to expire and old reload value. */ - if (ovalue != NULL) { - timer_gettime(timerid, ovalue); - } - - /* Stop the timer if the value is 0 */ - if ((value->it_value.tv_sec == 0) && (value->it_value.tv_nsec == 0)) { - if (timer->status == ACTIVE) { - k_timer_stop(&timer->ztimer); - } - - timer->status = NOT_ACTIVE; - return 0; - } - - /* Calculate timer period */ - timer->reload = _ts_to_ms(&value->it_interval); - timer->interval.tv_sec = value->it_interval.tv_sec; - timer->interval.tv_nsec = value->it_interval.tv_nsec; - - /* Calculate timer duration */ - duration = _ts_to_ms(&(value->it_value)); - if ((flags & TIMER_ABSTIME) != 0) { - current = k_timer_remaining_get(&timer->ztimer); - - if (current >= duration) { - duration = 0U; - } else { - duration -= current; - } - } - - if (timer->status == ACTIVE) { - k_timer_stop(&timer->ztimer); - } - - timer->status = ACTIVE; - k_timer_start(&timer->ztimer, K_MSEC(duration), K_MSEC(timer->reload)); - return 0; -} - -/** - * @brief Returns the timer expiration overrun count. - * - * See IEEE 1003.1 - */ -int timer_getoverrun(timer_t timerid) -{ - struct timer_obj *timer = (struct timer_obj *) timerid; - - if (timer == NULL) { - errno = EINVAL; - return -1; - } - - int overruns = k_timer_status_get(&timer->ztimer) - 1; - - if (overruns > CONFIG_TIMER_DELAYTIMER_MAX) { - overruns = CONFIG_TIMER_DELAYTIMER_MAX; - } - - return overruns; -} - -/** - * @brief Delete a per-process timer. - * - * See IEEE 1003.1 - */ -int timer_delete(timer_t timerid) -{ - struct timer_obj *timer = (struct timer_obj *) timerid; - - if (timer == NULL) { - errno = EINVAL; - return -1; - } - - if (timer->status == ACTIVE) { - timer->status = NOT_ACTIVE; - k_timer_stop(&timer->ztimer); - } - - if (timer->sigev_notify == SIGEV_THREAD) - pthread_cancel(timer->thread); - - k_mem_slab_free(&posix_timer_slab, (void *)timer); - - return 0; -} diff --git a/lib/utils/CMakeLists.txt b/lib/utils/CMakeLists.txt new file mode 100644 index 00000000000..e0e1673f445 --- /dev/null +++ b/lib/utils/CMakeLists.txt @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_BASE64 base64.c) + +zephyr_sources( + dec.c + hex.c + rb.c + timeutil.c + bitarray.c + ) + +zephyr_sources_ifdef(CONFIG_ONOFF onoff.c) +zephyr_sources_ifdef(CONFIG_NOTIFY notify.c) + +zephyr_sources_ifdef(CONFIG_JSON_LIBRARY json.c) + +zephyr_sources_ifdef(CONFIG_RING_BUFFER ring_buffer.c) + +zephyr_sources_ifdef(CONFIG_UTF8 utf8.c) + +zephyr_sources_ifdef(CONFIG_WINSTREAM winstream.c) + +zephyr_library_include_directories( + ${ZEPHYR_BASE}/kernel/include + ${ZEPHYR_BASE}/arch/${ARCH}/include +) diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig new file mode 100644 index 00000000000..340c0ac42c2 --- /dev/null +++ b/lib/utils/Kconfig @@ -0,0 +1,60 @@ +# Copyright (c) 2016 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menu "Utility Library" + +config JSON_LIBRARY + bool "Build JSON library" + help + Build a minimal JSON parsing/encoding library. Used by sample + applications such as the NATS client. + +config RING_BUFFER + bool "Ring buffers" + help + Enable usage of ring buffers. This is similar to kernel FIFOs but ring + buffers manage their own buffer memory and can store arbitrary data. + For optimal performance, use buffer sizes that are a power of 2. + +config NOTIFY + bool "Asynchronous Notifications" + help + Use this API to support async transactions. + +config BASE64 + bool "Base64 encoding and decoding" + help + Enable base64 encoding and decoding functionality + +config ONOFF + bool "On-Off Manager" + select NOTIFY + help + An on-off manager supports an arbitrary number of clients of a + service which has a binary state. Example applications are power + rails, clocks, and binary device power management. + +config WINSTREAM + bool "Lockless shared memory window byte stream" + help + Winstream is a byte stream IPC for use in shared memory + "windows", generally for transmit to non-Zephyr contexts that + can't share Zephyr APIs or data structures. + +if WINSTREAM +config WINSTREAM_STDLIB_MEMCOPY + bool "Use standard memcpy() in winstream" + help + The sys_winstream utility is sometimes used in early boot + environments before the standard library is usable. By + default it uses a simple internal bytewise memcpy(). Set + this to use the one from the standard library. +endif + +config UTF8 + bool "UTF-8 string operation supported" + help + Enable the utf8 API. The API implements functions to specifically + handle UTF-8 encoded strings. + +endmenu diff --git a/lib/os/base64.c b/lib/utils/base64.c similarity index 100% rename from lib/os/base64.c rename to lib/utils/base64.c diff --git a/lib/os/bitarray.c b/lib/utils/bitarray.c similarity index 100% rename from lib/os/bitarray.c rename to lib/utils/bitarray.c diff --git a/lib/os/dec.c b/lib/utils/dec.c similarity index 100% rename from lib/os/dec.c rename to lib/utils/dec.c diff --git a/lib/os/hex.c b/lib/utils/hex.c similarity index 100% rename from lib/os/hex.c rename to lib/utils/hex.c diff --git a/lib/os/json.c b/lib/utils/json.c similarity index 100% rename from lib/os/json.c rename to lib/utils/json.c diff --git a/lib/os/notify.c b/lib/utils/notify.c similarity index 100% rename from lib/os/notify.c rename to lib/utils/notify.c diff --git a/lib/os/onoff.c b/lib/utils/onoff.c similarity index 100% rename from lib/os/onoff.c rename to lib/utils/onoff.c diff --git a/lib/os/rb.c b/lib/utils/rb.c similarity index 100% rename from lib/os/rb.c rename to lib/utils/rb.c diff --git a/lib/os/ring_buffer.c b/lib/utils/ring_buffer.c similarity index 100% rename from lib/os/ring_buffer.c rename to lib/utils/ring_buffer.c diff --git a/lib/os/timeutil.c b/lib/utils/timeutil.c similarity index 100% rename from lib/os/timeutil.c rename to lib/utils/timeutil.c diff --git a/lib/os/utf8.c b/lib/utils/utf8.c similarity index 100% rename from lib/os/utf8.c rename to lib/utils/utf8.c diff --git a/lib/os/winstream.c b/lib/utils/winstream.c similarity index 100% rename from lib/os/winstream.c rename to lib/utils/winstream.c diff --git a/modules/Kconfig b/modules/Kconfig index 0c1b240efec..94a3ccdf590 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -31,7 +31,6 @@ source "modules/Kconfig.nxp_s32" source "modules/Kconfig.silabs" source "modules/Kconfig.simplelink" source "modules/Kconfig.sof" -source "modules/Kconfig.st" source "modules/Kconfig.stm32" source "modules/Kconfig.syst" source "modules/Kconfig.telink" diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 4147d138de3..7ca374f4f32 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -55,4 +55,14 @@ config HAS_XMCLIB_WDT help Enable XMCLIB WDT +config HAS_XMCLIB_ETH + bool + help + Enable XMCLIB Ethernet MAC + +config HAS_XMCLIB_CAN + bool + help + Enable XMCLIB CAN + endif # HAS_XMCLIB diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index 8df4bde8829..a2e1803b138 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -103,13 +103,19 @@ config MCUBOOT_ENCRYPTION_KEY_FILE config MCUBOOT_IMGTOOL_SIGN_VERSION string "Version to pass to imgtool when signing" - default "$(VERSION_MAJOR).$(VERSION_MINOR).$(PATCHLEVEL)+$(VERSION_TWEAK)" if "$(VERSION_MAJOR)" != "" + default "$(APP_VERSION_TWEAK_STRING)" if "$(VERSION_MAJOR)" != "" default "0.0.0+0" help When signing with imgtool then this setting will be passed as version argument to the tool. The format is major.minor.revision+build. +config MCUBOOT_IMGTOOL_OVERWRITE_ONLY + bool "Use overwrite-only instead of swap upgrades" + help + If enabled, --overwrite-only option passed to imgtool to avoid + adding the swap status area size when calculating overflow. + config MCUBOOT_EXTRA_IMGTOOL_ARGS string "Extra arguments to pass to imgtool when signing" default "" @@ -148,6 +154,7 @@ choice MCUBOOT_BOOTLOADER_MODE config MCUBOOT_BOOTLOADER_MODE_SINGLE_APP bool "MCUboot has been configured for single slot execution" + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will only boot slot0_partition placed application and does not care about other slots. In this mode application is not able @@ -178,6 +185,7 @@ config MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH config MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY bool "MCUboot has been configured to just overwrite primary slot" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot will take contents of secondary slot of an image and will overwrite primary slot with it. @@ -191,6 +199,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP bool "MCUboot has been configured for DirectXIP operation" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot can boot from either partition and will @@ -206,6 +215,7 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT select MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY help MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode MCUboot will boot the application with the higher version @@ -221,6 +231,15 @@ config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT to downgrade running application, but note that MCUboot may do that if application with higher version will not get confirmed. +config MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER + bool "MCUboot has been configured in firmware updater mode" + select MCUBOOT_IMGTOOL_OVERWRITE_ONLY + help + MCUboot will only boot slot0_partition for the main application but has + an entrance mechanism defined for entering the slot1_partition which is + a dedicated firmware updater application used to update the slot0_partition + application. + endchoice # MCUBOOT_BOOTLOADER_MODE config MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE diff --git a/modules/Kconfig.nuvoton b/modules/Kconfig.nuvoton index 4413c29423e..bc4ac6d158f 100644 --- a/modules/Kconfig.nuvoton +++ b/modules/Kconfig.nuvoton @@ -67,4 +67,8 @@ menu "Nuvoton NuMaker drivers" bool "NuMaker CAN FD" help Enable Nuvoton CAN FD HAL module driver + config HAS_NUMAKER_ADC + bool "NuMaker ADC" + help + Enable Nuvoton ADC HAL module driver endmenu diff --git a/modules/Kconfig.st b/modules/Kconfig.st deleted file mode 100644 index fd90aee0b17..00000000000 --- a/modules/Kconfig.st +++ /dev/null @@ -1,190 +0,0 @@ -# STLIB config - -# Copyright (c) 2017 STMicroelectronics - -config HAS_STLIB - bool - -config HAS_STMEMSC - bool - -if HAS_STMEMSC - -config USE_STDC_A3G4250D - bool - -config USE_STDC_AIS2DW12 - bool - -config USE_STDC_AIS328DQ - bool - -config USE_STDC_AIS3624DQ - bool - -config USE_STDC_H3LIS100DL - bool - -config USE_STDC_H3LIS331DL - bool - -config USE_STDC_HTS221 - bool - -config USE_STDC_I3G4250D - bool - -config USE_STDC_IIS2DH - bool - -config USE_STDC_IIS2DLPC - bool - -config USE_STDC_IIS2ICLX - bool - -config USE_STDC_IIS2MDC - bool - -config USE_STDC_IIS328DQ - bool - -config USE_STDC_IIS3DHHC - bool - -config USE_STDC_IIS3DWB - bool - -config USE_STDC_ILPS22QS - bool - -config USE_STDC_ISM303DAC - bool - -config USE_STDC_ISM330DHCX - bool - -config USE_STDC_ISM330DLC - bool - -config USE_STDC_L20G20IS - bool - -config USE_STDC_L3GD20H - bool - -config USE_STDC_LIS25BA - bool - -config USE_STDC_LIS2DE12 - bool - -config USE_STDC_LIS2DH12 - bool - -config USE_STDC_LIS2DS12 - bool - -config USE_STDC_LIS2DTW12 - bool - -config USE_STDC_LIS2DW12 - bool - -config USE_STDC_LIS2HH12 - bool - -config USE_STDC_LIS2MDL - bool - -config USE_STDC_LIS331DLH - bool - -config USE_STDC_LIS3DE - bool - -config USE_STDC_LIS3DHH - bool - -config USE_STDC_LIS3DH - bool - -config USE_STDC_LIS3DSH - bool - -config USE_STDC_LIS3MDL - bool - -config USE_STDC_LPS22DF - bool - -config USE_STDC_LPS22HB - bool - -config USE_STDC_LPS22HH - bool - -config USE_STDC_LPS25HB - bool - -config USE_STDC_LPS27HHW - bool - -config USE_STDC_LPS33HW - bool - -config USE_STDC_LPS33K - bool - -config USE_STDC_LPS33W - bool - -config USE_STDC_LSM303AGR - bool - -config USE_STDC_LSM303AH - bool - -config USE_STDC_LSM6DS3 - bool - -config USE_STDC_LSM6DS3TR - bool - -config USE_STDC_LSM6DSL - bool - -config USE_STDC_LSM6DSM - bool - -config USE_STDC_LSM6DSO - bool - -config USE_STDC_LSM6DSO16IS - bool - -config USE_STDC_LSM6DSO32 - bool - -config USE_STDC_LSM6DSOX - bool - -config USE_STDC_LSM6DSR - bool - -config USE_STDC_LSM6DSRX - bool - -config USE_STDC_LSM6DSV16X - bool - -config USE_STDC_LSM9DS1 - bool - -config USE_STDC_STTS22H - bool - -config USE_STDC_STTS751 - bool - -endif # HAS_STMEMSC diff --git a/modules/Kconfig.stm32 b/modules/Kconfig.stm32 index ad598f63006..57749a8ec6b 100644 --- a/modules/Kconfig.stm32 +++ b/modules/Kconfig.stm32 @@ -447,6 +447,11 @@ config USE_STM32_HAL_RAMECC help Enable STM32Cube RAM ECC monitoring (RAMECC) HAL module driver +config USE_STM32_HAL_RAMCFG + bool + help + Enable STM32Cube RAM config (RAMCFG) HAL module driver + config USE_STM32_HAL_RNG bool help diff --git a/modules/canopennode/CO_driver.c b/modules/canopennode/CO_driver.c index e8892e080f5..4d161a49400 100644 --- a/modules/canopennode/CO_driver.c +++ b/modules/canopennode/CO_driver.c @@ -96,6 +96,11 @@ static void canopen_rx_callback(const struct device *dev, struct can_frame *fram } if (((frame->id ^ buffer->ident) & buffer->mask) == 0U) { +#ifdef CONFIG_CAN_ACCEPT_RTR + if (buffer->rtr && ((frame->flags & CAN_FRAME_RTR) == 0U)) { + continue; + } +#endif /* CONFIG_CAN_ACCEPT_RTR */ rxMsg.ident = frame->id; rxMsg.DLC = frame->dlc; memcpy(rxMsg.data, frame->data, frame->dlc); @@ -310,7 +315,18 @@ CO_ReturnError_t CO_CANrxBufferInit(CO_CANmodule_t *CANmodule, uint16_t index, buffer->ident = ident; buffer->mask = mask; - filter.flags = (rtr ? CAN_FILTER_RTR : CAN_FILTER_DATA); +#ifndef CONFIG_CAN_ACCEPT_RTR + if (rtr) { + LOG_ERR("request for RTR frames, but RTR frames are rejected"); + CO_errorReport(CANmodule->em, CO_EM_GENERIC_SOFTWARE_ERROR, + CO_EMC_SOFTWARE_INTERNAL, 0); + return CO_ERROR_ILLEGAL_ARGUMENT; + } +#else /* !CONFIG_CAN_ACCEPT_RTR */ + buffer->rtr = rtr; +#endif /* CONFIG_CAN_ACCEPT_RTR */ + + filter.flags = 0U; filter.id = ident; filter.mask = mask; diff --git a/modules/canopennode/CO_driver_target.h b/modules/canopennode/CO_driver_target.h index 27b1f1caa9d..5dba56ef800 100644 --- a/modules/canopennode/CO_driver_target.h +++ b/modules/canopennode/CO_driver_target.h @@ -69,6 +69,9 @@ typedef struct canopen_rx { CO_CANrxBufferCallback_t pFunct; uint16_t ident; uint16_t mask; +#ifdef CONFIG_CAN_ACCEPT_RTR + bool rtr; +#endif /* CONFIG_CAN_ACCEPT_RTR */ } CO_CANrx_t; typedef struct canopen_tx { diff --git a/modules/cmsis-dsp/CMakeLists.txt b/modules/cmsis-dsp/CMakeLists.txt index 9afaa32b89d..b4f2b8edd00 100644 --- a/modules/cmsis-dsp/CMakeLists.txt +++ b/modules/cmsis-dsp/CMakeLists.txt @@ -52,112 +52,115 @@ if(CONFIG_CMSIS_DSP) zephyr_compile_definitions_ifndef(CONFIG_ARM __GNUC_PYTHON__) # BasicMathFunctions + if(CONFIG_CMSIS_DSP_BASICMATH) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f64.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f64.c + ) - set(SRCF64 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f64.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f64.c - ) - - set(SRCF32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f32.c - ) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f32.c + ) - set(SRCF16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f16.c - ) + set(SRCF16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_f16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_f16.c + ) - set(SRCQ31 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q31.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q31.c - ) + set(SRCQ31 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q31.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q31.c + ) - set(SRCQ15 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q15.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q15.c - ) + set(SRCQ15 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q15.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q15.c + ) - set(SRCQ7 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q7.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q7.c - ) + set(SRCQ7 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_abs_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_add_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_clip_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_dot_prod_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_mult_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_negate_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_offset_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_scale_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_shift_q7.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_sub_q7.c + ) - set(SRCU32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u32.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u32.c - ) + set(SRCU32 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u32.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u32.c + ) - set(SRCU16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u16.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u16.c - ) + set(SRCU16 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u16.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u16.c + ) - set(SRCU8 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u8.c - ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u8.c) + set(SRCU8 ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_and_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_or_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_not_u8.c + ${CMSIS_DSP_DIR}/Source/BasicMathFunctions/arm_xor_u8.c) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${SRCF16}) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${SRCF16}) + endif() - zephyr_library_sources(${SRCQ31}) - zephyr_library_sources(${SRCQ15}) - zephyr_library_sources(${SRCQ7}) + zephyr_library_sources(${SRCQ31}) + zephyr_library_sources(${SRCQ15}) + zephyr_library_sources(${SRCQ7}) - zephyr_library_sources(${SRCU32}) - zephyr_library_sources(${SRCU16}) - zephyr_library_sources(${SRCU8}) + zephyr_library_sources(${SRCU32}) + zephyr_library_sources(${SRCU16}) + zephyr_library_sources(${SRCU8}) + endif() # BayesFunctions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c) + if (CONFIG_CMSIS_DSP_BAYES) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f32.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f16.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/BayesFunctions/arm_gaussian_naive_bayes_predict_f16.c) + endif() endif() # Common Tables @@ -193,739 +196,762 @@ if(CONFIG_CMSIS_DSP) # MVE code is using a table for computing the fast sqrt arm_cmplx_mag_q31 # There is the possibility of not compiling this function and not including # the table. - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_fast_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f16.c) + if (CONFIG_CMSIS_DSP_COMPLEXMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_fast_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_q31.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_conj_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_dot_prod_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mag_squared_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_cmplx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ComplexMathFunctions/arm_cmplx_mult_real_f16.c) + endif() endif() # Controller Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q31.c) + if (CONFIG_CMSIS_DSP_CONTROLLER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_pid_reset_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/ControllerFunctions/arm_sin_cos_q31.c) + endif() # Distance Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_boolean_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dice_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_hamming_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jaccard_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_kulsinski_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_rogerstanimoto_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_russellrao_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalmichener_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalsneath_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_yule_distance.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_distance_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_path_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_init_window_q7.c) - - - zephyr_library_include_directories("${CMSIS_DSP_DIR}/Source/DistanceFunctions") - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f16.c) + if (CONFIG_CMSIS_DSP_DISTANCE) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_boolean_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dice_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_hamming_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jaccard_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_kulsinski_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_rogerstanimoto_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_russellrao_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalmichener_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_sokalsneath_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_yule_distance.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_distance_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_path_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_dtw_init_window_q7.c) + + + zephyr_library_include_directories("${CMSIS_DSP_DIR}/Source/DistanceFunctions") + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_braycurtis_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_canberra_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_chebyshev_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cityblock_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_correlation_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_cosine_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_euclidean_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_jensenshannon_distance_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/DistanceFunctions/arm_minkowski_distance_f16.c) + endif() endif() # Fast Math Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_f32.c) + if (CONFIG_CMSIS_DSP_FASTMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_cos_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sin_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_sqrt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_q15.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vinverse_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vlog_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vexp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_vinverse_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_divide_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FastMathFunctions/arm_atan2_q15.c) + endif() # Filtering Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_q31.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f16.c) + if (CONFIG_CMSIS_DSP_FILTERING) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_32x64_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_partial_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_conv_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_opt_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_decimate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_fast_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_interpolate_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_lattice_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_init_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_sparse_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_iir_lattice_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_norm_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_lms_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_q31.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_fir_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df1_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_df2T_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_biquad_cascade_stereo_df2T_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_correlate_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/FilteringFunctions/arm_levinson_durbin_f16.c) + endif() endif() # Interpolation Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_init_f32.c) - - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f16.c) + if (CONFIG_CMSIS_DSP_INTERPOLATION) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_spline_interp_init_f32.c) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_bilinear_interp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/InterpolationFunctions/arm_linear_interp_f16.c) + endif() endif() # Matrix Functions - set(SRCF64 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f64.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f64.c - ) + if (CONFIG_CMSIS_DSP_MATRIX) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f64.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f64.c + ) - set(SRCF32 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f32.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f32.c - ) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_ldlt_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f32.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f32.c + ) - set(SRCQ31 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_opt_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q31.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q31.c - ) + set(SRCQ31 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_opt_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q31.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q31.c + ) - set(SRCQ15 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q15.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q15.c - ) + set(SRCQ15 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_fast_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q15.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q15.c + ) - set(SRCQ7 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q7.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q7.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q7.c - ) + set(SRCQ7 ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_q7.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_q7.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_q7.c + ) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) - - zephyr_library_sources(${SRCQ31}) - zephyr_library_sources(${SRCQ15}) - zephyr_library_sources(${SRCQ7}) - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f16.c - ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f16.c - ) + zephyr_library_sources(${SRCQ31}) + zephyr_library_sources(${SRCQ15}) + zephyr_library_sources(${SRCQ7}) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_add_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cholesky_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_cmplx_trans_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_init_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_inverse_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_scale_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_lower_triangular_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_solve_upper_triangular_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_sub_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_trans_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_vec_mult_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_mat_qr_f16.c + ${CMSIS_DSP_DIR}/Source/MatrixFunctions/arm_householder_f16.c + ) + endif() endif() # Quaternion Math Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_norm_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_inverse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_conjugate_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_normalize_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_single_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion2rotation_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_rotation2quaternion_f32.c) + if (CONFIG_CMSIS_DSP_QUATERNIONMATH) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_norm_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_inverse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_conjugate_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_normalize_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_single_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion_product_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_quaternion2rotation_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/QuaternionMathFunctions/arm_rotation2quaternion_f32.c) + endif() # Statistics Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q7.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q7.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f32.c) - - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f16.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f16.c) + if (CONFIG_CMSIS_DSP_STATISTICS) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_q7.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q7.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mse_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f32.c) + + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_mean_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_power_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_rms_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_std_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_var_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_entropy_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_kullback_leibler_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_dot_prod_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_logsumexp_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_max_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_min_no_idx_f16.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmax_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_absmin_no_idx_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/StatisticsFunctions/arm_accumulate_f16.c) + endif() endif() # Support Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bitonic_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bubble_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_heap_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_insertion_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_init_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q7.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_f64.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_float.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q15.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q31.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_quick_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_selection_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_init_f32.c - ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f32.c - ) + if (CONFIG_CMSIS_DSP_SUPPORT) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bitonic_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_bubble_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_heap_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_insertion_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_merge_sort_init_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q31_to_q7.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_f64.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_float.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q15.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q7_to_q31.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_quick_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_selection_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_sort_init_f32.c + ${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f32.c + ) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_f16.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_copy_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_fill_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_q15_to_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_float_to_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_float.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_weighted_sum_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_barycenter_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f16_to_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SupportFunctions/arm_f64_to_f16.c) + endif() endif() # SVM Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f32.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f16.c) + if (CONFIG_CMSIS_DSP_SVM) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f32.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_linear_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_rbf_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_polynomial_predict_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/SVMFunctions/arm_svm_sigmoid_predict_f16.c) + endif() endif() # Transform Functions - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal2.c) + if (CONFIG_CMSIS_DSP_TRANSFORM) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal2.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_bitreversal_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) - endif() + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f64.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) - - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f64.c) - - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f16.c) - endif() + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f16.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f64.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) - if (WRAPPER) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q31.c) - endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_dct4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f64.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f64.c) - # For scipy or wrappers or benchmarks - if (WRAPPER) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f32.c) if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_fast_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix8_f16.c) endif() - endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f32.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q15.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_rfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_q31.c) + + if (WRAPPER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_q31.c) + endif() - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix4_init_q31.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q15.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q15.c) - if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f16.c) - zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f16.c) + # For scipy or wrappers or benchmarks + if (WRAPPER) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f32.c) + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_cfft_radix2_init_f16.c) + endif() + endif() + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f32.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f32.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q31.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q31.c) + + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_q15.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_q15.c) + + if ((NOT ARMAC5) AND (NOT DISABLEFLOAT16)) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_init_f16.c) + zephyr_library_sources(${CMSIS_DSP_DIR}/Source/TransformFunctions/arm_mfcc_f16.c) + endif() endif() # Window Functions - set(SRCF64 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f64.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f64.c - ) - - set(SRCF32 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f32.c - ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f32.c - ) + if (CONFIG_CMSIS_DSP_WINDOW) + set(SRCF64 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f64.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f64.c + ) - zephyr_library_sources(${SRCF64}) - zephyr_library_sources(${SRCF32}) + set(SRCF32 ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_welch_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_bartlett_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hamming_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hanning_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3a_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall3b_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4a_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_blackman_harris_92db_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4b_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_nuttall4c_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft90d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft95_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft116d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft144d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft169d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft196d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft223d_f32.c + ${CMSIS_DSP_DIR}/Source/WindowFunctions/arm_hft248d_f32.c + ) + zephyr_library_sources(${SRCF64}) + zephyr_library_sources(${SRCF32}) + endif() endif() diff --git a/modules/cmsis-dsp/Kconfig b/modules/cmsis-dsp/Kconfig index 2159f1f6c2e..b25e77ce9c7 100644 --- a/modules/cmsis-dsp/Kconfig +++ b/modules/cmsis-dsp/Kconfig @@ -11,6 +11,250 @@ menuconfig CMSIS_DSP if CMSIS_DSP +comment "Components" +config CMSIS_DSP_BASICMATH + bool "Basic Math Functions" + help + This option enables the Basic Math Functions, which support the + following operations: + + * Elementwise Clipping + * Vector Absolute Value + * Vector Addition + * Vector Subtraction + * Vector Multiplication + * Vector Dot Product + * Vector Absolute Value + * Vector Negate + * Vector Offset + * Vector Scale + * Vector Shift + * Vector Bitwise AND + * Vector Bitwise OR + * Vector Bitwise Exclusive OR + * Vector Bitwise NOT + +config CMSIS_DSP_COMPLEXMATH + bool "Complex Math Functions" + imply CMSIS_DSP_FASTMATH + help + This option enables the Complex Math Functions, which support the + following operations: + + * Complex-by-Complex Multiplication + * Complex-by-Real Multiplication + * Complex Dot Product + * Complex Magnitude + * Complex Magnitude Squared + * Complex Conjugate + +config CMSIS_DSP_CONTROLLER + bool "Controller Functions" + help + This option enables the Controller Functions, which support the + following operations: + + * PID Control + * Vector Clarke Transform + * Vector Inverse Clarke Transform + * Vector Park Transform + * Vector Inverse Park Transform + * Sine-Cosine + + These functions can be used to implement a generic PID controller, as + well as field oriented motor control using Space Vector Modulation + algorithm. + +config CMSIS_DSP_FASTMATH + bool "Fast Math Functions" + imply CMSIS_DSP_BASICMATH + help + This option enables the Fast Math Functions, which support the + following operations: + + * Fixed-Point Division + * Sine + * Cosine + * Square Root + +config CMSIS_DSP_FILTERING + bool "Filtering Functions" + imply CMSIS_DSP_BASICMATH + imply CMSIS_DSP_FASTMATH + imply CMSIS_DSP_SUPPORT + help + This option enables the Filtering Functions, which support the + following operations: + + * Convolution + * Partial Convolution + * Correlation + * Levinson-Durbin Algorithm + + The following filter types are supported: + + * FIR (finite impulse response) Filter + * FIR Lattice Filter + * FIR Sparse Filter + * FIR Filter with Decimator + * FIR Filter with Interpolator + * IIR (infinite impulse response) Lattice Filter + * Biquad Cascade IIR Filter, Direct Form I Structure + * Biquad Cascade IIR Filter, Direct Form II Transposed Structure + * High Precision Q31 Biquad Cascade Filter + * LMS (least mean square) Filter + * Normalized LMS Filter + +config CMSIS_DSP_INTERPOLATION + bool "Interpolation Functions" + help + This option enables the Interpolation Functions, which support the + following operations: + + * Bilinear Interpolation + * Linear Interpolation + * Cubic Spline Interpolation + +config CMSIS_DSP_MATRIX + bool "Matrix Functions" + help + This option enables the Matrix Functions, which support the following + operations: + + * Matrix Initialization + * Matrix Addition + * Matrix Subtraction + * Matrix Multiplication + * Complex Matrix Multiplication + * Matrix Vector Multiplication + * Matrix Inverse + * Matrix Scale + * Matrix Transpose + * Complex Matrix Transpose + * Cholesky and LDLT Decompositions + +config CMSIS_DSP_QUATERNIONMATH + bool "Quaternion Math Functions" + help + This option enables the Quaternion Math Functions, which support the + following operations: + + * Quaternion Conversions + * Quaternion Conjugate + * Quaternion Inverse + * Quaternion Norm + * Quaternion Normalization + * Quaternion Product + +config CMSIS_DSP_STATISTICS + bool "Statistics Functions" + imply CMSIS_DSP_BASICMATH + imply CMSIS_DSP_FASTMATH + help + This option enables the Statistics Functions, which support the + following operations: + + * Minimum + * Absolute Minimum + * Maximum + * Absolute Maximum + * Mean + * Root Mean Square (RMS) + * Variance + * Standard Deviation + * Power + * Entropy + * Kullback-Leibler Divergence + * LogSumExp (LSE) + +config CMSIS_DSP_SUPPORT + bool "Support Functions" + help + This option enables the Support Functions, which support the + following operations: + + * Vector 8-bit Integer Value Conversion + * Vector 16-bit Integer Value Conversion + * Vector 32-bit Integer Value Conversion + * Vector 16-bit Floating-Point Value Conversion + * Vector 32-bit Floating-Point Value Conversion + * Vector Copy + * Vector Fill + * Vector Sorting + * Weighted Sum + * Barycenter + +config CMSIS_DSP_TRANSFORM + bool "Transform Functions" + imply CMSIS_DSP_BASICMATH + help + This option enables the Transform Functions, which support the + following transformations: + + * Real Fast Fourier Transform (RFFT) + * Complex Fast Fourier Transform (CFFT) + * Type IV Discrete Cosine Transform (DCT4) + +config CMSIS_DSP_SVM + bool "Support Vector Machine Functions" + help + This option enables the Support Vector Machine Functions, which + support the following algorithms: + + * Linear + * Polynomial + * Sigmoid + * Radial Basis Function (RBF) + +config CMSIS_DSP_BAYES + bool "Bayesian Estimators" + imply CMSIS_DSP_STATISTICS + help + This option enables the Bayesian Estimator Functions, which + implements the naive gaussian Bayes estimator. + +config CMSIS_DSP_DISTANCE + bool "Distance Functions" + imply CMSIS_DSP_STATISTICS + help + This option enables the Distance Functions, which support the + following distance computation algorithms: + + * Boolean Vectors + * Hamming + * Jaccard + * Kulsinski + * Rogers-Tanimoto + * Russell-Rao + * Sokal-Michener + * Sokal-Sneath + * Yule + * Dice + + * Floating-Point Vectors + * Canberra + * Chebyshev + * Cityblock + * Correlation + * Cosine + * Euclidean + * Jensen-Shannon + * Minkowski + * Bray-Curtis + +config CMSIS_DSP_WINDOW + bool "Windowing Functions" + help + This option enabled the Window Functions, which support the + following windowing functions: + + * Bartlett + * Hamming + * Hanning + * Nuttall + * Blackman Harris + * HFT + comment "Instruction Set" # NOTE: These configurations should eventually be derived from the arch ISA and # FP support configurations. diff --git a/modules/cmsis/Kconfig b/modules/cmsis/Kconfig index 4b5a8ee2855..eff0be6f40c 100644 --- a/modules/cmsis/Kconfig +++ b/modules/cmsis/Kconfig @@ -21,4 +21,11 @@ config HAS_CMSIS_CORE_R config HAS_CMSIS_CORE_M bool +config CMSIS_M_CHECK_DEVICE_DEFINES + bool "Check device defines" + default n + depends on HAS_CMSIS_CORE_M + help + This options enables the validation of CMSIS configuration flags. + endif diff --git a/modules/cmsis/cmsis_core.h b/modules/cmsis/cmsis_core.h index 04e5566cc0a..4f57c682138 100644 --- a/modules/cmsis/cmsis_core.h +++ b/modules/cmsis/cmsis_core.h @@ -12,4 +12,4 @@ #include "cmsis_core_a_r.h" #endif -#endif /* ZEPHYR_INCLUDE_ARCH_ARM_AARCH32_CORTEX_M_CMSIS_H_ */ +#endif /* ZEPHYR_MODULES_CMSIS_CMSIS_H_ */ diff --git a/modules/cmsis/cmsis_core_m.h b/modules/cmsis/cmsis_core_m.h index 880ff614b5b..e7382633945 100644 --- a/modules/cmsis/cmsis_core_m.h +++ b/modules/cmsis/cmsis_core_m.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2023 Arm Limited * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,95 +15,57 @@ #ifndef ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ #define ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ +#if defined(CONFIG_CMSIS_M_CHECK_DEVICE_DEFINES) && CONFIG_CMSIS_M_CHECK_DEVICE_DEFINES == 1U +#define __CHECK_DEVICE_DEFINES 1U +#endif + #include #include -#ifdef __cplusplus -extern "C" { +#if __NVIC_PRIO_BITS != NUM_IRQ_PRIO_BITS +#error "NUM_IRQ_PRIO_BITS and __NVIC_PRIO_BITS are not set to the same value" +#endif + +#if __MPU_PRESENT != CONFIG_CPU_HAS_ARM_MPU +#error "__MPU_PRESENT and CONFIG_CPU_HAS_ARM_MPU are not set to the same value" +#endif + +#if __FPU_PRESENT != CONFIG_CPU_HAS_FPU +#error "__FPU_PRESENT and CONFIG_CPU_HAS_FPU are not set to the same value" #endif -/* Fill in CMSIS required values for non-CMSIS compliant SoCs. - * Use __NVIC_PRIO_BITS as it is required and simple to check, but - * ultimately all SoCs will define their own CMSIS types and constants. + +/* VTOR is only optional on armv6-m and armv8-m baseline. __VTOR_PRESENT is often + * left undefined on platform where it is not optional. */ -#ifndef __NVIC_PRIO_BITS -typedef enum { - Reset_IRQn = -15, - NonMaskableInt_IRQn = -14, - HardFault_IRQn = -13, -#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) - MemoryManagement_IRQn = -12, - BusFault_IRQn = -11, - UsageFault_IRQn = -10, -#if defined(CONFIG_ARM_SECURE_FIRMWARE) - SecureFault_IRQn = -9, -#endif /* CONFIG_ARM_SECURE_FIRMWARE */ -#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ - SVCall_IRQn = -5, - DebugMonitor_IRQn = -4, - PendSV_IRQn = -2, - SysTick_IRQn = -1, - Max_IRQn = CONFIG_NUM_IRQS, -} IRQn_Type; - -#if defined(CONFIG_CPU_CORTEX_M0) -#define __CM0_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M0PLUS) -#define __CM0PLUS_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M1) -#define __CM1_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M3) -#define __CM3_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M4) -#define __CM4_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M7) -#define __CM7_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M23) -#define __CM23_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M33) -#define __CM33_REV 0 -#elif defined(CONFIG_CPU_CORTEX_M55) -#define __CM55_REV 0 -#else -#error "Unknown Cortex-M device" +#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && \ + (__VTOR_PRESENT != CONFIG_CPU_CORTEX_M_HAS_VTOR) +#error "__VTOR_PRESENT and CONFIG_CPU_CORTEX_M_HAS_VTOR are not set to the same value." #endif -#ifndef __MPU_PRESENT -#define __MPU_PRESENT 0U +/* Some platform’s sdk incorrectly define __DSP_PRESENT for Cortex-M4 & Cortex-M7 + * DSP extension. __ARM_FEATURE_DSP is set by the compiler for these. So ignore + * __DSP_PRESENT discrepancy when __ARM_FEATURE_DSP is defined. + */ +#if !defined(__ARM_FEATURE_DSP) && (__DSP_PRESENT != CONFIG_ARMV8_M_DSP) +#error "__DSP_PRESENT and CONFIG_ARMV8_M_DSP are not set to the same value" #endif -#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS -#define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ -#endif /* __NVIC_PRIO_BITS */ -#if __NVIC_PRIO_BITS != NUM_IRQ_PRIO_BITS -#error "NUM_IRQ_PRIO_BITS and __NVIC_PRIO_BITS are not set to the same value" +#if __ICACHE_PRESENT != CONFIG_CPU_HAS_ICACHE +#error "__ICACHE_PRESENT and CONFIG_CPU_HAS_ICACHE are not set to the same value" +#endif + +#if __DCACHE_PRESENT != CONFIG_CPU_HAS_DCACHE +#error "__DCACHE_PRESENT and CONFIG_CPU_HAS_DCACHE are not set to the same value" #endif -#ifdef __cplusplus -} +#if __MVE_PRESENT != CONFIG_ARMV8_1_M_MVEI +#error "__MVE_PRESENT and CONFIG_ARMV8_1_M_MVEI are not set to the same value" #endif -#if defined(CONFIG_CPU_CORTEX_M0) -#include -#elif defined(CONFIG_CPU_CORTEX_M0PLUS) -#include -#elif defined(CONFIG_CPU_CORTEX_M1) -#include -#elif defined(CONFIG_CPU_CORTEX_M3) -#include -#elif defined(CONFIG_CPU_CORTEX_M4) -#include -#elif defined(CONFIG_CPU_CORTEX_M7) -#include -#elif defined(CONFIG_CPU_CORTEX_M23) -#include -#elif defined(CONFIG_CPU_CORTEX_M33) -#include -#elif defined(CONFIG_CPU_CORTEX_M55) -#include -#else -#error "Unknown Cortex-M device" +#if __SAUREGION_PRESENT != CONFIG_CPU_HAS_ARM_SAU +#error "__SAUREGION_PRESENT and CONFIG_CPU_HAS_ARM_SAU are not set to the same value" #endif #endif /* ZEPHYR_MODULES_CMSIS_CMSIS_M_H_ */ diff --git a/modules/cmsis/cmsis_core_m_defaults.h b/modules/cmsis/cmsis_core_m_defaults.h new file mode 100644 index 00000000000..bef62665493 --- /dev/null +++ b/modules/cmsis/cmsis_core_m_defaults.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2023 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief CMSIS interface file + * + * This header populates the default values required to configure the + * ARM CMSIS Core headers. + */ + +#ifndef ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ +#define ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Fill in CMSIS required values for non-CMSIS compliant SoCs. + * Use __NVIC_PRIO_BITS as it is required and simple to check, but + * ultimately all SoCs will define their own CMSIS types and constants. + */ +#ifndef __NVIC_PRIO_BITS +typedef enum { + Reset_IRQn = -15, + NonMaskableInt_IRQn = -14, + HardFault_IRQn = -13, +#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) + MemoryManagement_IRQn = -12, + BusFault_IRQn = -11, + UsageFault_IRQn = -10, +#if defined(CONFIG_ARM_SECURE_FIRMWARE) + SecureFault_IRQn = -9, +#endif /* CONFIG_ARM_SECURE_FIRMWARE */ +#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ + SVCall_IRQn = -5, + DebugMonitor_IRQn = -4, + PendSV_IRQn = -2, + SysTick_IRQn = -1, + Max_IRQn = CONFIG_NUM_IRQS, +} IRQn_Type; + +#if defined(CONFIG_CPU_CORTEX_M0) +#define __CM0_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M0PLUS) +#define __CM0PLUS_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M1) +#define __CM1_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M3) +#define __CM3_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M4) +#define __CM4_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M7) +#define __CM7_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M23) +#define __CM23_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M33) +#define __CM33_REV 0 +#elif defined(CONFIG_CPU_CORTEX_M55) +#define __CM55_REV 0 +#else +#error "Unknown Cortex-M device" +#endif + +#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS +#define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ +#endif /* __NVIC_PRIO_BITS */ + +#ifndef __MPU_PRESENT +#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#endif + +#ifndef __FPU_PRESENT +#define __FPU_PRESENT CONFIG_CPU_HAS_FPU +#endif + +#ifndef __FPU_DP +#define __FPU_DP CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION +#endif + +#ifndef __VTOR_PRESENT +#define __VTOR_PRESENT CONFIG_CPU_CORTEX_M_HAS_VTOR +#endif + +#ifndef __DSP_PRESENT +#define __DSP_PRESENT CONFIG_ARMV8_M_DSP +#endif + +#ifndef __ICACHE_PRESENT +#define __ICACHE_PRESENT CONFIG_CPU_HAS_ICACHE +#endif + +#ifndef __DCACHE_PRESENT +#define __DCACHE_PRESENT CONFIG_CPU_HAS_DCACHE +#endif + +#ifndef __MVE_PRESENT +#define __MVE_PRESENT CONFIG_ARMV8_1_M_MVEI +#endif + +#ifndef __SAUREGION_PRESENT +#define __SAUREGION_PRESENT CONFIG_CPU_HAS_ARM_SAU +#endif + +#ifndef __PMU_PRESENT +#define __PMU_PRESENT CONFIG_ARMV8_1_M_PMU +#define __PMU_NUM_EVENTCNT CONFIG_ARMV8_1_M_PMU_EVENTCNT +#endif + +#ifdef __cplusplus +} +#endif + +#if defined(CONFIG_CPU_CORTEX_M0) +#include +#elif defined(CONFIG_CPU_CORTEX_M0PLUS) +#include +#elif defined(CONFIG_CPU_CORTEX_M1) +#include +#elif defined(CONFIG_CPU_CORTEX_M3) +#include +#elif defined(CONFIG_CPU_CORTEX_M4) +#include +#elif defined(CONFIG_CPU_CORTEX_M7) +#include +#elif defined(CONFIG_CPU_CORTEX_M23) +#include +#elif defined(CONFIG_CPU_CORTEX_M33) +#include +#elif defined(CONFIG_CPU_CORTEX_M55) +#include +#else +#error "Unknown Cortex-M device" +#endif + +#endif /* ZEPHYR_MODULES_CMSIS_CMSIS_M_DEFAULTS_H_ */ diff --git a/modules/hal_ethos_u/Kconfig b/modules/hal_ethos_u/Kconfig index bfed9b94d82..ddb2d0a8ed6 100644 --- a/modules/hal_ethos_u/Kconfig +++ b/modules/hal_ethos_u/Kconfig @@ -9,10 +9,10 @@ config ARM_ETHOS_U help This option enables the Arm Ethos-U core driver. +if ARM_ETHOS_U menu "Arm Ethos-U NPU configuration" choice ARM_ETHOS_U_NPU_CONFIG prompt "Arm Ethos-U NPU configuration" - depends on ARM_ETHOS_U default ARM_ETHOS_U55_128 config ARM_ETHOS_U55_64 bool "using Ethos-U55 with 64 macs" @@ -69,3 +69,5 @@ config ARM_ETHOS_U_LOG_LEVEL default 2 if ARM_ETHOS_U_LOG_LEVEL_WRN default 3 if ARM_ETHOS_U_LOG_LEVEL_INF default 4 if ARM_ETHOS_U_LOG_LEVEL_DBG + +endif diff --git a/modules/hal_gigadevice/CMakeLists.txt b/modules/hal_gigadevice/CMakeLists.txt index 7a4096bc4d2..3b887f654a9 100644 --- a/modules/hal_gigadevice/CMakeLists.txt +++ b/modules/hal_gigadevice/CMakeLists.txt @@ -6,9 +6,9 @@ if(CONFIG_HAS_GD32_HAL) string(TOUPPER ${CONFIG_SOC} gd32_soc_uc) set(gd32_soc_dir ${ZEPHYR_HAL_GIGADEVICE_MODULE_DIR}/${CONFIG_SOC_SERIES}) -if(CONFIG_SOC_FAMILY_GD32_ARM) +if(CONFIG_ARM) set(gd32_soc_sys_dir ${gd32_soc_dir}/cmsis/gd/${CONFIG_SOC_SERIES}) -elseif(CONFIG_SOC_SERIES_GD32VF103) +elseif(CONFIG_RISCV) set(gd32_soc_sys_dir ${gd32_soc_dir}/riscv) zephyr_include_directories(${gd32_soc_dir}/riscv/drivers) endif() diff --git a/modules/hal_gigadevice/Kconfig b/modules/hal_gigadevice/Kconfig index 66132779eb1..84f6532b251 100644 --- a/modules/hal_gigadevice/Kconfig +++ b/modules/hal_gigadevice/Kconfig @@ -16,7 +16,7 @@ config GD32_HAS_AFIO_PINMUX config HAS_GD32_HAL bool - select HAS_CMSIS_CORE if SOC_FAMILY_GD32_ARM + select HAS_CMSIS_CORE if ARM if HAS_GD32_HAL diff --git a/modules/hal_nordic/CMakeLists.txt b/modules/hal_nordic/CMakeLists.txt index 693400aba76..6f5364ac8de 100644 --- a/modules/hal_nordic/CMakeLists.txt +++ b/modules/hal_nordic/CMakeLists.txt @@ -6,3 +6,19 @@ if (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) endif (CONFIG_NRF_802154_RADIO_DRIVER OR CONFIG_NRF_802154_SERIALIZATION) add_subdirectory_ifdef(CONFIG_HAS_NRFX nrfx) + +if(CONFIG_NRF_REGTOOL_GENERATE_UICR) + list(APPEND nrf_regtool_components GENERATE:UICR) +endif() +if(DEFINED nrf_regtool_components) + find_package(nrf-regtool 5.0.1 + COMPONENTS ${nrf_regtool_components} + PATHS ${CMAKE_CURRENT_LIST_DIR}/nrf-regtool + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_SYSTEM_PACKAGE_REGISTRY + ) +endif() diff --git a/modules/hal_nordic/Kconfig b/modules/hal_nordic/Kconfig index 6f77bbea427..c9cc93e9329 100644 --- a/modules/hal_nordic/Kconfig +++ b/modules/hal_nordic/Kconfig @@ -236,3 +236,4 @@ endif # NRF_802154_RADIO_DRIVER || NRF_802154_SERIALIZATION endmenu # HAS_NORDIC_DRIVERS rsource "nrfx/Kconfig" +rsource "Kconfig.nrf_regtool" diff --git a/modules/hal_nordic/Kconfig.nrf_regtool b/modules/hal_nordic/Kconfig.nrf_regtool new file mode 100644 index 00000000000..81659bcf0bb --- /dev/null +++ b/modules/hal_nordic/Kconfig.nrf_regtool @@ -0,0 +1,36 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "nrf-regtool options" + depends on SOC_SERIES_NRF54HX + +config NRF_REGTOOL_GENERATE_UICR + bool "Generate UICR" + help + Generate a UICR hex based on devicetree contents using nrf-regtool. + CPU domains that require UICR allocation aren't bootable without it + being programmed alongside the firmware. + +config NRF_REGTOOL_VERBOSITY + int "Verbosity level of console output" + range 0 3 + default 0 + help + Level of verbose output that nrf-regtool will print to the console. + + 0. Only critical information and warnings. + 1. Print a pretty, human-readable representation of a peripheral's + configuration. This is recommended for inspecting register values. + 2. Print extra details for debugging purposes, such as memory maps of + the peripheral configurations, but in a less readable format. + 3. Print even more details, which are typically only useful for + nrf-regtool developers. + +config NRF_REGTOOL_EXTRA_GENERATE_ARGS + string "Extra arguments to 'nrf-regtool generate'" + help + List of additional arguments to every nrf-regtool invocation used for + generating hex files. Example value: "--fill all --fill-byte 0xff". + Run "nrf-regtool generate -h" to see all of the available options. + +endmenu diff --git a/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake new file mode 100644 index 00000000000..d057c735e3f --- /dev/null +++ b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfig.cmake @@ -0,0 +1,48 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +function(nrf_regtool_generate_hex_from_dts peripheral) + string(TOLOWER "${peripheral}.hex" generated_hex_name) + string(TOLOWER "${peripheral}_merged.hex" merged_hex_name) + + # Prepare common argument sub-lists. + string(REPEAT "-v;" ${CONFIG_NRF_REGTOOL_VERBOSITY} verbosity) + list(TRANSFORM CACHED_DTS_ROOT_BINDINGS PREPEND "--bindings-dir;" OUTPUT_VARIABLE bindings_dirs) + separate_arguments(extra_args UNIX_COMMAND "${CONFIG_NRF_REGTOOL_EXTRA_GENERATE_ARGS}") + + set(generated_hex_file ${PROJECT_BINARY_DIR}/${generated_hex_name}) + execute_process( + COMMAND ${NRF_REGTOOL} ${verbosity} generate + --peripheral ${peripheral} + --svd-file ${SOC_SVD_FILE} + --dts-file ${ZEPHYR_DTS} + ${bindings_dirs} + --output-file ${generated_hex_file} + ${extra_args} + WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR} + COMMAND_ERROR_IS_FATAL ANY + ) + message(STATUS "Generated ${peripheral} hex file: ${generated_hex_file}") + + set(merged_hex_file ${PROJECT_BINARY_DIR}/${merged_hex_name}) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/build/mergehex.py + -o ${merged_hex_file} + ${generated_hex_file} + ${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME} + ) + set_property(TARGET runners_yaml_props_target PROPERTY hex_file ${merged_hex_file}) +endfunction() + + +foreach(component IN LISTS ${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS) + string(REGEX MATCH "(^.*):(.*$)" match ${component}) + set(operation "${CMAKE_MATCH_1}") + set(peripheral "${CMAKE_MATCH_2}") + + if(operation STREQUAL "GENERATE") + nrf_regtool_generate_hex_from_dts(${peripheral}) + else() + message(FATAL_ERROR "Unrecognized package component: \"${component}\"") + endif() +endforeach() diff --git a/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake new file mode 100644 index 00000000000..e147d1b0532 --- /dev/null +++ b/modules/hal_nordic/nrf-regtool/nrf-regtoolConfigVersion.cmake @@ -0,0 +1,32 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +find_program(NRF_REGTOOL nrf-regtool) + +if(NRF_REGTOOL) + execute_process( + COMMAND ${NRF_REGTOOL} --version + OUTPUT_VARIABLE version + RESULT_VARIABLE result + ) + + if(result EQUAL 0 AND version MATCHES "version ([0-9]+[.][0-9]+[.][0-9]+)") + set(PACKAGE_VERSION ${CMAKE_MATCH_1}) + if(PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + + message(STATUS + "Found nrf-regtool (found suitable version \"${PACKAGE_VERSION}\", " + "minimum required is \"${PACKAGE_FIND_VERSION}\")" + ) + return() + endif() + endif() +endif() + +# We only get here if we don't pass the version check. +set(PACKAGE_VERSION_UNSUITABLE TRUE) +set(NRF_REGTOOL NRF_REGTOOL-NOTFOUND CACHE INTERNAL "Path to a program") diff --git a/modules/hal_nordic/nrf_802154/CMakeLists.txt b/modules/hal_nordic/nrf_802154/CMakeLists.txt index 763f9625be8..30c4c237a04 100644 --- a/modules/hal_nordic/nrf_802154/CMakeLists.txt +++ b/modules/hal_nordic/nrf_802154/CMakeLists.txt @@ -93,8 +93,6 @@ else() target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_CARRIER_FUNCTIONS_ENABLED=0) endif() -target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_ENERGY_DETECTED_VERSION=1) - if (CONFIG_NRF_802154_ASSERT_ZEPHYR OR CONFIG_NRF_802154_ASSERT_ZEPHYR_MINIMAL) target_include_directories(zephyr-802154-interface INTERFACE include) target_compile_definitions(zephyr-802154-interface INTERFACE NRF_802154_PLATFORM_ASSERT_INCLUDE=\"nrf_802154_assert_zephyr.h\") diff --git a/modules/hal_nordic/nrfx/CMakeLists.txt b/modules/hal_nordic/nrfx/CMakeLists.txt index 69afbcc9c51..5a97c7ba44b 100644 --- a/modules/hal_nordic/nrfx/CMakeLists.txt +++ b/modules/hal_nordic/nrfx/CMakeLists.txt @@ -3,7 +3,12 @@ zephyr_library() -set(NRFX_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfx CACHE PATH "nrfx Directory") +# The nrfx source directory can be override through the definition of the NRFX_DIR symbol +# during the invocation of the build system +if(NOT DEFINED NRFX_DIR) + set(NRFX_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/nrfx CACHE PATH "nrfx Directory") +endif() + set(INC_DIR ${NRFX_DIR}/drivers/include) set(SRC_DIR ${NRFX_DIR}/drivers/src) set(MDK_DIR ${NRFX_DIR}/mdk) @@ -31,9 +36,18 @@ zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF5340_CPUAPP NRF5340_XXAA_APP zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP NRF5340_XXAA_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF5340_CPUNET NRF5340_XXAA_NETWORK) zephyr_compile_definitions_ifdef(CONFIG_SOC_COMPATIBLE_NRF5340_CPUNET NRF5340_XXAA_NETWORK) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54L15_ENGA NRF54L15_ENGA_XXAA) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54L15_ENGA_CPUAPP NRF_APPLICATION) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9120 NRF9120_XXAA) zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF9160 NRF9160_XXAA) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP NRF54H20_ENGA_XXAA + NRF_APPLICATION) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD NRF54H20_ENGA_XXAA + NRF_RADIOCORE) +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUPPR NRF54H20_ENGA_XXAA + NRF_PPR) + zephyr_compile_definitions_ifdef(CONFIG_NRF_APPROTECT_LOCK ENABLE_APPROTECT) zephyr_compile_definitions_ifdef(CONFIG_NRF_APPROTECT_USER_HANDLING @@ -64,6 +78,8 @@ zephyr_library_sources_ifdef(CONFIG_SOC_NRF52833 ${MDK_DIR}/system_nrf5283 zephyr_library_sources_ifdef(CONFIG_SOC_NRF52840 ${MDK_DIR}/system_nrf52840.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP ${MDK_DIR}/system_nrf5340_application.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUNET ${MDK_DIR}/system_nrf5340_network.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF54HX ${MDK_DIR}/system_nrf54h.c) +zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF54LX ${MDK_DIR}/system_nrf54l.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_NRF91X ${MDK_DIR}/system_nrf91.c) zephyr_library_sources(nrfx_glue.c) @@ -79,6 +95,7 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_COMP ${SRC_DIR}/nrfx_comp.c) zephyr_library_sources_ifdef(CONFIG_NRFX_DPPI ${SRC_DIR}/nrfx_dppi.c) zephyr_library_sources_ifdef(CONFIG_NRFX_EGU ${SRC_DIR}/nrfx_egu.c) zephyr_library_sources_ifdef(CONFIG_NRFX_GPIOTE ${SRC_DIR}/nrfx_gpiote.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_GRTC ${SRC_DIR}/nrfx_grtc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_I2S ${SRC_DIR}/nrfx_i2s.c) zephyr_library_sources_ifdef(CONFIG_NRFX_IPC ${SRC_DIR}/nrfx_ipc.c) zephyr_library_sources_ifdef(CONFIG_NRFX_LPCOMP ${SRC_DIR}/nrfx_lpcomp.c) @@ -111,6 +128,10 @@ if(CONFIG_NRFX_TWI OR CONFIG_NRFX_TWIM) zephyr_library_sources(${SRC_DIR}/nrfx_twi_twim.c) endif() +if (CONFIG_NRF_GRTC_TIMER AND CONFIG_NRF_GRTC_TIMER_CLOCK_MANAGEMENT) + zephyr_library_compile_definitions(NRF_GRTC_HAS_EXTENDED=1) +endif() + # Inject HAL "CONFIG_NFCT_PINS_AS_GPIOS" definition if user requests to # configure the NFCT pins as GPIOS. Do the same with "CONFIG_GPIO_AS_PINRESET" # to configure the reset GPIO as nRESET. This way, the HAL will take care of @@ -128,3 +149,38 @@ if(DEFINED uicr_path) zephyr_library_compile_definitions(CONFIG_GPIO_AS_PINRESET) endif() endif() + +if(CONFIG_SOC_NRF54L15) + dt_prop(clock_frequency PATH "/cpus/cpu@0" PROPERTY "clock-frequency") + math(EXPR clock_frequency_mhz "${clock_frequency} / 1000000") + zephyr_compile_definitions("NRF_CONFIG_CPU_FREQ_MHZ=${clock_frequency_mhz}") +endif() + +zephyr_compile_definitions_ifdef(CONFIG_SOC_NRF54LX_SKIP_CLOCK_CONFIG NRF_SKIP_CLOCK_CONFIGURATION) + +if(CONFIG_SOC_SERIES_NRF54LX AND CONFIG_NRFX_DPPI) + zephyr_library_sources(${HELPERS_DIR}/nrfx_gppi_dppi_ppib_lumos.c) +endif() + +# Get the SVD file for the current SoC +macro(mdk_svd_ifdef feature_toggle filename) + if(${feature_toggle}) + set(SOC_SVD_FILE ${MDK_DIR}/${filename} CACHE FILEPATH "Path to a CMSIS-SVD file") + endif() +endmacro() + +mdk_svd_ifdef(CONFIG_SOC_SERIES_NRF51X nrf51.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52805 nrf52805.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52810 nrf52810.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52811 nrf52811.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52820 nrf52820.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52832 nrf52.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52833 nrf52833.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF52840 nrf52840.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf5340_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF5340_CPUNET nrf5340_network.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUAPP nrf54h20_enga_application.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPUPPR nrf54h20_enga_ppr.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF54H20_ENGA_CPURAD nrf54h20_enga_radiocore.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF9120 nrf9120.svd) +mdk_svd_ifdef(CONFIG_SOC_NRF9160 nrf9160.svd) diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index 5dcda73c9be..ee1bd76b52f 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -63,8 +63,37 @@ config NRFX_EGU5 select NRFX_EGU config NRFX_GPIOTE - bool "GPIOTE driver" - depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + bool + +config NRFX_GPIOTE0 + bool "GPIOTE0 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote0,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE1 + bool "GPIOTE1 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote1,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE20 + bool "NRFX_GPIOTE20 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote20,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE30 + bool "NRFX_GPIOTE30 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote30,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE130 + bool "NRFX_GPIOTE130 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote130,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE + +config NRFX_GPIOTE131 + bool "NRFX_GPIOTE131 driver instance" + depends on $(dt_nodelabel_has_compat,gpiote131,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + select NRFX_GPIOTE config NRFX_GPIOTE_NUM_OF_EVT_HANDLERS int "Number of event handlers" @@ -74,6 +103,10 @@ config NRFX_GPIOTE_NUM_OF_EVT_HANDLERS Specifies number of handlers that can be registered to nrfx_gpiote driver by the user. +config NRFX_GRTC + bool "GRTC driver" + depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_GRTC)) + config NRFX_I2S bool @@ -389,6 +422,41 @@ config NRFX_TIMER4 depends on $(dt_nodelabel_has_compat,timer4,$(DT_COMPAT_NORDIC_NRF_TIMER)) select NRFX_TIMER +config NRFX_TIMER00 + bool "TIMER00 driver instance" + depends on $(dt_nodelabel_has_compat,timer00,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER10 + bool "TIMER10 driver instance" + depends on $(dt_nodelabel_has_compat,timer10,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER20 + bool "TIMER20 driver instance" + depends on $(dt_nodelabel_has_compat,timer20,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER21 + bool "TIMER21 driver instance" + depends on $(dt_nodelabel_has_compat,timer21,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER22 + bool "TIMER22 driver instance" + depends on $(dt_nodelabel_has_compat,timer22,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER23 + bool "TIMER23 driver instance" + depends on $(dt_nodelabel_has_compat,timer23,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + +config NRFX_TIMER24 + bool "TIMER24 driver instance" + depends on $(dt_nodelabel_has_compat,timer24,$(DT_COMPAT_NORDIC_NRF_TIMER)) + select NRFX_TIMER + config NRFX_TWI bool @@ -544,6 +612,97 @@ config NRFX_UARTE3 depends on $(dt_nodelabel_has_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) select NRFX_UARTE +config NRFX_UARTE00 + bool "UARTE00 driver instance" + depends on $(dt_nodelabel_has_compat,uart00,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE20 + bool "UARTE20 driver instance" + depends on $(dt_nodelabel_has_compat,uart20,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE21 + bool "UARTE21 driver instance" + depends on $(dt_nodelabel_has_compat,uart21,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE22 + bool "UARTE22 driver instance" + depends on $(dt_nodelabel_has_compat,uart22,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE30 + bool "UARTE30 driver instance" + depends on $(dt_nodelabel_has_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE120 + bool "UARTE120 driver instance" + depends on $(dt_nodelabel_has_compat,uart120,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE130 + bool "UARTE130 driver instance" + depends on $(dt_nodelabel_has_compat,uart130,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE131 + bool "UARTE131 driver instance" + depends on $(dt_nodelabel_has_compat,uart131,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE132 + bool "UARTE132 driver instance" + depends on $(dt_nodelabel_has_compat,uart132,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE133 + bool "UARTE133 driver instance" + depends on $(dt_nodelabel_has_compat,uart133,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE134 + bool "UARTE134 driver instance" + depends on $(dt_nodelabel_has_compat,uart134,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE135 + bool "UARTE135 driver instance" + depends on $(dt_nodelabel_has_compat,uart135,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE136 + bool "UARTE136 driver instance" + depends on $(dt_nodelabel_has_compat,uart136,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE137 + bool "UARTE137 driver instance" + depends on $(dt_nodelabel_has_compat,uart137,$(DT_COMPAT_NORDIC_NRF_UARTE)) + select NRFX_UARTE + +config NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG + bool "UARTE GPIO configuration support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG + bool "UARTE PSEL configuration support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_TX_LINK + bool "UARTE TX transfer linking support" + depends on NRFX_UARTE + +config NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + bool "UARTE RX caching support" + default y if $(dt_nodelabel_has_compat,ram3x,$(DT_COMPAT_MMIO_SRAM)) + depends on NRFX_UARTE + help + Feature might be enabled on platforms which has limitations regarding addresses + to which receiver can write data. If enabled then internal driver buffers + (cache buffers) are used for DMA transfers and data is copied to the user buffer. + config NRFX_USBREG bool "USBREG driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_USBREG)) @@ -561,6 +720,21 @@ config NRFX_WDT1 depends on $(dt_nodelabel_has_compat,wdt1,$(DT_COMPAT_NORDIC_NRF_WDT)) select NRFX_WDT +config NRFX_WDT30 + bool "WDT30 driver instance" + depends on $(dt_nodelabel_has_compat,wdt30,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + +config NRFX_WDT31 + bool "WDT31 driver instance" + depends on $(dt_nodelabel_has_compat,wdt31,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + +config NRFX_WDT130 + bool "WDT130 driver instance" + depends on $(dt_nodelabel_has_compat,wdt130,$(DT_COMPAT_NORDIC_NRF_WDT)) + select NRFX_WDT + menu "Peripheral Resource Sharing module" config NRFX_PRS diff --git a/modules/hal_nordic/nrfx/Kconfig.logging b/modules/hal_nordic/nrfx/Kconfig.logging index 7f7b785e70c..b24d683d3de 100644 --- a/modules/hal_nordic/nrfx/Kconfig.logging +++ b/modules/hal_nordic/nrfx/Kconfig.logging @@ -28,6 +28,10 @@ config NRFX_GPIOTE_LOG bool "GPIOTE driver logging" depends on NRFX_GPIOTE +config NRFX_GRTC_LOG + bool "GRTC driver logging" + depends on NRFX_GRTC + config NRFX_I2S_LOG bool "I2S driver logging" depends on NRFX_I2S diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index b5b09b96078..26d662be39d 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -9,12 +9,6 @@ #include -/* - * NRFX API version 2.10 flag. - * When the flag is set NRFX API is compatible with the newest NRFX release. - */ -#define NRFX_CONFIG_API_VER_2_10 1 - /* * These are mappings of Kconfig options enabling nrfx drivers and particular * peripheral instances to the corresponding symbols used inside of nrfx. @@ -115,17 +109,33 @@ #define NRFX_EGU5_ENABLED 1 #endif +#ifdef CONFIG_NRFX_GRTC +#define NRFX_GRTC_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GRTC_LOG +#define NRFX_GRTC_CONFIG_LOG_ENABLED 1 +#endif + #ifdef CONFIG_NRFX_GPIOTE #define NRFX_GPIOTE_ENABLED 1 -#if (defined(CONFIG_SOC_SERIES_NRF91X) || defined(CONFIG_SOC_SERIES_NRF53X)) \ - && defined(NRF_TRUSTZONE_NONSECURE) -#define NRFX_GPIOTE1_ENABLED 1 -#else +#endif +#ifdef CONFIG_NRFX_GPIOTE0 #define NRFX_GPIOTE0_ENABLED 1 #endif +#ifdef CONFIG_NRFX_GPIOTE1 +#define NRFX_GPIOTE1_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE20 +#define NRFX_GPIOTE20_ENABLED 1 #endif -#ifdef CONFIG_NRFX_GPIOTE_LOG -#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 1 +#ifdef CONFIG_NRFX_GPIOTE30 +#define NRFX_GPIOTE30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE130 +#define NRFX_GPIOTE130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_GPIOTE131 +#define NRFX_GPIOTE131_ENABLED 1 #endif #ifdef CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS @@ -441,6 +451,27 @@ #ifdef CONFIG_NRFX_TIMER4 #define NRFX_TIMER4_ENABLED 1 #endif +#ifdef CONFIG_NRFX_TIMER00 +#define NRFX_TIMER00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER10 +#define NRFX_TIMER10_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER20 +#define NRFX_TIMER20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER21 +#define NRFX_TIMER21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER22 +#define NRFX_TIMER22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER23 +#define NRFX_TIMER23_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_TIMER24 +#define NRFX_TIMER24_ENABLED 1 +#endif #ifdef CONFIG_NRFX_TWI #define NRFX_TWI_ENABLED 1 @@ -560,6 +591,60 @@ #ifdef CONFIG_NRFX_UARTE3 #define NRFX_UARTE3_ENABLED 1 #endif +#ifdef CONFIG_NRFX_UARTE00 +#define NRFX_UARTE00_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE20 +#define NRFX_UARTE20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE21 +#define NRFX_UARTE21_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE22 +#define NRFX_UARTE22_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE30 +#define NRFX_UARTE30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE120 +#define NRFX_UARTE120_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE130 +#define NRFX_UARTE130_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE131 +#define NRFX_UARTE131_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE132 +#define NRFX_UARTE132_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE133 +#define NRFX_UARTE133_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE134 +#define NRFX_UARTE134_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE135 +#define NRFX_UARTE135_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE136 +#define NRFX_UARTE136_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE137 +#define NRFX_UARTE137_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif +#ifdef CONFIG_NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif #ifdef CONFIG_NRFX_USBREG #define NRFX_USBREG_ENABLED 1 @@ -580,6 +665,15 @@ #ifdef CONFIG_NRFX_WDT1 #define NRFX_WDT1_ENABLED 1 #endif +#ifdef CONFIG_NRFX_WDT30 +#define NRFX_WDT30_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_WDT31 +#define NRFX_WDT31_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_WDT130 +#define NRFX_WDT130_ENABLED 1 +#endif #ifdef CONFIG_NRF52_ANOMALY_109_WORKAROUND #define NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED 1 @@ -608,6 +702,27 @@ #define NRF_PERIPH(P) P##_S #endif +/* If the GRTC system timer driver is to be used, prepare definitions required + * by the nrfx_grtc driver (NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK and + * NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS) based on information from devicetree. + */ +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) +#define NRFX_CONFIG_BIT_DT(node_id, prop, idx) \ + BIT(DT_PROP_BY_IDX(node_id, prop, idx)) +#define NRFX_CONFIG_GRTC_MASK_DT(prop) \ + (COND_CODE_1(DT_NODE_HAS_PROP(DT_INST(0, nordic_nrf_grtc), prop), \ + (DT_FOREACH_PROP_ELEM_SEP(DT_INST(0, nordic_nrf_grtc), prop, \ + NRFX_CONFIG_BIT_DT, (|))), \ + (0))) + +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK \ + (NRFX_CONFIG_GRTC_MASK_DT(owned_channels) & \ + ~NRFX_CONFIG_GRTC_MASK_DT(child_owned_channels)) +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS \ + (DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), owned_channels, 0) - \ + DT_PROP_LEN_OR(DT_INST(0, nordic_nrf_grtc), child_owned_channels, 0)) +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_grtc) */ + #include #if defined(NRF51) #include @@ -629,8 +744,16 @@ #include #elif defined(NRF5340_XXAA_NETWORK) #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_APPLICATION) + #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_RADIOCORE) + #include +#elif defined(NRF54H20_ENGA_XXAA) && defined(NRF_PPR) + #include #elif defined(NRF9120_XXAA) || defined(NRF9160_XXAA) #include +#elif defined(NRF54L15_ENGA_XXAA) && defined(NRF_APPLICATION) + #include #else #error "Unknown device." #endif diff --git a/modules/hal_nordic/nrfx/nrfx_config_common.h b/modules/hal_nordic/nrfx/nrfx_config_common.h index 8c0a58713a0..88a1a8b95e8 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_common.h +++ b/modules/hal_nordic/nrfx/nrfx_config_common.h @@ -18,7 +18,7 @@ /** @brief Symbol specifying minor version of the nrfx API to be used. */ #ifndef NRFX_CONFIG_API_VER_MINOR -#define NRFX_CONFIG_API_VER_MINOR 0 +#define NRFX_CONFIG_API_VER_MINOR 3 #endif /** @brief Symbol specifying micro version of the nrfx API to be used. */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h index 4a42f92ca98..18bcc40b2ac 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h @@ -83,6 +83,7 @@ * between secure and non-secure mapping. */ #if defined(NRF_TRUSTZONE_NONSECURE) +#define NRF_GPIOTE NRF_GPIOTE1 #define NRF_GPIOTE1 NRF_GPIOTE1_NS #else #define NRF_CACHE NRF_CACHE_S @@ -91,20 +92,14 @@ #define NRF_CRYPTOCELL NRF_CRYPTOCELL_S #define NRF_CTI NRF_CTI_S #define NRF_FICR NRF_FICR_S +#define NRF_GPIOTE NRF_GPIOTE0 #define NRF_GPIOTE0 NRF_GPIOTE0_S +#define NRF_GPIOTE1 NRF_GPIOTE1_NS #define NRF_SPU NRF_SPU_S #define NRF_TAD NRF_TAD_S #define NRF_UICR NRF_UICR_S #endif -/* Fixups for the GPIOTE driver. */ -#if defined(NRF_TRUSTZONE_NONSECURE) -#define NRF_GPIOTE NRF_GPIOTE1 -#else -#define NRF_GPIOTE NRF_GPIOTE0 -#endif - - /** * @brief NRFX_DEFAULT_IRQ_PRIORITY * diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h new file mode 100644 index 00000000000..e6c79341b9a --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_application.h @@ -0,0 +1,1935 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 7 +#endif + +/** + * @brief NRFX_BELLBOARD_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD_ENABLED +#define NRFX_BELLBOARD_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_BELLBOARD0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD0_ENABLED +#define NRFX_BELLBOARD0_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD1_ENABLED +#define NRFX_BELLBOARD1_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD2_ENABLED +#define NRFX_BELLBOARD2_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD3_ENABLED +#define NRFX_BELLBOARD3_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000f +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 4 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_MVDMA_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_MVDMA_ENABLED +#define NRFX_MVDMA_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking + * of TX transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT010_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT010_ENABLED +#define NRFX_WDT010_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT011_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT011_ENABLED +#define NRFX_WDT011_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_APPLICATION_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h new file mode 100644 index 00000000000..369fe18a81f --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_ppr.h @@ -0,0 +1,1855 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 3 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000030 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 2 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000000c0 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for + * workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking of TX + * transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_VEVIF_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_VEVIF_ENABLED +#define NRFX_VEVIF_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 3. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_PPR_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h new file mode 100644 index 00000000000..7b9a1c4b733 --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54h20_enga_radiocore.h @@ -0,0 +1,2016 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ +#define NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + +/** + * @brief NRFX_DEFAULT_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_DEFAULT_IRQ_PRIORITY +#define NRFX_DEFAULT_IRQ_PRIORITY 7 +#endif + +/** + * @brief NRFX_BELLBOARD_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD_ENABLED +#define NRFX_BELLBOARD_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_BELLBOARD_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_BELLBOARD0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD0_ENABLED +#define NRFX_BELLBOARD0_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD1_ENABLED +#define NRFX_BELLBOARD1_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD2_ENABLED +#define NRFX_BELLBOARD2_ENABLED 0 +#endif + +/** + * @brief NRFX_BELLBOARD3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_BELLBOARD3_ENABLED +#define NRFX_BELLBOARD3_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI020_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI030_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000f0 +#endif + +/** + * @brief NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000001e +#endif + +/** + * @brief NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000020 +#endif + +/** + * @brief NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000040 +#endif + +/** + * @brief NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000081 +#endif + +/** + * @brief NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI020_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI030_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000f +#endif + +/** + * @brief NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI131_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000ff +#endif + +/** + * @brief NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI132_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI133_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000e1 +#endif + +/** + * @brief NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI134_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000df +#endif + +/** + * @brief NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI135_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000bf +#endif + +/** + * @brief NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_DPPI136_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000007e +#endif + +/** + * @brief NRFX_EGU_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_EGU_ENABLED +#define NRFX_EGU_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_EGU020_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_EGU020_ENABLED +#define NRFX_EGU020_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0. Maximum: 15. + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 1 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_GPIOTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GPIOTE130_ENABLED +#define NRFX_GPIOTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 4 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x00000f00 +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_GRTC_CONFIG_LOG_ENABLED +#define NRFX_GRTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GRTC_CONFIG_LOG_LEVEL +#define NRFX_GRTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_I2S130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S130_ENABLED +#define NRFX_I2S130_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_I2S131_ENABLED +#define NRFX_I2S131_ENABLED 0 +#endif + +/** + * @brief NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000030 +#endif + +/** + * @brief NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_PUB_CONFIG_ALLOWED_CHANNELS_MASK 0x0000000c +#endif + +/** + * @brief NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x000000c0 +#endif + +/** + * @brief NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT120_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0 +#endif + +/** + * @brief NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK + */ +#ifndef NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK +#define NRFX_IPCT130_SUB_CONFIG_ALLOWED_CHANNELS_MASK 0x00000003 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_MVDMA_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_MVDMA_ENABLED +#define NRFX_MVDMA_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID - Timer instance used for workarounds in the driver. + * + * Integer value. Minimum: 0. Maximum: 5. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_6_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_6_ENABLED +#define NRFX_PRS_BOX_6_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_7_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_7_ENABLED +#define NRFX_PRS_BOX_7_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_8_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_8_ENABLED +#define NRFX_PRS_BOX_8_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_9_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PRS_BOX_9_ENABLED +#define NRFX_PRS_BOX_9_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_PWM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM120_ENABLED +#define NRFX_PWM120_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM130_ENABLED +#define NRFX_PWM130_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM131_ENABLED +#define NRFX_PWM131_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM132_ENABLED +#define NRFX_PWM132_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_PWM133_ENABLED +#define NRFX_PWM133_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_QDEC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC130_ENABLED +#define NRFX_QDEC130_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_QDEC131_ENABLED +#define NRFX_QDEC131_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_RTC130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC130_ENABLED +#define NRFX_RTC130_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_RTC131_ENABLED +#define NRFX_RTC131_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIM120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM120_ENABLED +#define NRFX_SPIM120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM121_ENABLED +#define NRFX_SPIM121_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM130_ENABLED +#define NRFX_SPIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM131_ENABLED +#define NRFX_SPIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM132_ENABLED +#define NRFX_SPIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM133_ENABLED +#define NRFX_SPIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM134_ENABLED +#define NRFX_SPIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM135_ENABLED +#define NRFX_SPIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM136_ENABLED +#define NRFX_SPIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIM137_ENABLED +#define NRFX_SPIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_SPIS120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS120_ENABLED +#define NRFX_SPIS120_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS130_ENABLED +#define NRFX_SPIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS131_ENABLED +#define NRFX_SPIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS132_ENABLED +#define NRFX_SPIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS133_ENABLED +#define NRFX_SPIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS134_ENABLED +#define NRFX_SPIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS135_ENABLED +#define NRFX_SPIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS136_ENABLED +#define NRFX_SPIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SPIS137_ENABLED +#define NRFX_SPIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TEMP_CONFIG_LOG_ENABLED +#define NRFX_TEMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TEMP_CONFIG_LOG_LEVEL +#define NRFX_TEMP_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TIMER020_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER020_ENABLED +#define NRFX_TIMER020_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER021_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER021_ENABLED +#define NRFX_TIMER021_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER022_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER022_ENABLED +#define NRFX_TIMER022_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER120_ENABLED +#define NRFX_TIMER120_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER121_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER121_ENABLED +#define NRFX_TIMER121_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER130_ENABLED +#define NRFX_TIMER130_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER131_ENABLED +#define NRFX_TIMER131_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER132_ENABLED +#define NRFX_TIMER132_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER133_ENABLED +#define NRFX_TIMER133_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER134_ENABLED +#define NRFX_TIMER134_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER135_ENABLED +#define NRFX_TIMER135_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER136_ENABLED +#define NRFX_TIMER136_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TIMER137_ENABLED +#define NRFX_TIMER137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIM130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM130_ENABLED +#define NRFX_TWIM130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM131_ENABLED +#define NRFX_TWIM131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM132_ENABLED +#define NRFX_TWIM132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM133_ENABLED +#define NRFX_TWIM133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM134_ENABLED +#define NRFX_TWIM134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM135_ENABLED +#define NRFX_TWIM135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM136_ENABLED +#define NRFX_TWIM136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIM137_ENABLED +#define NRFX_TWIM137_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY - Assume that any instance + * would be initialized only once. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE - Remove support for synchronous mode. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_TWIS130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS130_ENABLED +#define NRFX_TWIS130_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS131_ENABLED +#define NRFX_TWIS131_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS132_ENABLED +#define NRFX_TWIS132_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS133_ENABLED +#define NRFX_TWIS133_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS134_ENABLED +#define NRFX_TWIS134_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS135_ENABLED +#define NRFX_TWIS135_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS136_ENABLED +#define NRFX_TWIS136_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_TWIS137_ENABLED +#define NRFX_TWIS137_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG - If enabled, support for + * configuring GPIO pins is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_GPIO_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG - If enabled, support for + * configuring PSEL registers is removed from the driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG +#define NRFX_UARTE_CONFIG_SKIP_PSEL_CONFIG 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_TX_LINK - If enabled, driver supports linking + * of TX transfers. + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_TX_LINK +#define NRFX_UARTE_CONFIG_TX_LINK 1 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_RX_CACHE_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_RX_CACHE_ENABLED +#define NRFX_UARTE_CONFIG_RX_CACHE_ENABLED 1 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_UARTE120_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE120_ENABLED +#define NRFX_UARTE120_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE130_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE130_ENABLED +#define NRFX_UARTE130_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE131_ENABLED +#define NRFX_UARTE131_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE132_ENABLED +#define NRFX_UARTE132_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE133_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE133_ENABLED +#define NRFX_UARTE133_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE134_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE134_ENABLED +#define NRFX_UARTE134_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE135_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE135_ENABLED +#define NRFX_UARTE135_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE136_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE136_ENABLED +#define NRFX_UARTE136_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE137_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_UARTE137_ENABLED +#define NRFX_UARTE137_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0. Maximum: 7. + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY NRFX_DEFAULT_IRQ_PRIORITY +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ - Remove WDT IRQ handling from WDT driver + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 3 +#endif + +/** + * @brief NRFX_WDT010_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT010_ENABLED +#define NRFX_WDT010_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT011_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT011_ENABLED +#define NRFX_WDT011_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT131_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT131_ENABLED +#define NRFX_WDT131_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT132_ENABLED + * + * Boolean. Accepted values: 0 and 1. + */ +#ifndef NRFX_WDT132_ENABLED +#define NRFX_WDT132_ENABLED 0 +#endif + +#endif /* NRFX_CONFIG_NRF54H20_ENGA_RADIOCORE_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h new file mode 100644 index 00000000000..a694a07955d --- /dev/null +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf54l15_enga_application.h @@ -0,0 +1,1522 @@ +/* + * Copyright (c) 2024, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef NRFX_CONFIG_NRF54L15_APPLICATION_H__ +#define NRFX_CONFIG_NRF54L15_APPLICATION_H__ + +#ifndef NRFX_CONFIG_H__ +#error "This file should not be included directly. Include nrfx_config.h instead." +#endif + +/** + * @brief NRFX_CLOCK_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_ENABLED +#define NRFX_CLOCK_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LF_SRC + * + * Integer value. + * Supported values: + * - RC = 0 + * - XTAL = 1 + * - Synth = 2 + */ +#ifndef NRFX_CLOCK_CONFIG_LF_SRC +#define NRFX_CLOCK_CONFIG_LF_SRC 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LF_CAL_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LF_CAL_ENABLED +#define NRFX_CLOCK_CONFIG_LF_CAL_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED +#define NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_CLOCK_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_CLOCK_CONFIG_LOG_ENABLED +#define NRFX_CLOCK_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_CLOCK_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_CLOCK_CONFIG_LOG_LEVEL +#define NRFX_CLOCK_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_COMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_COMP_ENABLED +#define NRFX_COMP_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_COMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_COMP_CONFIG_LOG_ENABLED +#define NRFX_COMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_COMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_COMP_CONFIG_LOG_LEVEL +#define NRFX_COMP_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_DPPI_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_ENABLED +#define NRFX_DPPI_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_ENABLED +#define NRFX_DPPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_DPPI_CONFIG_LOG_LEVEL + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_DPPI_CONFIG_LOG_LEVEL +#define NRFX_DPPI_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_EGU_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU_ENABLED +#define NRFX_EGU_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU10_ENABLED +#define NRFX_EGU10_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_EGU20_ENABLED +#define NRFX_EGU20_ENABLED 0 +#endif + +/** + * @brief NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_EGU_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_GPIOTE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GPIOTE_ENABLED +#define NRFX_GPIOTE_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS + * + * Integer value. Minimum: 0 Maximum: 15 + */ +#ifndef NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS +#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS 0 +#endif + +/** + * @brief NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_ENABLED +#define NRFX_GPIOTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_GPIOTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_GPIOTE_CONFIG_LOG_LEVEL +#define NRFX_GPIOTE_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_GRTC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GRTC_ENABLED +#define NRFX_GRTC_ENABLED 0 +#endif + +/** + * @brief NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + * + * Integer value. + */ +#ifndef NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS +#define NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS 11 +#endif + +/** + * @brief GRTC CC channels ownership mask. + */ +#ifndef NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK +#define NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK 0x000007ff +#endif + +/** + * @brief NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_GRTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_I2S_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_I2S_ENABLED +#define NRFX_I2S_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_I2S_CONFIG_LOG_ENABLED +#define NRFX_I2S_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_I2S_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_I2S_CONFIG_LOG_LEVEL +#define NRFX_I2S_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_LPCOMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_LPCOMP_ENABLED +#define NRFX_LPCOMP_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_LPCOMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_ENABLED +#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_LPCOMP_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_LPCOMP_CONFIG_LOG_LEVEL +#define NRFX_LPCOMP_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_NFCT_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_ENABLED +#define NRFX_NFCT_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_NFCT_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID +#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_NFCT_CONFIG_LOG_ENABLED +#define NRFX_NFCT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_NFCT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_NFCT_CONFIG_LOG_LEVEL +#define NRFX_NFCT_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_PDM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PDM_ENABLED +#define NRFX_PDM_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PDM_CONFIG_LOG_ENABLED +#define NRFX_PDM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PDM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PDM_CONFIG_LOG_LEVEL +#define NRFX_PDM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_POWER_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_POWER_ENABLED +#define NRFX_POWER_ENABLED 0 +#endif + +/** + * @brief NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_POWER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PRS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_ENABLED +#define NRFX_PRS_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_0_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_0_ENABLED +#define NRFX_PRS_BOX_0_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_1_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_1_ENABLED +#define NRFX_PRS_BOX_1_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_2_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_2_ENABLED +#define NRFX_PRS_BOX_2_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_3_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_3_ENABLED +#define NRFX_PRS_BOX_3_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_4_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_4_ENABLED +#define NRFX_PRS_BOX_4_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_BOX_5_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_BOX_5_ENABLED +#define NRFX_PRS_BOX_5_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PRS_CONFIG_LOG_ENABLED +#define NRFX_PRS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PRS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PRS_CONFIG_LOG_LEVEL +#define NRFX_PRS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_PWM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM_ENABLED +#define NRFX_PWM_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM20_ENABLED +#define NRFX_PWM20_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM21_ENABLED +#define NRFX_PWM21_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM22_ENABLED +#define NRFX_PWM22_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_PWM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PWM_CONFIG_LOG_ENABLED +#define NRFX_PWM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_PWM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_PWM_CONFIG_LOG_LEVEL +#define NRFX_PWM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_QDEC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC_ENABLED +#define NRFX_QDEC_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC20_ENABLED +#define NRFX_QDEC20_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC21_ENABLED +#define NRFX_QDEC21_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_QDEC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_QDEC_CONFIG_LOG_ENABLED +#define NRFX_QDEC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_QDEC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_QDEC_CONFIG_LOG_LEVEL +#define NRFX_QDEC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_RTC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC_ENABLED +#define NRFX_RTC_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC10_ENABLED +#define NRFX_RTC10_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC30_ENABLED +#define NRFX_RTC30_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_RTC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_RTC_CONFIG_LOG_ENABLED +#define NRFX_RTC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_RTC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_RTC_CONFIG_LOG_LEVEL +#define NRFX_RTC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SAADC_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SAADC_ENABLED +#define NRFX_SAADC_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SAADC_CONFIG_LOG_ENABLED +#define NRFX_SAADC_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SAADC_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SAADC_CONFIG_LOG_LEVEL +#define NRFX_SAADC_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPI_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI_ENABLED +#define NRFX_SPI_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI00_ENABLED +#define NRFX_SPI00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI20_ENABLED +#define NRFX_SPI20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI21_ENABLED +#define NRFX_SPI21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI22_ENABLED +#define NRFX_SPI22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI30_ENABLED +#define NRFX_SPI30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPI_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPI_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPI_CONFIG_LOG_ENABLED +#define NRFX_SPI_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPI_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPI_CONFIG_LOG_LEVEL +#define NRFX_SPI_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPIM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_ENABLED +#define NRFX_SPIM_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM00_ENABLED +#define NRFX_SPIM00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM20_ENABLED +#define NRFX_SPIM20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM21_ENABLED +#define NRFX_SPIM21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM22_ENABLED +#define NRFX_SPIM22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM30_ENABLED +#define NRFX_SPIM30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_EXTENDED_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_EXTENDED_ENABLED +#define NRFX_SPIM_EXTENDED_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIM_CONFIG_LOG_ENABLED +#define NRFX_SPIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIM_CONFIG_LOG_LEVEL +#define NRFX_SPIM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SPIS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS_ENABLED +#define NRFX_SPIS_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS00_ENABLED +#define NRFX_SPIS00_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS20_ENABLED +#define NRFX_SPIS20_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS21_ENABLED +#define NRFX_SPIS21_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS22_ENABLED +#define NRFX_SPIS22_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS30_ENABLED +#define NRFX_SPIS30_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_SPIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SPIS_CONFIG_LOG_ENABLED +#define NRFX_SPIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_SPIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_SPIS_CONFIG_LOG_LEVEL +#define NRFX_SPIS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_SYSTICK_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_SYSTICK_ENABLED +#define NRFX_SYSTICK_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TEMP_ENABLED +#define NRFX_TEMP_ENABLED 0 +#endif + +/** + * @brief NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TEMP_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TIMER_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER_ENABLED +#define NRFX_TIMER_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER10_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER10_ENABLED +#define NRFX_TIMER10_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER20_ENABLED +#define NRFX_TIMER20_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER21_ENABLED +#define NRFX_TIMER21_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER22_ENABLED +#define NRFX_TIMER22_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER23_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER23_ENABLED +#define NRFX_TIMER23_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER24_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER24_ENABLED +#define NRFX_TIMER24_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TIMER_CONFIG_LOG_ENABLED +#define NRFX_TIMER_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TIMER_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TIMER_CONFIG_LOG_LEVEL +#define NRFX_TIMER_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TWIM_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM_ENABLED +#define NRFX_TWIM_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM20_ENABLED +#define NRFX_TWIM20_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM21_ENABLED +#define NRFX_TWIM21_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM22_ENABLED +#define NRFX_TWIM22_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM30_ENABLED +#define NRFX_TWIM30_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIM_CONFIG_LOG_ENABLED +#define NRFX_TWIM_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIM_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIM_CONFIG_LOG_LEVEL +#define NRFX_TWIM_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_TWIS_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_ENABLED +#define NRFX_TWIS_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS00_ENABLED +#define NRFX_TWIS00_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS20_ENABLED +#define NRFX_TWIS20_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS21_ENABLED +#define NRFX_TWIS21_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS22_ENABLED +#define NRFX_TWIS22_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS30_ENABLED +#define NRFX_TWIS30_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY +#define NRFX_TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0 +#endif + +/** + * @brief NRFX_TWIS_NO_SYNC_MODE + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_NO_SYNC_MODE +#define NRFX_TWIS_NO_SYNC_MODE 0 +#endif + +/** + * @brief NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_TWIS_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_TWIS_CONFIG_LOG_ENABLED +#define NRFX_TWIS_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_TWIS_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_TWIS_CONFIG_LOG_LEVEL +#define NRFX_TWIS_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_UARTE_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE_ENABLED +#define NRFX_UARTE_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE00_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE00_ENABLED +#define NRFX_UARTE00_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE20_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE20_ENABLED +#define NRFX_UARTE20_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE21_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE21_ENABLED +#define NRFX_UARTE21_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE22_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE22_ENABLED +#define NRFX_UARTE22_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE30_ENABLED +#define NRFX_UARTE30_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_UARTE_CONFIG_LOG_ENABLED +#define NRFX_UARTE_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_UARTE_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_UARTE_CONFIG_LOG_LEVEL +#define NRFX_UARTE_CONFIG_LOG_LEVEL 0 +#endif + +/** + * @brief NRFX_WDT_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_ENABLED +#define NRFX_WDT_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT30_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT30_ENABLED +#define NRFX_WDT30_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT31_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT31_ENABLED +#define NRFX_WDT31_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_NO_IRQ + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_NO_IRQ +#define NRFX_WDT_CONFIG_NO_IRQ 0 +#endif + +/** + * @brief NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY + * + * Integer value. Minimum: 0 Maximum: 7 + */ +#ifndef NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY +#define NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_WDT_CONFIG_LOG_ENABLED +#define NRFX_WDT_CONFIG_LOG_ENABLED 0 +#endif + +/** + * @brief NRFX_WDT_CONFIG_LOG_LEVEL + * + * Integer value. + * Supported values: + * - Off = 0 + * - Error = 1 + * - Warning = 2 + * - Info = 3 + * - Debug = 4 + */ +#ifndef NRFX_WDT_CONFIG_LOG_LEVEL +#define NRFX_WDT_CONFIG_LOG_LEVEL 0 +#endif + +#endif /* NRFX_CONFIG_NRF54L15_APPLICATION_H__ */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h index 873be583a35..c6029a18628 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf91.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf91.h @@ -67,25 +67,21 @@ * between secure and non-secure mapping. */ #if defined(NRF_TRUSTZONE_NONSECURE) +#define NRF_GPIOTE NRF_GPIOTE1 #define NRF_GPIOTE1 NRF_GPIOTE1_NS #else #define NRF_CC_HOST_RGF NRF_CC_HOST_RGF_S #define NRF_CRYPTOCELL NRF_CRYPTOCELL_S #define NRF_CTRL_AP_PERI NRF_CTRL_AP_PERI_S #define NRF_FICR NRF_FICR_S +#define NRF_GPIOTE NRF_GPIOTE0 #define NRF_GPIOTE0 NRF_GPIOTE0_S +#define NRF_GPIOTE1 NRF_GPIOTE1_NS #define NRF_SPU NRF_SPU_S #define NRF_TAD NRF_TAD_S #define NRF_UICR NRF_UICR_S #endif -/* Fixups for the GPIOTE driver. */ -#if defined(NRF_TRUSTZONE_NONSECURE) -#define NRF_GPIOTE NRF_GPIOTE1 -#else -#define NRF_GPIOTE NRF_GPIOTE0 -#endif - /** * @brief NRFX_DEFAULT_IRQ_PRIORITY * diff --git a/modules/hal_nordic/nrfx/nrfx_glue.h b/modules/hal_nordic/nrfx/nrfx_glue.h index 2257ea879a3..0edda440112 100644 --- a/modules/hal_nordic/nrfx/nrfx_glue.h +++ b/modules/hal_nordic/nrfx/nrfx_glue.h @@ -7,6 +7,13 @@ #ifndef NRFX_GLUE_H__ #define NRFX_GLUE_H__ +#if defined(CONFIG_CPU_CORTEX_M) +/* Workaround for missing __ICACHE_PRESENT and __DCACHE_PRESENT symbols in MDK + * SoC definitions. To be removed when this is fixed. + */ +#include +#endif + #include #include #include @@ -35,6 +42,11 @@ extern "C" { #define NRFX_ASSERT(expression) __ASSERT_NO_MSG(expression) #endif +#if defined(CONFIG_RISCV) +/* included here due to dependency on NRFX_ASSERT definition */ +#include +#endif + /** * @brief Macro for placing a compile time assertion. * @@ -84,14 +96,22 @@ extern "C" { * * @param irq_number IRQ number. */ -#define NRFX_IRQ_PENDING_SET(irq_number) NVIC_SetPendingIRQ(irq_number) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_PENDING_SET(irq_number) nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_PENDING_SET(irq_number) NVIC_SetPendingIRQ(irq_number) +#endif /** * @brief Macro for clearing the pending status of a specific IRQ. * * @param irq_number IRQ number. */ -#define NRFX_IRQ_PENDING_CLEAR(irq_number) NVIC_ClearPendingIRQ(irq_number) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_PENDING_CLEAR(irq_number) nrf_vpr_clic_int_pending_clear(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_PENDING_CLEAR(irq_number) NVIC_ClearPendingIRQ(irq_number) +#endif /** * @brief Macro for checking the pending status of a specific IRQ. @@ -99,7 +119,11 @@ extern "C" { * @retval true If the IRQ is pending. * @retval false Otherwise. */ -#define NRFX_IRQ_IS_PENDING(irq_number) (NVIC_GetPendingIRQ(irq_number) == 1) +#if defined(CONFIG_RISCV) +#define NRFX_IRQ_IS_PENDING(irq_number) nrf_vpr_clic_int_pending_check(NRF_VPRCLIC, irq_number) +#else +#define NRFX_IRQ_IS_PENDING(irq_number) (NVIC_GetPendingIRQ(irq_number) == 1) +#endif /** @brief Macro for entering into a critical section. */ #define NRFX_CRITICAL_SECTION_ENTER() { unsigned int irq_lock_key = irq_lock(); diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index 3281528d73f..6474b18055e 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -82,8 +82,6 @@ if(CONFIG_HAS_RPI_PICO) zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_GPIO ${rp2_common_dir}/hardware_gpio/include) - zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_UART - ${rp2_common_dir}/hardware_uart/uart.c) zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_UART ${rp2_common_dir}/hardware_uart/include) diff --git a/modules/hal_st/Kconfig b/modules/hal_st/Kconfig new file mode 100644 index 00000000000..020dbdc5d35 --- /dev/null +++ b/modules/hal_st/Kconfig @@ -0,0 +1,198 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_HAL_ST_MODULE + bool + +config HAS_STLIB + bool + +config HAS_STMEMSC + bool + +if HAS_STMEMSC + +config USE_STDC_A3G4250D + bool + +config USE_STDC_AIS2DW12 + bool + +config USE_STDC_AIS328DQ + bool + +config USE_STDC_AIS3624DQ + bool + +config USE_STDC_H3LIS100DL + bool + +config USE_STDC_H3LIS331DL + bool + +config USE_STDC_HTS221 + bool + +config USE_STDC_I3G4250D + bool + +config USE_STDC_IIS2DH + bool + +config USE_STDC_IIS2DLPC + bool + +config USE_STDC_IIS2ICLX + bool + +config USE_STDC_IIS2MDC + bool + +config USE_STDC_IIS328DQ + bool + +config USE_STDC_IIS3DHHC + bool + +config USE_STDC_IIS3DWB + bool + +config USE_STDC_ILPS22QS + bool + +config USE_STDC_ISM303DAC + bool + +config USE_STDC_ISM330DHCX + bool + +config USE_STDC_ISM330DLC + bool + +config USE_STDC_L20G20IS + bool + +config USE_STDC_L3GD20H + bool + +config USE_STDC_LIS25BA + bool + +config USE_STDC_LIS2DE12 + bool + +config USE_STDC_LIS2DH12 + bool + +config USE_STDC_LIS2DS12 + bool + +config USE_STDC_LIS2DTW12 + bool + +config USE_STDC_LIS2DU12 + bool + +config USE_STDC_LIS2DW12 + bool + +config USE_STDC_LIS2HH12 + bool + +config USE_STDC_LIS2MDL + bool + +config USE_STDC_LIS331DLH + bool + +config USE_STDC_LIS3DE + bool + +config USE_STDC_LIS3DHH + bool + +config USE_STDC_LIS3DH + bool + +config USE_STDC_LIS3DSH + bool + +config USE_STDC_LIS3MDL + bool + +config USE_STDC_LPS22DF + bool + +config USE_STDC_LPS22HB + bool + +config USE_STDC_LPS22HH + bool + +config USE_STDC_LPS25HB + bool + +config USE_STDC_LPS27HHW + bool + +config USE_STDC_LPS28DFW + bool + +config USE_STDC_LPS33HW + bool + +config USE_STDC_LPS33K + bool + +config USE_STDC_LPS33W + bool + +config USE_STDC_LSM303AGR + bool + +config USE_STDC_LSM303AH + bool + +config USE_STDC_LSM6DS3 + bool + +config USE_STDC_LSM6DS3TR + bool + +config USE_STDC_LSM6DSL + bool + +config USE_STDC_LSM6DSM + bool + +config USE_STDC_LSM6DSO + bool + +config USE_STDC_LSM6DSO16IS + bool + +config USE_STDC_LSM6DSO32 + bool + +config USE_STDC_LSM6DSOX + bool + +config USE_STDC_LSM6DSR + bool + +config USE_STDC_LSM6DSRX + bool + +config USE_STDC_LSM6DSV16X + bool + +config USE_STDC_LSM9DS1 + bool + +config USE_STDC_STTS22H + bool + +config USE_STDC_STTS751 + bool + +endif # HAS_STMEMSC diff --git a/modules/hostap/CMakeLists.txt b/modules/hostap/CMakeLists.txt index ed6b8185873..b24320acec5 100644 --- a/modules/hostap/CMakeLists.txt +++ b/modules/hostap/CMakeLists.txt @@ -15,10 +15,6 @@ set(HOSTAP_SRC_BASE ${HOSTAP_BASE}/src) set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -lnosys") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMISSING_SYSCALL_NAMES") -zephyr_compile_definitions( - CONFIG_ZEPHYR -) - zephyr_include_directories( ${HOSTAP_BASE}/ ${WIFI_NM_WPA_SUPPLICANT_BASE}/ @@ -34,6 +30,11 @@ zephyr_library_compile_definitions( CONFIG_NO_RANDOM_POOL CONFIG_NO_WPA CONFIG_NO_PBKDF2 + CONFIG_SHA256 + CONFIG_CTRL_IFACE_ZEPHYR +# CONFIG_MBO +# CONFIG_WNM + CONFIG_SUITEB192 ) zephyr_library_include_directories( @@ -44,6 +45,14 @@ zephyr_library_include_directories( ${HOSTAP_BASE}/src ${ZEPHYR_BASE}/include ${ZEPHYR_BASE}/include/net + ) + +zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_NO_PBKDF2 +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_NO_DEBUG + CONFIG_NO_STDOUT_DEBUG ) zephyr_library_sources( @@ -64,6 +73,8 @@ zephyr_library_sources( ${HOSTAP_SRC_BASE}/utils/wpa_debug_zephyr.c ${HOSTAP_SRC_BASE}/crypto/crypto_none.c ${HOSTAP_SRC_BASE}/crypto/tls_none.c + ${HOSTAP_SRC_BASE}/l2_packet/l2_packet_zephyr.c + ${HOSTAP_SRC_BASE}/drivers/driver_zephyr.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/config.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/notify.c @@ -77,8 +88,279 @@ zephyr_library_sources( ${WIFI_NM_WPA_SUPPLICANT_BASE}/scan.c ${WIFI_NM_WPA_SUPPLICANT_BASE}/ctrl_iface.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/bss.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/sme.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_supplicant.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/events.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/robust_av.c +# ${WIFI_NM_WPA_SUPPLICANT_BASE}/mbo.c +# ${WIFI_NM_WPA_SUPPLICANT_BASE}/wnm_sta.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_cli_cmds.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/ctrl_iface_zephyr.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wpa_cli_zephyr.c + # Zephyr specific files (glue code) - # TBD + src/supp_main.c + src/supp_api.c + src/supp_events.c +) + +zephyr_library_sources_ifdef(CONFIG_WPA_CLI + src/wpa_cli.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_AP + ${WIFI_NM_WPA_SUPPLICANT_BASE}/ap.c + ${HOSTAP_SRC_BASE}/ap/ap_config.c + ${HOSTAP_SRC_BASE}/ap/ap_drv_ops.c + ${HOSTAP_SRC_BASE}/ap/ap_list.c + ${HOSTAP_SRC_BASE}/ap/ap_mlme.c + ${HOSTAP_SRC_BASE}/ap/authsrv.c + ${HOSTAP_SRC_BASE}/ap/beacon.c + ${HOSTAP_SRC_BASE}/ap/bss_load.c + ${HOSTAP_SRC_BASE}/ap/dfs.c + ${HOSTAP_SRC_BASE}/ap/drv_callbacks.c + ${HOSTAP_SRC_BASE}/ap/eap_user_db.c + ${HOSTAP_SRC_BASE}/ap/hostapd.c + ${HOSTAP_SRC_BASE}/ap/hw_features.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_auth.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_he.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_ht.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_shared.c + ${HOSTAP_SRC_BASE}/ap/ieee802_11_vht.c + ${HOSTAP_SRC_BASE}/ap/ieee802_1x.c + ${HOSTAP_SRC_BASE}/ap/neighbor_db.c + ${HOSTAP_SRC_BASE}/ap/p2p_hostapd.c + ${HOSTAP_SRC_BASE}/ap/pmksa_cache_auth.c + ${HOSTAP_SRC_BASE}/ap/preauth_auth.c + ${HOSTAP_SRC_BASE}/ap/rrm.c + ${HOSTAP_SRC_BASE}/ap/sta_info.c + ${HOSTAP_SRC_BASE}/ap/tkip_countermeasures.c + ${HOSTAP_SRC_BASE}/ap/utils.c + ${HOSTAP_SRC_BASE}/ap/wmm.c + + ${HOSTAP_SRC_BASE}/ap/wpa_auth.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_ie.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_ft.c + ${HOSTAP_SRC_BASE}/ap/wpa_auth_glue.c + + ${HOSTAP_SRC_BASE}/eap_common/eap_common.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_identity.c + ${HOSTAP_SRC_BASE}/eap_server/eap_server_methods.c + ${HOSTAP_SRC_BASE}/eapol_auth/eapol_auth_sm.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_AP + CONFIG_AP + CONFIG_NO_RADIUS + CONFIG_NO_VLAN + CONFIG_NO_ACCOUNTING + CONFIG_NEED_AP_MLME + CONFIG_IEEE80211AX + CONFIG_EAP_SERVER + CONFIG_EAP_SERVER_IDENTITY +) + + +zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${HOSTAP_SRC_BASE}/crypto/crypto_none.c + ${HOSTAP_SRC_BASE}/crypto/tls_none.c +) + +zephyr_library_compile_definitions_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_NO_WPA + CONFIG_CRYPTO_INTERNAL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + CONFIG_WEP +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${HOSTAP_SRC_BASE}/common/wpa_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c + ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c + +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c +# ${HOSTAP_SRC_BASE}/crypto/tls_mbedtls.c + ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c + ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c + ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c +) + + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 + ${HOSTAP_SRC_BASE}/common/sae.c + ${HOSTAP_SRC_BASE}/common/dragonfly.c + + ${HOSTAP_SRC_BASE}/crypto/dh_groups.c + ${HOSTAP_SRC_BASE}/crypto/sha256-kdf.c ) +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPA3 + CONFIG_SAE + CONFIG_ECC +) + +zephyr_library_include_directories_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO + ${CMAKE_SOURCE_DIR} +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/p2p_supplicant_sd.c + ${HOSTAP_SRC_BASE}/p2p/p2p.c + ${HOSTAP_SRC_BASE}/p2p/p2p_utils.c + ${HOSTAP_SRC_BASE}/p2p/p2p_parse.c + ${HOSTAP_SRC_BASE}/p2p/p2p_build.c + ${HOSTAP_SRC_BASE}/p2p/p2p_go_neg.c + ${HOSTAP_SRC_BASE}/p2p/p2p_sd.c + ${HOSTAP_SRC_BASE}/p2p/p2p_pd.c + ${HOSTAP_SRC_BASE}/p2p/p2p_invitation.c + ${HOSTAP_SRC_BASE}/p2p/p2p_dev_disc.c + ${HOSTAP_SRC_BASE}/p2p/p2p_group.c + ${HOSTAP_SRC_BASE}/ap/p2p_hostapd.c + ${HOSTAP_SRC_BASE}/common/gas.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/gas_query.c + ${WIFI_NM_WPA_SUPPLICANT_BASE}/offchannel.c +) +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS + ${WIFI_NM_WPA_SUPPLICANT_BASE}/wps_supplicant.c + ${HOSTAP_SRC_BASE}/utils/uuid.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_wsc.c + ${HOSTAP_SRC_BASE}/eap_common/eap_wsc_common.c + ${HOSTAP_SRC_BASE}/wps/wps.c + ${HOSTAP_SRC_BASE}/ap/wps_hostapd.c + ${HOSTAP_SRC_BASE}/wps/wps_common.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_parse.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_build.c + ${HOSTAP_SRC_BASE}/wps/wps_attr_process.c + ${HOSTAP_SRC_BASE}/wps/wps_dev_attr.c + ${HOSTAP_SRC_BASE}/wps/wps_enrollee.c + ${HOSTAP_SRC_BASE}/wps/wps_registrar.c + ${HOSTAP_SRC_BASE}/crypto/dh_groups.c + ${HOSTAP_SRC_BASE}/crypto/dh_group5.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_P2P + CONFIG_P2P + CONFIG_GAS + CONFIG_OFFCHANNEL +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_WPS + CONFIG_WPS + EAP_WSC +) + +zephyr_library_sources_ifndef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + ${HOSTAP_SRC_BASE}/common/wpa_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa.c + ${HOSTAP_SRC_BASE}/rsn_supp/preauth.c + ${HOSTAP_SRC_BASE}/rsn_supp/wpa_ie.c + +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-bignum.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls-ec.c +# ${HOSTAP_SRC_BASE}/crypto/crypto_mbedtls.c + ${HOSTAP_SRC_BASE}/crypto/aes-wrap.c + ${HOSTAP_SRC_BASE}/crypto/aes-unwrap.c + ${HOSTAP_SRC_BASE}/crypto/rc4.c + ${HOSTAP_SRC_BASE}/crypto/sha1-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-prf.c + ${HOSTAP_SRC_BASE}/crypto/sha384-prf.c +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + ${HOSTAP_SRC_BASE}/eap_peer/eap_tls.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_tls_common.c + + + ${HOSTAP_SRC_BASE}/eap_peer/eap_peap.c + ${HOSTAP_SRC_BASE}/eap_common/eap_peap_common.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_ttls.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_md5.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_mschapv2.c + ${HOSTAP_SRC_BASE}/eap_common/chap.c + ${HOSTAP_SRC_BASE}/eap_peer/mschapv2.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_leap.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_psk.c + ${HOSTAP_SRC_BASE}/eap_common/eap_psk_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_fast.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_fast_pac.c + ${HOSTAP_SRC_BASE}/eap_common/eap_fast_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_pax.c + ${HOSTAP_SRC_BASE}/eap_common/eap_pax_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_sake.c + ${HOSTAP_SRC_BASE}/eap_common/eap_sake_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_gpsk.c + ${HOSTAP_SRC_BASE}/eap_common/eap_gpsk_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_pwd.c + ${HOSTAP_SRC_BASE}/eap_common/eap_pwd_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_eke.c + ${HOSTAP_SRC_BASE}/eap_common/eap_eke_common.c + + ${HOSTAP_SRC_BASE}/eap_peer/eap_ikev2.c + ${HOSTAP_SRC_BASE}/eap_peer/ikev2.c + ${HOSTAP_SRC_BASE}/eap_common/eap_ikev2_common.c + ${HOSTAP_SRC_BASE}/eap_common/ikev2_common.c + + # common + ${HOSTAP_SRC_BASE}/crypto/sha384-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha256-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tlsprf.c + ${HOSTAP_SRC_BASE}/crypto/sha1-tprf.c + ${HOSTAP_SRC_BASE}/crypto/ms_funcs.c + ${HOSTAP_SRC_BASE}/crypto/aes-eax.c + # MD4 removed from MbedTLS + ${HOSTAP_SRC_BASE}/crypto/md4-internal + ${HOSTAP_SRC_BASE}/crypto/aes-encblock.c + +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + CONFIG_EAP_TLS + CONFIG_IEEE8021X_EAPOL + CONFIG_EAP_PEAP + CONFIG_EAP_TTLS + CONFIG_EAP_MD5 + CONFIG_EAP_MSCHAPv2 + CONFIG_EAP_LEAP + CONFIG_EAP_PSK + CONFIG_EAP_FAST + CONFIG_EAP_PAX + CONFIG_EAP_SAKE + CONFIG_EAP_GPSK + CONFIG_EAP_PWD + CONFIG_EAP_EKE + CONFIG_EAP_IKEv2 +) + +zephyr_library_sources_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL + ${HOSTAP_SRC_BASE}/eapol_supp/eapol_supp_sm.c + ${HOSTAP_SRC_BASE}/eap_peer/eap.c + ${HOSTAP_SRC_BASE}/eap_peer/eap_methods.c + ${HOSTAP_SRC_BASE}/eap_common/eap_common.c + ${HOSTAP_SRC_BASE}/rsn_supp/pmksa_cache.c +) + +zephyr_library_compile_definitions_ifdef(CONFIG_WIFI_NM_WPA_SUPPLICANT_EAPOL + CONFIG_IEEE8021X_EAPOL +) endif() diff --git a/modules/hostap/Kconfig b/modules/hostap/Kconfig index 5ff3c13a494..61e21bee34e 100644 --- a/modules/hostap/Kconfig +++ b/modules/hostap/Kconfig @@ -8,6 +8,8 @@ config WIFI_NM_WPA_SUPPLICANT bool "WPA Suplicant from hostap project [EXPERIMENTAL]" select POSIX_CLOCK + select POSIX_SIGNAL + select POSIX_API select NET_SOCKETS select NET_SOCKETS_PACKET select NET_SOCKETPAIR @@ -21,6 +23,14 @@ config WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE int "Stack size for wpa_supplicant thread" default 8192 +config WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE + int "Stack size for wpa_supplicant iface workqueue" + default 4096 + +config WIFI_NM_WPA_SUPPLICANT_WQ_PRIO + int "Thread priority of wpa_supplicant iface workqueue" + default 7 + # Currently we default POSIX_MAX_FDS to 16 in lib/posix/Kconfig # l2_packet - 1 # ctrl_iface - 2 * socketpairs = 4(local and global) @@ -51,6 +61,77 @@ config WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL if WIFI_NM_WPA_SUPPLICANT +config WIFI_NM_WPA_SUPPLICANT_WEP + bool "WEP (Legacy crypto) support" + +choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND + prompt "WPA supplicant crypto implementation" + default WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + default WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA if BUILD_WITH_TFM + default WIFI_NM_WPA_SUPPLICANT_CRYPTO if !BUILD_WITH_TFM + help + Select the crypto implementation to use for WPA supplicant. + +# To easily manage the crypto dependencies we separate the crypto +# implementations into two Kconfig options. One for the legacy crypto +# and one for the PSA crypto. +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_PSA + bool "PSA Crypto support for WiFi" + select WIFI_NM_WPA_SUPPLICANT_WEP + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO + bool "Legacy Crypto support for WiFi" + select WIFI_NM_WPA_SUPPLICANT_WEP + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + bool "No Crypto support for WiFi" + +endchoice + +config WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + bool "Enterprise Crypto support for WiFi" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config WIFI_NM_WPA_SUPPLICANT_WPA3 + bool "WPA3 support" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + default y + +config WIFI_NM_WPA_SUPPLICANT_AP + bool "AP mode support" + +config WIFI_NM_WPA_SUPPLICANT_WPS + bool "WPS support" + depends on !WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE + +config WIFI_NM_WPA_SUPPLICANT_P2P + bool "P2P mode support" + select WIFI_NM_WPA_SUPPLICANT_AP + select WIFI_NM_WPA_SUPPLICANT_WPS + +config WIFI_NM_WPA_SUPPLICANT_EAPOL + bool "EAPoL supplicant" + +config WIFI_NM_WPA_SUPPLICANT_CLI + bool "CLI support for wpa_supplicant" + default n + +config WIFI_NM_WPA_SUPPLICANT_BSS_MAX_IDLE_TIME + int "BSS max idle timeout in seconds" + range 0 64000 + default 300 + help + BSS max idle timeout is the period for which AP may keep a client + in associated state while there is no traffic from that particular + client. Set 0 to disable inclusion of BSS max idle time tag in + association request. If a non-zero value is set, STA can suggest a + timeout by including BSS max idle period in the association request. + AP may choose to consider or ignore the STA's preferred value. + Ref: Sec 11.21.13 of IEEE Std 802.11™-2020 + +config WIFI_NM_WPA_SUPPLICANT_NO_DEBUG + bool "Disable printing of debug messages, saves code size significantly" + # Create hidden config options that are used in hostap. This way we do not need # to mark them as allowed for CI checks, and also someone else cannot use the # same name options. @@ -71,20 +152,153 @@ config CTRL_IFACE bool default y +config CTRL_IFACE_ZEPHYR + bool + default y + config NO_RANDOM_POOL bool default y +config WNM + bool + config NO_WPA bool - default y + default y if WIFI_NM_WPA_SUPPLICANT_CRYPTO_NONE config NO_PBKDF2 bool default y -config ZEPHYR +config SAE_PK + bool + +config FST + bool + +config TESTING_OPTIONS + bool + +config AP + bool + +config NO_RADIUS + bool + +config NO_VLAN + bool + +config NO_ACCOUNTING + bool + +config NEED_AP_MLME + bool + +config IEEE80211AX + bool + +config EAP_SERVER + bool + +config EAP_SERVER_IDENTITY + bool + +config P2P + bool + +config GAS + bool + +config OFFCHANNEL + bool + +config WPS + bool + +config WSC + bool + +config EAP_TLS + bool + +config IEEE8021X_EAPOL + bool + +config EAP_PEAP + bool + +config EAP_TTLS + bool + +config EAP_MD5 + bool + +config EAP_MSCHAPv2 + bool + +config EAP_LEAP + bool + +config EAP_PSK + bool + +config EAP_FAST + bool + +config EAP_PAX + bool + +config EAP_SAKE + bool + +config EAP_GPSK + bool + +config EAP_PWD + bool + +config EAP_EKE + bool + +config EAP_IKEv2 + bool + +config IEEE8021X_EAPOL + bool + +config CRYPTO_INTERNAL + bool + +config ECC + bool + +config MBO + bool + +config NO_STDOUT_DEBUG + bool + +config SAE + bool + +config SHA256 + bool + +config SUITEB192 + bool + +config WEP + bool + default y if WIFI_NM_WPA_SUPPLICANT_WEP + +config WPA_CLI + bool + +config WPA_CRYPTO + bool + +config WPA_SUPP_CRYPTO bool - default y endif # WIFI_NM_WPA_SUPPLICANT diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c new file mode 100644 index 00000000000..3b78940a4f5 --- /dev/null +++ b/modules/hostap/src/supp_api.c @@ -0,0 +1,635 @@ +/** + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +#include +#include + +#include "includes.h" +#include "common.h" +#include "common/defs.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" + +#include "supp_main.h" +#include "supp_api.h" +#include "wpa_cli_zephyr.h" +#include "supp_events.h" + +extern struct k_sem wpa_supplicant_ready_sem; +extern struct wpa_global *global; + +enum requested_ops { + CONNECT = 0, + DISCONNECT +}; + +enum status_thread_state { + STATUS_THREAD_STOPPED = 0, + STATUS_THREAD_RUNNING, +}; + +#define OP_STATUS_POLLING_INTERVAL 1 + +#define CONNECTION_SUCCESS 0 +#define CONNECTION_FAILURE 1 +#define CONNECTION_TERMINATED 2 + +#define DISCONNECT_TIMEOUT_MS 5000 + +K_MUTEX_DEFINE(wpa_supplicant_mutex); + + +struct wpa_supp_api_ctrl { + const struct device *dev; + enum requested_ops requested_op; + enum status_thread_state status_thread_state; + int connection_timeout; /* in seconds */ + struct k_work_sync sync; + bool terminate; +}; + +static struct wpa_supp_api_ctrl wpas_api_ctrl; + +static void supp_shell_connect_status(struct k_work *work); + +static K_WORK_DELAYABLE_DEFINE(wpa_supp_status_work, + supp_shell_connect_status); + +#define wpa_cli_cmd_v(cmd, ...) ({ \ + bool status; \ + \ + if (zephyr_wpa_cli_cmd_v(cmd, ##__VA_ARGS__) < 0) { \ + wpa_printf(MSG_ERROR, \ + "Failed to execute wpa_cli command: %s", \ + cmd); \ + status = false; \ + } else { \ + status = true; \ + } \ + \ + status; \ +}) + +static struct wpa_supplicant *get_wpa_s_handle(const struct device *dev) +{ + struct net_if *iface = net_if_lookup_by_dev(dev); + char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + struct wpa_supplicant *wpa_s; + int ret; + + if (!iface) { + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return NULL; + } + + ret = net_if_get_name(iface, if_name, sizeof(if_name)); + if (!ret) { + wpa_printf(MSG_ERROR, "Cannot get interface name (%d)", ret); + return NULL; + } + + wpa_s = zephyr_get_handle_by_ifname(if_name); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Interface %s not found", if_name); + return NULL; + } + + return wpa_s; +} + +static int wait_for_disconnect_complete(const struct device *dev) +{ + int ret = 0; + int timeout = 0; + struct wpa_supplicant *wpa_s = get_wpa_s_handle(dev); + + if (!wpa_s) { + ret = -ENODEV; + wpa_printf(MSG_ERROR, "Failed to get wpa_s handle"); + goto out; + } + + while (wpa_s->wpa_state != WPA_DISCONNECTED) { + if (timeout > DISCONNECT_TIMEOUT_MS) { + ret = -ETIMEDOUT; + wpa_printf(MSG_WARNING, "Failed to disconnect from network"); + break; + } + + k_sleep(K_MSEC(10)); + timeout++; + } +out: + return ret; +} + +static void supp_shell_connect_status(struct k_work *work) +{ + static int seconds_counter; + int status = CONNECTION_SUCCESS; + int conn_result = CONNECTION_FAILURE; + struct wpa_supplicant *wpa_s; + struct wpa_supp_api_ctrl *ctrl = &wpas_api_ctrl; + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + if (ctrl->status_thread_state == STATUS_THREAD_RUNNING && ctrl->terminate) { + status = CONNECTION_TERMINATED; + goto out; + } + + wpa_s = get_wpa_s_handle(ctrl->dev); + if (!wpa_s) { + status = CONNECTION_FAILURE; + goto out; + } + + if (ctrl->requested_op == CONNECT && wpa_s->wpa_state != WPA_COMPLETED) { + if (ctrl->connection_timeout > 0 && + seconds_counter++ > ctrl->connection_timeout) { + if (!wpa_cli_cmd_v("disconnect")) { + goto out; + } + + conn_result = -ETIMEDOUT; + supplicant_send_wifi_mgmt_event(wpa_s->ifname, + NET_EVENT_WIFI_CMD_CONNECT_RESULT, + (void *)&conn_result, sizeof(int)); + status = CONNECTION_FAILURE; + goto out; + } + + k_work_reschedule(&wpa_supp_status_work, K_SECONDS(OP_STATUS_POLLING_INTERVAL)); + ctrl->status_thread_state = STATUS_THREAD_RUNNING; + k_mutex_unlock(&wpa_supplicant_mutex); + return; + } +out: + seconds_counter = 0; + + ctrl->status_thread_state = STATUS_THREAD_STOPPED; + k_mutex_unlock(&wpa_supplicant_mutex); +} + +static inline void wpa_supp_restart_status_work(void) +{ + /* Terminate synchronously */ + wpas_api_ctrl.terminate = 1; + k_work_flush_delayable(&wpa_supp_status_work, &wpas_api_ctrl.sync); + wpas_api_ctrl.terminate = 0; + + /* Start afresh */ + k_work_reschedule(&wpa_supp_status_work, K_MSEC(10)); +} + +static inline int chan_to_freq(int chan) +{ + /* We use global channel list here and also use the widest + * op_class for 5GHz channels as there is no user input + * for these (yet). + */ + int freq; + + freq = ieee80211_chan_to_freq(NULL, 81, chan); + if (freq <= 0) { + freq = ieee80211_chan_to_freq(NULL, 128, chan); + } + + if (freq <= 0) { + wpa_printf(MSG_ERROR, "Invalid channel %d", chan); + return -1; + } + + return freq; +} + +static inline enum wifi_frequency_bands wpas_band_to_zephyr(enum wpa_radio_work_band band) +{ + switch (band) { + case BAND_2_4_GHZ: + return WIFI_FREQ_BAND_2_4_GHZ; + case BAND_5_GHZ: + return WIFI_FREQ_BAND_5_GHZ; + default: + return WIFI_FREQ_BAND_UNKNOWN; + } +} + +static inline enum wifi_security_type wpas_key_mgmt_to_zephyr(int key_mgmt) +{ + switch (key_mgmt) { + case WPA_KEY_MGMT_NONE: + return WIFI_SECURITY_TYPE_NONE; + case WPA_KEY_MGMT_PSK: + return WIFI_SECURITY_TYPE_PSK; + case WPA_KEY_MGMT_PSK_SHA256: + return WIFI_SECURITY_TYPE_PSK_SHA256; + case WPA_KEY_MGMT_SAE: + return WIFI_SECURITY_TYPE_SAE; + default: + return WIFI_SECURITY_TYPE_UNKNOWN; + } +} + +/* Public API */ +int supplicant_connect(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct add_network_resp resp = {0}; + struct wpa_supplicant *wpa_s; + int ret = 0; + + if (!net_if_is_admin_up(net_if_lookup_by_dev(dev))) { + wpa_printf(MSG_ERROR, + "Interface %s is down, dropping connect", + dev->name); + return -1; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -1; + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); + goto out; + } + + if (!wpa_cli_cmd_v("remove_network all")) { + goto out; + } + + ret = z_wpa_ctrl_add_network(&resp); + if (ret) { + wpa_printf(MSG_ERROR, "Failed to add network"); + goto out; + } + + wpa_printf(MSG_DEBUG, "NET added: %d\n", resp.network_id); + + if (!wpa_cli_cmd_v("set_network %d ssid \"%s\"", + resp.network_id, params->ssid)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d scan_ssid 1", resp.network_id)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt NONE", resp.network_id)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d ieee80211w 0", resp.network_id)) { + goto out; + } + + if (params->security != WIFI_SECURITY_TYPE_NONE) { + if (params->security == WIFI_SECURITY_TYPE_SAE) { + if (params->sae_password) { + if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->sae_password)) { + goto out; + } + } else { + if (!wpa_cli_cmd_v("set_network %d sae_password \"%s\"", + resp.network_id, params->psk)) { + goto out; + } + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt SAE", resp.network_id)) { + goto out; + } + } else if (params->security == WIFI_SECURITY_TYPE_PSK_SHA256) { + if (!wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK-SHA256", + resp.network_id)) { + goto out; + } + } else if (params->security == WIFI_SECURITY_TYPE_PSK) { + if (!wpa_cli_cmd_v("set_network %d psk \"%s\"", + resp.network_id, params->psk)) { + goto out; + } + + if (!wpa_cli_cmd_v("set_network %d key_mgmt WPA-PSK", + resp.network_id)) { + goto out; + } + } else { + ret = -1; + wpa_printf(MSG_ERROR, "Unsupported security type: %d", + params->security); + goto out; + } + + if (params->mfp) { + if (!wpa_cli_cmd_v("set_network %d ieee80211w %d", + resp.network_id, params->mfp)) { + goto out; + } + } + } + + /* enable and select network */ + if (!wpa_cli_cmd_v("enable_network %d", resp.network_id)) { + goto out; + } + + if (params->channel != WIFI_CHANNEL_ANY) { + int freq = chan_to_freq(params->channel); + + if (freq < 0) { + ret = -1; + wpa_printf(MSG_ERROR, "Invalid channel %d", params->channel); + goto out; + } + + zephyr_wpa_cli_cmd_v("set_network %d scan_freq %d", + resp.network_id, freq); + } + + if (!wpa_cli_cmd_v("select_network %d", resp.network_id)) { + goto out; + } + + zephyr_wpa_cli_cmd_v("select_network %d", resp.network_id); + + wpas_api_ctrl.dev = dev; + wpas_api_ctrl.requested_op = CONNECT; + wpas_api_ctrl.connection_timeout = params->timeout; + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (!ret) { + wpa_supp_restart_status_work(); + } + + return ret; +} + +int supplicant_disconnect(const struct device *dev) +{ + struct net_if *iface = net_if_lookup_by_dev(dev); + struct wpa_supplicant *wpa_s; + int ret; + + if (!iface) { + ret = -ENOENT; + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return ret; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + ret = -EINVAL; + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); + goto out; + } + + wpas_api_ctrl.dev = dev; + wpas_api_ctrl.requested_op = DISCONNECT; + + if (!wpa_cli_cmd_v("disconnect")) { + goto out; + } + +out: + k_mutex_unlock(&wpa_supplicant_mutex); + + if (ret) { + wpa_printf(MSG_ERROR, "Disconnect failed: %s", strerror(-ret)); + return ret; + } + + wpa_supp_restart_status_work(); + + ret = wait_for_disconnect_complete(dev); + + wifi_mgmt_raise_disconnect_complete_event(iface, ret); + + return ret; +} + +int supplicant_status(const struct device *dev, struct wifi_iface_status *status) +{ + struct net_if *iface = net_if_lookup_by_dev(dev); + struct wpa_supplicant *wpa_s; + int ret = -1; + struct wpa_signal_info *si = NULL; + struct wpa_conn_info *conn_info = NULL; + + if (!iface) { + ret = -ENOENT; + wpa_printf(MSG_ERROR, "Interface for device %s not found", dev->name); + return ret; + } + + k_mutex_lock(&wpa_supplicant_mutex, K_FOREVER); + + wpa_s = get_wpa_s_handle(dev); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Device %s not found", dev->name); + goto out; + } + + si = os_zalloc(sizeof(struct wpa_signal_info)); + if (!si) { + wpa_printf(MSG_ERROR, "Failed to allocate memory for signal info"); + goto out; + } + + status->state = wpa_s->wpa_state; /* 1-1 Mapping */ + + if (wpa_s->wpa_state >= WPA_ASSOCIATED) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 channel; + struct signal_poll_resp signal_poll; + + os_memcpy(status->bssid, wpa_s->bssid, WIFI_MAC_ADDR_LEN); + status->band = wpas_band_to_zephyr(wpas_freq_to_band(wpa_s->assoc_freq)); + status->security = wpas_key_mgmt_to_zephyr(wpa_s->key_mgmt); + status->mfp = ssid->ieee80211w; /* Same mapping */ + ieee80211_freq_to_chan(wpa_s->assoc_freq, &channel); + status->channel = channel; + + if (ssid) { + u8 *_ssid = ssid->ssid; + size_t ssid_len = ssid->ssid_len; + struct status_resp cli_status; + + if (ssid_len == 0) { + int _res = z_wpa_ctrl_status(&cli_status); + + if (_res < 0) { + ssid_len = 0; + } else { + ssid_len = cli_status.ssid_len; + } + + _ssid = cli_status.ssid; + } + os_memcpy(status->ssid, _ssid, ssid_len); + status->ssid_len = ssid_len; + status->iface_mode = ssid->mode; + if (wpa_s->connection_set == 1) { + status->link_mode = + wpa_s->connection_he ? WIFI_6 : + wpa_s->connection_vht ? WIFI_5 : + wpa_s->connection_ht ? WIFI_4 : + wpa_s->connection_g ? WIFI_3 : + wpa_s->connection_a ? WIFI_2 : + wpa_s->connection_b ? WIFI_1 : + WIFI_0; + } else { + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + } + } + + ret = z_wpa_ctrl_signal_poll(&signal_poll); + if (!ret) { + status->rssi = signal_poll.rssi; + } else { + wpa_printf(MSG_WARNING, "%s:Failed to read RSSI\n", + __func__); + status->rssi = -WPA_INVALID_NOISE; + ret = 0; + } + + conn_info = os_zalloc(sizeof(struct wpa_conn_info)); + if (!conn_info) { + wpa_printf(MSG_ERROR, "%s:Failed to allocate memory\n", + __func__); + ret = -ENOMEM; + goto out; + } + + ret = wpa_drv_get_conn_info(wpa_s, conn_info); + if (!ret) { + status->beacon_interval = conn_info->beacon_interval; + status->dtim_period = conn_info->dtim_period; + status->twt_capable = conn_info->twt_capable; + } else { + wpa_printf(MSG_WARNING, "%s: Failed to get connection info\n", + __func__); + + status->beacon_interval = 0; + status->dtim_period = 0; + status->twt_capable = false; + ret = 0; + } + + os_free(conn_info); + } else { + ret = 0; + } + +out: + os_free(si); + k_mutex_unlock(&wpa_supplicant_mutex); + return ret; +} + +/* Below APIs are not natively supported by WPA supplicant, so, + * these are just wrappers around driver offload APIs. But it is + * transparent to the user. + * + * In the future these might be implemented natively by the WPA + * supplicant. + */ + +static const struct wifi_mgmt_ops *const get_wifi_mgmt_api(const struct device *dev) +{ + struct net_wifi_mgmt_offload *api = (struct net_wifi_mgmt_offload *)dev->api; + + return api ? api->wifi_mgmt_api : NULL; +} + +int supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->scan) { + wpa_printf(MSG_ERROR, "Scan not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->scan(dev, params, cb); +} + +#ifdef CONFIG_NET_STATISTICS_WIFI +int supplicant_get_stats(const struct device *dev, struct net_stats_wifi *stats) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_stats) { + wpa_printf(MSG_ERROR, "Get stats not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_stats(dev, stats); +} +#endif /* CONFIG_NET_STATISTICS_WIFI */ + +int supplicant_set_power_save(const struct device *dev, struct wifi_ps_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_power_save) { + wpa_printf(MSG_ERROR, "Set power save not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_power_save(dev, params); +} + +int supplicant_set_twt(const struct device *dev, struct wifi_twt_params *params) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_twt) { + wpa_printf(MSG_ERROR, "Set TWT not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_twt(dev, params); +} + +int supplicant_get_power_save_config(const struct device *dev, + struct wifi_ps_config *config) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->get_power_save_config) { + wpa_printf(MSG_ERROR, "Get power save config not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->get_power_save_config(dev, config); +} + +int supplicant_reg_domain(const struct device *dev, + struct wifi_reg_domain *reg_domain) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->reg_domain) { + wpa_printf(MSG_ERROR, "Regulatory domain not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->reg_domain(dev, reg_domain); +} diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h new file mode 100644 index 00000000000..9be68e59d6e --- /dev/null +++ b/modules/hostap/src/supp_api.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUPP_MGMT_H +#define ZEPHYR_SUPP_MGMT_H + +#include + +#ifndef MAX_SSID_LEN +#define MAX_SSID_LEN 32 +#endif +#ifndef MAC_ADDR_LEN +#define MAC_ADDR_LEN 6 +#endif + +/** + * @brief Request a connection + * + * @param dev: Wi-Fi interface name to use + * @param params: Connection details + * + * @return: 0 for OK; -1 for ERROR + */ +int supplicant_connect(const struct device *dev, struct wifi_connect_req_params *params); + +/** + * @brief Forces station to disconnect and stops any subsequent scan + * or connection attempts + * + * @param dev: Wi-Fi interface name to use + * + * @return: 0 for OK; -1 for ERROR + */ +int supplicant_disconnect(const struct device *dev); + +/** + * @brief + * + * @param dev: Wi-Fi interface name to use + * @param status: Status structure to fill + * + * @return: 0 for OK; -1 for ERROR + */ +int supplicant_status(const struct device *dev, struct wifi_iface_status *status); + +/** + * @brief Request a scan + * + * @param dev Wi-Fi interface name to use + * @param params Scan parameters + * @param cb Callback to be called for each scan result + * + * @return 0 for OK; -1 for ERROR + */ +int supplicant_scan(const struct device *dev, struct wifi_scan_params *params, + scan_result_cb_t cb); + +#if defined(CONFIG_NET_STATISTICS_WIFI) || defined(__DOXYGEN__) +/** + * @brief Get Wi-Fi statistics + * + * @param dev Wi-Fi interface name to use + * @param stats Pointer to stats structure to fill + * + * @return 0 for OK; -1 for ERROR + */ +int supplicant_get_stats(const struct device *dev, struct net_stats_wifi *stats); +#endif /* CONFIG_NET_STATISTICS_WIFI || __DOXYGEN__ */ + +/** + * @brief Set Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param params Power save parameters to set + * + * @return 0 for OK; -1 for ERROR + */ +int supplicant_set_power_save(const struct device *dev, struct wifi_ps_params *params); + +/** + * @brief Set Wi-Fi TWT parameters + * + * @param dev Wi-Fi interface name to use + * @param params TWT parameters to set + * @return 0 for OK; -1 for ERROR + */ +int supplicant_set_twt(const struct device *dev, struct wifi_twt_params *params); + +/** + * @brief Get Wi-Fi power save configuration + * + * @param dev Wi-Fi interface name to use + * @param config Address of power save configuration to fill + * @return 0 for OK; -1 for ERROR + */ +int supplicant_get_power_save_config(const struct device *dev, struct wifi_ps_config *config); + +/** + * @brief Set Wi-Fi Regulatory domain + * + * @param dev Wi-Fi interface name to use + * @param reg_domain Regulatory domain to set + * @return 0 for OK; -1 for ERROR + */ +int supplicant_reg_domain(const struct device *dev, struct wifi_reg_domain *reg_domain); + +#endif /* ZEPHYR_SUPP_MGMT_H */ diff --git a/modules/hostap/src/supp_events.c b/modules/hostap/src/supp_events.c new file mode 100644 index 00000000000..3fd6c2cb700 --- /dev/null +++ b/modules/hostap/src/supp_events.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "supp_events.h" + +#include "includes.h" +#include "common.h" + +#define MAC_STR_FORMAT "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx" + +static const char * const supplicant_event_map[] = { + "CTRL-EVENT-CONNECTED", + "CTRL-EVENT-DISCONNECTED", + "CTRL-EVENT-ASSOC-REJECT", + "CTRL-EVENT-AUTH-REJECT", + "CTRL-EVENT-TERMINATING", + "CTRL-EVENT-SSID-TEMP-DISABLED", + "CTRL-EVENT-SSID-REENABLED", + "CTRL-EVENT-SCAN-STARTED", + "CTRL-EVENT-SCAN-RESULTS", + "CTRL-EVENT-SCAN-FAILED", + "CTRL-EVENT-BSS-ADDED", + "CTRL-EVENT-BSS-REMOVED", + "CTRL-EVENT-NETWORK-NOT-FOUND", + "CTRL-EVENT-NETWORK-ADDED", + "CTRL-EVENT-NETWORK-REMOVED", + "CTRL-EVENT-DSCP-POLICY", +}; + +static int supplicant_process_status(struct supplicant_int_event_data *event_data, + char *supplicant_status) +{ + int ret = 1; /* For cases where parsing is not being done*/ + int event = -1; + int i; + unsigned char *mac; + union supplicant_event_data *data; + + data = (union supplicant_event_data *)event_data->data; + + for (i = 0; i < ARRAY_SIZE(supplicant_event_map); i++) { + if (strncmp(supplicant_status, supplicant_event_map[i], + strlen(supplicant_event_map[i])) == 0) { + event = i; + break; + } + } + + if (i >= ARRAY_SIZE(supplicant_event_map)) { + wpa_printf(MSG_ERROR, "Event not supported: %s\n", supplicant_status); + return -ENOTSUP; + } + + event_data->event = event; + + switch (event_data->event) { + case SUPPLICANT_EVENT_CONNECTED: + mac = data->connected.bssid; + ret = sscanf(supplicant_status + + sizeof("CTRL-EVENT-CONNECTED - Connection to") - 1, + MAC_STR_FORMAT, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->connected); + break; + case SUPPLICANT_EVENT_DISCONNECTED: + mac = data->disconnected.bssid; + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-DISCONNECTED bssid=") - 1, + MAC_STR_FORMAT" reason=%d", &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5], &data->disconnected.reason_code); + event_data->data_len = sizeof(data->disconnected); + break; + case SUPPLICANT_EVENT_ASSOC_REJECT: + /* TODO */ + break; + case SUPPLICANT_EVENT_AUTH_REJECT: + mac = data->auth_reject.bssid; + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-AUTH-REJECT ") - 1, + MAC_STR_FORMAT + " auth_type=%u auth_transaction=%u status_code=%u", + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5], + &data->auth_reject.auth_type, + &data->auth_reject.auth_transaction, + &data->auth_reject.status_code); + event_data->data_len = sizeof(data->auth_reject); + break; + case SUPPLICANT_EVENT_SSID_TEMP_DISABLED: + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-SSID-TEMP-DISABLED ") - 1, + "id=%d ssid=%s auth_failures=%u duration=%d reason=%s", + &data->temp_disabled.id, data->temp_disabled.ssid, + &data->temp_disabled.auth_failures, + &data->temp_disabled.duration, + data->temp_disabled.reason_code); + event_data->data_len = sizeof(data->temp_disabled); + break; + case SUPPLICANT_EVENT_SSID_REENABLED: + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-SSID-REENABLED ") - 1, + "id=%d ssid=%s", &data->reenabled.id, + data->reenabled.ssid); + event_data->data_len = sizeof(data->reenabled); + break; + case SUPPLICANT_EVENT_BSS_ADDED: + mac = data->bss_added.bssid; + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-BSS-ADDED ") - 1, + "%u "MAC_STR_FORMAT, + &data->bss_added.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->bss_added); + break; + case SUPPLICANT_EVENT_BSS_REMOVED: + mac = data->bss_removed.bssid; + ret = sscanf(supplicant_status + sizeof("CTRL-EVENT-BSS-REMOVED ") - 1, + "%u "MAC_STR_FORMAT, + &data->bss_removed.id, + &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); + event_data->data_len = sizeof(data->bss_removed); + break; + case SUPPLICANT_EVENT_TERMINATING: + case SUPPLICANT_EVENT_SCAN_STARTED: + case SUPPLICANT_EVENT_SCAN_FAILED: + case SUPPLICANT_EVENT_NETWORK_NOT_FOUND: + case SUPPLICANT_EVENT_NETWORK_ADDED: + case SUPPLICANT_EVENT_NETWORK_REMOVED: + strncpy(data->supplicant_event_str, supplicant_event_map[event], + sizeof(data->supplicant_event_str)); + event_data->data_len = strlen(data->supplicant_event_str) + 1; + case SUPPLICANT_EVENT_DSCP_POLICY: + /* TODO */ + break; + default: + break; + } + + if (ret <= 0) { + wpa_printf(MSG_ERROR, "%s Parse failed: %s", + supplicant_event_map[event_data->event], strerror(errno)); + } + + return ret; +} + +int supplicant_send_wifi_mgmt_event(const char *ifname, enum net_event_wifi_cmd event, + void *supplicant_status, size_t len) +{ + struct net_if *iface = net_if_get_by_index(net_if_get_by_name(ifname)); + union supplicant_event_data data; + struct supplicant_int_event_data event_data; + + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_WIFI_CMD_CONNECT_RESULT: + wifi_mgmt_raise_connect_result_event(iface, *(int *)supplicant_status); + break; + case NET_EVENT_WIFI_CMD_DISCONNECT_RESULT: + wifi_mgmt_raise_disconnect_result_event(iface, *(int *)supplicant_status); + break; + case NET_EVENT_SUPPLICANT_CMD_INT_EVENT: + event_data.data = &data; + if (supplicant_process_status(&event_data, (char *)supplicant_status) > 0) { + net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_INT_EVENT, + iface, &event_data, sizeof(event_data)); + } + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} + +int supplicant_generate_state_event(const char *ifname, + enum net_event_supplicant_cmd event, + int status) +{ + struct net_if *iface; + + iface = net_if_get_by_index(net_if_get_by_name(ifname)); + if (!iface) { + wpa_printf(MSG_ERROR, "Could not find iface for %s", ifname); + return -ENODEV; + } + + switch (event) { + case NET_EVENT_SUPPLICANT_CMD_READY: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_READY, iface); + break; + case NET_EVENT_SUPPLICANT_CMD_NOT_READY: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_NOT_READY, iface); + break; + case NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_IFACE_ADDED, iface); + break; + case NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING: + net_mgmt_event_notify(NET_EVENT_SUPPLICANT_IFACE_REMOVING, iface); + break; + case NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED: + net_mgmt_event_notify_with_info(NET_EVENT_SUPPLICANT_IFACE_REMOVED, + iface, &status, sizeof(status)); + break; + default: + wpa_printf(MSG_ERROR, "Unsupported event %d", event); + return -EINVAL; + } + + return 0; +} diff --git a/modules/hostap/src/supp_events.h b/modules/hostap/src/supp_events.h new file mode 100644 index 00000000000..41e64d57f54 --- /dev/null +++ b/modules/hostap/src/supp_events.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __SUPP_EVENTS_H__ +#define __SUPP_EVENTS_H__ + +#include + +/* Connectivity Events */ +#define _NET_MGMT_SUPPLICANT_LAYER NET_MGMT_LAYER_L3 +#define _NET_MGMT_SUPPLICANT_CODE 0x157 +#define _NET_MGMT_SUPPLICANT_BASE (NET_MGMT_LAYER(_NET_MGMT_SUPPLICANT_LAYER) | \ + NET_MGMT_LAYER_CODE(_NET_MGMT_SUPPLICANT_CODE) | \ + NET_MGMT_IFACE_BIT) +#define _NET_MGMT_SUPPLICANT_EVENT (NET_MGMT_EVENT_BIT | _NET_MGMT_SUPPLICANT_BASE) + +enum net_event_supplicant_cmd { + NET_EVENT_SUPPLICANT_CMD_READY = 1, + NET_EVENT_SUPPLICANT_CMD_NOT_READY, + NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, + NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, + NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, + NET_EVENT_SUPPLICANT_CMD_INT_EVENT, + NET_EVENT_WIFI_CMD_MAX +}; + +#define NET_EVENT_SUPPLICANT_READY \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_READY) + +#define NET_EVENT_SUPPLICANT_NOT_READY \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_NOT_READY) + +#define NET_EVENT_SUPPLICANT_IFACE_ADDED \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED) + +#define NET_EVENT_SUPPLICANT_IFACE_REMOVED \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED) + +#define NET_EVENT_SUPPLICANT_IFACE_REMOVING \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING) + +#define NET_EVENT_SUPPLICANT_INT_EVENT \ + (_NET_MGMT_SUPPLICANT_EVENT | NET_EVENT_SUPPLICANT_CMD_INT_EVENT) + +int supplicant_send_wifi_mgmt_event(const char *ifname, + enum net_event_wifi_cmd event, + void *status, + size_t len); +int supplicant_generate_state_event(const char *ifname, + enum net_event_supplicant_cmd event, + int status); + +#define REASON_CODE_LEN 18 +#define NM_WIFI_EVENT_STR_LEN 64 +#define ETH_ALEN 6 + +union supplicant_event_data { + struct supplicant_event_auth_reject { + int auth_type; + int auth_transaction; + int status_code; + uint8_t bssid[ETH_ALEN]; + } auth_reject; + + struct supplicant_event_connected { + uint8_t bssid[ETH_ALEN]; + char ssid[WIFI_SSID_MAX_LEN]; + int id; + } connected; + + struct supplicant_event_disconnected { + uint8_t bssid[ETH_ALEN]; + int reason_code; + int locally_generated; + } disconnected; + + struct supplicant_event_assoc_reject { + int status_code; + int reason_code; + } assoc_reject; + + struct supplicant_event_temp_disabled { + int id; + char ssid[WIFI_SSID_MAX_LEN]; + unsigned int auth_failures; + unsigned int duration; + char reason_code[REASON_CODE_LEN]; + } temp_disabled; + + struct supplicant_event_reenabled { + int id; + char ssid[WIFI_SSID_MAX_LEN]; + } reenabled; + + struct supplicant_event_bss_added { + unsigned int id; + uint8_t bssid[ETH_ALEN]; + } bss_added; + + struct supplicant_event_bss_removed { + unsigned int id; + uint8_t bssid[ETH_ALEN]; + } bss_removed; + + struct supplicant_event_network_added { + unsigned int id; + } network_added; + + struct supplicant_event_network_removed { + unsigned int id; + } network_removed; + + char supplicant_event_str[NM_WIFI_EVENT_STR_LEN]; +}; + +enum supplicant_event_num { + SUPPLICANT_EVENT_CONNECTED, + SUPPLICANT_EVENT_DISCONNECTED, + SUPPLICANT_EVENT_ASSOC_REJECT, + SUPPLICANT_EVENT_AUTH_REJECT, + SUPPLICANT_EVENT_TERMINATING, + SUPPLICANT_EVENT_SSID_TEMP_DISABLED, + SUPPLICANT_EVENT_SSID_REENABLED, + SUPPLICANT_EVENT_SCAN_STARTED, + SUPPLICANT_EVENT_SCAN_RESULTS, + SUPPLICANT_EVENT_SCAN_FAILED, + SUPPLICANT_EVENT_BSS_ADDED, + SUPPLICANT_EVENT_BSS_REMOVED, + SUPPLICANT_EVENT_NETWORK_NOT_FOUND, + SUPPLICANT_EVENT_NETWORK_ADDED, + SUPPLICANT_EVENT_NETWORK_REMOVED, + SUPPLICANT_EVENT_DSCP_POLICY, +}; + +struct supplicant_int_event_data { + enum supplicant_event_num event; + void *data; + size_t data_len; +}; + +#endif /* __SUPP_EVENTS_H__ */ diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c new file mode 100644 index 00000000000..34b91b65ed6 --- /dev/null +++ b/modules/hostap/src/supp_main.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(wifi_supplicant, CONFIG_WIFI_NM_WPA_SUPPLICANT_LOG_LEVEL); + +#include +#include +#include + +#include +#include +#include + +static K_THREAD_STACK_DEFINE(supplicant_thread_stack, + CONFIG_WIFI_NM_WPA_SUPPLICANT_THREAD_STACK_SIZE); +static struct k_thread tid; + +static K_THREAD_STACK_DEFINE(iface_wq_stack, CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_STACK_SIZE); + +#define IFACE_NOTIFY_TIMEOUT_MS 1000 +#define IFACE_NOTIFY_RETRY_MS 10 + +#include "supp_main.h" +#include "supp_api.h" +#include "supp_events.h" + +#include "includes.h" +#include "common.h" +#include "eloop.h" +#include "wpa_supplicant/config.h" +#include "wpa_supplicant_i.h" +#include "fst/fst.h" +#include "includes.h" +#include "wpa_cli_zephyr.h" + +static const struct wifi_mgmt_ops mgmt_ops = { + .scan = supplicant_scan, + .connect = supplicant_connect, + .disconnect = supplicant_disconnect, + .iface_status = supplicant_status, +#ifdef CONFIG_NET_STATISTICS_WIFI + .get_stats = supplicant_get_stats, +#endif + .set_power_save = supplicant_set_power_save, + .set_twt = supplicant_set_twt, + .get_power_save_config = supplicant_get_power_save_config, + .reg_domain = supplicant_reg_domain, +}; + +DEFINE_WIFI_NM_INSTANCE(wifi_supplicant, &mgmt_ops); + +#define WRITE_TIMEOUT 100 /* ms */ +#define INTERFACE_EVENT_MASK (NET_EVENT_IF_ADMIN_UP | NET_EVENT_IF_ADMIN_DOWN) + +struct supplicant_context { + struct wpa_global *supplicant; + struct net_mgmt_event_callback cb; + struct net_if *iface; + char if_name[CONFIG_NET_INTERFACE_NAME_LEN + 1]; + int event_socketpair[2]; + struct k_work iface_work; + struct k_work_q iface_wq; + int (*iface_handler)(struct supplicant_context *ctx, struct net_if *iface); +}; + +static struct supplicant_context *get_default_context(void) +{ + static struct supplicant_context ctx; + + return &ctx; +} + +struct wpa_global *zephyr_get_default_supplicant_context(void) +{ + return get_default_context()->supplicant; +} + +int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg) +{ + struct supplicant_context *ctx; + struct pollfd fds[1]; + int ret; + + /* TODO: Fix this to get the correct container */ + ctx = get_default_context(); + + if (ctx->event_socketpair[1] < 0) { + ret = -ENOENT; + goto out; + } + + fds[0].fd = ctx->event_socketpair[0]; + fds[0].events = POLLOUT; + fds[0].revents = 0; + + ret = zsock_poll(fds, 1, WRITE_TIMEOUT); + if (ret < 0) { + ret = -errno; + LOG_ERR("Cannot write event (%d)", ret); + goto out; + } + + ret = zsock_send(ctx->event_socketpair[1], msg, sizeof(*msg), 0); + if (ret < 0) { + ret = -errno; + LOG_WRN("Event send failed (%d)", ret); + goto out; + } + + if (ret != sizeof(*msg)) { + ret = -EMSGSIZE; + LOG_WRN("Event partial send (%d)", ret); + goto out; + } + + ret = 0; + +out: + return ret; +} + +static int send_event(const struct wpa_supplicant_event_msg *msg) +{ + return zephyr_wifi_send_event(msg); +} + +static bool is_wanted_interface(struct net_if *iface) +{ + if (!net_if_is_wifi(iface)) { + return false; + } + + /* TODO: check against a list of valid interfaces */ + + return true; +} + +struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname) +{ + struct wpa_supplicant *wpa_s = NULL; + struct supplicant_context *ctx = get_default_context(); + int ret; + + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); + if (!wpa_s) { + wpa_printf(MSG_ERROR, "%s: Unable to get wpa_s handle for %s\n", __func__, ifname); + return NULL; + } + + return wpa_s; +} + +static int get_iface_count(struct supplicant_context *ctx) +{ + /* FIXME, should not access ifaces as it is supplicant internal data */ + struct wpa_supplicant *wpa_s; + unsigned int count = 0; + + for (wpa_s = ctx->supplicant->ifaces; wpa_s; wpa_s = wpa_s->next) { + count += 1; + } + + return count; +} + +static int add_interface(struct supplicant_context *ctx, struct net_if *iface) +{ + struct wpa_supplicant *wpa_s; + char ifname[IFNAMSIZ + 1] = { 0 }; + int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS; + + ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1); + if (ret < 0) { + LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface); + goto out; + } + + LOG_DBG("Adding interface %s [%d] (%p)", ifname, net_if_get_by_iface(iface), iface); + + ret = zephyr_wpa_cli_global_cmd_v("interface_add %s %s %s %s", + ifname, "zephyr", "zephyr", "zephyr"); + if (ret) { + LOG_ERR("Failed to add interface %s", ifname); + goto out; + } + + while (retry++ < count && !wpa_supplicant_get_iface(ctx->supplicant, ifname)) { + k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS)); + } + + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); + if (wpa_s == NULL) { + LOG_ERR("Failed to add iface %s", ifname); + goto out; + } + + wpa_s->conf->filter_ssids = 1; + wpa_s->conf->ap_scan = 1; + + /* Default interface, kick start supplicant */ + if (get_iface_count(ctx) > 0) { + ctx->iface = iface; + net_if_get_name(iface, ctx->if_name, CONFIG_NET_INTERFACE_NAME_LEN); + } + + ret = zephyr_wpa_ctrl_init(wpa_s); + if (ret) { + LOG_ERR("Failed to initialize supplicant control interface"); + goto out; + } + + ret = wifi_nm_register_mgd_iface(wifi_nm_get_instance("wifi_supplicant"), iface); + if (ret) { + LOG_ERR("Failed to register mgd iface with native stack %s (%d)", + ifname, ret); + goto out; + } + + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_ADDED, 0); + + if (get_iface_count(ctx) == 1) { + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_READY, 0); + } + + ret = 0; + +out: + return ret; +} + +static int del_interface(struct supplicant_context *ctx, struct net_if *iface) +{ + struct wpa_supplicant_event_msg msg; + struct wpa_supplicant *wpa_s; + union wpa_event_data *event = NULL; + int ret, retry = 0, count = IFACE_NOTIFY_TIMEOUT_MS / IFACE_NOTIFY_RETRY_MS; + char ifname[IFNAMSIZ + 1] = { 0 }; + + ret = net_if_get_name(iface, ifname, sizeof(ifname) - 1); + if (ret < 0) { + LOG_ERR("Cannot get interface %d (%p) name", net_if_get_by_iface(iface), iface); + goto out; + } + + LOG_DBG("Removing interface %s %d (%p)", ifname, net_if_get_by_iface(iface), iface); + + event = os_zalloc(sizeof(*event)); + if (!event) { + ret = -ENOMEM; + LOG_ERR("Failed to allocate event data"); + goto out; + } + + wpa_s = wpa_supplicant_get_iface(ctx->supplicant, ifname); + if (!wpa_s) { + ret = -ENOENT; + LOG_ERR("Failed to get wpa_s handle for %s", ifname); + goto out; + } + + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVING, 0); + + os_memcpy(event->interface_status.ifname, ifname, IFNAMSIZ); + event->interface_status.ievent = EVENT_INTERFACE_REMOVED; + + msg.global = true; + msg.ctx = ctx->supplicant; + msg.event = EVENT_INTERFACE_STATUS; + msg.data = event; + + send_event(&msg); + + while (retry++ < count && wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + k_sleep(K_MSEC(IFACE_NOTIFY_RETRY_MS)); + } + + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) { + LOG_ERR("Failed to notify remove interface %s", ifname); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, -1); + goto out; + } + + ret = zephyr_wpa_cli_global_cmd_v("interface_remove %s", ifname); + if (ret) { + LOG_ERR("Failed to remove interface %s", ifname); + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, + -EINVAL); + goto out; + } + + ret = wifi_nm_unregister_mgd_iface(wifi_nm_get_instance("wpa_supplicant"), iface); + if (ret) { + LOG_ERR("Failed to unregister mgd iface %s with native stack (%d)", + ifname, ret); + goto out; + } + + if (get_iface_count(ctx) == 0) { + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0); + } + + supplicant_generate_state_event(ifname, NET_EVENT_SUPPLICANT_CMD_IFACE_REMOVED, 0); + +out: + if (event) { + os_free(event); + } + + return ret; +} + +static void iface_work_handler(struct k_work *work) +{ + struct supplicant_context *ctx = CONTAINER_OF(work, struct supplicant_context, + iface_work); + int ret; + + ret = (*ctx->iface_handler)(ctx, ctx->iface); + if (ret < 0) { + LOG_ERR("Interface %d (%p) handler failed (%d)", + net_if_get_by_iface(ctx->iface), ctx->iface, ret); + } +} + +/* As the mgmt thread stack is limited, use a separate work queue for any network + * interface add/delete. + */ +static void submit_iface_work(struct supplicant_context *ctx, + struct net_if *iface, + int (*handler)(struct supplicant_context *ctx, + struct net_if *iface)) +{ + ctx->iface_handler = handler; + + k_work_submit_to_queue(&ctx->iface_wq, &ctx->iface_work); +} + +static void interface_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) +{ + struct supplicant_context *ctx = CONTAINER_OF(cb, struct supplicant_context, + cb); + + if ((mgmt_event & INTERFACE_EVENT_MASK) != mgmt_event) { + return; + } + + if (!is_wanted_interface(iface)) { + LOG_DBG("Ignoring event (0x%02x) from interface %d (%p)", + mgmt_event, net_if_get_by_iface(iface), iface); + return; + } + + if (mgmt_event == NET_EVENT_IF_ADMIN_UP) { + LOG_INF("Network interface %d (%p) up", net_if_get_by_iface(iface), iface); + submit_iface_work(ctx, iface, add_interface); + return; + } + + if (mgmt_event == NET_EVENT_IF_ADMIN_DOWN) { + LOG_INF("Network interface %d (%p) down", net_if_get_by_iface(iface), iface); + submit_iface_work(ctx, iface, del_interface); + return; + } +} + +static void iface_cb(struct net_if *iface, void *user_data) +{ + struct supplicant_context *ctx = user_data; + int ret; + + if (!net_if_is_wifi(iface)) { + return; + } + + if (!net_if_is_up(iface)) { + return; + } + + ret = add_interface(ctx, iface); + if (ret < 0) { + return; + } +} + +static int setup_interface_monitoring(struct supplicant_context *ctx, struct net_if *iface) +{ + ARG_UNUSED(iface); + + net_mgmt_init_event_callback(&ctx->cb, interface_handler, + INTERFACE_EVENT_MASK); + net_mgmt_add_event_callback(&ctx->cb); + + net_if_foreach(iface_cb, ctx); + + return 0; +} + +static void event_socket_handler(int sock, void *eloop_ctx, void *user_data) +{ + struct supplicant_context *ctx = user_data; + struct wpa_supplicant_event_msg msg; + int ret; + + ARG_UNUSED(eloop_ctx); + ARG_UNUSED(ctx); + + ret = zsock_recv(sock, &msg, sizeof(msg), 0); + if (ret < 0) { + LOG_ERR("Failed to recv the message (%d)", -errno); + return; + } + + if (ret != sizeof(msg)) { + LOG_ERR("Received incomplete message: got: %d, expected:%d", + ret, sizeof(msg)); + return; + } + + LOG_DBG("Passing message %d to wpa_supplicant", msg.event); + + if (msg.global) { + wpa_supplicant_event_global(msg.ctx, msg.event, msg.data); + } else { + wpa_supplicant_event(msg.ctx, msg.event, msg.data); + } + + if (msg.data) { + if (msg.event == EVENT_AUTH) { + union wpa_event_data *data = msg.data; + + os_free((char *)data->auth.ies); + } + + os_free(msg.data); + } +} + +static int register_supplicant_event_socket(struct supplicant_context *ctx) +{ + int ret; + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->event_socketpair); + if (ret < 0) { + ret = -errno; + LOG_ERR("Failed to initialize socket (%d)", ret); + return ret; + } + + eloop_register_read_sock(ctx->event_socketpair[0], event_socket_handler, NULL, ctx); + + return 0; +} + +static void handler(void) +{ + struct supplicant_context *ctx; + struct wpa_params params; + +#if defined(CONFIG_WPA_SUPP_CRYPTO) && !defined(CONFIG_MBEDTLS_ENABLE_HEAP) + /* Needed for crypto operation as default is no-op and fails */ + mbedtls_platform_set_calloc_free(calloc, free); +#endif /* CONFIG_WPA_SUPP_CRYPTO */ + + ctx = get_default_context(); + + k_work_queue_init(&ctx->iface_wq); + k_work_queue_start(&ctx->iface_wq, iface_wq_stack, + K_THREAD_STACK_SIZEOF(iface_wq_stack), + CONFIG_WIFI_NM_WPA_SUPPLICANT_WQ_PRIO, + NULL); + + k_work_init(&ctx->iface_work, iface_work_handler); + + memset(¶ms, 0, sizeof(params)); + params.wpa_debug_level = CONFIG_WIFI_NM_WPA_SUPPLICANT_DEBUG_LEVEL; + + ctx->supplicant = wpa_supplicant_init(¶ms); + if (ctx->supplicant == NULL) { + LOG_ERR("Failed to initialize %s", "wpa_supplicant"); + goto err; + } + + LOG_INF("%s initialized", "wpa_supplicant"); + + if (fst_global_init()) { + LOG_ERR("Failed to initialize %s", "FST"); + goto out; + } + +#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) + if (!fst_global_add_ctrl(fst_ctrl_cli)) { + LOG_WRN("Failed to add CLI FST ctrl"); + } +#endif + zephyr_global_wpa_ctrl_init(); + + register_supplicant_event_socket(ctx); + + submit_iface_work(ctx, NULL, setup_interface_monitoring); + + (void)wpa_supplicant_run(ctx->supplicant); + + supplicant_generate_state_event(ctx->if_name, NET_EVENT_SUPPLICANT_CMD_NOT_READY, 0); + + eloop_unregister_read_sock(ctx->event_socketpair[0]); + + zephyr_wpa_ctrl_deinit(ctx->supplicant); + zephyr_global_wpa_ctrl_deinit(); + + fst_global_deinit(); + +out: + wpa_supplicant_deinit(ctx->supplicant); + + zsock_close(ctx->event_socketpair[0]); + zsock_close(ctx->event_socketpair[1]); + +err: + os_free(params.pid_file); +} + +static int init(void) +{ + /* We create a thread that handles all supplicant connections */ + k_thread_create(&tid, supplicant_thread_stack, + K_THREAD_STACK_SIZEOF(supplicant_thread_stack), + (k_thread_entry_t)handler, NULL, NULL, NULL, + 0, 0, K_NO_WAIT); + + return 0; +} + +SYS_INIT(init, APPLICATION, 0); diff --git a/modules/hostap/src/supp_main.h b/modules/hostap/src/supp_main.h new file mode 100644 index 00000000000..24d9796d276 --- /dev/null +++ b/modules/hostap/src/supp_main.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef __SUPP_MAIN_H_ +#define __SUPP_MAIN_H_ + +#if !defined(CONFIG_NET_DHCPV4) +static inline void net_dhcpv4_start(struct net_if *iface) +{ + ARG_UNUSED(iface); +} +static inline void net_dhcpv4_stop(struct net_if *iface) +{ + ARG_UNUSED(iface); +} +#else +#include +#endif + +struct wpa_global *zephyr_get_default_supplicant_context(void); +struct wpa_supplicant *zephyr_get_handle_by_ifname(const char *ifname); +struct wpa_supplicant_event_msg { + bool global; + void *ctx; + unsigned int event; + void *data; +}; +int zephyr_wifi_send_event(const struct wpa_supplicant_event_msg *msg); +#endif /* __SUPP_MAIN_H_ */ diff --git a/modules/hostap/src/wpa_cli.c b/modules/hostap/src/wpa_cli.c new file mode 100644 index 00000000000..2a61d274e33 --- /dev/null +++ b/modules/hostap/src/wpa_cli.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* @file + * @brief wpa_cli implementation for Zephyr OS + */ + +#include +#include +#include + +#include "wpa_cli_zephyr.h" + +static int cmd_wpa_cli(const struct shell *sh, + size_t argc, + const char *argv[]) +{ + ARG_UNUSED(sh); + + if (argc == 1) { + shell_error(sh, "Missing argument"); + return -EINVAL; + } + + /* Remove wpa_cli from the argument list */ + return z_wpa_ctrl_zephyr_cmd(argc - 1, &argv[1]); +} + +/* Persisting with "wpa_cli" naming for compatibility with Wi-Fi + * certification applications and scripts. + */ +SHELL_CMD_REGISTER(wpa_cli, + NULL, + "wpa_cli commands (only for internal use)", + cmd_wpa_cli); diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt index 51eb2bd11da..a78950e4322 100644 --- a/modules/lvgl/CMakeLists.txt +++ b/modules/lvgl/CMakeLists.txt @@ -36,8 +36,8 @@ zephyr_library_sources( ${LVGL_DIR}/src/core/lv_theme.c ${LVGL_DIR}/src/draw/arm2d/lv_gpu_arm2d.c - ${LVGL_DIR}/src/draw/lv_draw.c ${LVGL_DIR}/src/draw/lv_draw_arc.c + ${LVGL_DIR}/src/draw/lv_draw.c ${LVGL_DIR}/src/draw/lv_draw_img.c ${LVGL_DIR}/src/draw/lv_draw_label.c ${LVGL_DIR}/src/draw/lv_draw_layer.c @@ -50,15 +50,21 @@ zephyr_library_sources( ${LVGL_DIR}/src/draw/lv_img_cache.c ${LVGL_DIR}/src/draw/lv_img_decoder.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_draw_pxp_blend.c + ${LVGL_DIR}/src/draw/nxp/pxp/lv_draw_pxp.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c ${LVGL_DIR}/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_arc.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_blend.c - ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_rect.c ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite.c - ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_line.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_draw_vglite_rect.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_vglite_buf.c + ${LVGL_DIR}/src/draw/nxp/vglite/lv_vglite_utils.c + ${LVGL_DIR}/src/draw/renesas/lv_gpu_d2_draw_label.c + ${LVGL_DIR}/src/draw/renesas/lv_gpu_d2_ra6m3.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_arc.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_bg.c + ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_composite.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_img.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_label.c @@ -71,9 +77,9 @@ zephyr_library_sources( ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_texture_cache.c ${LVGL_DIR}/src/draw/sdl/lv_draw_sdl_utils.c ${LVGL_DIR}/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c - ${LVGL_DIR}/src/draw/sw/lv_draw_sw.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_arc.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_blend.c + ${LVGL_DIR}/src/draw/sw/lv_draw_sw.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_dither.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_gradient.c ${LVGL_DIR}/src/draw/sw/lv_draw_sw_img.c @@ -91,6 +97,7 @@ zephyr_library_sources( ${LVGL_DIR}/src/extra/libs/ffmpeg/lv_ffmpeg.c ${LVGL_DIR}/src/extra/libs/freetype/lv_freetype.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_fatfs.c + ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_littlefs.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_posix.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_stdio.c ${LVGL_DIR}/src/extra/libs/fsdrv/lv_fs_win32.c @@ -103,6 +110,7 @@ zephyr_library_sources( ${LVGL_DIR}/src/extra/libs/rlottie/lv_rlottie.c ${LVGL_DIR}/src/extra/libs/sjpg/lv_sjpg.c ${LVGL_DIR}/src/extra/libs/sjpg/tjpgd.c + ${LVGL_DIR}/src/extra/libs/tiny_ttf/lv_tiny_ttf.c ${LVGL_DIR}/src/extra/lv_extra.c ${LVGL_DIR}/src/extra/others/fragment/lv_fragment.c ${LVGL_DIR}/src/extra/others/fragment/lv_fragment_manager.c @@ -189,8 +197,8 @@ zephyr_library_sources( ${LVGL_DIR}/src/misc/lv_templ.c ${LVGL_DIR}/src/misc/lv_timer.c ${LVGL_DIR}/src/misc/lv_tlsf.c - ${LVGL_DIR}/src/misc/lv_txt.c ${LVGL_DIR}/src/misc/lv_txt_ap.c + ${LVGL_DIR}/src/misc/lv_txt.c ${LVGL_DIR}/src/misc/lv_utils.c ${LVGL_DIR}/src/widgets/lv_arc.c @@ -228,6 +236,7 @@ zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_KSCAN input/lvgl_pointer_kscan zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_INPUT input/lvgl_pointer_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_BUTTON_INPUT input/lvgl_button_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_ENCODER_INPUT input/lvgl_encoder_input.c) +zephyr_library_sources_ifdef(CONFIG_LV_Z_KEYPAD_INPUT input/lvgl_keypad_input.c) zephyr_library_link_libraries(LVGL) target_link_libraries(LVGL INTERFACE zephyr_interface) diff --git a/modules/lvgl/Kconfig.input b/modules/lvgl/Kconfig.input index b6cbdad0c28..4f76643aa86 100644 --- a/modules/lvgl/Kconfig.input +++ b/modules/lvgl/Kconfig.input @@ -77,4 +77,17 @@ config LV_Z_ENCODER_INPUT_MSGQ_COUNT help Size of the encoder message queue buffering input events. +config LV_Z_KEYPAD_INPUT + bool "Input lvgl keypad" + default y + depends on INPUT + depends on DT_HAS_ZEPHYR_LVGL_KEYPAD_INPUT_ENABLED + +config LV_Z_KEYPAD_INPUT_MSGQ_COUNT + int "Input keypad queue message count" + default 4 + depends on LV_Z_KEYPAD_INPUT + help + Size of the keypad message queue buffering input events. + endmenu diff --git a/modules/lvgl/Kconfig.memory b/modules/lvgl/Kconfig.memory index fc59eccb2e3..6cb1b197d9d 100644 --- a/modules/lvgl/Kconfig.memory +++ b/modules/lvgl/Kconfig.memory @@ -26,6 +26,7 @@ choice LV_Z_MEMORY_POOL config LV_Z_MEM_POOL_SYS_HEAP bool "User space lvgl pool" + select SYS_HEAP_INFO help Use a dedicated memory pool from a private sys heap. diff --git a/modules/lvgl/include/lvgl_keypad_input.h b/modules/lvgl/include/lvgl_keypad_input.h new file mode 100644 index 00000000000..f1d6e925f12 --- /dev/null +++ b/modules/lvgl/include/lvgl_keypad_input.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ +#define ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int lvgl_keypad_input_init(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ */ diff --git a/modules/lvgl/input/lvgl_common_input.c b/modules/lvgl/input/lvgl_common_input.c index 2894538c62b..2f2e1d32bd1 100644 --- a/modules/lvgl/input/lvgl_common_input.c +++ b/modules/lvgl/input/lvgl_common_input.c @@ -12,6 +12,7 @@ #include "lvgl_pointer_input.h" #include "lvgl_button_input.h" #include "lvgl_encoder_input.h" +#include "lvgl_keypad_input.h" LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); @@ -90,5 +91,9 @@ int lvgl_init_input_devices(void) lvgl_encoder_input_init); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT + DT_FOREACH_STATUS_OKAY_VARGS(zephyr_lvgl_keypad_input, LV_DEV_INIT, lvgl_keypad_input_init); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + return 0; } diff --git a/modules/lvgl/input/lvgl_keypad_input.c b/modules/lvgl/input/lvgl_keypad_input.c new file mode 100644 index 00000000000..08fd8a37a4e --- /dev/null +++ b/modules/lvgl/input/lvgl_keypad_input.c @@ -0,0 +1,75 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_lvgl_keypad_input + +#include "lvgl_common_input.h" +#include "lvgl_keypad_input.h" +#include + +#include + +LOG_MODULE_DECLARE(lvgl); + +struct lvgl_keypad_input_config { + struct lvgl_common_input_config common_config; /* Needs to be first member */ + const uint16_t *input_codes; + const uint16_t *lvgl_codes; + uint8_t num_codes; +}; + +static void lvgl_keypad_process_event(const struct device *dev, struct input_event *evt) +{ + struct lvgl_common_input_data *data = dev->data; + const struct lvgl_keypad_input_config *cfg = dev->config; + uint8_t i; + + for (i = 0; i < cfg->num_codes; i++) { + if (evt->code == cfg->input_codes[i]) { + data->pending_event.key = cfg->lvgl_codes[i]; + break; + } + } + + if (i == cfg->num_codes) { + LOG_WRN("Ignored input event: %u", evt->code); + return; + } + + data->pending_event.state = evt->value ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (k_msgq_put(cfg->common_config.event_msgq, &data->pending_event, + K_NO_WAIT) != 0) { + LOG_WRN("Could not put input data into keypad queue"); + } +} + +int lvgl_keypad_input_init(const struct device *dev) +{ + return lvgl_input_register_driver(LV_INDEV_TYPE_KEYPAD, dev); +} + +#define ASSERT_PROPERTIES(inst) \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == DT_INST_PROP_LEN(inst, lvgl_codes), \ + "Property input-codes must have the same length as lvgl-codes."); + +#define LVGL_KEYPAD_INPUT_DEFINE(inst) \ + ASSERT_PROPERTIES(inst); \ + LVGL_INPUT_DEFINE(inst, keypad, CONFIG_LV_Z_KEYPAD_INPUT_MSGQ_COUNT, \ + lvgl_keypad_process_event); \ + static const uint16_t lvgl_keypad_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + static const uint16_t lvgl_keypad_lvgl_codes_##inst[] = DT_INST_PROP(inst, lvgl_codes); \ + static const struct lvgl_keypad_input_config lvgl_keypad_input_config_##inst = { \ + .common_config.event_msgq = &LVGL_INPUT_EVENT_MSGQ(inst, keypad), \ + .input_codes = lvgl_keypad_input_codes_##inst, \ + .lvgl_codes = lvgl_keypad_lvgl_codes_##inst, \ + .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ + }; \ + static struct lvgl_common_input_data lvgl_common_input_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_common_input_data_##inst, \ + &lvgl_keypad_input_config_##inst, POST_KERNEL, \ + CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(LVGL_KEYPAD_INPUT_DEFINE) diff --git a/modules/mbedtls/CMakeLists.txt b/modules/mbedtls/CMakeLists.txt index c1c8e076b83..c0b17419a1c 100644 --- a/modules/mbedtls/CMakeLists.txt +++ b/modules/mbedtls/CMakeLists.txt @@ -16,6 +16,12 @@ zephyr_interface_library_named(mbedTLS) MBEDTLS_CONFIG_FILE="${CONFIG_MBEDTLS_CFG_FILE}" ) + if (CONFIG_BUILD_WITH_TFM) + target_include_directories(mbedTLS INTERFACE + $/api_ns/interface/include + ) + endif() + # Add regular includes target_include_directories(mbedTLS INTERFACE ${ZEPHYR_CURRENT_MODULE_DIR}/include @@ -28,30 +34,24 @@ zephyr_interface_library_named(mbedTLS) # Base mbed TLS files list(APPEND mbedtls_base_src + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aes.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aesni.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/aria.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/asn1parse.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/asn1write.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/base64.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_core.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod_raw.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/nist_kw.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/oid.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/padlock.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform_util.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/version.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/constant_time.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aes.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aesni.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/aria.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum_mod.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/bignum.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/camellia.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ccm.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/chacha20.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/chachapoly.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher_wrap.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/cipher.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/cmac.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/constant_time.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ctr_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/debug.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/des.c @@ -59,22 +59,27 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdh.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecdsa.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecjpake.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp_curves_new.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp_curves.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy_poll.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/entropy.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/error.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/gcm.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/hash_info.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/hkdf.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/hmac_drbg.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/lmots.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/lms.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/md5.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/md.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/md5.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/memory_buffer_alloc.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_reader.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/mps_trace.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/nist_kw.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/oid.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/padlock.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform_util.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/platform.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/poly1305.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/ripemd160.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/rsa_alt_helpers.c @@ -85,6 +90,7 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/threading.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/timing.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/version_features.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/version.c zephyr_init.c ) @@ -110,11 +116,11 @@ zephyr_interface_library_named(mbedTLS) zephyr_library_named(mbedTLSCrypto) - if (CONFIG_MBEDTLS_PSA_CRYPTO_C) + if (CONFIG_MBEDTLS_PSA_CRYPTO_C AND NOT CONFIG_BUILD_WITH_TFM) list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_aead.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_cipher.c - ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_driver_wrappers.c + ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_driver_wrappers_no_static.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_ecp.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_hash.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_mac.c @@ -122,11 +128,6 @@ zephyr_interface_library_named(mbedTLS) ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_se.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_storage.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_its_file.c - ) - endif() - - if (NOT CONFIG_BUILD_WITH_TFM) - list(APPEND crypto_source ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_client.c ${ZEPHYR_CURRENT_MODULE_DIR}/library/psa_crypto_slot_management.c diff --git a/modules/mbedtls/Kconfig.psa b/modules/mbedtls/Kconfig.psa index 42d2a48825b..25ac778eb2d 100644 --- a/modules/mbedtls/Kconfig.psa +++ b/modules/mbedtls/Kconfig.psa @@ -133,6 +133,40 @@ config PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY help Elliptic curve public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + bool "PSA ECC import key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: import for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT + bool "PSA ECC export key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: export for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE + bool "PSA ECC generate key pair support" + default y if PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + select PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY + help + Elliptic curve key pair: generate for both the private and public key. + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC + bool + default y + depends on PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT || \ + PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE + +config PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE + bool + default y + depends on PSA_WANT_KEY_TYPE_ECC_KEY_PAIR + config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR bool "PSA RSA key pair type support" select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY @@ -144,6 +178,34 @@ config PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY help RSA public key. +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT + bool "PSA RSA key pair import key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: import key for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT + bool "PSA RSA key pair export key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: export key for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE + bool "PSA RSA key pair generate key" + default y if PSA_WANT_KEY_TYPE_RSA_KEY_PAIR + select PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY + help + RSA key pair: key generation for both the private and public key. + +config PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC + bool + default y + depends on PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT || \ + PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE + config PSA_WANT_KEY_TYPE_DH_KEY_PAIR bool "PSA DH key pair type support" select PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY diff --git a/modules/mbedtls/configs/config-mini-tls1_1.h b/modules/mbedtls/configs/config-mini-tls1_1.h index 2bce8647caf..da8bf795c1d 100644 --- a/modules/mbedtls/configs/config-mini-tls1_1.h +++ b/modules/mbedtls/configs/config-mini-tls1_1.h @@ -59,6 +59,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_CIPHER_MODE_CBC diff --git a/modules/mbedtls/configs/config-no-entropy.h b/modules/mbedtls/configs/config-no-entropy.h index b5295bf1fb7..b3406a394b4 100644 --- a/modules/mbedtls/configs/config-no-entropy.h +++ b/modules/mbedtls/configs/config-no-entropy.h @@ -62,6 +62,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_CIPHER_MODE_CBC diff --git a/modules/mbedtls/configs/config-suite-b.h b/modules/mbedtls/configs/config-suite-b.h index 6f2cc963bd1..7468f763358 100644 --- a/modules/mbedtls/configs/config-suite-b.h +++ b/modules/mbedtls/configs/config-suite-b.h @@ -66,6 +66,7 @@ /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME +#define MBEDTLS_PLATFORM_MS_TIME_ALT /* mbed TLS feature support */ #define MBEDTLS_ECP_DP_SECP256R1_ENABLED diff --git a/modules/mbedtls/configs/config-tls-generic.h b/modules/mbedtls/configs/config-tls-generic.h index ab4a9610732..ea12a28e84d 100644 --- a/modules/mbedtls/configs/config-tls-generic.h +++ b/modules/mbedtls/configs/config-tls-generic.h @@ -37,6 +37,7 @@ #if defined(CONFIG_MBEDTLS_HAVE_TIME_DATE) #define MBEDTLS_HAVE_TIME #define MBEDTLS_HAVE_TIME_DATE +#define MBEDTLS_PLATFORM_MS_TIME_ALT #endif #if defined(CONFIG_MBEDTLS_TEST) @@ -486,21 +487,6 @@ #include CONFIG_MBEDTLS_USER_CONFIG_FILE #endif -#if !defined(CONFIG_MBEDTLS_PSA_CRYPTO_C) -/* When PSA API is used the checking header is included over the chain: - * |-psa/crypto.h - * |-psa/crypto_platform.h - * |-mbedtls/build_info.h - * |-mbedtls/check_config.h - * If include this header here then PSA API will be in semiconfigured state - * without considering dependencies from mbedtls/config_psa.h. - * mbedtls/config_psa.h should be included right after config-tls-generic.h before checking. - * Formally, all settings are correct but mbedtls library cannot be built. - * The behavior was introduced after adding mbedTLS 3.4.0 - */ -#include "mbedtls/check_config.h" -#endif - #if defined(CONFIG_NRF_CC3XX_PLATFORM) #define MBEDTLS_PLATFORM_ZEROIZE_ALT #endif diff --git a/modules/mbedtls/zephyr_init.c b/modules/mbedtls/zephyr_init.c index 3329c3b9c8d..49c9ffc8aff 100644 --- a/modules/mbedtls/zephyr_init.c +++ b/modules/mbedtls/zephyr_init.c @@ -15,6 +15,8 @@ #include #include #include +#include + #include @@ -107,3 +109,9 @@ int mbedtls_init(void) { return _mbedtls_init(); } + +/* TLS 1.3 ticket lifetime needs a timing interface */ +mbedtls_ms_time_t mbedtls_ms_time(void) +{ + return (mbedtls_ms_time_t)k_uptime_get(); +} diff --git a/modules/nanopb/nanopb.cmake b/modules/nanopb/nanopb.cmake index ddcdb5f61d1..5158090aae9 100644 --- a/modules/nanopb/nanopb.cmake +++ b/modules/nanopb/nanopb.cmake @@ -6,13 +6,16 @@ include_guard(GLOBAL) list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_NANOPB_MODULE_DIR}/extra) -find_program(PROTOC protoc) -if(NOT PROTOC) +find_package(Nanopb REQUIRED) + +if(NOT PROTOBUF_PROTOC_EXECUTABLE) message(FATAL_ERROR "'protoc' not found, please ensure protoc is installed\ and in path. See https://docs.zephyrproject.org/latest/samples/modules/nanopb/README.html") +else() + message(STATUS "Found protoc: ${PROTOBUF_PROTOC_EXECUTABLE}") endif() -find_package(Nanopb REQUIRED) +add_custom_target(nanopb_generated_headers) # Usage: # list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_BASE}/modules/nanopb) @@ -30,4 +33,11 @@ function(zephyr_nanopb_sources target) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_sources(${target} PRIVATE ${proto_srcs} ${proto_hdrs}) + + # Create unique target name for generated header list + string(MD5 unique_chars "${proto_hdrs}") + set(gen_target_name ${target}_proto_${unique_chars}) + + add_custom_target(${gen_target_name} DEPENDS ${proto_hdrs}) + add_dependencies(nanopb_generated_headers ${gen_target_name}) endfunction() diff --git a/modules/openthread/platform/crypto_psa.c b/modules/openthread/platform/crypto_psa.c index c818c5695a3..6ad286f3734 100644 --- a/modules/openthread/platform/crypto_psa.c +++ b/modules/openthread/platform/crypto_psa.c @@ -603,4 +603,66 @@ otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef) return psaToOtError(status); } +otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword, + uint16_t aPasswordLen, + const uint8_t *aSalt, + uint16_t aSaltLen, + uint32_t aIterationCounter, + uint16_t aKeyLen, + uint8_t *aKey) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_id_t key_id = PSA_KEY_ID_NULL; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_algorithm_t algorithm = PSA_ALG_PBKDF2_AES_CMAC_PRF_128; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE); + psa_set_key_algorithm(&attributes, algorithm); + psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD); + psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(aPasswordLen)); + + status = psa_import_key(&attributes, aPassword, aPasswordLen, &key_id); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_setup(&operation, algorithm); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, + aIterationCounter); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, + aSalt, aSaltLen); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, + key_id); + if (status != PSA_SUCCESS) { + goto out; + } + + status = psa_key_derivation_output_bytes(&operation, aKey, aKeyLen); + if (status != PSA_SUCCESS) { + goto out; + } + +out: + psa_reset_key_attributes(&attributes); + psa_key_derivation_abort(&operation); + psa_destroy_key(key_id); + + __ASSERT_NO_MSG(status == PSA_SUCCESS); + return psaToOtError(status); +} + #endif /* #if CONFIG_OPENTHREAD_ECDSA */ diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index d405539bcc0..64effaef337 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -63,6 +63,8 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); */ #define PHR_DURATION_US 32U +#define DEFAULT_SENSITIVITY -100 + enum pending_events { PENDING_EVENT_FRAME_TO_SEND, /* There is a tx frame to send */ PENDING_EVENT_FRAME_RECEIVED, /* Radio has received new frame */ @@ -1106,7 +1108,7 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) { ARG_UNUSED(aInstance); - return -100; + return DEFAULT_SENSITIVITY; } otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) diff --git a/modules/trusted-firmware-m/CMakeLists.txt b/modules/trusted-firmware-m/CMakeLists.txt index ad1109d849b..2ca875c4df2 100644 --- a/modules/trusted-firmware-m/CMakeLists.txt +++ b/modules/trusted-firmware-m/CMakeLists.txt @@ -40,9 +40,11 @@ if (CONFIG_BUILD_WITH_TFM) endif() if (CONFIG_TFM_REGRESSION_S) list(APPEND TFM_CMAKE_ARGS -DTEST_S=ON) + list(APPEND TFM_CMAKE_ARGS -DTFM_S_REG_TEST:BOOL=ON) endif() if (CONFIG_TFM_REGRESSION_NS) list(APPEND TFM_CMAKE_ARGS -DTEST_NS=ON) + list(APPEND TFM_CMAKE_ARGS -DTFM_NS_REG_TEST:BOOL=ON) endif() if (CONFIG_TFM_BL2) list(APPEND TFM_CMAKE_ARGS -DBL2=TRUE) @@ -51,11 +53,6 @@ if (CONFIG_BUILD_WITH_TFM) else() list(APPEND TFM_CMAKE_ARGS -DBL2=FALSE) endif() - if (CONFIG_TFM_BUILD_NS) - list(APPEND TFM_CMAKE_ARGS -DNS=TRUE) - else() - list(APPEND TFM_CMAKE_ARGS -DNS=FALSE) - endif() if (CONFIG_TFM_ISOLATION_LEVEL) list(APPEND TFM_CMAKE_ARGS -DTFM_ISOLATION_LEVEL=${CONFIG_TFM_ISOLATION_LEVEL}) endif() @@ -68,20 +65,6 @@ if (CONFIG_BUILD_WITH_TFM) if (CONFIG_TFM_PROFILE) list(APPEND TFM_CMAKE_ARGS -DTFM_PROFILE=${CONFIG_TFM_PROFILE}) endif() - if (CONFIG_TFM_PSA_TEST_CRYPTO) - set(TFM_PSA_TEST_SUITE CRYPTO) - elseif (CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE) - set(TFM_PSA_TEST_SUITE PROTECTED_STORAGE) - elseif (CONFIG_TFM_PSA_TEST_INTERNAL_TRUSTED_STORAGE) - set(TFM_PSA_TEST_SUITE INTERNAL_TRUSTED_STORAGE) - elseif (CONFIG_TFM_PSA_TEST_STORAGE) - set(TFM_PSA_TEST_SUITE STORAGE) - elseif (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION) - set(TFM_PSA_TEST_SUITE INITIAL_ATTESTATION) - endif() - if (DEFINED TFM_PSA_TEST_SUITE) - list(APPEND TFM_CMAKE_ARGS -DTEST_PSA_API=${TFM_PSA_TEST_SUITE}) - endif() if (CONFIG_TFM_CMAKE_BUILD_TYPE_RELEASE) set(TFM_CMAKE_BUILD_TYPE "Release") elseif (CONFIG_TFM_CMAKE_BUILD_TYPE_MINSIZEREL) @@ -169,34 +152,17 @@ if (CONFIG_BUILD_WITH_TFM) foreach(module ${TFM_CRYPTO_MODULES}) if (CONFIG_TFM_${module}_ENABLED) # list(APPEND TFM_ENABLED_CRYPTO_MODULES_ARG ${module}) - set(val "FALSE") - else() - set(val "TRUE") + list(APPEND TFM_CMAKE_ARGS -D${module}_ENABLED=True) endif() - list(APPEND TFM_CMAKE_ARGS -D${module}_DISABLED=${val}) endforeach() set(TFM_BINARY_DIR ${CMAKE_BINARY_DIR}/tfm) - set(TFM_TEST_REPO_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../tf-m-tests) set(PSA_ARCH_TESTS_PATH ${ZEPHYR_CURRENT_MODULE_DIR}/../psa-arch-tests) - set(VENEERS_FILE ${TFM_BINARY_DIR}/secure_fw/s_veneers.o) - set(TFM_API_NS_PATH ${TFM_BINARY_DIR}/tf-m-tests/app/libtfm_api_ns.a) - set(PLATFORM_NS_FILE ${TFM_BINARY_DIR}/platform/ns/libplatform_ns.a) - set(TFM_GENERATED_INCLUDES ${TFM_BINARY_DIR}/generated/interface/include) - set(TFM_INTERFACE_SOURCE_DIR ${TFM_BINARY_DIR}/install/interface/src) - - if (TFM_PSA_TEST_SUITE) - set(PSA_TEST_VAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/val/val_nspe.a) - set(PSA_TEST_PAL_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/platform/pal_nspe.a) - set(COMBINE_DIR_STORAGE storage) - set(COMBINE_DIR_PROTECTED_STORAGE storage) - set(COMBINE_DIR_INTERNAL_TRUSTED_STORAGE storage) - set(COMBINE_DIR_CRYPTO crypto) - set(COMBINE_DIR_INITIAL_ATTESTATION initial_attestation) - set(PSA_TEST_COMBINE_FILE ${TFM_BINARY_DIR}/tf-m-tests/app/psa_api_tests/dev_apis/${COMBINE_DIR_${TFM_PSA_TEST_SUITE}}/test_combine.a) - endif() + set(TFM_INTERFACE_SOURCE_DIR ${TFM_BINARY_DIR}/api_ns/interface/src) + set(TFM_INTERFACE_INCLUDE_DIR ${TFM_BINARY_DIR}/api_ns/interface/include) + set(TFM_INTERFACE_LIB_DIR ${TFM_BINARY_DIR}/api_ns/interface/lib) if(CONFIG_TFM_BL2) set(BL2_ELF_FILE ${TFM_BINARY_DIR}/bin/bl2.elf) @@ -207,38 +173,33 @@ if (CONFIG_BUILD_WITH_TFM) set(TFM_S_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s.bin) set(TFM_S_HEX_FILE ${TFM_BINARY_DIR}/bin/tfm_s.hex) set(TFM_NS_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_ns.bin) - set(TFM_NS_HEX_FILE ${TFM_BINARY_DIR}/bin/tfm_ns.hex) + set(TFM_NS_HEX_FILE ${CMAKE_BINARY_DIR}/tfm_ns/bin/tfm_ns.hex) set(TFM_S_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s_signed.bin) set(TFM_NS_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_ns_signed.bin) set(TFM_S_NS_SIGNED_BIN_FILE ${TFM_BINARY_DIR}/bin/tfm_s_ns_signed.bin) set(BUILD_BYPRODUCTS - ${VENEERS_FILE} - ${TFM_API_NS_PATH} - ${TFM_GENERATED_INCLUDES}/psa_manifest/sid.h ${PSA_TEST_VAL_FILE} ${PSA_TEST_PAL_FILE} ${PSA_TEST_COMBINE_FILE} - ${PLATFORM_NS_FILE} ${BL2_ELF_FILE} ${BL2_BIN_FILE} ${BL2_HEX_FILE} ${TFM_S_ELF_FILE} ${TFM_S_BIN_FILE} ${TFM_S_HEX_FILE} - ${TFM_NS_BIN_FILE} - ${TFM_NS_HEX_FILE} ${TFM_S_SIGNED_BIN_FILE} - ${TFM_NS_SIGNED_BIN_FILE} ${TFM_S_NS_SIGNED_BIN_FILE} + ${TFM_INTERFACE_LIB_DIR}/s_veneers.o + ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c - ${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c + ${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c # Specific to nordic_nrf platform ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c @@ -263,33 +224,7 @@ if (CONFIG_BUILD_WITH_TFM) message(FATAL_ERROR "Unsupported ZEPHYR_TOOLCHAIN_VARIANT: ${ZEPHYR_TOOLCHAIN_VARIANT}") endif() - if (CONFIG_TFM_PARTITION_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") - # TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, - # or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has - # been manually downloaded by the user before starting the build. - message(FATAL_ERROR "CONFIG_TFM_PARTITION_INITIAL_ATTESTATION is not available " - "with TF-M 1.7.0 due to licensing issues with a dependent library. This " - "restriction will be removed once licensing issues have been resolved." - ) - endif() - - if (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") - # TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, - # or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has - # been manually downloaded by the user before starting the build. - message(FATAL_ERROR "CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION is not available " - "with TF-M 1.7.0 due to licensing issues with a dependent library. This " - "restriction will be removed once licensing issues have been resolved." - ) - endif() - - if (CONFIG_TFM_QCBOR_PATH STREQUAL "DOWNLOAD") - # Change CMake cache type to string to avoid QCBOR_PATH=/absolute/path/DOWNLOAD being set. - set(QCBOR_PATH_TYPE ":STRING") - endif() - # Always set QCBOR_PATH, this will make sure that we don't automatically download this - # dependency in the TF-M build system and it will fail when set to an invalid value. - list(APPEND TFM_CMAKE_ARGS -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH}) + string(REPLACE "toolchain" "toolchain_ns" TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_FILE}) if(CONFIG_BOARD_LPCXPRESSO55S69_CPU0) # Supply path to NXP HAL sources used for TF-M build @@ -306,13 +241,6 @@ if (CONFIG_BUILD_WITH_TFM) list(APPEND TFM_CMAKE_ARGS -DMCUBOOT_DATA_SHARING=ON) endif() - if(TFM_PSA_TEST_SUITE) - list(APPEND TFM_CMAKE_ARGS - -DPSA_TOOLCHAIN_FILE=${CMAKE_CURRENT_LIST_DIR}/psa/GNUARM.cmake - -DTOOLCHAIN=INHERIT - ) - endif() - if(CONFIG_FPU AND CONFIG_FP_HARDABI) list(APPEND TFM_CMAKE_ARGS -DCONFIG_TFM_ENABLE_FP=ON) # Note: This is not a cmake option in TF-M. @@ -337,10 +265,10 @@ if (CONFIG_BUILD_WITH_TFM) -DTFM_PLATFORM=${CONFIG_TFM_BOARD} -DCONFIG_TFM_BUILD_LOG_QUIET=ON -DCONFIG_TFM_MEMORY_USAGE_QUIET=OFF + -DPython3_EXECUTABLE=${Python3_EXECUTABLE} ${TFM_CMAKE_ARGS} $> -DMBEDCRYPTO_PATH=$>,$,${ZEPHYR_MBEDTLS_MODULE_DIR}> - -DTFM_TEST_REPO_PATH=${TFM_TEST_REPO_PATH} -DPSA_ARCH_TESTS_PATH=${PSA_ARCH_TESTS_PATH} ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR} WORKING_DIRECTORY ${TFM_BINARY_DIR} @@ -379,6 +307,11 @@ if (CONFIG_BUILD_WITH_TFM) # This is the root of all TFM build artifacts. set_target_properties(tfm PROPERTIES TFM_BINARY_DIR ${TFM_BINARY_DIR}) + # Set TFM toolchain properties on 'tfm' + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_NS_FILE ${TFM_TOOLCHAIN_NS_FILE}) + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_PREFIX ${TFM_TOOLCHAIN_PREFIX}) + set_target_properties(tfm PROPERTIES TFM_TOOLCHAIN_PATH ${TFM_TOOLCHAIN_PATH}) + # Set BL2 (MCUboot) executable file paths as target properties on 'tfm' # These files are produced by the TFM build system. if(CONFIG_TFM_BL2) @@ -415,48 +348,27 @@ if (CONFIG_BUILD_WITH_TFM) if (CONFIG_TFM_PARTITION_PLATFORM AND NOT CONFIG_TFM_PARTITION_PLATFORM_CUSTOM_REBOOT) zephyr_library_sources(src/reboot.c) endif() - zephyr_library_sources_ifndef(CONFIG_TFM_PSA_TEST_NONE src/zephyr_tfm_psa_test.c) - - if (TFM_PSA_TEST_SUITE) - zephyr_library_link_libraries( - ${PSA_TEST_VAL_FILE} - ${PSA_TEST_PAL_FILE} - ${PSA_TEST_COMBINE_FILE} - ) - endif() - - if(NOT CONFIG_TFM_BUILD_NS) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PROTECTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INTERNAL_TRUSTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_CRYPTO ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INITIAL_ATTESTATION ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_FIRMWARE_UPDATE ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c) - zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_psa_ns_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_platform_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PROTECTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_ps_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INTERNAL_TRUSTED_STORAGE ${TFM_INTERFACE_SOURCE_DIR}/tfm_its_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_CRYPTO ${TFM_INTERFACE_SOURCE_DIR}/tfm_crypto_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_INITIAL_ATTESTATION ${TFM_INTERFACE_SOURCE_DIR}/tfm_attest_api.c) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_FIRMWARE_UPDATE ${TFM_INTERFACE_SOURCE_DIR}/tfm_fwu_api.c) - if(CONFIG_SOC_FAMILY_NRF) - zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) - endif() + zephyr_library_sources(${TFM_INTERFACE_SOURCE_DIR}/tfm_tz_psa_ns_api.c) - else() - zephyr_library_link_libraries( - ${PLATFORM_NS_FILE} - ${TFM_API_NS_PATH} - ) + if(CONFIG_SOC_FAMILY_NRF) + zephyr_library_sources_ifdef(CONFIG_TFM_PARTITION_PLATFORM ${TFM_INTERFACE_SOURCE_DIR}/tfm_ioctl_core_ns_api.c) endif() - zephyr_include_directories( - ${TFM_GENERATED_INCLUDES} - ) - target_include_directories(tfm_api PRIVATE - ${TFM_BINARY_DIR}/install/interface/include - ${TFM_BINARY_DIR}/install/interface/include/crypto_keys + ${TFM_INTERFACE_INCLUDE_DIR} + ${TFM_INTERFACE_INCLUDE_DIR}/crypto_keys ) zephyr_library_link_libraries( - ${VENEERS_FILE} + ${TFM_INTERFACE_LIB_DIR}/s_veneers.o ) # To ensure that generated include files are created before they are used. diff --git a/modules/trusted-firmware-m/Kconfig.tfm b/modules/trusted-firmware-m/Kconfig.tfm index a0d71328540..277dd8a8d09 100644 --- a/modules/trusted-firmware-m/Kconfig.tfm +++ b/modules/trusted-firmware-m/Kconfig.tfm @@ -17,7 +17,6 @@ config TFM_BOARD default "stm/stm32l562e_dk" if BOARD_STM32L562E_DK default "arm/musca_b1" if BOARD_MUSCA_B1 default "arm/musca_s1" if BOARD_MUSCA_S1 - default "lairdconnectivity/bl5340_dvk_cpuapp" if BOARD_BL5340_DVK_CPUAPP_NS default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf9160" if SOC_NRF9160 default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf9120" if SOC_NRF9120 default "${ZEPHYR_BASE}/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp" if SOC_NRF5340_CPUAPP @@ -45,7 +44,7 @@ menuconfig BUILD_WITH_TFM Notes: Building with the "_ns" BOARD variant (e.g. "mps2_an521_ns") - ensures that CONFIG_TRUSTED_EXECUTION_NONSECURE is enabled. + ensures that CONFIG_TRUSTED_EXECUTION_NONSECURE is enabled. By default we allow Zephyr preemptible threads be preempted while performing a secure function call. @@ -75,6 +74,7 @@ config TFM_PROFILE depends on BUILD_WITH_TFM default "profile_small" if TFM_PROFILE_TYPE_SMALL default "profile_medium" if TFM_PROFILE_TYPE_MEDIUM + default "profile_medium_arotless" if TFM_PROFILE_TYPE_AROTLESS default "profile_large" if TFM_PROFILE_TYPE_LARGE help Build profile used to build tfm_s image. The available values are @@ -92,7 +92,7 @@ choice TFM_PROFILE_TYPE isolation level. config TFM_PROFILE_TYPE_NOT_SET - bool "TF-M build profile is not set" + bool "TF-M build profile: not set (base)" config TFM_PROFILE_TYPE_SMALL bool "TF-M build profile: small" @@ -100,6 +100,9 @@ config TFM_PROFILE_TYPE_SMALL config TFM_PROFILE_TYPE_MEDIUM bool "TF-M build profile: medium" +config TFM_PROFILE_TYPE_AROTLESS + bool "TF-M build profile: ARoT-less" + config TFM_PROFILE_TYPE_LARGE bool "TF-M build profile: large" @@ -226,19 +229,8 @@ config TFM_BL2 TFM is designed to run with MCUboot in a certain configuration. This config adds MCUboot to the build - built via TFM's build system. -config TFM_BUILD_NS - bool "Build the TF-M Non-Secure application and libraries" - help - Instruct the TF-M build system to build the TF-M Non-Secure - application and libraries. - - This option is intended for testing purposes only, since this is the - easiest way to build the TF-M regression tests application and test - support libraries in the zephyr build system. - config TFM_USE_NS_APP bool "Use the TF-M Non-Secure application" - depends on TFM_BUILD_NS help The TF-M build system can produce multiple executable files. The main one is the TF-M secure firmware. Optionally the TF-M @@ -343,7 +335,6 @@ config TFM_IPC config TFM_SFN bool "SFN model" - depends on !FP_HARDABI help Use the SFN Model as the SPM backend for the PSA API. The SFN model supports the SFN Partition model, and isolation level 1. diff --git a/modules/trusted-firmware-m/interface/interface.c b/modules/trusted-firmware-m/interface/interface.c index ad0ed1abdfe..d949a9dc027 100644 --- a/modules/trusted-firmware-m/interface/interface.c +++ b/modules/trusted-firmware-m/interface/interface.c @@ -35,7 +35,7 @@ int32_t tfm_ns_interface_dispatch(veneer_fn fn, if (!is_pre_kernel) { /* TF-M request protected by NS lock */ if (k_mutex_lock(&tfm_mutex, K_FOREVER) != 0) { - return (int32_t)TFM_ERROR_GENERIC; + return (int32_t)PSA_ERROR_GENERIC_ERROR; } #if !defined(CONFIG_ARM_NONSECURE_PREEMPTIBLE_SECURE_CALLS) @@ -79,7 +79,7 @@ uint32_t tfm_ns_interface_init(void) * The static K_MUTEX_DEFINE handles mutex initialization, * so this function may be implemented as no-op. */ - return TFM_SUCCESS; + return PSA_SUCCESS; } @@ -90,7 +90,7 @@ uint32_t tfm_ns_interface_init(void) static int ns_interface_init(void) { - __ASSERT(tfm_ns_interface_init() == TFM_SUCCESS, + __ASSERT(tfm_ns_interface_init() == PSA_SUCCESS, "TF-M NS interface init failed"); return 0; diff --git a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt index 41dca2f15a9..d75b34a8109 100644 --- a/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/CMakeLists.txt @@ -36,14 +36,6 @@ target_include_directories(platform_s ${board_includes} ) -target_include_directories(platform_ns - PUBLIC - include - include/util - ${partition_includes} - ${board_includes} -) - if(BL2) target_include_directories(platform_bl2 PUBLIC @@ -54,14 +46,18 @@ if(BL2) ) endif() -if (TFM_PARTITION_PLATFORM) -install(FILES include/tfm_ioctl_api.h - DESTINATION ${TFM_INSTALL_PATH}/interface/include) -endif() - -#========================= tfm_spm ============================================# - target_sources(tfm_spm PRIVATE src/tfm_hal_platform.c ) + +if (TFM_PARTITION_PLATFORM) +install(FILES include/tfm_ioctl_api.h + include/device_cfg.h + include/RTE_Device.h + include/tfm_ioctl_api.h + DESTINATION ${INSTALL_INTERFACE_INC_DIR}) +endif() + +install(FILES ns/CMakeLists.txt + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h b/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h index c6c36ee927f..3fade10525a 100644 --- a/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h +++ b/modules/trusted-firmware-m/nordic_nrf/include/tfm_ioctl_api.h @@ -9,7 +9,6 @@ #include #include -#include #include /* Include core IOCTL services */ diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt index 279ea385996..b74620fe2d5 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/CMakeLists.txt @@ -5,8 +5,19 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf5340) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf5340 nrf5340) add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf5340dk_nrf5340_cpuapp/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR} +) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake index b3e5d74181c..ae50a4846dd 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf5340 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf5340/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake new file mode 100644 index 00000000000..f19d7f43c67 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/cpuarch.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf5340/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..077e88bd37b --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(PLATFORM_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/common/nrf5340/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake deleted file mode 100644 index d9bd226eb65..00000000000 --- a/modules/trusted-firmware-m/nordic_nrf/nrf5340_cpuapp/preload.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023, Nordic Semiconductor ASA. -# -# SPDX-License-Identifier: Apache-2.0 -# - -include(platform/ext/target/nordic_nrf/common/nrf5340/preload.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt index a84c6fd9fd5..64fff7cdb86 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/CMakeLists.txt @@ -5,8 +5,21 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf91) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf91 nrf91) add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf9120/cpuarch.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf9120) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf9161dk_nrf9161/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake index 3f58e7b89eb..e858eda3a27 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf91 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf91/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake new file mode 100644 index 00000000000..9f0886c7a51 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/cpuarch.cmake @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf9120/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..c53d684d7e8 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9120/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(PLATFORM_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/common/nrf9120/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake deleted file mode 100644 index 4b3c6ee79ab..00000000000 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9120/preload.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023, Nordic Semiconductor ASA. -# -# SPDX-License-Identifier: Apache-2.0 -# - -include(platform/ext/target/nordic_nrf/common/nrf9120/preload.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt index a84c6fd9fd5..aa2ef831031 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/CMakeLists.txt @@ -5,8 +5,21 @@ # set(NRF_BOARD_SELECTED True) -set(NRF_SOC_VARIANT nrf91) add_subdirectory(${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf91 nrf91) add_subdirectory(.. common) + +install(FILES ${CMAKE_CURRENT_LIST_DIR}/ns/cpuarch_ns.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR} + RENAME cpuarch.cmake) + +install(FILES ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/common/nrf9160/cpuarch.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}/common/nrf9160) + +install(FILES config.cmake + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) + +install(DIRECTORY ${Trusted\ Firmware\ M_SOURCE_DIR}/platform/ext/target/nordic_nrf/nrf9160dk_nrf9160/tests + + DESTINATION ${INSTALL_PLATFORM_NS_DIR}) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake index 3f58e7b89eb..e858eda3a27 100644 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/config.cmake @@ -4,5 +4,6 @@ # SPDX-License-Identifier: Apache-2.0 # -set(PLATFORM_PATH platform/ext/target/nordic_nrf/) +set(NRF_SOC_VARIANT nrf91 CACHE STRING "nRF SoC Variant") + include(${PLATFORM_PATH}/common/nrf91/config.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake new file mode 100644 index 00000000000..f728014d3f7 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/cpuarch.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_PATH platform/ext/target/nordic_nrf) + +include(${PLATFORM_PATH}/common/nrf9160/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake new file mode 100644 index 00000000000..902e7fe7ef4 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/nrf9160/ns/cpuarch_ns.cmake @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(PLATFORM_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(PLATFORM_PATH ${CMAKE_CURRENT_LIST_DIR}) + +include(${CMAKE_CURRENT_LIST_DIR}/common/nrf9160/cpuarch.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake b/modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake deleted file mode 100644 index 364480a6f7f..00000000000 --- a/modules/trusted-firmware-m/nordic_nrf/nrf9160/preload.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023, Nordic Semiconductor ASA. -# -# SPDX-License-Identifier: Apache-2.0 -# - -include(platform/ext/target/nordic_nrf/common/nrf9160/preload.cmake) diff --git a/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt b/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt new file mode 100644 index 00000000000..5bb8cb5bd94 --- /dev/null +++ b/modules/trusted-firmware-m/nordic_nrf/ns/CMakeLists.txt @@ -0,0 +1,46 @@ +# +# Copyright (c) 2023, Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_policy(SET CMP0076 NEW) +set(CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +set(NRF_BOARD_SELECTED True) + +add_library(platform_ns STATIC) + +set(partition_includes + ${CMAKE_CURRENT_LIST_DIR}/common/${NRF_SOC_VARIANT}/partition + ${CMAKE_BINARY_DIR}/../zephyr/include/generated +) + +set(board_includes + ${CMAKE_BINARY_DIR}/../zephyr/misc/generated/syscalls_links/include + ${ZEPHYR_BASE}/include +) + +target_include_directories(platform_region_defs + INTERFACE + ${partition_includes} +) + +target_include_directories(platform_ns + PUBLIC + ${partition_includes} + ${board_includes} +) + +# Get the value of HAL_NORDIC_PATH +include(${CMAKE_CURRENT_LIST_DIR}/common/core/config_nordic_nrf_spe.cmake) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common/${NRF_SOC_VARIANT} ${NRF_SOC_VARIANT}) + +target_include_directories(platform_ns + PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_link_libraries(platform_ns + PUBLIC + platform_region_defs +) diff --git a/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c b/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c deleted file mode 100644 index d7d68f9db67..00000000000 --- a/modules/trusted-firmware-m/src/zephyr_tfm_psa_test.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/** - * \brief This symbol is the entry point provided by the PSA API compliance - * test libraries - */ -extern void val_entry(void); - - -void psa_test(void) -{ - val_entry(); -} diff --git a/modules/uoscore-uedhoc/CMakeLists.txt b/modules/uoscore-uedhoc/CMakeLists.txt index e23ad7da2e6..aaf842e392c 100644 --- a/modules/uoscore-uedhoc/CMakeLists.txt +++ b/modules/uoscore-uedhoc/CMakeLists.txt @@ -29,7 +29,7 @@ if (CONFIG_UOSCORE OR CONFIG_UEDHOC) if (CONFIG_BUILD_WITH_TFM) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/modules/zcbor/CMakeLists.txt b/modules/zcbor/CMakeLists.txt index 33b60bdfbcb..45535fc8594 100644 --- a/modules/zcbor/CMakeLists.txt +++ b/modules/zcbor/CMakeLists.txt @@ -10,6 +10,8 @@ if(CONFIG_ZCBOR) ${ZEPHYR_ZCBOR_MODULE_DIR}/src/zcbor_encode.c ) + zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L) + zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_CANONICAL ZCBOR_CANONICAL) zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_STOP_ON_ERROR ZCBOR_STOP_ON_ERROR) zephyr_compile_definitions_ifdef(CONFIG_ZCBOR_VERBOSE ZCBOR_VERBOSE) diff --git a/modules/zcbor/Kconfig b/modules/zcbor/Kconfig index 1b3fd15d5e3..655fb2ed2a8 100644 --- a/modules/zcbor/Kconfig +++ b/modules/zcbor/Kconfig @@ -33,4 +33,11 @@ config ZCBOR_ASSERT config ZCBOR_BIG_ENDIAN def_bool BIG_ENDIAN +config ZCBOR_MAX_STR_LEN + int "Default max length when calling zcbor_tstr_put_term()" + default 256 + help + This can be manually used if no other value is readily available, but + using this is discouraged. + endif # ZCBOR diff --git a/samples/basic/blinky/README.rst b/samples/basic/blinky/README.rst index 893d00b5103..ec23fe5403f 100644 --- a/samples/basic/blinky/README.rst +++ b/samples/basic/blinky/README.rst @@ -40,8 +40,9 @@ Build and flash Blinky as follows, changing ``reel_board`` for your board: :goals: build flash :compact: -After flashing, the LED starts to blink. If a runtime error occurs, the sample -exits without printing to the console. +After flashing, the LED starts to blink and messages with the current LED state +are printed on the console. If a runtime error occurs, the sample exits without +printing to the console. Build errors ************ diff --git a/samples/basic/blinky/src/main.c b/samples/basic/blinky/src/main.c index fb86da1abdc..4cab4969d94 100644 --- a/samples/basic/blinky/src/main.c +++ b/samples/basic/blinky/src/main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -22,6 +23,7 @@ static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); int main(void) { int ret; + bool led_state = true; if (!gpio_is_ready_dt(&led)) { return 0; @@ -37,6 +39,9 @@ int main(void) if (ret < 0) { return 0; } + + led_state = !led_state; + printf("LED state: %s\n", led_state ? "ON" : "OFF"); k_msleep(SLEEP_TIME_MS); } return 0; diff --git a/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay b/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay index fc5466c9cbe..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay +++ b/samples/basic/blinky_pwm/boards/esp32_devkitc_wroom.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay b/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_devkitm.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay index a438cc5246b..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay +++ b/samples/basic/blinky_pwm/boards/esp32c3_luatos_core_usb.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay b/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay index 5709c54d180..a9a1d685e99 100644 --- a/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s2_saola.overlay @@ -6,7 +6,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay b/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay index c6ca7b5a52b..99d9e2d9bfd 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_devkitm.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay index 61152f82f94..70069ad3b10 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay index 61152f82f94..70069ad3b10 100644 --- a/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay +++ b/samples/basic/blinky_pwm/boards/esp32s3_luatos_core_usb.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/blinky_pwm/boards/wio_terminal.overlay b/samples/basic/blinky_pwm/boards/wio_terminal.overlay new file mode 100644 index 00000000000..cf60fe058b7 --- /dev/null +++ b/samples/basic/blinky_pwm/boards/wio_terminal.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +/{ + aliases { + pwm-led0 = &pwm_led0; + }; + + pwmleds { + compatible = "pwm-leds"; + pwm_led0: pwm_led_0 { + pwms = <&tcc1 3 PWM_MSEC(500)>; + label = "Blue PWM LED"; + }; + }; +}; + +&tcc1 { + status = "okay"; + compatible = "atmel,sam0-tcc-pwm"; + prescaler = <4>; + #pwm-cells = <2>; + + pinctrl-0 = <&pwm_default>; + pinctrl-names = "default"; +}; + +&pinctrl { + pwm_default: pwm_default { + group1 { + pinmux = ; + }; + }; +}; diff --git a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay index 045056613e0..86ffa3dcdf0 100644 --- a/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay +++ b/samples/basic/blinky_pwm/boards/xiao_esp32s3.overlay @@ -5,7 +5,6 @@ */ #include -#include / { aliases { diff --git a/samples/basic/hash_map/sample.yaml b/samples/basic/hash_map/sample.yaml index 40dec267473..9e1ee6558ca 100644 --- a/samples/basic/hash_map/sample.yaml +++ b/samples/basic/hash_map/sample.yaml @@ -16,8 +16,6 @@ common: type: one_line regex: - .*success - platform_exclude: - - esp32_net tests: diff --git a/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt b/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt new file mode 100644 index 00000000000..770ad7912f3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(broadcast_audio_assistant) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/broadcast_audio_assistant/Kconfig b/samples/bluetooth/broadcast_audio_assistant/Kconfig new file mode 100644 index 00000000000..9e01743a101 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/Kconfig @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Demant A/S +# SPDX-License-Identifier: Apache-2.0 + +mainmenu "Bluetooth: Broadcast Audio Assistant" + +config SELECT_SOURCE_NAME + string "Selected Broadcast Source name" + default "" + help + Name of broadcast source device to select. This will be used as a + substring matched against both BT device name and broadcast name. + If empty, the first broadcast source found will be chosen. + Matching is not case sensitive. + +config SELECT_SINK_NAME + string "Selected Broadcast Sink name" + default "" + help + Name of broadcast sink device to select. This will be used as a + substring matched against the BT device name. + If empty, the first broadcast sink found will be chosen. + Matching is not case sensitive. + +source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_assistant/README.rst b/samples/bluetooth/broadcast_audio_assistant/README.rst new file mode 100644 index 00000000000..faff37a6e22 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/README.rst @@ -0,0 +1,56 @@ +.. zephyr:code-sample:: bluetooth_broadcast_audio_assistant + :name: Bluetooth: Broadcast Audio Assistant + :relevant-api: bt_bap + + Use LE Audio Broadcast Assistant functionality + +Overview +******** + +Application demonstrating the LE Audio broadcast assistant functionality. + +The sample will automatically try to connect to a device in the BAP Scan Delegator +role (advertising support for the Broadcast Audio Scan Service (BASS)). +It will then search for a broadcast source and (if found) add the broadcast ID to +the BAP Scan Delegator. + +Practical use of this sample requires a sink (e.g. the Broadcast Audio Sink sample or +a set of LE Audio Broadcast capable earbuds) and a source (e.g. the Broadcast Audio +Source sample). + +This sample can be found under +:zephyr_file:`samples/bluetooth/broadcast_audio_assistant` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support +* Broadcast Audio Source and Sink devices + +Building and Running +******************** + +The application will act as a broadcast assistant with optionally preconfigured +filtering of broadcast sink and broadcast source names. By default, the application will +search for and connect to the first broadcast audio sink found (advertising PACS and +BASS UUIDs) and then search for and select the first broadcast audio source found +(advertising a broadcast ID). + +Filter these by modifying the following configs: + +``CONFIG_SELECT_SINK_NAME``: Substring of BT name of the sink. + +and + +``CONFIG_SELECT_SOURCE_NAME``: Substring of BT name or broadcast name of the source. + +Building for an nrf52840dk +-------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/broadcast_audio_assistant/ + :board: nrf52840dk_nrf52840 + :goals: build diff --git a/samples/bluetooth/broadcast_audio_assistant/prj.conf b/samples/bluetooth/broadcast_audio_assistant/prj.conf new file mode 100644 index 00000000000..df902e7917d --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/prj.conf @@ -0,0 +1,18 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_AUDIO=y +CONFIG_BT_SMP=y +CONFIG_BT_BONDABLE=n +CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191 + +CONFIG_BT_TINYCRYPT_ECC=y + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_BAP_BROADCAST_ASSISTANT=y + +# CONFIG_BT_BAP_SCAN_DELEGATOR=y is required until the following +# bug is fixed: https://github.com/zephyrproject-rtos/zephyr/issues/68338 +CONFIG_BT_BAP_SCAN_DELEGATOR=y diff --git a/samples/bluetooth/broadcast_audio_assistant/sample.yaml b/samples/bluetooth/broadcast_audio_assistant/sample.yaml new file mode 100644 index 00000000000..8481ebeeeb4 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/sample.yaml @@ -0,0 +1,11 @@ +sample: + description: Bluetooth Low Energy Broadcast Assistant sample + name: Bluetooth Low Energy Broadcast Assistant sample +tests: + sample.bluetooth.broadcast_audio_assistant: + harness: bluetooth + platform_allow: + - nrf52840dk_nrf52840 + integration_platforms: + - nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/broadcast_audio_assistant/src/main.c b/samples/bluetooth/broadcast_audio_assistant/src/main.c new file mode 100644 index 00000000000..1712255c3f3 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_assistant/src/main.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2024 Demant A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define NAME_LEN 30 + +/* Broadcast IDs are 24bit, so this is out of valid range */ +#define INVALID_BROADCAST_ID 0xFFFFFFFFU + +static void scan_for_broadcast_sink(void); + +/* Struct to collect information from scanning + * for Broadcast Source or Sink + */ +struct scan_recv_info { + char bt_name[NAME_LEN]; + char broadcast_name[NAME_LEN]; + uint32_t broadcast_id; + bool has_bass; + bool has_pacs; +}; + +static struct bt_conn *broadcast_sink_conn; +static uint32_t selected_broadcast_id; +static uint8_t selected_sid; +static uint16_t selected_pa_interval; +static bt_addr_le_t selected_addr; + +static bool scanning_for_broadcast_source; + +static K_SEM_DEFINE(sem_source_discovered, 0, 1); +static K_SEM_DEFINE(sem_sink_discovered, 0, 1); +static K_SEM_DEFINE(sem_sink_connected, 0, 1); +static K_SEM_DEFINE(sem_sink_disconnected, 0, 1); +static K_SEM_DEFINE(sem_security_updated, 0, 1); +static K_SEM_DEFINE(sem_bass_discovered, 0, 1); + +static bool device_found(struct bt_data *data, void *user_data) +{ + struct scan_recv_info *sr_info = (struct scan_recv_info *)user_data; + struct bt_uuid_16 adv_uuid; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + memcpy(sr_info->bt_name, data->data, MIN(data->data_len, NAME_LEN - 1)); + return true; + case BT_DATA_BROADCAST_NAME: + memcpy(sr_info->broadcast_name, data->data, MIN(data->data_len, NAME_LEN - 1)); + return true; + case BT_DATA_SVC_DATA16: + /* Check for Broadcast ID */ + if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO) != 0) { + return true; + } + + sr_info->broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + return true; + case BT_DATA_UUID16_SOME: + case BT_DATA_UUID16_ALL: + /* NOTE: According to the BAP 1.0.1 Spec, + * Section 3.9.2. Additional Broadcast Audio Scan Service requirements, + * If the Scan Delegator implements a Broadcast Sink, it should also + * advertise a Service Data field containing the Broadcast Audio + * Scan Service (BASS) UUID. + * + * However, it seems that this is not the case with the sinks available + * while developing this sample application. Therefore, we instead, + * search for the existence of BASS and PACS in the list of service UUIDs, + * which does seem to exist in the sinks available. + */ + + /* Check for BASS and PACS */ + if (data->data_len % sizeof(uint16_t) != 0U) { + printk("UUID16 AD malformed\n"); + return true; + } + + for (size_t i = 0; i < data->data_len; i += sizeof(uint16_t)) { + const struct bt_uuid *uuid; + uint16_t u16; + + memcpy(&u16, &data->data[i], sizeof(u16)); + uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16)); + + if (bt_uuid_cmp(uuid, BT_UUID_BASS)) { + sr_info->has_bass = true; + continue; + } + + if (bt_uuid_cmp(uuid, BT_UUID_PACS)) { + sr_info->has_pacs = true; + continue; + } + } + return true; + default: + return true; + } +} + +static bool is_substring(const char *substr, const char *str) +{ + const size_t str_len = strlen(str); + const size_t sub_str_len = strlen(substr); + + if (sub_str_len > str_len) { + return false; + } + + for (size_t pos = 0; pos < str_len; pos++) { + if (pos + sub_str_len > str_len) { + return false; + } + + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; + } + } + + return false; +} + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + int err; + struct scan_recv_info sr_info = {0}; + + if (scanning_for_broadcast_source) { + /* Scan for and select Broadcast Source */ + + sr_info.broadcast_id = INVALID_BROADCAST_ID; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0 || + info->interval == 0) { + return; + } + + bt_data_parse(ad, device_found, (void *)&sr_info); + + if (sr_info.broadcast_id != INVALID_BROADCAST_ID) { + printk("Broadcast Source Found:\n"); + printk(" BT Name: %s\n", sr_info.bt_name); + printk(" Broadcast Name: %s\n", sr_info.broadcast_name); + printk(" Broadcast ID: 0x%06x\n\n", sr_info.broadcast_id); + + if (strlen(CONFIG_SELECT_SOURCE_NAME) > 0U) { + /* Compare names with CONFIG_SELECT_SOURCE_NAME */ + if (is_substring(CONFIG_SELECT_SOURCE_NAME, sr_info.bt_name) || + is_substring(CONFIG_SELECT_SOURCE_NAME, + sr_info.broadcast_name)) { + printk("Match found for '%s'\n", CONFIG_SELECT_SOURCE_NAME); + } else { + printk("'%s' not found in names\n\n", + CONFIG_SELECT_SOURCE_NAME); + return; + } + } + + err = bt_le_scan_stop(); + if (err != 0) { + printk("bt_le_scan_stop failed with %d\n", err); + } + + /* TODO: Add support for syncing to the PA and parsing the BASE + * in order to obtain the right subgroup information to send to + * the sink when adding a broadcast source (see in main function below). + */ + + printk("Selecting Broadcast ID: 0x%06x\n", sr_info.broadcast_id); + + selected_broadcast_id = sr_info.broadcast_id; + selected_sid = info->sid; + selected_pa_interval = info->interval; + bt_addr_le_copy(&selected_addr, info->addr); + + k_sem_give(&sem_source_discovered); + } + } else { + /* Scan for and connect to Broadcast Sink */ + + /* We are only interested in connectable advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) { + return; + } + + bt_data_parse(ad, device_found, (void *)&sr_info); + + if (sr_info.has_bass && sr_info.has_pacs) { + printk("Broadcast Sink Found:\n"); + printk(" BT Name: %s\n", sr_info.bt_name); + + if (strlen(CONFIG_SELECT_SINK_NAME) > 0U) { + /* Compare names with CONFIG_SELECT_SINK_NAME */ + if (is_substring(CONFIG_SELECT_SINK_NAME, sr_info.bt_name)) { + printk("Match found for '%s'\n", CONFIG_SELECT_SINK_NAME); + } else { + printk("'%s' not found in names\n\n", + CONFIG_SELECT_SINK_NAME); + return; + } + } + + err = bt_le_scan_stop(); + if (err != 0) { + printk("bt_le_scan_stop failed with %d\n", err); + } + + printk("Connecting to Broadcast Sink: %s\n", sr_info.bt_name); + + err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, + &broadcast_sink_conn); + if (err != 0) { + printk("Failed creating connection (err=%u)\n", err); + scan_for_broadcast_sink(); + } + + k_sem_give(&sem_sink_discovered); + } + } +} + +static void scan_timeout_cb(void) +{ + printk("Scan timeout\n"); +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv_cb, + .timeout = scan_timeout_cb, +}; + +static void scan_for_broadcast_source(void) +{ + int err; + + scanning_for_broadcast_source = true; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning for Broadcast Source successfully started\n"); + + err = k_sem_take(&sem_source_discovered, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_source_discovered (err %d)\n", err); + } +} + +static void scan_for_broadcast_sink(void) +{ + int err; + + scanning_for_broadcast_source = false; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + + printk("Scanning for Broadcast Sink successfully started\n"); + + err = k_sem_take(&sem_sink_discovered, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_discovered (err %d)\n", err); + } +} + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + printk("Failed to connect to %s (%u)\n", addr, err); + + bt_conn_unref(broadcast_sink_conn); + broadcast_sink_conn = NULL; + + scan_for_broadcast_sink(); + return; + } + + if (conn != broadcast_sink_conn) { + return; + } + + printk("Connected: %s\n", addr); + k_sem_give(&sem_sink_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != broadcast_sink_conn) { + return; + } + + (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(broadcast_sink_conn); + broadcast_sink_conn = NULL; + + k_sem_give(&sem_sink_disconnected); +} + +static void security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) +{ + if (err == 0) { + printk("Security level changed: %u\n", level); + k_sem_give(&sem_security_updated); + } else { + printk("Failed to set security level: %u\n", err); + } +} + +static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, + uint8_t recv_state_count) +{ + if (err == 0) { + printk("BASS discover done with %u recv states\n", + recv_state_count); + k_sem_give(&sem_bass_discovered); + } else { + printk("BASS discover failed (%d)\n", err); + } +} + +static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) +{ + if (err == 0) { + printk("BASS add source successful\n"); + } else { + printk("BASS add source failed (%d)\n", err); + } +} + +static struct bt_bap_broadcast_assistant_cb ba_cbs = { + .discover = bap_broadcast_assistant_discover_cb, + .add_src = bap_broadcast_assistant_add_src_cb, +}; + +static void reset(void) +{ + printk("\n\nReset...\n\n"); + + broadcast_sink_conn = NULL; + selected_broadcast_id = INVALID_BROADCAST_ID; + selected_sid = 0; + selected_pa_interval = 0; + (void)memset(&selected_addr, 0, sizeof(selected_addr)); + + k_sem_reset(&sem_source_discovered); + k_sem_reset(&sem_sink_discovered); + k_sem_reset(&sem_sink_connected); + k_sem_reset(&sem_sink_disconnected); + k_sem_reset(&sem_security_updated); + k_sem_reset(&sem_bass_discovered); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed_cb +}; + +int main(void) +{ + int err; + struct bt_bap_scan_delegator_subgroup subgroup = { 0 }; + struct bt_bap_broadcast_assistant_add_src_param param = { 0 }; + + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + + bt_le_scan_cb_register(&scan_callbacks); + bt_bap_broadcast_assistant_register_cb(&ba_cbs); + + while (true) { + scan_for_broadcast_sink(); + + err = k_sem_take(&sem_sink_connected, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_connected (err %d)\n", err); + } + + err = bt_bap_broadcast_assistant_discover(broadcast_sink_conn); + if (err != 0) { + printk("Failed to discover BASS on the sink (err %d)\n", err); + } + + err = k_sem_take(&sem_security_updated, K_SECONDS(10)); + if (err != 0) { + printk("Failed to take sem_security_updated (err %d), resetting\n", err); + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_AUTH_FAIL); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + err = k_sem_take(&sem_bass_discovered, K_SECONDS(10)); + if (err != 0) { + if (err == -EAGAIN) { + printk("Failed to take sem_bass_discovered (err %d)\n", err); + } + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + /* TODO: Discover and parse the PACS on the sink and use the information + * when discovering and adding a source to the sink. + * Also, before populating the parameters to sync to the broadcast source + * first, parse the source BASE and determine if the sink supports the source. + * If not, then look for another source. + */ + + scan_for_broadcast_source(); + + /* FIX NEEDED: It should be valid to assign BT_BAP_BIS_SYNC_NO_PREF + * to bis_sync, but currently (2024-01-30), the broadcast_audio_sink + * sample seems to reject it (err=19) while other sinks don't. + * + * Also, if the source contains more than one stream (e.g. stereo), + * some sinks have been observed to have issues. In this case, + * set only one bit in bis_sync, e.g. subgroup.bis_sync = BIT(1). + * + * When PA sync and BASE is parsed (see note in the scan_recv_cb function), + * the available bits can be used for proper selection. + */ + subgroup.bis_sync = BT_BAP_BIS_SYNC_NO_PREF; + + bt_addr_le_copy(¶m.addr, &selected_addr); + param.adv_sid = selected_sid; + param.pa_interval = selected_pa_interval; + param.broadcast_id = selected_broadcast_id; + param.pa_sync = true; + + /* TODO: Obtain the and set the correct subgroup information. + * See above in the broadcast audio source discovery part + * of the scan_recv_cb function. + */ + param.num_subgroups = 1; + param.subgroups = &subgroup; + + err = bt_bap_broadcast_assistant_add_src(broadcast_sink_conn, ¶m); + if (err) { + printk("Failed to add source: %d\n", err); + bt_conn_disconnect(broadcast_sink_conn, BT_HCI_ERR_UNSUPP_REMOTE_FEATURE); + + if (k_sem_take(&sem_sink_disconnected, K_SECONDS(10)) != 0) { + /* This should not happen */ + return -ETIMEDOUT; + } + + reset(); + continue; + } + + /* Reset if the sink disconnects */ + err = k_sem_take(&sem_sink_disconnected, K_FOREVER); + if (err != 0) { + printk("Failed to take sem_sink_disconnected (err %d)\n", err); + } + + reset(); + } + + return 0; +} diff --git a/samples/bluetooth/broadcast_audio_sink/Kconfig b/samples/bluetooth/broadcast_audio_sink/Kconfig index b70a42e2d99..e24193fccad 100644 --- a/samples/bluetooth/broadcast_audio_sink/Kconfig +++ b/samples/bluetooth/broadcast_audio_sink/Kconfig @@ -43,4 +43,25 @@ config ENABLE_LC3 select LIBLC3 select FPU +config USE_USB_AUDIO_OUTPUT + bool "Use USB Audio as output" + depends on ENABLE_LC3 + select USB_DEVICE_STACK + select USB_DEVICE_AUDIO + select RING_BUFFER + help + Enables USB audio as output as a USB peripheral. This does not support providing USB + audio to e.g. speakers that are also USB peripherals, but can be connected to e.g. a + phone or PC as a USB-in device (such as a USB microphone). + USB audio only supports a single audio channel. + +config TARGET_BROADCAST_CHANNEL + int "Broadcast Channel Audio Location to sync to" + range 0 2 + default 1 + depends on USE_USB_AUDIO_OUTPUT + help + Channel Audio Location to sync to. These corresponds to the bt_audio_location, + supporting mono, left and right channels + source "Kconfig.zephyr" diff --git a/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index 8ab7a163fb6..f8f7db343e8 100644 --- a/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -1,3 +1,7 @@ # The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence # inctease stack size for that thread. CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_ENABLE_LC3=y +CONFIG_TARGET_BROADCAST_CHANNEL=1 +CONFIG_USE_USB_AUDIO_OUTPUT=y +CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" diff --git a/samples/bluetooth/broadcast_audio_sink/src/main.c b/samples/bluetooth/broadcast_audio_sink/src/main.c index 6b519b715f6..f2f1b2c646a 100644 --- a/samples/bluetooth/broadcast_audio_sink/src/main.c +++ b/samples/bluetooth/broadcast_audio_sink/src/main.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,15 @@ #include #include #include +#if defined(CONFIG_LIBLC3) +#include "lc3.h" +#endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) +#include +#include +#include +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), "Either SCAN_SELF or SCAN_OFFLOAD must be enabled"); @@ -30,6 +40,28 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD), #define PA_SYNC_SKIP 5 #define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1 +#if defined(CONFIG_LIBLC3) +#define MAX_SAMPLE_RATE 48000U +#define MAX_FRAME_DURATION_US 10000U +#define MAX_NUM_SAMPLES_MONO ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) +#define MAX_NUM_SAMPLES_STEREO (MAX_NUM_SAMPLES_MONO * 2) + +#define LC3_ENCODER_STACK_SIZE 4096 +#define LC3_ENCODER_PRIORITY 5 +#endif /* defined(CONFIG_LIBLC3) */ + +#if defined(CONFIG_USB_DEVICE_AUDIO) +#define USB_SAMPLE_RATE 48000U +#define USB_FRAME_DURATION_US 1000U +#define USB_TX_BUF_NUM 10U +#define BROADCAST_DATA_ELEMENT_SIZE sizeof(int16_t) +#define BROADCAST_MONO_SAMPLE_SIZE (MAX_NUM_SAMPLES_MONO * BROADCAST_DATA_ELEMENT_SIZE) +#define BROADCAST_STEREO_SAMPLE_SIZE (BROADCAST_MONO_SAMPLE_SIZE * BROADCAST_DATA_ELEMENT_SIZE) +#define USB_STEREO_SAMPLE_SIZE ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE * \ + BROADCAST_DATA_ELEMENT_SIZE * 2) / USEC_PER_SEC) +#define AUDIO_RING_BUF_SIZE 10000U +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + static K_SEM_DEFINE(sem_connected, 0U, 1U); static K_SEM_DEFINE(sem_disconnected, 0U, 1U); static K_SEM_DEFINE(sem_broadcaster_found, 0U, 1U); @@ -52,6 +84,7 @@ static struct bt_le_per_adv_sync *pa_sync; static uint32_t broadcaster_broadcast_id; static struct broadcast_sink_stream { struct bt_bap_stream stream; + bool has_data; size_t recv_cnt; size_t loss_cnt; size_t error_cnt; @@ -61,7 +94,14 @@ static struct broadcast_sink_stream { struct k_work_delayable lc3_decode_work; /* Internal lock for protecting net_buf from multiple access */ struct k_mutex lc3_decoder_mutex; + lc3_decoder_t lc3_decoder; + lc3_decoder_mem_48k_t lc3_decoder_mem; #endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) + struct ring_buf audio_ring_buf; + uint8_t _ring_buffer[AUDIO_RING_BUF_SIZE]; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + } streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; static struct bt_conn *broadcast_assistant_conn; @@ -83,70 +123,77 @@ static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE]; uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */ -#if defined(CONFIG_LIBLC3) +#if defined(CONFIG_USB_DEVICE_AUDIO) +static int16_t usb_audio_data[MAX_NUM_SAMPLES_STEREO] = {0}; +static int16_t usb_audio_data_stereo[MAX_NUM_SAMPLES_STEREO] = {0}; -#include "lc3.h" +RING_BUF_DECLARE(ring_buf_usb, AUDIO_RING_BUF_SIZE); +NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_TX_BUF_NUM, BROADCAST_STEREO_SAMPLE_SIZE, 0, + net_buf_destroy); -#define MAX_SAMPLE_RATE 16000 -#define MAX_FRAME_DURATION_US 10000 -#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC) +static void mix_mono_to_stereo(enum bt_audio_location channels); +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ -static int16_t audio_buf[MAX_NUM_SAMPLES]; -static lc3_decoder_t lc3_decoder; -static lc3_decoder_mem_16k_t lc3_decoder_mem; +#if defined(CONFIG_LIBLC3) +static int16_t audio_buf[MAX_NUM_SAMPLES_MONO]; static int frames_per_sdu; +static K_SEM_DEFINE(lc3_decoder_sem, 0, 1); -static int lc3_enable(const struct bt_audio_codec_cfg *codec_cfg) -{ - int ret; - int freq_hz; - int frame_duration_us; +static void do_lc3_decode(struct broadcast_sink_stream *sink_stream); +static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3); +K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread, + NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1); - printk("Enable: stream with codec %p\n", codec_cfg); +/* Consumer thread of the decoded stream data */ +static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3) +{ + while (true) { + k_sem_take(&lc3_decoder_sem, K_FOREVER); +#if defined(CONFIG_USB_DEVICE_AUDIO) + int err = 0; + enum bt_audio_location channels; + struct broadcast_sink_stream *stream_for_usb = &streams[0]; + + /* For now we only handle one BIS, so always only decode the first element in + * streams. + */ + do_lc3_decode(&streams[0]); - ret = bt_audio_codec_cfg_get_freq(codec_cfg); - if (ret > 0) { - freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); - } else { - printk("Error: Codec frequency not set, cannot start codec."); - return -1; - } + err = bt_audio_codec_cfg_get_chan_allocation(stream_for_usb->stream.codec_cfg, + &channels); + if (err != 0) { + printk("Could not get channel allocation (err=%d)\n", err); + continue; + } - ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); - if (ret > 0) { - frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); - } else { - printk("Error: Frame duration not set, cannot start codec."); - return ret; + /* If the ring buffer usage is larger than zero, then there is data to process */ + if (ring_buf_space_get(&stream_for_usb->audio_ring_buf)) { + mix_mono_to_stereo(channels); + } +#else + for (size_t i = 0; i < ARRAY_SIZE(streams); i++) { + if (streams[i].has_data) { + do_lc3_decode(&streams[i]); + } } - frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); - - lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, /* No resampling */ - &lc3_decoder_mem); - - if (lc3_decoder == NULL) { - printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n"); - return -1; +#endif /* #if defined(CONFIG_USB_DEVICE_AUDIO) */ } - - return 0; } -static void lc3_decode_handler(struct k_work *work) +static void do_lc3_decode(struct broadcast_sink_stream *sink_stream) { int err = 0; int offset = 0; uint8_t *buf_data; struct net_buf *ptr_net_buf; int octets_per_frame; - struct broadcast_sink_stream *sink_stream = CONTAINER_OF( - k_work_delayable_from_work(work), struct broadcast_sink_stream, lc3_decode_work); k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER); + sink_stream->has_data = false; + if (sink_stream->in_buf == NULL) { - printk("buf data is NULL, nothing to be docoded\n"); k_mutex_unlock(&sink_stream->lc3_decoder_mutex); return; } @@ -160,23 +207,182 @@ static void lc3_decode_handler(struct k_work *work) octets_per_frame = ptr_net_buf->len / frames_per_sdu; for (int i = 0; i < frames_per_sdu; i++) { - err = lc3_decode(lc3_decoder, buf_data + offset, octets_per_frame, - LC3_PCM_FORMAT_S16, audio_buf, 1); + err = lc3_decode(sink_stream->lc3_decoder, buf_data + offset, octets_per_frame, + LC3_PCM_FORMAT_S16, audio_buf, 1); if (err == 1) { printk(" decoder performed PLC\n"); } else if (err < 0) { - printk(" decoder failed - wrong parameters?\n"); + printk(" decoder failed - wrong parameters? (err = %d)\n", err); } offset += octets_per_frame; } net_buf_unref(ptr_net_buf); + +#if defined(CONFIG_USB_DEVICE_AUDIO) + uint32_t rbret; + + if (ring_buf_space_get(&sink_stream->audio_ring_buf) == 0) { + /* Since the data in the buffer is old by now, and we add enough data for many + * request to consume at a time, just erase what is already in the buffer. + */ + ring_buf_reset(&sink_stream->audio_ring_buf); + } + + /* Put in ring-buffer to be consumed */ + rbret = ring_buf_put(&sink_stream->audio_ring_buf, (uint8_t *)audio_buf, + BROADCAST_MONO_SAMPLE_SIZE); + if (rbret != BROADCAST_MONO_SAMPLE_SIZE) { + static int rb_add_failures; + + rb_add_failures++; + if (rb_add_failures % 1000 == 0) { + printk("Failure to add to ring buffer %d, %u\n", rb_add_failures, rbret); + } + return; + } +#endif /*#if defined(CONFIG_USB_DEVICE_AUDIO)*/ } +static int lc3_enable(struct broadcast_sink_stream *sink_stream) +{ + int ret; + int freq_hz; + int frame_duration_us; + + printk("Enable: stream with codec %p\n", sink_stream->stream.codec_cfg); + + ret = bt_audio_codec_cfg_get_freq(sink_stream->stream.codec_cfg); + if (ret > 0) { + freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret); + } else { + printk("Error: Codec frequency not set, cannot start codec."); + return -1; + } + + ret = bt_audio_codec_cfg_get_frame_dur(sink_stream->stream.codec_cfg); + if (ret > 0) { + frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); + } else { + printk("Error: Frame duration not set, cannot start codec."); + return ret; + } + + frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(sink_stream->stream.codec_cfg, + true); + +#if defined(CONFIG_USB_DEVICE_AUDIO) + sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, USB_SAMPLE_RATE, + &sink_stream->lc3_decoder_mem); +#else + sink_stream->lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, + &sink_stream->lc3_decoder_mem); +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + + if (sink_stream->lc3_decoder == NULL) { + printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n"); + return -1; + } + + k_thread_start(decoder_tid); + + return 0; +} #endif /* defined(CONFIG_LIBLC3) */ +#if defined(CONFIG_USB_DEVICE_AUDIO) +static uint8_t get_channel_index(const enum bt_audio_location allocated_channels, + const enum bt_audio_location channel) +{ + /* If we are looking for the right channel, and left channel is present, then the index is + * 1. For all other combinations the index has to be 0, since it would mean that it is the + * lowest possible bit enumeration + */ + if (channel == BT_AUDIO_LOCATION_FRONT_RIGHT && + allocated_channels & BT_AUDIO_LOCATION_FRONT_LEFT) { + return 1; + } + + return 0; +} + +/* Duplicate the audio from one channel and put it in both channels */ +static void mix_mono_to_stereo(enum bt_audio_location channels) +{ + uint32_t size; + uint8_t cidx; + + size = ring_buf_get(&streams[0].audio_ring_buf, (uint8_t *)usb_audio_data, + MAX_NUM_SAMPLES_STEREO); + if (size != MAX_NUM_SAMPLES_STEREO) { + memset(&((uint8_t *)usb_audio_data)[size], 0, sizeof(usb_audio_data) - size); + } + + cidx = get_channel_index(channels, CONFIG_TARGET_BROADCAST_CHANNEL); + + /* Interleave the channel sample */ + for (size_t i = 0U; i < MAX_NUM_SAMPLES_MONO; i++) { + usb_audio_data_stereo[i * 2] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i]; + usb_audio_data_stereo[i * 2 + 1] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i]; + } + + size = ring_buf_put(&ring_buf_usb, (uint8_t *)usb_audio_data_stereo, + BROADCAST_STEREO_SAMPLE_SIZE); + if (size != BROADCAST_STEREO_SAMPLE_SIZE) { + static int rb_put_failures; + + rb_put_failures++; + if (rb_put_failures == 1000) { + printk("%s: Failure to add to ring buffer %d, %u\n", __func__, + rb_put_failures, size); + rb_put_failures = 0; + } + } +} + +/* USB consumer callback, called every 1ms, consumes data from ring-buffer */ +static void data_request(const struct device *dev) +{ + static struct net_buf *pcm_buf; + int err; + uint32_t size; + void *out; + int16_t usb_audio_data[USB_STEREO_SAMPLE_SIZE] = {0}; + + size = ring_buf_get(&ring_buf_usb, (uint8_t *)usb_audio_data, USB_STEREO_SAMPLE_SIZE); + if (size != USB_STEREO_SAMPLE_SIZE) { + memset(&((uint8_t *)usb_audio_data)[size], 0, USB_STEREO_SAMPLE_SIZE); + } + + pcm_buf = net_buf_alloc(&usb_tx_buf_pool, K_NO_WAIT); + if (pcm_buf == NULL) { + printk("Couldnt allocate pcm_buf\n"); + return; + } + + out = net_buf_add(pcm_buf, USB_STEREO_SAMPLE_SIZE); + memcpy(out, usb_audio_data, USB_STEREO_SAMPLE_SIZE); + + err = usb_audio_send(dev, pcm_buf, USB_STEREO_SAMPLE_SIZE); + if (err) { + net_buf_unref(pcm_buf); + } +} + +static void data_written(const struct device *dev, struct net_buf *buf, size_t size) +{ + /* Unreference the buffer now that the USB is done with it */ + net_buf_unref(buf); +} + +static const struct usb_audio_ops ops = { + .data_request_cb = data_request, + .data_written_cb = data_written, +}; +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + static void stream_started_cb(struct bt_bap_stream *stream) { struct broadcast_sink_stream *sink_stream = @@ -190,9 +396,23 @@ static void stream_started_cb(struct bt_bap_stream *stream) sink_stream->valid_cnt = 0U; sink_stream->error_cnt = 0U; + #if defined(CONFIG_LIBLC3) - k_work_init_delayable(&sink_stream->lc3_decode_work, lc3_decode_handler); -#endif /* defined(CONFIG_LIBLC3) */ + int err; + + if (stream->codec_cfg != 0 && stream->codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { + /* No subgroups with LC3 was found */ + printk("Did not parse an LC3 codec\n"); + return; + } + + err = lc3_enable(sink_stream); + if (err < 0) { + printk("Error: cannot enable LC3 codec: %d", err); + return; + } +#endif /* CONFIG_LIBLC3 */ + k_sem_give(&sem_bis_synced); } @@ -233,7 +453,8 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec sink_stream->in_buf = net_buf_ref(buf); k_mutex_unlock(&sink_stream->lc3_decoder_mutex); - k_work_schedule(&sink_stream->lc3_decode_work, K_NO_WAIT); + sink_stream->has_data = true; + k_sem_give(&lc3_decoder_sem); #endif /* defined(CONFIG_LIBLC3) */ } @@ -252,46 +473,90 @@ static struct bt_bap_stream_ops stream_ops = { .recv = stream_recv_cb, }; -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +#if defined(CONFIG_TARGET_BROADCAST_CHANNEL) +static bool find_valid_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) { - uint32_t base_bis_index_bitfield = 0U; + int err; + struct bt_audio_codec_cfg codec_cfg = {0}; + enum bt_audio_location chan_allocation; + uint8_t *bis_index = user_data; - if (k_sem_count_get(&sem_base_received) != 0U) { - return; + err = bt_bap_base_subgroup_bis_codec_to_codec_cfg(bis, &codec_cfg); + if (err != 0) { + printk("Could not find codec configuration (err=%d)\n", err); + return true; } - printk("Received BASE with %u subgroups from broadcast sink %p\n", - base->subgroup_count, sink); + err = bt_audio_codec_cfg_get_chan_allocation(&codec_cfg, &chan_allocation); + if (err != 0) { + printk("Could not find channel allocation (err=%d)\n", err); + return true; + } - for (size_t i = 0U; i < base->subgroup_count; i++) { - const size_t bis_count = base->subgroups[i].bis_count; + if (((CONFIG_TARGET_BROADCAST_CHANNEL) == BT_AUDIO_LOCATION_MONO_AUDIO && + chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) || + chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) { + *bis_index = bis->index; - printk("Subgroup[%zu] has %zu streams\n", i, bis_count); + return false; + } - for (size_t j = 0U; j < bis_count; j++) { - const uint8_t index = base->subgroups[i].bis_data[j].index; + return true; +} - printk("\tIndex 0x%02x\n", index); +static bool find_valid_bis_in_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + return bt_bap_base_subgroup_foreach_bis(subgroup, find_valid_bis_cb, user_data) + == -ECANCELED ? false : true; +} - base_bis_index_bitfield |= BIT(index); - } -#if defined(CONFIG_LIBLC3) - int ret; - const struct bt_audio_codec_cfg *codec_cfg = &base->subgroups[i].codec_cfg; +static int base_get_first_valid_bis(const struct bt_bap_base *base, uint32_t *bis_index) +{ + int err; + uint8_t valid_bis_index = 0U; - if (codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) { - printk("unsupported codec 0x%02x", codec_cfg->id); - return; - } + err = bt_bap_base_foreach_subgroup(base, find_valid_bis_in_subgroup_cb, &valid_bis_index); + if (err != -ECANCELED) { + printk("Failed to parse subgroups: %d\n", err); + return err != 0 ? err : -ENOENT; + } - ret = lc3_enable(codec_cfg); - if (ret < 0) { - printk("Error: cannot enable LC3 codec: %d", ret); - return; - } -#endif /* defined(CONFIG_LIBLC3) */ + *bis_index = 0; + *bis_index |= ((uint8_t)1 << valid_bis_index); + + return 0; +} +#endif /* CONFIG_TARGET_BROADCAST_CHANNEL */ + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + uint32_t base_bis_index_bitfield = 0U; + int err; + + if (k_sem_count_get(&sem_base_received) != 0U) { + return; } + printk("Received BASE with %d subgroups from broadcast sink %p\n", + bt_bap_base_get_subgroup_count(base), sink); + +#if defined(CONFIG_TARGET_BROADCAST_CHANNEL) + err = base_get_first_valid_bis(base, &base_bis_index_bitfield); + if (err != 0) { + printk("Failed to find a valid BIS\n"); + return; + } +#else + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + printk("Failed to BIS indexes: %d\n", err); + return; + } +#endif /* CONFIG_TARGET_BROADCAST_CHANNEL */ + bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; if (broadcast_assistant_conn == NULL) { @@ -591,14 +856,12 @@ static bool is_substring(const char *substr, const char *str) } for (size_t pos = 0; pos < str_len; pos++) { - if (tolower(substr[pos]) == tolower(str[pos])) { - if (pos + sub_str_len > str_len) { - return false; - } + if (pos + sub_str_len > str_len) { + return false; + } - if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { - return true; - } + if (strncasecmp(substr, &str[pos], sub_str_len) == 0) { + return true; } } @@ -696,6 +959,29 @@ static int init(void) streams[i].stream.ops = &stream_ops; } + /* Initialize ring buffers and USB */ +#if defined(CONFIG_USB_DEVICE_AUDIO) + int ret; + const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); + + for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT; i++) { + ring_buf_init(&streams[i].audio_ring_buf, AUDIO_RING_BUF_SIZE, + streams[i]._ring_buffer); + } + + if (!device_is_ready(hs_dev)) { + printk("Cannot get USB Headset Device\n"); + return -EIO; + } + + usb_audio_register(hs_dev, &ops); + ret = usb_enable(NULL); + if (ret != 0) { + printk("Failed to enable USB\n"); + return err; + } +#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ + return 0; } diff --git a/samples/bluetooth/broadcast_audio_source/Kconfig b/samples/bluetooth/broadcast_audio_source/Kconfig index d88378d0848..683eeaf9dbf 100644 --- a/samples/bluetooth/broadcast_audio_source/Kconfig +++ b/samples/bluetooth/broadcast_audio_source/Kconfig @@ -24,7 +24,8 @@ config ENABLE_LC3 bool "Enable the LC3 codec" # By default let's enable it in the platforms we know are capable of supporting it default y - depends on (ARCH_POSIX || SOC_NRF5340_CPUAPP) + depends on CPU_HAS_FPU && \ + (ARCH_POSIX || SOC_COMPATIBLE_NRF52X || SOC_COMPATIBLE_NRF5340_CPUAPP) select LIBLC3 select FPU diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf new file mode 100644 index 00000000000..ff68bab6356 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.conf @@ -0,0 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=4096 + +# Use USB Audio as input +CONFIG_USE_USB_AUDIO_INPUT=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 00000000000..b8e72f1b61c --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,15 @@ +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + hs_0: hs_0 { + compatible = "usb-audio-hs"; + mic-feature-mute; + mic-channel-l; + mic-channel-r; + + hp-feature-mute; + hp-channel-l; + hp-channel-r; + }; +}; diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf new file mode 100644 index 00000000000..ff68bab6356 --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.conf @@ -0,0 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=4096 + +# Use USB Audio as input +CONFIG_USE_USB_AUDIO_INPUT=y +CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay new file mode 100644 index 00000000000..b8e72f1b61c --- /dev/null +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf52840dongle_nrf52840.overlay @@ -0,0 +1,15 @@ +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + hs_0: hs_0 { + compatible = "usb-audio-hs"; + mic-feature-mute; + mic-channel-l; + mic-channel-r; + + hp-feature-mute; + hp-channel-l; + hp-channel-r; + }; +}; diff --git a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index ff8004f0dc0..ff68bab6356 100644 --- a/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/broadcast_audio_source/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -3,6 +3,3 @@ CONFIG_MAIN_STACK_SIZE=4096 # Use USB Audio as input CONFIG_USE_USB_AUDIO_INPUT=y CONFIG_USB_DEVICE_PRODUCT="Zephyr Broadcast Source" - -# Two streams in one subgroup (stereo) -CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 diff --git a/samples/bluetooth/broadcast_audio_source/prj.conf b/samples/bluetooth/broadcast_audio_source/prj.conf index d74cbbe50ce..746b7fff423 100644 --- a/samples/bluetooth/broadcast_audio_source/prj.conf +++ b/samples/bluetooth/broadcast_audio_source/prj.conf @@ -7,9 +7,10 @@ CONFIG_BT_BAP_BROADCAST_SOURCE=y CONFIG_BT_ISO_MAX_CHAN=2 CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 -CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=2 -CONFIG_BT_ISO_TX_BUF_COUNT=4 +# Two streams in one subgroup (stereo) +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 +CONFIG_BT_ISO_TX_BUF_COUNT=6 CONFIG_BT_ISO_TX_MTU=60 CONFIG_BT_DEVICE_NAME="Broadcast Audio Source" diff --git a/samples/bluetooth/broadcast_audio_source/sample.yaml b/samples/bluetooth/broadcast_audio_source/sample.yaml index 1c27238c35f..3c554803409 100644 --- a/samples/bluetooth/broadcast_audio_source/sample.yaml +++ b/samples/bluetooth/broadcast_audio_source/sample.yaml @@ -20,8 +20,10 @@ tests: - nrf52_bsim - nrf52833dk_nrf52820 - nrf52833dk_nrf52833 + - nrf52840dongle_nrf52840 integration_platforms: - nrf52_bsim - nrf52833dk_nrf52833 + - nrf52840dongle_nrf52840 extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf tags: bluetooth diff --git a/samples/bluetooth/broadcast_audio_source/src/main.c b/samples/bluetooth/broadcast_audio_source/src/main.c index 8a129e3f361..ee343f5123f 100644 --- a/samples/bluetooth/broadcast_audio_source/src/main.c +++ b/samples/bluetooth/broadcast_audio_source/src/main.c @@ -25,7 +25,7 @@ /* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that * the controller is never idle */ -#define BROADCAST_ENQUEUE_COUNT 2U +#define BROADCAST_ENQUEUE_COUNT 3U #define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT) BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED, @@ -98,7 +98,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415f / sine_period_samples; for (unsigned int i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } @@ -145,7 +145,7 @@ static int frame_duration_us; static int frames_per_sdu; static int octets_per_frame; -static K_SEM_DEFINE(lc3_encoder_sem, 0U, ARRAY_SIZE(streams)); +static K_SEM_DEFINE(lc3_encoder_sem, 0U, TOTAL_BUF_NEEDED); #endif static void send_data(struct broadcast_source_stream *source_stream) @@ -465,10 +465,11 @@ int main(void) usb_audio_register(hs_dev, &ops); err = usb_enable(NULL); - if (err) { - printk("Failed to enable USB"); + if (err && err != -EALREADY) { + printk("Failed to enable USB (%d)", err); return 0; } + #endif /* defined(CONFIG_USB_DEVICE_AUDIO) */ k_thread_start(encoder); #endif /* defined(CONFIG_LIBLC3) */ diff --git a/samples/bluetooth/central_gatt_write/src/gatt_write_common.c b/samples/bluetooth/central_gatt_write/src/gatt_write_common.c index 58c8c58f50f..7deecd11219 100644 --- a/samples/bluetooth/central_gatt_write/src/gatt_write_common.c +++ b/samples/bluetooth/central_gatt_write/src/gatt_write_common.c @@ -27,6 +27,11 @@ static void write_cmd_cb(struct bt_conn *conn, void *user_data) delta = k_cycle_get_32() - cycle_stamp; delta = k_cyc_to_ns_floor64(delta); + if (delta == 0) { + /* Skip division by zero */ + return; + } + /* if last data rx-ed was greater than 1 second in the past, * reset the metrics. */ diff --git a/samples/bluetooth/central_hr/src/main.c b/samples/bluetooth/central_hr/src/main.c index ecb262c8517..305066bccd6 100644 --- a/samples/bluetooth/central_hr/src/main.c +++ b/samples/bluetooth/central_hr/src/main.c @@ -113,7 +113,7 @@ static bool eir_found(struct bt_data *data, void *user_data) for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { struct bt_le_conn_param *param; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/central_ht/src/main.c b/samples/bluetooth/central_ht/src/main.c index f2396115cc2..cc9bdae61c1 100644 --- a/samples/bluetooth/central_ht/src/main.c +++ b/samples/bluetooth/central_ht/src/main.c @@ -174,7 +174,7 @@ static bool eir_found(struct bt_data *data, void *user_data) } for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/central_otc/src/main.c b/samples/bluetooth/central_otc/src/main.c index 5dd9412ff65..7c2c659f510 100644 --- a/samples/bluetooth/central_otc/src/main.c +++ b/samples/bluetooth/central_otc/src/main.c @@ -237,7 +237,7 @@ static bool eir_found(struct bt_data *data, void *user_data) for (i = 0; i < data->data_len; i += sizeof(uint16_t)) { struct bt_le_conn_param *param; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t u16; int err; diff --git a/samples/bluetooth/direct_adv/src/main.c b/samples/bluetooth/direct_adv/src/main.c index d93f77083eb..c8ebda0df9b 100644 --- a/samples/bluetooth/direct_adv/src/main.c +++ b/samples/bluetooth/direct_adv/src/main.c @@ -23,13 +23,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); static int signed_value; diff --git a/samples/bluetooth/eddystone/src/main.c b/samples/bluetooth/eddystone/src/main.c index ff4ab59cd9c..86a99aaac4c 100644 --- a/samples/bluetooth/eddystone/src/main.c +++ b/samples/bluetooth/eddystone/src/main.c @@ -40,55 +40,55 @@ static const struct bt_data ad[] = { /* Eddystone Service Variables */ /* Service UUID a3c87500-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87500, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87501-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_caps_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_caps_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87501, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87502-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_slot_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_slot_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87502, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87503-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_intv_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_intv_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87503, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87504-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_tx_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_tx_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87504, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87505-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_adv_tx_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_adv_tx_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87505, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87506-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_lock_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_lock_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87506, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87507-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_unlock_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_unlock_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87507, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87508-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_ecdh_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_ecdh_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87508, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c87509-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_eid_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_eid_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c87509, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750a-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_data_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_data_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750a, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750b-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_reset_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_reset_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750b, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); /* Characteristic UUID a3c8750c-8ed3-4bdf-8a39-a01bebede295 */ -static struct bt_uuid_128 eds_connectable_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 eds_connectable_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0xa3c8750c, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295)); enum { diff --git a/samples/bluetooth/extended_adv/README.rst b/samples/bluetooth/extended_adv/README.rst new file mode 100644 index 00000000000..c5c402818e6 --- /dev/null +++ b/samples/bluetooth/extended_adv/README.rst @@ -0,0 +1,96 @@ +.. _bluetooth_extended_advertising_sample: + +Bluetooth: Extended Advertising +################################ + +Overview +******** + +This sample demonstrates the use of the extended advertising feature, by: + +- Outlining the steps required to initialize an extended advertising application. +- Demo how to gracefully restart the functionality, after a disconnect. + +The sample consists of the advertiser initiating a connectable advertisement set, +which prompts the scanner to connect after scanning for extended advertisements. +Once the connection is established, the advertiser waits for 5 seconds to disconnect. +After the connection is dropped, the advertiser immediately restarts broadcasting, +while the scanner cools-down for 5 seconds to restart its process. + +This sample handles all actions in a separate thread, to promote good design +practices. Even though it is not strictly required, scheduling from another context is +strongly recommended (e.g. using a work item), as re-starting an advertiser or +scanner from within the `recycled` callback exposes the application to deadlocking. + +Requirements +************ + +* Two boards with Bluetooth Low Energy support + +Building and Running +******************** + +This sample can be found under +:zephyr_file:`samples/bluetooth/extended_adv` in the Zephyr tree. + +See :ref:`bluetooth samples section ` for details. + +This sample uses two applications, so two devices need to be setup. +Flash one device with the scanner application, and another device with the +advertiser application. + +The two devices should automatically connect if they are close enough. + +Here are the outputs you should get by default: + +Advertiser: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4935-gfc7972183da5 *** + Starting Extended Advertising Demo + Starting Extended Advertising + Connected (err 0x00) + Connected state! + Initiating disconnect within 5 seconds... + Disconnected (reason 0x16) + Connection object available from previous conn. Disconnect is complete! + Disconnected state! Restarting advertising + Starting Extended Advertising + Connected (err 0x00) + Connected state! + Initiating disconnect within 5 seconds... + Disconnected (reason 0x16) + Connection object available from previous conn. Disconnect is complete! + Disconnected state! Restarting advertising + Starting Extended Advertising + +Scanner: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4935-ge3308caf97bc *** + Starting Extended Advertising Demo [Scanner] + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! + Starting to scan for extended adv + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! + Starting to scan for extended adv + Found extended advertisement packet! + Stopping scan + Connected (err 0x00) + Connected state! + Disconnected (reason 0x13) + Recycled cb called! + Disconnected, cooldown for 5 seconds! diff --git a/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt b/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt new file mode 100644 index 00000000000..b710615679e --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(extended_adv) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/extended_adv/advertiser/prj.conf b/samples/bluetooth/extended_adv/advertiser/prj.conf new file mode 100644 index 00000000000..0c352e3950f --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/prj.conf @@ -0,0 +1,6 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="test_ext_adv" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y diff --git a/samples/bluetooth/extended_adv/advertiser/sample.yaml b/samples/bluetooth/extended_adv/advertiser/sample.yaml new file mode 100644 index 00000000000..06b723062ce --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth Extended Advertising Advertiser +tests: + sample.bluetooth.extended_advertising.advertiser: + harness: bluetooth + platform_allow: nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/extended_adv/advertiser/src/main.c b/samples/bluetooth/extended_adv/advertiser/src/main.c new file mode 100644 index 00000000000..915e61b9366 --- /dev/null +++ b/samples/bluetooth/extended_adv/advertiser/src/main.c @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static struct bt_conn *default_conn; + +enum bt_sample_adv_evt { + BT_SAMPLE_EVT_CONNECTED, + BT_SAMPLE_EVT_DISCONNECTED, + BT_SAMPLE_EVT_MAX, +}; + +enum bt_sample_adv_st { + BT_SAMPLE_ST_ADV, + BT_SAMPLE_ST_CONNECTED, +}; + +static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX); + +static volatile enum bt_sample_adv_st app_st = BT_SAMPLE_ST_ADV; + +static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig); +static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &poll_sig); + +static void raise_evt(enum bt_sample_adv_evt evt) +{ + (void)atomic_set_bit(evt_bitmask, evt); + k_poll_signal_raise(poll_evt.signal, 1); +} + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + printk("Connected (err 0x%02X)\n", err); + + if (err) { + return; + } + + __ASSERT(!default_conn, "Attempting to override existing connection object!"); + default_conn = bt_conn_ref(conn); + + raise_evt(BT_SAMPLE_EVT_CONNECTED); +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + printk("Disconnected (reason 0x%02X)\n", reason); + + __ASSERT(conn == default_conn, "Unexpected disconnected callback"); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +static void recycled_cb(void) +{ + printk("Connection object available from previous conn. Disconnect is complete!\n"); + raise_evt(BT_SAMPLE_EVT_DISCONNECTED); +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .connected = connected_cb, + .disconnected = disconnected_cb, + .recycled = recycled_cb, +}; + +static int start_advertising(struct bt_le_ext_adv *adv) +{ + int err; + + printk("Starting Extended Advertising\n"); + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising (err %d)\n", err); + } + + return err; +} + +int main(void) +{ + int err; + struct bt_le_ext_adv *adv; + + printk("Starting Extended Advertising Demo\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return err; + } + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN_NAME, NULL, &adv); + if (err) { + printk("Failed to create advertising set (err %d)\n", err); + return err; + } + + err = start_advertising(adv); + if (err) { + return err; + } + + while (true) { + k_poll(&poll_evt, 1, K_FOREVER); + + k_poll_signal_reset(poll_evt.signal); + poll_evt.state = K_POLL_STATE_NOT_READY; + + /* Identify event and act upon if applicable */ + if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) && + app_st == BT_SAMPLE_ST_ADV) { + + printk("Connected state!\n"); + app_st = BT_SAMPLE_ST_CONNECTED; + + printk("Initiating disconnect within 5 seconds...\n"); + k_sleep(K_SECONDS(5)); + + bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) && + app_st == BT_SAMPLE_ST_CONNECTED) { + + printk("Disconnected state! Restarting advertising\n"); + app_st = BT_SAMPLE_ST_ADV; + err = start_advertising(adv); + if (err) { + return err; + } + } + } + + return err; +} diff --git a/samples/bluetooth/extended_adv/scanner/CMakeLists.txt b/samples/bluetooth/extended_adv/scanner/CMakeLists.txt new file mode 100644 index 00000000000..0c31cebb89b --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2024 Croxel, Inc. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(extended_adv_scanner) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/bluetooth/extended_adv/scanner/prj.conf b/samples/bluetooth/extended_adv/scanner/prj.conf new file mode 100644 index 00000000000..0b8fe5716d9 --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/prj.conf @@ -0,0 +1,5 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_EXT_ADV=y + +CONFIG_ASSERT=y diff --git a/samples/bluetooth/extended_adv/scanner/sample.yaml b/samples/bluetooth/extended_adv/scanner/sample.yaml new file mode 100644 index 00000000000..7cb06719dff --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Bluetooth Extended Advertising Scanner +tests: + sample.bluetooth.extended_advertising.scanner: + harness: bluetooth + platform_allow: nrf52840dk_nrf52840 + tags: bluetooth diff --git a/samples/bluetooth/extended_adv/scanner/src/main.c b/samples/bluetooth/extended_adv/scanner/src/main.c new file mode 100644 index 00000000000..a4773830fc3 --- /dev/null +++ b/samples/bluetooth/extended_adv/scanner/src/main.c @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2024 Croxel, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define NAME_LEN 30 + +static struct bt_conn *default_conn; +bt_addr_le_t ext_addr; + +enum bt_sample_scan_evt { + BT_SAMPLE_EVT_EXT_ADV_FOUND, + BT_SAMPLE_EVT_CONNECTED, + BT_SAMPLE_EVT_DISCONNECTED, + BT_SAMPLE_EVT_SCAN_DUE, + BT_SAMPLE_EVT_MAX, +}; + +enum bt_sample_scan_st { + BT_SAMPLE_ST_SCANNING, + BT_SAMPLE_ST_CONNECTING, + BT_SAMPLE_ST_CONNECTED, + BT_SAMPLE_ST_COOLDOWN, +}; + +static volatile enum bt_sample_scan_st app_st = BT_SAMPLE_ST_SCANNING; + +static ATOMIC_DEFINE(evt_bitmask, BT_SAMPLE_EVT_MAX); + +static struct k_poll_signal poll_sig = K_POLL_SIGNAL_INITIALIZER(poll_sig); +static struct k_poll_event poll_evt = K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, &poll_sig); + +static void raise_evt(enum bt_sample_scan_evt evt) +{ + (void)atomic_set_bit(evt_bitmask, evt); + k_poll_signal_raise(poll_evt.signal, 1); +} + +static void connected_cb(struct bt_conn *conn, uint8_t err) +{ + printk("Connected (err 0x%02X)\n", err); + + if (err) { + bt_conn_unref(default_conn); + default_conn = NULL; + return; + } + + raise_evt(BT_SAMPLE_EVT_CONNECTED); +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + bt_conn_unref(default_conn); + default_conn = NULL; + + printk("Disconnected (reason 0x%02X)\n", reason); +} + +static void recycled_cb(void) +{ + printk("Connection object available from previous conn. Disconnect is complete!\n"); + raise_evt(BT_SAMPLE_EVT_DISCONNECTED); +} + +BT_CONN_CB_DEFINE(conn_cb) = { + .connected = connected_cb, + .disconnected = disconnected_cb, + .recycled = recycled_cb, +}; + + +static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) +{ + if (info->adv_type & BT_GAP_ADV_TYPE_EXT_ADV && + info->adv_props & BT_GAP_ADV_PROP_EXT_ADV && + info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) { + /* Attempt connection request for device with extended advertisements */ + memcpy(&ext_addr, info->addr, sizeof(ext_addr)); + raise_evt(BT_SAMPLE_EVT_EXT_ADV_FOUND); + } +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; + +static inline int attempt_connection(void) +{ + int err; + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err) { + printk("Failed to stop scan: %d\n", err); + return err; + } + + err = bt_conn_le_create(&ext_addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Failed to establish conn: %d\n", err); + return err; + } + + return 0; +} + +static inline int start_scanning(void) +{ + int err; + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("failed (err %d)\n", err); + } + + return err; +} + +int main(void) +{ + int err; + + printk("Starting Extended Advertising Demo [Scanner]\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + bt_le_scan_cb_register(&scan_callbacks); + + err = start_scanning(); + if (err) { + return err; + } + + while (true) { + (void)k_poll(&poll_evt, 1, K_FOREVER); + + k_poll_signal_reset(poll_evt.signal); + poll_evt.state = K_POLL_STATE_NOT_READY; + + /* Identify event and act upon if applicable */ + if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_EXT_ADV_FOUND) && + app_st == BT_SAMPLE_ST_SCANNING) { + + printk("Found extended advertisement packet!\n"); + app_st = BT_SAMPLE_ST_CONNECTING; + err = attempt_connection(); + if (err) { + return err; + } + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_CONNECTED) && + (app_st == BT_SAMPLE_ST_CONNECTING)) { + + printk("Connected state!\n"); + app_st = BT_SAMPLE_ST_CONNECTED; + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_DISCONNECTED) && + (app_st == BT_SAMPLE_ST_CONNECTED)) { + + printk("Disconnected, cooldown for 5 seconds!\n"); + app_st = BT_SAMPLE_ST_COOLDOWN; + + /* Wait a few seconds before starting to re-scan again... */ + k_sleep(K_SECONDS(5)); + + raise_evt(BT_SAMPLE_EVT_SCAN_DUE); + + } else if (atomic_test_and_clear_bit(evt_bitmask, BT_SAMPLE_EVT_SCAN_DUE) && + (app_st == BT_SAMPLE_ST_COOLDOWN)) { + + printk("Starting to scan for extended adv\n"); + app_st = BT_SAMPLE_ST_SCANNING; + err = start_scanning(); + if (err) { + return err; + } + + } + } + + return 0; +} diff --git a/samples/bluetooth/handsfree/prj.conf b/samples/bluetooth/handsfree/prj.conf index ce7e742f10b..924d9c0af0e 100644 --- a/samples/bluetooth/handsfree/prj.conf +++ b/samples/bluetooth/handsfree/prj.conf @@ -4,3 +4,4 @@ CONFIG_BT_RFCOMM=y CONFIG_BT_HFP_HF=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="test-Handsfree" +CONFIG_BT_COD=0x200408 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index e9e5ac63483..f80f324be53 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -7,6 +7,7 @@ CONFIG_MAIN_STACK_SIZE=512 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_CBPRINTF_REDUCED_INTEGRAL=y CONFIG_BT=y CONFIG_BT_HCI_RAW=y diff --git a/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay b/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay new file mode 100644 index 00000000000..adef7109b3c --- /dev/null +++ b/samples/bluetooth/hci_uart_async/boards/nrf52_bsim.overlay @@ -0,0 +1 @@ +/* Purposely empty. To avoid using the one provided by the application */ diff --git a/samples/bluetooth/iso_receive/src/main.c b/samples/bluetooth/iso_receive/src/main.c index a746a2f2fd0..844a7161443 100644 --- a/samples/bluetooth/iso_receive/src/main.c +++ b/samples/bluetooth/iso_receive/src/main.c @@ -277,7 +277,7 @@ static struct bt_iso_big_sync_param big_sync_param = { .bis_channels = bis, .num_bis = BIS_ISO_CHAN_COUNT, .bis_bitfield = (BIT_MASK(BIS_ISO_CHAN_COUNT) << 1), - .mse = 1, + .mse = BT_ISO_SYNC_MSE_ANY, /* any number of subevents */ .sync_timeout = 100, /* in 10 ms units */ }; diff --git a/samples/bluetooth/mesh/CMakeLists.txt b/samples/bluetooth/mesh/CMakeLists.txt index 6ee28b12d48..74734eb84b4 100644 --- a/samples/bluetooth/mesh/CMakeLists.txt +++ b/samples/bluetooth/mesh/CMakeLists.txt @@ -16,6 +16,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index 4693e4d1f78..f56dfa703f1 100644 --- a/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -2,7 +2,3 @@ CONFIG_BT_HOST_CRYPTO=n # The option adds GATT caching feature that is based on TinyCrypt. CONFIG_BT_GATT_CACHING=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_demo/CMakeLists.txt b/samples/bluetooth/mesh_demo/CMakeLists.txt index 07736d6c12e..f5d347ab373 100644 --- a/samples/bluetooth/mesh_demo/CMakeLists.txt +++ b/samples/bluetooth/mesh_demo/CMakeLists.txt @@ -15,6 +15,6 @@ endif() if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index 4693e4d1f78..f56dfa703f1 100644 --- a/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_demo/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -2,7 +2,3 @@ CONFIG_BT_HOST_CRYPTO=n # The option adds GATT caching feature that is based on TinyCrypt. CONFIG_BT_GATT_CACHING=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mesh_provisioner/CMakeLists.txt b/samples/bluetooth/mesh_provisioner/CMakeLists.txt index 7b22bd0fe14..aefe3628ba8 100644 --- a/samples/bluetooth/mesh_provisioner/CMakeLists.txt +++ b/samples/bluetooth/mesh_provisioner/CMakeLists.txt @@ -10,6 +10,6 @@ target_sources(app PRIVATE src/main.c) if (CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf index c3d134592fc..c4aa66d1201 100644 --- a/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf +++ b/samples/bluetooth/mesh_provisioner/boards/nrf5340dk_nrf5340_cpuapp_ns.conf @@ -1,6 +1,2 @@ # The option adds TinyCrypt based bt_rand. CONFIG_BT_HOST_CRYPTO=n - -# Known issue: non secure platforms do not work with settings subsystem. -CONFIG_SETTINGS=n -CONFIG_BT_SETTINGS=n diff --git a/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c b/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c index f30e50a85ab..66af1bf86b5 100644 --- a/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c +++ b/samples/bluetooth/mtu_update/peripheral/src/peripheral_mtu_update.c @@ -16,9 +16,9 @@ #define MTU_TEST_SERVICE_TYPE BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f0) -static struct bt_uuid_128 mtu_test_service = BT_UUID_INIT_128(MTU_TEST_SERVICE_TYPE); +static const struct bt_uuid_128 mtu_test_service = BT_UUID_INIT_128(MTU_TEST_SERVICE_TYPE); -static struct bt_uuid_128 notify_characteristic_uuid = +static const struct bt_uuid_128 notify_characteristic_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x2e2b8dc3, 0x06e0, 0x4f93, 0x9bb2, 0x734091c356f3)); static const struct bt_data adv_ad_data[] = { diff --git a/samples/bluetooth/periodic_sync_rsp/src/main.c b/samples/bluetooth/periodic_sync_rsp/src/main.c index d39a7814943..24be636d8c9 100644 --- a/samples/bluetooth/periodic_sync_rsp/src/main.c +++ b/samples/bluetooth/periodic_sync_rsp/src/main.c @@ -122,9 +122,9 @@ static struct bt_le_per_adv_sync_cb sync_callbacks = { .recv = recv_cb, }; -static struct bt_uuid_128 pawr_svc_uuid = +static const struct bt_uuid_128 pawr_svc_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); -static struct bt_uuid_128 pawr_char_uuid = +static const struct bt_uuid_128 pawr_char_uuid = BT_UUID_INIT_128(BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); static ssize_t write_timing(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, diff --git a/samples/bluetooth/peripheral/src/main.c b/samples/bluetooth/peripheral/src/main.c index 53847832e16..7cd65636037 100644 --- a/samples/bluetooth/peripheral/src/main.c +++ b/samples/bluetooth/peripheral/src/main.c @@ -31,13 +31,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); #define VND_MAX_LEN 20 diff --git a/samples/bluetooth/peripheral_accept_list/src/main.c b/samples/bluetooth/peripheral_accept_list/src/main.c index e9b4b670578..f185bfdd6c8 100644 --- a/samples/bluetooth/peripheral_accept_list/src/main.c +++ b/samples/bluetooth/peripheral_accept_list/src/main.c @@ -19,13 +19,13 @@ #define BT_UUID_CUSTOM_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0) -static struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 primary_service_uuid = BT_UUID_INIT_128( BT_UUID_CUSTOM_SERVICE_VAL); -static struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 read_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); -static struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 write_characteristic_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2)); static int signed_value; diff --git a/samples/bluetooth/peripheral_hr/src/main.c b/samples/bluetooth/peripheral_hr/src/main.c index addee9bf92e..135f41667e2 100644 --- a/samples/bluetooth/peripheral_hr/src/main.c +++ b/samples/bluetooth/peripheral_hr/src/main.c @@ -22,6 +22,8 @@ #include #include +static bool hrf_ntf_enabled; + static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_ALL, @@ -49,6 +51,25 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .disconnected = disconnected, }; +static void hrs_ntf_changed(bool enabled) +{ + hrf_ntf_enabled = enabled; + + printk("HRS notification status changed: %s\n", enabled ? "enabled" : "disabled"); +} + +static struct bt_hrs_cb hrs_cb = { + .ntf_changed = hrs_ntf_changed, +}; + +/** @brief Heart rate service callback register + * + * This function will register callbacks that will be called in + * certain events related to Heart rate service. + * + * @param cb Pointer to callbacks structure + */ + static void bt_ready(void) { int err; @@ -100,7 +121,9 @@ static void hrs_notify(void) heartrate = 90U; } - bt_hrs_notify(heartrate); + if (hrf_ntf_enabled) { + bt_hrs_notify(heartrate); + } } int main(void) @@ -117,6 +140,7 @@ int main(void) bt_conn_auth_cb_register(&auth_cb_display); + bt_hrs_cb_register(&hrs_cb); /* Implement notification. At the moment there is no suitable way * of starting delayed work so we do it here */ diff --git a/samples/bluetooth/peripheral_ht/prj.conf b/samples/bluetooth/peripheral_ht/prj.conf index d25259ec660..b8a3da4f5b5 100644 --- a/samples/bluetooth/peripheral_ht/prj.conf +++ b/samples/bluetooth/peripheral_ht/prj.conf @@ -7,5 +7,4 @@ CONFIG_BT_DIS_PNP=n CONFIG_BT_BAS=y CONFIG_BT_DEVICE_NAME="Zephyr Health Thermometer" CONFIG_BT_DEVICE_APPEARANCE=768 -CONFIG_BT_ATT_ENFORCE_FLOW=n CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/bluetooth/public_broadcast_sink/CMakeLists.txt b/samples/bluetooth/public_broadcast_sink/CMakeLists.txt new file mode 100644 index 00000000000..74bed078bdd --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(pbp_broadcast_sink) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild b/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild new file mode 100644 index 00000000000..f434010f81d --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/public_broadcast_sink/README.rst b/samples/bluetooth/public_broadcast_sink/README.rst new file mode 100644 index 00000000000..5f47bcd05ab --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/README.rst @@ -0,0 +1,77 @@ +.. zephyr:code-sample:: bluetooth_public_broadcast_sink + :name: Bluetooth: Public Broadcast Sink + :relevant-api: bluetooth + + Bluetooth: Public Broadcast Sink + +Overview +******** + +Application demonstrating the LE Public Broadcast Profile sink functionality. +Starts by scanning for LE Audio broadcast sources and then synchronizes to +the first found source which defines a Public Broadcast Announcement including +a High Quality Public Broadcast Audio Stream configuration. + +This sample can be found under +:zephyr_file:`samples/bluetooth/public_broadcast_sink` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** + +When building targeting an nrf52 series board with the Zephyr Bluetooth Controller, +use `-DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf` to enable the required ISO +feature support. + +Building for an nrf5340dk +------------------------- + +You can build both the application core image and an appropriate controller image for the network +core with: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +If you prefer to only build the application core image, you can do so by doing instead: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + +In that case you can pair this application core image with the +:ref:`hci_ipc sample ` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration. + +Building for a simulated nrf5340bsim +------------------------------------ + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf52_bsim +----------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_sink/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf b/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf new file mode 100644 index 00000000000..e336dae38e1 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/overlay-bt_ll_sw_split.conf @@ -0,0 +1,16 @@ +# Zephyr Bluetooth Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Enable support for Broadcast ISO Sync +CONFIG_BT_CTLR_SYNC_ISO=y + +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_SYNC_ISO_PDU_LEN_MAX=155 + +# Supports the highest advertising data that is set in a single HCI command in +# Zephyr Bluetooth Controller +CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191 + +# Number of supported streams +CONFIG_BT_CTLR_SYNC_ISO_STREAM_MAX=2 +CONFIG_BT_CTLR_ISOAL_SINKS=2 diff --git a/samples/bluetooth/public_broadcast_sink/prj.conf b/samples/bluetooth/public_broadcast_sink/prj.conf new file mode 100644 index 00000000000..0feae717a77 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/prj.conf @@ -0,0 +1,34 @@ +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_PAC_SNK=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_AUDIO=y +CONFIG_UTF8=y + +CONFIG_BT_SMP=y +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y +CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_HCI_ACL_FLOW_CONTROL=n +CONFIG_BT_AUDIO_CODEC_CAP_MAX_METADATA_SIZE=196 + +# CAP +CONFIG_BT_CAP_ACCEPTOR=y + +# BAP support +CONFIG_BT_BAP_SCAN_DELEGATOR=y +CONFIG_BT_BAP_BROADCAST_SINK=y +CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=1 + +# Support an ISO channel per ASE +CONFIG_BT_ISO_MAX_CHAN=2 + +# Sink PAC Location Support +CONFIG_BT_PAC_SNK_LOC=y + +# Generic config +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="PBP Broadcast Sink" + +# PBP Support +CONFIG_BT_PBP=y diff --git a/samples/bluetooth/public_broadcast_sink/sample.yaml b/samples/bluetooth/public_broadcast_sink/sample.yaml new file mode 100644 index 00000000000..8b81f4cc364 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/sample.yaml @@ -0,0 +1,27 @@ +sample: + description: Bluetooth Low Energy Audio PBP Broadcast Sink sample + name: Bluetooth Low Energy Audio PBP Broadcast Sink sample +tests: + sample.bluetooth.public_broadcast_sink: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp + integration_platforms: + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + tags: bluetooth + sysbuild: true + sample.bluetooth.public_broadcast_sink.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf52833dk_nrf52820 + - nrf52833dk_nrf52833 + integration_platforms: + - nrf52_bsim + - nrf52833dk_nrf52833 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/public_broadcast_sink/src/main.c b/samples/bluetooth/public_broadcast_sink/src/main.c new file mode 100644 index 00000000000..52d1cadbad7 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/src/main.c @@ -0,0 +1,435 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AVAILABLE_SINK_CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | \ + BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ + BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + BT_AUDIO_CONTEXT_TYPE_GAME | \ + BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL) + +#define SEM_TIMEOUT K_SECONDS(10) +#define PA_SYNC_SKIP 5 +#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */ +#define INVALID_BROADCAST_ID 0xFFFFFFFF + +static bool pbs_found; + +static K_SEM_DEFINE(sem_pa_synced, 0U, 1U); +static K_SEM_DEFINE(sem_base_received, 0U, 1U); +static K_SEM_DEFINE(sem_syncable, 0U, 1U); +static K_SEM_DEFINE(sem_pa_sync_lost, 0U, 1U); + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad); + +static void broadcast_scan_timeout(void); + +static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info); + +static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf); + +static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info); + +static struct bt_le_scan_cb broadcast_scan_cb = { + .recv = broadcast_scan_recv, + .timeout = broadcast_scan_timeout +}; + +static struct bt_le_per_adv_sync_cb broadcast_sync_cb = { + .synced = broadcast_pa_synced, + .recv = broadcast_pa_recv, + .term = broadcast_pa_terminated, +}; + +static struct bt_bap_broadcast_sink *broadcast_sink; +static uint32_t bcast_id; +static struct bt_le_per_adv_sync *bcast_pa_sync; + +static struct bt_bap_stream streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; +struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)]; + +static const struct bt_audio_codec_cap codec = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_LC3_FREQ_48KHZ, BT_AUDIO_CODEC_LC3_DURATION_10, + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u, (BT_AUDIO_CONTEXT_TYPE_MEDIA)); + +/* Create a mask for the maximum BIS we can sync to using the number of streams + * we have. We add an additional 1 since the bis indexes start from 1 and not + * 0. + */ +static const uint32_t bis_index_mask = BIT_MASK(ARRAY_SIZE(streams) + 1U); +static uint32_t bis_index_bitfield; + +static void stream_started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); +} + +static void stream_recv_cb(struct bt_bap_stream *stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + static uint32_t recv_cnt; + + recv_cnt++; + if ((recv_cnt % 20U) == 0U) { + printk("Received %u total ISO packets\n", recv_cnt); + } +} + +static struct bt_bap_stream_ops stream_ops = { + .started = stream_started_cb, + .stopped = stream_stopped_cb, + .recv = stream_recv_cb +}; + +static struct bt_pacs_cap cap = { + .codec_cap = &codec, +}; + +static uint16_t interval_to_sync_timeout(uint16_t interval) +{ + uint32_t interval_ms; + uint16_t timeout; + + /* Ensure that the following calculation does not overflow silently */ + __ASSERT(SYNC_RETRY_COUNT < 10, "SYNC_RETRY_COUNT shall be less than 10"); + + /* Add retries and convert to unit in 10's of ms */ + interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(interval); + timeout = (interval_ms * SYNC_RETRY_COUNT) / 10; + + /* Enforce restraints */ + timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT); + + return timeout; +} + +static void sync_broadcast_pa(const struct bt_le_scan_recv_info *info, + uint32_t broadcast_id) +{ + struct bt_le_per_adv_sync_param param; + int err; + + /* Unregister the callbacks to prevent broadcast_scan_recv to be called again */ + bt_le_scan_cb_unregister(&broadcast_scan_cb); + + err = bt_le_scan_stop(); + if (err != 0) { + printk("Could not stop scan: %d", err); + } + + bt_addr_le_copy(¶m.addr, info->addr); + param.options = 0; + param.sid = info->sid; + param.skip = PA_SYNC_SKIP; + param.timeout = interval_to_sync_timeout(info->interval); + err = bt_le_per_adv_sync_create(¶m, &bcast_pa_sync); + + if (err != 0) { + printk("Could not sync to PA: %d", err); + } else { + bcast_id = broadcast_id; + } +} + +static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data) +{ + enum bt_pbp_announcement_feature source_features; + uint32_t *broadcast_id = user_data; + struct bt_uuid_16 adv_uuid; + uint8_t *tmp_meta = NULL; + int ret; + + if (data->type != BT_DATA_SVC_DATA16) { + return true; + } + + if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) { + return true; + } + + if (!bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) { + *broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16); + return true; + } + + ret = bt_pbp_parse_announcement(data, &source_features, &tmp_meta); + if (ret >= 0) { + if (!(source_features & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY)) { + /* This is a Standard Quality Public Broadcast Audio stream */ + printk("This is a Standard Quality Public Broadcast Audio stream\n"); + pbs_found = false; + + return false; + } + + printk("Found Suitable Public Broadcast Announcement with %d octets of metadata\n", + ret); + pbs_found = true; + + /** + * Continue parsing if Broadcast Audio Announcement Service + * was not found. + */ + if (*broadcast_id == INVALID_BROADCAST_ID) { + return true; + } + } + + return true; +} + +static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *ad) +{ + uint32_t broadcast_id; + + pbs_found = false; + + /* We are only interested in non-connectable periodic advertisers */ + if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) || info->interval == 0) { + return; + } + + broadcast_id = INVALID_BROADCAST_ID; + bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)&broadcast_id); + + if ((broadcast_id != INVALID_BROADCAST_ID) && pbs_found) { + sync_broadcast_pa(info, broadcast_id); + } +} + +static void broadcast_scan_timeout(void) +{ + printk("Broadcast scan timed out\n"); +} + +static bool pa_decode_base(struct bt_data *data, void *user_data) +{ + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + uint32_t base_bis_index_bitfield = 0U; + int err; + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { + return false; + } + + bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; + k_sem_give(&sem_base_received); + + return false; +} + +static void broadcast_pa_recv(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_recv_info *info, + struct net_buf_simple *buf) +{ + bt_data_parse(buf, pa_decode_base, NULL); +} + +static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) +{ + k_sem_give(&sem_syncable); +} + +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) +{ + k_sem_give(&sem_base_received); +} + +static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = { + .syncable = syncable_cb, + .base_recv = base_recv_cb, +}; + +static void broadcast_pa_synced(struct bt_le_per_adv_sync *sync, + struct bt_le_per_adv_sync_synced_info *info) +{ + if (sync == bcast_pa_sync) { + printk("PA sync %p synced for broadcast sink with broadcast ID 0x%06X\n", + sync, bcast_id); + + k_sem_give(&sem_pa_synced); + } +} + +static void broadcast_pa_terminated(struct bt_le_per_adv_sync *sync, + const struct bt_le_per_adv_sync_term_info *info) +{ + if (sync == bcast_pa_sync) { + printk("PA sync %p lost with reason %u\n", sync, info->reason); + bcast_pa_sync = NULL; + + k_sem_give(&sem_pa_sync_lost); + } +} + +static int reset(void) +{ + if (broadcast_sink != NULL) { + int err = bt_bap_broadcast_sink_delete(broadcast_sink); + + if (err) { + printk("Deleting broadcast sink failed (err %d)\n", err); + + return err; + } + + broadcast_sink = NULL; + } + k_sem_reset(&sem_pa_synced); + k_sem_reset(&sem_base_received); + k_sem_reset(&sem_syncable); + k_sem_reset(&sem_pa_sync_lost); + + return 0; +} + +int bap_broadcast_sink_init(void) +{ + int err; + + bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs); + bt_le_per_adv_sync_cb_register(&broadcast_sync_cb); + + err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap); + if (err) { + printk("Capability register failed (err %d)\n", err); + + return err; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) { + streams[i].ops = &stream_ops; + } + + for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) { + streams_p[i] = &streams[i]; + } + + return 0; +} + +int bap_broadcast_sink_run(void) +{ + while (true) { + int err = reset(); + + if (err != 0) { + printk("Resetting failed: %d - Aborting\n", err); + + return err; + } + + /* Register callbacks */ + bt_le_scan_cb_register(&broadcast_scan_cb); + + /* Start scanning */ + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); + if (err) { + printk("Scan start failed (err %d)\n", err); + + return err; + } + + /* Wait until a suitable source is found */ + err = k_sem_take(&sem_pa_synced, K_FOREVER); + printk("Broadcast source PA synced, waiting for BASE\n"); + + /* Wait for BASE decode */ + err = k_sem_take(&sem_base_received, SEM_TIMEOUT); + if (err != 0) { + printk("sem_base_received timed out\n"); + + return err; + } + + /* Create broadcast sink */ + printk("BASE received, creating broadcast sink\n"); + err = bt_bap_broadcast_sink_create(bcast_pa_sync, bcast_id, &broadcast_sink); + if (err != 0) { + printk("bt_bap_broadcast_sink_create failed: %d\n", err); + + return err; + } + + k_sem_take(&sem_syncable, SEM_TIMEOUT); + if (err != 0) { + printk("sem_syncable timed out\n"); + + return err; + } + + /* Sync to broadcast source */ + printk("Syncing to broadcast\n"); + err = bt_bap_broadcast_sink_sync(broadcast_sink, bis_index_bitfield, + streams_p, NULL); + if (err != 0) { + printk("Unable to sync to broadcast source: %d\n", err); + + return err; + } + + k_sem_take(&sem_pa_sync_lost, K_FOREVER); + } + + return 0; +} + +int main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + printk("Bluetooth init failed (err %d)\n", err); + + return err; + } + printk("Bluetooth initialized\n"); + + printk("Initializing BAP Broadcast Sink\n"); + err = bap_broadcast_sink_init(); + if (err != 0) { + return err; + } + + err = bap_broadcast_sink_run(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/samples/bluetooth/public_broadcast_sink/sysbuild.cmake b/samples/bluetooth/public_broadcast_sink/sysbuild.cmake new file mode 100644 index 00000000000..2523aac8ea7 --- /dev/null +++ b/samples/bluetooth/public_broadcast_sink/sysbuild.cmake @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) + # For builds in the nrf5340, we build the netcore image with the controller + + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE + ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + CACHE INTERNAL "" + ) + + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +endif() + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/public_broadcast_source/CMakeLists.txt b/samples/bluetooth/public_broadcast_source/CMakeLists.txt new file mode 100644 index 00000000000..6331703e2d8 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(public_broadcast_source) + +target_sources(app PRIVATE + src/main.c +) + +zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) diff --git a/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild b/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild new file mode 100644 index 00000000000..f434010f81d --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/Kconfig.sysbuild @@ -0,0 +1,15 @@ +# Copyright 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "nrf5340_audio_dk_nrf5340_cpunet" if $(BOARD) = "nrf5340_audio_dk_nrf5340_cpuapp" + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NET_CORE_IMAGE_HCI_IPC + bool "HCI IPC image on network core" + default y + depends on NET_CORE_BOARD != "" diff --git a/samples/bluetooth/public_broadcast_source/README.rst b/samples/bluetooth/public_broadcast_source/README.rst new file mode 100644 index 00000000000..9111cd3f614 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/README.rst @@ -0,0 +1,77 @@ +.. zephyr:code-sample:: bluetooth_public_broadcast_source + :name: Bluetooth: Public Broadcast Source + :relevant-api: bluetooth + + Bluetooth: Public Broadcast Source + +Overview +******** + +Application demonstrating the LE Public Broadcast Profile source functionality. +Will start advertising extended advertising and includes a Broadcast Audio Announcement. +The advertised broadcast audio stream quality will cycle between high and standard quality +every 15 seconds. + +This sample can be found under +:zephyr_file:`samples/bluetooth/public_broadcast_source` in the Zephyr tree. + +Check the :ref:`bluetooth samples section ` for general information. + +Requirements +************ + +* BlueZ running on the host, or +* A board with Bluetooth Low Energy 5.2 support + +Building and Running +******************** + +When building targeting an nrf52 series board with the Zephyr Bluetooth Controller, +use `-DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf` to enable the required ISO +feature support. + +Building for an nrf5340dk +------------------------- + +You can build both the application core image and an appropriate controller image for the network +core with: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +If you prefer to only build the application core image, you can do so by doing instead: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340dk_nrf5340_cpuapp + :goals: build + +In that case you can pair this application core image with the +:ref:`hci_ipc sample ` +:zephyr_file:`samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf` configuration. + +Building for a simulated nrf5340bsim +------------------------------------ + +Similarly to how you would for real HW, you can do: + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf5340bsim_nrf5340_cpuapp + :goals: build + :west-args: --sysbuild + +Note this will produce a Linux executable in `./build/zephyr/zephyr.exe`. +For more information, check :ref:`this board documentation `. + +Building for a simulated nrf52_bsim +----------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/bluetooth/public_broadcast_source/ + :board: nrf52_bsim + :goals: build + :gen-args: -DOVERLAY_CONFIG=overlay-bt_ll_sw_split.conf diff --git a/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf b/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf new file mode 100644 index 00000000000..c73ff9c3ea9 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/overlay-bt_ll_sw_split.conf @@ -0,0 +1,24 @@ +# Zephyr Bluetooth Controller +CONFIG_BT_LL_SW_SPLIT=y + +# Zephyr Controller tested maximum advertising data that can be set in a single HCI command +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 + +# Enable support for Broadcast ISO in Zephyr Bluetooth Controller +CONFIG_BT_CTLR_ADV_ISO=y + +# Sufficient ISO PDU length for any BAP LC3 presets (155) +CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=155 + +# Number of supported streams +CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=2 +CONFIG_BT_CTLR_ISOAL_SOURCES=2 + +# FIXME: Host needs CONFIG_BT_ISO_TX_MTU + 4 bytes for sequence number, and optionally +# additional + 4 bytes for timestamp when not using BT_ISO_TIMESTAMP_NONE in bt_iso_chan_send(), +# otherwise Host tries to fragment ISO data. +# When Host is fixed, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE can inherit the +# CONFIG_BT_ISO_TX_MTU value. +# +# Supports the highest SDU size required by any BAP LC3 presets (155) +CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=163 diff --git a/samples/bluetooth/public_broadcast_source/prj.conf b/samples/bluetooth/public_broadcast_source/prj.conf new file mode 100644 index 00000000000..ca7d3f38261 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/prj.conf @@ -0,0 +1,26 @@ +CONFIG_MAIN_STACK_SIZE=2048 + +CONFIG_BT=y +CONFIG_LOG=y +CONFIG_BT_AUDIO=y +CONFIG_BT_PERIPHERAL=y + +CONFIG_BT_ISO_MAX_CHAN=2 +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=2 +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=2 +CONFIG_BT_ISO_TX_BUF_COUNT=4 +CONFIG_BT_HCI_ACL_FLOW_CONTROL=n + +# PBP support +CONFIG_BT_PBP=y + +# CAP support +CONFIG_BT_CAP_INITIATOR=y + +# BAP support +CONFIG_BT_BAP_BROADCAST_SOURCE=y +CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT=1 +CONFIG_BT_BAP_BROADCAST_SRC_SUBGROUP_COUNT=1 + +CONFIG_BT_EXT_ADV=y +CONFIG_BT_DEVICE_NAME="PBS" diff --git a/samples/bluetooth/public_broadcast_source/sample.yaml b/samples/bluetooth/public_broadcast_source/sample.yaml new file mode 100644 index 00000000000..eb2bd5dc79b --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/sample.yaml @@ -0,0 +1,27 @@ +sample: + description: Bluetooth Low Energy Public Broadcast Source sample + name: Bluetooth Low Energy Public Broadcast Source sample +tests: + sample.bluetooth.public_broadcast_source: + harness: bluetooth + platform_allow: + - qemu_cortex_m3 + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + - nrf5340bsim_nrf5340_cpuapp + integration_platforms: + - qemu_x86 + - nrf5340dk_nrf5340_cpuapp + tags: bluetooth + sysbuild: true + sample.bluetooth.public_broadcast_source.bt_ll_sw_split: + harness: bluetooth + platform_allow: + - nrf52_bsim + - nrf52833dk_nrf52820 + - nrf52833dk_nrf52833 + integration_platforms: + - nrf52_bsim + - nrf52833dk_nrf52833 + extra_args: OVERLAY_CONFIG=overlay-bt_ll_sw_split.conf + tags: bluetooth diff --git a/samples/bluetooth/public_broadcast_source/src/main.c b/samples/bluetooth/public_broadcast_source/src/main.c new file mode 100644 index 00000000000..c719810e243 --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/src/main.c @@ -0,0 +1,424 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BROADCAST_ENQUEUE_COUNT 2U + +/* PBS ASCII text */ +#define PBS_DEMO 'P', 'B', 'P' + +NET_BUF_POOL_FIXED_DEFINE(tx_pool, + (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT), + BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); + +static K_SEM_DEFINE(sem_broadcast_started, 0, 1); +static K_SEM_DEFINE(sem_broadcast_stopped, 0, 1); + +static struct bt_cap_stream broadcast_source_stream; +static struct bt_cap_stream *broadcast_stream; + +static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA( + BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ))}; + + +const uint8_t pba_metadata[] = { + BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_PROGRAM_INFO, PBS_DEMO) +}; + +static uint8_t appearance_addata[] = { + BT_BYTES_LIST_LE16(BT_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE) +}; + +static const char broadcast_name[] = "PBP Source Demo"; + +static struct bt_bap_lc3_preset broadcast_preset_48_2_1 = + BT_BAP_LC3_UNICAST_PRESET_48_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, + BT_AUDIO_CONTEXT_TYPE_MEDIA); + +struct bt_cap_initiator_broadcast_stream_param stream_params; +struct bt_cap_initiator_broadcast_subgroup_param subgroup_param; +struct bt_cap_initiator_broadcast_create_param create_param; +struct bt_cap_broadcast_source *broadcast_source; +struct bt_le_ext_adv *ext_adv; + +static void broadcast_started_cb(struct bt_bap_stream *stream) +{ + printk("Stream %p started\n", stream); + k_sem_give(&sem_broadcast_started); +} + +static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + if (reason == BT_HCI_ERR_LOCALHOST_TERM_CONN) { + printk("Stream %p ended\n", stream); + } else { + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + } + + k_sem_give(&sem_broadcast_stopped); +} + +static void broadcast_sent_cb(struct bt_bap_stream *stream) +{ + static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU]; + static bool mock_data_initialized; + static uint32_t seq_num; + struct net_buf *buf; + int ret; + + if (broadcast_preset_48_2_1.qos.sdu > CONFIG_BT_ISO_TX_MTU) { + printk("Invalid SDU %u for the MTU: %d", broadcast_preset_48_2_1.qos.sdu, + CONFIG_BT_ISO_TX_MTU); + + return; + } + + if (!mock_data_initialized) { + for (size_t i = 0U; i < ARRAY_SIZE(mock_data); i++) { + /* Initialize mock data */ + mock_data[i] = (uint8_t)i; + } + mock_data_initialized = true; + } + + buf = net_buf_alloc(&tx_pool, K_FOREVER); + if (buf == NULL) { + printk("Could not allocate buffer when sending on %p\n", stream); + + return; + } + + net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE); + net_buf_add_mem(buf, mock_data, broadcast_preset_48_2_1.qos.sdu); + ret = bt_bap_stream_send(stream, buf, seq_num++, BT_ISO_TIMESTAMP_NONE); + if (ret < 0) { + /* This will end broadcasting on this stream. */ + net_buf_unref(buf); + + return; + } +} + +static struct bt_bap_stream_ops broadcast_stream_ops = { + .started = broadcast_started_cb, + .stopped = broadcast_stopped_cb, + .sent = broadcast_sent_cb +}; + +static int setup_extended_adv(struct bt_le_ext_adv **adv) +{ + int err; + + /* Create a non-connectable non-scannable advertising set */ + err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, adv); + if (err != 0) { + printk("Unable to create extended advertising set: %d\n", err); + + return err; + } + + /* Set periodic advertising parameters */ + err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); + if (err) { + printk("Failed to set periodic advertising parameters: %d\n", err); + + return err; + } + + return 0; +} + +static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, + struct bt_le_ext_adv *adv) +{ + /* Broadcast Audio Streaming Endpoint advertising data */ + NET_BUF_SIMPLE_DEFINE(ad_buf, + BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE); + NET_BUF_SIMPLE_DEFINE(base_buf, 128); + NET_BUF_SIMPLE_DEFINE(pbp_ad_buf, BT_UUID_SIZE_16 + 1 + ARRAY_SIZE(pba_metadata)); + static enum bt_pbp_announcement_feature pba_params; + struct bt_data ext_ad[4]; + struct bt_data per_ad; + uint32_t broadcast_id; + int err; + + err = bt_cap_initiator_broadcast_get_id(source, &broadcast_id); + if (err != 0) { + printk("Unable to get broadcast ID: %d\n", err); + + return err; + } + + /* Setup extended advertising data */ + ext_ad[0].type = BT_DATA_GAP_APPEARANCE; + ext_ad[0].data_len = 2; + ext_ad[0].data = appearance_addata; + /* Broadcast name AD Type */ + ext_ad[1].type = BT_DATA_BROADCAST_NAME; + ext_ad[1].data_len = ARRAY_SIZE(broadcast_name); + ext_ad[1].data = broadcast_name; + /* Broadcast Audio Announcement */ + net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); + net_buf_simple_add_le24(&ad_buf, broadcast_id); + ext_ad[2].type = BT_DATA_SVC_DATA16; + ext_ad[2].data_len = ad_buf.len + sizeof(ext_ad[2].type); + ext_ad[2].data = ad_buf.data; + + /** + * Create a Public Broadcast Announcement + * Cycle between high and standard quality public broadcast audio. + */ + if (pba_params & BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY) { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_STANDARD_QUALITY; + printk("Starting stream with standard quality!\n"); + } else { + pba_params = 0; + pba_params |= BT_PBP_ANNOUNCEMENT_FEATURE_HIGH_QUALITY; + printk("Starting stream with high quality!\n"); + } + err = bt_pbp_get_announcement(&pba_metadata[1], ARRAY_SIZE(pba_metadata) - 1, + pba_params, &pbp_ad_buf); + if (err != 0) { + printk("Failed to create public broadcast announcement!: %d\n", err); + + return err; + } + ext_ad[3].type = BT_DATA_SVC_DATA16; + ext_ad[3].data_len = pbp_ad_buf.len; + ext_ad[3].data = pbp_ad_buf.data; + err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0); + if (err != 0) { + printk("Failed to set extended advertising data: %d\n", err); + + return err; + } + + /* Setup periodic advertising data */ + err = bt_cap_initiator_broadcast_get_base(source, &base_buf); + if (err != 0) { + printk("Failed to get encoded BASE: %d\n", err); + + return err; + } + + per_ad.type = BT_DATA_SVC_DATA16; + per_ad.data_len = base_buf.len; + per_ad.data = base_buf.data; + err = bt_le_per_adv_set_data(adv, &per_ad, 1); + if (err != 0) { + printk("Failed to set periodic advertising data: %d\n", err); + + return err; + } + + return 0; +} + +static int start_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Start extended advertising */ + err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); + if (err) { + printk("Failed to start extended advertising: %d\n", err); + + return err; + } + + /* Enable Periodic Advertising */ + err = bt_le_per_adv_start(adv); + if (err) { + printk("Failed to enable periodic advertising: %d\n", err); + + return err; + } + + return 0; +} + +static int stop_and_delete_extended_adv(struct bt_le_ext_adv *adv) +{ + int err; + + /* Stop extended advertising */ + err = bt_le_per_adv_stop(adv); + if (err) { + printk("Failed to stop periodic advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_stop(adv); + if (err) { + printk("Failed to stop extended advertising: %d\n", err); + + return err; + } + + err = bt_le_ext_adv_delete(adv); + if (err) { + printk("Failed to delete extended advertising: %d\n", err); + + return err; + } + + return 0; +} + +static int reset(void) +{ + k_sem_reset(&sem_broadcast_started); + k_sem_reset(&sem_broadcast_stopped); + + return 0; +} + +int cap_initiator_init(void) +{ + if (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE)) { + broadcast_stream = &broadcast_source_stream; + bt_bap_stream_cb_register(&broadcast_stream->bap_stream, &broadcast_stream_ops); + } + + return 0; +} + +void cap_initiator_setup(void) +{ + int err; + + stream_params.stream = &broadcast_source_stream; + stream_params.data_len = ARRAY_SIZE(bis_codec_data); + stream_params.data = bis_codec_data; + + subgroup_param.stream_count = 1U; + subgroup_param.stream_params = &stream_params; + subgroup_param.codec_cfg = &broadcast_preset_48_2_1.codec_cfg; + + create_param.subgroup_count = 1U; + create_param.subgroup_params = &subgroup_param; + create_param.qos = &broadcast_preset_48_2_1.qos; + create_param.packing = BT_ISO_PACKING_SEQUENTIAL; + create_param.encryption = false; + + while (true) { + err = reset(); + if (err != 0) { + printk("Resetting failed: %d - Aborting\n", err); + + return; + } + + err = setup_extended_adv(&ext_adv); + if (err != 0) { + printk("Unable to setup extended advertiser: %d\n", err); + + return; + } + + err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source); + if (err != 0) { + printk("Unable to create broadcast source: %d\n", err); + + return; + } + + err = bt_cap_initiator_broadcast_audio_start(broadcast_source, ext_adv); + if (err != 0) { + printk("Unable to start broadcast source: %d\n", err); + + return; + } + + err = setup_extended_adv_data(broadcast_source, ext_adv); + if (err != 0) { + printk("Unable to setup extended advertising data: %d\n", err); + + return; + } + + err = start_extended_adv(ext_adv); + if (err != 0) { + printk("Unable to start extended advertiser: %d\n", err); + + return; + } + k_sem_take(&sem_broadcast_started, K_FOREVER); + + /* Initialize sending */ + for (unsigned int j = 0U; j < BROADCAST_ENQUEUE_COUNT; j++) { + broadcast_sent_cb(&broadcast_stream->bap_stream); + } + + /* Keeping running for a little while */ + k_sleep(K_SECONDS(15)); + + err = bt_cap_initiator_broadcast_audio_stop(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + + return; + } + + k_sem_take(&sem_broadcast_stopped, K_FOREVER); + err = bt_cap_initiator_broadcast_audio_delete(broadcast_source); + if (err != 0) { + printk("Failed to stop broadcast source: %d\n", err); + + return; + } + broadcast_source = NULL; + + err = stop_and_delete_extended_adv(ext_adv); + if (err != 0) { + printk("Failed to stop and delete extended advertising: %d\n", err); + + return; + } + } +} + + +int main(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + printk("Bluetooth enable failed (err %d)\n", err); + + return err; + } + + printk("Bluetooth initialized\n"); + + /* Initialize CAP Initiator */ + err = cap_initiator_init(); + if (err != 0) { + return err; + } + + printk("CAP initialized\n"); + + /* Configure and start broadcast stream */ + cap_initiator_setup(); + + return 0; +} diff --git a/samples/bluetooth/public_broadcast_source/sysbuild.cmake b/samples/bluetooth/public_broadcast_source/sysbuild.cmake new file mode 100644 index 00000000000..d3bf7be5b6c --- /dev/null +++ b/samples/bluetooth/public_broadcast_source/sysbuild.cmake @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) + # For builds in the nrf5340, we build the netcore image with the controller + + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE + ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + CACHE INTERNAL "" + ) + + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +endif() + +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/samples/bluetooth/st_ble_sensor/src/main.c b/samples/bluetooth/st_ble_sensor/src/main.c index 3a65cc0d777..95060f9167a 100644 --- a/samples/bluetooth/st_ble_sensor/src/main.c +++ b/samples/bluetooth/st_ble_sensor/src/main.c @@ -36,15 +36,15 @@ static ssize_t recv(struct bt_conn *conn, uint16_t len, uint16_t offset, uint8_t flags); /* ST Custom Service */ -static struct bt_uuid_128 st_service_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 st_service_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe40, 0xcc7a, 0x482a, 0x984a, 0x7f2ed5b3e58f)); /* ST LED service */ -static struct bt_uuid_128 led_char_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 led_char_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe41, 0x8e22, 0x4541, 0x9d4c, 0x21edae82ed19)); /* ST Notify button service */ -static struct bt_uuid_128 but_notif_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 but_notif_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x0000fe42, 0x8e22, 0x4541, 0x9d4c, 0x21edae82ed19)); #define DEVICE_NAME CONFIG_BT_DEVICE_NAME diff --git a/samples/bluetooth/tmap_bmr/prj.conf b/samples/bluetooth/tmap_bmr/prj.conf index 3a0fd96f598..7c3ea5b0372 100644 --- a/samples/bluetooth/tmap_bmr/prj.conf +++ b/samples/bluetooth/tmap_bmr/prj.conf @@ -8,7 +8,7 @@ CONFIG_UTF8=y CONFIG_BT_SMP=y CONFIG_BT_KEYS_OVERWRITE_OLDEST=y -CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_ATT_TX_COUNT=20 # TMAP support CONFIG_BT_TMAP=y diff --git a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c index 7a306cfb304..cc6c95a3fe6 100644 --- a/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c +++ b/samples/bluetooth/tmap_bmr/src/bap_broadcast_sink.c @@ -215,29 +215,20 @@ static void broadcast_scan_timeout(void) static bool pa_decode_base(struct bt_data *data, void *user_data) { + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); uint32_t base_bis_index_bitfield = 0U; - struct bt_bap_base base = { 0 }; - - if (data->type != BT_DATA_SVC_DATA16) { - return true; - } + int err; - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { return true; } - if (bt_bap_decode_base(data, &base) != 0) { + err = bt_bap_base_get_bis_indexes(base, &base_bis_index_bitfield); + if (err != 0) { return false; } - for (size_t i = 0U; i < base.subgroup_count; i++) { - for (size_t j = 0U; j < base.subgroups[i].bis_count; j++) { - const uint8_t index = base.subgroups[i].bis_data[j].index; - - base_bis_index_bitfield |= BIT(index); - } - } - bis_index_bitfield = base_bis_index_bitfield & bis_index_mask; k_sem_give(&sem_base_received); @@ -256,7 +247,8 @@ static void syncable_cb(struct bt_bap_broadcast_sink *sink, bool encrypted) k_sem_give(&sem_syncable); } -static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { k_sem_give(&sem_base_received); } diff --git a/samples/bluetooth/tmap_bms/prj.conf b/samples/bluetooth/tmap_bms/prj.conf index ab3641a7a0f..be8acce1880 100644 --- a/samples/bluetooth/tmap_bms/prj.conf +++ b/samples/bluetooth/tmap_bms/prj.conf @@ -1,3 +1,5 @@ +CONFIG_MAIN_STACK_SIZE=2048 + CONFIG_BT=y CONFIG_LOG=y CONFIG_BT_PERIPHERAL=y diff --git a/samples/bluetooth/tmap_bms/src/cap_initiator.c b/samples/bluetooth/tmap_bms/src/cap_initiator.c index af946f8ba94..1e50977eab5 100644 --- a/samples/bluetooth/tmap_bms/src/cap_initiator.c +++ b/samples/bluetooth/tmap_bms/src/cap_initiator.c @@ -16,7 +16,7 @@ #include #define BROADCAST_ENQUEUE_COUNT 2U -#define MOCK_CCID 0xAB + NET_BUF_POOL_FIXED_DEFINE(tx_pool, (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT), BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL); @@ -32,8 +32,7 @@ static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA( static const uint8_t new_metadata[] = { BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT, - BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)), - BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, MOCK_CCID), + BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)) }; static struct bt_bap_lc3_preset broadcast_preset_48_2_1 = @@ -60,6 +59,7 @@ static void broadcast_started_cb(struct bt_bap_stream *stream) static void broadcast_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) { printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + k_sem_give(&sem_broadcast_stopped); } @@ -151,11 +151,13 @@ static int setup_extended_adv_data(struct bt_cap_broadcast_source *source, ext_ad[0].type = BT_DATA_SVC_DATA16; ext_ad[0].data_len = ARRAY_SIZE(tmap_addata); ext_ad[0].data = tmap_addata; + /* Broadcast Audio Announcement */ net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL); net_buf_simple_add_le24(&ad_buf, broadcast_id); ext_ad[1].type = BT_DATA_SVC_DATA16; ext_ad[1].data_len = ad_buf.len + sizeof(ext_ad[1].type); ext_ad[1].data = ad_buf.data; + err = bt_le_ext_adv_set_data(adv, ext_ad, ARRAY_SIZE(ext_ad), NULL, 0); if (err != 0) { printk("Failed to set extended advertising data: %d\n", err); diff --git a/samples/bluetooth/tmap_central/src/cap_initiator.c b/samples/bluetooth/tmap_central/src/cap_initiator.c index 1b45741e14b..fe75d0e0ace 100644 --- a/samples/bluetooth/tmap_central/src/cap_initiator.c +++ b/samples/bluetooth/tmap_central/src/cap_initiator.c @@ -119,8 +119,7 @@ static void cap_discovery_complete_cb(struct bt_conn *conn, int err, k_sem_give(&sem_cas_discovery); } -static void unicast_start_complete_cb(struct bt_bap_unicast_group *unicast_group, - int err, struct bt_conn *conn) +static void unicast_start_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { printk("Failed to start (failing conn %p): %d", conn, err); @@ -138,8 +137,7 @@ static void unicast_update_complete_cb(int err, struct bt_conn *conn) } } -static void unicast_stop_complete_cb(struct bt_bap_unicast_group *unicast_group, int err, - struct bt_conn *conn) +static void unicast_stop_complete_cb(int err, struct bt_conn *conn) { if (err != 0) { printk("Failed to stop (failing conn %p): %d", conn, err); @@ -330,7 +328,7 @@ static int unicast_group_create(struct bt_bap_unicast_group **out_unicast_group) return err; } -static int unicast_audio_start(struct bt_conn *conn, struct bt_bap_unicast_group *unicast_group) +static int unicast_audio_start(struct bt_conn *conn) { int err = 0; struct bt_cap_unicast_audio_start_stream_param stream_param; @@ -345,7 +343,7 @@ static int unicast_audio_start(struct bt_conn *conn, struct bt_bap_unicast_group stream_param.ep = unicast_sink_eps[0]; stream_param.codec_cfg = &unicast_preset_48_2_1.codec_cfg; - err = bt_cap_initiator_unicast_audio_start(¶m, unicast_group); + err = bt_cap_initiator_unicast_audio_start(¶m); if (err != 0) { printk("Failed to start unicast audio: %d\n", err); return err; @@ -457,7 +455,7 @@ int cap_initiator_setup(struct bt_conn *conn) return err; } - err = unicast_audio_start(conn, unicast_group); + err = unicast_audio_start(conn); if (err != 0) { return err; } diff --git a/samples/bluetooth/tmap_central/src/main.c b/samples/bluetooth/tmap_central/src/main.c index d890eb77107..fa75817c8f9 100644 --- a/samples/bluetooth/tmap_central/src/main.c +++ b/samples/bluetooth/tmap_central/src/main.c @@ -138,7 +138,7 @@ static bool check_audio_support_and_connect(struct bt_data *data, void *user_dat { bt_addr_le_t *addr = user_data; struct net_buf_simple tmas_svc_data; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t uuid_val; uint16_t peer_tmap_role = 0; int err; diff --git a/samples/bluetooth/tmap_peripheral/prj.conf b/samples/bluetooth/tmap_peripheral/prj.conf index 6b7d7d390a8..79725aaba2b 100644 --- a/samples/bluetooth/tmap_peripheral/prj.conf +++ b/samples/bluetooth/tmap_peripheral/prj.conf @@ -7,7 +7,7 @@ CONFIG_UTF8=y CONFIG_BT_SMP=y CONFIG_BT_KEYS_OVERWRITE_OLDEST=y -CONFIG_BT_L2CAP_TX_BUF_COUNT=20 +CONFIG_BT_ATT_TX_COUNT=20 # TMAP support CONFIG_BT_TMAP=y diff --git a/samples/bluetooth/unicast_audio_client/src/main.c b/samples/bluetooth/unicast_audio_client/src/main.c index 3953bee99f0..8fe82543ab7 100644 --- a/samples/bluetooth/unicast_audio_client/src/main.c +++ b/samples/bluetooth/unicast_audio_client/src/main.c @@ -106,7 +106,6 @@ static int frame_duration_100us; static int frames_per_sdu; static int octets_per_frame; - /** * Use the math lib to generate a sine-wave using 16 bit samples into a buffer. * @@ -122,7 +121,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415f / sine_period_samples; for (unsigned int i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } @@ -402,7 +401,7 @@ static bool check_audio_support_and_connect(struct bt_data *data, bt_addr_le_t *addr = user_data; uint8_t announcement_type; uint32_t audio_contexts; - struct bt_uuid *uuid; + const struct bt_uuid *uuid; uint16_t uuid_val; uint8_t meta_len; size_t min_size; diff --git a/samples/boards/arc_secure_services/nsim_sem_normal_defconfig b/samples/boards/arc_secure_services/nsim_sem_normal_defconfig index 98b3d6edca0..91b9775a7dd 100644 --- a/samples/boards/arc_secure_services/nsim_sem_normal_defconfig +++ b/samples/boards/arc_secure_services/nsim_sem_normal_defconfig @@ -10,5 +10,4 @@ CONFIG_ARCV2_TIMER=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y CONFIG_SERIAL=y -CONFIG_ARC_EXCEPTION_DEBUG=y CONFIG_TRUSTED_EXECUTION_NONSECURE=y diff --git a/samples/boards/bbc_microbit/pong/src/ble.c b/samples/boards/bbc_microbit/pong/src/ble.c index 08ebe38a254..89f34f3585f 100644 --- a/samples/boards/bbc_microbit/pong/src/ble.c +++ b/samples/boards/bbc_microbit/pong/src/ble.c @@ -30,9 +30,9 @@ #define PONG_CHR_UUID \ BT_UUID_128_ENCODE(0xabbf8f1c, 0xc56a, 0x82b5, 0xc640, 0x2ccdd7af94dd) -static struct bt_uuid_128 pong_svc_uuid = BT_UUID_INIT_128(PONG_SVC_UUID); -static struct bt_uuid_128 pong_chr_uuid = BT_UUID_INIT_128(PONG_CHR_UUID); -static struct bt_uuid *gatt_ccc_uuid = BT_UUID_GATT_CCC; +static const struct bt_uuid_128 pong_svc_uuid = BT_UUID_INIT_128(PONG_SVC_UUID); +static const struct bt_uuid_128 pong_chr_uuid = BT_UUID_INIT_128(PONG_CHR_UUID); +static const struct bt_uuid *gatt_ccc_uuid = BT_UUID_GATT_CCC; static struct bt_gatt_discover_params discov_param; static struct bt_gatt_subscribe_params subscribe_param; diff --git a/samples/boards/bbc_microbit/sound/README.rst b/samples/boards/bbc_microbit/sound/README.rst index 33373f0b545..b02faffb2d6 100644 --- a/samples/boards/bbc_microbit/sound/README.rst +++ b/samples/boards/bbc_microbit/sound/README.rst @@ -7,29 +7,46 @@ Overview ******** This sample demonstrates how to use a piezo buzzer connected -to port P0 on the edge connector of the BBC micro:bit board. +to port P0 on the edge connector of the **BBC micro:bit v1** or +using the on-board buzzer on the **BBC micro:bit v2**. Requirements ************ -A separate piezo buzzer connected to the board. One example is the MI:Power -board that has a piezo buzzer in addition to a coin-cell battery. Resellers of -this board can be fairly easily found using online search. +Using **BBC micro:bit v1**, a separate piezo buzzer must be connected to the board. +One example is the MI:Power board that has a piezo buzzer in addition to a +coin-cell battery. Resellers of this board can be fairly easily found using online search. + +The upgraded **BBC micro:bit v2** board does not need a separate buzzer as it has one +built-in on the backside of the board (marked as 'speaker'). + Building and running ******************** The sample can be built as follows: +Building for a BBC micro:bit v1 +------------------------------- + .. zephyr-app-commands:: :zephyr-app: samples/boards/bbc_microbit/sound :board: bbc_microbit :goals: build flash :compact: +Building for a BBC micro:bit v2 +------------------------------- + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/bbc_microbit/sound + :board: bbc_microbit_v2 + :goals: build flash + :compact: + Sample Output ============= -This sample outputs sounds through a connected piezo buzzer based on +This sample outputs sounds through a piezo buzzer based on button presses of the two main buttons. For each press the current output frequency will be printed on the 5x5 LED display. diff --git a/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay b/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay new file mode 100644 index 00000000000..33e471dc6b5 --- /dev/null +++ b/samples/boards/bbc_microbit/sound/boards/bbc_microbit_v2.overlay @@ -0,0 +1,6 @@ +/ { + zephyr,user { + /* period cell corresponds to initial period */ + pwms = <&pwm1 0 PWM_USEC(1500) PWM_POLARITY_NORMAL>; + }; +}; diff --git a/samples/boards/bbc_microbit/sound/prj.conf b/samples/boards/bbc_microbit/sound/prj.conf index 2341a68c528..d6277787129 100644 --- a/samples/boards/bbc_microbit/sound/prj.conf +++ b/samples/boards/bbc_microbit/sound/prj.conf @@ -2,4 +2,3 @@ CONFIG_GPIO=y CONFIG_DISPLAY=y CONFIG_MICROBIT_DISPLAY=y CONFIG_PWM=y -CONFIG_PWM_NRF_SW=y diff --git a/samples/boards/bbc_microbit/sound/sample.yaml b/samples/boards/bbc_microbit/sound/sample.yaml index 241fce89d8c..8a819a03a1d 100644 --- a/samples/boards/bbc_microbit/sound/sample.yaml +++ b/samples/boards/bbc_microbit/sound/sample.yaml @@ -2,5 +2,7 @@ sample: name: BBC micro:bit Sound tests: sample.board.bbc_microbit.sound: - platform_allow: bbc_microbit + platform_allow: + - bbc_microbit + - bbc_microbit_v2 tags: sound diff --git a/samples/boards/nrf/nrfx/Kconfig b/samples/boards/nrf/nrfx/Kconfig index 0d54067202a..a46af347ba9 100644 --- a/samples/boards/nrf/nrfx/Kconfig +++ b/samples/boards/nrf/nrfx/Kconfig @@ -2,9 +2,19 @@ # SPDX-License-Identifier: Apache-2.0 config NRFX_DPPI - default HAS_HW_NRF_DPPIC + default $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_DPPIC)) config NRFX_PPI - default HAS_HW_NRF_PPI + default $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_PPI)) + +config NRFX_GPIOTE0 + default y if SOC_SERIES_NRF51X || \ + SOC_SERIES_NRF52X || \ + (SOC_SERIES_NRF53X && !TRUSTED_EXECUTION_NONSECURE) || \ + (SOC_SERIES_NRF91X && !TRUSTED_EXECUTION_NONSECURE) + +config NRFX_GPIOTE1 + default y if (SOC_SERIES_NRF53X && TRUSTED_EXECUTION_NONSECURE) || \ + (SOC_SERIES_NRF91X && TRUSTED_EXECUTION_NONSECURE) source "Kconfig.zephyr" diff --git a/samples/boards/nrf/nrfx/prj.conf b/samples/boards/nrf/nrfx/prj.conf index 32cbfc3279c..d4f0c29699f 100644 --- a/samples/boards/nrf/nrfx/prj.conf +++ b/samples/boards/nrf/nrfx/prj.conf @@ -1,4 +1,3 @@ CONFIG_GPIO=n -CONFIG_NRFX_GPIOTE=y CONFIG_LOG=y CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100 diff --git a/samples/boards/nrf/nrfx/src/main.c b/samples/boards/nrf/nrfx/src/main.c index 615b800545e..8b3819f2d8a 100644 --- a/samples/boards/nrf/nrfx/src/main.c +++ b/samples/boards/nrf/nrfx/src/main.c @@ -8,18 +8,22 @@ #include #include -#if defined(DPPI_PRESENT) -#include -#else -#include -#endif #include #include LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF); -#define INPUT_PIN DT_GPIO_PIN(DT_ALIAS(sw0), gpios) -#define OUTPUT_PIN DT_GPIO_PIN(DT_ALIAS(led0), gpios) +#define INPUT_PIN NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios) +#define OUTPUT_PIN NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(led0), gpios) + +#define GPIOTE_INST NRF_DT_GPIOTE_INST(DT_ALIAS(sw0), gpios) +#define GPIOTE_NODE DT_NODELABEL(_CONCAT(gpiote, GPIOTE_INST)) + +BUILD_ASSERT(NRF_DT_GPIOTE_INST(DT_ALIAS(led0), gpios) == GPIOTE_INST, + "Both sw0 and led0 GPIOs must use the same GPIOTE instance"); +BUILD_ASSERT(IS_ENABLED(_CONCAT(CONFIG_, _CONCAT(NRFX_GPIOTE, GPIOTE_INST))), + "NRFX_GPIOTE" STRINGIFY(GPIOTE_INST) " must be enabled in Kconfig"); + static void button_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t trigger, @@ -35,28 +39,28 @@ int main(void) nrfx_err_t err; uint8_t in_channel, out_channel; uint8_t ppi_channel; + const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(GPIOTE_INST); - /* Connect GPIOTE_0 IRQ to nrfx_gpiote_irq_handler */ - IRQ_CONNECT(DT_IRQN(DT_NODELABEL(gpiote)), - DT_IRQ(DT_NODELABEL(gpiote), priority), - nrfx_isr, nrfx_gpiote_irq_handler, 0); + /* Connect GPIOTE instance IRQ to irq handler */ + IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority), nrfx_isr, + NRFX_CONCAT(nrfx_gpiote_, GPIOTE_INST, _irq_handler), 0); /* Initialize GPIOTE (the interrupt priority passed as the parameter * here is ignored, see nrfx_glue.h). */ - err = nrfx_gpiote_init(0); + err = nrfx_gpiote_init(&gpiote, 0); if (err != NRFX_SUCCESS) { LOG_ERR("nrfx_gpiote_init error: 0x%08X", err); return 0; } - err = nrfx_gpiote_channel_alloc(&in_channel); + err = nrfx_gpiote_channel_alloc(&gpiote, &in_channel); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate in_channel, error: 0x%08X", err); return 0; } - err = nrfx_gpiote_channel_alloc(&out_channel); + err = nrfx_gpiote_channel_alloc(&gpiote, &out_channel); if (err != NRFX_SUCCESS) { LOG_ERR("Failed to allocate out_channel, error: 0x%08X", err); return 0; @@ -65,20 +69,22 @@ int main(void) /* Initialize input pin to generate event on high to low transition * (falling edge) and call button_handler() */ - static const nrfx_gpiote_input_config_t input_config = { - .pull = NRF_GPIO_PIN_PULLUP, - }; - const nrfx_gpiote_trigger_config_t trigger_config = { + static const nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLUP; + nrfx_gpiote_trigger_config_t trigger_config = { .trigger = NRFX_GPIOTE_TRIGGER_HITOLO, .p_in_channel = &in_channel, }; static const nrfx_gpiote_handler_config_t handler_config = { .handler = button_handler, }; - err = nrfx_gpiote_input_configure(INPUT_PIN, - &input_config, - &trigger_config, - &handler_config); + nrfx_gpiote_input_pin_config_t input_config = { + .p_pull_config = &pull_config, + .p_trigger_config = &trigger_config, + .p_handler_config = &handler_config + }; + + err = nrfx_gpiote_input_configure(&gpiote, INPUT_PIN, &input_config); + if (err != NRFX_SUCCESS) { LOG_ERR("nrfx_gpiote_input_configure error: 0x%08X", err); return 0; @@ -97,7 +103,7 @@ int main(void) .polarity = NRF_GPIOTE_POLARITY_TOGGLE, .init_val = 1, }; - err = nrfx_gpiote_output_configure(OUTPUT_PIN, + err = nrfx_gpiote_output_configure(&gpiote, OUTPUT_PIN, &output_config, &task_config); if (err != NRFX_SUCCESS) { @@ -105,8 +111,8 @@ int main(void) return 0; } - nrfx_gpiote_trigger_enable(INPUT_PIN, true); - nrfx_gpiote_out_task_enable(OUTPUT_PIN); + nrfx_gpiote_trigger_enable(&gpiote, INPUT_PIN, true); + nrfx_gpiote_out_task_enable(&gpiote, OUTPUT_PIN); LOG_INF("nrfx_gpiote initialized"); @@ -122,8 +128,8 @@ int main(void) * the button is pressed, the LED pin will be toggled. */ nrfx_gppi_channel_endpoints_setup(ppi_channel, - nrfx_gpiote_in_event_address_get(INPUT_PIN), - nrfx_gpiote_out_task_address_get(OUTPUT_PIN)); + nrfx_gpiote_in_event_address_get(&gpiote, INPUT_PIN), + nrfx_gpiote_out_task_address_get(&gpiote, OUTPUT_PIN)); /* Enable the channel. */ nrfx_gppi_channels_enable(BIT(ppi_channel)); diff --git a/samples/boards/reel_board/mesh_badge/src/main.c b/samples/boards/reel_board/mesh_badge/src/main.c index 13dedb3a5c1..49dd110ec0e 100644 --- a/samples/boards/reel_board/mesh_badge/src/main.c +++ b/samples/boards/reel_board/mesh_badge/src/main.c @@ -59,10 +59,10 @@ static ssize_t write_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, return len; } -static struct bt_uuid_128 name_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 name_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)); -static struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128( +static const struct bt_uuid_128 name_enc_uuid = BT_UUID_INIT_128( BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)); #define CPF_FORMAT_UTF8 0x19 diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst index f65294f2aa8..ce0034e2d86 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/README.rst +++ b/samples/boards/sensortile_box_pro/sensors-on-board/README.rst @@ -15,6 +15,7 @@ sensors: - HTS221: ambient temperature and relative humidity - LPS22DF: ambient temperature and atmospheric pressure - LSM6DSV16X: 6-Axis acceleration and angular velocity +- LIS2DU12: 3-Axis acceleration Requirements ************ @@ -67,7 +68,11 @@ The sample code outputs sensors data on the SensorTile.box Pro console. LPS22DF: Pressure:99.694 kpa LSM6DSV16X: Accel (m.s-2): x: -0.158, y: 0.158, z: 9.811 LSM6DSV16X: GYro (dps): x: 0.003, y: 0.000, z: -0.005 + LIS2DU12: Accel (m.s-2): x: -0.756, y: -0.249, z: -9.629 + 1:: lps22df trig 199 1:: lsm6dsv16x acc trig 836 1:: lsm6dsv16x gyr trig 836 + 1:: lis2mdl trig 402 + 1:: lis2du12 trig 1589 diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf index a7c57f2f746..97e6a2d17f2 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf +++ b/samples/boards/sensortile_box_pro/sensors-on-board/prj.conf @@ -8,8 +8,9 @@ CONFIG_GPIO=y CONFIG_SENSOR=y CONFIG_SENSOR_LOG_LEVEL_DBG=y CONFIG_HTS221_TRIGGER_NONE=y -CONFIG_LPS22DF_TRIGGER_OWN_THREAD=y +CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y +CONFIG_LIS2DU12_TRIGGER_OWN_THREAD=y CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c index 7aab1f36b13..cc27fc2c125 100644 --- a/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c +++ b/samples/boards/sensortile_box_pro/sensors-on-board/src/main.c @@ -15,7 +15,7 @@ #include -#ifdef CONFIG_LPS22DF_TRIGGER +#ifdef CONFIG_LPS2XDF_TRIGGER static int lps22df_trig_cnt; static void lps22df_trigger_handler(const struct device *dev, @@ -64,6 +64,17 @@ static void lis2mdl_trigger_handler(const struct device *dev, } #endif +#ifdef CONFIG_LIS2DU12_TRIGGER +static int lis2du12_trig_cnt; + +static void lis2du12_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2du12_trig_cnt++; +} +#endif + static void lps22df_config(const struct device *lps22df) { struct sensor_value odr_attr; @@ -78,7 +89,7 @@ static void lps22df_config(const struct device *lps22df) return; } -#ifdef CONFIG_LPS22DF_TRIGGER +#ifdef CONFIG_LPS2XDF_TRIGGER struct sensor_trigger trig; trig.type = SENSOR_TRIG_DATA_READY; @@ -167,6 +178,29 @@ static void lis2mdl_config(const struct device *lis2mdl) #endif } +static void lis2du12_config(const struct device *lis2du12) +{ + struct sensor_value odr_attr; + + /* set LIS2DU12 sampling frequency to 400 Hz */ + odr_attr.val1 = 400; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2du12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DU12\n"); + return; + } + +#ifdef CONFIG_LIS2DU12_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lis2du12, &trig, lis2du12_trigger_handler); +#endif +} + static int led_pattern_out(void) { const struct gpio_dt_spec led0_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); @@ -236,6 +270,7 @@ int main(void) const struct device *const lps22df = DEVICE_DT_GET_ONE(st_lps22df); const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); + const struct device *const lis2du12 = DEVICE_DT_GET_ONE(st_lis2du12); if (!device_is_ready(hts221)) { printk("%s: device not ready.\n", hts221->name); @@ -253,7 +288,12 @@ int main(void) printk("%s: device not ready.\n", lis2mdl->name); return 0; } + if (!device_is_ready(lis2du12)) { + printk("%s: device not ready.\n", lis2du12->name); + return 0; + } + lis2du12_config(lis2du12); lis2mdl_config(lis2mdl); lps22df_config(lps22df); lsm6dsv16x_config(lsm6dsv16x); @@ -264,6 +304,7 @@ int main(void) struct sensor_value lsm6dsv16x_accel[3], lsm6dsv16x_gyro[3]; struct sensor_value lis2mdl_magn[3]; struct sensor_value lis2mdl_temp; + struct sensor_value lis2du12_accel[3]; /* handle HTS221 sensor */ if (sensor_sample_fetch(hts221) < 0) { @@ -278,7 +319,7 @@ int main(void) } #endif -#ifndef CONFIG_LPS22DF_TRIGGER +#ifndef CONFIG_LPS2XDF_TRIGGER if (sensor_sample_fetch(lps22df) < 0) { printf("LPS22DF Sensor sample update error\n"); return 0; @@ -292,6 +333,13 @@ int main(void) } #endif +#ifndef CONFIG_LIS2DU12_TRIGGER + if (sensor_sample_fetch(lis2du12) < 0) { + printf("LIS2DU12 xl Sensor sample update error\n"); + return 0; + } +#endif + sensor_channel_get(hts221, SENSOR_CHAN_HUMIDITY, &hts221_hum); sensor_channel_get(hts221, SENSOR_CHAN_AMBIENT_TEMP, &hts221_temp); sensor_channel_get(lps22df, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); @@ -300,6 +348,7 @@ int main(void) sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gyro); sensor_channel_get(lis2mdl, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); sensor_channel_get(lis2mdl, SENSOR_CHAN_DIE_TEMP, &lis2mdl_temp); + sensor_channel_get(lis2du12, SENSOR_CHAN_ACCEL_XYZ, lis2du12_accel); /* Display sensor data */ @@ -343,7 +392,12 @@ int main(void) printf("LIS2MDL: Temperature: %.1f C\n", sensor_value_to_double(&lis2mdl_temp)); -#ifdef CONFIG_LPS22DF_TRIGGER + printf("LIS2DU12: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2du12_accel[0]), + sensor_value_to_double(&lis2du12_accel[1]), + sensor_value_to_double(&lis2du12_accel[2])); + +#ifdef CONFIG_LPS2XDF_TRIGGER printk("%d:: lps22df trig %d\n", cnt, lps22df_trig_cnt); #endif @@ -356,6 +410,10 @@ int main(void) printk("%d:: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); #endif +#ifdef CONFIG_LIS2DU12_TRIGGER + printk("%d:: lis2du12 trig %d\n", cnt, lis2du12_trig_cnt); +#endif + k_sleep(K_MSEC(2000)); } } diff --git a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay index 3cd6cb64bf5..f92c541e298 100644 --- a/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay +++ b/samples/boards/stm32/power_mgmt/adc/boards/nucleo_wba52cg.overlay @@ -10,3 +10,17 @@ io-channels = <&adc4 8>; }; }; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/blinky/README.rst b/samples/boards/stm32/power_mgmt/blinky/README.rst index 4687b07326e..1f75e2bddbc 100644 --- a/samples/boards/stm32/power_mgmt/blinky/README.rst +++ b/samples/boards/stm32/power_mgmt/blinky/README.rst @@ -9,6 +9,12 @@ Overview This sample is a minimum application to demonstrate basic power management behavior in a basic blinking LED set up using the :ref:`GPIO API ` in low power context. +Note that lptim instance selected for the low power timer is named **&stm32_lp_tick_source** +When setting a prescaler to decrease the lptimer input clock frequency, the system can sleep +for a longer timeout value and the CONFIG_SYS_CLOCK_TICKS_PER_SEC is adjusted. +For example, when clocking the low power Timer with LSE clock at 32768Hz and adding a +prescaler of <32>, then the kernel sleep period can reach 65536 * 32/32768 = 64 seconds +CONFIG_SYS_CLOCK_TICKS_PER_SEC is set to 1024. .. _stm32-pm-blinky-sample-requirements: @@ -30,7 +36,10 @@ Build and flash Blinky as follows, changing ``stm32l562e_dk`` for your board: :goals: build flash :compact: -After flashing, the LED starts to blink. +After flashing, the LED starts to blink with a fixed period (SLEEP_TIME_MS). +When LPTIM input clock has a prescaler, longer perdiod (up to 64 seconds) +of low power can be tested. + PM configurations ***************** diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay new file mode 100644 index 00000000000..f6f5d399148 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/blinky/boards/b_u585i_iot02a.overlay @@ -0,0 +1,9 @@ + /* + * give a prescaler to the lptim clock : LSE / 16 = 2048Hz + * so that the sleep period is of 32s in the sample application + * with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096 + * with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler + */ +&stm32_lp_tick_source { + st,prescaler = <16>; +}; diff --git a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay index 66bca43ae2f..11767aa004b 100644 --- a/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay +++ b/samples/boards/stm32/power_mgmt/blinky/boards/nucleo_wb55rg.overlay @@ -1,9 +1,9 @@ /* * give a prescaler to the lptim clock : LSE / 32 = 1024Hz * so that the sleep period is of 64s in the sample application - * + * with a LPTIM1 prescaler of <1> to <8>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is 4096 + * with a LPTIM1 prescaler >= <16>, CONFIG_SYS_CLOCK_TICKS_PER_SEC is LSE / prescaler */ - -&lptim1 { +&stm32_lp_tick_source { st,prescaler = <32>; }; diff --git a/samples/boards/stm32/power_mgmt/blinky/prj.conf b/samples/boards/stm32/power_mgmt/blinky/prj.conf index 9ac206bd0f3..fa60e82b4f0 100644 --- a/samples/boards/stm32/power_mgmt/blinky/prj.conf +++ b/samples/boards/stm32/power_mgmt/blinky/prj.conf @@ -2,3 +2,4 @@ CONFIG_PM=y CONFIG_PM_DEVICE=y CONFIG_PM_DEVICE_RUNTIME=y CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_ASSERT=y diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay new file mode 100644 index 00000000000..cce711c785c --- /dev/null +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/b_u585i_iot02a.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; +}; + +&usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; + + /* Configure device as wakeup source */ + wakeup-source; + + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ + pinctrl-1 = <&analog_pa9 &analog_pa10>; + pinctrl-names = "default", "sleep"; +}; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay index f924e6fdea5..bcbed7c5824 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wb55rg.overlay @@ -1,19 +1,35 @@ /* * Copyright (c) 2022 Linaro Limited + * Copyright (c) 2022 STMicroelectronics * * SPDX-License-Identifier: Apache-2.0 */ -&clk_hsi { - status = "okay"; +&cpu0{ + /* USART Wakeup requires automatic HSI16 switch on in deepsleep mode + * which isn't possible in Stop Mode 2. + * Remove Stop Mode 2 from supported modes + */ + cpu-power-states = <&stop0 &stop1>; }; &usart1 { + /* Set domain clock to HSI to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, <&rcc STM32_SRC_HSI USART1_SEL(2)>; + /* Configure device as wakeup source */ wakeup-source; + /* Configure sleep pinctrl configuration which will be used when + * device is not configured as wakeup source by the application. + * This use case is only applicable in PM_DEVICE mode. + */ pinctrl-1 = <&analog_pb6 &analog_pb7>; pinctrl-names = "default", "sleep"; }; + +&clk_hsi { + /* Make sure HSI is enabled */ + status = "okay"; +}; diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay index 83c607ff8a0..8b6b062cd67 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/boards/nucleo_wl55jc.overlay @@ -4,17 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ -&clk_lse { - status = "okay"; -}; -/* LPUART1 clock source on LSE : set console at 9600 */ &lpuart1 { - /delete-property/ clocks; + /* Set domain clock to LSE to allow wakeup from Stop mode */ clocks = <&rcc STM32_CLOCK_BUS_APB1_2 0x00000001>, <&rcc STM32_SRC_LSE LPUART1_SEL(3)>; + /* LPUART1 clock source on LSE : set console at 9600 */ current-speed = <9600>; + + /* Enable as wakeup source */ wakeup-source; - wakeup-line = <28>; +}; + +&clk_lse { + /* Make sure LSE clock is enabled */ + status = "okay"; }; diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf index 3e1a61bf9db..ca1e6cf73a9 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/prj.conf @@ -1,7 +1,8 @@ CONFIG_PM=y CONFIG_PM_DEVICE=y -CONFIG_PM_DEVICE_RUNTIME=n -CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=y + CONFIG_SHELL=y CONFIG_DEBUG=n diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml index 42528be505d..e0f61361500 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/sample.yaml @@ -4,8 +4,6 @@ tests: sample.boards.stm32.power_mgmt.serial_wakeup: tags: - UART - - Wake - - up - power harness: console harness_config: diff --git a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c index 74284abf41b..35846c04411 100644 --- a/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c +++ b/samples/boards/stm32/power_mgmt/serial_wakeup/src/main.c @@ -24,7 +24,8 @@ int main(void) #if CONFIG_PM_DEVICE /* In PM_DEVICE modes, enable device as a wakeup source will prevent * system to switch it off (clock off, set pins to sleep configuration, ...) - * It is not requested in PM mode only since this mode will not + * It is not requested in CONFIG_PM mode only as in this case, device is not + * suspended before stop mode entry. */ bool ret; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt b/samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt new file mode 100644 index 00000000000..8e813b2d175 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(stm32_pm_suspend_to_ram) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst new file mode 100644 index 00000000000..246ac96ea10 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/README.rst @@ -0,0 +1,42 @@ +.. _stm32-pm-suspend-to-ram-sample: + +STM32 PM Suspend to RAM +####################### + +Overview +******** + +This sample is a minimum application to demonstrate basic power management +behavior in a basic blinking LED set up using the :ref:`GPIO API ` in +low power context + ADC measurements and entropy. + +.. _stm32-pm-suspend-to-ram-sample-requirements: + +Requirements +************ + +The board should support enabling PM. For a STM32 based target, it means that +it should support a clock source alternative to Cortex Systick that can be used +in core sleep states, as LPTIM (:dtcompatible:`st,stm32-lptim`). +The board shall have an RTC to use it during the standby mode as a replacement +for LPTIM (which is disabled). The board shall also have RAM retention to be +able to restore context after standby. + +Building and Running +******************** + +Build and flash Blinky as follows, changing ``stm32wba55cg`` for your board: + +.. zephyr-app-commands:: + :zephyr-app: samples/boards/stm32/power_mgmt/suspend_to_ram + :board: stm32wba55cg + :goals: build flash + :compact: + +After flashing, the LED starts to blink. + +PM configurations +***************** + +By default, :kconfig:option:`CONFIG_PM_DEVICE` and :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` +are enabled. diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay new file mode 100644 index 00000000000..3ed3dab7a88 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/boards/nucleo_wba55cg.overlay @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 STMicroelectronics + */ + +/ { + /* Change min residency time to ease power consumption measurement */ + cpus { + power-states { + stop0: state0 { + min-residency-us = <500000>; + exit-latency-us = <50>; + }; + stop1: state1 { + min-residency-us = <1000000>; + exit-latency-us = <100>; + }; + standby: state2 { + min-residency-us = <2000000>; + exit-latency-us = <1000>; + }; + }; + }; + + zephyr,user { + /* adjust channel number according to pinmux in board.dts */ + io-channels = <&adc4 8>; + }; +}; + +&lptim1 { + status = "okay"; +}; + +&adc4 { + pinctrl-0 = <&adc4_in8_pa1>; + #address-cells = <1>; + #size-cells = <0>; + + channel@8 { + reg = <8>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; +}; diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf new file mode 100644 index 00000000000..acef64bb9a8 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/prj.conf @@ -0,0 +1,8 @@ +CONFIG_PM=y +CONFIG_PM_DEVICE=y +CONFIG_PM_DEVICE_RUNTIME=y +CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE=n +CONFIG_PM_S2RAM=y +CONFIG_ADC=y +CONFIG_ENTROPY_GENERATOR=y +#CONFIG_DEBUG=y diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml b/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml new file mode 100644 index 00000000000..f7eb4383664 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/sample.yaml @@ -0,0 +1,17 @@ +sample: + name: STM32 PM Standby Power Management +tests: + sample.boards.stm32.power_mgmt.suspend_to_ram: + tags: + - power + harness: console + harness_config: + type: one_line + regex: + - "Exit Standby" + filter: dt_compat_enabled("zephyr,power-state") and + dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_compat_enabled("st,stm32-lptim") + extra_args: "CONFIG_DEBUG=y" + platform_allow: + - nucleo_wba55cg diff --git a/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c new file mode 100644 index 00000000000..bb1ca9dbb55 --- /dev/null +++ b/samples/boards/stm32/power_mgmt/suspend_to_ram/src/main.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLEEP_TIME_STOP0_MS 800 +#define SLEEP_TIME_STOP1_MS 1500 +#define SLEEP_TIME_STANDBY_MS 3000 +#define SLEEP_TIME_BUSY_MS 2000 + +static const struct gpio_dt_spec led = + GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + +#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ + !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) +#error "No suitable devicetree overlay specified" +#endif + +#define DT_SPEC_AND_COMMA(node_id, prop, idx) \ + ADC_DT_SPEC_GET_BY_IDX(node_id, idx), + +/* Data of ADC io-channels specified in devicetree. */ +static const struct adc_dt_spec adc_channels[] = { + DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, + DT_SPEC_AND_COMMA) +}; + +const struct device *rng_dev; + +#define BUFFER_LENGTH 3 + +static uint8_t entropy_buffer[BUFFER_LENGTH] = {0}; + +static int adc_test(void) +{ + int err; + static uint32_t count; + uint16_t buf; + struct adc_sequence sequence = { + .buffer = &buf, + /* buffer size in bytes, not number of samples */ + .buffer_size = sizeof(buf), + }; + + /* Configure channels individually prior to sampling. */ + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + if (!adc_is_ready_dt(&adc_channels[i])) { + printk("ADC controller device %s not ready\n", adc_channels[i].dev->name); + return 0; + } + + err = adc_channel_setup_dt(&adc_channels[i]); + if (err < 0) { + printk("Could not setup channel #%d (%d)\n", i, err); + return 0; + } + } + + printk("ADC reading[%u]:\n", count++); + for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) { + int32_t val_mv; + + printk("- %s, channel %d: ", + adc_channels[i].dev->name, + adc_channels[i].channel_id); + + (void)adc_sequence_init_dt(&adc_channels[i], &sequence); + + err = adc_read_dt(&adc_channels[i], &sequence); + if (err < 0) { + printk("Could not read (%d)\n", err); + continue; + } + + /* + * If using differential mode, the 16 bit value + * in the ADC sample buffer should be a signed 2's + * complement value. + */ + if (adc_channels[i].channel_cfg.differential) { + val_mv = (int32_t)((int16_t)buf); + } else { + val_mv = (int32_t)buf; + } + printk("%"PRId32, val_mv); + err = adc_raw_to_millivolts_dt(&adc_channels[i], + &val_mv); + /* conversion to mV may not be supported, skip if not */ + if (err < 0) { + printk(" (value in mV not available)\n"); + } else { + printk(" = %"PRId32" mV\n", val_mv); + } + } + + return 0; +} + +void print_buf(uint8_t *buffer) +{ + int i; + int count = 0; + + for (i = 0; i < BUFFER_LENGTH; i++) { + printk(" 0x%02x", buffer[i]); + if (buffer[i] == 0x00) { + count++; + } + } + printk("\n"); +} + +int main(void) +{ + __ASSERT_NO_MSG(gpio_is_ready_dt(&led)); + + rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + if (!device_is_ready(rng_dev)) { + printk("error: random device not ready"); + } + + printk("Device ready\n"); + + while (true) { + gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); + k_msleep(SLEEP_TIME_STOP0_MS); + printk("Exit Stop0\n"); + + gpio_pin_set_dt(&led, 1); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_set_dt(&led, 0); + k_msleep(SLEEP_TIME_STOP1_MS); + printk("Exit Stop1\n"); + + (void)memset(entropy_buffer, 0x00, BUFFER_LENGTH); + entropy_get_entropy(rng_dev, (char *)entropy_buffer, BUFFER_LENGTH); + printk("Sync entropy: "); + print_buf(entropy_buffer); + + gpio_pin_set_dt(&led, 1); + adc_test(); + k_busy_wait(SLEEP_TIME_BUSY_MS*1000); + gpio_pin_configure_dt(&led, GPIO_DISCONNECTED); + k_msleep(SLEEP_TIME_STANDBY_MS); + printk("Exit Standby\n"); + } + return 0; +} diff --git a/samples/charger/src/main.c b/samples/charger/src/main.c index 4f24e1932d9..91961fe15b1 100644 --- a/samples/charger/src/main.c +++ b/samples/charger/src/main.c @@ -45,7 +45,7 @@ int main(void) val.status = CHARGER_STATUS_CHARGING; - ret = charger_set_prop(chgdev, CHARGER_PROP_STATUS, &val); + ret = charger_charge_enable(chgdev, true); if (ret == -ENOTSUP) { printk("Enabling charge not supported, assuming auto charge enable\n"); continue; diff --git a/samples/cpp/hello_world/CMakeLists.txt b/samples/cpp/hello_world/CMakeLists.txt new file mode 100644 index 00000000000..da4e1f7da41 --- /dev/null +++ b/samples/cpp/hello_world/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(hello_cpp_world) + +target_sources(app PRIVATE src/main.cpp) diff --git a/samples/cpp/hello_world/README.rst b/samples/cpp/hello_world/README.rst new file mode 100644 index 00000000000..cfc2541ff39 --- /dev/null +++ b/samples/cpp/hello_world/README.rst @@ -0,0 +1,33 @@ +.. _hello_cpp_world: + +Hello C++ World +############### + +Overview +******** + +A simple :ref:`C++ ` sample that can be used with many supported board and prints +"Hello, C++ world!" to the console. + +Building and Running +******************** + +This configuration can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/cpp/hello_world + :host-os: unix + :board: qemu_riscv32 + :goals: run + :compact: + +To build for another board, change "qemu_riscv32" above to that board's name. + +Sample Output +============= + +.. code-block:: console + + Hello C++, world! qemu_riscv32 + +Exit QEMU by pressing :kbd:`CTRL+C` diff --git a/samples/cpp/hello_world/prj.conf b/samples/cpp/hello_world/prj.conf new file mode 100644 index 00000000000..b801dee1855 --- /dev/null +++ b/samples/cpp/hello_world/prj.conf @@ -0,0 +1,2 @@ +CONFIG_CPP=y +CONFIG_REQUIRES_FULL_LIBCPP=y diff --git a/samples/cpp/hello_world/sample.yaml b/samples/cpp/hello_world/sample.yaml new file mode 100644 index 00000000000..244c7b4f345 --- /dev/null +++ b/samples/cpp/hello_world/sample.yaml @@ -0,0 +1,24 @@ +sample: + description: Hello World C++ sample, the simplest C++ Zephyr application + name: hello cpp world +common: + tags: introduction + integration_platforms: + - qemu_riscv32 + harness: console + harness_config: + type: one_line + regex: + - "Hello, C\\+\\+ world! (.*)" +tests: + sample.cpp.helloworld: + min_ram: 128 + arch_exclude: + # See #66027 + - xtensa + platform_exclude: + # See zephyrproject-rtos/sdk-ng#593 + - qemu_x86 + - intel_ish_5_4_1 + - intel_ish_5_6_0 + - intel_ish_5_8_0 diff --git a/samples/cpp/hello_world/src/main.cpp b/samples/cpp/hello_world/src/main.cpp new file mode 100644 index 00000000000..369e3573526 --- /dev/null +++ b/samples/cpp/hello_world/src/main.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +int main(void) +{ + std::cout << "Hello, C++ world! " << CONFIG_BOARD << std::endl; + return 0; +} diff --git a/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay b/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay new file mode 100644 index 00000000000..ce71fa65f01 --- /dev/null +++ b/samples/drivers/audio/dmic/boards/mimxrt595_evk_cm33.overlay @@ -0,0 +1,3 @@ +dmic_dev: &dmic0 { + status = "okay"; +}; diff --git a/samples/drivers/can/counter/sample.yaml b/samples/drivers/can/counter/sample.yaml index 579fc82a069..edbb0817c4d 100644 --- a/samples/drivers/can/counter/sample.yaml +++ b/samples/drivers/can/counter/sample.yaml @@ -7,6 +7,7 @@ tests: integration_platforms: - native_sim filter: dt_chosen_enabled("zephyr,canbus") and not dt_compat_enabled("kvaser,pcican") + and not dt_compat_enabled("infineon,xmc4xxx-can-node") harness: console harness_config: type: one_line diff --git a/samples/drivers/can/counter/src/main.c b/samples/drivers/can/counter/src/main.c index 78048308ca2..2119069e43e 100644 --- a/samples/drivers/can/counter/src/main.c +++ b/samples/drivers/can/counter/src/main.c @@ -63,7 +63,7 @@ void rx_thread(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg2); ARG_UNUSED(arg3); const struct can_filter filter = { - .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, + .flags = CAN_FILTER_IDE, .id = COUNTER_MSG_ID, .mask = CAN_EXT_ID_MASK }; @@ -76,6 +76,10 @@ void rx_thread(void *arg1, void *arg2, void *arg3) while (1) { k_msgq_get(&counter_msgq, &frame, K_FOREVER); + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } + if (frame.dlc != 2U) { printf("Wrong data length: %u\n", frame.dlc); continue; @@ -92,6 +96,10 @@ void change_led_work_handler(struct k_work *work) int ret; while (k_msgq_get(&change_led_msgq, &frame, K_NO_WAIT) == 0) { + if (IS_ENABLED(CONFIG_CAN_ACCEPT_RTR) && (frame.flags & CAN_FRAME_RTR) != 0U) { + continue; + } + if (led.port == NULL) { printf("LED %s\n", frame.data[0] == SET_LED ? "ON" : "OFF"); } else { @@ -192,7 +200,7 @@ void state_change_callback(const struct device *dev, enum can_state state, int main(void) { const struct can_filter change_led_filter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = LED_MSG_ID, .mask = CAN_STD_ID_MASK }; diff --git a/samples/drivers/counter/alarm/CMakeLists.txt b/samples/drivers/counter/alarm/CMakeLists.txt index eadc9e99e67..747c2b27ebd 100644 --- a/samples/drivers/counter/alarm/CMakeLists.txt +++ b/samples/drivers/counter/alarm/CMakeLists.txt @@ -9,6 +9,6 @@ target_sources(app PRIVATE ${app_sources}) if(CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/drivers/display/sample.yaml b/samples/drivers/display/sample.yaml index ba93efd5c2e..579773f3c8c 100644 --- a/samples/drivers/display/sample.yaml +++ b/samples/drivers/display/sample.yaml @@ -146,3 +146,11 @@ tests: - CONFIG_IDLE_STACK_SIZE=400 harness_config: fixture: fixture_display + sample.display.builtin: + # This test case is intended to insure that this sample builds & runs + # correctly for all boards that have a supported built-in display. + filter: dt_chosen_enabled("zephyr,display") + harness: console + harness_config: + fixture: fixture_display + tags: display diff --git a/samples/drivers/display/src/main.c b/samples/drivers/display/src/main.c index 5e74e7a018d..a9267b51c74 100644 --- a/samples/drivers/display/src/main.c +++ b/samples/drivers/display/src/main.c @@ -140,23 +140,36 @@ static void fill_buffer_bgr565(enum corner corner, uint8_t grey, uint8_t *buf, } } -static void fill_buffer_mono(enum corner corner, uint8_t grey, uint8_t *buf, - size_t buf_size) +static void fill_buffer_mono(enum corner corner, uint8_t grey, + uint8_t black, uint8_t white, + uint8_t *buf, size_t buf_size) { uint16_t color; switch (corner) { case BOTTOM_LEFT: - color = (grey & 0x01u) ? 0xFFu : 0x00u; + color = (grey & 0x01u) ? white : black; break; default: - color = 0; + color = black; break; } memset(buf, color, buf_size); } +static inline void fill_buffer_mono01(enum corner corner, uint8_t grey, + uint8_t *buf, size_t buf_size) +{ + fill_buffer_mono(corner, grey, 0x00u, 0xFFu, buf, buf_size); +} + +static inline void fill_buffer_mono10(enum corner corner, uint8_t grey, + uint8_t *buf, size_t buf_size) +{ + fill_buffer_mono(corner, grey, 0xFFu, 0x00u, buf, buf_size); +} + int main(void) { size_t x; @@ -166,6 +179,7 @@ int main(void) size_t h_step; size_t scale; size_t grey_count; + uint8_t bg_color; uint8_t *buf; int32_t grey_scale_sleep; const struct device *display_dev; @@ -196,8 +210,17 @@ int main(void) rect_h = 1; } - h_step = rect_h; - scale = (capabilities.x_resolution / 8) / rect_h; + if ((capabilities.x_resolution < 3 * rect_w) || + (capabilities.y_resolution < 3 * rect_h) || + (capabilities.x_resolution < 8 * rect_h)) { + rect_w = capabilities.x_resolution * 40 / 100; + rect_h = capabilities.y_resolution * 40 / 100; + h_step = capabilities.y_resolution * 20 / 100; + scale = 1; + } else { + h_step = rect_h; + scale = (capabilities.x_resolution / 8) / rect_h; + } rect_w *= scale; rect_h *= scale; @@ -216,25 +239,36 @@ int main(void) switch (capabilities.current_pixel_format) { case PIXEL_FORMAT_ARGB_8888: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_argb8888; buf_size *= 4; break; case PIXEL_FORMAT_RGB_888: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_rgb888; buf_size *= 3; break; case PIXEL_FORMAT_RGB_565: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_rgb565; buf_size *= 2; break; case PIXEL_FORMAT_BGR_565: + bg_color = 0xFFu; fill_buffer_fnc = fill_buffer_bgr565; buf_size *= 2; break; case PIXEL_FORMAT_MONO01: + bg_color = 0xFFu; + fill_buffer_fnc = fill_buffer_mono01; + buf_size = DIV_ROUND_UP(DIV_ROUND_UP( + buf_size, NUM_BITS(uint8_t)), sizeof(uint8_t)); + break; case PIXEL_FORMAT_MONO10: - fill_buffer_fnc = fill_buffer_mono; - buf_size /= 8; + bg_color = 0x00u; + fill_buffer_fnc = fill_buffer_mono10; + buf_size = DIV_ROUND_UP(DIV_ROUND_UP( + buf_size, NUM_BITS(uint8_t)), sizeof(uint8_t)); break; default: LOG_ERR("Unsupported pixel format. Aborting sample."); @@ -256,7 +290,7 @@ int main(void) #endif } - (void)memset(buf, 0xFFu, buf_size); + (void)memset(buf, bg_color, buf_size); buf_desc.buf_size = buf_size; buf_desc.pitch = capabilities.x_resolution; diff --git a/samples/drivers/espi/prj_mec172xevb_assy6906.conf b/samples/drivers/espi/boards/mec172xevb_assy6906.conf similarity index 100% rename from samples/drivers/espi/prj_mec172xevb_assy6906.conf rename to samples/drivers/espi/boards/mec172xevb_assy6906.conf diff --git a/samples/drivers/espi/src/main.c b/samples/drivers/espi/src/main.c index 71f0a86d75a..ce6cb08c322 100644 --- a/samples/drivers/espi/src/main.c +++ b/samples/drivers/espi/src/main.c @@ -10,33 +10,37 @@ #include #include #include -#include #include #include #include /* OOB operations will be attempted regardless of channel enabled or not */ #include "espi_oob_handler.h" + +#ifdef CONFIG_ESPI_SAF +#include +#endif + LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL); /* eSPI flash parameters */ -#define MAX_TEST_BUF_SIZE 1024u -#define MAX_FLASH_REQUEST 64u -#define TARGET_FLASH_REGION 0x72000ul +#define MAX_TEST_BUF_SIZE 1024u +#define MAX_FLASH_REQUEST 64u +#define TARGET_FLASH_REGION 0x72000ul -#define ESPI_FREQ_20MHZ 20u -#define ESPI_FREQ_25MHZ 25u -#define ESPI_FREQ_66MHZ 66u +#define ESPI_FREQ_20MHZ 20u +#define ESPI_FREQ_25MHZ 25u +#define ESPI_FREQ_66MHZ 66u -#define K_WAIT_DELAY 100u +#define K_WAIT_DELAY 100u /* eSPI event */ -#define EVENT_MASK 0x0000FFFFu -#define EVENT_DETAILS_MASK 0xFFFF0000u -#define EVENT_DETAILS_POS 16u -#define EVENT_TYPE(x) (x & EVENT_MASK) -#define EVENT_DETAILS(x) ((x & EVENT_DETAILS_MASK) >> EVENT_DETAILS_POS) +#define EVENT_MASK 0x0000FFFFu +#define EVENT_DETAILS_MASK 0xFFFF0000u +#define EVENT_DETAILS_POS 16u +#define EVENT_TYPE(x) (x & EVENT_MASK) +#define EVENT_DETAILS(x) ((x & EVENT_DETAILS_MASK) >> EVENT_DETAILS_POS) -#define PWR_SEQ_TIMEOUT 3000u +#define PWR_SEQ_TIMEOUT 3000u /* The devicetree node identifier for the board power rails pins. */ #define BRD_PWR_NODE DT_NODELABEL(board_power) @@ -62,25 +66,25 @@ static uint8_t flash_read_buf[MAX_TEST_BUF_SIZE]; #endif #ifdef CONFIG_ESPI_SAF -#define SAF_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(espi_saf0)) +#define SAF_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(espi_saf0)) -#define SAF_TEST_FREQ_HZ 24000000U +#define SAF_TEST_FREQ_HZ 24000000U #define SAF_TEST_BUF_SIZE 4096U /* SPI address of 4KB sector modified by test */ #define SAF_SPI_TEST_ADDRESS 0x1000U -#define SPI_WRITE_STATUS1 0x01U -#define SPI_WRITE_STATUS2 0x31U -#define SPI_WRITE_DISABLE 0x04U -#define SPI_READ_STATUS1 0x05U -#define SPI_WRITE_ENABLE 0x06U -#define SPI_READ_STATUS2 0x35U +#define SPI_WRITE_STATUS1 0x01U +#define SPI_WRITE_STATUS2 0x31U +#define SPI_WRITE_DISABLE 0x04U +#define SPI_READ_STATUS1 0x05U +#define SPI_WRITE_ENABLE 0x06U +#define SPI_READ_STATUS2 0x35U #define SPI_WRITE_ENABLE_VS 0x50U -#define SPI_READ_JEDEC_ID 0x9FU +#define SPI_READ_JEDEC_ID 0x9FU #define SPI_STATUS1_BUSY 0x80U -#define SPI_STATUS2_QE 0x02U +#define SPI_STATUS2_QE 0x02U #define W25Q128_JEDEC_ID 0x001840efU @@ -95,10 +99,8 @@ struct saf_addr_info { uintptr_t saf_struct_addr; uintptr_t saf_exp_addr; }; -static const struct device *const qspi_dev = - DEVICE_DT_GET(DT_NODELABEL(spi0)); -static const struct device *const espi_saf_dev = - DEVICE_DT_GET(DT_NODELABEL(espi_saf0)); +static const struct device *const qspi_dev = DEVICE_DT_GET(DT_NODELABEL(spi0)); +static const struct device *const espi_saf_dev = DEVICE_DT_GET(DT_NODELABEL(espi_saf0)); static uint8_t safbuf[SAF_TEST_BUF_SIZE] __aligned(4); static uint8_t safbuf2[SAF_TEST_BUF_SIZE] __aligned(4); @@ -116,15 +118,8 @@ static const struct espi_saf_flash_cfg flash_w25q128 = { .cont_prefix = 0U, .cs_cfg_descr_ids = MCHP_CS0_CFG_DESCR_IDX_REG_VAL, .flags = 0, - .descr = { - MCHP_W25Q128_CM_RD_D0, - MCHP_W25Q128_CM_RD_D1, - MCHP_W25Q128_CM_RD_D2, - MCHP_W25Q128_ENTER_CM_D0, - MCHP_W25Q128_ENTER_CM_D1, - MCHP_W25Q128_ENTER_CM_D2 - } -}; + .descr = {MCHP_W25Q128_CM_RD_D0, MCHP_W25Q128_CM_RD_D1, MCHP_W25Q128_CM_RD_D2, + MCHP_W25Q128_ENTER_CM_D0, MCHP_W25Q128_ENTER_CM_D1, MCHP_W25Q128_ENTER_CM_D2}}; /* * SAF driver configuration. @@ -136,37 +131,27 @@ static const struct espi_saf_flash_cfg flash_w25q128 = { #ifdef CONFIG_ESPI_SAF_XEC_V2 static const struct espi_saf_cfg saf_cfg1 = { .nflash_devices = 1U, - .hwcfg = { - .version = 2U, /* TODO */ - .flags = 0U, /* TODO */ - .qmspi_cpha = 0U, /* TODO */ - .qmspi_cs_timing = 0U, /* TODO */ - .flash_pd_timeout = 0U, /* TODO */ - .flash_pd_min_interval = 0U, /* TODO */ - .generic_descr = { - MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, - MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15 - }, - .tag_map = { 0U, 0U, 0U } - }, - .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128 -}; + .hwcfg = {.version = 2U, /* TODO */ + .flags = 0U, /* TODO */ + .qmspi_cpha = 0U, /* TODO */ + .qmspi_cs_timing = 0U, /* TODO */ + .flash_pd_timeout = 0U, /* TODO */ + .flash_pd_min_interval = 0U, /* TODO */ + .generic_descr = {MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, + MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15}, + .tag_map = {0U, 0U, 0U}}, + .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128}; #else static const struct espi_saf_cfg saf_cfg1 = { .nflash_devices = 1U, - .hwcfg = { - .qmspi_freq_hz = 0U, - .qmspi_cs_timing = 0U, - .qmspi_cpha = 0U, - .flags = 0U, - .generic_descr = { - MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, - MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15 - }, - .tag_map = { 0U, 0U, 0U } - }, - .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128 -}; + .hwcfg = {.qmspi_freq_hz = 0U, + .qmspi_cs_timing = 0U, + .qmspi_cpha = 0U, + .flags = 0U, + .generic_descr = {MCHP_SAF_EXIT_CM_DESCR12, MCHP_SAF_EXIT_CM_DESCR13, + MCHP_SAF_POLL_DESCR14, MCHP_SAF_POLL_DESCR15}, + .tag_map = {0U, 0U, 0U}}, + .flash_cfgs = (struct espi_saf_flash_cfg *)&flash_w25q128}; #endif /* @@ -175,28 +160,24 @@ static const struct espi_saf_cfg saf_cfg1 = { static const struct espi_saf_pr w25q128_protect_regions[2] = { { .start = 0xe00000U, - .size = 0x100000U, + .size = 0x100000U, .master_bm_we = (1U << MCHP_SAF_MSTR_HOST_PCH_ME), .master_bm_rd = (1U << MCHP_SAF_MSTR_HOST_PCH_ME), .pr_num = 1U, - .flags = MCHP_SAF_PR_FLAG_ENABLE - | MCHP_SAF_PR_FLAG_LOCK, + .flags = MCHP_SAF_PR_FLAG_ENABLE | MCHP_SAF_PR_FLAG_LOCK, }, { .start = 0xf00000U, - .size = 0x100000U, + .size = 0x100000U, .master_bm_we = (1U << MCHP_SAF_MSTR_HOST_PCH_LAN), .master_bm_rd = (1U << MCHP_SAF_MSTR_HOST_PCH_LAN), .pr_num = 2U, - .flags = MCHP_SAF_PR_FLAG_ENABLE - | MCHP_SAF_PR_FLAG_LOCK, + .flags = MCHP_SAF_PR_FLAG_ENABLE | MCHP_SAF_PR_FLAG_LOCK, }, }; -static const struct espi_saf_protection saf_pr_w25q128 = { - .nregions = 2U, - .pregions = w25q128_protect_regions -}; +static const struct espi_saf_protection saf_pr_w25q128 = {.nregions = 2U, + .pregions = w25q128_protect_regions}; /* * Initialize the local attached SPI flash. @@ -230,8 +211,7 @@ int spi_saf_init(void) memset(safbuf2, 0x55, 4U); spi_cfg.frequency = SAF_TEST_FREQ_HZ; - spi_cfg.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB - | SPI_WORD_SET(8); + spi_cfg.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8); /* * Use SPI master mode and inform driver the SPI controller hardware @@ -313,13 +293,13 @@ int spi_saf_init(void) rx_bufs.buffers = NULL; rx_bufs.count = 0U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Send write enable volatile spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -335,13 +315,13 @@ int spi_saf_init(void) rx_bufs.buffers = NULL; rx_bufs.count = 0U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Write SPI STATUS2 QE=1 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -362,20 +342,21 @@ int spi_saf_init(void) rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Read SPI STATUS1 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } spi_status1 = safbuf2[0]; if (spi_status1 & SPI_STATUS1_BUSY) { LOG_ERR("SPI BUSY set after write to volatile STATUS2:" - " STATUS1=0x%02X", spi_status1); + " STATUS1=0x%02X", + spi_status1); return ret; } @@ -396,13 +377,13 @@ int spi_saf_init(void) rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; - ret = spi_transceive(qspi_dev, - (const struct spi_config *)&spi_cfg, + ret = spi_transceive(qspi_dev, (const struct spi_config *)&spi_cfg, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); if (ret) { LOG_ERR("Read 2 of SPI STATUS2 spi_transceive" - " failure: error %d", ret); + " failure: error %d", + ret); return ret; } @@ -429,8 +410,7 @@ int espi_saf_init(void) LOG_INF("eSPI SAF configured successfully!"); } - ret = espi_saf_set_protection_regions(espi_saf_dev, - &saf_pr_w25q128); + ret = espi_saf_set_protection_regions(espi_saf_dev, &saf_pr_w25q128); if (ret) { LOG_ERR("Failed to set SAF protection region(s) %d", ret); } else { @@ -440,8 +420,7 @@ int espi_saf_init(void) return ret; } -static int pr_check_range(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_range(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { uint32_t limit; @@ -459,17 +438,14 @@ static int pr_check_range(struct mchp_espi_saf *regs, return 0; } -static int pr_check_enable(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_enable(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { if (pr->flags & MCHP_SAF_PR_FLAG_ENABLE) { - if (regs->SAF_PROT_RG[pr->pr_num].LIMIT > - regs->SAF_PROT_RG[pr->pr_num].START) { + if (regs->SAF_PROT_RG[pr->pr_num].LIMIT > regs->SAF_PROT_RG[pr->pr_num].START) { return 0; } } else { - if (regs->SAF_PROT_RG[pr->pr_num].START > - regs->SAF_PROT_RG[pr->pr_num].LIMIT) { + if (regs->SAF_PROT_RG[pr->pr_num].START > regs->SAF_PROT_RG[pr->pr_num].LIMIT) { return 0; } } @@ -477,8 +453,7 @@ static int pr_check_enable(struct mchp_espi_saf *regs, return -2; } -static int pr_check_lock(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_lock(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { if (pr->flags & MCHP_SAF_PR_FLAG_LOCK) { if (regs->SAF_PROT_LOCK & BIT(pr->pr_num)) { @@ -496,16 +471,13 @@ static int pr_check_lock(struct mchp_espi_saf *regs, /* * NOTE: bit[0] of bit map registers is read-only = 1 */ -static int pr_check_master_bm(struct mchp_espi_saf *regs, - const struct espi_saf_pr *pr) +static int pr_check_master_bm(struct mchp_espi_saf *regs, const struct espi_saf_pr *pr) { - if (regs->SAF_PROT_RG[pr->pr_num].WEBM != - (pr->master_bm_we | BIT(0))) { + if (regs->SAF_PROT_RG[pr->pr_num].WEBM != (pr->master_bm_we | BIT(0))) { return -4; } - if (regs->SAF_PROT_RG[pr->pr_num].RDBM != - (pr->master_bm_rd | BIT(0))) { + if (regs->SAF_PROT_RG[pr->pr_num].RDBM != (pr->master_bm_rd | BIT(0))) { return -4; } @@ -530,29 +502,25 @@ static int espi_saf_test_pr1(const struct espi_saf_protection *spr) for (size_t n = 0U; n < spr->nregions; n++) { rc = pr_check_range(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u range fail", - pr->pr_num); + LOG_INF("SAF Protection region %u range fail", pr->pr_num); return rc; } rc = pr_check_enable(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u enable fail", - pr->pr_num); + LOG_INF("SAF Protection region %u enable fail", pr->pr_num); return rc; } rc = pr_check_lock(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u lock check fail", - pr->pr_num); + LOG_INF("SAF Protection region %u lock check fail", pr->pr_num); return rc; } rc = pr_check_master_bm(saf_regs, pr); if (rc) { - LOG_INF("SAF Protection region %u Master select fail", - pr->pr_num); + LOG_INF("SAF Protection region %u Master select fail", pr->pr_num); return rc; } @@ -568,7 +536,7 @@ static int espi_saf_test_pr1(const struct espi_saf_protection *spr) static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) { int rc, chunk_len, n; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; if ((dest == NULL) || (len < 0)) { return -EINVAL; @@ -589,8 +557,8 @@ static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) rc = espi_saf_flash_read(espi_saf_dev, &saf_pkt); if (rc != 0) { LOG_INF("%s: error = %d: chunk_len = %d " - "spi_addr = %x", __func__, rc, chunk_len, - spi_addr); + "spi_addr = %x", + __func__, rc, chunk_len, spi_addr); return rc; } @@ -610,7 +578,7 @@ static int saf_read(uint32_t spi_addr, uint8_t *dest, int len) static int saf_erase_block(uint32_t spi_addr, enum saf_erase_size ersz) { int rc; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; switch (ersz) { case SAF_ERASE_4K: @@ -646,7 +614,7 @@ static int saf_erase_block(uint32_t spi_addr, enum saf_erase_size ersz) static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) { int rc, chunk_len, n; - struct espi_saf_packet saf_pkt = { 0 }; + struct espi_saf_packet saf_pkt = {0}; if ((src == NULL) || (progsz < 0) || (progsz > 256)) { return -EINVAL; @@ -670,8 +638,8 @@ static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) rc = espi_saf_flash_write(espi_saf_dev, &saf_pkt); if (rc != 0) { - LOG_INF("%s: error = %d: erase fail spi_addr = 0x%X", - __func__, rc, spi_addr); + LOG_INF("%s: error = %d: erase fail spi_addr = 0x%X", __func__, rc, + spi_addr); return rc; } @@ -683,7 +651,6 @@ static int saf_page_prog(uint32_t spi_addr, const uint8_t *src, int progsz) return progsz; } - int espi_saf_test1(uint32_t spi_addr) { int rc, retries; @@ -694,11 +661,9 @@ int espi_saf_test1(uint32_t spi_addr) LOG_INF("%s: activate = %d", __func__, rc); if (spi_addr & 0xfffU) { - LOG_INF("%s: SPI address 0x%08x not 4KB aligned", __func__, - spi_addr); - spi_addr &= ~(4096U-1U); - LOG_INF("%s: Aligned SPI address to 0x%08x", __func__, - spi_addr); + LOG_INF("%s: SPI address 0x%08x not 4KB aligned", __func__, spi_addr); + spi_addr &= ~(4096U - 1U); + LOG_INF("%s: Aligned SPI address to 0x%08x", __func__, spi_addr); } memset(safbuf, 0x55, sizeof(safbuf)); @@ -710,8 +675,8 @@ int espi_saf_test1(uint32_t spi_addr) /* read 4KB sector at 0 */ rc = saf_read(spi_addr, safbuf, 4096); if (rc != 4096) { - LOG_INF("%s: error=%d Read 4K sector at 0x%X failed", - __func__, rc, spi_addr); + LOG_INF("%s: error=%d Read 4K sector at 0x%X failed", __func__, rc, + spi_addr); return rc; } @@ -725,23 +690,25 @@ int espi_saf_test1(uint32_t spi_addr) if (rc == 0) { LOG_INF("4KB sector at 0x%x is in erased state. " - "Continue tests", spi_addr); + "Continue tests", + spi_addr); erased = true; } else { LOG_INF("4KB sector at 0x%x not in erased state. " - "Send 4K erase.", spi_addr); + "Send 4K erase.", + spi_addr); rc = saf_erase_block(spi_addr, SAF_ERASE_4K); if (rc != 0) { LOG_INF("SAF erase block at 0x%x returned " - "error %d", spi_addr, rc); + "error %d", + spi_addr, rc); return rc; } } } if (!erased) { - LOG_INF("%s: Could not erase 4KB sector at 0x%08x", - __func__, spi_addr); + LOG_INF("%s: Could not erase 4KB sector at 0x%08x", __func__, spi_addr); return -1; } @@ -762,11 +729,9 @@ int espi_saf_test1(uint32_t spi_addr) LOG_INF("%s: Program 4KB sector at 0x%X", __func__, saddr); while (n < progsz) { - rc = saf_page_prog(saddr, (const uint8_t *)src, - (int)chunksz); + rc = saf_page_prog(saddr, (const uint8_t *)src, (int)chunksz); if (rc != chunksz) { - LOG_INF("saf_page_prog error=%d at 0x%X", rc, - saddr); + LOG_INF("saf_page_prog error=%d at 0x%X", rc, saddr); break; } saddr += chunksz; @@ -801,17 +766,14 @@ static void host_warn_handler(uint32_t signal, uint32_t status) LOG_INF("Host reset warning %d", status); if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) { LOG_INF("HOST RST ACK %d", status); - espi_send_vwire(espi_dev, - ESPI_VWIRE_SIGNAL_HOST_RST_ACK, - status); + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, status); } break; case ESPI_VWIRE_SIGNAL_SUS_WARN: LOG_INF("Host suspend warning %d", status); if (!IS_ENABLED(CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE)) { LOG_INF("SUS ACK %d", status); - espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_ACK, - status); + espi_send_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_ACK, status); } break; default: @@ -820,8 +782,7 @@ static void host_warn_handler(uint32_t signal, uint32_t status) } /* eSPI bus event handler */ -static void espi_reset_handler(const struct device *dev, - struct espi_callback *cb, +static void espi_reset_handler(const struct device *dev, struct espi_callback *cb, struct espi_event event) { if (event.evt_type == ESPI_BUS_RESET) { @@ -831,8 +792,7 @@ static void espi_reset_handler(const struct device *dev, } /* eSPI logical channels enable/disable event handler */ -static void espi_ch_handler(const struct device *dev, - struct espi_callback *cb, +static void espi_ch_handler(const struct device *dev, struct espi_callback *cb, struct espi_event event) { if (event.evt_type == ESPI_BUS_EVENT_CHANNEL_READY) { @@ -868,8 +828,7 @@ static void vwire_handler(const struct device *dev, struct espi_callback *cb, break; case ESPI_VWIRE_SIGNAL_SUS_WARN: case ESPI_VWIRE_SIGNAL_HOST_RST_WARN: - host_warn_handler(event.evt_details, - event.evt_data); + host_warn_handler(event.evt_details, event.evt_data); break; } } @@ -894,8 +853,7 @@ static void periph_handler(const struct device *dev, struct espi_callback *cb, espi_remove_callback(espi_dev, &p80_cb); break; default: - LOG_INF("%s periph 0x%x [%x]", __func__, periph_type, - event.evt_data); + LOG_INF("%s periph 0x%x [%x]", __func__, periph_type, event.evt_data); } } @@ -923,8 +881,8 @@ int espi_init(void) ret = espi_config(espi_dev, &cfg); if (ret) { - LOG_ERR("Failed to configure eSPI slave channels:%x err: %d", - cfg.channel_caps, ret); + LOG_ERR("Failed to configure eSPI slave channels:%x err: %d", cfg.channel_caps, + ret); return ret; } else { LOG_INF("eSPI slave configured successfully!"); @@ -932,15 +890,11 @@ int espi_init(void) LOG_INF("eSPI test - callbacks initialization... "); espi_init_callback(&espi_bus_cb, espi_reset_handler, ESPI_BUS_RESET); - espi_init_callback(&vw_rdy_cb, espi_ch_handler, - ESPI_BUS_EVENT_CHANNEL_READY); - espi_init_callback(&vw_cb, vwire_handler, - ESPI_BUS_EVENT_VWIRE_RECEIVED); - espi_init_callback(&p80_cb, periph_handler, - ESPI_BUS_PERIPHERAL_NOTIFICATION); + espi_init_callback(&vw_rdy_cb, espi_ch_handler, ESPI_BUS_EVENT_CHANNEL_READY); + espi_init_callback(&vw_cb, vwire_handler, ESPI_BUS_EVENT_VWIRE_RECEIVED); + espi_init_callback(&p80_cb, periph_handler, ESPI_BUS_PERIPHERAL_NOTIFICATION); #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC - espi_init_callback(&oob_cb, oob_rx_handler, - ESPI_BUS_EVENT_OOB_RECEIVED); + espi_init_callback(&oob_cb, oob_rx_handler, ESPI_BUS_EVENT_OOB_RECEIVED); #endif LOG_INF("complete"); @@ -988,8 +942,7 @@ static int wait_for_pin(const struct gpio_dt_spec *gpio, uint16_t timeout, int e } #endif -static int wait_for_vwire(const struct device *espi_dev, - enum espi_vwire_signal signal, +static int wait_for_vwire(const struct device *espi_dev, enum espi_vwire_signal signal, uint16_t timeout, uint8_t exp_level) { int ret; @@ -1043,30 +996,30 @@ int espi_handshake(void) int ret; LOG_INF("eSPI test - Handshake with eSPI master..."); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_WARN, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SUS_WARN, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SUS_WARN Timeout"); return ret; } LOG_INF("1st phase completed"); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S5, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S5, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S5 Timeout"); return ret; } - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S4, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S4, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S4 Timeout"); return ret; } - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S3, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLP_S3, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("SLP_S3 Timeout"); return ret; @@ -1074,8 +1027,8 @@ int espi_handshake(void) LOG_INF("2nd phase completed"); - ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_PLTRST, - CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, 1); + ret = wait_for_vwire(espi_dev, ESPI_VWIRE_SIGNAL_PLTRST, CONFIG_ESPI_VIRTUAL_WIRE_TIMEOUT, + 1); if (ret) { LOG_ERR("PLT_RST Timeout"); return ret; @@ -1091,7 +1044,7 @@ int read_test_block(uint8_t *buf, uint32_t start_flash_adr, uint16_t block_len) { uint8_t i = 0; uint32_t flash_addr = start_flash_adr; - uint16_t transactions = block_len/MAX_FLASH_REQUEST; + uint16_t transactions = block_len / MAX_FLASH_REQUEST; int ret = 0; struct espi_flash_packet pckt; @@ -1118,7 +1071,7 @@ int write_test_block(uint8_t *buf, uint32_t start_flash_adr, uint16_t block_len) { uint8_t i = 0; uint32_t flash_addr = start_flash_adr; - uint16_t transactions = block_len/MAX_FLASH_REQUEST; + uint16_t transactions = block_len / MAX_FLASH_REQUEST; int ret = 0; struct espi_flash_packet pckt; @@ -1154,8 +1107,7 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks) pattern = 0x99; for (i = 0; i <= blocks; i++) { memset(flash_write_buf, pattern++, sizeof(flash_write_buf)); - ret = write_test_block(flash_write_buf, flash_addr, - sizeof(flash_write_buf)); + ret = write_test_block(flash_write_buf, flash_addr, sizeof(flash_write_buf)); if (ret) { LOG_ERR("Failed to write to eSPI"); return ret; @@ -1172,20 +1124,17 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks) memset(flash_write_buf, pattern, sizeof(flash_write_buf)); /* Clear last read content */ memset(flash_read_buf, 0, sizeof(flash_read_buf)); - ret = read_test_block(flash_read_buf, flash_addr, - sizeof(flash_read_buf)); + ret = read_test_block(flash_read_buf, flash_addr, sizeof(flash_read_buf)); if (ret) { LOG_ERR("Failed to read from eSPI"); return ret; } /* Compare buffers */ - int cmp = memcmp(flash_write_buf, flash_read_buf, - sizeof(flash_write_buf)); + int cmp = memcmp(flash_write_buf, flash_read_buf, sizeof(flash_write_buf)); if (cmp != 0) { - LOG_ERR("eSPI read mismmatch at %d expected %x", - cmp, pattern); + LOG_ERR("eSPI read mismmatch at %d expected %x", cmp, pattern); } flash_addr += sizeof(flash_read_buf); @@ -1202,8 +1151,7 @@ static void send_slave_bootdone(void) int ret; uint8_t boot_done; - ret = espi_receive_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, - &boot_done); + ret = espi_receive_vwire(espi_dev, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE, &boot_done); LOG_INF("%s boot_done: %d", __func__, boot_done); if (ret) { LOG_WRN("Fail to retrieve slave boot done"); @@ -1293,7 +1241,6 @@ int espi_test(void) return ret; } - ret = espi_saf_test_pr1(&saf_pr_w25q128); if (ret) { LOG_INF("eSPI SAF test pr1 returned error %d", ret); @@ -1334,16 +1281,13 @@ int espi_test(void) k_sleep(K_SECONDS(2)); do { - vw_ch_sts = espi_get_channel_status(espi_dev, - ESPI_CHANNEL_VWIRE); + vw_ch_sts = espi_get_channel_status(espi_dev, ESPI_CHANNEL_VWIRE); k_busy_wait(100); } while (!vw_ch_sts); - send_slave_bootdone(); #endif - #ifdef CONFIG_ESPI_FLASH_CHANNEL /* Flash operation need to be perform before VW handshake or * after eSPI host completes full initialization. @@ -1353,8 +1297,7 @@ int espi_test(void) bool flash_sts; do { - flash_sts = espi_get_channel_status(espi_dev, - ESPI_CHANNEL_FLASH); + flash_sts = espi_get_channel_status(espi_dev, ESPI_CHANNEL_FLASH); k_busy_wait(100); } while (!flash_sts); diff --git a/samples/drivers/i2s/output/CMakeLists.txt b/samples/drivers/i2s/output/CMakeLists.txt new file mode 100644 index 00000000000..100cc967f23 --- /dev/null +++ b/samples/drivers/i2s/output/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(i2s_output) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/i2s/output/README.rst b/samples/drivers/i2s/output/README.rst new file mode 100644 index 00000000000..d8e10d81e0e --- /dev/null +++ b/samples/drivers/i2s/output/README.rst @@ -0,0 +1,36 @@ +.. zephyr:code-sample:: i2s-output + :name: I2S output + :relevant-api: i2s_interface + + Send I2S output stream + +Overview +******** + +This sample demonstrates how to use an I2S driver to send an output stream of +audio data. Currently, no codec is used with this sample. The I2S output can +be verified with a signal analyzer. + +The sample will send a short burst of audio data, consisting of a sine wave. +The I2S TX queue will then be drained, and audio output will stop. + +Requirements +************ + +The I2S device to be used by the sample is specified by defining +a devicetree alias named ``i2s_tx`` + +This sample has been tested on :ref:`mimxrt1060_evk` (mimxrt1060_evkb) + +Building and Running +******************** + +The code can be found in :zephyr_file:`samples/drivers/i2s/output`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/i2s/output + :board: mimxrt1060_evkb + :goals: build flash + :compact: diff --git a/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf new file mode 100644 index 00000000000..c27a69285c6 --- /dev/null +++ b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.conf @@ -0,0 +1,2 @@ +# Raise DMA TCD Queue size, as this is required by the I2S SAI driver +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay new file mode 100644 index 00000000000..92ffdea0a37 --- /dev/null +++ b/samples/drivers/i2s/output/boards/mimxrt1060_evkb.overlay @@ -0,0 +1,11 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2s-tx = &sai1; + }; +}; diff --git a/samples/drivers/i2s/output/prj.conf b/samples/drivers/i2s/output/prj.conf new file mode 100644 index 00000000000..c1378264b96 --- /dev/null +++ b/samples/drivers/i2s/output/prj.conf @@ -0,0 +1 @@ +CONFIG_I2S=y diff --git a/samples/drivers/i2s/output/sample.yaml b/samples/drivers/i2s/output/sample.yaml new file mode 100644 index 00000000000..8763b5128b2 --- /dev/null +++ b/samples/drivers/i2s/output/sample.yaml @@ -0,0 +1,9 @@ +sample: + description: I2S Output Sample + name: i2s_output +common: + tags: drivers + depends_on: i2s +tests: + sample.drivers.i2s.output: + filter: dt_alias_exists("i2s-tx") diff --git a/samples/drivers/i2s/output/src/main.c b/samples/drivers/i2s/output/src/main.c new file mode 100644 index 00000000000..34f1629ceb3 --- /dev/null +++ b/samples/drivers/i2s/output/src/main.c @@ -0,0 +1,128 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define SAMPLE_NO 64 + +/* The data represent a sine wave */ +static int16_t data[SAMPLE_NO] = { + 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, + 25329, 27244, 28897, 30272, 31356, 32137, 32609, 32767, + 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, + 20787, 18204, 15446, 12539, 9511, 6392, 3211, 0, + -3212, -6393, -9512, -12540, -15447, -18205, -20788, -23170, + -25330, -27245, -28898, -30273, -31357, -32138, -32610, -32767, + -32610, -32138, -31357, -30273, -28898, -27245, -25330, -23170, + -20788, -18205, -15447, -12540, -9512, -6393, -3212, -1, +}; + +/* Fill buffer with sine wave on left channel, and sine wave shifted by + * 90 degrees on right channel. "att" represents a power of two to attenuate + * the samples by + */ +static void fill_buf(int16_t *tx_block, int att) +{ + int r_idx; + + for (int i = 0; i < SAMPLE_NO; i++) { + /* Left channel is sine wave */ + tx_block[2 * i] = data[i] / (1 << att); + /* Right channel is same sine wave, shifted by 90 degrees */ + r_idx = (i + (ARRAY_SIZE(data) / 4)) % ARRAY_SIZE(data); + tx_block[2 * i + 1] = data[r_idx] / (1 << att); + } +} + +#define NUM_BLOCKS 20 +#define BLOCK_SIZE (2 * sizeof(data)) + +#ifdef CONFIG_NOCACHE_MEMORY + #define MEM_SLAB_CACHE_ATTR __nocache +#else + #define MEM_SLAB_CACHE_ATTR +#endif /* CONFIG_NOCACHE_MEMORY */ + +static char MEM_SLAB_CACHE_ATTR __aligned(WB_UP(32)) + _k_mem_slab_buf_tx_0_mem_slab[(NUM_BLOCKS) * WB_UP(BLOCK_SIZE)]; + +static STRUCT_SECTION_ITERABLE(k_mem_slab, tx_0_mem_slab) = + Z_MEM_SLAB_INITIALIZER(tx_0_mem_slab, _k_mem_slab_buf_tx_0_mem_slab, + WB_UP(BLOCK_SIZE), NUM_BLOCKS); + +int main(void) +{ + void *tx_block[NUM_BLOCKS]; + struct i2s_config i2s_cfg; + int ret; + uint32_t tx_idx; + const struct device *dev_i2s = DEVICE_DT_GET(DT_ALIAS(i2s_tx)); + + if (!device_is_ready(dev_i2s)) { + printf("I2S device not ready\n"); + return -ENODEV; + } + /* Configure I2S stream */ + i2s_cfg.word_size = 16U; + i2s_cfg.channels = 2U; + i2s_cfg.format = I2S_FMT_DATA_FORMAT_I2S; + i2s_cfg.frame_clk_freq = 44100; + i2s_cfg.block_size = BLOCK_SIZE; + i2s_cfg.timeout = 2000; + /* Configure the Transmit port as Master */ + i2s_cfg.options = I2S_OPT_FRAME_CLK_MASTER + | I2S_OPT_BIT_CLK_MASTER; + i2s_cfg.mem_slab = &tx_0_mem_slab; + ret = i2s_configure(dev_i2s, I2S_DIR_TX, &i2s_cfg); + if (ret < 0) { + printf("Failed to configure I2S stream\n"); + return ret; + } + + /* Prepare all TX blocks */ + for (tx_idx = 0; tx_idx < NUM_BLOCKS; tx_idx++) { + ret = k_mem_slab_alloc(&tx_0_mem_slab, &tx_block[tx_idx], + K_FOREVER); + if (ret < 0) { + printf("Failed to allocate TX block\n"); + return ret; + } + fill_buf((uint16_t *)tx_block[tx_idx], tx_idx % 3); + } + + tx_idx = 0; + /* Send first block */ + ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE); + if (ret < 0) { + printf("Could not write TX buffer %d\n", tx_idx); + return ret; + } + /* Trigger the I2S transmission */ + ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_START); + if (ret < 0) { + printf("Could not trigger I2S tx\n"); + return ret; + } + + for (; tx_idx < NUM_BLOCKS; ) { + ret = i2s_write(dev_i2s, tx_block[tx_idx++], BLOCK_SIZE); + if (ret < 0) { + printf("Could not write TX buffer %d\n", tx_idx); + return ret; + } + } + /* Drain TX queue */ + ret = i2s_trigger(dev_i2s, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + if (ret < 0) { + printf("Could not trigger I2S tx\n"); + return ret; + } + printf("All I2S blocks written\n"); + return 0; +} diff --git a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt index 458f0c9f256..83869676324 100644 --- a/samples/drivers/ipm/ipm_esp32/CMakeLists.txt +++ b/samples/drivers/ipm/ipm_esp32/CMakeLists.txt @@ -2,23 +2,33 @@ cmake_minimum_required(VERSION 3.20.0) -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipm_esp32_net-prefix/src/ipm_esp32_net-build/zephyr) +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipm_esp32_appcpu-prefix/src/ipm_esp32_appcpu-build/zephyr) + +if("${BOARD}" STREQUAL "esp32_devkitc_wrover") + set(BOARD_REMOTE "esp32_devkitc_wrover_appcpu") +elseif("${BOARD}" STREQUAL "esp32_devkitc_wroom") + set(BOARD_REMOTE "esp32_devkitc_wroom_appcpu") +elseif("${BOARD}" STREQUAL "esp32s3_devkitm") + set(BOARD_REMOTE "esp32s3_devkitm_appcpu") +else() + message(FATAL_ERROR "${BOARD} was not supported for this sample") +endif() find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(ipm_esp32) -set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c PROPERTIES GENERATED TRUE) -target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) +set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c PROPERTIES GENERATED TRUE) +target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_appcpu_firmware.c) include(ExternalProject) ExternalProject_Add( - ipm_esp32_net - SOURCE_DIR ${APPLICATION_SOURCE_DIR}/ipm_esp32_net + ipm_esp32_appcpu + SOURCE_DIR ${APPLICATION_SOURCE_DIR}/ipm_esp_appcpu INSTALL_COMMAND "" - CMAKE_CACHE_ARGS -DBOARD:STRING=esp32_net + CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE} BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}" BUILD_ALWAYS True ) -add_dependencies(app ipm_esp32_net) +add_dependencies(app ipm_esp32_appcpu) diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf new file mode 100644 index 00000000000..0bef3d481fd --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wroom.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf new file mode 100644 index 00000000000..0bef3d481fd --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32_devkitc_wrover.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf new file mode 100644 index 00000000000..a8ee714a955 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.conf @@ -0,0 +1 @@ +CONFIG_SOC_ESP32S3_PROCPU=y diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/boards/esp32_net.overlay b/samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay similarity index 100% rename from samples/drivers/ipm/ipm_esp32/ipm_esp32_net/boards/esp32_net.overlay rename to samples/drivers/ipm/ipm_esp32/boards/esp32s3_devkitm.overlay diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt deleted file mode 100644 index 0292180dbf3..00000000000 --- a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) - -find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(ipm_esp32_net) - -target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf b/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf deleted file mode 100644 index 82a82514edf..00000000000 --- a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_HEAP_MEM_POOL_SIZE=256 -CONFIG_IPM=y -CONFIG_KERNEL_BIN_NAME="esp32_net_firmware" diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt new file mode 100644 index 00000000000..44114da8450 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ipm_esp32_appcpu) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wroom_appcpu.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32_devkitc_wrover_appcpu.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay new file mode 100644 index 00000000000..80f7950333f --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/boards/esp32s3_dekvitm_appcpu.overlay @@ -0,0 +1,3 @@ +&ipm0 { + status = "okay"; +}; diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf new file mode 100644 index 00000000000..05a3de09ec1 --- /dev/null +++ b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/prj.conf @@ -0,0 +1,2 @@ +CONFIG_HEAP_MEM_POOL_SIZE=256 +CONFIG_IPM=y diff --git a/samples/drivers/ipm/ipm_esp32/ipm_esp32_net/src/main.c b/samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/src/main.c similarity index 100% rename from samples/drivers/ipm/ipm_esp32/ipm_esp32_net/src/main.c rename to samples/drivers/ipm/ipm_esp32/ipm_esp_appcpu/src/main.c diff --git a/samples/drivers/ipm/ipm_esp32/prj.conf b/samples/drivers/ipm/ipm_esp32/prj.conf index dfabff594df..553edc1f28b 100644 --- a/samples/drivers/ipm/ipm_esp32/prj.conf +++ b/samples/drivers/ipm/ipm_esp32/prj.conf @@ -1,3 +1,2 @@ -CONFIG_ESP32_NETWORK_CORE=y CONFIG_IPM=y CONFIG_LOG=y diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 795bd515212..92dd10208dd 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -22,6 +22,8 @@ #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(st_stm32_ospi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_s32_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_s32_qspi_nor) +#elif DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi_nor) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_imx_flexspi_nor) #else #error Unsupported flash driver #define FLASH_NODE DT_INVALID_NODE diff --git a/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf b/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf new file mode 100644 index 00000000000..9ccb06fb7bc --- /dev/null +++ b/samples/drivers/led_ws2812/boards/adafruit_kb2040.conf @@ -0,0 +1 @@ +CONFIG_WS2812_STRIP_RPI_PICO_PIO=y diff --git a/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf b/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf new file mode 100644 index 00000000000..6805516207c --- /dev/null +++ b/samples/drivers/led_ws2812/boards/adafruit_qt_py_rp2040.conf @@ -0,0 +1,3 @@ +CONFIG_WS2812_STRIP_RPI_PICO_PIO=y +CONFIG_GPIO=y +CONFIG_GPIO_HOGS=y diff --git a/samples/drivers/mbox/CMakeLists.txt b/samples/drivers/mbox/CMakeLists.txt index e65d44f0048..ca6513822a8 100644 --- a/samples/drivers/mbox/CMakeLists.txt +++ b/samples/drivers/mbox/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -8,10 +9,16 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") OR ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpuapp") OR ("${BOARD}" STREQUAL "adp_xc7k_ae350") OR - ("${BOARD}" STREQUAL "mimxrt595_evk_cm33")) + ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt595_evk_cm33") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu0")) message(STATUS "${BOARD} compile as Main in this sample") else() message(FATAL_ERROR "${BOARD} is not supported for this sample") @@ -21,4 +28,9 @@ project(mbox_ipc) enable_language(C ASM) +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox/Kconfig b/samples/drivers/mbox/Kconfig new file mode 100644 index 00000000000..3837c49b6e9 --- /dev/null +++ b/samples/drivers/mbox/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/samples/drivers/mbox/Kconfig.sysbuild b/samples/drivers/mbox/Kconfig.sysbuild index 46ffe3e12ae..20903872c34 100644 --- a/samples/drivers/mbox/Kconfig.sysbuild +++ b/samples/drivers/mbox/Kconfig.sysbuild @@ -1,4 +1,5 @@ # Copyright 2023 Nordic Semiconductor ASA +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 @@ -10,3 +11,7 @@ string default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" default "adp_xc7k_ae350" if $(BOARD) = "adp_xc7k_ae350" default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "mimxrt595_evk_cm33" + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" diff --git a/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..5077d775881 --- /dev/null +++ b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_MBOX_NXP_MAILBOX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..b5919c4fd72 --- /dev/null +++ b/samples/drivers/mbox/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 00000000000..942f67ba6a9 --- /dev/null +++ b/samples/drivers/mbox/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox/remote/CMakeLists.txt b/samples/drivers/mbox/remote/CMakeLists.txt index 3aee2d96482..2c7c8fff29e 100644 --- a/samples/drivers/mbox/remote/CMakeLists.txt +++ b/samples/drivers/mbox/remote/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Carlo Caione +# Copyright 2023-2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -10,6 +11,10 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) if(("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet") OR ("${BOARD}" STREQUAL "nrf5340bsim_nrf5340_cpunet") OR + ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu1") OR ("${BOARD}" STREQUAL "adp_xc7k_ae350")) message(STATUS "${BOARD} compile as remote in this sample") else() diff --git a/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 00000000000..b499f5da051 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,10 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_MBOX_NXP_MAILBOX=y + +# For purpose of sample enable UART Console on CPU1 +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CLOCK_CONTROL=y diff --git a/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 00000000000..36e6f0ff267 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,43 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + zephyr,console = &flexcomm0; + zephyr,shell-uart = &flexcomm0; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mbox@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +&flexcomm0 { + status = "okay"; +}; + +&dma0 { + status = "okay"; +}; + +&syscon { + status = "okay"; +}; diff --git a/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 00000000000..cc05e9b96c1 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 00000000000..cc05e9b96c1 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 00000000000..392141712a9 --- /dev/null +++ b/samples/drivers/mbox/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,49 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox/sample.yaml b/samples/drivers/mbox/sample.yaml index f7aa8953ea1..d646b241e9e 100644 --- a/samples/drivers/mbox/sample.yaml +++ b/samples/drivers/mbox/sample.yaml @@ -9,9 +9,21 @@ tests: - nrf5340dk_nrf5340_cpuapp - adp_xc7k_ae350 - mimxrt595_evk_cm33 + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 integration_platforms: - nrf5340dk_nrf5340_cpuapp - harness: remote + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Ping \\(on channel 0\\)" + - "Pong \\(on channel 0\\)" + - "Ping \\(on channel 1\\)" + - "Pong \\(on channel 1\\)" sample.drivers.mbox.simu: platform_allow: - nrf5340bsim_nrf5340_cpuapp diff --git a/samples/drivers/mbox/sysbuild.cmake b/samples/drivers/mbox/sysbuild.cmake index a8dfb8ebdf4..063f6157ddb 100644 --- a/samples/drivers/mbox/sysbuild.cmake +++ b/samples/drivers/mbox/sysbuild.cmake @@ -1,4 +1,5 @@ # Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") @@ -18,3 +19,15 @@ ExternalZephyrProject_Add( native_simulator_set_child_images(${DEFAULT_IMAGE} ${REMOTE_APP}) native_simulator_set_final_executable(${DEFAULT_IMAGE}) + +if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR + "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" OR + "${BOARD}" STREQUAL "lpcxpresso55s69_cpu0" + ) + # For these NXP boards the main core application is dependent on + # 'zephyr_image_info.h' generated by remote application. + + # Let's build the remote application first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +endif() diff --git a/samples/drivers/mbox_data/CMakeLists.txt b/samples/drivers/mbox_data/CMakeLists.txt new file mode 100644 index 00000000000..a410ac3d214 --- /dev/null +++ b/samples/drivers/mbox_data/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../remote/zephyr) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm7") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm7") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu0")) + message(STATUS "${BOARD} compile as Main in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc) + +enable_language(C ASM) + +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox_data/Kconfig b/samples/drivers/mbox_data/Kconfig new file mode 100644 index 00000000000..ee3874c39f9 --- /dev/null +++ b/samples/drivers/mbox_data/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/samples/drivers/mbox_data/Kconfig.sysbuild b/samples/drivers/mbox_data/Kconfig.sysbuild new file mode 100644 index 00000000000..2ddab228177 --- /dev/null +++ b/samples/drivers/mbox_data/Kconfig.sysbuild @@ -0,0 +1,12 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config REMOTE_BOARD +string + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" diff --git a/samples/drivers/mbox_data/README.rst b/samples/drivers/mbox_data/README.rst new file mode 100644 index 00000000000..1f8b1615f8e --- /dev/null +++ b/samples/drivers/mbox_data/README.rst @@ -0,0 +1,104 @@ +.. zephyr:code-sample:: mbox_data + :name: MBOX Data + :relevant-api: mbox_interface + + Perform inter-processor mailbox communication using the MBOX API with data. + +Overview +******** + +This sample demonstrates how to use the :ref:`MBOX API ` in data transfer mode. +It can be used only with mbox driver which supports data transfer mode. + +Sample will ping-pong up to 4 bytes of data between two cores via two mbox channels. +After each core receives data, it increments it by one and sends it back to other core. + +Building and Running +******************** + +The sample can be built and executed on boards supporting MBOX with data transfer mode. + +Building the application for mimxrt1160_evk_cm7 +=============================================== + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1160_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evk_cm7 +=============================================== + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1170_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evkb_cm7 +================================================ + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: mimxrt1170_evkb_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for lpcxpresso55s69_cpu1 +================================================= + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/mbox_data/ + :board: lpcxpresso55s69_cpu1 + :goals: debug + :west-args: --sysbuild + +Sample Output +============= + +Open a serial terminal (minicom, putty, etc.) and connect the board with the +following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and the following message will appear on the corresponding +serial port, one is the main core another is the remote core: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4051-g12f4f4dc8679 *** + mbox_data Client demo started + Client send (on channel 3) value: 0 + Client received (on channel 2) value: 1 + Client send (on channel 3) value: 2 + Client received (on channel 2) value: 3 + Client send (on channel 3) value: 4 + ... + Client received (on channel 2) value: 95 + Client send (on channel 3) value: 96 + Client received (on channel 2) value: 97 + Client send (on channel 3) value: 98 + Client received (on channel 2) value: 99 + mbox_data Client demo ended + + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-4051-g12f4f4dc8679 *** + mbox_data Server demo started + Server receive (on channel 3) value: 0 + Server send (on channel 2) value: 1 + Server receive (on channel 3) value: 2 + Server send (on channel 2) value: 3 + Server receive (on channel 3) value: 4 + ... + Server send (on channel 2) value: 95 + Server receive (on channel 3) value: 96 + Server send (on channel 2) value: 97 + Server receive (on channel 3) value: 98 + Server send (on channel 2) value: 99 + mbox_data Server demo ended. diff --git a/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 00000000000..5077d775881 --- /dev/null +++ b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_MBOX_NXP_MAILBOX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 00000000000..b5919c4fd72 --- /dev/null +++ b/samples/drivers/mbox_data/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mailbox0@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..583b4950360 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 00000000000..0dfb100ed70 --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 00000000000..870b9928faf --- /dev/null +++ b/samples/drivers/mbox_data/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c48000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c48000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c48000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/prj.conf b/samples/drivers/mbox_data/prj.conf new file mode 100644 index 00000000000..293e2834f25 --- /dev/null +++ b/samples/drivers/mbox_data/prj.conf @@ -0,0 +1,2 @@ +CONFIG_PRINTK=y +CONFIG_MBOX=y diff --git a/samples/drivers/mbox_data/remote/CMakeLists.txt b/samples/drivers/mbox_data/remote/CMakeLists.txt new file mode 100644 index 00000000000..47e1cae8628 --- /dev/null +++ b/samples/drivers/mbox_data/remote/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +if(("${BOARD}" STREQUAL "mimxrt1170_evkb_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1170_evk_cm4") OR + ("${BOARD}" STREQUAL "mimxrt1160_evk_cm4") OR + ("${BOARD}" STREQUAL "lpcxpresso55s69_cpu1")) + message(STATUS "${BOARD} compile as remote in this sample") +else() + message(FATAL_ERROR "${BOARD} is not supported for this sample") +endif() + +project(mbox_data_ipc_remote) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 00000000000..14ed92ba8f4 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,3 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_MBOX_NXP_MAILBOX=y diff --git a/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 00000000000..96bd5aa1c3a --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,29 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /* Delete IPM Driver node nxp,lpc-mailbox */ + /delete-node/ mailbox@8b000; + + /* Attach MBOX driver to Mailbox Unit */ + mbox:mbox@5008b000 { + compatible = "nxp,mbox-mailbox"; + reg = <0x5008b000 0xEC>; + interrupts = <31 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 00000000000..3f6115b9c58 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,54 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 00000000000..0d36a72aec6 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,4 @@ +CONFIG_MBOX_NXP_IMX_MU=y +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 00000000000..e3576826702 --- /dev/null +++ b/samples/drivers/mbox_data/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,55 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + + /* Delete ipc chosen property where old IPM mailbox driver bellow is + * configured. + */ + /delete-property/ zephyr,ipc; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + + /* Delete IPM Driver node nxp,imx-mu */ + /delete-node/ mailbox@40c4c000; + + /* Attach MBOX driver to MU Unit */ + mbox:mbox@40c4c000 { + compatible = "nxp,mbox-imx-mu"; + reg = <0x40c4c000 0x4000>; + interrupts = <118 0>; + rx-channels = <4>; + #mbox-cells = <1>; + status = "okay"; + }; + }; + +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/samples/drivers/mbox_data/remote/prj.conf b/samples/drivers/mbox_data/remote/prj.conf new file mode 100644 index 00000000000..473e4280601 --- /dev/null +++ b/samples/drivers/mbox_data/remote/prj.conf @@ -0,0 +1,2 @@ +CONFIG_STDOUT_CONSOLE=n +CONFIG_MBOX=y diff --git a/samples/drivers/mbox_data/remote/src/main.c b/samples/drivers/mbox_data/remote/src/main.c new file mode 100644 index 00000000000..0f3ad77a4d0 --- /dev/null +++ b/samples/drivers/mbox_data/remote/src/main.c @@ -0,0 +1,83 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_received_channel; + +#define TX_ID (2) +#define RX_ID (3) + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + memcpy(&g_mbox_received_data, data->data, data->size); + g_mbox_received_channel = channel; + + k_sem_give(&g_mbox_data_rx_sem); +} + +int main(void) +{ + struct mbox_channel tx_channel; + struct mbox_channel rx_channel; + const struct device *dev; + struct mbox_msg msg = {0}; + uint32_t message = 0; + + printk("mbox_data Server demo started\n"); + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + mbox_init_channel(&tx_channel, dev, TX_ID); + mbox_init_channel(&rx_channel, dev, RX_ID); + + const int max_transfer_size_bytes = mbox_mtu_get(dev); + /* Sample currently supports only transfer size up to 4 bytes */ + if ((max_transfer_size_bytes <= 0) || (max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + return 0; + } + + if (mbox_register_callback(&rx_channel, callback, NULL)) { + printk("mbox_register_callback() error\n"); + return 0; + } + + if (mbox_set_enabled(&rx_channel, 1)) { + printk("mbox_set_enable() error\n"); + return 0; + } + + while (message < 99) { + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + message = g_mbox_received_data; + + printk("Server receive (on channel %d) value: %d\n", g_mbox_received_channel, + g_mbox_received_data); + + message++; + + msg.data = &message; + msg.size = max_transfer_size_bytes; + + printk("Server send (on channel %d) value: %d\n", tx_channel.id, message); + if (mbox_send(&tx_channel, &msg) < 0) { + printk("mbox_send() error\n"); + return 0; + } + } + + printk("mbox_data Server demo ended.\n"); + return 0; +} diff --git a/samples/drivers/mbox_data/sample.yaml b/samples/drivers/mbox_data/sample.yaml new file mode 100644 index 00000000000..b4a1e23a9bc --- /dev/null +++ b/samples/drivers/mbox_data/sample.yaml @@ -0,0 +1,29 @@ +sample: + name: MBOX Data IPC sample +common: + sysbuild: true + tags: mbox +tests: + sample.drivers.mbox_data.real_hw: + platform_allow: + - mimxrt1170_evkb_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 + integration_platforms: + - mimxrt1160_evk_cm7 + - lpcxpresso55s69_cpu0 + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Client received \\(on channel 2\\) value: 1" + - "Client send \\(on channel 3\\) value: 2" + - "Client received \\(on channel 2\\) value: 3" + - "Client send \\(on channel 3\\) value: 4" + - "Client received \\(on channel 2\\) value: 41" + - "Client send \\(on channel 3\\) value: 42" + - "Client received \\(on channel 2\\) value: 97" + - "Client send \\(on channel 3\\) value: 98" + - "Client received \\(on channel 2\\) value: 99" diff --git a/samples/drivers/mbox_data/src/main.c b/samples/drivers/mbox_data/src/main.c new file mode 100644 index 00000000000..85df24940c4 --- /dev/null +++ b/samples/drivers/mbox_data/src/main.c @@ -0,0 +1,82 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static K_SEM_DEFINE(g_mbox_data_rx_sem, 0, 1); + +static uint32_t g_mbox_received_data; +static uint32_t g_mbox_received_channel; + +#define TX_ID (3) +#define RX_ID (2) + +static void callback(const struct device *dev, uint32_t channel, void *user_data, + struct mbox_msg *data) +{ + memcpy(&g_mbox_received_data, data->data, data->size); + g_mbox_received_channel = channel; + + k_sem_give(&g_mbox_data_rx_sem); +} + +int main(void) +{ + struct mbox_channel tx_channel; + struct mbox_channel rx_channel; + const struct device *dev; + struct mbox_msg msg = {0}; + uint32_t message = 0; + + printk("mbox_data Client demo started\n"); + + dev = DEVICE_DT_GET(DT_NODELABEL(mbox)); + + mbox_init_channel(&tx_channel, dev, TX_ID); + mbox_init_channel(&rx_channel, dev, RX_ID); + + const int max_transfer_size_bytes = mbox_mtu_get(dev); + /* Sample currently supports only transfer size up to 4 bytes */ + if ((max_transfer_size_bytes < 0) || (max_transfer_size_bytes > 4)) { + printk("mbox_mtu_get() error\n"); + return 0; + } + + if (mbox_register_callback(&rx_channel, callback, NULL)) { + printk("mbox_register_callback() error\n"); + return 0; + } + + if (mbox_set_enabled(&rx_channel, 1)) { + printk("mbox_set_enable() error\n"); + return 0; + } + + while (message < 100) { + msg.data = &message; + msg.size = max_transfer_size_bytes; + + printk("Client send (on channel %d) value: %d\n", tx_channel.id, message); + if (mbox_send(&tx_channel, &msg) < 0) { + printk("mbox_send() error\n"); + return 0; + } + + k_sem_take(&g_mbox_data_rx_sem, K_FOREVER); + message = g_mbox_received_data; + + printk("Client received (on channel %d) value: %d\n", g_mbox_received_channel, + message); + message++; + } + + printk("mbox_data Client demo ended\n"); + return 0; +} diff --git a/samples/drivers/mbox_data/sysbuild.cmake b/samples/drivers/mbox_data/sysbuild.cmake new file mode 100644 index 00000000000..5c536a6229a --- /dev/null +++ b/samples/drivers/mbox_data/sysbuild.cmake @@ -0,0 +1,28 @@ +# Copyright 2024 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +if("${SB_CONFIG_REMOTE_BOARD}" STREQUAL "") + message(FATAL_ERROR + "Target ${BOARD} not supported for this sample. " + "There is no remote board selected in Kconfig.sysbuild") +endif() + +set(REMOTE_APP remote) + +ExternalZephyrProject_Add( + APPLICATION ${REMOTE_APP} + SOURCE_DIR ${APP_DIR}/${REMOTE_APP} + BOARD ${SB_CONFIG_REMOTE_BOARD} +) + +if ("${BOARD}" STREQUAL "mimxrt1170_evkb_cm7" OR + "${BOARD}" STREQUAL "mimxrt1170_evk_cm7" OR + "${BOARD}" STREQUAL "mimxrt1160_evk_cm7" + ) + # For these NXP boards the main core application is dependent on + # 'zephyr_image_info.h' generated by remote application. + + # Let's build the remote application first + add_dependencies(${DEFAULT_IMAGE} ${REMOTE_APP}) +endif() diff --git a/samples/drivers/soc_flash_nand/CMakeLists.txt b/samples/drivers/soc_flash_nand/CMakeLists.txt new file mode 100644 index 00000000000..ea5e877d899 --- /dev/null +++ b/samples/drivers/soc_flash_nand/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(cdns_nand) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay b/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..1275aa15a25 --- /dev/null +++ b/samples/drivers/soc_flash_nand/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 Intel Corporation + * SPDX-License-Identifier: Apache-2.0 + */ + +/* The overlay file should be used to enable any + * dts nodes required by this application for this + * board. + */ + +/ { + aliases { + nand = &nand; + }; +}; + +&nand { + status = "okay"; +}; diff --git a/samples/drivers/soc_flash_nand/prj.conf b/samples/drivers/soc_flash_nand/prj.conf new file mode 100644 index 00000000000..463cd27a152 --- /dev/null +++ b/samples/drivers/soc_flash_nand/prj.conf @@ -0,0 +1,10 @@ +# Copyright (c) 2023, Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +# Misc +CONFIG_HEAP_MEM_POOL_SIZE=363840 + +# Enable Flash +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_LOG=y diff --git a/samples/drivers/soc_flash_nand/sample.yaml b/samples/drivers/soc_flash_nand/sample.yaml new file mode 100644 index 00000000000..1e68da3131a --- /dev/null +++ b/samples/drivers/soc_flash_nand/sample.yaml @@ -0,0 +1,28 @@ +sample: + description: Cadence Nand Driver sample application. + name: cdns_nand +tests: + sample.drivers.flash.soc_flash_nand: + platform_allow: + - intel_socfpga_agilex5_socdk + integration_platforms: + - intel_socfpga_agilex5_socdk + tags: + - flash + - cdns + harness: console + harness_config: + fixture: external_flash + type: multi_line + ordered: true + regex: + - "Nand flash driver test sample" + - "Nand flash driver block size 20000" + - "The Page size of 800" + - "Nand flash driver data erase successful...." + - "Nand flash driver write completed...." + - "Nand flash driver read completed...." + - "Nand flash driver read verified" + - "Nand flash driver data erase successful...." + - "Nand flash driver read verified after erase...." + - "Nand flash driver test sample completed...." diff --git a/samples/drivers/soc_flash_nand/src/main.c b/samples/drivers/soc_flash_nand/src/main.c new file mode 100644 index 00000000000..ddcd8fcba91 --- /dev/null +++ b/samples/drivers/soc_flash_nand/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifndef OFFSET_PAGE +#define OFFSET_PAGE 0x00 +#endif + +#ifndef NAND_NUM_PAGES +#define NAND_NUM_PAGES 50 +#endif + +#define NAND_DEV DEVICE_DT_GET(DT_ALIAS(nand)); + +int main(void) +{ + const struct device *nand_dev; + struct flash_pages_info page; + size_t flash_block_size; + size_t total_pages; + int ret; + uint8_t *w_Page_buffer; + uint8_t *r_Page_buffer; + uint8_t page_data = 0; + + printk("Nand flash driver test sample\n"); + + nand_dev = NAND_DEV; + + if (!device_is_ready(nand_dev)) { + printk("Nand flash driver is not ready\n"); + return -ENODEV; + } + + total_pages = flash_get_page_count(nand_dev); + + flash_block_size = flash_get_write_block_size(nand_dev); + printk("Nand flash driver block size %lx\n", flash_block_size); + + ret = flash_get_page_info_by_offs(nand_dev, 0x00, &page); + + if (ret < 0) { + printk("Nand flash driver page info error\n"); + return ret; + } + printk("The Page size of %lx\n", page.size); + + w_Page_buffer = (uint8_t *)k_malloc(page.size * NAND_NUM_PAGES); + + r_Page_buffer = (uint8_t *)k_malloc(page.size * NAND_NUM_PAGES); + + if (w_Page_buffer != NULL) { + + for (int index = 0; index < page.size * NAND_NUM_PAGES; index++) { + w_Page_buffer[index] = (page_data++ % 255); + } + + } else { + printk("Write memory not allocated\n"); + return -ENOSR; + } + + if (r_Page_buffer != NULL) { + memset(r_Page_buffer, 0x55, page.size * NAND_NUM_PAGES); + } else { + printk("Read memory not allocated\n"); + k_free(w_Page_buffer); + return -ENOSR; + } + + ret = flash_erase(nand_dev, OFFSET_PAGE, flash_block_size); + + if (ret < 0) { + printk("Nand flash driver read Error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver data erase successful....\n"); + + ret = flash_write(nand_dev, OFFSET_PAGE, w_Page_buffer, page.size * NAND_NUM_PAGES); + if (ret < 0) { + printk("Nand flash driver write error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver write completed....\n"); + + ret = flash_read(nand_dev, OFFSET_PAGE, r_Page_buffer, page.size * NAND_NUM_PAGES); + if (ret < 0) { + printk("Nand flash driver read error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + + printk("Nand flash driver read completed....\n"); + + ret = memcmp(w_Page_buffer, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret < 0) { + printk("Nand flash driver read not match\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver read verified\n"); + + ret = flash_erase(nand_dev, OFFSET_PAGE, flash_block_size); + + if (ret < 0) { + printk("Nand flash driver read Error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver data erase successful....\n"); + + ret = flash_read(nand_dev, OFFSET_PAGE, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret != 0) { + printk("Nand flash driver read error\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + memset(w_Page_buffer, 0xFF, page.size * NAND_NUM_PAGES); + + ret = memcmp(w_Page_buffer, r_Page_buffer, page.size * NAND_NUM_PAGES); + + if (ret < 0) { + printk("Nand flash driver read not match\n"); + k_free(w_Page_buffer); + k_free(r_Page_buffer); + return ret; + } + printk("Nand flash driver read verified after erase....\n"); + printk("Nand flash driver test sample completed....\n"); + + return 0; +} diff --git a/samples/drivers/spi_flash/README.rst b/samples/drivers/spi_flash/README.rst index 70b523a58a4..6f2e81959be 100644 --- a/samples/drivers/spi_flash/README.rst +++ b/samples/drivers/spi_flash/README.rst @@ -15,8 +15,13 @@ savings is correctly implemented. Building and Running ******************** -The application will build only for a target that has a :ref:`devicetree -` entry with ``jedec,spi-nor`` as a compatible. +The application will build only for a target that has a :ref:`devicetree ` +``spi-flash0`` alias that refers to an entry with one of the following bindings as a compatible: + +* :dtcompatible:`jedec,spi-nor`, +* :dtcompatible:`st,stm32-qspi-nor`, +* :dtcompatible:`st,stm32-ospi-nor`, +* :dtcompatible:`nordic,qspi-nor`. .. zephyr-app-commands:: :zephyr-app: samples/drivers/spi_flash diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index e24f9a00525..b3bec006e9c 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -7,6 +7,7 @@ tests: - flash filter: dt_compat_enabled("jedec,spi-nor") or dt_compat_enabled("st,stm32-qspi-nor") or dt_compat_enabled("st,stm32-ospi-nor") + or (dt_compat_enabled("nordic,qspi-nor") and CONFIG_NORDIC_QSPI_NOR) platform_exclude: hifive_unmatched harness: console harness_config: diff --git a/samples/drivers/uart/native_tty/CMakeLists.txt b/samples/drivers/uart/native_tty/CMakeLists.txt index c0fa477a106..528ed22fc56 100644 --- a/samples/drivers/uart/native_tty/CMakeLists.txt +++ b/samples/drivers/uart/native_tty/CMakeLists.txt @@ -4,8 +4,5 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(native_tty) -set(CMAKE_EXPORT_COMPILE_COMMANDS on) -zephyr_compile_options(-fdiagnostics-color=always) - file(GLOB app_sources src/main.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/drivers/uart/passthrough/CMakeLists.txt b/samples/drivers/uart/passthrough/CMakeLists.txt new file mode 100644 index 00000000000..ca7c7f7faa5 --- /dev/null +++ b/samples/drivers/uart/passthrough/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(passthrough) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/uart/passthrough/README.rst b/samples/drivers/uart/passthrough/README.rst new file mode 100644 index 00000000000..94d58f3dca1 --- /dev/null +++ b/samples/drivers/uart/passthrough/README.rst @@ -0,0 +1,50 @@ +.. zephyr:code-sample:: uart-passthrough + :name: UART Passthrough + :relevant-api: uart_interface + + Pass data directly between the console and another UART interface. + +Overview +******** + +This sample will virtually connect two UART interfaces together, as if Zephyr +and the processor were not present. Data read from the console is transmitted +to the "*other*" interface, and data read from the "*other*" interface is +relayed to the console. + +The source code for this sample application can be found at: +:zephyr_file:`samples/drivers/uart/passthrough`. + +Requirements +************ + +#. One UART interface, identified as Zephyr's console. +#. A second UART connected to something interesting (e.g: GPS), identified as + the chosen ``uart,passthrough`` device - the pins and baudrate will need to + be configured correctly. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``nucleo_l476rg`` for your +board: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/uart/passthrough + :board: nucleo_l476rg + :goals: build flash + :compact: + +Sample Output +============= + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-2988-gb84bab36b941 *** + Console Device: 0x8003940 + Other Device: 0x800392c + $GNGSA,A,3,31,29,25,26,,,,,,,,,11.15,10.66,3.29,1*06 + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,2*0F + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,3*0E + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,4*09 + $GNGSA,A,3,,,,,,,,,,,,,11.15,10.66,3.29,5*08 diff --git a/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay b/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay new file mode 100644 index 00000000000..5292b54e5f5 --- /dev/null +++ b/samples/drivers/uart/passthrough/boards/nucleo_l476rg.overlay @@ -0,0 +1,12 @@ +/ { + chosen { + uart,passthrough = &uart4; + }; +}; + +&uart4 { + pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pa1>; + pinctrl-names = "default"; + current-speed = <9600>; + status = "okay"; +}; diff --git a/samples/drivers/uart/passthrough/prj.conf b/samples/drivers/uart/passthrough/prj.conf new file mode 100644 index 00000000000..70eec2fbac3 --- /dev/null +++ b/samples/drivers/uart/passthrough/prj.conf @@ -0,0 +1,3 @@ +CONFIG_SERIAL=y +CONFIG_RING_BUFFER=y +CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/samples/drivers/uart/passthrough/sample.yml b/samples/drivers/uart/passthrough/sample.yml new file mode 100644 index 00000000000..5e4abf91f4d --- /dev/null +++ b/samples/drivers/uart/passthrough/sample.yml @@ -0,0 +1,14 @@ +sample: + name: UART Passthrough +tests: + sample.drivers.uart: + integration_platforms: + - qemu_x86 + tags: + - serial + - uart + filter: CONFIG_SERIAL and + CONFIG_UART_INTERRUPT_DRIVEN and + dt_chosen_enabled("zephyr,console") and + dt_chosen_enabled("uart,passthrough") + harness: keyboard diff --git a/samples/drivers/uart/passthrough/src/main.c b/samples/drivers/uart/passthrough/src/main.c new file mode 100644 index 00000000000..2168207a751 --- /dev/null +++ b/samples/drivers/uart/passthrough/src/main.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2024 Argentum Systems Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +struct patch_info { + const uint8_t * const name; + + const struct device *rx_dev; + struct ring_buf *rx_ring_buf; + bool rx_error; + bool rx_overflow; + + const struct device *tx_dev; +}; + +#define DEV_CONSOLE DEVICE_DT_GET(DT_CHOSEN(zephyr_console)) +#define DEV_OTHER DEVICE_DT_GET(DT_CHOSEN(uart_passthrough)) + +#define RING_BUF_SIZE 64 + +RING_BUF_DECLARE(rb_console, RING_BUF_SIZE); +struct patch_info patch_c2o = { + .name = "c2o", + + .rx_dev = DEV_CONSOLE, + .rx_ring_buf = &rb_console, + .rx_error = false, + .rx_overflow = false, + + .tx_dev = DEV_OTHER, +}; + +RING_BUF_DECLARE(rb_other, RING_BUF_SIZE); +struct patch_info patch_o2c = { + .name = "o2c", + + .rx_dev = DEV_OTHER, + .rx_ring_buf = &rb_other, + .rx_error = false, + .rx_overflow = false, + + .tx_dev = DEV_CONSOLE, +}; + +static void uart_cb(const struct device *dev, void *ctx) +{ + struct patch_info *patch = (struct patch_info *)ctx; + int ret; + uint8_t *buf; + uint32_t len; + + while (uart_irq_update(patch->rx_dev) > 0) { + ret = uart_irq_rx_ready(patch->rx_dev); + if (ret < 0) { + patch->rx_error = true; + } + if (ret <= 0) { + break; + } + + len = ring_buf_put_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE); + if (len == 0) { + /* no space for Rx, disable the IRQ */ + uart_irq_rx_disable(patch->rx_dev); + patch->rx_overflow = true; + break; + } + + ret = uart_fifo_read(patch->rx_dev, buf, len); + if (ret < 0) { + patch->rx_error = true; + } + if (ret <= 0) { + break; + } + len = ret; + + ret = ring_buf_put_finish(patch->rx_ring_buf, len); + if (ret != 0) { + patch->rx_error = true; + break; + } + } +} + +static void passthrough(struct patch_info *patch) +{ + int ret; + uint8_t *buf; + uint32_t len; + + if (patch->rx_error) { + printk("<<%s: Rx Error!>>\n", patch->name); + patch->rx_error = false; + } + + if (patch->rx_overflow) { + printk("<<%s: Rx Overflow!>>\n", patch->name); + patch->rx_overflow = false; + } + + len = ring_buf_get_claim(patch->rx_ring_buf, &buf, RING_BUF_SIZE); + if (len == 0) { + goto done; + } + + ret = uart_fifo_fill(patch->tx_dev, buf, len); + if (ret < 0) { + goto error; + } + len = ret; + + ret = ring_buf_get_finish(patch->rx_ring_buf, len); + if (ret < 0) { + goto error; + } + +done: + uart_irq_rx_enable(patch->rx_dev); + return; + +error: + printk("<<%s: Tx Error!>>\n", patch->name); +} + +int main(void) +{ + printk("Console Device: %p\n", patch_c2o.rx_dev); + printk("Other Device: %p\n", patch_o2c.rx_dev); + + uart_irq_callback_user_data_set(patch_c2o.rx_dev, uart_cb, (void *)&patch_c2o); + uart_irq_callback_user_data_set(patch_o2c.rx_dev, uart_cb, (void *)&patch_o2c); + + for (;;) { + passthrough(&patch_c2o); + passthrough(&patch_o2c); + } + + return 0; +} diff --git a/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay b/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..660b55c0512 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tco_wdt { + status = "okay"; +}; diff --git a/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay b/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..6bcb1dc5909 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &watchdog0; + }; +}; + +&watchdog0 { + interrupt-parent = <&gic>; + interrupts = ; + status = "okay"; +}; diff --git a/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay b/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay new file mode 100644 index 00000000000..6bcb1dc5909 --- /dev/null +++ b/samples/drivers/watchdog/boards/intel_socfpga_agilex_socdk.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + watchdog0 = &watchdog0; + }; +}; + +&watchdog0 { + interrupt-parent = <&gic>; + interrupts = ; + status = "okay"; +}; diff --git a/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..66157d79fb3 --- /dev/null +++ b/samples/drivers/watchdog/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,8 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +&wdt30 { + status = "okay"; +}; diff --git a/samples/modules/chre/src/main.cpp b/samples/modules/chre/src/main.cpp index f9b2b16cb52..675e57e8932 100644 --- a/samples/modules/chre/src/main.cpp +++ b/samples/modules/chre/src/main.cpp @@ -37,12 +37,12 @@ int main(void) k_msleep(100); } printk("Starting EchoApp... %s\n", boolToString(eventLoop.startNanoapp(echo_app))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Finding instance ID... %s\n", boolToString(eventLoop.findNanoappInstanceIdByAppId(1, &instanceId))); - printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Nanoapp count=%zu\n", eventLoop.getNanoappCount()); printk("Instance ID: %u\n", instanceId); - printk("Sending event %u...\n", eventLoop.getNanoappCount()); + printk("Sending event %zu...\n", eventLoop.getNanoappCount()); eventLoop.postEventOrDie(CHRE_EVENT_MESSAGE_FROM_HOST, nullptr, [](uint16_t eventType, void *eventData) { printk("Event (%u) complete!\n", eventType); }); diff --git a/samples/modules/lvgl/demos/sample.yaml b/samples/modules/lvgl/demos/sample.yaml index b928d9f37f0..bd7461dd46c 100644 --- a/samples/modules/lvgl/demos/sample.yaml +++ b/samples/modules/lvgl/demos/sample.yaml @@ -6,7 +6,11 @@ common: - lvgl harness: none filter: dt_chosen_enabled("zephyr,display") - tags: samples lvgl display gui + tags: + - samples + - display + - lvgl + - gui tests: sample.modules.lvgl.demo_music: extra_configs: @@ -17,3 +21,22 @@ tests: sample.modules.lvgl.demo_stress: extra_configs: - CONFIG_LV_Z_DEMO_STRESS=y + sample.modules.lvgl.demo_widgets: + extra_configs: + - CONFIG_LV_Z_DEMO_WIDGETS=y + sample.modules.lvgl.demos.st_b_lcd40_dsi1_mb1166: + platform_allow: stm32h747i_disco_m7 + extra_args: SHIELD=st_b_lcd40_dsi1_mb1166 + harness: console + harness_config: + fixture: fixture_display + extra_configs: + - CONFIG_LV_Z_DEMO_BENCHMARK=y + modules: + - lvgl + tags: + - samples + - display + - shield + - lvgl + - gui diff --git a/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp b/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp index 0491f7a7962..13733aaa0c6 100644 --- a/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp +++ b/samples/modules/tflite-micro/magic_wand/src/accelerometer_handler.cpp @@ -40,13 +40,8 @@ TfLiteStatus SetupAccelerometer() return kTfLiteApplicationError; } - if (sensor == NULL) { - MicroPrintf("Failed to get accelerometer, name: %s\n", - sensor->name); - } else { - MicroPrintf("Got accelerometer, name: %s\n", - sensor->name); - } + MicroPrintf("Got accelerometer, name: %s\n", sensor->name); + return kTfLiteOk; } diff --git a/samples/modules/thrift/hello/README.rst b/samples/modules/thrift/hello/README.rst index 90a6d089a92..a773bc547b5 100644 --- a/samples/modules/thrift/hello/README.rst +++ b/samples/modules/thrift/hello/README.rst @@ -48,6 +48,14 @@ layers in thrift can be combined to build an application with desired features. Requirements ************ +- Optional Modules + +.. code-block:: console + :caption: Download optional modules with west + + west config manifest.group-filter -- +optional + west update + - QEMU Networking (described in :ref:`networking_with_qemu`) - Thrift dependencies installed for your host OS e.g. in Ubuntu diff --git a/samples/net/cellular_modem/src/main.c b/samples/net/cellular_modem/src/main.c index 95e1c45f160..35a97d3e831 100644 --- a/samples/net/cellular_modem/src/main.c +++ b/samples/net/cellular_modem/src/main.c @@ -13,6 +13,8 @@ #include #include +#include + #define SAMPLE_TEST_ENDPOINT_HOSTNAME ("test-endpoint.com") #define SAMPLE_TEST_ENDPOINT_UDP_ECHO_PORT (7780) #define SAMPLE_TEST_ENDPOINT_UDP_RECEIVE_PORT (7781) @@ -44,6 +46,48 @@ static void init_sample_test_packet(void) } } +static void print_cellular_info(void) +{ + int rc; + int16_t rssi; + char buffer[64]; + + rc = cellular_get_signal(modem, CELLULAR_SIGNAL_RSSI, &rssi); + if (!rc) { + printk("RSSI %d\n", rssi); + } + + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_IMEI, &buffer[0], sizeof(buffer)); + if (!rc) { + printk("IMEI: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_MODEL_ID, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("MODEL_ID: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_MANUFACTURER, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("MANUFACTURER: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_SIM_IMSI, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("SIM_IMSI: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_SIM_ICCID, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("SIM_ICCID: %s\n", buffer); + } + rc = cellular_get_modem_info(modem, CELLULAR_MODEM_INFO_FW_VERSION, &buffer[0], + sizeof(buffer)); + if (!rc) { + printk("FW_VERSION: %s\n", buffer); + } +} + static void sample_dns_request_result(enum dns_resolve_status status, struct dns_addrinfo *info, void *user_data) { @@ -264,6 +308,9 @@ int main(void) NET_EVENT_DNS_SERVER_ADD, &raised_event, &info, &info_len, K_SECONDS(10)); + printk("Retrieving cellular info\n"); + print_cellular_info(); + printk("Performing DNS lookup of %s\n", SAMPLE_TEST_ENDPOINT_HOSTNAME); ret = sample_dns_request(); if (ret < 0) { diff --git a/samples/net/gptp/boards/xmc45_relax_kit.conf b/samples/net/gptp/boards/xmc45_relax_kit.conf new file mode 100644 index 00000000000..720b511fdb9 --- /dev/null +++ b/samples/net/gptp/boards/xmc45_relax_kit.conf @@ -0,0 +1,2 @@ +CONFIG_NET_TC_TX_COUNT=3 +CONFIG_NET_TC_RX_COUNT=2 diff --git a/samples/net/gptp/sample.yaml b/samples/net/gptp/sample.yaml index a668d6325a5..e65327ef47a 100644 --- a/samples/net/gptp/sample.yaml +++ b/samples/net/gptp/sample.yaml @@ -21,3 +21,10 @@ tests: depends_on: netif integration_platforms: - frdm_k64f + sample.net.gpt.nxp_enet_experimental: + extra_args: EXTRA_DTC_OVERLAY_FILE="nxp,enet-experimental.overlay" + platform_allow: + - mimxrt1050_evk + - mimxrt1060_evk + - mimxrt1064_evk + - mimxrt1024_evk diff --git a/samples/net/lwm2m_client/Kconfig b/samples/net/lwm2m_client/Kconfig index 22fab04bbef..2037d281ce0 100644 --- a/samples/net/lwm2m_client/Kconfig +++ b/samples/net/lwm2m_client/Kconfig @@ -29,8 +29,9 @@ endif config LWM2M_APP_SERVER string "LwM2M server address" - default "coaps://192.0.2.2:5684" if LWM2M_DTLS_SUPPORT default "coap://192.0.2.2:5683" if !LWM2M_DTLS_SUPPORT + default "coaps://192.0.2.2:5684" if (LWM2M_DTLS_SUPPORT && !LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + default "coaps://192.0.2.2:5784" if (LWM2M_DTLS_SUPPORT && LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) help LwM2M server address. Write as a full URI including optional port number. Only accepted protocols are "coap://" and "coaps://" diff --git a/samples/net/lwm2m_client/overlay-bootstrap.conf b/samples/net/lwm2m_client/overlay-bootstrap.conf index 68308bbd22b..5993329cb1b 100644 --- a/samples/net/lwm2m_client/overlay-bootstrap.conf +++ b/samples/net/lwm2m_client/overlay-bootstrap.conf @@ -1,2 +1 @@ -CONFIG_LWM2M_PEER_PORT=5783 CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP=y diff --git a/samples/net/lwm2m_client/overlay-queue.conf b/samples/net/lwm2m_client/overlay-queue.conf index 946c0fbab67..2f2ee2aceaa 100644 --- a/samples/net/lwm2m_client/overlay-queue.conf +++ b/samples/net/lwm2m_client/overlay-queue.conf @@ -1,5 +1,12 @@ CONFIG_LWM2M_QUEUE_MODE_ENABLED=y -CONFIG_LWM2M_QUEUE_MODE_UPTIME=20 + +# Listen for incoming CoAP messages for 30 seconds after last TX. +# This is a common NAT timeout for cellular networks. +CONFIG_LWM2M_QUEUE_MODE_UPTIME=30 + +# When DTLS Connection Identifier is used, we can keep socket open +# and just stop polling while in idle state (QUEUE_RX_OFF). +# If the server does not support DTLS-CID, use CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE=y # Default lifetime is 1 day diff --git a/samples/net/sockets/can/src/main.c b/samples/net/sockets/can/src/main.c index 506157c6afe..8bd51984a64 100644 --- a/samples/net/sockets/can/src/main.c +++ b/samples/net/sockets/can/src/main.c @@ -32,7 +32,7 @@ static struct k_thread rx_data; #define CLOSE_PERIOD 15 static const struct can_filter zfilter = { - .flags = CAN_FILTER_DATA, + .flags = 0U, .id = 0x1, .mask = CAN_STD_ID_MASK }; diff --git a/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c b/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c index 76b94934df8..d9194ca0dd2 100644 --- a/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c +++ b/samples/net/sockets/dumb_http_server/src/socket_dumb_http.c @@ -40,6 +40,21 @@ static const char content[] = { #endif }; +/* If accept returns an error, then we are probably running + * out of resource. Sleep a small amount of time in order the + * system to cool down. + */ +#define ACCEPT_ERROR_WAIT 100 /* in ms */ + +static void sleep_after_error(unsigned int amount) +{ +#if defined(__ZEPHYR__) + k_msleep(amount); +#else + usleep(amount * 1000U); +#endif +} + int main(void) { int serv; @@ -72,6 +87,7 @@ int main(void) &client_addr_len); if (client < 0) { printf("Error in accept: %d - continuing\n", errno); + sleep_after_error(ACCEPT_ERROR_WAIT); continue; } diff --git a/samples/net/sockets/dumb_http_server_mt/src/main.c b/samples/net/sockets/dumb_http_server_mt/src/main.c index baa295b7f50..06f9f0c6e71 100644 --- a/samples/net/sockets/dumb_http_server_mt/src/main.c +++ b/samples/net/sockets/dumb_http_server_mt/src/main.c @@ -20,6 +20,12 @@ LOG_MODULE_REGISTER(net_dumb_http_srv_mt_sample); #define MY_PORT 8080 +/* If accept returns an error, then we are probably running + * out of resource. Sleep a small amount of time in order the + * system to cool down. + */ +#define ACCEPT_ERROR_WAIT 100 /* in ms */ + #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) #define STACK_SIZE 4096 @@ -268,8 +274,9 @@ static int process_tcp(int *sock, int *accepted) client = accept(*sock, (struct sockaddr *)&client_addr, &client_addr_len); if (client < 0) { - LOG_ERR("Error in accept %d, stopping server", -errno); - return -errno; + LOG_DBG("Error in accept %d, ignored", -errno); + k_msleep(ACCEPT_ERROR_WAIT); + return 0; } slot = get_free_slot(accepted); diff --git a/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf b/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf index 5426e8ba625..085594463e1 100644 --- a/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf +++ b/samples/net/sockets/echo_client/boards/atsamr21_xpro.conf @@ -1,23 +1,33 @@ # -# Copyright (c) 2020-2021, Gerson Fernando Budke # Copyright (c) 2019, Benjamin Valentin +# Copyright (c) 2020-2024, Gerson Fernando Budke # # SPDX-License-Identifier: Apache-2.0 # -# Reduced buffers to fit into SAMR21 SoC +# Reduced configs to fit into SAMR21 SoC CONFIG_CPP=n -CONFIG_NET_PKT_RX_COUNT=6 -CONFIG_NET_PKT_TX_COUNT=6 -CONFIG_NET_BUF_RX_COUNT=6 -CONFIG_NET_BUF_TX_COUNT=6 -CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_PKT_RX_COUNT=5 +CONFIG_NET_PKT_TX_COUNT=5 +CONFIG_NET_BUF_RX_COUNT=5 +CONFIG_NET_BUF_TX_COUNT=5 +CONFIG_NET_MAX_CONTEXTS=2 CONFIG_NET_MAX_CONN=1 CONFIG_NET_MAX_ROUTES=1 CONFIG_NET_MAX_NEXTHOPS=1 CONFIG_SHELL_STACK_SIZE=768 -CONFIG_SHELL_CMD_BUFF_SIZE=64 +CONFIG_SHELL_CMD_BUFF_SIZE=32 CONFIG_SHELL_ARGC_MAX=6 -CONFIG_SHELL_HISTORY_BUFFER=64 +CONFIG_SHELL_HISTORY_BUFFER=4 + +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_NET_IP_DSCP_ECN=n +CONFIG_NET_STATISTICS=n +CONFIG_NET_MGMT_EVENT_STACK_SIZE=512 +CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE=512 + +CONFIG_UART_USE_RUNTIME_CONFIGURE=n +CONFIG_NET_CONTEXT_REUSEADDR=n +CONFIG_NET_CONTEXT_REUSEPORT=n diff --git a/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf b/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf index 5426e8ba625..085594463e1 100644 --- a/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf +++ b/samples/net/sockets/echo_server/boards/atsamr21_xpro.conf @@ -1,23 +1,33 @@ # -# Copyright (c) 2020-2021, Gerson Fernando Budke # Copyright (c) 2019, Benjamin Valentin +# Copyright (c) 2020-2024, Gerson Fernando Budke # # SPDX-License-Identifier: Apache-2.0 # -# Reduced buffers to fit into SAMR21 SoC +# Reduced configs to fit into SAMR21 SoC CONFIG_CPP=n -CONFIG_NET_PKT_RX_COUNT=6 -CONFIG_NET_PKT_TX_COUNT=6 -CONFIG_NET_BUF_RX_COUNT=6 -CONFIG_NET_BUF_TX_COUNT=6 -CONFIG_NET_MAX_CONTEXTS=4 +CONFIG_NET_PKT_RX_COUNT=5 +CONFIG_NET_PKT_TX_COUNT=5 +CONFIG_NET_BUF_RX_COUNT=5 +CONFIG_NET_BUF_TX_COUNT=5 +CONFIG_NET_MAX_CONTEXTS=2 CONFIG_NET_MAX_CONN=1 CONFIG_NET_MAX_ROUTES=1 CONFIG_NET_MAX_NEXTHOPS=1 CONFIG_SHELL_STACK_SIZE=768 -CONFIG_SHELL_CMD_BUFF_SIZE=64 +CONFIG_SHELL_CMD_BUFF_SIZE=32 CONFIG_SHELL_ARGC_MAX=6 -CONFIG_SHELL_HISTORY_BUFFER=64 +CONFIG_SHELL_HISTORY_BUFFER=4 + +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_NET_IP_DSCP_ECN=n +CONFIG_NET_STATISTICS=n +CONFIG_NET_MGMT_EVENT_STACK_SIZE=512 +CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE=512 + +CONFIG_UART_USE_RUNTIME_CONFIGURE=n +CONFIG_NET_CONTEXT_REUSEADDR=n +CONFIG_NET_CONTEXT_REUSEPORT=n diff --git a/samples/net/sockets/echo_service/CMakeLists.txt b/samples/net/sockets/echo_service/CMakeLists.txt new file mode 100644 index 00000000000..fda31959a7d --- /dev/null +++ b/samples/net/sockets/echo_service/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(sockets_service_echo) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/sockets/echo_service/README.rst b/samples/net/sockets/echo_service/README.rst new file mode 100644 index 00000000000..3e1d7625d70 --- /dev/null +++ b/samples/net/sockets/echo_service/README.rst @@ -0,0 +1,51 @@ +.. zephyr:code-sample:: sockets-service-echo + :name: Echo server (service) + :relevant-api: bsd_sockets + + Implements a simple IPv4/IPv6 TCP echo server using BSD sockets and socket service API. + +Overview +******** + +The sockets/echo_service sample application for Zephyr implements a TCP echo +server supporting both IPv4 and IPv6 and using a BSD Sockets compatible API. + +The purpose of this sample is to show how to use socket service API. +The socket service is a concept where many blocking sockets can be listened by +one thread, and which can then trigger a callback if there is activity in the set +of sockets. This saves memory as only one thread needs to be created in the +system. + +The application supports IPv4 and IPv6, and both UDP and TCP are also supported. +The source code for this sample application can be found at: +:zephyr_file:`samples/net/sockets/echo_service`. + +Requirements +************ + +- :ref:`networking_with_host` +- or, a board with hardware networking + +Building and Running +******************** + +Build the Zephyr version of the sockets/echo_service application like this: + +.. zephyr-app-commands:: + :zephyr-app: samples/net/sockets/echo_service + :board: + :goals: build + :compact: + +After the sample starts, it expects connections at 192.0.2.1, or 2001:db8::1 +and port 4242. +The easiest way to connect is: + +.. code-block:: console + + $ telnet 192.0.2.1 4242 + +After a connection is made, the application will echo back any line sent +to it. The application implements a single-threaded server using blocking +sockets, and currently is only implemented to serve only one client connection +at time. After the current client disconnects, the next connection can proceed. diff --git a/samples/net/sockets/echo_service/overlay-e1000.conf b/samples/net/sockets/echo_service/overlay-e1000.conf new file mode 100644 index 00000000000..adcf29f904d --- /dev/null +++ b/samples/net/sockets/echo_service/overlay-e1000.conf @@ -0,0 +1,6 @@ +# Overlay for experimental TCP as qemu_x86 with E1000 + +CONFIG_PCIE=y + +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_QEMU_ETHERNET=y diff --git a/samples/net/sockets/echo_service/prj.conf b/samples/net/sockets/echo_service/prj.conf new file mode 100644 index 00000000000..c39159ea7e4 --- /dev/null +++ b/samples/net/sockets/echo_service/prj.conf @@ -0,0 +1,38 @@ +# General config +# The async method used in the sample needs more stack for the workqueue +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1500 +CONFIG_POSIX_API=y + +# Networking config +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y +CONFIG_NET_IPV4_MAPPING_TO_IPV6=y +CONFIG_POSIX_MAX_FDS=10 +CONFIG_NET_MAX_CONN=5 +CONFIG_NET_SOCKETS_SERVICE=y +CONFIG_NET_SOCKETS_POLL_MAX=20 + +# Network driver config +CONFIG_TEST_RANDOM_GENERATOR=y + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_CONFIG_NEED_IPV6=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" + +# Network buffers +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_PKT_TX_COUNT=16 +CONFIG_NET_BUF_RX_COUNT=64 +CONFIG_NET_BUF_TX_COUNT=64 +CONFIG_NET_CONTEXT_NET_PKT_POOL=y + +CONFIG_NET_SHELL=y diff --git a/samples/net/sockets/echo_service/sample.yaml b/samples/net/sockets/echo_service/sample.yaml new file mode 100644 index 00000000000..aee10686c0f --- /dev/null +++ b/samples/net/sockets/echo_service/sample.yaml @@ -0,0 +1,16 @@ +sample: + description: echo server using socket service API + name: socket_service_echo +common: + harness: net + depends_on: netif + filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC + # eventfd does not work properly with native_posix so exclude it here + platform_exclude: + - native_posix + - native_posix_64 +tests: + sample.net.sockets.service.echo: + tags: + - net + - socket diff --git a/samples/net/sockets/echo_service/src/main.c b/samples/net/sockets/echo_service/src/main.c new file mode 100644 index 00000000000..dbdde28cf30 --- /dev/null +++ b/samples/net/sockets/echo_service/src/main.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_echo_server_svc_sample, LOG_LEVEL_DBG); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MY_PORT 4242 + +static char addr_str[INET6_ADDRSTRLEN]; + +static struct pollfd sockfd_udp[1] = { + [0] = { .fd = -1 }, /* UDP socket */ +}; +static struct pollfd sockfd_tcp[1] = { + [0] = { .fd = -1 }, /* TCP socket */ +}; + +#define MAX_SERVICES 1 + +static void receive_data(bool is_udp, struct net_socket_service_event *pev, + char *buf, size_t buflen); + +static void tcp_service_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + static char buf[1500]; + + /* Note that in this application we receive / send data from + * system work queue. In proper application the socket reading and data + * sending should be done so that the system work queue is not blocked. + * It is possible to create a socket service that uses own work queue. + */ + receive_data(false, pev, buf, sizeof(buf)); +} + +static void udp_service_handler(struct k_work *work) +{ + struct net_socket_service_event *pev = + CONTAINER_OF(work, struct net_socket_service_event, work); + static char buf[1500]; + + receive_data(true, pev, buf, sizeof(buf)); +} + +/* In this example we create two services, one with async behavior and one with + * sync one. The async is for TCP and sync is for UDP (this is just an arbitrary + * choice). + * This is an artificial example, both UDP and TCP sockets could be served by the + * same service. + */ +NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_udp, NULL, udp_service_handler, MAX_SERVICES); +NET_SOCKET_SERVICE_ASYNC_DEFINE_STATIC(service_tcp, NULL, tcp_service_handler, MAX_SERVICES); + +static void receive_data(bool is_udp, struct net_socket_service_event *pev, + char *buf, size_t buflen) +{ + struct pollfd *pfd = &pev->event; + int client = pfd->fd; + struct sockaddr_in6 addr; + socklen_t addrlen = sizeof(addr); + int len, out_len; + char *p; + + len = recvfrom(client, buf, buflen, 0, + (struct sockaddr *)&addr, &addrlen); + if (len <= 0) { + if (len < 0) { + LOG_ERR("recv: %d", -errno); + } + + /* If the TCP socket is closed, mark it as non pollable */ + if (!is_udp && sockfd_tcp[0].fd == client) { + sockfd_tcp[0].fd = -1; + + /* Update the handler so that client connection is + * not monitored any more. + */ + (void)net_socket_service_register(&service_tcp, sockfd_tcp, + ARRAY_SIZE(sockfd_tcp), NULL); + close(client); + + LOG_INF("Connection from %s closed", addr_str); + } + + return; + } + + p = buf; + do { + out_len = sendto(client, p, len, 0, + (struct sockaddr *)&addr, addrlen); + if (out_len < 0) { + LOG_ERR("sendto: %d", -errno); + break; + } + + p += out_len; + len -= out_len; + } while (len); +} + +static int setup_tcp_socket(struct sockaddr_in6 *addr) +{ + socklen_t optlen = sizeof(int); + int ret, sock, opt; + + sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + LOG_ERR("socket: %d", -errno); + return -errno; + } + + ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen); + if (ret == 0 && opt) { + LOG_INF("IPV6_V6ONLY option is on, turning it off."); + + opt = 0; + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen); + if (ret < 0) { + LOG_WRN("Cannot turn off IPV6_V6ONLY option"); + } else { + LOG_INF("Sharing same socket between IPv6 and IPv4"); + } + } + + if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + LOG_ERR("bind: %d", -errno); + return -errno; + } + + if (listen(sock, 5) < 0) { + LOG_ERR("listen: %d", -errno); + return -errno; + } + + return sock; +} + +static int setup_udp_socket(struct sockaddr_in6 *addr) +{ + socklen_t optlen = sizeof(int); + int ret, sock, opt; + + sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + LOG_ERR("socket: %d", -errno); + return -errno; + } + + ret = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, &optlen); + if (ret == 0 && opt) { + LOG_INF("IPV6_V6ONLY option is on, turning it off."); + + opt = 0; + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, optlen); + if (ret < 0) { + LOG_WRN("Cannot turn off IPV6_V6ONLY option"); + } else { + LOG_INF("Sharing same socket between IPv6 and IPv4"); + } + } + + if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { + LOG_ERR("bind: %d", -errno); + return -errno; + } + + return sock; +} + +int main(void) +{ + int tcp_sock, udp_sock, ret; + struct sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + .sin6_port = htons(MY_PORT), + }; + static int counter; + + tcp_sock = setup_tcp_socket(&addr); + if (tcp_sock < 0) { + return tcp_sock; + } + + udp_sock = setup_udp_socket(&addr); + if (udp_sock < 0) { + return udp_sock; + } + + sockfd_udp[0].fd = udp_sock; + sockfd_udp[0].events = POLLIN; + + /* Register UDP socket to service handler */ + ret = net_socket_service_register(&service_udp, sockfd_udp, + ARRAY_SIZE(sockfd_udp), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", ret); + } + + LOG_INF("Single-threaded TCP/UDP echo server waits " + "for a connection on port %d", MY_PORT); + + while (1) { + struct sockaddr_in6 client_addr; + socklen_t client_addr_len = sizeof(client_addr); + int client; + + client = accept(tcp_sock, (struct sockaddr *)&client_addr, + &client_addr_len); + if (client < 0) { + LOG_ERR("accept: %d", -errno); + continue; + } + + inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr, + addr_str, sizeof(addr_str)); + LOG_INF("Connection #%d from %s (%d)", counter++, addr_str, client); + + sockfd_tcp[0].fd = client; + sockfd_tcp[0].events = POLLIN; + + /* Register all the sockets to service handler */ + ret = net_socket_service_register(&service_tcp, sockfd_tcp, + ARRAY_SIZE(sockfd_tcp), NULL); + if (ret < 0) { + LOG_ERR("Cannot register socket service handler (%d)", + ret); + break; + } + } + + (void)net_socket_service_unregister(&service_tcp); + (void)net_socket_service_unregister(&service_udp); + + close(tcp_sock); + close(udp_sock); + + return 0; +} diff --git a/samples/net/sockets/net_mgmt/sample.yaml b/samples/net/sockets/net_mgmt/sample.yaml index 7199cb2614a..337e8d08a75 100644 --- a/samples/net/sockets/net_mgmt/sample.yaml +++ b/samples/net/sockets/net_mgmt/sample.yaml @@ -17,3 +17,5 @@ tests: tags: userspace extra_configs: - CONFIG_USERSPACE=y + platform_exclude: + - ip_k66f diff --git a/samples/net/syslog_net/prj.conf b/samples/net/syslog_net/prj.conf index b0ae6043cef..7bd3870b431 100644 --- a/samples/net/syslog_net/prj.conf +++ b/samples/net/syslog_net/prj.conf @@ -7,6 +7,7 @@ CONFIG_NET_PKT_RX_COUNT=32 CONFIG_NET_PKT_TX_COUNT=32 CONFIG_NET_BUF_RX_COUNT=32 CONFIG_NET_BUF_TX_COUNT=32 +CONFIG_NET_SOCKETS=y CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 @@ -36,5 +37,5 @@ CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" CONFIG_LOG_BACKEND_NET=y CONFIG_LOG_BACKEND_NET_SERVER="[2001:db8::2]:514" -# Get newlib by default as it has proper time function support +# Get a proper libc by default in order to get working time function support CONFIG_REQUIRES_FULL_LIBC=y diff --git a/samples/net/wifi/boards/esp32_devkitc_wroom.conf b/samples/net/wifi/boards/esp32_devkitc_wroom.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32_devkitc_wroom.conf +++ b/samples/net/wifi/boards/esp32_devkitc_wroom.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32_devkitc_wrover.conf b/samples/net/wifi/boards/esp32_devkitc_wrover.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32_devkitc_wrover.conf +++ b/samples/net/wifi/boards/esp32_devkitc_wrover.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_devkitm.conf b/samples/net/wifi/boards/esp32c3_devkitm.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_devkitm.conf +++ b/samples/net/wifi/boards/esp32c3_devkitm.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_luatos_core.conf b/samples/net/wifi/boards/esp32c3_luatos_core.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_luatos_core.conf +++ b/samples/net/wifi/boards/esp32c3_luatos_core.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf b/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf +++ b/samples/net/wifi/boards/esp32c3_luatos_core_usb.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/wifi/boards/xiao_esp32c3.conf b/samples/net/wifi/boards/xiao_esp32c3.conf new file mode 100644 index 00000000000..a72fdf39efa --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32c3.conf @@ -0,0 +1,11 @@ +CONFIG_WIFI=y + +CONFIG_NETWORKING=y +CONFIG_NET_L2_ETHERNET=y + +CONFIG_NET_IPV6=n +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_ESP32_WIFI_STA_AUTO_DHCPV4=y + +CONFIG_NET_LOG=y diff --git a/samples/net/wifi/boards/xiao_esp32c3.overlay b/samples/net/wifi/boards/xiao_esp32c3.overlay new file mode 100644 index 00000000000..4d69fe29493 --- /dev/null +++ b/samples/net/wifi/boards/xiao_esp32c3.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&wifi { + status = "okay"; +}; diff --git a/samples/net/wifi/boards/yd_esp32.conf b/samples/net/wifi/boards/yd_esp32.conf index 5c37cfc402d..a72fdf39efa 100644 --- a/samples/net/wifi/boards/yd_esp32.conf +++ b/samples/net/wifi/boards/yd_esp32.conf @@ -1,5 +1,4 @@ CONFIG_WIFI=y -CONFIG_HEAP_MEM_POOL_SIZE=98304 CONFIG_NETWORKING=y CONFIG_NET_L2_ETHERNET=y diff --git a/samples/net/zperf/CMakeLists.txt b/samples/net/zperf/CMakeLists.txt index ae9b46dadc0..c4552f97141 100644 --- a/samples/net/zperf/CMakeLists.txt +++ b/samples/net/zperf/CMakeLists.txt @@ -8,3 +8,17 @@ project(zperf) target_sources(app PRIVATE src/main.c ) + +if (CONFIG_NET_SAMPLE_CODE_RELOCATE) + # Relocate key networking stack components and L2 layer to RAM + zephyr_code_relocate(LIBRARY subsys__net__ip + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) + zephyr_code_relocate(LIBRARY subsys__net + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) +if (CONFIG_NET_L2_ETHERNET) + zephyr_code_relocate(LIBRARY drivers__ethernet + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) + zephyr_code_relocate(LIBRARY subsys__net__l2__ethernet + LOCATION "${CONFIG_NET_SAMPLE_CODE_RAM_NAME}_TEXT" NOKEEP) +endif() +endif() diff --git a/samples/net/zperf/Kconfig b/samples/net/zperf/Kconfig new file mode 100644 index 00000000000..a56cd6b9416 --- /dev/null +++ b/samples/net/zperf/Kconfig @@ -0,0 +1,22 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config NET_SAMPLE_CODE_RELOCATE + bool "Relocate networking code into RAM" + select CODE_DATA_RELOCATION + help + Relocate networking code into RAM when running the zperf + sample. Can improve performance on platforms with fast code + RAM. + +if NET_SAMPLE_CODE_RELOCATE + +config NET_SAMPLE_CODE_RAM_NAME + string "Networking code RAM location" + default "RAM" + help + Region to relocate networking code to + +endif # NET_SAMPLE_CODE_RELOCATE diff --git a/samples/net/zperf/boards/mimxrt1050_evk.conf b/samples/net/zperf/boards/mimxrt1050_evk.conf index 8f90b5bd833..287d55db122 100644 --- a/samples/net/zperf/boards/mimxrt1050_evk.conf +++ b/samples/net/zperf/boards/mimxrt1050_evk.conf @@ -1,2 +1,4 @@ # Note: HW accleration does not support IPV6 CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1050_evk.overlay b/samples/net/zperf/boards/mimxrt1050_evk.overlay deleted file mode 100644 index 4340caf2abc..00000000000 --- a/samples/net/zperf/boards/mimxrt1050_evk.overlay +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Use cortex systick as hardware timer */ -&systick { - status = "okay"; -}; - -&gpt_hw_timer { - status = "disabled"; -}; diff --git a/samples/net/zperf/boards/mimxrt1060_evk.conf b/samples/net/zperf/boards/mimxrt1060_evk.conf index 8f90b5bd833..287d55db122 100644 --- a/samples/net/zperf/boards/mimxrt1060_evk.conf +++ b/samples/net/zperf/boards/mimxrt1060_evk.conf @@ -1,2 +1,4 @@ # Note: HW accleration does not support IPV6 CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1060_evk.overlay b/samples/net/zperf/boards/mimxrt1060_evk.overlay deleted file mode 100644 index 4340caf2abc..00000000000 --- a/samples/net/zperf/boards/mimxrt1060_evk.overlay +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Use cortex systick as hardware timer */ -&systick { - status = "okay"; -}; - -&gpt_hw_timer { - status = "disabled"; -}; diff --git a/samples/net/zperf/boards/mimxrt1064_evk.conf b/samples/net/zperf/boards/mimxrt1064_evk.conf new file mode 100644 index 00000000000..287d55db122 --- /dev/null +++ b/samples/net/zperf/boards/mimxrt1064_evk.conf @@ -0,0 +1,4 @@ +# Note: HW accleration does not support IPV6 +CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf b/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 00000000000..287d55db122 --- /dev/null +++ b/samples/net/zperf/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,4 @@ +# Note: HW accleration does not support IPV6 +CONFIG_ETH_MCUX_HW_ACCELERATION=y +CONFIG_NET_SAMPLE_CODE_RELOCATE=y +CONFIG_NET_SAMPLE_CODE_RAM_NAME="ITCM" diff --git a/samples/net/zperf/prj.conf b/samples/net/zperf/prj.conf index 39f1217d62d..230e0462333 100644 --- a/samples/net/zperf/prj.conf +++ b/samples/net/zperf/prj.conf @@ -20,7 +20,7 @@ CONFIG_NET_MAX_CONTEXTS=5 CONFIG_NET_TC_TX_COUNT=1 CONFIG_NET_SOCKETS=y CONFIG_NET_SOCKETS_POSIX_NAMES=y -CONFIG_NET_SOCKETS_POLL_MAX=4 +CONFIG_NET_SOCKETS_POLL_MAX=9 CONFIG_POSIX_MAX_FDS=8 CONFIG_INIT_STACKS=y diff --git a/samples/net/zperf/sample.yaml b/samples/net/zperf/sample.yaml index 201940c23a9..99b8f50d31a 100644 --- a/samples/net/zperf/sample.yaml +++ b/samples/net/zperf/sample.yaml @@ -80,3 +80,16 @@ tests: depends_on: - arduino_spi - arduino_gpio + sample.net.zperf.nxp_enet_experimental: + extra_args: EXTRA_DTC_OVERLAY_FILE="nxp,enet-experimental.overlay" + tags: + - net + - zperf + platform_allow: + - mimxrt1050_evk + - mimxrt1060_evk + - mimxrt1064_evk + - mimxrt1024_evk + - frdm_k64f + - mimxrt1170_evk_cm7 + - mimxrt1160_evk_cm7 diff --git a/samples/philosophers/prj.conf b/samples/philosophers/prj.conf index 8db50d11529..05e25c210d7 100644 --- a/samples/philosophers/prj.conf +++ b/samples/philosophers/prj.conf @@ -1,9 +1,4 @@ CONFIG_STDOUT_CONSOLE=n -CONFIG_ASSERT=y -CONFIG_ASSERT_LEVEL=2 -CONFIG_NUM_COOP_PRIORITIES=29 -CONFIG_NUM_PREEMPT_PRIORITIES=40 -CONFIG_SCHED_SCALABLE=y CONFIG_MP_MAX_NUM_CPUS=1 #Enable thread awareness for debugging tools supporting it diff --git a/samples/philosophers/sample.yaml b/samples/philosophers/sample.yaml index 2db2c1563f4..5ca2a2d8340 100644 --- a/samples/philosophers/sample.yaml +++ b/samples/philosophers/sample.yaml @@ -3,7 +3,7 @@ sample: common: extra_args: DEBUG_PRINTF=1 tags: - - inroduction + - introduction - kernel harness: console min_ram: 16 diff --git a/samples/posix/eventfd/Makefile.host b/samples/posix/eventfd/Makefile.host index 8cb1f7d7da6..b5080991747 100644 --- a/samples/posix/eventfd/Makefile.host +++ b/samples/posix/eventfd/Makefile.host @@ -1,4 +1,5 @@ # This makefile builds the sample for a POSIX system, like Linux eventfd: src/main.c - $(CC) $^ -o $@ + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/eventfd/README.rst b/samples/posix/eventfd/README.rst new file mode 100644 index 00000000000..c6947d6e57c --- /dev/null +++ b/samples/posix/eventfd/README.rst @@ -0,0 +1,46 @@ +.. _posix-eventfd-sample: + +POSIX eventfd() +############### + +Overview +******** + +This sample application demonstrates using the POSIX eventfd() function to create a file descriptor, +which can be used for event notification. The returned file descriptor is used with write/read calls +and write/read values are output to the console. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/eventfd + :host-os: unix + :board: qemu_x86 + :goals: run + :compact: + +For comparison, to build directly for your host OS if it is POSIX compliant (for ex. Linux): + +.. code-block:: console + + cd samples/posix/eventfd + make -f Makefile.host + +The make output file will be located in samples/posix/eventfd/build. + +Sample Output +============= + +.. code-block:: console + + Writing 1 to efd + Writing 2 to efd + Writing 3 to efd + Writing 4 to efd + Completed write loop + About to read + Read 10 (0xa) from efd + Finished diff --git a/samples/posix/gettimeofday/Makefile.host b/samples/posix/gettimeofday/Makefile.host index eb0529e1864..76023d7f21e 100644 --- a/samples/posix/gettimeofday/Makefile.host +++ b/samples/posix/gettimeofday/Makefile.host @@ -1,4 +1,5 @@ # This makefile builds the sample for a POSIX system, like Linux gettimeofday: src/main.c - $(CC) $^ -o $@ + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/gettimeofday/README.rst b/samples/posix/gettimeofday/README.rst index c01f1c65e33..a9cd4771818 100644 --- a/samples/posix/gettimeofday/README.rst +++ b/samples/posix/gettimeofday/README.rst @@ -6,10 +6,9 @@ POSIX gettimeofday() with clock initialization over SNTP Overview ******** -This sample application demonstrates using the POSIX gettimeofday() -function to display the absolute wall clock time and local time every -second. At system startup, the current time is queried using the SNTP -networking protocol, enabled by setting the +This sample application demonstrates using the POSIX `gettimeofday()`_ function to display the +absolute wall clock time and local time every second. At system startup, the current time is +queried using the SNTP networking protocol, enabled by setting the :kconfig:option:`CONFIG_NET_CONFIG_CLOCK_SNTP_INIT` and :kconfig:option:`CONFIG_NET_CONFIG_SNTP_INIT_SERVER` options. @@ -24,8 +23,7 @@ Requirements Building and Running ******************** -This project outputs to the console. It can be built and executed -on QEMU as follows: +This project outputs to the console. It can be built and executed on QEMU as follows: .. zephyr-app-commands:: :zephyr-app: samples/posix/gettimeofday @@ -38,4 +36,9 @@ For comparison, to build directly for your host OS if it is POSIX compliant (for .. code-block:: console + cd samples/posix/gettimeofday make -f Makefile.host + +The make output file will be located in samples/posix/gettimeofday/build. + +.. _gettimeofday(): https://pubs.opengroup.org/onlinepubs/009604599/functions/gettimeofday.html diff --git a/samples/posix/philosophers/CMakeLists.txt b/samples/posix/philosophers/CMakeLists.txt new file mode 100644 index 00000000000..2f19561d195 --- /dev/null +++ b/samples/posix/philosophers/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(posix_philosophers) + +target_sources(app PRIVATE src/main.c) +# For translating POSIX scheduler policies and priorities to +# Zephyr priorities. +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/lib/posix/options) diff --git a/samples/posix/philosophers/Kconfig b/samples/posix/philosophers/Kconfig new file mode 100644 index 00000000000..5105138ca83 --- /dev/null +++ b/samples/posix/philosophers/Kconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024, Meta +# +# SPDX-License-Identifier: Apache-2.0 + +config SAMPLE_ERROR_CHECKING + bool "Perform error checking" + +config SAMPLE_DEBUG_PRINTF + bool "Print debug information" + default y + +config SAMPLE_SAME_PRIO + bool "Print debug information" + default n + +source "Kconfig.zephyr" diff --git a/samples/posix/philosophers/README.rst b/samples/posix/philosophers/README.rst new file mode 100644 index 00000000000..a480d4398a7 --- /dev/null +++ b/samples/posix/philosophers/README.rst @@ -0,0 +1,56 @@ +.. _posix-philosophers-sample: + +POSIX Philosophers +################## + +Overview +******** + +This sample implements Zephyr's :ref:`Dining Philosophers Sample ` using the +:ref:`POSIX API `. The source code for this sample can be found under +:file:`samples/posix/philosophers`. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/philosophers + :host-os: unix + :board: qemu_riscv64 + :goals: run + :compact: + +Sample Output +============= + +.. code-block:: console + + Philosopher 0 [P: 3] HOLDING ONE FORK + Philosopher 1 [P: 2] HOLDING ONE FORK + Philosopher 2 [P: 1] EATING [ 1900 ms ] + Philosopher 3 [P: 0] THINKING [ 2500 ms ] + Philosopher 4 [C:-1] THINKING [ 2200 ms ] + Philosopher 5 [C:-2] THINKING [ 1700 ms ] + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + +Debugging +********* + +Like the original philosophers sample, the POSIX variant also enables +:kconfig:option:`CONFIG_DEBUG_THREAD_INFO` by default. + +.. zephyr-app-commands:: + :zephyr-app: samples/philosophers + :host-os: unix + :board: + :goals: debug + :compact: + +Additional Information +********************** + +For additional information, please refer to the +:ref:`Dining Philosophers Sample `. diff --git a/samples/posix/philosophers/prj.conf b/samples/posix/philosophers/prj.conf new file mode 100644 index 00000000000..0934325aea6 --- /dev/null +++ b/samples/posix/philosophers/prj.conf @@ -0,0 +1,13 @@ +CONFIG_STDOUT_CONSOLE=n +CONFIG_MP_MAX_NUM_CPUS=1 + +CONFIG_POSIX_API=y +CONFIG_THREAD_STACK_INFO=y +CONFIG_DYNAMIC_THREAD=y + +CONFIG_DYNAMIC_THREAD_POOL_SIZE=6 +CONFIG_MAX_PTHREAD_COUNT=6 +CONFIG_MAX_PTHREAD_MUTEX_COUNT=6 + +#Enable thread awareness for debugging tools supporting it +CONFIG_DEBUG_THREAD_INFO=y diff --git a/samples/posix/philosophers/sample.yaml b/samples/posix/philosophers/sample.yaml new file mode 100644 index 00000000000..08e0c1d970a --- /dev/null +++ b/samples/posix/philosophers/sample.yaml @@ -0,0 +1,21 @@ +sample: + name: POSIX Philosophers +common: + tags: + - introduction + - posix + harness: console + min_ram: 16 + integration_platforms: + - native_sim + filter: not CONFIG_NATIVE_APPLICATION + harness_config: + type: multi_line + ordered: false + regex: + - ".*STARVING.*" + - ".*DROPPED ONE FORK.*" + - ".*THINKING.*" + - ".*EATING.*" +tests: + sample.posix.philosopher: {} diff --git a/samples/posix/philosophers/src/main.c b/samples/posix/philosophers/src/main.c new file mode 100644 index 00000000000..29861803aab --- /dev/null +++ b/samples/posix/philosophers/src/main.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2011-2016 Wind River Systems, Inc. + * Copyright (c) 2024, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_internal.h" + +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_THREAD_NAME +#define MAX_NAME_LEN CONFIG_THREAD_MAX_NAME_LEN +#else +#define MAX_NAME_LEN 1 +#endif + +#define NUM_PHIL CONFIG_MAX_PTHREAD_COUNT +#define obj_init_type "POSIX" +#define fork_type_str "mutexes" + +BUILD_ASSERT(CONFIG_MAX_PTHREAD_COUNT == CONFIG_MAX_PTHREAD_MUTEX_COUNT); +BUILD_ASSERT(CONFIG_DYNAMIC_THREAD_POOL_SIZE == CONFIG_MAX_PTHREAD_COUNT); + +typedef pthread_mutex_t *fork_t; + +LOG_MODULE_REGISTER(posix_philosophers, LOG_LEVEL_INF); + +static pthread_mutex_t forks[NUM_PHIL]; +static pthread_t threads[NUM_PHIL]; + +static inline void fork_init(fork_t frk) +{ + int ret; + + ret = pthread_mutex_init(frk, NULL); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_init"); + __ASSERT(false, "Failed to initialize fork"); + } +} + +static inline fork_t fork(size_t idx) +{ + return &forks[idx]; +} + +static inline void take(fork_t frk) +{ + int ret; + + ret = pthread_mutex_lock(frk); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_lock"); + __ASSERT(false, "Failed to lock mutex"); + } +} + +static inline void drop(fork_t frk) +{ + int ret; + + ret = pthread_mutex_unlock(frk); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_mutex_unlock"); + __ASSERT(false, "Failed to unlock mutex"); + } +} + +static void set_phil_state_pos(int id) +{ + if (IS_ENABLED(CONFIG_SAMPLE_DEBUG_PRINTF)) { + printk("\x1b[%d;%dH", id + 1, 1); + } +} + +static void print_phil_state(int id, const char *fmt, int32_t delay) +{ + int ret; + int prio; + int policy; + struct sched_param param; + + ret = pthread_getschedparam(pthread_self(), &policy, ¶m); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_getschedparam"); + __ASSERT(false, "Failed to get scheduler params"); + } + + prio = posix_to_zephyr_priority(param.sched_priority, policy); + + set_phil_state_pos(id); + + printk("Philosopher %d [%s:%s%d] ", id, prio < 0 ? "C" : "P", prio < 0 ? "" : " ", prio); + + if (delay) { + printk(fmt, delay < 1000 ? " " : "", delay); + } else { + printk(fmt, ""); + } + + printk("\n"); +} + +static int32_t get_random_delay(int id, int period_in_ms) +{ + int32_t ms; + int32_t delay; + int32_t uptime; + struct timespec ts; + + /* + * The random delay is unit-less, and is based on the philosopher's ID + * and the current uptime to create some pseudo-randomness. It produces + * a value between 0 and 31. + */ + clock_gettime(CLOCK_MONOTONIC, &ts); + uptime = ts.tv_sec * MSEC_PER_SEC + (ts.tv_nsec / NSEC_PER_MSEC); + delay = (uptime / 100 * (id + 1)) & 0x1f; + + /* add 1 to not generate a delay of 0 */ + ms = (delay + 1) * period_in_ms; + + return ms; +} + +static inline int is_last_philosopher(int id) +{ + return id == (NUM_PHIL - 1); +} + +static void *philosopher(void *arg) +{ + fork_t my_fork1; + fork_t my_fork2; + + int my_id = POINTER_TO_INT(arg); + + /* Djkstra's solution: always pick up the lowest numbered fork first */ + if (is_last_philosopher(my_id)) { + my_fork1 = fork(0); + my_fork2 = fork(my_id); + } else { + my_fork1 = fork(my_id); + my_fork2 = fork(my_id + 1); + } + + while (1) { + int32_t delay; + + print_phil_state(my_id, " STARVING ", 0); + take(my_fork1); + print_phil_state(my_id, " HOLDING ONE FORK ", 0); + take(my_fork2); + + delay = get_random_delay(my_id, 25); + print_phil_state(my_id, " EATING [ %s%d ms ] ", delay); + usleep(delay * USEC_PER_MSEC); + + drop(my_fork2); + print_phil_state(my_id, " DROPPED ONE FORK ", 0); + drop(my_fork1); + + delay = get_random_delay(my_id, 25); + print_phil_state(my_id, " THINKING [ %s%d ms ] ", delay); + usleep(delay * USEC_PER_MSEC); + } + + return NULL; +} + +static int new_prio(int phil) +{ + if (CONFIG_NUM_COOP_PRIORITIES > 0 && CONFIG_NUM_PREEMPT_PRIORITIES > 0) { + if (IS_ENABLED(CONFIG_SAMPLE_SAME_PRIO)) { + return 0; + } + + return -(phil - (NUM_PHIL / 2)); + } + + if (CONFIG_NUM_COOP_PRIORITIES > 0) { + return -phil - 2; + } + + if (CONFIG_NUM_PREEMPT_PRIORITIES > 0) { + return phil; + } + + __ASSERT_NO_MSG("Unsupported scheduler configuration"); +} + +static void init_objects(void) +{ + ARRAY_FOR_EACH(forks, i) { + LOG_DBG("Initializing fork %zu", i); + fork_init(fork(i)); + } +} + +static void start_threads(void) +{ + int ret; + int prio; + int policy; + struct sched_param param; + + ARRAY_FOR_EACH(forks, i) { + LOG_DBG("Initializing philosopher %zu", i); + ret = pthread_create(&threads[i], NULL, philosopher, INT_TO_POINTER(i)); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_create"); + __ASSERT(false, "Failed to create thread"); + } + + prio = new_prio(i); + param.sched_priority = zephyr_to_posix_priority(prio, &policy); + ret = pthread_setschedparam(threads[i], policy, ¶m); + if (IS_ENABLED(CONFIG_SAMPLE_ERROR_CHECKING) && ret != 0) { + errno = ret; + perror("pthread_setschedparam"); + __ASSERT(false, "Failed to set scheduler params"); + } + + if (IS_ENABLED(CONFIG_THREAD_NAME)) { + char tname[MAX_NAME_LEN]; + + snprintf(tname, sizeof(tname), "Philosopher %zu", i); + pthread_setname_np(threads[i], tname); + } + } +} + +#define DEMO_DESCRIPTION \ + "\x1b[2J\x1b[15;1H" \ + "Demo Description\n" \ + "----------------\n" \ + "An implementation of a solution to the Dining Philosophers\n" \ + "problem (a classic multi-thread synchronization problem).\n" \ + "This particular implementation demonstrates the usage of multiple\n" \ + "preemptible and cooperative threads of differing priorities, as\n" \ + "well as %s %s and thread sleeping.\n", \ + obj_init_type, fork_type_str + +static void display_demo_description(void) +{ + if (IS_ENABLED(CONFIG_SAMPLE_DEBUG_PRINTF)) { + printk(DEMO_DESCRIPTION); + } +} + +int main(void) +{ + display_demo_description(); + + init_objects(); + start_threads(); + + if (IS_ENABLED(CONFIG_COVERAGE)) { + /* Wait a few seconds before main() exit, giving the sample the + * opportunity to dump some output before coverage data gets emitted + */ + sleep(5); + } + + return 0; +} diff --git a/samples/posix/posix.rst b/samples/posix/posix.rst index c7b2e1d83a3..f7d026eb2cd 100644 --- a/samples/posix/posix.rst +++ b/samples/posix/posix.rst @@ -1,7 +1,7 @@ .. _posix-samples: -POSIX Subsystem Samples -####################### +POSIX API Samples +################# .. toctree:: :maxdepth: 1 diff --git a/samples/posix/uname/Makefile.host b/samples/posix/uname/Makefile.host new file mode 100644 index 00000000000..d5077cf0ec6 --- /dev/null +++ b/samples/posix/uname/Makefile.host @@ -0,0 +1,5 @@ +# This makefile builds the sample for a POSIX system, like Linux + +uname: src/main.c + mkdir -p build + $(CC) $^ -o build/$@ diff --git a/samples/posix/uname/README.rst b/samples/posix/uname/README.rst new file mode 100644 index 00000000000..a7d6c69946b --- /dev/null +++ b/samples/posix/uname/README.rst @@ -0,0 +1,52 @@ +.. _posix-uname-sample: + +POSIX uname() +############# + +Overview +******** + +In this sample application, the POSIX `uname()`_ function is used to acquire system information and +it is output to the console. Additionally, uname is added as a shell command and system information +is displayed according to the option(s) provided for the command. + +Building and Running +******************** + +This project outputs to the console. It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/posix/uname + :host-os: unix + :board: qemu_x86 + :goals: run + :compact: + +For comparison, to build directly for your host OS if it is POSIX compliant (for ex. Linux): + +.. code-block:: console + + cd samples/posix/uname + make -f Makefile.host + +The make output file will be located in samples/posix/uname/build. + +Sample Output +============= + +.. code-block:: console + + Printing everything in utsname... + sysname[7]: Zephyr + nodename[7]: zephyr + release[13]: 3.5.99 + version[61]: zephyr-v3.5.0-3515-g10156f5f1d9c Jan 9 2024 22:23:04 + machine[4]: x86 + + + uart:~$ uname -a + Zephyr zephyr 3.5.99 zephyr-v3.5.0-3515-g10156f5f1d9c Jan 9 2024 22:23:04 x86 qemu_x86 + uart:~$ uname -smi + Zephyr x86 qemu_x86 + +.. _uname(): https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html diff --git a/samples/posix/uname/prj.conf b/samples/posix/uname/prj.conf index 7b1dfc80964..1f171e76a4b 100644 --- a/samples/posix/uname/prj.conf +++ b/samples/posix/uname/prj.conf @@ -1,4 +1,4 @@ CONFIG_POSIX_API=y CONFIG_SHELL=y -CONFIG_SHELL_GETOPT=y +CONFIG_POSIX_UNAME_SHELL=y CONFIG_MP_MAX_NUM_CPUS=1 diff --git a/samples/posix/uname/src/main.c b/samples/posix/uname/src/main.c index 93af0af529d..c6a480fe6dd 100644 --- a/samples/posix/uname/src/main.c +++ b/samples/posix/uname/src/main.c @@ -4,172 +4,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include - +#include #include -#include -#include - int main(void) { struct utsname info; uname(&info); - printk("\nPrinting everything in utsname...\n"); - printk("sysname[%zu]: %s\n", sizeof(info.sysname), info.sysname); - printk("nodename[%zu]: %s\n", sizeof(info.nodename), info.nodename); - printk("release[%zu]: %s\n", sizeof(info.release), info.release); - printk("version[%zu]: %s\n", sizeof(info.version), info.version); - printk("machine[%zu]: %s\n", sizeof(info.machine), info.machine); - - return 0; -} - -#define UNAME_KERNEL BIT(0) -#define UNAME_NODE BIT(1) -#define UNAME_RELEASE BIT(2) -#define UNAME_VERSION BIT(3) -#define UNAME_MACHINE BIT(4) -#define UNAME_PLATFORM BIT(5) -#define UNAME_UNKNOWN BIT(6) -#define UNAME_ALL \ - (UNAME_KERNEL | UNAME_NODE | UNAME_RELEASE | UNAME_VERSION | UNAME_MACHINE | UNAME_PLATFORM) - -static void uname_print_usage(const struct shell *sh) -{ - shell_print(sh, "usage: uname [-asonrvmpi]"); -} - -static int uname_cmd_handler(const struct shell *sh, size_t argc, char **argv) -{ - struct getopt_state *state = getopt_state_get(); - struct utsname info; - unsigned int set; - int option; - char badarg = 0; - int ret; - - set = 0; - - /* Get the uname options */ - - optind = 1; - while ((option = getopt(argc, argv, "asonrvmpi")) != -1) { - switch (option) { - case 'a': - set = UNAME_ALL; - break; - - case 'o': - case 's': - set |= UNAME_KERNEL; - break; - - case 'n': - set |= UNAME_NODE; - break; - - case 'r': - set |= UNAME_RELEASE; - break; - - case 'v': - set |= UNAME_VERSION; - break; - - case 'm': - set |= UNAME_MACHINE; - break; - - case 'p': - if (set != UNAME_ALL) { - set |= UNAME_UNKNOWN; - } - break; - - case 'i': - set |= UNAME_PLATFORM; - break; - - case '?': - default: - badarg = (char)state->optopt; - break; - } - } - - if (argc != optind) { - shell_error(sh, "extra operand %s", argv[optind]); - uname_print_usage(sh); - return -1; - } - - /* If a bad argument was encountered, then return without processing the - * command - */ - - if (badarg != 0) { - shell_error(sh, "uname: illegal option -- %c", badarg); - uname_print_usage(sh); - return -1; - } - - /* If nothing is provided on the command line, the default is -s */ - - if (set == 0) { - set = UNAME_KERNEL; - } - - /* Get uname data */ - - ret = uname(&info); - if (ret < 0) { - shell_error(sh, "cannot get system name"); - return -1; - } - - /* Process each option */ - - /* print the kernel/operating system name */ - if (set & UNAME_KERNEL) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.sysname); - } - - /* Print nodename */ - if (set & UNAME_NODE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.nodename); - } - - /* Print the kernel release */ - if (set & UNAME_RELEASE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.release); - } - - /* Print the kernel version */ - if (set & UNAME_VERSION) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.version); - } - - /* Print the machine hardware name */ - if (set & UNAME_MACHINE) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", info.machine); - } - - /* Print the machine platform name */ - if (set & UNAME_PLATFORM) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", CONFIG_BOARD); - } - - /* Print "unknown" */ - if (set & UNAME_UNKNOWN) { - shell_fprintf(sh, SHELL_NORMAL, "%s ", "unknown"); - } - - shell_fprintf(sh, SHELL_NORMAL, "\n"); + printf("\nPrinting everything in utsname...\n"); + printf("sysname[%zu]: %s\n", sizeof(info.sysname), info.sysname); + printf("nodename[%zu]: %s\n", sizeof(info.nodename), info.nodename); + printf("release[%zu]: %s\n", sizeof(info.release), info.release); + printf("version[%zu]: %s\n", sizeof(info.version), info.version); + printf("machine[%zu]: %s\n", sizeof(info.machine), info.machine); return 0; } - -SHELL_CMD_REGISTER(uname, NULL, NULL, uname_cmd_handler); diff --git a/samples/sensor/bme280/boards/intel_adl_crb.overlay b/samples/sensor/bme280/boards/intel_adl_crb.overlay index 6b24f92e9af..957dd83180a 100644 --- a/samples/sensor/bme280/boards/intel_adl_crb.overlay +++ b/samples/sensor/bme280/boards/intel_adl_crb.overlay @@ -5,9 +5,9 @@ */ &i2c0 { - bme280@76 { - compatible = "bosch,bme280"; - reg = <0x76>; + bme280@76 { + compatible = "bosch,bme280"; + reg = <0x76>; status = "okay"; - }; + }; }; diff --git a/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay b/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay new file mode 100644 index 00000000000..5868d248950 --- /dev/null +++ b/samples/sensor/bme280/boards/intel_rpl_p_crb.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c1 { + bme280@76 { + compatible = "bosch,bme280"; + reg = <0x76>; + status = "okay"; + }; +}; diff --git a/samples/sensor/bme280/rpi_pico_spi_pio.overlay b/samples/sensor/bme280/rpi_pico_spi_pio.overlay index 473cfae2a0b..a555e93213c 100644 --- a/samples/sensor/bme280/rpi_pico_spi_pio.overlay +++ b/samples/sensor/bme280/rpi_pico_spi_pio.overlay @@ -22,7 +22,7 @@ status = "okay"; #address-cells = <1>; #size-cells = <0>; - clocks = < &system_clk >; + clocks = <&clocks RPI_PICO_CLKID_CLK_SYS>; miso-gpios = <&gpio0 12 0>; cs-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; clk-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; diff --git a/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay b/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay new file mode 100644 index 00000000000..aeb8043f621 --- /dev/null +++ b/samples/sensor/die_temp_polling/boards/esp32s3_devkitm.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Application overlay for enabling temperature sensor device instance + */ + +&coretemp { + status = "okay"; +}; diff --git a/samples/sensor/hts221/sample.yaml b/samples/sensor/hts221/sample.yaml index beffa273cfd..472986177a1 100644 --- a/samples/sensor/hts221/sample.yaml +++ b/samples/sensor/hts221/sample.yaml @@ -23,3 +23,5 @@ tests: sample.sensor.hts221.trigger: extra_configs: - CONFIG_HTS221_TRIGGER_OWN_THREAD=y + platform_exclude: + - b_u585i_iot02a diff --git a/samples/sensor/lps22hb/README.rst b/samples/sensor/lps22hb/README.rst index f469f05b6db..4ff98457e50 100644 --- a/samples/sensor/lps22hb/README.rst +++ b/samples/sensor/lps22hb/README.rst @@ -1,6 +1,6 @@ .. _lps22hb: -LPS22HB: Temperature and Humidity Monitor +LPS22HB: Temperature and Pressure Monitor ######################################### Overview diff --git a/samples/sensor/qdec/boards/esp32s3_devkitm.overlay b/samples/sensor/qdec/boards/esp32s3_devkitm.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_devkitm.overlay +++ b/samples/sensor/qdec/boards/esp32s3_devkitm.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay +++ b/samples/sensor/qdec/boards/esp32s3_luatos_core.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay b/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay index d347ea85345..4562dd868bb 100644 --- a/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay +++ b/samples/sensor/qdec/boards/esp32s3_luatos_core_usb.overlay @@ -4,8 +4,6 @@ * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. */ -#include - / { aliases { qdec0 = &pcnt; diff --git a/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay b/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..3d872a2071b --- /dev/null +++ b/samples/sensor/qdec/boards/nrf54l15pdk_nrf54l15_cpuapp.overlay @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + qdec0 = &qdec20; + qenca = &phase_a; + qencb = &phase_b; + }; + + encoder-emulate { + compatible = "gpio-leds"; + phase_a: phase_a { + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + phase_b: phase_b { + gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&pinctrl { + qdec_pinctrl: qdec_pinctrl { + group1 { + psels = , + ; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&qdec20 { + status = "okay"; + pinctrl-0 = <&qdec_pinctrl>; + pinctrl-names = "default"; + steps = <120>; + led-pre = <500>; +}; diff --git a/samples/shields/lmp90100_evb/rtd/app.overlay b/samples/shields/lmp90100_evb/rtd/app.overlay index 7ea69d39c83..27044a27865 100644 --- a/samples/shields/lmp90100_evb/rtd/app.overlay +++ b/samples/shields/lmp90100_evb/rtd/app.overlay @@ -1,9 +1,29 @@ /* - * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright (c) 2019-2024 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 */ +/ { + zephyr,user { + io-channels = <&lmp90100_lmp90100_evb 0>; + }; +}; + &lmp90100_lmp90100_evb { + #address-cells = <1>; + #size-cells = <0>; + rtd-current = <1000>; + + channel@0 { + reg = <0>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_EXTERNAL1"; + zephyr,acquisition-time = ; + zephyr,resolution = <24>; + zephyr,differential; + zephyr,input-positive = <0>; + zephyr,input-negative = <1>; + }; }; diff --git a/samples/shields/lmp90100_evb/rtd/src/main.c b/samples/shields/lmp90100_evb/rtd/src/main.c index 939f2c331ad..040a1d23509 100644 --- a/samples/shields/lmp90100_evb/rtd/src/main.c +++ b/samples/shields/lmp90100_evb/rtd/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Vestas Wind Systems A/S + * Copyright (c) 2019-2024 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,11 +17,8 @@ LOG_MODULE_REGISTER(main); /* Nominal RTD (PT100) resistance in ohms */ #define RTD_NOMINAL_RESISTANCE 100 -/* ADC resolution in bits */ -#define ADC_RESOLUTION 24U - /* ADC maximum value (taking sign bit into consideration) */ -#define ADC_MAX BIT_MASK(ADC_RESOLUTION - 1) +#define ADC_MAX(resolution) BIT_MASK(resolution - 1) /* Bottom resistor value in ohms */ #define BOTTOM_RESISTANCE 2000 @@ -42,46 +39,39 @@ static double rtd_temperature(int nom, double resistance) int main(void) { - const struct device *const lmp90100 = DEVICE_DT_GET_ONE(ti_lmp90100); + const struct adc_dt_spec ch_cfg = ADC_DT_SPEC_GET(DT_PATH(zephyr_user)); + double adc_max = ADC_MAX(ch_cfg.resolution); double resistance; int32_t buffer; int err; - const struct adc_channel_cfg ch_cfg = { - .channel_id = 0, - .differential = 1, - .input_positive = 0, - .input_negative = 1, - .reference = ADC_REF_EXTERNAL1, - .gain = ADC_GAIN_1, - .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, 0) - }; - const struct adc_sequence seq = { - .options = NULL, - .channels = BIT(0), + struct adc_sequence seq = { .buffer = &buffer, .buffer_size = sizeof(buffer), - .resolution = ADC_RESOLUTION, - .oversampling = 0, - .calibrate = 0 }; - if (!device_is_ready(lmp90100)) { + if (!adc_is_ready_dt(&ch_cfg)) { LOG_ERR("LMP90100 device not ready"); return 0; } - err = adc_channel_setup(lmp90100, &ch_cfg); - if (err) { + err = adc_channel_setup_dt(&ch_cfg); + if (err != 0) { LOG_ERR("failed to setup ADC channel (err %d)", err); return 0; } + err = adc_sequence_init_dt(&ch_cfg, &seq); + if (err != 0) { + LOG_ERR("failed to initialize ADC sequence (err %d)", err); + return 0; + } + while (true) { - err = adc_read(lmp90100, &seq); - if (err) { + err = adc_read_dt(&ch_cfg, &seq); + if (err != 0) { LOG_ERR("failed to read ADC (err %d)", err); } else { - resistance = (buffer / (double)ADC_MAX) * BOTTOM_RESISTANCE; + resistance = (buffer / adc_max) * BOTTOM_RESISTANCE; printf("R: %.02f ohm\n", resistance); printf("T: %.02f degC\n", rtd_temperature(RTD_NOMINAL_RESISTANCE, diff --git a/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay b/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay index 339ad015c0c..762a84311fb 100644 --- a/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay +++ b/samples/shields/npm1300_ek/nrf52dk_nrf52832.overlay @@ -9,14 +9,32 @@ }; &npm1300_ek_regulators { - dvs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>, - <&gpio0 18 GPIO_ACTIVE_LOW>; + dvs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>, + <&gpio0 18 GPIO_ACTIVE_LOW>; }; &npm1300_ek_buck1 { regulator-init-microvolt = <2000000>; }; +&npm1300_ek_buck2 { + regulator-init-microvolt = <3300000>; + retention-microvolt = <2500000>; + enable-gpios = <&npm1300_ek_gpio 1 GPIO_ACTIVE_LOW>; + retention-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_HIGH>; + pwm-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + +&npm1300_ek_ldo1 { + regulator-initial-mode = ; + enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + +&npm1300_ek_ldo2 { + regulator-initial-mode = ; + enable-gpios = <&npm1300_ek_gpio 2 GPIO_ACTIVE_LOW>; +}; + &npm1300_ek_pmic { host-int-gpios = <&gpio0 22 0>; pmic-int-pin = <3>; diff --git a/samples/shields/npm1300_ek/prj.conf b/samples/shields/npm1300_ek/prj.conf index c8421d9bf0c..975d56d4e50 100644 --- a/samples/shields/npm1300_ek/prj.conf +++ b/samples/shields/npm1300_ek/prj.conf @@ -4,7 +4,9 @@ CONFIG_SHELL=y CONFIG_LOG=y CONFIG_GPIO=y +CONFIG_GPIO_SHELL=y CONFIG_REGULATOR=y CONFIG_REGULATOR_SHELL=y CONFIG_SENSOR=y +CONFIG_SENSOR_SHELL=y CONFIG_LED=y diff --git a/samples/shields/npm1300_ek/src/main.c b/samples/shields/npm1300_ek/src/main.c index 62e1059cf09..47ed6214677 100644 --- a/samples/shields/npm1300_ek/src/main.c +++ b/samples/shields/npm1300_ek/src/main.c @@ -93,7 +93,8 @@ void read_sensors(void) printk("I: %s%d.%04d ", ((current.val1 < 0) || (current.val2 < 0)) ? "-" : "", abs(current.val1), abs(current.val2) / 100); - printk("T: %d.%02d\n", temp.val1, temp.val2 / 10000); + printk("T: %s%d.%02d\n", ((temp.val1 < 0) || (temp.val2 < 0)) ? "-" : "", abs(temp.val1), + abs(temp.val2) / 10000); printk("Charger Status: %d, Error: %d\n", status.val1, error.val1); } diff --git a/samples/shields/x_nucleo_iks01a3/standard/README.rst b/samples/shields/x_nucleo_iks01a3/standard/README.rst index 03213d0006c..0677fad6c52 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/README.rst +++ b/samples/shields/x_nucleo_iks01a3/standard/README.rst @@ -41,6 +41,17 @@ References - X-NUCLEO-IKS01A3: https://www.st.com/en/ecosystems/x-nucleo-iks01a3.html +DIL24 socket +************ + +In addition to sensors on board it is possible to place any other compatible +sensor on DIL24 socket. The sample is written in such a way that, if sensor is +not present, it will just be skipped. + +List of sensors currently supported on DIL24 by this sample: + +- LIS2DE12 + Building and Running ******************** diff --git a/samples/shields/x_nucleo_iks01a3/standard/app.overlay b/samples/shields/x_nucleo_iks01a3/standard/app.overlay new file mode 100644 index 00000000000..86abf4f60f4 --- /dev/null +++ b/samples/shields/x_nucleo_iks01a3/standard/app.overlay @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Sensors declared here are possibly present on DIL24 + */ +&arduino_i2c { + status = "okay"; + + lis2de18_18_x_nucleo_iks01a3: lis2de12@18 { + compatible = "st,lis2de12"; + reg = <0x18>; + int1-gpios = <&arduino_header 5 GPIO_ACTIVE_HIGH>; /* A5 */ + }; + +}; diff --git a/samples/shields/x_nucleo_iks01a3/standard/prj.conf b/samples/shields/x_nucleo_iks01a3/standard/prj.conf index 8731ee38c54..ae43106404f 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/prj.conf +++ b/samples/shields/x_nucleo_iks01a3/standard/prj.conf @@ -11,3 +11,7 @@ CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y CONFIG_LSM6DSO_ENABLE_TEMP=n CONFIG_LSM6DSO_TRIGGER_OWN_THREAD=y CONFIG_CBPRINTF_FP_SUPPORT=y + +# DIL24 section +CONFIG_LIS2DE12_ENABLE_TEMP=y +CONFIG_LIS2DE12_TRIGGER_NONE=y diff --git a/samples/shields/x_nucleo_iks01a3/standard/src/main.c b/samples/shields/x_nucleo_iks01a3/standard/src/main.c index 7520d74d599..023b7eab76e 100644 --- a/samples/shields/x_nucleo_iks01a3/standard/src/main.c +++ b/samples/shields/x_nucleo_iks01a3/standard/src/main.c @@ -80,6 +80,17 @@ static void lsm6dso_temp_trig_handler(const struct device *dev, } #endif +#ifdef CONFIG_LIS2DE12_TRIGGER +static int lis2de12_trig_cnt; + +static void lis2de12_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2de12_trig_cnt++; +} +#endif + static void lis2mdl_config(const struct device *lis2mdl) { struct sensor_value odr_attr; @@ -237,6 +248,37 @@ static void lsm6dso_config(const struct device *lsm6dso) #endif } +static void lis2de12_config(const struct device *lis2de12) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LIS2DE12 accel/gyro sampling frequency to 100 Hz */ + odr_attr.val1 = 200; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2de12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DE12 accel\n"); + return; + } + + sensor_g_to_ms2(2, &fs_attr); + + if (sensor_attr_set(lis2de12, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set sampling frequency for LIS2DE12 gyro\n"); + return; + } + +#ifdef CONFIG_LIS2DE12_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lis2de12, &trig, lis2de12_trigger_handler); +#endif +} + int main(void) { struct sensor_value temp1, temp2, temp3, hum, press; @@ -247,13 +289,21 @@ int main(void) struct sensor_value accel1[3], accel2[3]; struct sensor_value gyro[3]; struct sensor_value magn[3]; + struct sensor_value lis2de12_xl[3]; +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + struct sensor_value lis2de12_die_temp; +#endif const struct device *const hts221 = DEVICE_DT_GET_ONE(st_hts221); const struct device *const lps22hh = DEVICE_DT_GET_ONE(st_lps22hh); const struct device *const stts751 = DEVICE_DT_GET_ONE(st_stts751); const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); const struct device *const lis2dw12 = DEVICE_DT_GET_ONE(st_lis2dw12); const struct device *const lsm6dso = DEVICE_DT_GET_ONE(st_lsm6dso); + + /* on DIL24 */ + const struct device *const lis2de12 = DEVICE_DT_GET_ANY(st_lis2de12); int cnt = 1; + int lis2de12_on_dil24 = 0; if (!device_is_ready(hts221)) { printk("%s: device not ready.\n", hts221->name); @@ -279,12 +329,20 @@ int main(void) printk("%s: device not ready.\n", lsm6dso->name); return 0; } + if (device_is_ready(lis2de12)) { + lis2de12_on_dil24 = 1; + } else { + printf("Device %s is not ready\n", lis2de12->name); + /* no device on DIL24, skip it */ + } lis2mdl_config(lis2mdl); lps22hh_config(lps22hh); stts751_config(stts751); lis2dw12_config(lis2dw12); lsm6dso_config(lsm6dso); + if (lis2de12_on_dil24) + lis2de12_config(lis2de12); while (1) { /* Get sensor samples */ @@ -323,6 +381,14 @@ int main(void) return 0; } #endif +#ifndef CONFIG_LIS2DE12_TRIGGER + if (lis2de12_on_dil24) { + if (sensor_sample_fetch(lis2de12) < 0) { + printf("LIS2DE12 Sensor sample update error\n"); + return 0; + } + } +#endif /* Get sensor data */ @@ -339,6 +405,12 @@ int main(void) #ifdef CONFIG_LSM6DSO_ENABLE_TEMP sensor_channel_get(lsm6dso, SENSOR_CHAN_DIE_TEMP, &die_temp); #endif + if (lis2de12_on_dil24) { + sensor_channel_get(lis2de12, SENSOR_CHAN_ACCEL_XYZ, lis2de12_xl); +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + sensor_channel_get(lis2de12, SENSOR_CHAN_DIE_TEMP, &lis2de12_die_temp); +#endif + } /* Display sensor data */ @@ -396,6 +468,18 @@ int main(void) printf("LSM6DSO: Temperature: %.1f C\n", sensor_value_to_double(&die_temp)); #endif + if (lis2de12_on_dil24) { + printf("LIS2DE12: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2de12_xl[0]), + sensor_value_to_double(&lis2de12_xl[1]), + sensor_value_to_double(&lis2de12_xl[2])); + +#ifdef CONFIG_LIS2DE12_ENABLE_TEMP + /* temperature */ + printf("LIS2DE12: Temperature: %.1f C\n", + sensor_value_to_double(&lis2de12_die_temp)); +#endif + } #if defined(CONFIG_LIS2MDL_TRIGGER) printk("%d:: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); @@ -419,6 +503,9 @@ int main(void) printk("%d:: lsm6dso temp trig %d\n", cnt, lsm6dso_temp_trig_cnt); #endif +#ifdef CONFIG_LIS2DE12_TRIGGER + printk("%d:: lis2de12 acc trig %d\n", cnt, lis2de12_trig_cnt); +#endif cnt++; k_sleep(K_MSEC(2000)); diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt new file mode 100644 index 00000000000..e901945a062 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1_shub1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst b/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst new file mode 100644 index 00000000000..73296ce36ca --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/README.rst @@ -0,0 +1,60 @@ +.. _x-nucleo-iks4a1-shub1-sample: + +X-NUCLEO-IKS4A1 shield SHUB1 (Mode 3) sample +############################################ + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in SHUB1 (Mode 3). +Please refer to :ref:`x-nucleo-iks4a1-mode-3` for more info on this configuration. + +This sample enables LSM6DSV16X IMU in sensorhub mode with LIS2MDL magnetometer and +LPS22DF pressure and temperature sensor. + +Then sensor data are displayed periodically + +- LSM6DSV16X 6-Axis acceleration and angular velocity +- LSM6DSV16X (from LIS2MDL) 3-Axis magnetic field intensity +- LSM6DSV16X (from LPS22DF) ambient temperature and atmospheric pressure + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/sensorhub1/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS01A4 sensor dashboard + + LSM6DSV16X: Accel (m.s-2): x: 0.081, y: -0.177, z: 9.945 + LSM6DSV16X: GYro (dps): x: 0.001, y: -0.000, z: 0.004 + LSM6DSV16X: Magn (gauss): x: 0.217, y: 0.015, z: -0.415 + LSM6DSV16X: Temperature: 19.8 C + LSM6DSV16X: Pressure:99.655 kpa + 16:: lsm6dso16is acc trig 6432 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf b/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf new file mode 100644 index 00000000000..f7af0f8fe0f --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/prj.conf @@ -0,0 +1,10 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSV16X_SENSORHUB=y +CONFIG_LSM6DSV16X_EXT_LIS2MDL=y +CONFIG_LSM6DSV16X_EXT_LPS22DF=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml b/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml new file mode 100644 index 00000000000..bec5bda73ff --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +tests: + sample.shields.x_nucleo_iks4a1.sensorhub1: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - mimxrt1010_evk + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c b/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c new file mode 100644 index 00000000000..0454a75dd90 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub1/src/main.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +static int lsm6dsv16x_acc_trig_cnt; + +static void lsm6dsv16x_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dsv16x_acc_trig_cnt++; +} +#endif + +static void lsm6dsv16x_config(const struct device *lsm6dsv16x) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LSM6DSV16X accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X gyro\n"); + return; + } + + /* set LSM6DSV16X external magn sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_MAGN_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext magn\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_PRESS, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext pressure\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_HTS221 + odr_attr.val1 = 12; + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_HUMIDITY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X ext humidity\n"); + } +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_acc_trig_handler); +#endif +} + +int main(void) +{ + struct sensor_value lsm6dsv16x_xl[3], lsm6dsv16x_gy[3]; +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + struct sensor_value lsm6dsv16x_temp; +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + struct sensor_value lis2mdl_magn[3]; +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + struct sensor_value lps22df_press; + struct sensor_value lps22df_temp; +#endif + const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); + int cnt = 1; + + if (!device_is_ready(lsm6dsv16x)) { + printk("%s: device not ready.\n", lsm6dsv16x->name); + return 0; + } + + lsm6dsv16x_config(lsm6dsv16x); + + while (1) { + /* Get sensor samples */ +#ifndef CONFIG_LSM6DSV16X_TRIGGER + if (sensor_sample_fetch(lsm6dsv16x) < 0) { + printf("LSM6DSV16X Sensor sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_xl); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gy); +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_DIE_TEMP, &lsm6dsv16x_temp); +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); +#endif +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_PRESS, &lps22df_press); +#endif + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS01A4 sensor dashboard\n\n"); + + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_xl[0]), + sensor_value_to_double(&lsm6dsv16x_xl[1]), + sensor_value_to_double(&lsm6dsv16x_xl[2])); + + printf("LSM6DSV16X: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_gy[0]), + sensor_value_to_double(&lsm6dsv16x_gy[1]), + sensor_value_to_double(&lsm6dsv16x_gy[2])); + +#ifdef CONFIG_LSM6DSV16X_ENABLE_TEMP + /* temperature */ + printf("LSM6DSV16X: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dsv16x_temp)); +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LIS2MDL + printf("LSM6DSV16X: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); +#endif + +#ifdef CONFIG_LSM6DSV16X_EXT_LPS22DF + printf("LSM6DSV16X: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + printf("LSM6DSV16X: Pressure:%.3f kpa\n", + sensor_value_to_double(&lps22df_press)); +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + printk("%d: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt new file mode 100644 index 00000000000..9ad8c2e6b01 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1_shub2) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst b/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst new file mode 100644 index 00000000000..9fc28a45b57 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/README.rst @@ -0,0 +1,60 @@ +.. _x-nucleo-iks4a1-shub2-sample: + +X-NUCLEO-IKS4A1: shield SHUB2 (Mode 2) sample +############################################# + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in Sensor Hub mode (Mode 2). +Please refer to :ref:`x-nucleo-iks4a1-mode-2` for more info on this configuration. + +This sample enables LSM6DSO16IS IMU in sensorhub mode with LIS2MDL magnetometer and +LPS22DF pressure and temperature sensor. + +Then sensor data are displayed periodically + +- LSM6DSO16IS 6-Axis acceleration and angular velocity +- LSM6DSO16IS (from LIS2MDL) 3-Axis magnetic field intensity +- LSM6DSO16IS (from LPS22DF) ambient temperature and atmospheric pressure + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/sensorhub2/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS01A4 sensor dashboard + + LSM6DSO16IS: Accel (m.s-2): x: 0.081, y: -0.177, z: 9.945 + LSM6DSO16IS: GYro (dps): x: 0.001, y: -0.000, z: 0.004 + LSM6DSO16IS: Magn (gauss): x: 0.217, y: 0.015, z: -0.415 + LSM6DSO16IS: Temperature: 20.8 C + LSM6DSO16IS: Pressure:99.756 kpa + 736:: lsm6dso16is acc trig 314944 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf b/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf new file mode 100644 index 00000000000..8637d6b6c1a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/prj.conf @@ -0,0 +1,11 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LSM6DSO16IS_ENABLE_TEMP=n +CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_SENSORHUB=y +CONFIG_LSM6DSO16IS_EXT_LIS2MDL=y +CONFIG_LSM6DSO16IS_EXT_LPS22DF=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml new file mode 100644 index 00000000000..1931d2aaa4a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/sample.yaml @@ -0,0 +1,13 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +tests: + sample.shields.x_nucleo_iks4a1.sensorhub2: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - pan1781_evb + - pan1782_evb + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c b/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c new file mode 100644 index 00000000000..e4351acb360 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/sensorhub2/src/main.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER +static int lsm6dso16is_acc_trig_cnt; + +static void lsm6dso16is_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dso16is_acc_trig_cnt++; +} +#endif + +static void lsm6dso16is_config(const struct device *lsm6dso16is) +{ + struct sensor_value odr_attr, fs_attr; + + /* set LSM6DSO16IS accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS gyro\n"); + return; + } + + /* set LSM6DSO16IS external magn sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_MAGN_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext magn\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_PRESS, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext pressure\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_HTS221 + odr_attr.val1 = 12; + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_HUMIDITY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS ext humidity\n"); + } +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dso16is, &trig, lsm6dso16is_acc_trig_handler); +#endif +} + +int main(void) +{ + struct sensor_value lsm6dso16is_xl[3], lsm6dso16is_gy[3]; +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + struct sensor_value lsm6dso16is_temp; +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + struct sensor_value lis2mdl_magn[3]; +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + struct sensor_value lps22df_press; + struct sensor_value lps22df_temp; +#endif + const struct device *const lsm6dso16is = DEVICE_DT_GET_ONE(st_lsm6dso16is); + int cnt = 1; + + if (!device_is_ready(lsm6dso16is)) { + printk("%s: device not ready.\n", lsm6dso16is->name); + return 0; + } + + lsm6dso16is_config(lsm6dso16is); + + while (1) { + /* Get sensor samples */ +#ifndef CONFIG_LSM6DSO16IS_TRIGGER + if (sensor_sample_fetch(lsm6dso16is) < 0) { + printf("LSM6DSO16IS Sensor sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, lsm6dso16is_xl); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, lsm6dso16is_gy); +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_DIE_TEMP, &lsm6dso16is_temp); +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); +#endif +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_PRESS, &lps22df_press); +#endif + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS01A4 sensor dashboard\n\n"); + + printf("LSM6DSO16IS: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_xl[0]), + sensor_value_to_double(&lsm6dso16is_xl[1]), + sensor_value_to_double(&lsm6dso16is_xl[2])); + + printf("LSM6DSO16IS: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_gy[0]), + sensor_value_to_double(&lsm6dso16is_gy[1]), + sensor_value_to_double(&lsm6dso16is_gy[2])); + +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + /* temperature */ + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dso16is_temp)); +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LIS2MDL + printf("LSM6DSO16IS: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); +#endif + +#ifdef CONFIG_LSM6DSO16IS_EXT_LPS22DF + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lps22df_temp)); + + printf("LSM6DSO16IS: Pressure:%.3f kpa\n", + sensor_value_to_double(&lps22df_press)); +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + printk("%d: lsm6dso16is acc trig %d\n", cnt, lsm6dso16is_acc_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} diff --git a/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt b/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt new file mode 100644 index 00000000000..1e8a99f3f81 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +cmake_minimum_required(VERSION 3.20.0) + +# This sample is specific to x_nucleo_iks4a1 shield. Enforce -DSHIELD option +set(SHIELD x_nucleo_iks4a1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(x_nucleo_iks4a1) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/shields/x_nucleo_iks4a1/standard/README.rst b/samples/shields/x_nucleo_iks4a1/standard/README.rst new file mode 100644 index 00000000000..0dfc2651da7 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/README.rst @@ -0,0 +1,66 @@ +.. _x-nucleo-iks4a1-std-sample: + +X-NUCLEO-IKS4A1 shield Standard (Mode 1) sample +############################################### + +Overview +******** +This sample is provided as an example to test the X-NUCLEO-IKS4A1 shield +configured in Standard mode (Mode 1). +Please refer to :ref:`x-nucleo-iks4a1-mode-1` for more info on this configuration. + +This sample enables the following four sensors of a X-NUCLEO-IKS4A1 shield, and then +periodically reads and displays data from the shield sensors: + +- LSM6DSV16X 6-Axis acceleration and angular velocity +- LSM6DSO16IS 6-Axis acceleration and angular velocity +- LPS22DF ambient temperature and atmospheric pressure +- LIS2MDL 3-Axis magnetic field intensity + +Requirements +************ + +This sample communicates over I2C with the X-NUCLEO-IKS4A1 shield +stacked on a board with an Arduino connector, e.g. the +:ref:`nucleo_f411re_board` board. + +Building and Running +******************** + +This sample runs with X-NUCLEO-IKS4A1 stacked on any board with a matching +Arduino connector. For this example, we use a :ref:`nucleo_f411re_board` board. + +.. zephyr-app-commands:: + :zephyr-app: samples/shields/x_nucleo_iks4a1/standard/ + :host-os: unix + :board: nucleo_f411re + :goals: build flash + :compact: + +Sample Output +============= + + .. code-block:: console + + X-NUCLEO-IKS4A1 sensor dashboard + + LIS2MDL: Magn (gauss): x: -0.364, y: -0.523, z: -0.399 + LIS2MDL: Temperature: 22.4 C + LSM6DSO16IS: Accel (m.s-2): x: -0.167, y: -0.249, z: 9.954 + LSM6DSO16IS: GYro (dps): x: 0.047, y: -0.052, z: -0.042 + LSM6DSO16IS: Temperature: 25.8 C + LSM6DSV16X: Accel (m.s-2): x: 0.005, y: 0.053, z: 9.930 + LSM6DSV16X: GYro (dps): x: -0.000, y: 0.000, z: 0.005 + LPS22DF: Temperature: 25.2 C + LPS22DF: Pressure:98.121 kpa + 10:: lis2mdl trig 1839 + 10:: lsm6dso16is acc trig 3892 + 10:: lsm6dsv16x acc trig 4412 + 10:: lps22df trig 174 + + + +References +********** + +:ref:`x-nucleo-iks4a1` diff --git a/samples/shields/x_nucleo_iks4a1/standard/prj.conf b/samples/shields/x_nucleo_iks4a1/standard/prj.conf new file mode 100644 index 00000000000..2e9e206de76 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/prj.conf @@ -0,0 +1,11 @@ +CONFIG_LOG=y +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SENSOR=y +CONFIG_SENSOR_LOG_LEVEL_DBG=y +CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y +CONFIG_LPS2XDF_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_TRIGGER_OWN_THREAD=y +CONFIG_LSM6DSO16IS_ENABLE_TEMP=y +CONFIG_LSM6DSV16X_TRIGGER_OWN_THREAD=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/shields/x_nucleo_iks4a1/standard/sample.yaml b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml new file mode 100644 index 00000000000..54a66edb45a --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/sample.yaml @@ -0,0 +1,16 @@ +sample: + name: X-NUCLEO-IKS01A4 sensor shield +common: + min_ram: 16 +tests: + sample.shields.x_nucleo_iks4a1.standard: + harness: shield + tags: shield + depends_on: arduino_i2c arduino_gpio + platform_exclude: + - disco_l475_iot1 + - lpcxpresso55s16 + - mimxrt1010_evk + - pan1781_evb + - pan1782_evb + - stm32mp157c_dk2 diff --git a/samples/shields/x_nucleo_iks4a1/standard/src/main.c b/samples/shields/x_nucleo_iks4a1/standard/src/main.c new file mode 100644 index 00000000000..15ac7805452 --- /dev/null +++ b/samples/shields/x_nucleo_iks4a1/standard/src/main.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_LPS2XDF_TRIGGER +static int lps22df_trig_cnt; + +static void lps22df_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lps22df_trig_cnt++; +} +#endif + +#ifdef CONFIG_LIS2MDL_TRIGGER +static int lis2mdl_trig_cnt; + +static void lis2mdl_trigger_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lis2mdl_trig_cnt++; +} +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER +static int lsm6dso16is_acc_trig_cnt; + +static void lsm6dso16is_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dso16is_acc_trig_cnt++; +} +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER +static int lsm6dsv16x_acc_trig_cnt; + +static void lsm6dsv16x_acc_trig_handler(const struct device *dev, + const struct sensor_trigger *trig) +{ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ALL); + lsm6dsv16x_acc_trig_cnt++; +} +#endif + +static void lis2mdl_config(const struct device *lis2mdl) +{ + struct sensor_value odr_attr; + + /* set LIS2MDL sampling frequency to 100 Hz */ + odr_attr.val1 = 100; + odr_attr.val2 = 0; + + if (sensor_attr_set(lis2mdl, SENSOR_CHAN_ALL, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LIS2MDL\n"); + return; + } + +#ifdef CONFIG_LIS2MDL_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_MAGN_XYZ; + sensor_trigger_set(lis2mdl, &trig, lis2mdl_trigger_handler); +#endif +} + +static void lsm6dso16is_config(const struct device *lsm6dso16is) +{ + struct sensor_value odr_attr, fs_attr, mode_attr; + + mode_attr.val1 = 0; /* HP */ + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_CONFIGURATION, &mode_attr) < 0) { + printk("Cannot set mode for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS accel\n"); + return; + } + + /* set LSM6DSO16IS gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSO16IS gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSO16IS gyro\n"); + return; + } + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dso16is, &trig, lsm6dso16is_acc_trig_handler); +#endif +} + +static void lsm6dsv16x_config(const struct device *lsm6dsv16x) +{ + struct sensor_value odr_attr, fs_attr, mode_attr; + + mode_attr.val1 = 0; /* HP */ + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_CONFIGURATION, &mode_attr) < 0) { + printk("Cannot set mode for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X accel sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X accel\n"); + return; + } + + sensor_g_to_ms2(16, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X accel\n"); + return; + } + + /* set LSM6DSV16X gyro sampling frequency to 208 Hz */ + odr_attr.val1 = 208; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LSM6DSV16X gyro\n"); + return; + } + + sensor_degrees_to_rad(250, &fs_attr); + + if (sensor_attr_set(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, + SENSOR_ATTR_FULL_SCALE, &fs_attr) < 0) { + printk("Cannot set full scale for LSM6DSV16X gyro\n"); + return; + } + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + sensor_trigger_set(lsm6dsv16x, &trig, lsm6dsv16x_acc_trig_handler); +#endif +} + +static void lps22df_config(const struct device *lps22df) +{ + struct sensor_value odr_attr; + + /* set LPS22DF accel sampling frequency to 10 Hz */ + odr_attr.val1 = 10; + odr_attr.val2 = 0; + + if (sensor_attr_set(lps22df, SENSOR_CHAN_ALL, + SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) { + printk("Cannot set sampling frequency for LPS22DF accel\n"); + return; + } + +#ifdef CONFIG_LPS2XDF_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ALL; + sensor_trigger_set(lps22df, &trig, lps22df_trigger_handler); +#endif +} + +int main(void) +{ + struct sensor_value lis2mdl_magn[3], lis2mdl_temp, lps22df_press, lps22df_temp; + struct sensor_value lsm6dso16is_xl[3], lsm6dso16is_gy[3]; +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + struct sensor_value lsm6dso16is_temp; +#endif + struct sensor_value lsm6dsv16x_xl[3], lsm6dsv16x_gy[3]; + const struct device *const lis2mdl = DEVICE_DT_GET_ONE(st_lis2mdl); + const struct device *const lsm6dso16is = DEVICE_DT_GET_ONE(st_lsm6dso16is); + const struct device *const lsm6dsv16x = DEVICE_DT_GET_ONE(st_lsm6dsv16x); + const struct device *const lps22df = DEVICE_DT_GET_ONE(st_lps22df); + int cnt = 1; + + if (!device_is_ready(lsm6dso16is)) { + printk("%s: device not ready.\n", lsm6dso16is->name); + return 0; + } + if (!device_is_ready(lsm6dsv16x)) { + printk("%s: device not ready.\n", lsm6dsv16x->name); + return 0; + } + if (!device_is_ready(lis2mdl)) { + printk("%s: device not ready.\n", lis2mdl->name); + return 0; + } + if (!device_is_ready(lps22df)) { + printk("%s: device not ready.\n", lps22df->name); + return 0; + } + + lis2mdl_config(lis2mdl); + lsm6dso16is_config(lsm6dso16is); + lsm6dsv16x_config(lsm6dsv16x); + lps22df_config(lps22df); + + while (1) { + /* Get sensor samples */ + +#ifndef CONFIG_LIS2MDL_TRIGGER + if (sensor_sample_fetch(lis2mdl) < 0) { + printf("LIS2MDL Magn Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LSM6DSO16IS_TRIGGER + if (sensor_sample_fetch(lsm6dso16is) < 0) { + printf("LSM6DSO16IS Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LSM6DSV16X_TRIGGER + if (sensor_sample_fetch(lsm6dsv16x) < 0) { + printf("LSM6DSV16X Sensor sample update error\n"); + return 0; + } +#endif +#ifndef CONFIG_LPS2XDF_TRIGGER + if (sensor_sample_fetch(lps22df) < 0) { + printf("LPS22DF pressure sample update error\n"); + return 0; + } +#endif + + /* Get sensor data */ + sensor_channel_get(lis2mdl, SENSOR_CHAN_MAGN_XYZ, lis2mdl_magn); + sensor_channel_get(lis2mdl, SENSOR_CHAN_DIE_TEMP, &lis2mdl_temp); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_ACCEL_XYZ, lsm6dso16is_xl); + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_GYRO_XYZ, lsm6dso16is_gy); +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + sensor_channel_get(lsm6dso16is, SENSOR_CHAN_DIE_TEMP, &lsm6dso16is_temp); +#endif + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_ACCEL_XYZ, lsm6dsv16x_xl); + sensor_channel_get(lsm6dsv16x, SENSOR_CHAN_GYRO_XYZ, lsm6dsv16x_gy); + + sensor_channel_get(lps22df, SENSOR_CHAN_PRESS, &lps22df_press); + sensor_channel_get(lps22df, SENSOR_CHAN_AMBIENT_TEMP, &lps22df_temp); + + /* Display sensor data */ + + /* Erase previous */ + printf("\0033\014"); + + printf("X-NUCLEO-IKS4A1 sensor dashboard\n\n"); + + /* lis2mdl */ + printf("LIS2MDL: Magn (gauss): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lis2mdl_magn[0]), + sensor_value_to_double(&lis2mdl_magn[1]), + sensor_value_to_double(&lis2mdl_magn[2])); + + printf("LIS2MDL: Temperature: %.1f C\n", + sensor_value_to_double(&lis2mdl_temp)); + + printf("LSM6DSO16IS: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_xl[0]), + sensor_value_to_double(&lsm6dso16is_xl[1]), + sensor_value_to_double(&lsm6dso16is_xl[2])); + + printf("LSM6DSO16IS: Gyro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dso16is_gy[0]), + sensor_value_to_double(&lsm6dso16is_gy[1]), + sensor_value_to_double(&lsm6dso16is_gy[2])); + +#ifdef CONFIG_LSM6DSO16IS_ENABLE_TEMP + /* temperature */ + printf("LSM6DSO16IS: Temperature: %.1f C\n", + sensor_value_to_double(&lsm6dso16is_temp)); +#endif + + printf("LSM6DSV16X: Accel (m.s-2): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_xl[0]), + sensor_value_to_double(&lsm6dsv16x_xl[1]), + sensor_value_to_double(&lsm6dsv16x_xl[2])); + + printf("LSM6DSV16X: GYro (dps): x: %.3f, y: %.3f, z: %.3f\n", + sensor_value_to_double(&lsm6dsv16x_gy[0]), + sensor_value_to_double(&lsm6dsv16x_gy[1]), + sensor_value_to_double(&lsm6dsv16x_gy[2])); + + printf("LPS22DF: Temperature: %.1f C\n", sensor_value_to_double(&lps22df_temp)); + printf("LPS22DF: Pressure:%.3f kpa\n", sensor_value_to_double(&lps22df_press)); + +#if defined(CONFIG_LIS2MDL_TRIGGER) + printk("%d: lis2mdl trig %d\n", cnt, lis2mdl_trig_cnt); +#endif + +#ifdef CONFIG_LSM6DSO16IS_TRIGGER + printk("%d: lsm6dso16is acc trig %d\n", cnt, lsm6dso16is_acc_trig_cnt); +#endif + +#ifdef CONFIG_LSM6DSV16X_TRIGGER + printk("%d: lsm6dsv16x acc trig %d\n", cnt, lsm6dsv16x_acc_trig_cnt); +#endif +#ifdef CONFIG_LPS2XDF_TRIGGER + printk("%d: lps22df trig %d\n", cnt, lps22df_trig_cnt); +#endif + + cnt++; + k_sleep(K_MSEC(2000)); + } +} diff --git a/samples/subsys/console/echo/README.rst b/samples/subsys/console/echo/README.rst new file mode 100644 index 00000000000..b5851f16265 --- /dev/null +++ b/samples/subsys/console/echo/README.rst @@ -0,0 +1,43 @@ +.. zephyr:code-sample:: console_echo + :name: Console echo + :relevant-api: console_api + + Echo an input character back to the output using the Console API. + +Overview +******** + +This example shows how the :c:func:`console_getchar` and +:c:func:`console_putchar` functions can be used to echo an input character +back to the console. + +Requirements +************ + +UART console is required to run this sample. + +Building and Running +******************** + +Build and flash the sample as follows, changing ``nucleo_f401re`` for your +board. Alternatively you can run this using QEMU, as described in +:zephyr:code-sample:`console_getchar`. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/console/echo + :host-os: unix + :board: nucleo_f401re + :goals: build flash + :compact: + +Following the initial prompt given by the firmware, start pressing keys on a +keyboard, and they will be echoed back to the terminal program you are using. + +Sample Output +============= + +.. code-block:: console + + You should see another line with instructions below. If not, + the (interrupt-driven) console device doesn't work as expected: + Start typing characters to see them echoed back diff --git a/samples/subsys/debug/debugmon/src/main.c b/samples/subsys/debug/debugmon/src/main.c index 9029cc44ae7..8c0c8bc3471 100644 --- a/samples/subsys/debug/debugmon/src/main.c +++ b/samples/subsys/debug/debugmon/src/main.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #define LED0_NODE DT_ALIAS(led0) static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); diff --git a/samples/subsys/display/lvgl/README.rst b/samples/subsys/display/lvgl/README.rst index 84bb5fdb40b..be5eecd9db1 100644 --- a/samples/subsys/display/lvgl/README.rst +++ b/samples/subsys/display/lvgl/README.rst @@ -1,17 +1,36 @@ .. zephyr:code-sample:: lvgl :name: LVGL basic sample - :relevant-api: display_interface + :relevant-api: display_interface input_interface - Display "Hello World" and a dynamic counter using LVGL. + Display a "Hello World" and react to user input using LVGL. Overview ******** This sample application displays "Hello World" in the center of the screen -and a counter at the bottom which increments every second. If an input driver -is supported, such as the touch panel controller on mimxrt10{50,60,64}_evk -boards, "Hello World" is enclosed in a button that changes to the toggled state -when touched. +and a counter at the bottom which increments every second. +Based on the available input devices on the board used to run the sample, +additional widgets may be displayed and additional interactions enabled: + +* Pointer + If your board has a touch panel controller + (:dtcompatible:`zephyr,lvgl-pointer-input`), a button widget is displayed + in the center of the screen. Otherwise a label widget is displayed. +* Button + The button pseudo device (:dtcompatible:`zephyr,lvgl-button-input`) maps + a press/release action to a specific coordinate on screen. In the case + of this sample, the coordinates are mapped to the center of the screen. +* Encoder + The encoder pseudo device (:dtcompatible:`zephyr,lvgl-encoder-input`) + can be used to navigate between widgets and edit their values. If the + board contains an encoder, an arc widget is displayed, which can be + edited. +* Keypad + The keypad pseudo device (:dtcompatible:`zephyr,lvgl-keypad-input`) can + be used for focus shifting and also entering characters inside editable + widgets such as text areas. If the board used with this sample has a + keypad device, a button matrix is displayed at the bottom of the screen + to showcase the focus shifting capabilities. Requirements ************ diff --git a/samples/subsys/display/lvgl/boards/native_posix.overlay b/samples/subsys/display/lvgl/boards/native_posix.overlay index 43cc9818d5a..29c03cc0928 100644 --- a/samples/subsys/display/lvgl/boards/native_posix.overlay +++ b/samples/subsys/display/lvgl/boards/native_posix.overlay @@ -5,6 +5,7 @@ */ #include +#include / { aliases { @@ -25,16 +26,31 @@ button0: button0 { /* gpio0 pin 0 is already aliased to led0 */ gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; - zephyr,code = ; + zephyr,code = ; }; button1: button1 { gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; - zephyr,code = ; + zephyr,code = ; }; encoder_button: encoder_button { gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_left: button_left { + gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_right: button_right { + gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + zephyr,code = ; + }; + + button_enter: button_enter { + gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; zephyr,code = ; }; }; @@ -42,24 +58,31 @@ lvgl_button_input { compatible = "zephyr,lvgl-button-input"; input = <&keys>; - input-codes = ; + input-codes = ; coordinates = <160 120>; }; lvgl_encoder_input { compatible = "zephyr,lvgl-encoder-input"; rotation-input-code = ; - button-input-code = ; + button-input-code = ; + }; + + lvgl_keypad_input { + compatible = "zephyr,lvgl-keypad-input"; + input = <&keys>; + input-codes = ; + lvgl-codes = ; }; }; &gpio0 { - ngpios = <6>; + ngpios = <9>; sdl_gpio { status = "okay"; compatible = "zephyr,gpio-emul-sdl"; /* Skip pin 0 with the unknown code 0 */ - scancodes = <0 21 5 30 31 32>; + scancodes = <0 21 5 30 31 32 80 79 40>; }; }; diff --git a/samples/subsys/display/lvgl/boards/wio_terminal.conf b/samples/subsys/display/lvgl/boards/wio_terminal.conf new file mode 100644 index 00000000000..de103d88fed --- /dev/null +++ b/samples/subsys/display/lvgl/boards/wio_terminal.conf @@ -0,0 +1 @@ +CONFIG_INPUT=y diff --git a/samples/subsys/display/lvgl/boards/wio_terminal.overlay b/samples/subsys/display/lvgl/boards/wio_terminal.overlay new file mode 100644 index 00000000000..2f9e228cd82 --- /dev/null +++ b/samples/subsys/display/lvgl/boards/wio_terminal.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Joel Guittet + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + lvgl_button_input { + compatible = "zephyr,lvgl-button-input"; + input = <&buttons>; + input-codes = ; + coordinates = <160 120>; + }; + + lvgl_keypad_input { + compatible = "zephyr,lvgl-keypad-input"; + input = <&joystick>; + input-codes = ; + lvgl-codes = ; + }; +}; diff --git a/samples/subsys/display/lvgl/sample.yaml b/samples/subsys/display/lvgl/sample.yaml index c57ab87122b..3c6e56cdfe1 100644 --- a/samples/subsys/display/lvgl/sample.yaml +++ b/samples/subsys/display/lvgl/sample.yaml @@ -40,3 +40,17 @@ tests: - mimxrt595_evk_cm33 integration_platforms: - mimxrt1170_evk_cm7 + sample.subsys.display.lvgl.st_b_lcd40_dsi1_mb1166: + platform_allow: stm32h747i_disco_m7 + extra_args: SHIELD=st_b_lcd40_dsi1_mb1166 + harness: console + harness_config: + fixture: fixture_display + modules: + - lvgl + tags: + - samples + - display + - shield + - lvgl + - gui diff --git a/samples/subsys/display/lvgl/src/main.c b/samples/subsys/display/lvgl/src/main.c index d58be550278..2fca16023ad 100644 --- a/samples/subsys/display/lvgl/src/main.c +++ b/samples/subsys/display/lvgl/src/main.c @@ -42,6 +42,11 @@ static const struct device *lvgl_encoder = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_encoder_input)); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT +static const struct device *lvgl_keypad = + DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_keypad_input)); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + static void lv_btn_click_callback(lv_event_t *e) { ARG_UNUSED(e); @@ -95,7 +100,7 @@ int main(void) lv_group_t *arc_group; arc = lv_arc_create(lv_scr_act()); - lv_obj_align(arc, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(arc, LV_ALIGN_CENTER, 0, -15); lv_obj_set_size(arc, 150, 150); arc_group = lv_group_create(); @@ -103,13 +108,28 @@ int main(void) lv_indev_set_group(lvgl_input_get_indev(lvgl_encoder), arc_group); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT + lv_obj_t *btn_matrix; + lv_group_t *btn_matrix_group; + static const char *const btnm_map[] = {"1", "2", "3", "4", ""}; + + btn_matrix = lv_btnmatrix_create(lv_scr_act()); + lv_obj_align(btn_matrix, LV_ALIGN_CENTER, 0, 70); + lv_btnmatrix_set_map(btn_matrix, (const char **)btnm_map); + lv_obj_set_size(btn_matrix, 100, 50); + + btn_matrix_group = lv_group_create(); + lv_group_add_obj(btn_matrix_group, btn_matrix); + lv_indev_set_group(lvgl_input_get_indev(lvgl_keypad), btn_matrix_group); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN) || IS_ENABLED(CONFIG_LV_Z_POINTER_INPUT)) { lv_obj_t *hello_world_button; hello_world_button = lv_btn_create(lv_scr_act()); - lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, -15); lv_obj_add_event_cb(hello_world_button, lv_btn_click_callback, LV_EVENT_CLICKED, - NULL); + NULL); hello_world_label = lv_label_create(hello_world_button); } else { hello_world_label = lv_label_create(lv_scr_act()); diff --git a/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay b/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay new file mode 100644 index 00000000000..22d18f5879c --- /dev/null +++ b/samples/subsys/fs/fs_sample/boards/intel_socfpga_agilex5_socdk.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&sdmmc { + status = "okay"; +}; diff --git a/samples/subsys/fs/fs_sample/sample.yaml b/samples/subsys/fs/fs_sample/sample.yaml index 375bacf4f8f..58c0cf62361 100644 --- a/samples/subsys/fs/fs_sample/sample.yaml +++ b/samples/subsys/fs/fs_sample/sample.yaml @@ -43,6 +43,8 @@ tests: integration_platforms: - frdm_k64f sample.filesystem.ext2: + simulation_exclude: + - renode extra_args: CONF_FILE="prj_ext.conf" platform_allow: hifive_unmatched bl5340_dvk_cpuapp sample.filesystem.fat_fs.stm32h747i_disco_m7_sdmmc: diff --git a/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay b/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay index c8baceee06b..b7a8c63fed6 100644 --- a/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay +++ b/samples/subsys/fs/littlefs/boards/nucleo_h743zi.overlay @@ -23,11 +23,10 @@ flash-id = <2>; status = "okay"; - mx25l25645g: qspi-nor-flash@0 { + mx25l25645g: qspi-nor-flash@90000000 { compatible = "st,stm32-qspi-nor"; - reg = <0>; + reg = <0x90000000 DT_SIZE_M(32)>; /* 256 Mbits */ qspi-max-frequency = <50000000>; - size = ; reset-gpios = <&gpiod 3 GPIO_ACTIVE_LOW>; reset-gpios-duration = <1>; spi-bus-width = <4>; diff --git a/samples/subsys/input/input_dump/Kconfig b/samples/subsys/input/input_dump/Kconfig new file mode 100644 index 00000000000..680cafae127 --- /dev/null +++ b/samples/subsys/input/input_dump/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +configdefault INPUT_SHELL + default y + +configdefault INPUT_SHELL_KBD_MATRIX_STATE + default y + +source "Kconfig.zephyr" diff --git a/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay b/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32_devkitc_wroom.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay b/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32_devkitc_wrover.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay b/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32s2_saola.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay b/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay new file mode 100644 index 00000000000..3ed71e8b137 --- /dev/null +++ b/samples/subsys/input/input_dump/boards/esp32s3_devkitm.overlay @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +&touch { + status = "okay"; + + touch_sensor_set: touch_sensor_0 { + channel-num = <9>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_play: touch_sensor_1 { + channel-num = <8>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_inc: touch_sensor_2 { + channel-num = <6>; + channel-sens = <20>; + zephyr,code = ; + }; + + touch_sensor_vol_dec: touch_sensor_3 { + channel-num = <4>; + channel-sens = <20>; + zephyr,code = ; + }; +}; diff --git a/samples/subsys/input/input_dump/sample.yaml b/samples/subsys/input/input_dump/sample.yaml index 1fb4d9d30a9..7015f6026ae 100644 --- a/samples/subsys/input/input_dump/sample.yaml +++ b/samples/subsys/input/input_dump/sample.yaml @@ -1,8 +1,12 @@ sample: name: Input Dump +common: + tags: input + build_only: true + integration_platforms: + - native_sim tests: - sample.input.input_dump: - tags: input - build_only: true - integration_platforms: - - native_sim + sample.input.input_dump: {} + sample.input.input_dump_shell: + extra_configs: + - CONFIG_SHELL=y diff --git a/samples/subsys/ipc/openamp_rsc_table/README.rst b/samples/subsys/ipc/openamp_rsc_table/README.rst index 95eaabfae60..a0d46e3a4bd 100644 --- a/samples/subsys/ipc/openamp_rsc_table/README.rst +++ b/samples/subsys/ipc/openamp_rsc_table/README.rst @@ -18,69 +18,89 @@ a Linux kernel OS on the main processor and a Zephyr application on the co-processor. Building the application -************************* +************************ Zephyr -------- +====== .. zephyr-app-commands:: :zephyr-app: samples/subsys/ipc/openamp_rsc_table :goals: test -Linux ------- - -Enable SAMPLE_RPMSG_CLIENT configuration to build and install -the rpmsg_client_sample.ko module on the target. +Running the client sample +************************* -Running the sample -******************* +Linux setup +=========== -Zephyr console ---------------- +Enable ``SAMPLE_RPMSG_CLIENT`` configuration to build the :file:`rpmsg_client_sample.ko` module. -Open a serial terminal (minicom, putty, etc.) and connect the board with the -following settings: +Zephyr setup +============ -- Speed: 115200 -- Data: 8 bits -- Parity: None -- Stop bits: 1 - -Reset the board. +Open a serial terminal (minicom, putty, etc.) and connect to the board using default serial port settings. Linux console ---------------- +============= -Open a Linux shell (minicom, ssh, etc.) and insert a module into the Linux Kernel +Open a Linux shell (minicom, ssh, etc.) and insert the ``rpmsg_client_sample`` module into the Linux Kernel. +Right after, logs should be displayed to notify channel creation/destruction and incoming message. .. code-block:: console root@linuxshell: insmod rpmsg_client_sample.ko + [ 44.625407] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: new channel: 0x401 -> 0x400! + [ 44.631401] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 1 (src: 0x400) + [ 44.640614] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 2 (src: 0x400) + ... + [ 45.152269] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 99 (src: 0x400) + [ 45.157678] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: incoming msg 100 (src: 0x400) + [ 45.158822] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: goodbye! + [ 45.159741] virtio_rpmsg_bus virtio0: destroying channel rpmsg-client-sample addr 0x400 + [ 45.160856] rpmsg_client_sample virtio0.rpmsg-client-sample.-1.1024: rpmsg sample client driver is removed -Result on Zephyr console on boot --------------------------------- -The following message will appear on the corresponding Zephyr console: +Zephyr console +============== + +For each message received, its content is displayed as shown down below then sent back to Linux. .. code-block:: console - ***** Booting Zephyr OS v#.##.#-####-g########## ***** - Starting application thread! + *** Booting Zephyr OS build zephyr-v#.#.#-####-g########## *** + Starting application threads! + + OpenAMP[remote] Linux responder demo started + + OpenAMP[remote] Linux sample client responder started - OpenAMP demo started - Remote core received message 1: hello world! - Remote core received message 2: hello world! - Remote core received message 3: hello world! + OpenAMP[remote] Linux TTY responder started + [Linux sample client] incoming msg 1: hello world! + [Linux sample client] incoming msg 2: hello world! ... - Remote core received message 100: hello world! - OpenAMP demo ended. + [Linux sample client] incoming msg 99: hello world! + [Linux sample client] incoming msg 100: hello world! + OpenAMP Linux sample client responder ended + + +Running the rpmsg TTY demo +************************** + +Linux setup +=========== +Enable ``RPMSG_TTY`` in the kernel configuration. -rpmsg TTY demo on Linux console -------------------------------- +Zephyr setup +============ -On the Linux console send a message to Zephyr which answers with the "TTY " prefix. +Open a serial terminal (minicom, putty, etc.) and connect to the board using default serial port settings. + +Linux console +============= + +Open a Linux shell (minicom, ssh, etc.) and print the messages coming through the rpmsg-tty endpoint created during the sample initialization. +On the Linux console, send a message to Zephyr which answers with the :samp:`TTY {}:` prefix. corresponds to the Zephyr rpmsg-tty endpoint address: .. code-block:: console @@ -88,3 +108,20 @@ On the Linux console send a message to Zephyr which answers with the "TTY " $> cat /dev/ttyRPMSG0 & $> echo "Hello Zephyr" >/dev/ttyRPMSG0 TTY 0x0401: Hello Zephyr + +Zephyr console +============== + +On the Zephyr console, the received message is displayed as shown below, then sent back to Linux. + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v#.#.#-####-g########## *** + Starting application threads! + + OpenAMP[remote] Linux responder demo started + + OpenAMP[remote] Linux sample client responder started + + OpenAMP[remote] Linux TTY responder started + [Linux TTY] incoming msg: Hello Zephyr diff --git a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c index ebee382cdf8..50c93f3905c 100644 --- a/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c +++ b/samples/subsys/ipc/openamp_rsc_table/src/main_remote.c @@ -291,6 +291,8 @@ void app_rpmsg_client_sample(void *arg1, void *arg2, void *arg3) while (msg_cnt < 100) { k_sem_take(&data_sc_sem, K_FOREVER); msg_cnt++; + printk("[Linux sample client] incoming msg %d: %.*s\n", msg_cnt, sc_msg.len, + (char *)sc_msg.data); rpmsg_send(&sc_ept, sc_msg.data, sc_msg.len); } rpmsg_destroy_ept(&sc_ept); @@ -309,7 +311,7 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) k_sem_take(&data_tty_sem, K_FOREVER); - printk("\r\nOpenAMP[remote] Linux tty responder started\r\n"); + printk("\r\nOpenAMP[remote] Linux TTY responder started\r\n"); tty_ept.priv = &tty_msg; ret = rpmsg_create_ept(&tty_ept, rpdev, "rpmsg-tty", @@ -319,9 +321,10 @@ void app_rpmsg_tty(void *arg1, void *arg2, void *arg3) while (tty_ept.addr != RPMSG_ADDR_ANY) { k_sem_take(&data_tty_sem, K_FOREVER); if (tty_msg.len) { + printk("[Linux TTY] incoming msg: %.*s", tty_msg.len, (char *)tty_msg.data); snprintf(tx_buff, 13, "TTY 0x%04x: ", tty_ept.addr); memcpy(&tx_buff[12], tty_msg.data, tty_msg.len); - rpmsg_send(&tty_ept, tx_buff, tty_msg.len + 13); + rpmsg_send(&tty_ept, tx_buff, tty_msg.len + 12); rpmsg_release_rx_buffer(&tty_ept, tty_msg.data); } tty_msg.len = 0; @@ -342,7 +345,7 @@ void rpmsg_mng_task(void *arg1, void *arg2, void *arg3) unsigned int len; int ret = 0; - printk("\r\nOpenAMP[remote] linux responder demo started\r\n"); + printk("\r\nOpenAMP[remote] Linux responder demo started\r\n"); /* Initialize platform */ ret = platform_init(); diff --git a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt index 7411ab59dae..85356c531de 100644 --- a/samples/subsys/ipc/rpmsg_service/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/CMakeLists.txt @@ -1,61 +1,23 @@ cmake_minimum_required(VERSION 3.20.0) # Copyright (c) 2019 Linaro Limited # Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # -set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/rpmsg_service_remote-prefix/src/rpmsg_service_remote-build/zephyr) - -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp") - set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet") -elseif("${BOARD}" STREQUAL "bl5340_dvk_cpuapp") - set(BOARD_REMOTE "bl5340_dvk_cpunet") -elseif("${BOARD}" STREQUAL "lpcxpresso54114_m4") - set(BOARD_REMOTE "lpcxpresso54114_m0") -elseif("${BOARD}" STREQUAL "mps2_an521") - set(QEMU_EXTRA_FLAGS "-device;loader,file=${REMOTE_ZEPHYR_DIR}/zephyr.elf") - set(BOARD_REMOTE "mps2_an521_remote") -elseif("${BOARD}" STREQUAL "v2m_musca_b1") - set(BOARD_REMOTE "v2m_musca_b1_ns") -elseif("${BOARD}" STREQUAL "esp32_devkitc_wrover") - set(BOARD_REMOTE "esp32_net") -elseif("${BOARD}" STREQUAL "esp32s3_devkitm") - set(BOARD_REMOTE "esp32s3_devkitm_appcpu") -else() - message(FATAL_ERROR "${BOARD} was not supported for this sample") -endif() - -message(STATUS "${BOARD} compile as Master in this sample") +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../rpmsg_service_remote/zephyr) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(rpmsg_service) -enable_language(C ASM) +message(STATUS "${BOARD} compile as Master in this sample") -target_sources(app PRIVATE src/main.c) +enable_language(C ASM) if("${BOARD}" STREQUAL "esp32_devkitc_wrover" OR "${BOARD}" STREQUAL "esp32s3_devkitm") set_source_files_properties(${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c PROPERTIES GENERATED TRUE) target_sources(app PRIVATE src/main.c ${REMOTE_ZEPHYR_DIR}/esp32_net_firmware.c) +else() + target_sources(app PRIVATE src/main.c) endif() - -include(ExternalProject) - -ExternalProject_Add( - rpmsg_service_remote - SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote - INSTALL_COMMAND "" # This particular build system has no install command - CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE} - BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}" - # NB: Do we need to pass on more CMake variables? - BUILD_ALWAYS True -) - -if(("${BOARD}" STREQUAL "lpcxpresso54114_m4")) - add_dependencies(core_m0_inc_target rpmsg_service_remote) -elseif("${BOARD}" STREQUAL "esp32_devkitc_wrover" OR "${BOARD}" STREQUAL "esp32s3_devkitm") - add_dependencies(app rpmsg_service_remote) -endif() - -target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild new file mode 100644 index 00000000000..9dec2087f95 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/Kconfig.sysbuild @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Arm Limited +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config RPMSG_REMOTE_BOARD +string + default "nrf5340dk_nrf5340_cpunet" if $(BOARD) = "nrf5340dk_nrf5340_cpuapp" + default "bl5340_dvk_cpunet" if $(BOARD) = "bl5340_dvk_cpuapp" + default "lpcxpresso54114_m0" if $(BOARD) = "lpcxpresso54114_m4" + default "mps2_an521_remote" if $(BOARD) = "mps2_an521" + default "v2m_musca_b1_ns" if $(BOARD) = "v2m_musca_b1" + default "esp32_devkitc_wroom_appcpu" if $(BOARD) = "esp32_devkitc_wroom" + default "esp32_devkitc_wrover_appcpu" if $(BOARD) = "esp32_devkitc_wrover" + default "esp32s3_devkitm_appcpu" if $(BOARD) = "esp32s3_devkitm" diff --git a/samples/subsys/ipc/rpmsg_service/README.rst b/samples/subsys/ipc/rpmsg_service/README.rst index ce32b16b61e..0c63b8dc3bb 100644 --- a/samples/subsys/ipc/rpmsg_service/README.rst +++ b/samples/subsys/ipc/rpmsg_service/README.rst @@ -11,7 +11,9 @@ RPMsg Service is an abstraction created over OpenAMP that makes initialization and endpoints creation process easier. This application demonstrates how to use RPMsg Service in Zephyr. It is designed to demonstrate how to integrate RPMsg Service with Zephyr both from a build -perspective and code. +perspective and code. Note that the remote and primary image core images can be +flashed independently, but sysbuild must be used in order to flash them in one +step. Building the application for nrf5340dk_nrf5340_cpuapp ***************************************************** diff --git a/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf index 5cb30cb75c0..0bef3d481fd 100644 --- a/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf +++ b/samples/subsys/ipc/rpmsg_service/boards/esp32_devkitc_wrover.conf @@ -1 +1 @@ -CONFIG_ESP32_NETWORK_CORE=y +CONFIG_SOC_ESP32_PROCPU=y diff --git a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt index 76fc92e6307..2545f2e1d71 100644 --- a/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt +++ b/samples/subsys/ipc/rpmsg_service/remote/CMakeLists.txt @@ -1,24 +1,15 @@ cmake_minimum_required(VERSION 3.20.0) # Copyright (c) 2019 Linaro Limited # Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # -if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet" - OR "${BOARD}" STREQUAL "bl5340_dvk_cpunet" - OR "${BOARD}" STREQUAL "lpcxpresso54114_m0" - OR "${BOARD}" STREQUAL "mps2_an521_remote" - OR "${BOARD}" STREQUAL "v2m_musca_b1_ns" - OR "${BOARD}" STREQUAL "esp32_net" - OR "${BOARD}" STREQUAL "esp32s3_devkitm_appcpu") - message(STATUS "${BOARD} compile as slave in this sample") -else() - message(FATAL_ERROR "${BOARD} was not supported for this sample") -endif() - find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(rpmsg_service_remote) +message(STATUS "${BOARD} compile as remote in this sample") + target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) diff --git a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.overlay b/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_devkitc_wrover_appcpu.overlay similarity index 100% rename from samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.overlay rename to samples/subsys/ipc/rpmsg_service/remote/boards/esp32_devkitc_wrover_appcpu.overlay diff --git a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf b/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf deleted file mode 100644 index eee0f29606c..00000000000 --- a/samples/subsys/ipc/rpmsg_service/remote/boards/esp32_net.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_KERNEL_BIN_NAME="esp32_net_firmware" diff --git a/samples/subsys/ipc/rpmsg_service/remote/sample.yaml b/samples/subsys/ipc/rpmsg_service/remote/sample.yaml deleted file mode 100644 index e085ef2f51b..00000000000 --- a/samples/subsys/ipc/rpmsg_service/remote/sample.yaml +++ /dev/null @@ -1,14 +0,0 @@ -sample: - description: This app provides an example of how to integrate RPMsg Service with - Zephyr. - name: RPMsg Service example integration (remote) -common: - harness: remote -tests: - sample.ipc.rpmsg_service.remote: - platform_allow: - - mps2_an521_remote - - v2m_musca_b1_ns - integration_platforms: - - v2m_musca_b1_ns - tags: ipm diff --git a/samples/subsys/ipc/rpmsg_service/sample.yaml b/samples/subsys/ipc/rpmsg_service/sample.yaml deleted file mode 100644 index 84647ea51a4..00000000000 --- a/samples/subsys/ipc/rpmsg_service/sample.yaml +++ /dev/null @@ -1,19 +0,0 @@ -sample: - description: This app provides an example of how to integrate RPMsg Service with - Zephyr. - name: RPMsg Service example integration -tests: - sample.ipc.rpmsg_service: - platform_allow: - - mps2_an521 - - v2m_musca_b1 - integration_platforms: - - mps2_an521 - tags: ipm - harness: console - harness_config: - type: multi_line - regex: - - "Master core received a message: 1" - - "Master core received a message: 99" - - "RPMsg Service demo ended." diff --git a/samples/subsys/ipc/rpmsg_service/sysbuild.cmake b/samples/subsys/ipc/rpmsg_service/sysbuild.cmake new file mode 100644 index 00000000000..08af67aeb85 --- /dev/null +++ b/samples/subsys/ipc/rpmsg_service/sysbuild.cmake @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20.0) +# Copyright (c) 2019 Linaro Limited +# Copyright (c) 2018-2021 Nordic Semiconductor ASA +# Copyright (c) 2023 Arm Limited +# +# SPDX-License-Identifier: Apache-2.0 +# + +ExternalZephyrProject_Add( + APPLICATION rpmsg_service_remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_RPMSG_REMOTE_BOARD} + ) + +add_dependencies(rpmsg_service rpmsg_service_remote) diff --git a/samples/subsys/llext/shell_loader/sample.yaml b/samples/subsys/llext/shell_loader/sample.yaml index acb30def4da..3cf54e45020 100644 --- a/samples/subsys/llext/shell_loader/sample.yaml +++ b/samples/subsys/llext/shell_loader/sample.yaml @@ -1,3 +1,11 @@ +common: + tags: llext + arch_allow: + - arm + - xtensa + filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 + platform_exclude: + - nuvoton_pfm_m487 # See #63167 sample: description: Loadable extensions with shell sample name: Extension loader shell @@ -5,10 +13,5 @@ tests: sample.llext.shell: tags: shell llext harness: keyboard - filter: not CONFIG_CPU_HAS_MMU and not CONFIG_SOC_SERIES_S32ZE_R52 - arch_allow: arm extra_configs: - - CONFIG_ARM_MPU=n - # Broken platforms - platform_exclude: - - nuvoton_pfm_m487 # See #63167 + - arch:arm:CONFIG_ARM_MPU=n diff --git a/samples/subsys/logging/dictionary/README.rst b/samples/subsys/logging/dictionary/README.rst index 2253ff18320..1d54e228664 100644 --- a/samples/subsys/logging/dictionary/README.rst +++ b/samples/subsys/logging/dictionary/README.rst @@ -11,6 +11,13 @@ This is a sample app which utilizes :ref:`dictionary-based logging #include #include +#include -LOG_MODULE_REGISTER(hello_world, 4); +LOG_MODULE_REGISTER(hello_world, LOG_LEVEL_DBG); static const char *hexdump_msg = "HEXDUMP! HEXDUMP@ HEXDUMP#"; @@ -72,3 +73,16 @@ int main(void) #endif return 0; } + +static int rt_demo_cmd(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + LOG_ERR("demo %s", argc > 1 ? argv[1] : ""); + LOG_WRN("demo %s", argc > 1 ? argv[1] : ""); + LOG_INF("demo %s", argc > 1 ? argv[1] : ""); + LOG_DBG("demo %s", argc > 1 ? argv[1] : ""); + + return 0; +} + +SHELL_CMD_REGISTER(log_rt_demo, NULL, "Command can be used to test runtime filtering", rt_demo_cmd); diff --git a/samples/subsys/logging/logger/arm_itm_swo.conf b/samples/subsys/logging/logger/arm_itm_swo.conf new file mode 100644 index 00000000000..0b3d792e707 --- /dev/null +++ b/samples/subsys/logging/logger/arm_itm_swo.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_LOG_BACKEND_SWO=y +CONFIG_LOG_BACKEND_SWO_FREQ_HZ=2000000 diff --git a/samples/subsys/logging/logger/sample.yaml b/samples/subsys/logging/logger/sample.yaml index 2364dabd6b4..8ef962daeb9 100644 --- a/samples/subsys/logging/logger/sample.yaml +++ b/samples/subsys/logging/logger/sample.yaml @@ -32,6 +32,12 @@ tests: sample.logger.usermode: integration_platforms: - mps2_an385 + platform_exclude: + - ip_k66f + - bl652_dvk + - bl654_dvk + - decawave_dwm1001_dev + - segger_trb_stm32f407 arch_exclude: - posix tags: diff --git a/samples/subsys/lorawan/class_a/README.rst b/samples/subsys/lorawan/class_a/README.rst index 3a7a7944997..c29853ae064 100644 --- a/samples/subsys/lorawan/class_a/README.rst +++ b/samples/subsys/lorawan/class_a/README.rst @@ -30,7 +30,8 @@ Extended Configuration ********************** This sample can be configured to run the application-layer clock -synchronization service in the background. +synchronization service and/or the remote multicast setup service +in the background. The following commands build and flash the sample with clock synchronization enabled. @@ -41,3 +42,13 @@ enabled. :goals: build flash :gen-args: -DEXTRA_CONF_FILE=overlay-clock-sync.conf :compact: + +The following commands build and flash the sample with remote multicast setup +enabled. + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/lorawan/class_a + :board: nucleo_wl55jc + :goals: build flash + :gen-args: -DEXTRA_CONF_FILE=overlay-multicast.conf + :compact: diff --git a/samples/subsys/lorawan/class_a/overlay-multicast.conf b/samples/subsys/lorawan/class_a/overlay-multicast.conf new file mode 100644 index 00000000000..6bd51655643 --- /dev/null +++ b/samples/subsys/lorawan/class_a/overlay-multicast.conf @@ -0,0 +1,9 @@ +# NVS required to store LoRaWAN DevNonce and multicast sessions +CONFIG_NVS=y +CONFIG_SETTINGS=y +CONFIG_LORAWAN_NVM_SETTINGS=y + +CONFIG_LORAWAN_SERVICES=y +CONFIG_LORAWAN_SERVICES_LOG_LEVEL_DBG=y +CONFIG_LORAWAN_APP_CLOCK_SYNC=y +CONFIG_LORAWAN_REMOTE_MULTICAST=y diff --git a/samples/subsys/lorawan/class_a/sample.yaml b/samples/subsys/lorawan/class_a/sample.yaml index fb0a3c0de30..7a757da815d 100644 --- a/samples/subsys/lorawan/class_a/sample.yaml +++ b/samples/subsys/lorawan/class_a/sample.yaml @@ -49,3 +49,8 @@ tests: filter: CONFIG_ENTROPY_HAS_DRIVER integration_platforms: - nucleo_wl55jc + sample.lorawan.class_a.multicast: + extra_args: OVERLAY_CONFIG="overlay-multicast.conf" + filter: CONFIG_ENTROPY_HAS_DRIVER + integration_platforms: + - nucleo_wl55jc diff --git a/samples/subsys/mgmt/osdp/README.rst b/samples/subsys/mgmt/osdp/README.rst index 7656d1cd8ab..ac65db5ee57 100644 --- a/samples/subsys/mgmt/osdp/README.rst +++ b/samples/subsys/mgmt/osdp/README.rst @@ -12,7 +12,7 @@ OSDP describes the communication protocol for interfacing one or more Peripheral Devices (PD) to a Control Panel (CP) over a two-wire RS-485 multi-drop serial communication channel. Nevertheless, this protocol can be used to transfer secure data over any stream based physical channel. Read more about `OSDP here -`_.. +`_.. Although OSDP is steered towards the Access and Security industries, it can be used as a general communication protocol for devices in a secure way without diff --git a/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf b/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf new file mode 100644 index 00000000000..a13fc8f12b7 --- /dev/null +++ b/samples/subsys/mgmt/osdp/control_panel/prj_sc.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2020 Siddharth Chandrasekaran +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_GPIO=y + +# OSDP config +CONFIG_OSDP=y +CONFIG_OSDP_MODE_CP=y + +# Secure Channel +CONFIG_ENTROPY_GENERATOR=y +CONFIG_OSDP_SC_ENABLED=y + +CONFIG_OSDP_LOG_LEVEL=4 diff --git a/samples/subsys/mgmt/osdp/control_panel/sample.yaml b/samples/subsys/mgmt/osdp/control_panel/sample.yaml index c9322a4ebd9..5fecf6ad24a 100644 --- a/samples/subsys/mgmt/osdp/control_panel/sample.yaml +++ b/samples/subsys/mgmt/osdp/control_panel/sample.yaml @@ -1,12 +1,18 @@ sample: description: OSDP Control Panel Sample name: osdp +common: + tags: osdp + depends_on: gpio + filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL + harness: osdp + integration_platforms: + - stm32_min_dev_black tests: sample.mgmt.osdp.control_panel: - tags: osdp - depends_on: gpio - filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL - harness: osdp - integration_platforms: - - stm32_min_dev_black + extra_args: CONF_FILE=prj.conf + + sample.mgmt.osdp.control_panel_sc: + build_only: true + extra_args: CONF_FILE=prj_sc.conf diff --git a/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf b/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf new file mode 100644 index 00000000000..cd67c09e7bc --- /dev/null +++ b/samples/subsys/mgmt/osdp/peripheral_device/prj_sc.conf @@ -0,0 +1,19 @@ +# +# Copyright (c) 2020 Siddharth Chandrasekaran +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_GPIO=y + +# OSDP config +CONFIG_OSDP=y +CONFIG_OSDP_MODE_PD=y + +# Secure Channel +CONFIG_ENTROPY_GENERATOR=y +CONFIG_OSDP_SC_ENABLED=y + +CONFIG_OSDP_LOG_LEVEL=4 diff --git a/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml b/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml index ded4397ac41..994ea535e3f 100644 --- a/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml +++ b/samples/subsys/mgmt/osdp/peripheral_device/sample.yaml @@ -1,12 +1,18 @@ sample: description: OSDP Peripheral Device Sample name: osdp +common: + tags: osdp + depends_on: gpio + filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and + dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL + harness: osdp + integration_platforms: + - stm32_min_dev_black tests: sample.mgmt.osdp.peripheral_device: - tags: osdp - depends_on: gpio - filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") and - dt_chosen_enabled("zephyr,osdp-uart") and CONFIG_SERIAL - harness: osdp - integration_platforms: - - stm32_min_dev_black + extra_args: CONF_FILE=prj.conf + + sample.mgmt.osdp.peripheral_device_sc: + build_only: true + extra_args: CONF_FILE=prj_sc.conf diff --git a/samples/subsys/nvs/boards/nucleo_g431rb.overlay b/samples/subsys/nvs/boards/nucleo_g431rb.overlay new file mode 100644 index 00000000000..ee0f1af77ac --- /dev/null +++ b/samples/subsys/nvs/boards/nucleo_g431rb.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &storage_partition; + +&flash0 { + partitions { + /* Set 6KB of storage at the end of 128KB flash */ + storage_partition: partition@1e800 { + label = "storage"; + reg = <0x0001e800 DT_SIZE_K(6)>; + }; + }; +}; diff --git a/samples/subsys/portability/portability.rst b/samples/subsys/portability/portability.rst index b47ee35edc9..9034372320f 100644 --- a/samples/subsys/portability/portability.rst +++ b/samples/subsys/portability/portability.rst @@ -8,3 +8,5 @@ Portability Samples :glob: **/* + +See also :ref:`POSIX API Samples `. diff --git a/samples/subsys/sensing/simple/boards/native_sim.overlay b/samples/subsys/sensing/simple/boards/native_sim.overlay index d11630cd5d9..73a81b81f64 100644 --- a/samples/subsys/sensing/simple/boards/native_sim.overlay +++ b/samples/subsys/sensing/simple/boards/native_sim.overlay @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + &i2c0 { bmi160_i2c: bmi@68 { compatible = "bosch,bmi160"; @@ -24,22 +26,33 @@ compatible = "zephyr,sensing"; status = "okay"; - base_accel: base-accel { + base_accel_gyro: base-accel-gyro { compatible = "zephyr,sensing-phy-3d-sensor"; status = "okay"; - sensor-type = <0x73>; - friendly-name = "Base Accelerometer Sensor"; + sensor-types = ; + friendly-name = "Base Accel Gyro Sensor"; minimal-interval = <625>; underlying-device = <&bmi160_i2c>; }; - lid_accel: lid-accel { + lid_accel_gyro: lid-accel-gyro { compatible = "zephyr,sensing-phy-3d-sensor"; status = "okay"; - sensor-type = <0x73>; - friendly-name = "Lid Accelerometer Sensor"; + sensor-types = ; + friendly-name = "Lid Accel Gyro Sensor"; minimal-interval = <625>; underlying-device = <&bmi160_spi>; }; + + hinge_angle: hinge-angle { + compatible = "zephyr,sensing-hinge-angle"; + status = "okay"; + sensor-types = ; + friendly-name = "Hinge Angle Sensor"; + reporters = <&base_accel_gyro &lid_accel_gyro>; + reporters-index = <0 0>; + minimal-interval = <100000>; + stream-mode; + }; }; }; diff --git a/samples/subsys/sensing/simple/src/main.c b/samples/subsys/sensing/simple/src/main.c index 9a5b6687682..d0749d3b52c 100644 --- a/samples/subsys/sensing/simple/src/main.c +++ b/samples/subsys/sensing/simple/src/main.c @@ -12,11 +12,14 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); -static void acc_data_event_callback(sensing_sensor_handle_t handle, const void *buf) +static void acc_data_event_callback(sensing_sensor_handle_t handle, const void *buf, + void *context) { const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); struct sensing_sensor_value_3d_q31 *sample = (struct sensing_sensor_value_3d_q31 *)buf; + ARG_UNUSED(context); + LOG_INF("%s(%d), handle:%p, Sensor:%s data:(x:%d, y:%d, z:%d)", __func__, __LINE__, handle, info->name, sample->readings[0].x, @@ -24,17 +27,35 @@ static void acc_data_event_callback(sensing_sensor_handle_t handle, const void * sample->readings[0].z); } +static void hinge_angle_data_event_callback(sensing_sensor_handle_t handle, const void *buf, + void *context) +{ + const struct sensing_sensor_info *info = sensing_get_sensor_info(handle); + struct sensing_sensor_value_q31 *sample = (struct sensing_sensor_value_q31 *)buf; + + ARG_UNUSED(context); + + LOG_INF("handle:%p, Sensor:%s data:(v:%d)", handle, info->name, sample->readings[0].v); +} + +static struct sensing_callback_list base_acc_cb_list = { + .on_data_event = &acc_data_event_callback, +}; + +static struct sensing_callback_list hinge_angle_cb_list = { + .on_data_event = &hinge_angle_data_event_callback, +}; + int main(void) { - const struct sensing_callback_list base_acc_cb_list = { - .on_data_event = &acc_data_event_callback, - }; - const struct sensing_callback_list lid_acc_cb_list = { - .on_data_event = &acc_data_event_callback, - }; const struct sensing_sensor_info *info; sensing_sensor_handle_t base_acc; - sensing_sensor_handle_t lid_acc; + sensing_sensor_handle_t hinge_angle; + struct sensing_sensor_config base_acc_config; + struct sensing_sensor_config hinge_angle_config; + const struct sensing_sensor_info *tmp_sensor_info = NULL; + const struct sensing_sensor_info *accle_info = NULL; + const struct sensing_sensor_info *hinge_info = NULL; int ret, i, num = 0; ret = sensing_get_sensors(&num, &info); @@ -49,32 +70,99 @@ int main(void) info[i].name, info[i].friendly_name, info[i].type); + switch (info[i].type) { + case SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D: + accle_info = &info[i]; + break; + case SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE: + hinge_info = &info[i]; + break; + default: + break; + } } LOG_INF("sensing subsystem run successfully"); - ret = sensing_open_sensor(&info[0], &base_acc_cb_list, &base_acc); + ret = sensing_open_sensor(accle_info, &base_acc_cb_list, &base_acc); if (ret) { LOG_ERR("sensing_open_sensor, type:0x%x index:0 error:%d", SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); } - ret = sensing_open_sensor_by_dt(DEVICE_DT_GET(DT_NODELABEL(lid_accel)), - &lid_acc_cb_list, - &lid_acc); + ret = sensing_open_sensor(hinge_info, &hinge_angle_cb_list, + &hinge_angle); if (ret) { - LOG_ERR("sensing_open_sensor, type:0x%x index:1 error:%d", - SENSING_SENSOR_TYPE_MOTION_ACCELEROMETER_3D, ret); + LOG_ERR("sensing_open_sensor_by_type, type:0x%x index:0 error:%d", + SENSING_SENSOR_TYPE_MOTION_HINGE_ANGLE, ret); + } + + /* set base acc, lid acc, hinge sensor interval */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + base_acc_config.interval = 100 * USEC_PER_MSEC; + ret = sensing_set_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_set_interval error:%d\n", ret); } - ret = sensing_close_sensor(&base_acc); + tmp_sensor_info = sensing_get_sensor_info(hinge_angle); + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + hinge_angle_config.interval = tmp_sensor_info->minimal_interval; + ret = sensing_set_config(hinge_angle, &hinge_angle_config, 1); if (ret) { - LOG_ERR("sensing_close_sensor:%p error:%d", base_acc, ret); + LOG_ERR("hinge_angle sensing_set_interval error:%d\n", ret); } - ret = sensing_close_sensor(&lid_acc); + memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); + + /* get base acc, lid acc, hinge sensor interval */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + ret = sensing_get_config(base_acc, &base_acc_config, 1); if (ret) { - LOG_ERR("sensing_close_sensor:%p error:%d", lid_acc, ret); + LOG_ERR("base_acc sensing_get_interval error:%d\n", ret); } + + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_INTERVAL; + ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_get_interval error:%d\n", ret); + } + + /* set base acc, lid acc, hinge sensor sensitivity */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + base_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + base_acc_config.sensitivity = 0; + ret = sensing_set_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_set_sensitivity error:%d\n", ret); + } + + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + hinge_angle_config.sensitivity = 1; + ret = sensing_set_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_set_sensitivity error:%d\n", ret); + } + + memset(&base_acc_config, 0x00, sizeof(struct sensing_sensor_config)); + memset(&hinge_angle_config, 0x00, sizeof(struct sensing_sensor_config)); + + /* get base acc, lid acc, hinge sensor sensitivity */ + base_acc_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + base_acc_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + ret = sensing_get_config(base_acc, &base_acc_config, 1); + if (ret) { + LOG_ERR("base_acc sensing_get_sensitivity error:%d\n", ret); + } + + hinge_angle_config.attri = SENSING_SENSOR_ATTRIBUTE_SENSITIVITY; + hinge_angle_config.data_field = SENSING_SENSITIVITY_INDEX_ALL; + ret = sensing_get_config(hinge_angle, &hinge_angle_config, 1); + if (ret) { + LOG_ERR("hinge_angle sensing_get_sensitivity error:%d\n", ret); + } + return 0; } diff --git a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf index 489e3f9fe16..b96ff81fe83 100644 --- a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.conf @@ -27,3 +27,19 @@ CONFIG_ARM_SIP_SVC_SUBSYS_SINGLY_OPEN=y #SiP SVC Service Shell CONFIG_ARM_SIP_SVC_SUBSYS_SHELL=y + +# Enable File System Shell +CONFIG_FILE_SYSTEM_SHELL=y + +# Enable Disk access +CONFIG_DISK_ACCESS=y + +# File System Setting +CONFIG_FILE_SYSTEM=y +CONFIG_FAT_FILESYSTEM_ELM=y + +# Enable SDMMC +CONFIG_DISK_DRIVER_SDMMC=y + +# Enable SDHC +CONFIG_SDHC=y diff --git a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay index a35c307aeca..c7de2dd4529 100644 --- a/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay +++ b/samples/subsys/shell/shell_module/boards/intel_socfpga_agilex5_socdk.overlay @@ -31,3 +31,7 @@ status = "okay"; zephyr,num-clients = <2>; }; + +&sdmmc { + status = "okay"; +}; diff --git a/samples/subsys/shell/shell_module/prj.conf b/samples/subsys/shell/shell_module/prj.conf index c11e1133d25..41d51f8e22a 100644 --- a/samples/subsys/shell/shell_module/prj.conf +++ b/samples/subsys/shell/shell_module/prj.conf @@ -1,6 +1,7 @@ CONFIG_PRINTK=y CONFIG_SHELL=y CONFIG_LOG=y +CONFIG_LOG_CMDS=y CONFIG_INIT_STACKS=y CONFIG_THREAD_STACK_INFO=y CONFIG_KERNEL_SHELL=y diff --git a/samples/subsys/testsuite/pytest/shell/README.rst b/samples/subsys/testsuite/pytest/shell/README.rst new file mode 100644 index 00000000000..4fb4eea11fc --- /dev/null +++ b/samples/subsys/testsuite/pytest/shell/README.rst @@ -0,0 +1,79 @@ +.. zephyr:code-sample:: pytest_shell + :name: Pytest shell application testing + + Execute pytest tests against the Zephyr shell. + +Overview +******** + +The sample project illustrates usage of pytest framework integrated with +Twister test runner. + +A simple application provides basic Zephyr shell interface. Twister builds it +and then calls pytest in subprocess which runs tests from +``pytest/test_shell.py`` file. The first test verifies valid response for +``help`` command, second one verifies if application is able to return +information about used kernel version. Both tests use ``shell`` fixture, which +is defined in ``pytest-twister-harness`` plugin. More information about plugin +can be found :ref:`here `. + +Requirements +************ + +Board (hardware, ``native_sim`` or ``QEMU``) with UART console. + +Building and Running +******************** + +Build and run sample by Twister: + +.. code-block:: console + + $ ./scripts/twister -vv --platform native_sim -T samples/subsys/testsuite/pytest/shell + + +Sample Output +============= + +.. code-block:: console + + ... + samples/subsys/testsuite/pytest/shell/pytest/test_shell.py::test_shell_print_help + INFO: send "help" command + DEBUG: #: uart:~$ help + DEBUG: #: Please press the button to see all available commands. + DEBUG: #: You can also use the button to prompt or auto-complete all commands or its subcommands. + DEBUG: #: You can try to call commands with <-h> or <--help> parameter for more information. + DEBUG: #: Shell supports following meta-keys: + DEBUG: #: Ctrl + (a key from: abcdefklnpuw) + DEBUG: #: Alt + (a key from: bf) + DEBUG: #: Please refer to shell documentation for more details. + DEBUG: #: Available commands: + DEBUG: #: clear :Clear screen. + DEBUG: #: device :Device commands + DEBUG: #: devmem :Read/write physical memory + DEBUG: #: Usage: + DEBUG: #: Read memory at address with optional width: + DEBUG: #: devmem address [width] + DEBUG: #: Write memory at address with mandatory width and value: + DEBUG: #: devmem address + DEBUG: #: help :Prints the help message. + DEBUG: #: history :Command history. + DEBUG: #: kernel :Kernel commands + DEBUG: #: rem :Ignore lines beginning with 'rem ' + DEBUG: #: resize :Console gets terminal screen size or assumes default in case the + DEBUG: #: readout fails. It must be executed after each terminal width change + DEBUG: #: to ensure correct text display. + DEBUG: #: retval :Print return value of most recent command + DEBUG: #: shell :Useful, not Unix-like shell commands. + DEBUG: #: uart:~$ + INFO: response is valid + PASSED + samples/subsys/testsuite/pytest/shell/pytest/test_shell.py::test_shell_print_version + INFO: send "kernel version" command + DEBUG: #: uart:~$ kernel version + DEBUG: #: Zephyr version 3.5.99 + DEBUG: #: uart:~$ + INFO: response is valid + PASSED + ... diff --git a/samples/subsys/testsuite/testsuite.rst b/samples/subsys/testsuite/testsuite.rst new file mode 100644 index 00000000000..7c84784e9a6 --- /dev/null +++ b/samples/subsys/testsuite/testsuite.rst @@ -0,0 +1,10 @@ +.. _testsuite-samples: + +Testsuite samples +################# + +.. toctree:: + :maxdepth: 1 + :glob: + + **/README diff --git a/samples/subsys/usb/cdc_acm/CMakeLists.txt b/samples/subsys/usb/cdc_acm/CMakeLists.txt index 0cba7b39068..c97b4990766 100644 --- a/samples/subsys/usb/cdc_acm/CMakeLists.txt +++ b/samples/subsys/usb/cdc_acm/CMakeLists.txt @@ -4,5 +4,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(cdc_acm) +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/cdc_acm/Kconfig b/samples/subsys/usb/cdc_acm/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/cdc_acm/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + +source "Kconfig.zephyr" diff --git a/samples/subsys/usb/cdc_acm/src/main.c b/samples/subsys/usb/cdc_acm/src/main.c index 6847ed8d11e..1fa40ace366 100644 --- a/samples/subsys/usb/cdc_acm/src/main.c +++ b/samples/subsys/usb/cdc_acm/src/main.c @@ -12,6 +12,8 @@ * to the serial port. */ +#include + #include #include #include @@ -32,66 +34,19 @@ struct ring_buf ringbuf; static bool rx_throttled; #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD CDC ACM"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0001); +static struct usbd_contex *sample_usbd; static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - LOG_ERR("Failed to initialize language descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - LOG_ERR("Failed to initialize product descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - LOG_ERR("Failed to initialize SN descriptor (%d)", err); - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - LOG_ERR("Failed to add configuration (%d)", err); - return err; - } - - err = usbd_register_class(&sample_usbd, "cdc_acm_0", 1); - if (err) { - LOG_ERR("Failed to register CDC ACM class (%d)", err); - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - LOG_ERR("Failed to initialize device support"); - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { LOG_ERR("Failed to enable device support"); return err; diff --git a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf index 36076b593ad..c5147519f87 100644 --- a/samples/subsys/usb/cdc_acm/usbd_next_prj.conf +++ b/samples/subsys/usb/cdc_acm/usbd_next_prj.conf @@ -8,3 +8,6 @@ CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +CONFIG_SAMPLE_USBD_PID=0x0001 +CONFIG_SAMPLE_USBD_PRODUCT="USBD CDC ACM sample" diff --git a/samples/subsys/usb/common/Kconfig.sample_usbd b/samples/subsys/usb/common/Kconfig.sample_usbd new file mode 100644 index 00000000000..1d330c2ad08 --- /dev/null +++ b/samples/subsys/usb/common/Kconfig.sample_usbd @@ -0,0 +1,48 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# This file contains Kconfig options and defaults for configuring USB devices +# using the new experimental USB device support. The scope of these options is +# limited to USB samples in project tree, you cannot use them in your own +# application. + +menu "USB sample options" + depends on USB_DEVICE_STACK_NEXT + +config SAMPLE_USBD_MANUFACTURER + string "USB device sample manufacturer string" + default "Zephyr Project" + help + USB device sample manufacturer string. + +config SAMPLE_USBD_PRODUCT + string "USB device sample product string" + default "USBD sample" + help + USB device sample product stringa. + +config SAMPLE_USBD_PID + hex "USB device sample Product ID" + default 0x0001 + help + USB device sample Product ID. + +config SAMPLE_USBD_SELF_POWERED + bool "USB device sample Self-powered attribute" + default y + help + Set the Self-powered attribute in the sample configuration. + +config SAMPLE_USBD_REMOTE_WAKEUP + bool "USB device sample Remote Wakeup attribute" + help + Set the Remote Wakeup attribute in the sample configuration. + +config SAMPLE_USBD_MAX_POWER + int "USB device sample bMaxPower value" + default 125 + range 0 250 + help + bMaxPower value in the sample configuration in 2 mA units. + +endmenu diff --git a/samples/subsys/usb/common/common.cmake b/samples/subsys/usb/common/common.cmake new file mode 100644 index 00000000000..08d90a86612 --- /dev/null +++ b/samples/subsys/usb/common/common.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set(SAMPLE_USBD_DIR ${ZEPHYR_BASE}/samples/subsys/usb/common) + +target_include_directories(app PRIVATE ${SAMPLE_USBD_DIR}) +target_sources_ifdef(CONFIG_USB_DEVICE_STACK_NEXT app PRIVATE + ${SAMPLE_USBD_DIR}/sample_usbd_init.c +) diff --git a/samples/subsys/usb/common/sample_usbd.h b/samples/subsys/usb/common/sample_usbd.h new file mode 100644 index 00000000000..95880f02b0a --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H +#define ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H + +#include +#include + +/* + * The scope of this header is limited to use in USB samples together with the + * new experimental USB device stack, you should not use it in your own + * application. However, you can use the code as a template. + */ + +/* + * This function uses Kconfig.sample_usbd options to configure and initialize a + * USB device. It configures sample's device context, default string descriptors, + * USB device configuration, registers any available class instances, and + * finally initializes USB device. It is limited to a single device with a + * single configuration instantiated in sample_usbd_init.c, which should be + * enough for a simple USB device sample. + * + * It returns the configured and initialized USB device context on success, + * otherwise it returns NULL. + */ +struct usbd_contex *sample_usbd_init_device(void); + +#endif /* ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H */ diff --git a/samples/subsys/usb/common/sample_usbd_init.c b/samples/subsys/usb/common/sample_usbd_init.c new file mode 100644 index 00000000000..75809b06d30 --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usbd_sample_config); + +#define ZEPHYR_PROJECT_USB_VID 0x2fe3 + +USBD_DEVICE_DEFINE(sample_usbd, + DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), + ZEPHYR_PROJECT_USB_VID, CONFIG_SAMPLE_USBD_PID); + +USBD_DESC_LANG_DEFINE(sample_lang); +USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, CONFIG_SAMPLE_USBD_MANUFACTURER); +USBD_DESC_PRODUCT_DEFINE(sample_product, CONFIG_SAMPLE_USBD_PRODUCT); +USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); + +static const uint8_t attributes = (IS_ENABLED(CONFIG_SAMPLE_USBD_SELF_POWERED) ? + USB_SCD_SELF_POWERED : 0) | + (IS_ENABLED(CONFIG_SAMPLE_USBD_REMOTE_WAKEUP) ? + USB_SCD_REMOTE_WAKEUP : 0); + +USBD_CONFIGURATION_DEFINE(sample_config, + attributes, + CONFIG_SAMPLE_USBD_MAX_POWER); + +struct usbd_contex *sample_usbd_init_device(void) +{ + int err; + + err = usbd_add_descriptor(&sample_usbd, &sample_lang); + if (err) { + LOG_ERR("Failed to initialize language descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_sn); + if (err) { + LOG_ERR("Failed to initialize SN descriptor (%d)", err); + return NULL; + } + + err = usbd_add_configuration(&sample_usbd, &sample_config); + if (err) { + LOG_ERR("Failed to add configuration (%d)", err); + return NULL; + } + + STRUCT_SECTION_FOREACH(usbd_class_node, node) { + /* Pull everything that is enabled in our configuration. */ + err = usbd_register_class(&sample_usbd, node->name, 1); + if (err) { + LOG_ERR("Failed to register %s (%d)", node->name, err); + return NULL; + } + + LOG_DBG("Register %s", node->name); + } + + /* Always use class code information from Interface Descriptors */ + if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || + IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS) || + IS_ENABLED(CONFIG_USBD_AUDIO2_CLASS)) { + /* + * Class with multiple interfaces have an Interface + * Association Descriptor available, use an appropriate triple + * to indicate it. + */ + usbd_device_set_code_triple(&sample_usbd, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } else { + usbd_device_set_code_triple(&sample_usbd, 0, 0, 0); + } + + err = usbd_init(&sample_usbd); + if (err) { + LOG_ERR("Failed to initialize device support"); + return NULL; + } + + return &sample_usbd; +} diff --git a/samples/subsys/usb/console/CMakeLists.txt b/samples/subsys/usb/console/CMakeLists.txt index cf1601304ab..8ef0ebe2e70 100644 --- a/samples/subsys/usb/console/CMakeLists.txt +++ b/samples/subsys/usb/console/CMakeLists.txt @@ -4,5 +4,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(console) +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/usb/console/Kconfig b/samples/subsys/usb/console/Kconfig new file mode 100644 index 00000000000..96c54558948 --- /dev/null +++ b/samples/subsys/usb/console/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + +source "Kconfig.zephyr" diff --git a/samples/subsys/usb/console/src/main.c b/samples/subsys/usb/console/src/main.c index d0cd78b60dc..6c39cac89a6 100644 --- a/samples/subsys/usb/console/src/main.c +++ b/samples/subsys/usb/console/src/main.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -14,59 +16,18 @@ BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart), "Console device is not ACM CDC UART device"); #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD ACM console"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0001); +static struct usbd_contex *sample_usbd; static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - return err; - } - - err = usbd_register_class(&sample_usbd, "cdc_acm_0", 1); - if (err) { - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { return err; } diff --git a/samples/subsys/usb/console/usbd_next_prj.conf b/samples/subsys/usb/console/usbd_next_prj.conf index 36076b593ad..841bffbf012 100644 --- a/samples/subsys/usb/console/usbd_next_prj.conf +++ b/samples/subsys/usb/console/usbd_next_prj.conf @@ -8,3 +8,6 @@ CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + +CONFIG_SAMPLE_USBD_PID=0x0004 +CONFIG_SAMPLE_USBD_PRODUCT="USBD console sample" diff --git a/samples/subsys/usb/mass/CMakeLists.txt b/samples/subsys/usb/mass/CMakeLists.txt index ef71596104d..3b4d6a7ee64 100644 --- a/samples/subsys/usb/mass/CMakeLists.txt +++ b/samples/subsys/usb/mass/CMakeLists.txt @@ -10,11 +10,12 @@ if((NOT CONFIG_DISK_DRIVER_FLASH) AND message( FATAL_ERROR "No disk access settings detected." ) endif() +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) if(CONFIG_BUILD_WITH_TFM) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/samples/subsys/usb/mass/Kconfig b/samples/subsys/usb/mass/Kconfig index e031a4545db..69cf30f5186 100644 --- a/samples/subsys/usb/mass/Kconfig +++ b/samples/subsys/usb/mass/Kconfig @@ -1,6 +1,8 @@ # Copyright (c) 2019-2020 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 +menu "MSC sample options" + config APP_WIPE_STORAGE bool "Option to clear the flash area before mounting" help @@ -65,4 +67,11 @@ endif # NORDIC_QSPI_NOR endif # DISK_DRIVER_FLASH +endmenu + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + source "Kconfig.zephyr" diff --git a/samples/subsys/usb/mass/src/main.c b/samples/subsys/usb/mass/src/main.c index 0d8d6ba982a..760612279cf 100644 --- a/samples/subsys/usb/mass/src/main.c +++ b/samples/subsys/usb/mass/src/main.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -34,19 +36,7 @@ FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage); static struct fs_mount_t fs_mnt; #if defined(CONFIG_USB_DEVICE_STACK_NEXT) -USBD_CONFIGURATION_DEFINE(config_1, - USB_SCD_SELF_POWERED, - 200); - -USBD_DESC_LANG_DEFINE(sample_lang); -USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, "ZEPHYR"); -USBD_DESC_PRODUCT_DEFINE(sample_product, "Zephyr USBD MSC"); -USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); - - -USBD_DEVICE_DEFINE(sample_usbd, - DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), - 0x2fe3, 0x0008); +static struct usbd_contex *sample_usbd; #if CONFIG_DISK_DRIVER_RAM USBD_DEFINE_MSC_LUN(RAM, "Zephyr", "RAMDisk", "0.00"); @@ -64,49 +54,13 @@ static int enable_usb_device_next(void) { int err; - err = usbd_add_descriptor(&sample_usbd, &sample_lang); - if (err) { - LOG_ERR("Failed to initialize language descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_mfr); - if (err) { - LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_product); - if (err) { - LOG_ERR("Failed to initialize product descriptor (%d)", err); - return err; - } - - err = usbd_add_descriptor(&sample_usbd, &sample_sn); - if (err) { - LOG_ERR("Failed to initialize SN descriptor (%d)", err); - return err; - } - - err = usbd_add_configuration(&sample_usbd, &config_1); - if (err) { - LOG_ERR("Failed to add configuration (%d)", err); - return err; - } - - err = usbd_register_class(&sample_usbd, "msc_0", 1); - if (err) { - LOG_ERR("Failed to register MSC class (%d)", err); - return err; - } - - err = usbd_init(&sample_usbd); - if (err) { - LOG_ERR("Failed to initialize device support"); - return err; + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + LOG_ERR("Failed to initialize USB device"); + return -ENODEV; } - err = usbd_enable(&sample_usbd); + err = usbd_enable(sample_usbd); if (err) { LOG_ERR("Failed to enable device support"); return err; diff --git a/samples/subsys/usb/mass/usbd_next_prj.conf b/samples/subsys/usb/mass/usbd_next_prj.conf index cdf37f75ada..1f7345d25fd 100644 --- a/samples/subsys/usb/mass/usbd_next_prj.conf +++ b/samples/subsys/usb/mass/usbd_next_prj.conf @@ -10,4 +10,6 @@ CONFIG_LOG=y CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +CONFIG_SAMPLE_USBD_PID=0x0008 +CONFIG_SAMPLE_USBD_PRODUCT="USBD MSC sample" CONFIG_MAIN_STACK_SIZE=1536 diff --git a/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay new file mode 100644 index 00000000000..ff51b08078e --- /dev/null +++ b/samples/subsys/usb/shell/nucleo_f413zh_dwc2.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/delete-node/ &zephyr_udc0; + +/ { + soc { + dwc2_fsotg0: usb@50000000 { + compatible = "st,stm32f4-fsotg", "snps,dwc2"; + reg = <0x50000000 0x40000>; + interrupts = <67 0>; + interrupt-names = "fsotg"; + clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00000080>, + <&rcc STM32_SRC_PLL_Q NO_SEL>; + }; + }; +}; + +zephyr_udc0: &dwc2_fsotg0 { + pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt new file mode 100644 index 00000000000..26ce264c421 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(usb_audio_async_i2s) + +include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) +target_sources(app PRIVATE src/main.c) + +if (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP) + target_sources(app PRIVATE src/feedback_nrf53.c) +else() + target_sources(app PRIVATE src/feedback_dummy.c) +endif() diff --git a/samples/subsys/usb/uac2_explicit_feedback/Kconfig b/samples/subsys/usb/uac2_explicit_feedback/Kconfig new file mode 100644 index 00000000000..bee6118a00d --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/Kconfig @@ -0,0 +1,19 @@ +# Copyright (c) 2023-2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +menu "UAC2 external feedback sample options" + +config APP_USE_I2S_LRCLK_EDGES_COUNTER + bool "Measure I2S LRCLK edges directly" + help + Use this to use I2S LRCLK edge counting for calculating feedback. + On nRF53 this option requires externally connecting I2S LRCLK back to + separate GPIOTE input pin (P1.09). +endmenu + +# Source common USB sample options used to initialize new experimental USB +# device stack. The scope of these options is limited to USB samples in project +# tree, you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + +source "Kconfig.zephyr" diff --git a/samples/subsys/usb/uac2_explicit_feedback/README.rst b/samples/subsys/usb/uac2_explicit_feedback/README.rst new file mode 100644 index 00000000000..8d9ff40dc7a --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/README.rst @@ -0,0 +1,64 @@ +.. zephyr:code-sample:: uac2-explicit-feedback + :name: USB Audio asynchronous explicit feedback sample + :relevant-api: _usb_device_core_api i2s_interface + + USB Audio 2 explicit feedback sample playing audio on I2S. + +Overview +******** + +This sample demonstrates how to implement USB asynchronous audio playback with +explicit feedback. It can run on any board with USB and I2S support, but the +feedback calculation is currently only implemented for the Nordic nRF5340 IC. + +The device running this sample presents itself to the host as a Full-Speed +Asynchronous USB Audio 2 class device supporting 48 kHz 16-bit 2-channel +(stereo) playback. + +Explicit Feedback +***************** + +Asynchronous USB Audio is used when the actual sample clock is not controlled by +USB host. Because the sample clock is independent from USB SOF it is inevitable +that 1 ms according to audio sink (I2S) will be either slightly longer or +shorter than 1 ms according to audio source (USB host). In the long run, this +discrepancy leads to overruns or underruns. By providing explicit feedback to +host, the device can tell host how many samples on average it needs every frame. +The host achieves the average by sending either nominal or nominal ±1 sample +packets every frame. + +The dummy feedback implementation, used when there is no target-specific +feedback code available, returns a feedback value that results in host sending +nominal number of samples every frame. Theoretically it should be possible to +obtain the timing information based on I2S and USB interrupts, but currently +neither subsystem provides the necessary timestamp information. + +Explcit Feedback on nRF5340 +*************************** + +The nRF5340 is capable of counting both edges of I2S LRCLK relative to USB SOF +with the use of DPPI, TIMER and GPIOTE input. Alternatively, if the GPIOTE input +is not available, the DPPI and TIMER peripherals on nRF5340 can be configured to +provide relative timing information between I2S FRAMESTART and USB SOF. + +This sample in both modes (direct sample counting and indirect I2S buffer output +to USB SOF offset) has been tested on :ref:`nrf5340dk_nrf5340`. + +The sample defaults to indirect feedback calculation because direct sample +counting requires external connection between I2S LRCLK output pin to GPIOTE +input pin (hardcoded to P1.09) on :ref:`nrf5340dk_nrf5340`. In the indirect mode +no extra connections are necessary and the sample can even be used without any +I2S device connected where I2S signals can be checked e.g. on logic analyzer. + +Building and Running +******************** + +The code can be found in :zephyr_file:`samples/subsys/usb/uac2_explicit_feedback`. + +To build and flash the application: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/usb/uac2_explicit_feedback + :board: nrf5340dk_nrf5340_cpuapp + :goals: build flash + :compact: diff --git a/samples/subsys/usb/uac2_explicit_feedback/app.overlay b/samples/subsys/usb/uac2_explicit_feedback/app.overlay new file mode 100644 index 00000000000..08044d529f5 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/app.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + uac2_headphones: usb_audio2 { + compatible = "zephyr,uac2"; + status = "okay"; + audio-function = ; + + uac_aclk: aclk { + compatible = "zephyr,uac2-clock-source"; + clock-type = "internal-programmable"; + frequency-control = "host-programmable"; + sampling-frequencies = <48000>; + }; + + out_terminal: out_terminal { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + front-left; + front-right; + }; + + headphones_output: headphones { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&out_terminal>; + clock-source = <&uac_aclk>; + terminal-type = ; + }; + + as_iso_out: out_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&out_terminal>; + subslot-size = <2>; + bit-resolution = <16>; + }; + }; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..ce67033381a --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,2 @@ +#Enable timer for asynchronous feedback +CONFIG_NRFX_TIMER2=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..47205e2ed61 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" + +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + psels = , + , + ; + }; + }; +}; + +&clock { + hfclkaudio-frequency = <12288000>; +}; + +i2s_tx: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; + clock-source = "ACLK"; +}; diff --git a/samples/subsys/usb/uac2_explicit_feedback/prj.conf b/samples/subsys/usb/uac2_explicit_feedback/prj.conf new file mode 100644 index 00000000000..3979a5190e6 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/prj.conf @@ -0,0 +1,12 @@ +CONFIG_I2S=y + +#USB related configs +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_AUDIO2_CLASS=y +CONFIG_SAMPLE_USBD_PID=0x000E +CONFIG_SAMPLE_USBD_PRODUCT="UAC2 explicit feedback sample" + +#LOG subsystem related configs +CONFIG_LOG=y +CONFIG_USBD_LOG_LEVEL_WRN=y +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y diff --git a/samples/subsys/usb/uac2_explicit_feedback/sample.yaml b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml new file mode 100644 index 00000000000..7fa75c76127 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/sample.yaml @@ -0,0 +1,6 @@ +sample: + name: USB Audio 2 asynchronous explicit feedback sample +tests: + sample.subsys.usb.uac2_explicit_feedback: + tags: usb i2s + platform_allow: nrf5340dk_nrf5340_cpuapp diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h new file mode 100644 index 00000000000..7f5bf2027d8 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef FEEDBACK_H_ +#define FEEDBACK_H_ + +#include + +/* Nominal number of samples received on each SOF. This sample is currently + * supporting only 48 kHz sample rate. + */ +#define SAMPLES_PER_SOF 48 + +struct feedback_ctx *feedback_init(void); +void feedback_reset_ctx(struct feedback_ctx *ctx); +void feedback_process(struct feedback_ctx *ctx); +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued); +uint32_t feedback_value(struct feedback_ctx *ctx); + +#endif /* FEEDBACK_H_ */ diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c new file mode 100644 index 00000000000..7e274ca2ed0 --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_dummy.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "feedback.h" + +#warning "No target specific feedback code, overruns/underruns will occur" + +#define FEEDBACK_K 10 + +struct feedback_ctx *feedback_init(void) +{ + return NULL; +} + +void feedback_process(struct feedback_ctx *ctx) +{ + ARG_UNUSED(ctx); +} + +void feedback_reset_ctx(struct feedback_ctx *ctx) +{ + ARG_UNUSED(ctx); +} + +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +{ + ARG_UNUSED(ctx); + ARG_UNUSED(i2s_blocks_queued); +} + +uint32_t feedback_value(struct feedback_ctx *ctx) +{ + /* Always request nominal number of samples */ + return SAMPLES_PER_SOF << FEEDBACK_K; +} diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c new file mode 100644 index 00000000000..e5f93a846fd --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/feedback_nrf53.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "feedback.h" + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(feedback, LOG_LEVEL_INF); + +static const nrfx_gpiote_t gpiote = NRFX_GPIOTE_INSTANCE(0); + +#define FEEDBACK_PIN NRF_GPIO_PIN_MAP(1, 9) +#define FEEDBACK_TIMER_INSTANCE_NUMBER 2 +#define FEEDBACK_TIMER_USBD_SOF_CAPTURE 0 +#define FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE 1 + +static const nrfx_timer_t feedback_timer_instance = + NRFX_TIMER_INSTANCE(FEEDBACK_TIMER_INSTANCE_NUMBER); + +/* See 5.12.4.2 Feedback in Universal Serial Bus Specification Revision 2.0 for + * more information about the feedback. There is a direct implementation of the + * specification where P=1 when @kconfig{CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER} + * is enabled, because I2S LRCLK edges (and not the clock) are being counted by + * a timer. Otherwise, when @kconfig{CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER} is + * disabled, we are faking P=5 value using indirect offset measurements and + * we use such estimate on PI controller updated on every SOF. + * + * While it might be possible to determine I2S FRAMESTART to USB SOF offset + * entirely in software, the I2S API lacks appropriate timestamping. Therefore + * this sample uses target-specific code to perform the measurements. Note that + * the use of dedicated target-specific peripheral essentially eliminates + * software scheduling jitter and it is likely that a pure software only + * solution would require additional filtering in indirect offset measurements. + * + * Full-Speed isochronous feedback is Q10.10 unsigned integer left-justified in + * the 24-bits so it has Q10.14 format. This sample application puts zeroes to + * the 4 least significant bits (does not use the bits for extra precision). + */ +#define FEEDBACK_K 10 +#if IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER) +#define FEEDBACK_P 1 +#else +#define FEEDBACK_P 5 +#endif + +#define FEEDBACK_FS_SHIFT 4 + +static struct feedback_ctx { + uint32_t fb_value; + int32_t rel_sof_offset; + int32_t base_sof_offset; + union { + /* For edge counting */ + struct { + uint32_t fb_counter; + uint16_t fb_periods; + }; + /* For PI controller */ + int32_t integrator; + }; +} fb_ctx; + +static nrfx_err_t feedback_edge_counter_setup(void) +{ + nrfx_err_t err; + uint8_t feedback_gpiote_channel; + uint8_t feedback_gppi_channel; + nrfx_gpiote_trigger_config_t trigger_config = { + .trigger = NRFX_GPIOTE_TRIGGER_TOGGLE, + .p_in_channel = &feedback_gpiote_channel, + }; + nrfx_gpiote_input_pin_config_t input_pin_config = { + .p_trigger_config = &trigger_config, + }; + + /* App core is using feedback pin */ + nrf_gpio_pin_control_select(FEEDBACK_PIN, NRF_GPIO_PIN_SEL_APP); + + err = nrfx_gpiote_channel_alloc(&gpiote, &feedback_gpiote_channel); + if (err != NRFX_SUCCESS) { + return err; + } + + nrfx_gpiote_input_configure(&gpiote, FEEDBACK_PIN, &input_pin_config); + nrfx_gpiote_trigger_enable(&gpiote, FEEDBACK_PIN, false); + + /* Configure TIMER in COUNTER mode */ + const nrfx_timer_config_t cfg = { + .frequency = NRFX_MHZ_TO_HZ(1UL), + .mode = NRF_TIMER_MODE_COUNTER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + .p_context = NULL, + }; + + err = nrfx_timer_init(&feedback_timer_instance, &cfg, NULL); + if (err != NRFX_SUCCESS) { + LOG_ERR("nrfx timer init error (sample clk feedback) - Return value: %d", err); + return err; + } + + /* Subscribe TIMER COUNT task to GPIOTE IN event */ + err = nrfx_gppi_channel_alloc(&feedback_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return err; + } + + nrfx_gppi_channel_endpoints_setup(feedback_gppi_channel, + nrfx_gpiote_in_event_address_get(&gpiote, FEEDBACK_PIN), + nrfx_timer_task_address_get(&feedback_timer_instance, NRF_TIMER_TASK_COUNT)); + + nrfx_gppi_channels_enable(BIT(feedback_gppi_channel)); + + return NRFX_SUCCESS; +} + +static nrfx_err_t feedback_relative_timer_setup(void) +{ + nrfx_err_t err; + const nrfx_timer_config_t cfg = { + .frequency = NRFX_MHZ_TO_HZ(16UL), + .mode = NRF_TIMER_MODE_TIMER, + .bit_width = NRF_TIMER_BIT_WIDTH_32, + .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, + .p_context = NULL, + }; + + err = nrfx_timer_init(&feedback_timer_instance, &cfg, NULL); + if (err != NRFX_SUCCESS) { + LOG_ERR("nrfx timer init error (relative timer) - Return value: %d", err); + } + + return err; +} + +struct feedback_ctx *feedback_init(void) +{ + nrfx_err_t err; + uint8_t usbd_sof_gppi_channel; + uint8_t i2s_framestart_gppi_channel; + + feedback_reset_ctx(&fb_ctx); + + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + err = feedback_edge_counter_setup(); + } else { + err = feedback_relative_timer_setup(); + } + + if (err != NRFX_SUCCESS) { + return &fb_ctx; + } + + /* Subscribe TIMER CAPTURE task to USBD SOF event */ + err = nrfx_gppi_channel_alloc(&usbd_sof_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return &fb_ctx; + } + + nrfx_gppi_channel_endpoints_setup(usbd_sof_gppi_channel, + nrf_usbd_event_address_get(NRF_USBD, NRF_USBD_EVENT_SOF), + nrfx_timer_capture_task_address_get(&feedback_timer_instance, + FEEDBACK_TIMER_USBD_SOF_CAPTURE)); + nrfx_gppi_fork_endpoint_setup(usbd_sof_gppi_channel, + nrfx_timer_task_address_get(&feedback_timer_instance, + NRF_TIMER_TASK_CLEAR)); + + nrfx_gppi_channels_enable(BIT(usbd_sof_gppi_channel)); + + /* Subscribe TIMER CAPTURE task to I2S FRAMESTART event */ + err = nrfx_gppi_channel_alloc(&i2s_framestart_gppi_channel); + if (err != NRFX_SUCCESS) { + LOG_ERR("gppi_channel_alloc failed with: %d\n", err); + return &fb_ctx; + } + + nrfx_gppi_channel_endpoints_setup(i2s_framestart_gppi_channel, + nrf_i2s_event_address_get(NRF_I2S0, NRF_I2S_EVENT_FRAMESTART), + nrfx_timer_capture_task_address_get(&feedback_timer_instance, + FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE)); + + nrfx_gppi_channels_enable(BIT(i2s_framestart_gppi_channel)); + + /* Enable feedback timer */ + nrfx_timer_enable(&feedback_timer_instance); + + return &fb_ctx; +} + +static void update_sof_offset(struct feedback_ctx *ctx, uint32_t sof_cc, + uint32_t framestart_cc) +{ + int sof_offset; + + if (!IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + uint32_t clks_per_edge; + + /* Convert timer clock (independent from both Audio clock and + * USB host SOF clock) to fake sample clock shifted by P values. + * This works fine because the regulator cares only about error + * (SOF offset is both error and regulator input) and achieves + * its goal by adjusting feedback value. SOF offset is around 0 + * when regulated and therefore the relative clock frequency + * discrepancies are essentially negligible. + */ + clks_per_edge = sof_cc / (SAMPLES_PER_SOF << FEEDBACK_P); + sof_cc /= MAX(clks_per_edge, 1); + framestart_cc /= MAX(clks_per_edge, 1); + } + + /* /2 because we treat the middle as a turning point from being + * "too late" to "too early". + */ + if (framestart_cc > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { + sof_offset = framestart_cc - (SAMPLES_PER_SOF << FEEDBACK_P); + } else { + sof_offset = framestart_cc; + } + + /* The heuristic above is not enough when the offset gets too large. + * If the sign of the simple heuristic changes, check whether the offset + * crossed through the zero or the outer bound. + */ + if ((ctx->rel_sof_offset >= 0) != (sof_offset >= 0)) { + uint32_t abs_diff; + int32_t base_change; + + if (sof_offset >= 0) { + abs_diff = sof_offset - ctx->rel_sof_offset; + base_change = -(SAMPLES_PER_SOF << FEEDBACK_P); + } else { + abs_diff = ctx->rel_sof_offset - sof_offset; + base_change = SAMPLES_PER_SOF << FEEDBACK_P; + } + + /* Adjust base offset only if the change happened through the + * outer bound. The actual changes should be significantly lower + * than the threshold here. + */ + if (abs_diff > (SAMPLES_PER_SOF << FEEDBACK_P)/2) { + ctx->base_sof_offset += base_change; + } + } + + ctx->rel_sof_offset = sof_offset; +} + +static inline int32_t offset_to_correction(int32_t offset) +{ + return -(offset / BIT(FEEDBACK_P)) * BIT(FEEDBACK_FS_SHIFT); +} + +static int32_t pi_update(struct feedback_ctx *ctx) +{ + int32_t sof_offset = ctx->rel_sof_offset + ctx->base_sof_offset; + /* SOF offset is measured in pow(2, -FEEDBACK_P) samples, i.e. when + * FEEDBACK_P is 0, offset is in samples, and for 1 -> half-samples, + * 2 -> quarter-samples, 3 -> eightth-samples and so on. + * In order to simplify the PI controller description here, normalize + * the offset to 1/1024 samples (alternatively it can be treated as + * samples in Q10 fixed point format) and use it as Process Variable. + */ + int32_t PV = BIT(10 - FEEDBACK_P) * sof_offset; + /* The control goal is to keep I2S FRAMESTART as close as possible to + * USB SOF and therefore Set Point is 0. + */ + int32_t SP = 0; + int32_t error = SP - PV; + + /* + * With above normalization at Full-Speed, when data received during + * SOF n appears on I2S during SOF n+3, the Ziegler Nichols Ultimate + * Gain is around 1.15 and the oscillation period is around 90 SOF. + * (much nicer oscillations with 204.8 SOF period can be observed with + * gain 0.5 when the delay is not n+3, but n+33 - surprisingly the + * resulting PI coefficients after power of two rounding are the same). + * + * Ziegler-Nichols rule with applied stability margin of 2 results in: + * Kc = 0.22 * Ku = 0.22 * 1.15 = 0.253 + * Ti = 0.83 * tu = 0.83 * 80 = 66.4 + * + * Converting the rules above to parallel PI gives: + * Kp = Kc = 0.253 + * Ki = Kc/Ti = 0.254/66.4 ~= 0.0038253 + * + * Because we want fixed-point optimized non-tunable implementation, + * the parameters can be conveniently expressed with power of two: + * Kp ~= pow(2, -2) = 0.25 (divide by 4) + * Ki ~= pow(2, -8) = 0.0039 (divide by 256) + * + * This can be implemented as: + * ctx->integrator += error; + * return (error + (ctx->integrator / 64)) / 4; + * but unfortunately such regulator is pretty aggressive and keeps + * oscillating rather quickly around the setpoint (within +-1 sample). + * + * Manually tweaking the constants so the regulator output is shifted + * down by 4 bits (i.e. change /64 to /2048 and /4 to /128) yields + * really good results (the outcome is similar, even slightly better, + * than using I2S LRCLK edge counting directly). + */ + ctx->integrator += error; + return (error + (ctx->integrator / 2048)) / 128; +} + +void feedback_process(struct feedback_ctx *ctx) +{ + uint32_t sof_cc; + uint32_t framestart_cc; + uint32_t fb; + + sof_cc = nrfx_timer_capture_get(&feedback_timer_instance, + FEEDBACK_TIMER_USBD_SOF_CAPTURE); + framestart_cc = nrfx_timer_capture_get(&feedback_timer_instance, + FEEDBACK_TIMER_I2S_FRAMESTART_CAPTURE); + + update_sof_offset(ctx, sof_cc, framestart_cc); + + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + int32_t offset = ctx->rel_sof_offset + ctx->base_sof_offset; + + ctx->fb_counter += sof_cc; + ctx->fb_periods++; + + if (ctx->fb_periods == BIT(FEEDBACK_K - FEEDBACK_P)) { + + /* fb_counter holds Q10.10 value, left-justify it */ + fb = ctx->fb_counter << FEEDBACK_FS_SHIFT; + + /* Align I2S FRAMESTART to USB SOF by adjusting reported + * feedback value. This is endpoint specific correction + * mentioned but not specified in USB 2.0 Specification. + */ + if (abs(offset) > BIT(FEEDBACK_P)) { + fb += offset_to_correction(offset); + } + + ctx->fb_value = fb; + ctx->fb_counter = 0; + ctx->fb_periods = 0; + } + } else { + /* Use PI controller to generate required feedback deviation + * from nominal feedback value. + */ + fb = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + /* Clear the additional LSB bits in feedback value, i.e. do not + * use the optional extra resolution. + */ + fb += pi_update(ctx) & ~0xF; + ctx->fb_value = fb; + } +} + +void feedback_reset_ctx(struct feedback_ctx *ctx) +{ + /* Reset feedback to nominal value */ + ctx->fb_value = SAMPLES_PER_SOF << (FEEDBACK_K + FEEDBACK_FS_SHIFT); + if (IS_ENABLED(CONFIG_APP_USE_I2S_LRCLK_EDGES_COUNTER)) { + ctx->fb_counter = 0; + ctx->fb_periods = 0; + } else { + ctx->integrator = 0; + } +} + +void feedback_start(struct feedback_ctx *ctx, int i2s_blocks_queued) +{ + /* I2S data was supposed to go out at SOF, but it is inevitably + * delayed due to triggering I2S start by software. Set relative + * SOF offset value in a way that ensures that values past "half + * frame" are treated as "too late" instead of "too early" + */ + ctx->rel_sof_offset = (SAMPLES_PER_SOF << FEEDBACK_P) / 2; + /* If there are more than 2 I2S blocks queued, use feedback regulator + * to correct the situation. + */ + ctx->base_sof_offset = (i2s_blocks_queued - 2) * + (SAMPLES_PER_SOF << FEEDBACK_P); +} + +uint32_t feedback_value(struct feedback_ctx *ctx) +{ + return ctx->fb_value; +} diff --git a/samples/subsys/usb/uac2_explicit_feedback/src/main.c b/samples/subsys/usb/uac2_explicit_feedback/src/main.c new file mode 100644 index 00000000000..69dc731833d --- /dev/null +++ b/samples/subsys/usb/uac2_explicit_feedback/src/main.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023-2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include "feedback.h" + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(uac2_sample, LOG_LEVEL_INF); + +#define HEADPHONES_OUT_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(out_terminal)) + +#define SAMPLE_FREQUENCY (SAMPLES_PER_SOF * 1000) +#define SAMPLE_BIT_WIDTH 16 +#define NUMBER_OF_CHANNELS 2 +#define BYTES_PER_SAMPLE DIV_ROUND_UP(SAMPLE_BIT_WIDTH, 8) +#define BYTES_PER_SLOT (BYTES_PER_SAMPLE * NUMBER_OF_CHANNELS) +#define MIN_BLOCK_SIZE ((SAMPLES_PER_SOF - 1) * BYTES_PER_SLOT) +#define BLOCK_SIZE (SAMPLES_PER_SOF * BYTES_PER_SLOT) +#define MAX_BLOCK_SIZE ((SAMPLES_PER_SOF + 1) * BYTES_PER_SLOT) + +/* Absolute minimum is 5 buffers (1 actively consumed by I2S, 2nd queued as next + * buffer, 3rd acquired by USB stack to receive data to, and 2 to handle SOF/I2S + * offset errors), but add 2 additional buffers to prevent out of memory errors + * when USB host decides to perform rapid terminal enable/disable cycles. + */ +#define I2S_BUFFERS_COUNT 7 +K_MEM_SLAB_DEFINE_STATIC(i2s_tx_slab, MAX_BLOCK_SIZE, I2S_BUFFERS_COUNT, 4); + +struct usb_i2s_ctx { + const struct device *i2s_dev; + bool terminal_enabled; + bool i2s_started; + /* Number of blocks written, used to determine when to start I2S. + * Overflows are not a problem becuse this variable is not necessary + * after I2S is started. + */ + uint8_t i2s_blocks_written; + struct feedback_ctx *fb; +}; + +static void uac2_terminal_update_cb(const struct device *dev, uint8_t terminal, + bool enabled, bool microframes, + void *user_data) +{ + struct usb_i2s_ctx *ctx = user_data; + + /* This sample has only one terminal therefore the callback can simply + * ignore the terminal variable. + */ + __ASSERT_NO_MSG(terminal == HEADPHONES_OUT_TERMINAL_ID); + /* This sample is for Full-Speed only devices. */ + __ASSERT_NO_MSG(microframes == false); + + ctx->terminal_enabled = enabled; + if (ctx->i2s_started && !enabled) { + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); + ctx->i2s_started = false; + ctx->i2s_blocks_written = 0; + feedback_reset_ctx(ctx->fb); + } +} + +static void *uac2_get_recv_buf(const struct device *dev, uint8_t terminal, + uint16_t size, void *user_data) +{ + ARG_UNUSED(dev); + struct usb_i2s_ctx *ctx = user_data; + void *buf = NULL; + int ret; + + if (terminal == HEADPHONES_OUT_TERMINAL_ID) { + __ASSERT_NO_MSG(size <= MAX_BLOCK_SIZE); + + if (!ctx->terminal_enabled) { + LOG_ERR("Buffer request on disabled terminal"); + return NULL; + } + + ret = k_mem_slab_alloc(&i2s_tx_slab, &buf, K_NO_WAIT); + if (ret != 0) { + buf = NULL; + } + } + + return buf; +} + +static void uac2_data_recv_cb(const struct device *dev, uint8_t terminal, + void *buf, uint16_t size, void *user_data) +{ + struct usb_i2s_ctx *ctx = user_data; + int ret; + + if (!ctx->terminal_enabled) { + k_mem_slab_free(&i2s_tx_slab, buf); + return; + } + + if (!size) { + /* Zero fill to keep I2S going. If this is transient error, then + * this is probably best we can do. Otherwise, host will likely + * either disable terminal (or the cable will be disconnected) + * which will stop I2S. + */ + size = BLOCK_SIZE; + memset(buf, 0, size); + sys_cache_data_flush_range(buf, size); + } + + LOG_DBG("Received %d data to input terminal %d", size, terminal); + + ret = i2s_write(ctx->i2s_dev, buf, size); + if (ret < 0) { + ctx->i2s_started = false; + ctx->i2s_blocks_written = 0; + feedback_reset_ctx(ctx->fb); + + /* Most likely underrun occurred, prepare I2S restart */ + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_PREPARE); + + ret = i2s_write(ctx->i2s_dev, buf, size); + if (ret < 0) { + /* Drop data block, will try again on next frame */ + k_mem_slab_free(&i2s_tx_slab, buf); + } + } + + if (ret == 0) { + ctx->i2s_blocks_written++; + } +} + +static void uac2_buf_release_cb(const struct device *dev, uint8_t terminal, + void *buf, void *user_data) +{ + /* This sample does not send audio data so this won't be called */ +} + +/* Variables for debug use to facilitate simple how feedback value affects + * audio data rate experiments. These debug variables can also be used to + * determine how well the feedback regulator deals with errors. The values + * are supposed to be modified by debugger. + * + * Setting use_hardcoded_feedback to true, essentially bypasses the feedback + * regulator and makes host send hardcoded_feedback samples every 16384 SOFs + * (when operating at Full-Speed). + * + * The feedback at Full-Speed is Q10.14 value. For 48 kHz audio sample rate, + * there are nominally 48 samples every SOF. The corresponding value is thus + * 48 << 14. Such feedback value would result in host sending always 48 samples. + * Now, if we want to receive more samples (because 1 ms according to audio + * sink is shorter than 1 ms according to USB Host 500 ppm SOF timer), then + * the feedback value has to be increased. The fractional part is 14-bit wide + * and therefore increment by 1 means 1 additional sample every 2**14 SOFs. + * (48 << 14) + 1 therefore results in host sending 48 samples 16383 times and + * 49 samples 1 time during every 16384 SOFs. + * + * Similarly, if we want to receive less samples (because 1 ms according to + * audio signk is longer than 1 ms according to USB Host), then the feedback + * value has to be decreased. (48 << 14) - 1 therefore results in host sending + * 48 samples 16383 times and 47 samples 1 time during every 16384 SOFs. + * + * If the feedback value differs by more than 1 (i.e. LSB), then the +1/-1 + * samples packets are generally evenly distributed. For example feedback value + * (48 << 14) + (1 << 5) results in 48 samples 511 times and 49 samples 1 time + * during every 512 SOFs. + * + * For High-Speed above changes slightly, because the feedback format is Q16.16 + * and microframes are used. The 48 kHz audio sample rate is achieved by sending + * 6 samples every SOF (microframe). The nominal value is the average number of + * samples to send every microframe and therefore for 48 kHz the nominal value + * is (6 << 16). + */ +static volatile bool use_hardcoded_feedback; +static volatile uint32_t hardcoded_feedback = (48 << 14) + 1; + +static uint32_t uac2_feedback_cb(const struct device *dev, uint8_t terminal, + void *user_data) +{ + /* Sample has only one UAC2 instance with one terminal so both can be + * ignored here. + */ + ARG_UNUSED(dev); + ARG_UNUSED(terminal); + struct usb_i2s_ctx *ctx = user_data; + + if (use_hardcoded_feedback) { + return hardcoded_feedback; + } else { + return feedback_value(ctx->fb); + } +} + +static void uac2_sof(const struct device *dev, void *user_data) +{ + ARG_UNUSED(dev); + struct usb_i2s_ctx *ctx = user_data; + + if (ctx->i2s_started) { + feedback_process(ctx->fb); + } + + /* We want to maintain 3 SOFs delay, i.e. samples received during SOF n + * should be on I2S during SOF n+3. This provides enough wiggle room + * for software scheduling that effectively eliminates "buffers not + * provided in time" problem. + * + * ">= 2" translates into 3 SOFs delay because the timeline is: + * USB SOF n + * OUT DATA0 n received from host + * USB SOF n+1 + * DATA0 n is available to UDC driver (See Universal Serial Bus + * Specification Revision 2.0 5.12.5 Data Prebuffering) and copied + * to I2S buffer before SOF n+2; i2s_blocks_written = 1 + * OUT DATA0 n+1 received from host + * USB SOF n+2 + * DATA0 n+1 is copied; i2s_block_written = 2 + * OUT DATA0 n+2 received from host + * USB SOF n+3 + * This function triggers I2S start + * DATA0 n+2 is copied; i2s_block_written is no longer relevant + * OUT DATA0 n+3 received from host + */ + if (!ctx->i2s_started && ctx->terminal_enabled && + ctx->i2s_blocks_written >= 2) { + i2s_trigger(ctx->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); + ctx->i2s_started = true; + feedback_start(ctx->fb, ctx->i2s_blocks_written); + } +} + +static struct uac2_ops usb_audio_ops = { + .sof_cb = uac2_sof, + .terminal_update_cb = uac2_terminal_update_cb, + .get_recv_buf = uac2_get_recv_buf, + .data_recv_cb = uac2_data_recv_cb, + .buf_release_cb = uac2_buf_release_cb, + .feedback_cb = uac2_feedback_cb, +}; + +static struct usb_i2s_ctx main_ctx; + +int main(void) +{ + const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(uac2_headphones)); + struct usbd_contex *sample_usbd; + struct i2s_config config; + int ret; + + main_ctx.i2s_dev = DEVICE_DT_GET(DT_NODELABEL(i2s_tx)); + + if (!device_is_ready(main_ctx.i2s_dev)) { + printk("%s is not ready\n", main_ctx.i2s_dev->name); + return 0; + } + + config.word_size = SAMPLE_BIT_WIDTH; + config.channels = NUMBER_OF_CHANNELS; + config.format = I2S_FMT_DATA_FORMAT_I2S; + config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER; + config.frame_clk_freq = SAMPLE_FREQUENCY; + config.mem_slab = &i2s_tx_slab; + config.block_size = MAX_BLOCK_SIZE; + config.timeout = 0; + + ret = i2s_configure(main_ctx.i2s_dev, I2S_DIR_TX, &config); + if (ret < 0) { + printk("Failed to configure TX stream: %d\n", ret); + return 0; + } + + main_ctx.fb = feedback_init(); + + usbd_uac2_set_ops(dev, &usb_audio_ops, &main_ctx); + + sample_usbd = sample_usbd_init_device(); + if (sample_usbd == NULL) { + return -ENODEV; + } + + ret = usbd_enable(sample_usbd); + if (ret) { + return ret; + } + + return 0; +} diff --git a/samples/subsys/usb/webusb/src/main.c b/samples/subsys/usb/webusb/src/main.c index d9e40d9b991..69317465877 100644 --- a/samples/subsys/usb/webusb/src/main.c +++ b/samples/subsys/usb/webusb/src/main.c @@ -40,6 +40,9 @@ LOG_MODULE_REGISTER(main); static struct msosv2_descriptor_t { struct msosv2_descriptor_set_header header; +#if defined(CONFIG_USB_CDC_ACM) + struct msosv2_function_subset_header subset_header; +#endif struct msosv2_compatible_id webusb_compatible_id; struct msosv2_guids_property webusb_guids_property; } __packed msosv2_descriptor = { @@ -52,6 +55,23 @@ static struct msosv2_descriptor_t { .dwWindowsVersion = 0x06030000, .wTotalLength = sizeof(struct msosv2_descriptor_t), }, +#if defined(CONFIG_USB_CDC_ACM) + /* If CONFIG_USB_CDC_ACM is selected, extra interfaces will be added on build time, + * making the target a composite device, which requires an extra Function + * Subset Header. + */ + .subset_header = { + .wLength = sizeof(struct msosv2_function_subset_header), + .wDescriptorType = MS_OS_20_SUBSET_HEADER_FUNCTION, + /* The WebUSB interface number becomes the first when CDC_ACM is enabled by + * configuration. Beware that if this sample is used as as inspiration for + * applications, where the WebUSB interface is no longer the first, + * remember to adjust bFirstInterface. + */ + .bFirstInterface = 0, + .wSubsetLength = 160 + }, +#endif .webusb_compatible_id = { .wLength = sizeof(struct msosv2_compatible_id), .wDescriptorType = MS_OS_20_FEATURE_COMPATIBLE_ID, diff --git a/samples/subsys/zbus/benchmark/CMakeLists.txt b/samples/subsys/zbus/benchmark/CMakeLists.txt index e66cd1e4ace..548225af792 100644 --- a/samples/subsys/zbus/benchmark/CMakeLists.txt +++ b/samples/subsys/zbus/benchmark/CMakeLists.txt @@ -4,5 +4,17 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(benchmark) -FILE(GLOB app_sources src/*.c) +set(app_sources src/benchmark.c) + +if(CONFIG_BM_LISTENERS) + list(APPEND app_sources src/lis.c) + +elseif(CONFIG_BM_SUBSCRIBERS) + list(APPEND app_sources src/sub.c) + +elseif(CONFIG_BM_MSG_SUBSCRIBERS) + list(APPEND app_sources src/msg_sub.c) + +endif() + target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/zbus/benchmark/Kconfig b/samples/subsys/zbus/benchmark/Kconfig index 2fdeb3ff76b..3a21c2fd6f8 100644 --- a/samples/subsys/zbus/benchmark/Kconfig +++ b/samples/subsys/zbus/benchmark/Kconfig @@ -9,8 +9,25 @@ config BM_ONE_TO int "Number of consumers" default 8 -config BM_ASYNC - bool "Consuming in asynchronous mode" - default false +choice BM_OBSERVER_TYPE + bool "Observer type to be used in the benchmark" + +config BM_LISTENERS + bool "Synchronous using listeners" + +config BM_SUBSCRIBERS + bool "Asynchronous using subscribers" + +config BM_MSG_SUBSCRIBERS + bool "Asynchronous using message subscribers" + select ZBUS_MSG_SUBSCRIBER + +endchoice + +config BM_FAIRPLAY + bool "Force a comparison with same actions" + help + Forces a message copy on the listeners and subscribers to behave equivalent to + message subscribers. source "Kconfig.zephyr" diff --git a/samples/subsys/zbus/benchmark/README.rst b/samples/subsys/zbus/benchmark/README.rst index 4dd14607623..52a7d864481 100644 --- a/samples/subsys/zbus/benchmark/README.rst +++ b/samples/subsys/zbus/benchmark/README.rst @@ -2,9 +2,10 @@ :name: Benchmarking :relevant-api: zbus_apis - Measure the time for sending 256KB from a producer to X consumers. + Measure the time for sending 256KB from a producer to N consumers. -This sample implements an application to measure the time for sending 256KB from the producer to the consumers. +This sample implements an application to measure the time for sending 256KB from the producer to the +consumers. Building and Running ******************** @@ -13,14 +14,16 @@ Building and Running :zephyr-app: samples/subsys/zbus/dyn_channel :host-os: unix :board: qemu_cortex_m3 - :gen-args: -DCONFIG_BM_MESSAGE_SIZE=1 -DCONFIG_BM_ONE_TO=1 -DCONFIG_BM_ASYNC=y + :gen-args: -DCONFIG_BM_MESSAGE_SIZE=512 -DCONFIG_BM_ONE_TO=1 -DCONFIG_BM_LISTENERS=y :goals: build run Notice we have the following parameters: -* **CONFIG_BM_MESSAGE_SIZE** the size of the message to be transferred (1, 2, 4, 8, 16, 32, 64, 128, or 256); -* **CONFIG_BM_ONE_TO** number of consumers to send (1, 2, 4, or 8); -* **CONFIG_BM_ASYNC** if the execution must be asynchronous or synchronous. Use y to async and n to sync; +* **CONFIG_BM_MESSAGE_SIZE** the size of the message to be transferred (2 to 4096 bytes); +* **CONFIG_BM_ONE_TO** number of consumers to send (1 up to 8 consumers); +* **CONFIG_BM_LISTENERS** Use y to perform the benchmark listeners; +* **CONFIG_BM_SUBSCRIBERS** Use y to perform the benchmark subscribers; +* **CONFIG_BM_MSG_SUBSCRIBERS** Use y to perform the benchmark message subscribers. Sample Output ============= @@ -28,13 +31,13 @@ The result would be something like: .. code-block:: console - *** Booting Zephyr OS build zephyr-v3.3.0 *** - I: Benchmark 1 to 1: Dynamic memory, SYNC transmission and message size 1 - I: Bytes sent = 262144, received = 262144 - I: Average data rate: 0.6MB/s - I: Duration: 4.72020167s + *** Booting Zephyr OS build zephyr-vX.Y.Z *** + I: Benchmark 1 to 1 using LISTENERS to transmit with message size: 512 bytes + I: Bytes sent = 262144, received = 262144 + I: Average data rate: 12.62MB/s + I: Duration: 0.019805908s - @4072020167 + @19805 Running the benchmark automatically @@ -43,91 +46,64 @@ Running the benchmark automatically There is a `Robot framework `_ script called ``benchmark_256KB.robot`` which runs all the input combinations as the complete benchmark. The resulting file, ``zbus_dyn_benchmark_256KB.csv`` is generated in the project root folder. It takes a long time to execute. In the CSV file, we have the following columns: -+------------+---------------------+--------------------------+---------------+-------------+-------------+ -| Style | Number of consumers | Message size (bytes) | Duration (ns) | RAM (bytes) | ROM (bytes) | -+============+=====================+==========================+===============+=============+=============+ -| SYNC/ASYNC | 1,2,4,8 | 1,2,4,8,16,32,64,128,256 | float | int | int | -+------------+---------------------+--------------------------+---------------+-------------+-------------+ ++-----------------+---------------------+--------------------------+---------------+-------------+-------------+ +| Observer type | Number of consumers | Message size (bytes) | Duration (ns) | RAM (bytes) | ROM (bytes) | ++=================+=====================+==========================+===============+=============+=============+ +| LIS/SUB/MSG_SUB | 1,4,8 | 2,8,32,128,512 | float | int | int | ++-----------------+---------------------+--------------------------+---------------+-------------+-------------+ The complete benchmark command using Robot framework is: .. code-block:: console - robot --variable serial_port:/dev/ttyACM0 --variable board:nrf52833dk_nrf52833 -d /tmp/benchmark_out benchmark_256KB.robot + robot --variable serial_port:/dev/ttyACM0 --variable board:nrf52dk_nrf52832 -d /tmp/benchmark_out benchmark_256KB.robot -An example of execution using the ``nrf52833dk_nrf52833`` board would generate a file like this: +An example of execution using the ``nrf52dk_nrf52832`` board would generate a file like this: .. code-block:: - SYNC,1,1,2312815348.3333335,7286,23752 - SYNC,1,2,1172444661.3333333,7287,23760 - SYNC,1,4,602284749.6666666,7289,23768 - SYNC,1,8,323750814.0,7293,23772 - SYNC,1,16,175120035.66666666,7301,23776 - SYNC,1,32,103942871.33333333,7317,23776 - SYNC,1,64,68318685.0,7349,23776 - SYNC,1,128,50567627.333333336,7477,23776 - SYNC,1,256,41656494.0,7733,23776 - SYNC,2,1,1277842204.3333333,7298,23768 - SYNC,2,2,647094726.6666666,7299,23776 - SYNC,2,4,329559326.3333333,7301,23784 - SYNC,2,8,170979817.66666666,7305,23796 - SYNC,2,16,95174153.66666667,7313,23792 - SYNC,2,32,55786133.0,7329,23792 - SYNC,2,64,36173502.333333336,7361,23792 - SYNC,2,128,26326497.666666668,7489,23792 - SYNC,2,256,21280924.333333332,7745,23792 - SYNC,4,1,745513916.0,7322,23800 - SYNC,4,2,374755859.6666667,7323,23808 - SYNC,4,4,191497802.66666666,7325,23816 - SYNC,4,8,101399739.66666667,7329,23820 - SYNC,4,16,54026286.0,7337,23824 - SYNC,4,32,31097412.0,7353,23824 - SYNC,4,64,19643148.333333332,7385,23824 - SYNC,4,128,13936360.333333334,7513,23824 - SYNC,4,256,11047363.333333334,7769,23824 - SYNC,8,1,477518717.3333333,7370,23864 - SYNC,8,2,240773518.66666666,7371,23872 - SYNC,8,4,121897379.33333333,7373,23880 - SYNC,8,8,64015706.333333336,7377,23884 - SYNC,8,16,33681234.0,7385,23888 - SYNC,8,32,18880208.333333332,7401,23888 - SYNC,8,64,11505127.0,7433,23888 - SYNC,8,128,7781982.333333333,7561,23888 - SYNC,8,256,5940755.333333333,7817,23888 - ASYNC,1,1,9422749837.333334,7962,24108 - ASYNC,1,2,4728759765.333333,7963,24116 - ASYNC,1,4,2380554199.3333335,7965,24124 - ASYNC,1,8,1225118001.6666667,7969,24128 - ASYNC,1,16,618764241.6666666,7977,24132 - ASYNC,1,32,326253255.3333333,7993,24132 - ASYNC,1,64,179473876.66666666,8025,24132 - ASYNC,1,128,106170654.33333333,8217,24132 - ASYNC,1,256,69386800.33333333,8601,24136 - ASYNC,2,1,8347330729.0,8650,24288 - ASYNC,2,2,4186747233.3333335,8651,24296 - ASYNC,2,4,2092895507.3333333,8653,24304 - ASYNC,2,8,1049245198.6666666,8657,24316 - ASYNC,2,16,541544596.6666666,8665,24312 - ASYNC,2,32,281127929.6666667,8681,24312 - ASYNC,2,64,150746663.66666666,8713,24312 - ASYNC,2,128,85662842.0,8969,24312 - ASYNC,2,256,48909505.0,9481,24320 - ASYNC,4,1,7854085286.666667,10026,24652 - ASYNC,4,2,3935852050.3333335,10027,24660 - ASYNC,4,4,1972869873.0,10029,24668 - ASYNC,4,8,979451497.6666666,10033,24672 - ASYNC,4,16,499348958.0,10041,24676 - ASYNC,4,32,253712972.0,10057,24676 - ASYNC,4,64,131022135.33333333,10089,24676 - ASYNC,4,128,69610595.66666667,10473,24676 - ASYNC,4,256,38706461.666666664,11241,24692 - ASYNC,8,1,7590311686.666667,12778,25220 - ASYNC,8,2,3800333658.6666665,12779,25228 - ASYNC,8,4,1900014241.6666667,12781,25236 - ASYNC,8,8,940419515.0,12785,25240 - ASYNC,8,16,478739420.6666667,12793,25244 - ASYNC,8,32,241465250.66666666,12809,25244 - ASYNC,8,64,122701009.0,12841,25244 - ASYNC,8,128,63405355.0,13481,25244 - ASYNC,8,256,33752441.666666664,14761,25244 + LISTENERS,1,2,890787.3333333334,9247,23091 + LISTENERS,1,8,237925.0,9253,23091 + LISTENERS,1,32,74513.0,9277,23151 + LISTENERS,1,128,33813.0,9565,23231 + LISTENERS,1,512,35746.0,10717,23623 + LISTENERS,4,2,314198.3333333333,9274,23142 + LISTENERS,4,8,82244.33333333333,9280,23142 + LISTENERS,4,32,24057.333333333332,9304,23202 + LISTENERS,4,128,9816.0,9592,23282 + LISTENERS,4,512,9277.0,10744,23674 + LISTENERS,8,2,211465.66666666666,9310,23202 + LISTENERS,8,8,56294.0,9316,23210 + LISTENERS,8,32,15635.0,9340,23270 + LISTENERS,8,128,5818.0,9628,23350 + LISTENERS,8,512,4862.0,10780,23742 + SUBSCRIBERS,1,2,7804351.333333333,9927,23463 + SUBSCRIBERS,1,8,1978179.3333333333,9933,23463 + SUBSCRIBERS,1,32,514139.3333333333,9957,23523 + SUBSCRIBERS,1,128,146759.0,10309,23603 + SUBSCRIBERS,1,512,55104.0,11845,23995 + SUBSCRIBERS,4,2,5551961.0,11994,24134 + SUBSCRIBERS,4,8,1395009.0,12000,24134 + SUBSCRIBERS,4,32,354583.3333333333,12024,24194 + SUBSCRIBERS,4,128,92976.66666666667,12568,24274 + SUBSCRIBERS,4,512,28015.0,15256,24666 + SUBSCRIBERS,8,2,5449839.0,14750,24858 + SUBSCRIBERS,8,8,1321766.6666666667,14756,24866 + SUBSCRIBERS,8,32,332804.0,14780,24926 + SUBSCRIBERS,8,128,85489.33333333333,15580,25006 + SUBSCRIBERS,8,512,23905.0,19804,25398 + MSG_SUBSCRIBERS,1,2,8783538.333333334,10371,25615 + MSG_SUBSCRIBERS,1,8,2249592.6666666665,10377,25615 + MSG_SUBSCRIBERS,1,32,610168.0,10401,25675 + MSG_SUBSCRIBERS,1,128,207295.0,10753,25755 + MSG_SUBSCRIBERS,1,512,143584.66666666666,12289,26147 + MSG_SUBSCRIBERS,4,2,5787699.0,12318,26126 + MSG_SUBSCRIBERS,4,8,1473907.0,12324,26126 + MSG_SUBSCRIBERS,4,32,396127.6666666667,12348,26186 + MSG_SUBSCRIBERS,4,128,126362.66666666667,12892,26266 + MSG_SUBSCRIBERS,4,512,59040.666666666664,15580,26658 + MSG_SUBSCRIBERS,8,2,5453999.333333333,14914,26610 + MSG_SUBSCRIBERS,8,8,1356312.3333333333,14920,26650 + MSG_SUBSCRIBERS,8,32,361368.3333333333,14944,26710 + MSG_SUBSCRIBERS,8,128,113148.66666666667,15744,26790 + MSG_SUBSCRIBERS,8,512,51218.333333333336,19968,27182 diff --git a/samples/subsys/zbus/benchmark/benchmark_256KB.robot b/samples/subsys/zbus/benchmark/benchmark_256KB.robot index ef637f358f1..db2ab59d6a4 100644 --- a/samples/subsys/zbus/benchmark/benchmark_256KB.robot +++ b/samples/subsys/zbus/benchmark/benchmark_256KB.robot @@ -8,19 +8,23 @@ Suite Teardown Terminate All Processes kill=True *** Variables *** -${csv_file} zbus_dyn_benchmark_256kb.csv -${board} hifive1_revb -${serial_port} /dev/ttyACM0 +${csv_file} zbus_dyn_benchmark_256kb.csv +${board} hifive1_revb +${serial_port} /dev/ttyACM0 + *** Tasks *** Clear Old CSV File Empty Csv File ${csv_file} Zbus Benchmark - FOR ${async} IN "n" "y" - FOR ${consumers} IN 1 2 4 8 - FOR ${msg_size} IN 1 2 4 8 16 32 64 128 256 - Benchmark Report For message_size=${msg_size} one_to=${consumers} asynchronous=${async} + FOR ${obs_type} IN 0 1 2 + FOR ${consumers} IN 1 4 8 + FOR ${msg_size} IN 2 8 32 128 512 + Benchmark Report For + ... message_size=${msg_size} + ... one_to=${consumers} + ... observer_type=${obs_type} END END END @@ -54,30 +58,41 @@ Measure Results [Teardown] Delete All Ports Benchmark - [Arguments] ${message_size}=256 ${one_to}=1 ${asynchronous}=n + [Arguments] ${message_size}=256 ${one_to}=1 ${observer_type}=LISTENERS ${result} Run Process - ... west build -b ${board} -p always -- -DCONFIG_BM_MESSAGE_SIZE\=${message_size} -DCONFIG_BM_ONE_TO\=${one_to} -DCONFIG_BM_ASYNC\=${asynchronous} + ... west build -b ${board} -p always -- -DCONFIG_BM_MESSAGE_SIZE\=${message_size} -DCONFIG_BM_ONE_TO\=${one_to} -DCONFIG_BM_${observer_type}\=y ... shell=True Should Be Equal As Integers ${result.rc} 0 ${duration} Measure Results RETURN ${duration} Benchmark Report For - [Arguments] ${message_size}=256 ${one_to}=1 ${asynchronous}=n - ${duration} Benchmark message_size=${message_size} one_to=${one_to} asynchronous=${asynchronous} + [Arguments] ${message_size}=256 ${one_to}=1 ${observer_type}=0 + + ${obs_type_str} Set Variable LISTENERS + IF ${observer_type} == 1 + ${obs_type_str} Set Variable SUBSCRIBERS + ELSE IF ${observer_type} == 2 + ${obs_type_str} Set Variable MSG_SUBSCRIBERS + END + + ${duration} Benchmark + ... message_size=${message_size} + ... one_to=${one_to} + ... observer_type=${obs_type_str} + ${ram_amount} Run Memory Report ram + ${rom_amount} Run Memory Report rom - IF ${asynchronous} == "y" - ${async_str} Set Variable ASYNC - ELSE - ${async_str} Set Variable SYNC - END + @{results} Create List - ... ${async_str} + ... ${obs_type_str} ... ${one_to} ... ${message_size} ... ${duration} ... ${ram_amount} ... ${rom_amount} + Log To Console \n${results} + Append To Csv File ${csv_file} ${results} diff --git a/samples/subsys/zbus/benchmark/prj.conf b/samples/subsys/zbus/benchmark/prj.conf index 2c2865f3918..d79ae4dffe8 100644 --- a/samples/subsys/zbus/benchmark/prj.conf +++ b/samples/subsys/zbus/benchmark/prj.conf @@ -1,5 +1,7 @@ CONFIG_LOG=y +CONFIG_BOOT_BANNER=n CONFIG_LOG_MODE_MINIMAL=y CONFIG_ASSERT=n CONFIG_ZBUS=y CONFIG_ZBUS_LOG_LEVEL_INF=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/samples/subsys/zbus/benchmark/sample.yaml b/samples/subsys/zbus/benchmark/sample.yaml index b090cc9d467..089d62209e2 100644 --- a/samples/subsys/zbus/benchmark/sample.yaml +++ b/samples/subsys/zbus/benchmark/sample.yaml @@ -10,7 +10,7 @@ tests: type: multi_line ordered: true regex: - - "I: Benchmark 1 to 8: Dynamic memory, ASYNC transmission and message size 256" + - "I: Benchmark 1 to 8 using LISTENERS to transmit with message size: 256 bytes" - "I: Bytes sent = 262144, received = 262144" - "I: Average data rate: (\\d+).(\\d+)MB/s" - "I: Duration: (\\d+).(\\d+)s" @@ -18,7 +18,29 @@ tests: extra_configs: - CONFIG_BM_ONE_TO=8 - CONFIG_BM_MESSAGE_SIZE=256 - - CONFIG_BM_ASYNC=y + - CONFIG_BM_LISTENERS=y + - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + - CONFIG_IDLE_STACK_SIZE=1024 + integration_platforms: + - qemu_x86 + sample.zbus.benchmark_async_msg_sub: + tags: zbus + min_ram: 16 + filter: CONFIG_SYS_CLOCK_EXISTS and not (CONFIG_ARCH_POSIX and not CONFIG_BOARD_NATIVE_POSIX) + harness: console + harness_config: + type: multi_line + ordered: true + regex: + - "I: Benchmark 1 to 8 using MSG_SUBSCRIBERS to transmit with message size: 256 bytes" + - "I: Bytes sent = 262144, received = 262144" + - "I: Average data rate: (\\d+).(\\d+)MB/s" + - "I: Duration: (\\d+).(\\d+)s" + - "@(.*)" + extra_configs: + - CONFIG_BM_ONE_TO=8 + - CONFIG_BM_MESSAGE_SIZE=256 + - CONFIG_BM_MSG_SUBSCRIBERS=y - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 - CONFIG_IDLE_STACK_SIZE=1024 integration_platforms: @@ -32,7 +54,7 @@ tests: type: multi_line ordered: true regex: - - "I: Benchmark 1 to 8: Dynamic memory, SYNC transmission and message size 256" + - "I: Benchmark 1 to 8 using SUBSCRIBERS to transmit with message size: 256 bytes" - "I: Bytes sent = 262144, received = 262144" - "I: Average data rate: (\\d+).(\\d+)MB/s" - "I: Duration: (\\d+).(\\d+)s" @@ -40,7 +62,7 @@ tests: extra_configs: - CONFIG_BM_ONE_TO=8 - CONFIG_BM_MESSAGE_SIZE=256 - - CONFIG_BM_ASYNC=n + - CONFIG_BM_SUBSCRIBERS=y - arch:nios2:CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 - CONFIG_IDLE_STACK_SIZE=1024 integration_platforms: diff --git a/samples/subsys/zbus/benchmark/src/benchmark.c b/samples/subsys/zbus/benchmark/src/benchmark.c index ac781a6306f..267c593b4b1 100644 --- a/samples/subsys/zbus/benchmark/src/benchmark.c +++ b/samples/subsys/zbus/benchmark/src/benchmark.c @@ -4,8 +4,6 @@ */ #include "messages.h" -#include - #include #include #include @@ -27,183 +25,57 @@ LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); #define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) #define PRODUCER_STACK_SIZE (CONFIG_MAIN_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) -ZBUS_CHAN_DEFINE(bm_channel, /* Name */ +ZBUS_CHAN_DEFINE(bm_channel, /* Name */ struct bm_msg, /* Message type */ - NULL, /* Validator */ - NULL, /* User data */ - ZBUS_OBSERVERS(s1 - -#if (CONFIG_BM_ONE_TO >= 2LLU) - , - s2 -#if (CONFIG_BM_ONE_TO > 2LLU) - , - s3, s4 -#if (CONFIG_BM_ONE_TO > 4LLU) - , - s5, s6, s7, s8 -#if (CONFIG_BM_ONE_TO > 8LLU) - , - s9, s10, s11, s12, s13, s14, s15, s16 -#endif -#endif -#endif -#endif - ), /* observers */ - ZBUS_MSG_INIT(0) /* Initial value {0} */ + NULL, /* Validator */ + NULL, /* User data */ + ZBUS_OBSERVERS_EMPTY, /* observers */ + ZBUS_MSG_INIT(0) /* Initial value {0} */ ); #define BYTES_TO_BE_SENT (256LLU * 1024LLU) -static atomic_t count; - -#if (CONFIG_BM_ASYNC == 1) -ZBUS_SUBSCRIBER_DEFINE(s1, 4); -#if (CONFIG_BM_ONE_TO >= 2LLU) -ZBUS_SUBSCRIBER_DEFINE(s2, 4); -#if (CONFIG_BM_ONE_TO > 2LLU) -ZBUS_SUBSCRIBER_DEFINE(s3, 4); -ZBUS_SUBSCRIBER_DEFINE(s4, 4); -#if (CONFIG_BM_ONE_TO > 4LLU) -ZBUS_SUBSCRIBER_DEFINE(s5, 4); -ZBUS_SUBSCRIBER_DEFINE(s6, 4); -ZBUS_SUBSCRIBER_DEFINE(s7, 4); -ZBUS_SUBSCRIBER_DEFINE(s8, 4); -#if (CONFIG_BM_ONE_TO > 8LLU) -ZBUS_SUBSCRIBER_DEFINE(s9, 4); -ZBUS_SUBSCRIBER_DEFINE(s10, 4); -ZBUS_SUBSCRIBER_DEFINE(s11, 4); -ZBUS_SUBSCRIBER_DEFINE(s12, 4); -ZBUS_SUBSCRIBER_DEFINE(s13, 4); -ZBUS_SUBSCRIBER_DEFINE(s14, 4); -ZBUS_SUBSCRIBER_DEFINE(s15, 4); -ZBUS_SUBSCRIBER_DEFINE(s16, 4); -#endif -#endif -#endif -#endif - -#define S_TASK(name) \ - void name##_task(void) \ - { \ - const struct zbus_channel *chan; \ - struct bm_msg *msg_received; \ - \ - while (!zbus_sub_wait(&name, &chan, K_FOREVER)) { \ - zbus_chan_claim(chan, K_NO_WAIT); \ - \ - msg_received = zbus_chan_msg(chan); \ - \ - zbus_chan_finish(chan); \ - \ - atomic_add(&count, CONFIG_BM_MESSAGE_SIZE); \ - } \ - } \ - \ - K_THREAD_DEFINE(name##_id, CONSUMER_STACK_SIZE, name##_task, NULL, NULL, NULL, 3, 0, 0); - -S_TASK(s1) -#if (CONFIG_BM_ONE_TO >= 2LLU) -S_TASK(s2) -#if (CONFIG_BM_ONE_TO > 2LLU) -S_TASK(s3) -S_TASK(s4) -#if (CONFIG_BM_ONE_TO > 4LLU) -S_TASK(s5) -S_TASK(s6) -S_TASK(s7) -S_TASK(s8) -#if (CONFIG_BM_ONE_TO > 8LLU) -S_TASK(s9) -S_TASK(s10) -S_TASK(s11) -S_TASK(s12) -S_TASK(s13) -S_TASK(s14) -S_TASK(s15) -S_TASK(s16) -#endif -#endif -#endif -#endif - -#else /* SYNC */ - -static void s_cb(const struct zbus_channel *chan); - -ZBUS_LISTENER_DEFINE(s1, s_cb); - -#if (CONFIG_BM_ONE_TO >= 2LLU) -ZBUS_LISTENER_DEFINE(s2, s_cb); -#if (CONFIG_BM_ONE_TO > 2LLU) -ZBUS_LISTENER_DEFINE(s3, s_cb); -ZBUS_LISTENER_DEFINE(s4, s_cb); -#if (CONFIG_BM_ONE_TO > 4LLU) -ZBUS_LISTENER_DEFINE(s5, s_cb); -ZBUS_LISTENER_DEFINE(s6, s_cb); -ZBUS_LISTENER_DEFINE(s7, s_cb); -ZBUS_LISTENER_DEFINE(s8, s_cb); -#if (CONFIG_BM_ONE_TO > 8LLU) -ZBUS_LISTENER_DEFINE(s9, s_cb); -ZBUS_LISTENER_DEFINE(s10, s_cb); -ZBUS_LISTENER_DEFINE(s11, s_cb); -ZBUS_LISTENER_DEFINE(s12, s_cb); -ZBUS_LISTENER_DEFINE(s13, s_cb); -ZBUS_LISTENER_DEFINE(s14, s_cb); -ZBUS_LISTENER_DEFINE(s15, s_cb); -ZBUS_LISTENER_DEFINE(s16, s_cb); -#endif -#endif -#endif -#endif - -static void s_cb(const struct zbus_channel *chan) -{ - const struct bm_msg *actual_message_data = zbus_chan_const_msg(chan); - - /* It only illustrates the message is ready to be consumed */ - ARG_UNUSED(actual_message_data); - - count += CONFIG_BM_MESSAGE_SIZE; -} - -#endif /* CONFIG_BM_ASYNC */ +atomic_t count; static void producer_thread(void) { - LOG_INF("Benchmark 1 to %d: Dynamic memory, %sSYNC transmission and message size %u", - CONFIG_BM_ONE_TO, IS_ENABLED(CONFIG_BM_ASYNC) ? "A" : "", CONFIG_BM_MESSAGE_SIZE); + LOG_INF("Benchmark 1 to %d using %s to transmit with message size: %u bytes", + CONFIG_BM_ONE_TO, + IS_ENABLED(CONFIG_BM_LISTENERS) + ? "LISTENERS" + : (IS_ENABLED(CONFIG_BM_SUBSCRIBERS) ? "SUBSCRIBERS" : "MSG_SUBSCRIBERS"), + CONFIG_BM_MESSAGE_SIZE); - struct bm_msg msg; + struct bm_msg msg = {{0}}; - for (uint64_t i = (CONFIG_BM_MESSAGE_SIZE - 1); i > 0; --i) { - msg.bytes[i] = i; - } + uint16_t message_size = CONFIG_BM_MESSAGE_SIZE; + + memcpy(msg.bytes, &message_size, sizeof(message_size)); uint64_t start_ns = GET_ARCH_TIME_NS(); for (uint64_t internal_count = BYTES_TO_BE_SENT / CONFIG_BM_ONE_TO; internal_count > 0; internal_count -= CONFIG_BM_MESSAGE_SIZE) { - zbus_chan_pub(&bm_channel, &msg, K_MSEC(200)); + zbus_chan_pub(&bm_channel, &msg, K_FOREVER); } uint64_t end_ns = GET_ARCH_TIME_NS(); - uint64_t duration = end_ns - start_ns; + uint64_t duration_ns = end_ns - start_ns; - if (duration == 0) { + if (duration_ns == 0) { LOG_ERR("Something wrong. Duration is zero!\n"); k_oops(); } - uint64_t i = ((BYTES_TO_BE_SENT * NSEC_PER_SEC) / MB(1)) / duration; - uint64_t f = ((BYTES_TO_BE_SENT * NSEC_PER_SEC * 100) / MB(1) / duration) % 100; + uint64_t i = ((BYTES_TO_BE_SENT * NSEC_PER_SEC) / MB(1)) / duration_ns; + uint64_t f = ((BYTES_TO_BE_SENT * NSEC_PER_SEC * 100) / MB(1) / duration_ns) % 100; - LOG_INF("Bytes sent = %lld, received = %lu", BYTES_TO_BE_SENT, atomic_get(&count)); + LOG_INF("Bytes sent = %llu, received = %lu", BYTES_TO_BE_SENT, atomic_get(&count)); LOG_INF("Average data rate: %llu.%lluMB/s", i, f); - LOG_INF("Duration: %lld.%09llus", duration / NSEC_PER_SEC, duration % NSEC_PER_SEC); + LOG_INF("Duration: %llu.%09llus", duration_ns / NSEC_PER_SEC, duration_ns % NSEC_PER_SEC); - printk("\n@%llu\n", duration); + printk("\n@%llu\n", duration_ns / 1000); } -K_THREAD_DEFINE(producer_thread_id, PRODUCER_STACK_SIZE, producer_thread, NULL, NULL, NULL, 5, 0, - 0); +K_THREAD_DEFINE(producer_thread_id, PRODUCER_STACK_SIZE * 2, producer_thread, NULL, NULL, NULL, 5, + 0, 0); diff --git a/samples/subsys/zbus/benchmark/src/lis.c b/samples/subsys/zbus/benchmark/src/lis.c new file mode 100644 index 00000000000..0a1e3a7757e --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/lis.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +static void s_cb(const struct zbus_channel *chan); + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_LISTENER_DEFINE(s, s_cb) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static void s_cb(const struct zbus_channel *chan) +{ + + if (IS_ENABLED(CONFIG_BM_FAIRPLAY)) { + struct bm_msg msg_received; + + memcpy(zbus_chan_msg(chan), &msg_received, chan->message_size); + + atomic_add(&count, *((uint16_t *)msg_received.bytes)); + } else { + const struct bm_msg *msg_received = zbus_chan_const_msg(chan); + + atomic_add(&count, *((uint16_t *)msg_received->bytes)); + } +} diff --git a/samples/subsys/zbus/benchmark/src/msg_sub.c b/samples/subsys/zbus/benchmark/src/msg_sub.c new file mode 100644 index 00000000000..d4edc5db774 --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/msg_sub.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_MSG_SUBSCRIBER_DEFINE(s) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static int msg_sub_thread(void *msub_ref, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + struct bm_msg msg_received; + struct zbus_observer *msub = msub_ref; + + while (1) { + if (zbus_sub_wait_msg(msub, &chan, &msg_received, K_FOREVER) == 0) { + atomic_add(&count, *((uint16_t *)msg_received.bytes)); + } else { + k_oops(); + } + } + + return -EFAULT; +} + +#define CREATE_THREADS(name) \ + K_THREAD_DEFINE(name##_msub_id, CONSUMER_STACK_SIZE, msg_sub_thread, &name, NULL, NULL, 3, \ + 0, 0); +/* clang-format off */ +FOR_EACH(CREATE_THREADS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ diff --git a/samples/subsys/zbus/benchmark/src/sub.c b/samples/subsys/zbus/benchmark/src/sub.c new file mode 100644 index 00000000000..f6a00531260 --- /dev/null +++ b/samples/subsys/zbus/benchmark/src/sub.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ +#include "messages.h" + +#include +#include +#include +#include + +#define CONSUMER_STACK_SIZE (CONFIG_IDLE_STACK_SIZE + CONFIG_BM_MESSAGE_SIZE) + +extern atomic_t count; + +ZBUS_CHAN_DECLARE(bm_channel); + +#define SFY(i, _) s##i + +#define CONSUMERS_NAME_LIST LISTIFY(CONFIG_BM_ONE_TO, SFY, (, /* separator */)) + +#define CREATE_OBSERVER(s) ZBUS_SUBSCRIBER_DEFINE(s, 4) + +#define CREATE_OBSERVATIONS(s) ZBUS_CHAN_ADD_OBS(bm_channel, s, 3) + +/* clang-format off */ +FOR_EACH(CREATE_OBSERVER, (;), CONSUMERS_NAME_LIST); + +FOR_EACH(CREATE_OBSERVATIONS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ + +static int sub_thread(void *sub_ref, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + const struct zbus_channel *chan; + struct zbus_observer *sub = sub_ref; + + while (1) { + if (zbus_sub_wait(sub, &chan, K_FOREVER) == 0) { + if (zbus_chan_claim(chan, K_FOREVER) != 0) { + k_oops(); + } + + if (IS_ENABLED(CONFIG_BM_FAIRPLAY)) { + struct bm_msg message; + + memcpy(zbus_chan_msg(chan), &message, chan->message_size); + + atomic_add(&count, *((uint16_t *)message.bytes)); + } else { + const struct bm_msg *msg_received = zbus_chan_const_msg(chan); + + atomic_add(&count, *((uint16_t *)msg_received->bytes)); + } + + zbus_chan_finish(chan); + } else { + k_oops(); + } + } + return -EFAULT; +} + +#define CREATE_THREADS(name) \ + K_THREAD_DEFINE(name##_sub_id, CONSUMER_STACK_SIZE, sub_thread, &name, NULL, NULL, 3, 0, 0); + +/* clang-format off */ +FOR_EACH(CREATE_THREADS, (;), CONSUMERS_NAME_LIST); +/* clang-format on */ diff --git a/samples/subsys/zbus/msg_subscriber/sample.yaml b/samples/subsys/zbus/msg_subscriber/sample.yaml index a344a9ee087..716ffd9b829 100644 --- a/samples/subsys/zbus/msg_subscriber/sample.yaml +++ b/samples/subsys/zbus/msg_subscriber/sample.yaml @@ -95,7 +95,7 @@ tests: harness: console extra_configs: - CONFIG_ZBUS_LOG_LEVEL_DBG=y - - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC=y + - CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_STATIC=y - CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_STATIC_DATA_SIZE=16 harness_config: type: multi_line diff --git a/samples/subsys/zbus/msg_subscriber/src/main.c b/samples/subsys/zbus/msg_subscriber/src/main.c index 03f9cead113..aa5bb42c4f1 100644 --- a/samples/subsys/zbus/msg_subscriber/src/main.c +++ b/samples/subsys/zbus/msg_subscriber/src/main.c @@ -26,14 +26,14 @@ void on_heap_free(uintptr_t heap_id, void *mem, size_t bytes) (unsigned int)total_allocated); } -#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC) +#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) HEAP_LISTENER_ALLOC_DEFINE(my_heap_listener_alloc, HEAP_ID_FROM_POINTER(&_system_heap), on_heap_alloc); HEAP_LISTENER_FREE_DEFINE(my_heap_listener_free, HEAP_ID_FROM_POINTER(&_system_heap), on_heap_free); -#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC */ +#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC */ struct acc_msg { int x; int y; @@ -154,9 +154,9 @@ static void subscriber_task(void *sub) } K_THREAD_DEFINE(subscriber_task_id17, CONFIG_MAIN_STACK_SIZE, subscriber_task, &bar_sub1, NULL, - NULL, 3, 0, 0); + NULL, 2, 0, 0); K_THREAD_DEFINE(subscriber_task_id18, CONFIG_MAIN_STACK_SIZE, subscriber_task, &bar_sub2, NULL, - NULL, 3, 0, 0); + NULL, 4, 0, 0); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_sub2, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub10, 3); @@ -167,18 +167,19 @@ ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub14, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub15, 3); ZBUS_CHAN_ADD_OBS(acc_data_chan, bar_msg_sub16, 3); +static struct acc_msg acc = {.x = 1, .y = 10, .z = 100}; + int main(void) { - struct acc_msg acc = {.x = 1, .y = 10, .z = 100}; total_allocated = 0; -#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC) +#if defined(CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC) heap_listener_register(&my_heap_listener_alloc); heap_listener_register(&my_heap_listener_free); -#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_NET_BUF_DYNAMIC */ +#endif /* CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_ALLOC_DYNAMIC */ while (1) { LOG_INF("----> Publishing to %s channel", zbus_chan_name(&acc_data_chan)); @@ -186,7 +187,6 @@ int main(void) acc.x += 1; acc.y += 10; acc.z += 100; - k_msleep(1000); } diff --git a/samples/subsys/zbus/priority_boost/CMakeLists.txt b/samples/subsys/zbus/priority_boost/CMakeLists.txt new file mode 100644 index 00000000000..f2d9b727321 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(priority_boost) + +file(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/subsys/zbus/priority_boost/README.rst b/samples/subsys/zbus/priority_boost/README.rst new file mode 100644 index 00000000000..ca903a7183c --- /dev/null +++ b/samples/subsys/zbus/priority_boost/README.rst @@ -0,0 +1,197 @@ +.. zephyr:code-sample:: zbus-priority-boost + :name: zbus Priority Boost + :relevant-api: zbus_apis + + Illustrates zbus priority boost feature with a priority inversion scenario. + +Overview +******** +This sample implements a simple application that illustrates the priority boost feature. The +application implements the below figure scenario. When the priority boost feature is disabled, the +execution sequence presents a priority inversion problem, which may not affect much of the +developer's application. Those who want to avoid priority inversions between message subscribers and +plain subscribers should use the priority boost strategy. + +.. code-block:: c + + ZBUS_CHAN_DEFINE(chan_a, + int, + NULL, + NULL, + ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), + 0 + ); + + +.. figure:: zbus_publishing_process_example_scenario.svg + :alt: ZBus priority boost scenario example. + :width: 45% + +.. note:: + + The developer must use the :c:func:`zbus_obs_attach_to_thread` function to ensure a proper + priority boost execution. + + +Building and Running +******************** + +The figure below illustrates the execution of the cited scenario but with the priority boost +disabled. + +.. figure:: without_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost disabled. + :width: 70% + + +It can be built and executed on QEMU as follows: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=n + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 ---> L2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 ---> L2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 5 + I: 2 -> MS1: T1 prio 5 + I: 2 ---> L2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: 2 -> MS2: T1 prio 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 5 + I: 3 -> MS1: T1 prio 5 + I: 3 ---> L2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: 3 -> MS2: T1 prio 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 5 + I: 4 ---> L2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: 4 -> MS2: T1 prio 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 5 + I: 5 ---> L2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: 5 -> MS2: T1 prio 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 ---> L2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + + +The figure below illustrates the execution of the same scenario but with the priority boost enabled. +The developer must enable the priority boost and properly attach all the observers to their threads. + +.. figure:: with_hlp_priority_boost_feature.svg + :alt: ZBus example scenario for priority boost enabled. + :width: 75% + +To execute the sample with priority boost feature enabled, run the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/zbus/priority_boost -- -DCONFIG_ZBUS_PRIORITY_BOOST=y + :host-os: unix + :board: qemu_x86 + :goals: run + +Sample Output +============= + +.. code-block:: console + + I: -------------- + I: 0 -> T1: prio before 5 + I: 0 ---> L1: T1 prio 1 + I: 0 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 0 -> S1: T1 prio 5 + I: 0 -> MS1: T1 prio 5 + I: 0 -> MS2: T1 prio 5 + I: 0 -> T1: prio after 5 + I: -------------- + I: 1 -> T1: prio before 5 + I: 1 ---> L1: T1 prio 1 + I: 1 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 1 -> S1: T1 prio 5 + I: 1 -> MS1: T1 prio 5 + I: 1 -> MS2: T1 prio 5 + I: 1 -> T1: prio after 5 + I: -------------- + I: 2 -> T1: prio before 5 + I: 2 ---> L1: T1 prio 2 + I: 2 ---> L2: T1 prio 2 + I: 2 -> MS1: T1 prio 5 + I: 2 -> MS2: T1 prio 5 + I: 2 -> T1: prio after 5 + I: -------------- + I: 3 -> T1: prio before 5 + I: 3 ---> L1: T1 prio 2 + I: 3 ---> L2: T1 prio 2 + I: 3 -> MS1: T1 prio 5 + I: 3 -> MS2: T1 prio 5 + I: 3 -> T1: prio after 5 + I: -------------- + I: 4 -> T1: prio before 5 + I: 4 ---> L1: T1 prio 3 + I: 4 ---> L2: T1 prio 3 + I: 4 -> MS2: T1 prio 5 + I: 4 -> T1: prio after 5 + I: -------------- + I: 5 -> T1: prio before 5 + I: 5 ---> L1: T1 prio 3 + I: 5 ---> L2: T1 prio 3 + I: 5 -> MS2: T1 prio 5 + I: 5 -> T1: prio after 5 + I: -------------- + I: 6 -> T1: prio before 5 + I: 6 ---> L1: T1 prio 1 + I: 6 ---> L2: T1 prio 1 + I: N -> S1: T1 prio 5 + I: 6 -> S1: T1 prio 5 + I: 6 -> MS1: T1 prio 5 + I: 6 -> MS2: T1 prio 5 + I: 6 -> T1: prio after 5 + I: -------------- + + + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. diff --git a/samples/subsys/zbus/priority_boost/prj.conf b/samples/subsys/zbus/priority_boost/prj.conf new file mode 100644 index 00000000000..67af0befda1 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/prj.conf @@ -0,0 +1,6 @@ +CONFIG_LOG=y +CONFIG_LOG_MODE_MINIMAL=y +CONFIG_ZBUS_LOG_LEVEL_INF=y +CONFIG_ZBUS=y +CONFIG_ZBUS_MSG_SUBSCRIBER=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 diff --git a/samples/subsys/zbus/priority_boost/sample.yaml b/samples/subsys/zbus/priority_boost/sample.yaml new file mode 100644 index 00000000000..5bbdc772030 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/sample.yaml @@ -0,0 +1,81 @@ +sample: + name: Priority boost +tests: + sample.zbus.non_priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 5" + - "I: 0 ---> L2: T1 prio 5" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 5" + - "I: 1 ---> L2: T1 prio 5" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 5" + - "I: 2 ---> L2: T1 prio 5" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 5" + - "I: 3 ---> L2: T1 prio 5" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 5" + - "I: 4 ---> L2: T1 prio 5" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 5" + - "I: 5 ---> L2: T1 prio 5" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 5" + - "I: 6 ---> L2: T1 prio 5" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=n + tags: zbus + integration_platforms: + - qemu_x86 + sample.zbus.priority_boost: + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "I: 0 -> T1: prio before 5" + - "I: 0 ---> L1: T1 prio 1" + - "I: 0 ---> L2: T1 prio 1" + - "I: 0 -> T1: prio after 5" + - "I: 1 -> T1: prio before 5" + - "I: 1 ---> L1: T1 prio 1" + - "I: 1 ---> L2: T1 prio 1" + - "I: 1 -> T1: prio after 5" + - "I: 2 -> T1: prio before 5" + - "I: 2 ---> L1: T1 prio 2" + - "I: 2 ---> L2: T1 prio 2" + - "I: 2 -> T1: prio after 5" + - "I: 3 -> T1: prio before 5" + - "I: 3 ---> L1: T1 prio 2" + - "I: 3 ---> L2: T1 prio 2" + - "I: 3 -> T1: prio after 5" + - "I: 4 -> T1: prio before 5" + - "I: 4 ---> L1: T1 prio 3" + - "I: 4 ---> L2: T1 prio 3" + - "I: 4 -> T1: prio after 5" + - "I: 5 -> T1: prio before 5" + - "I: 5 ---> L1: T1 prio 3" + - "I: 5 ---> L2: T1 prio 3" + - "I: 5 -> T1: prio after 5" + - "I: 6 -> T1: prio before 5" + - "I: 6 ---> L1: T1 prio 1" + - "I: 6 ---> L2: T1 prio 1" + - "I: 6 -> T1: prio after 5" + extra_configs: + - CONFIG_ZBUS_PRIORITY_BOOST=y + tags: zbus + integration_platforms: + - qemu_x86 diff --git a/samples/subsys/zbus/priority_boost/src/main.c b/samples/subsys/zbus/priority_boost/src/main.c new file mode 100644 index 00000000000..b54a44468c2 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/src/main.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2023 Rodrigo Peixoto + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +LOG_MODULE_DECLARE(zbus, CONFIG_ZBUS_LOG_LEVEL); + +ZBUS_CHAN_DEFINE(chan_a, int, NULL, NULL, ZBUS_OBSERVERS(l1, ms1, ms2, s1, l2), 0); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3); +K_THREAD_DEFINE(t1_id, CONFIG_MAIN_STACK_SIZE, t1_thread, NULL, NULL, NULL, 5, 0, 0); + +ZBUS_SUBSCRIBER_DEFINE(s1, 4); +static void s1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + const struct zbus_channel *chan; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&s1);)); + + while (1) { + err = zbus_sub_wait(&s1, &chan, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("N -> S1: T1 prio %d", k_thread_priority_get(t1_id)); + + err = zbus_chan_read(chan, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> S1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(s1_id, CONFIG_MAIN_STACK_SIZE, s1_thread, NULL, NULL, NULL, 2, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms1); +static void ms1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms1);)); + + while (1) { + err = zbus_sub_wait_msg(&ms1, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200000); + + LOG_INF("%d -> MS1: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms1_id, CONFIG_MAIN_STACK_SIZE, ms1_thread, NULL, NULL, NULL, 3, 0, 0); + +ZBUS_MSG_SUBSCRIBER_DEFINE(ms2); +static void ms2_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + const struct zbus_channel *chan; + int a = 0; + + IF_ENABLED(CONFIG_ZBUS_PRIORITY_BOOST, (zbus_obs_attach_to_thread(&ms2);)); + + while (1) { + err = zbus_sub_wait_msg(&ms2, &chan, &a, K_FOREVER); + if (err) { + return; + } + + /* Faking some workload */ + k_busy_wait(200 * USEC_PER_MSEC); + + LOG_INF("%d -> MS2: T1 prio %d", a, k_thread_priority_get(t1_id)); + } +} +K_THREAD_DEFINE(ms2_id, CONFIG_MAIN_STACK_SIZE, ms2_thread, NULL, NULL, NULL, 4, 0, 0); + +static void l1_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L1: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l1, l1_callback); + +static void l2_callback(const struct zbus_channel *chan) +{ + LOG_INF("%d ---> L2: T1 prio %d", *((int *)zbus_chan_const_msg(chan)), + k_thread_priority_get(t1_id)); +} +ZBUS_LISTENER_DEFINE(l2, l2_callback); + +static void t1_thread(void *ptr1, void *ptr2, void *ptr3) +{ + ARG_UNUSED(ptr1); + ARG_UNUSED(ptr2); + ARG_UNUSED(ptr3); + + int err; + int a = 0; + + while (1) { + LOG_INF("--------------"); + + if (a == 2) { + zbus_obs_set_enable(&s1, false); + } else if (a == 4) { + zbus_obs_set_enable(&ms1, false); + } else if (a == 6) { + zbus_obs_set_enable(&s1, true); + zbus_obs_set_enable(&ms1, true); + } + + LOG_INF("%d -> T1: prio before %d", a, k_thread_priority_get(k_current_get())); + err = zbus_chan_pub(&chan_a, &a, K_FOREVER); + if (err) { + return; + } + LOG_INF("%d -> T1: prio after %d", a, k_thread_priority_get(k_current_get())); + ++a; + + k_msleep(2000); + } +} diff --git a/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg new file mode 100644 index 00000000000..e1c58da9b28 --- /dev/null +++ b/samples/subsys/zbus/priority_boost/with_hlp_priority_boost_feature.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg new file mode 100644 index 00000000000..c912344567a --- /dev/null +++ b/samples/subsys/zbus/priority_boost/without_hlp_priority_boost_feature.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg new file mode 100644 index 00000000000..bf2df426e3a --- /dev/null +++ b/samples/subsys/zbus/priority_boost/zbus_publishing_process_example_scenario.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/tfm_integration/psa_crypto/CMakeLists.txt b/samples/tfm_integration/psa_crypto/CMakeLists.txt index 17339b470b8..f8ef1eca23f 100644 --- a/samples/tfm_integration/psa_crypto/CMakeLists.txt +++ b/samples/tfm_integration/psa_crypto/CMakeLists.txt @@ -16,7 +16,7 @@ target_sources(app PRIVATE src/util_app_log.c) target_sources(app PRIVATE src/util_sformat.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) # In TF-M, default value of CRYPTO_ENGINE_BUF_SIZE is 0x2080. It causes diff --git a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt index bbb8a2041fd..dfb0169eda6 100644 --- a/samples/tfm_integration/psa_protected_storage/CMakeLists.txt +++ b/samples/tfm_integration/psa_protected_storage/CMakeLists.txt @@ -13,5 +13,5 @@ project(protected_storage) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) diff --git a/samples/tfm_integration/tfm_ipc/CMakeLists.txt b/samples/tfm_integration/tfm_ipc/CMakeLists.txt index f11b67af843..896af7bfbda 100644 --- a/samples/tfm_integration/tfm_ipc/CMakeLists.txt +++ b/samples/tfm_integration/tfm_ipc/CMakeLists.txt @@ -9,5 +9,5 @@ project(tfm_ipc) target_sources(app PRIVATE src/main.c) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) diff --git a/samples/tfm_integration/tfm_ipc/src/main.c b/samples/tfm_integration/tfm_ipc/src/main.c index 7179705cbe3..133c7203b0e 100644 --- a/samples/tfm_integration/tfm_ipc/src/main.c +++ b/samples/tfm_integration/tfm_ipc/src/main.c @@ -7,7 +7,6 @@ #include #include -#include "tfm_api.h" #include "tfm_ns_interface.h" #ifdef TFM_PSA_API #include "psa_manifest/sid.h" diff --git a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt index 9dcbf12ae64..0d11c021627 100644 --- a/samples/tfm_integration/tfm_psa_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_psa_test/CMakeLists.txt @@ -8,10 +8,103 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(tfm_psa_storage_test) +project(tfm_psa_arch_test) target_sources(app PRIVATE src/main.c) -target_include_directories(app PRIVATE - $/install/interface/include +get_target_property(TFM_BINARY_DIR tfm TFM_BINARY_DIR) +get_target_property(TFM_NS_BIN_FILE tfm TFM_NS_BIN_FILE) +get_target_property(TFM_NS_HEX_FILE tfm TFM_NS_HEX_FILE) +get_target_property(TFM_NS_SIGNED_BIN_FILE tfm TFM_NS_SIGNED_BIN_FILE) + +get_target_property(TFM_TOOLCHAIN_PATH tfm TFM_TOOLCHAIN_PATH) +get_target_property(TFM_TOOLCHAIN_PREFIX tfm TFM_TOOLCHAIN_PREFIX) +get_target_property(TFM_TOOLCHAIN_NS_FILE tfm TFM_TOOLCHAIN_NS_FILE) + +set(TFM_TEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../tf-m-tests) +set(TFM_PSA_ARCHTEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../psa-arch-tests) + +if (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION AND CONFIG_TFM_QCBOR_PATH STREQUAL "") +# TODO: Remove this when QCBOR licensing issues w/t_cose have been resolved, +# or only allow it when 'QCBOR_PATH' is set to a local path where QCBOR has +# been manually downloaded by the user before starting the build. +message(FATAL_ERROR "CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION is not available " + "with TF-M 2.0.0 due to licensing issues with a dependent library. This " + "restriction will be removed once licensing issues have been resolved." + ) +endif() + + +set(TFM_TEST_DIR "${TFM_TEST_REPO_PATH}/tests_psa_arch/spe/partitions") +set(PSA_ARCH_TESTS_CONFIG_FILE "${TFM_TEST_REPO_PATH}/tests_psa_arch/spe/config/config_test_psa_api.cmake") +if (CONFIG_TFM_PSA_TEST_CRYPTO) +set(TFM_PSA_TEST_SUITE CRYPTO) +elseif (CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE) +set(TFM_PSA_TEST_SUITE PROTECTED_STORAGE) +elseif (CONFIG_TFM_PSA_TEST_INTERNAL_TRUSTED_STORAGE) +set(TFM_PSA_TEST_SUITE INTERNAL_TRUSTED_STORAGE) +elseif (CONFIG_TFM_PSA_TEST_STORAGE) +set(TFM_PSA_TEST_SUITE STORAGE) +elseif (CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION) +set(TFM_PSA_TEST_SUITE INITIAL_ATTESTATION) +endif() + +if (NOT DEFINED TFM_PSA_TEST_SUITE) + message(FATAL_ERROR "Please define witch test suite to run: + CONFIG_TFM_PSA_TEST_CRYPTO + CONFIG_TFM_PSA_TEST_PROTECTED_STORAGE + CONFIG_TFM_PSA_TEST_STORAGE + CONFIG_TFM_PSA_TEST_INITIAL_ATTESTATION") +endif() +set(TEST_PSA_API "${TFM_PSA_TEST_SUITE}") + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DPSA_ARCH_TESTS_PATH=${TFM_PSA_ARCHTEST_REPO_PATH} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_DIR=${TFM_TEST_DIR} ) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_PSA_ARCH_TESTS_CONFIG_FILE=${PSA_ARCH_TESTS_CONFIG_FILE} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DTEST_PSA_API=${TEST_PSA_API} +) + +include(ExternalProject) + +ExternalProject_Add(tfm_psa_arch_test_app + SOURCE_DIR ${TFM_TEST_REPO_PATH}/tests_psa_arch + BINARY_DIR ${PROJECT_BINARY_DIR}/tfm_ns + CONFIGURE_COMMAND + ${CMAKE_COMMAND} + -G ${CMAKE_GENERATOR} + -S ${TFM_TEST_REPO_PATH}/tests_psa_arch + -B ${PROJECT_BINARY_DIR}/tfm_ns + -DCROSS_COMPILE=${TFM_TOOLCHAIN_PATH}/${TFM_TOOLCHAIN_PREFIX} + -DPSA_TOOLCHAIN_FILE=${TFM_BINARY_DIR}/api_ns/cmake/${TFM_TOOLCHAIN_NS_FILE} + -DCONFIG_SPE_PATH=${TFM_BINARY_DIR}/api_ns + -DTFM_TOOLCHAIN_FILE=cmake/${TFM_TOOLCHAIN_NS_FILE} + -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH} + -DCMAKE_BUILD_TYPE=RelWithDebInfo + -DTEST_PSA_API=${TEST_PSA_API} + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND "" + BUILD_ALWAYS True + USES_TERMINAL_BUILD True + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tfm_ns + DEPENDS tfm + BUILD_BYPRODUCTS + ${TFM_NS_HEX_FILE} + ${TFM_NS_BIN_FILE} + ${TFM_NS_SIGNED_BIN_FILE} +) + +add_dependencies(app tfm_psa_arch_test_app) diff --git a/samples/tfm_integration/tfm_psa_test/prj.conf b/samples/tfm_integration/tfm_psa_test/prj.conf index 3ceca574528..bab1254229d 100644 --- a/samples/tfm_integration/tfm_psa_test/prj.conf +++ b/samples/tfm_integration/tfm_psa_test/prj.conf @@ -5,9 +5,10 @@ # CONFIG_BUILD_WITH_TFM=y -CONFIG_TFM_BUILD_NS=y CONFIG_TFM_PROFILE_TYPE_NOT_SET=y +CONFIG_TFM_USE_NS_APP=y CONFIG_QEMU_ICOUNT_SHIFT=1 + # Needed for CRYPTO and INITIAL_ATTESTATION CONFIG_MAIN_STACK_SIZE=4096 diff --git a/samples/tfm_integration/tfm_psa_test/src/main.c b/samples/tfm_integration/tfm_psa_test/src/main.c index 232fc505cfd..9d2809fe269 100644 --- a/samples/tfm_integration/tfm_psa_test/src/main.c +++ b/samples/tfm_integration/tfm_psa_test/src/main.c @@ -1,21 +1,15 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA. + * Copyright (c) 2023 Nordic Semiconductor ASA. * * SPDX-License-Identifier: Apache-2.0 */ #include -/* Run the PSA test suite */ -void psa_test(void); - int main(void) { -#ifdef CONFIG_TFM_PSA_TEST_NONE - #error "No PSA test suite set. Use Kconfig to enable a test suite.\n" -#else - psa_test(); -#endif + printk("Should not be printed, expected TF-M's NS application to be run instead.\n"); + k_panic(); for (;;) { } diff --git a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt index 5f34b1c0b26..b86eebc4a81 100644 --- a/samples/tfm_integration/tfm_regression_test/CMakeLists.txt +++ b/samples/tfm_integration/tfm_regression_test/CMakeLists.txt @@ -11,3 +11,56 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(tfm_regression_test) target_sources(app PRIVATE src/main.c) + +get_target_property(TFM_BINARY_DIR tfm TFM_BINARY_DIR) +get_target_property(TFM_NS_BIN_FILE tfm TFM_NS_BIN_FILE) +get_target_property(TFM_NS_HEX_FILE tfm TFM_NS_HEX_FILE) +get_target_property(TFM_NS_SIGNED_BIN_FILE tfm TFM_NS_SIGNED_BIN_FILE) + +get_target_property(TFM_TOOLCHAIN_PATH tfm TFM_TOOLCHAIN_PATH) +get_target_property(TFM_TOOLCHAIN_PREFIX tfm TFM_TOOLCHAIN_PREFIX) +get_target_property(TFM_TOOLCHAIN_NS_FILE tfm TFM_TOOLCHAIN_NS_FILE) + +set(TFM_TEST_REPO_PATH ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/../tf-m-tests) + +set(TFM_TEST_DIR "${TFM_TEST_REPO_PATH}/tests_reg/test/secure_regression") +set(TFM_TEST_CONFIG_FILE "${TFM_TEST_REPO_PATH}/tests_reg/test/config/config.cmake") + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_DIR=${TFM_TEST_DIR} +) + +set_property(TARGET zephyr_property_target + APPEND PROPERTY TFM_CMAKE_OPTIONS + -DCONFIG_TFM_TEST_CONFIG_FILE=${TFM_TEST_CONFIG_FILE} +) + +include(ExternalProject) + +ExternalProject_Add(tfm_regression_test_app + SOURCE_DIR ${TFM_TEST_REPO_PATH}/tests_reg + BINARY_DIR ${PROJECT_BINARY_DIR}/tfm_ns + CONFIGURE_COMMAND + ${CMAKE_COMMAND} + -G ${CMAKE_GENERATOR} + -S ${TFM_TEST_REPO_PATH}/tests_reg + -B ${PROJECT_BINARY_DIR}/tfm_ns + -DCONFIG_SPE_PATH=${TFM_BINARY_DIR}/api_ns + -DTFM_TOOLCHAIN_FILE=cmake/${TFM_TOOLCHAIN_NS_FILE} + -DCROSS_COMPILE=${TFM_TOOLCHAIN_PATH}/${TFM_TOOLCHAIN_PREFIX} + -DQCBOR_PATH${QCBOR_PATH_TYPE}=${CONFIG_TFM_QCBOR_PATH} + -DCMAKE_BUILD_TYPE=RelWithDebInfo + BUILD_COMMAND ${CMAKE_COMMAND} --build . + INSTALL_COMMAND "" + BUILD_ALWAYS True + USES_TERMINAL_BUILD True + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tfm_ns + DEPENDS tfm + BUILD_BYPRODUCTS + ${TFM_NS_HEX_FILE} + ${TFM_NS_BIN_FILE} + ${TFM_NS_SIGNED_BIN_FILE} +) + +add_dependencies(app tfm_regression_test_app) diff --git a/samples/tfm_integration/tfm_regression_test/prj.conf b/samples/tfm_integration/tfm_regression_test/prj.conf index 6817a7f717b..0a6573f811c 100644 --- a/samples/tfm_integration/tfm_regression_test/prj.conf +++ b/samples/tfm_integration/tfm_regression_test/prj.conf @@ -6,7 +6,6 @@ CONFIG_BUILD_WITH_TFM=y CONFIG_TFM_PROFILE_TYPE_NOT_SET=y -CONFIG_TFM_BUILD_NS=y CONFIG_TFM_USE_NS_APP=y CONFIG_TFM_REGRESSION_S=y CONFIG_TFM_REGRESSION_NS=y diff --git a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt index 69901f73928..beadae9230a 100644 --- a/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/CMakeLists.txt @@ -28,7 +28,7 @@ target_sources(app PRIVATE ) target_include_directories(app PRIVATE - $/install/interface/include + $/api_ns/interface/include ) target_compile_definitions(app diff --git a/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt b/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt index 0e335a73028..013332ccb1a 100644 --- a/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt +++ b/samples/tfm_integration/tfm_secure_partition/dummy_partition/CMakeLists.txt @@ -50,7 +50,7 @@ target_link_libraries(tfm_partitions tfm_app_rot_partition_dp ) -target_compile_definitions(tfm_partition_defs +target_compile_definitions(tfm_config INTERFACE TFM_PARTITION_DUMMY_PARTITION ) diff --git a/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c b/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c index 6519723058c..d618868ddbf 100644 --- a/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c +++ b/samples/tfm_integration/tfm_secure_partition/dummy_partition/dummy_partition.c @@ -7,7 +7,6 @@ #include #include #include -#include "tfm_api.h" #include "psa/service.h" #include "psa_manifest/tfm_dummy_partition.h" diff --git a/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h b/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h index b31ce897d27..7ca52b3c5c4 100644 --- a/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h +++ b/samples/tfm_integration/tfm_secure_partition/src/dummy_partition.h @@ -4,8 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "tfm_api.h" - psa_status_t dp_secret_digest(uint32_t secret_index, void *p_digest, size_t digest_size); diff --git a/samples/userspace/hello_world_user/sample.yaml b/samples/userspace/hello_world_user/sample.yaml index f782f36cad4..b40042f71f5 100644 --- a/samples/userspace/hello_world_user/sample.yaml +++ b/samples/userspace/hello_world_user/sample.yaml @@ -16,4 +16,6 @@ tests: filter: CONFIG_ARCH_HAS_USERSPACE arch_exclude: - posix + platform_exclude: + - qemu_xtensa_mmu tags: introduction diff --git a/samples/userspace/hello_world_user/src/main.c b/samples/userspace/hello_world_user/src/main.c index 0a2b724117e..3223d4a1a27 100644 --- a/samples/userspace/hello_world_user/src/main.c +++ b/samples/userspace/hello_world_user/src/main.c @@ -8,6 +8,10 @@ #include #define USER_STACKSIZE 2048 +#ifndef CONFIG_USERSPACE +#error This sample requires CONFIG_USERSPACE. +#endif + struct k_thread user_thread; K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); diff --git a/samples/userspace/prod_consumer/sample.yaml b/samples/userspace/prod_consumer/sample.yaml index cc4aaa5d118..232fdd31f06 100644 --- a/samples/userspace/prod_consumer/sample.yaml +++ b/samples/userspace/prod_consumer/sample.yaml @@ -15,3 +15,5 @@ tests: filter: CONFIG_ARCH_HAS_USERSPACE arch_exclude: - posix + platform_exclude: + - ucans32k1sic diff --git a/samples/userspace/shared_mem/sample.yaml b/samples/userspace/shared_mem/sample.yaml index 954b6a9d3d6..5b42ae2b7e3 100644 --- a/samples/userspace/shared_mem/sample.yaml +++ b/samples/userspace/shared_mem/sample.yaml @@ -20,5 +20,6 @@ tests: - twr_ke18f - cy8cproto_062_4343w - cy8cproto_063_ble + - ucans32k1sic extra_configs: - CONFIG_TEST_HW_STACK_PROTECTION=n diff --git a/samples/userspace/syscall_perf/prj.conf b/samples/userspace/syscall_perf/prj.conf index c16c800cc93..08f8fc9aaf7 100644 --- a/samples/userspace/syscall_perf/prj.conf +++ b/samples/userspace/syscall_perf/prj.conf @@ -1,5 +1,4 @@ CONFIG_USERSPACE=y -CONFIG_APPLICATION_DEFINED_SYSCALL=y CONFIG_ASSERT=y CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y diff --git a/scripts/build/elf_parser.py b/scripts/build/elf_parser.py index bd7a970431c..101e61dbadf 100644 --- a/scripts/build/elf_parser.py +++ b/scripts/build/elf_parser.py @@ -24,6 +24,9 @@ def __init__(self, elf, sym): self.sym = sym self.data = self.elf.symbol_data(sym) + def __lt__(self, other): + return self.sym.entry.st_value < other.sym.entry.st_value + def _data_native_read(self, offset): (format, size) = self.elf.native_struct_format return struct.unpack(format, self.data[offset:offset + size])[0] @@ -238,8 +241,8 @@ def _on_device(sym): self.devices.append(Device(self, sym)) self._object_find_named('__device_', _on_device) - # Sort the device array by address for handle calculation - self.devices = sorted(self.devices, key = lambda k: k.sym.entry.st_value) + # Sort the device array by address (st_value) for handle calculation + self.devices = sorted(self.devices) # Assign handles to the devices for idx, dev in enumerate(self.devices): @@ -280,6 +283,6 @@ def device_dependency_graph(self, title, comment): ) dot.node(str(dev.ordinal), text) for dev in self.devices: - for sup in dev.devs_supports: + for sup in sorted(dev.devs_supports): dot.edge(str(dev.ordinal), str(sup.ordinal)) return dot diff --git a/scripts/build/gen_isr_tables.py b/scripts/build/gen_isr_tables.py index cd329f85551..84812d708e8 100755 --- a/scripts/build/gen_isr_tables.py +++ b/scripts/build/gen_isr_tables.py @@ -2,118 +2,280 @@ # # Copyright (c) 2017 Intel Corporation # Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA # # SPDX-License-Identifier: Apache-2.0 # import argparse -import struct import sys import os +import importlib from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection -ISR_FLAG_DIRECT = 1 << 0 - -# The below few hardware independent magic numbers represent various -# levels of interrupts in a multi-level interrupt system. -# 0x000000FF - represents the 1st level (i.e. the interrupts -# that directly go to the processor). -# 0x0000FF00 - represents the 2nd level (i.e. the interrupts funnel -# into 1 line which then goes into the 1st level) -# 0x00FF0000 - represents the 3rd level (i.e. the interrupts funnel -# into 1 line which then goes into the 2nd level) -FIRST_LVL_INTERRUPTS = 0x000000FF -SECND_LVL_INTERRUPTS = 0x0000FF00 -THIRD_LVL_INTERRUPTS = 0x00FF0000 - -INTERRUPT_BITS = [8, 8, 8] - -def debug(text): - if args.debug: - sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") - -def error(text): - sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") - -def endian_prefix(): - if args.big_endian: - return ">" - else: - return "<" - -def read_intlist(elfobj, syms, snames): - """read a binary file containing the contents of the kernel's .intList - section. This is an instance of a header created by - include/zephyr/linker/intlist.ld: - - struct { - uint32_t num_vectors; <- typically CONFIG_NUM_IRQS - struct _isr_list isrs[]; <- Usually of smaller size than num_vectors - } - - Followed by instances of struct _isr_list created by IRQ_CONNECT() - calls: - - struct _isr_list { - /** IRQ line number */ - int32_t irq; - /** Flags for this IRQ, see ISR_FLAG_* definitions */ - int32_t flags; - /** ISR to call */ - void *func; - /** Parameter for non-direct IRQs */ - const void *param; - }; - """ - intList_sect = None - intlist = {} - prefix = endian_prefix() +class gen_isr_log: - intlist_header_fmt = prefix + "II" - if "CONFIG_64BIT" in syms: - intlist_entry_fmt = prefix + "iiQQ" - else: - intlist_entry_fmt = prefix + "iiII" + def __init__(self, debug = False): + self.__debug = debug - for sname in snames: - intList_sect = elfobj.get_section_by_name(sname) - if intList_sect is not None: - debug("Found intlist section: \"{}\"".format(sname)) - break + def debug(self, text): + """Print debug message if debugging is enabled. - if intList_sect is None: - error("Cannot find the intlist section!") + Note - this function requires config global variable to be initialized. + """ + if self.__debug: + sys.stdout.write(os.path.basename(sys.argv[0]) + ": " + text + "\n") - intdata = intList_sect.data() + @staticmethod + def error(text): + sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") - header_sz = struct.calcsize(intlist_header_fmt) - header = struct.unpack_from(intlist_header_fmt, intdata, 0) - intdata = intdata[header_sz:] + def set_debug(self, state): + self.__debug = state - debug(str(header)) - intlist["num_vectors"] = header[0] - intlist["offset"] = header[1] +log = gen_isr_log() - intlist["interrupts"] = [i for i in - struct.iter_unpack(intlist_entry_fmt, intdata)] - debug("Configured interrupt routing") - debug("handler irq flags param") - debug("--------------------------") +class gen_isr_config: + """All the constants and configuration gathered in single class for readability. + """ + # Constants + __ISR_FLAG_DIRECT = 1 << 0 + __swt_spurious_handler = "z_irq_spurious" + __swt_shared_handler = "z_shared_isr" + __vt_spurious_handler = "z_irq_spurious" + __vt_irq_handler = "_isr_wrapper" + __shared_array_name = "z_shared_sw_isr_table" + __sw_isr_array_name = "_sw_isr_table" + __irq_vector_array_name = "_irq_vector_table" + + @staticmethod + def __bm(bits): + return (1 << bits) - 1 + + def __init__(self, args, syms, log): + """Initialize the configuration object. + + The configuration object initialization takes only arguments as a parameter. + This is done to allow debug function work as soon as possible. + """ + # Store the arguments required for work + self.__args = args + self.__syms = syms + self.__log = log + + # Select the default interrupt vector handler + if self.args.sw_isr_table: + self.__vt_default_handler = self.__vt_irq_handler + else: + self.__vt_default_handler = self.__vt_spurious_handler + # Calculate interrupt bits + self.__int_bits = [8, 8, 8] + # The below few hardware independent magic numbers represent various + # levels of interrupts in a multi-level interrupt system. + # 0x000000FF - represents the 1st level (i.e. the interrupts + # that directly go to the processor). + # 0x0000FF00 - represents the 2nd level (i.e. the interrupts funnel + # into 1 line which then goes into the 1st level) + # 0x00FF0000 - represents the 3rd level (i.e. the interrupts funnel + # into 1 line which then goes into the 2nd level) + self.__int_lvl_masks = [0x000000FF, 0x0000FF00, 0x00FF0000] + + self.__irq2_baseoffset = None + self.__irq3_baseoffset = None + self.__irq2_offsets = None + self.__irq3_offsets = None + + if self.check_multi_level_interrupts(): + self.__max_irq_per = self.get_sym("CONFIG_MAX_IRQ_PER_AGGREGATOR") + + self.__int_bits[0] = self.get_sym("CONFIG_1ST_LEVEL_INTERRUPT_BITS") + self.__int_bits[1] = self.get_sym("CONFIG_2ND_LEVEL_INTERRUPT_BITS") + self.__int_bits[2] = self.get_sym("CONFIG_3RD_LEVEL_INTERRUPT_BITS") + + if sum(self.int_bits) > 32: + raise ValueError("Too many interrupt bits") + + self.__int_lvl_masks[0] = self.__bm(self.int_bits[0]) + self.__int_lvl_masks[1] = self.__bm(self.int_bits[1]) << self.int_bits[0] + self.__int_lvl_masks[2] = self.__bm(self.int_bits[2]) << (self.int_bits[0] + self.int_bits[1]) + + self.__log.debug("Level Bits Bitmask") + self.__log.debug("----------------------------") + for i in range(3): + bitmask_str = "0x" + format(self.__int_lvl_masks[i], '08X') + self.__log.debug(f"{i + 1:>5} {self.__int_bits[i]:>7} {bitmask_str:>14}") + + if self.check_sym("CONFIG_2ND_LEVEL_INTERRUPTS"): + num_aggregators = self.get_sym("CONFIG_NUM_2ND_LEVEL_AGGREGATORS") + self.__irq2_baseoffset = self.get_sym("CONFIG_2ND_LVL_ISR_TBL_OFFSET") + self.__irq2_offsets = [self.get_sym('CONFIG_2ND_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))) for i in + range(num_aggregators)] + + self.__log.debug('2nd level offsets: {}'.format(self.__irq2_offsets)) + + if self.check_sym("CONFIG_3RD_LEVEL_INTERRUPTS"): + num_aggregators = self.get_sym("CONFIG_NUM_3RD_LEVEL_AGGREGATORS") + self.__irq3_baseoffset = self.get_sym("CONFIG_3RD_LVL_ISR_TBL_OFFSET") + self.__irq3_offsets = [self.get_sym('CONFIG_3RD_LVL_INTR_{}_OFFSET'. + format(str(i).zfill(2))) for i in + range(num_aggregators)] + + self.__log.debug('3rd level offsets: {}'.format(self.__irq3_offsets)) + + @property + def args(self): + return self.__args + + @property + def swt_spurious_handler(self): + return self.__swt_spurious_handler + + @property + def swt_shared_handler(self): + return self.__swt_shared_handler + + @property + def vt_default_handler(self): + return self.__vt_default_handler + + @property + def shared_array_name(self): + return self.__shared_array_name + + @property + def sw_isr_array_name(self): + return self.__sw_isr_array_name + + @property + def irq_vector_array_name(self): + return self.__irq_vector_array_name + + @property + def int_bits(self): + return self.__int_bits + + @property + def int_lvl_masks(self): + return self.__int_lvl_masks + + def endian_prefix(self): + if self.args.big_endian: + return ">" + else: + return "<" + + def get_irq_baseoffset(self, lvl): + if lvl == 2: + return self.__irq2_baseoffset + if lvl == 3: + return self.__irq3_baseoffset + self.__log.error("Unsupported irq level: {}".format(lvl)) + + def get_irq_index(self, irq, lvl): + if lvl == 2: + offsets = self.__irq2_offsets + elif lvl == 3: + offsets = self.__irq3_offsets + else: + self.__log.error("Unsupported irq level: {}".format(lvl)) + try: + return offsets.index(irq) + except ValueError: + self.__log.error("IRQ {} not present in parent offsets ({}). ". + format(irq, offsets) + + " Recheck interrupt configuration.") + + def get_swt_table_index(self, offset, irq): + if not self.check_multi_level_interrupts(): + return irq - offset + # Calculate index for multi level interrupts + self.__log.debug('IRQ = ' + hex(irq)) + irq3 = (irq & self.int_lvl_masks[2]) >> (self.int_bits[0] + self.int_bits[1]) + irq2 = (irq & self.int_lvl_masks[1]) >> (self.int_bits[0]) + irq1 = irq & self.int_lvl_masks[0] + # Figure out third level interrupt position + if irq3: + list_index = self.get_irq_index(irq2, 3) + irq3_pos = self.get_irq_baseoffset(3) + self.__max_irq_per * list_index + irq3 - 1 + self.__log.debug('IRQ_level = 3') + self.__log.debug('IRQ_Indx = ' + str(irq3)) + self.__log.debug('IRQ_Pos = ' + str(irq3_pos)) + return irq3_pos - offset + # Figure out second level interrupt position + if irq2: + list_index = self.get_irq_index(irq1, 2) + irq2_pos = self.get_irq_baseoffset(2) + self.__max_irq_per * list_index + irq2 - 1 + self.__log.debug('IRQ_level = 2') + self.__log.debug('IRQ_Indx = ' + str(irq2)) + self.__log.debug('IRQ_Pos = ' + str(irq2_pos)) + return irq2_pos - offset + # Figure out first level interrupt position + self.__log.debug('IRQ_level = 1') + self.__log.debug('IRQ_Indx = ' + str(irq1)) + self.__log.debug('IRQ_Pos = ' + str(irq1)) + return irq1 - offset + + def get_intlist_snames(self): + return self.args.intlist_section + + def test_isr_direct(self, flags): + return flags & self.__ISR_FLAG_DIRECT + + def get_sym_from_addr(self, addr): + for key, value in self.__syms.items(): + if addr == value: + return key + return None + + def get_sym(self, name): + return self.__syms.get(name) + + def check_sym(self, name): + return name in self.__syms + + def check_multi_level_interrupts(self): + return self.check_sym("CONFIG_MULTI_LEVEL_INTERRUPTS") + + def check_shared_interrupts(self): + return self.check_sym("CONFIG_SHARED_INTERRUPTS") + + def check_64b(self): + return self.check_sym("CONFIG_64BIT") - for irq in intlist["interrupts"]: - debug("{0:<10} {1:<3} {2:<3} {3}".format( - hex(irq[2]), irq[0], irq[1], hex(irq[3]))) - return intlist +def get_symbols(obj): + for section in obj.iter_sections(): + if isinstance(section, SymbolTableSection): + return {sym.name: sym.entry.st_value + for sym in section.iter_symbols()} + log.error("Could not find symbol table") -def parse_args(): - global args +def read_intList_sect(elfobj, snames): + """ + Load the raw intList section data in a form of byte array. + """ + intList_sect = None + for sname in snames: + intList_sect = elfobj.get_section_by_name(sname) + if intList_sect is not None: + log.debug("Found intlist section: \"{}\"".format(sname)) + break + + if intList_sect is None: + log.error("Cannot find the intlist section!") + + intdata = intList_sect.data() + + return intdata + +def parse_args(): parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) @@ -124,6 +286,12 @@ def parse_args(): help="Print additional debugging information") parser.add_argument("-o", "--output-source", required=True, help="Output source file") + parser.add_argument("-l", "--linker-output-files", + nargs=2, + metavar=("vector_table_link", "software_interrupt_link"), + help="Output linker files. " + "Used only if CONFIG_ISR_TABLES_LOCAL_DECLARATION is enabled. " + "In other case empty file would be generated.") parser.add_argument("-k", "--kernel", required=True, help="Zephyr kernel image") parser.add_argument("-s", "--sw-isr-table", action="store_true", @@ -134,313 +302,43 @@ def parse_args(): help="The name of the section to search for the interrupt data. " "This is accumulative argument. The first section found would be used.") - args = parser.parse_args() - -source_assembly_header = """ -#ifndef ARCH_IRQ_VECTOR_JUMP_CODE -#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" -#endif -""" - -def get_symbol_from_addr(syms, addr): - for key, value in syms.items(): - if addr == value: - return key - return None - -def write_code_irq_vector_table(fp, vt, nv, syms): - fp.write(source_assembly_header) - - fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") - for i in range(nv): - func = vt[i] - - if isinstance(func, int): - func_as_string = get_symbol_from_addr(syms, func) - else: - func_as_string = func - - fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) - fp.write("}\n") - -def write_address_irq_vector_table(fp, vt, nv): - fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % nv) - for i in range(nv): - func = vt[i] - - if isinstance(func, int): - fp.write("\t{},\n".format(vt[i])) - else: - fp.write("\t((uintptr_t)&{}),\n".format(vt[i])) - - fp.write("};\n") - -source_header = """ -/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ - -#include -#include -#include -#include - -typedef void (* ISR)(const void *); -""" - -def write_shared_table(fp, shared, nv): - fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" - " z_shared_sw_isr_table[%d] = {\n" % nv) - - for i in range(nv): - client_num = shared[i][1] - client_list = shared[i][0] - - if not client_num: - fp.write("\t{ },\n") - else: - fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") - for j in range(0, client_num): - routine = client_list[j][1] - arg = client_list[j][0] - - fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " - f".arg = (const void *){hex(arg)} }},") - - fp.write(" },\n},\n") - - fp.write("};\n") - -def write_source_file(fp, vt, swt, intlist, syms, shared): - fp.write(source_header) - - nv = intlist["num_vectors"] - - if "CONFIG_SHARED_INTERRUPTS" in syms: - write_shared_table(fp, shared, nv) - - if vt: - if "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS" in syms: - write_address_irq_vector_table(fp, vt, nv) - elif "CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE" in syms: - write_code_irq_vector_table(fp, vt, nv, syms) - else: - error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") - - if not swt: - return - - fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" - % nv) - - level2_offset = syms.get("CONFIG_2ND_LVL_ISR_TBL_OFFSET") - level3_offset = syms.get("CONFIG_3RD_LVL_ISR_TBL_OFFSET") - - for i in range(nv): - param = "{0:#x}".format(swt[i][0]) - func = swt[i][1] - - if isinstance (func, str) and "z_shared_isr" in func: - param = "&z_shared_sw_isr_table[{0}]".format(i) - if isinstance(func, int): - func_as_string = "{0:#x}".format(func) - else: - func_as_string = func - - if level2_offset is not None and i == level2_offset: - fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". - format(level2_offset)) - if level3_offset is not None and i == level3_offset: - fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". - format(level3_offset)) - - fp.write("\t{{(const void *){0}, (ISR){1}}},\n".format(param, func_as_string)) - fp.write("};\n") - -def get_symbols(obj): - for section in obj.iter_sections(): - if isinstance(section, SymbolTableSection): - return {sym.name: sym.entry.st_value - for sym in section.iter_symbols()} - - error("Could not find symbol table") - -def getindex(irq, irq_aggregator_pos): - try: - return irq_aggregator_pos.index(irq) - except ValueError: - error("IRQ {} not present in parent offsets ({}). ". - format(irq, irq_aggregator_pos) + - " Recheck interrupt configuration.") - -def bit_mask(bits): - mask = 0 - for _ in range(0, bits): - mask = (mask << 1) | 1 - return mask - -def update_masks(): - global FIRST_LVL_INTERRUPTS - global SECND_LVL_INTERRUPTS - global THIRD_LVL_INTERRUPTS - - if sum(INTERRUPT_BITS) > 32: - raise ValueError("Too many interrupt bits") - - FIRST_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[0]) - SECND_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[1]) << INTERRUPT_BITS[0] - THIRD_LVL_INTERRUPTS = bit_mask(INTERRUPT_BITS[2]) << INTERRUPT_BITS[0] + INTERRUPT_BITS[2] + return parser.parse_args() def main(): - parse_args() + args = parse_args() + # Configure logging as soon as possible + log.set_debug(args.debug) with open(args.kernel, "rb") as fp: kernel = ELFFile(fp) - syms = get_symbols(kernel) - intlist = read_intlist(kernel, syms, args.intlist_section) - - if "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: - max_irq_per = syms["CONFIG_MAX_IRQ_PER_AGGREGATOR"] - - INTERRUPT_BITS[0] = syms["CONFIG_1ST_LEVEL_INTERRUPT_BITS"] - INTERRUPT_BITS[1] = syms["CONFIG_2ND_LEVEL_INTERRUPT_BITS"] - INTERRUPT_BITS[2] = syms["CONFIG_3RD_LEVEL_INTERRUPT_BITS"] - update_masks() - - if "CONFIG_2ND_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_2ND_LEVEL_AGGREGATORS"] - irq2_baseoffset = syms["CONFIG_2ND_LVL_ISR_TBL_OFFSET"] - list_2nd_lvl_offsets = [syms['CONFIG_2ND_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] - - debug('2nd level offsets: {}'.format(list_2nd_lvl_offsets)) - - if "CONFIG_3RD_LEVEL_INTERRUPTS" in syms: - num_aggregators = syms["CONFIG_NUM_3RD_LEVEL_AGGREGATORS"] - irq3_baseoffset = syms["CONFIG_3RD_LVL_ISR_TBL_OFFSET"] - list_3rd_lvl_offsets = [syms['CONFIG_3RD_LVL_INTR_{}_OFFSET'. - format(str(i).zfill(2))] for i in - range(num_aggregators)] - - debug('3rd level offsets: {}'.format(list_3rd_lvl_offsets)) - - nvec = intlist["num_vectors"] - offset = intlist["offset"] - - if nvec > pow(2, 15): - raise ValueError('nvec is too large, check endianness.') - - swt_spurious_handler = "((uintptr_t)&z_irq_spurious)" - swt_shared_handler = "((uintptr_t)&z_shared_isr)" - vt_spurious_handler = "z_irq_spurious" - vt_irq_handler = "_isr_wrapper" - - debug('offset is ' + str(offset)) - debug('num_vectors is ' + str(nvec)) - - # Set default entries in both tables - if args.sw_isr_table: - # All vectors just jump to the common vt_irq_handler. If some entries - # are used for direct interrupts, they will be replaced later. - if args.vector_table: - vt = [vt_irq_handler for i in range(nvec)] - else: - vt = None - # Default to spurious interrupt handler. Configured interrupts - # will replace these entries. - swt = [(0, swt_spurious_handler) for i in range(nvec)] - shared = [([], 0) for i in range(nvec)] - else: - if args.vector_table: - vt = [vt_spurious_handler for i in range(nvec)] - else: - error("one or both of -s or -V needs to be specified on command line") - swt = None - - for irq, flags, func, param in intlist["interrupts"]: - if flags & ISR_FLAG_DIRECT: - if param != 0: - error("Direct irq %d declared, but has non-NULL parameter" - % irq) - if not 0 <= irq - offset < len(vt): - error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (irq - offset, offset, len(vt) - 1)) - vt[irq - offset] = func + config = gen_isr_config(args, get_symbols(kernel), log) + intlist_data = read_intList_sect(kernel, config.get_intlist_snames()) + + if config.check_sym("CONFIG_ISR_TABLES_LOCAL_DECLARATION"): + sys.stdout.write( + "Warning: The EXPERIMENTAL ISR_TABLES_LOCAL_DECLARATION feature selected\n") + parser_module = importlib.import_module('gen_isr_tables_parser_local') + parser = parser_module.gen_isr_parser(intlist_data, config, log) else: - # Regular interrupt - if not swt: - error("Regular Interrupt %d declared with parameter 0x%x " - "but no SW ISR_TABLE in use" - % (irq, param)) - - if not "CONFIG_MULTI_LEVEL_INTERRUPTS" in syms: - table_index = irq - offset - else: - # Figure out third level interrupt position - debug('IRQ = ' + hex(irq)) - irq3 = (irq & THIRD_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] + INTERRUPT_BITS[1] - irq2 = (irq & SECND_LVL_INTERRUPTS) >> INTERRUPT_BITS[0] - irq1 = irq & FIRST_LVL_INTERRUPTS - - if irq3: - irq_parent = irq2 - list_index = getindex(irq_parent, list_3rd_lvl_offsets) - irq3_pos = irq3_baseoffset + max_irq_per*list_index + irq3 - 1 - debug('IRQ_level = 3') - debug('IRQ_Indx = ' + str(irq3)) - debug('IRQ_Pos = ' + str(irq3_pos)) - table_index = irq3_pos - offset - - # Figure out second level interrupt position - elif irq2: - irq_parent = irq1 - list_index = getindex(irq_parent, list_2nd_lvl_offsets) - irq2_pos = irq2_baseoffset + max_irq_per*list_index + irq2 - 1 - debug('IRQ_level = 2') - debug('IRQ_Indx = ' + str(irq2)) - debug('IRQ_Pos = ' + str(irq2_pos)) - table_index = irq2_pos - offset - - # Figure out first level interrupt position - else: - debug('IRQ_level = 1') - debug('IRQ_Indx = ' + str(irq1)) - debug('IRQ_Pos = ' + str(irq1)) - table_index = irq1 - offset - - if not 0 <= table_index < len(swt): - error("IRQ %d (offset=%d) exceeds the maximum of %d" % - (table_index, offset, len(swt) - 1)) - if "CONFIG_SHARED_INTERRUPTS" in syms: - if swt[table_index] != (0, swt_spurious_handler): - # check client limit - if syms["CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"] == shared[table_index][1]: - error(f"Reached shared interrupt client limit. Maybe increase" - + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") - lst = shared[table_index][0] - delta_size = 1 - if not shared[table_index][1]: - lst.append(swt[table_index]) - # note: the argument will be fixed when writing the ISR table - # to isr_table.c - swt[table_index] = (0, swt_shared_handler) - delta_size += 1 - if (param, func) in lst: - error("Attempting to register the same ISR/arg pair twice.") - lst.append((param, func)) - shared[table_index] = (lst, shared[table_index][1] + delta_size) - else: - swt[table_index] = (param, func) - else: - if swt[table_index] != (0, swt_spurious_handler): - error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" - + f"\nExisting handler 0x{swt[table_index][1]:x}, new handler 0x{func:x}" - + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" - ) - else: - swt[table_index] = (param, func) + parser_module = importlib.import_module('gen_isr_tables_parser_carrays') + parser = parser_module.gen_isr_parser(intlist_data, config, log) with open(args.output_source, "w") as fp: - write_source_file(fp, vt, swt, intlist, syms, shared) + parser.write_source(fp) + + if args.linker_output_files is not None: + with open(args.linker_output_files[0], "w") as fp_vt, \ + open(args.linker_output_files[1], "w") as fp_swi: + if hasattr(parser, 'write_linker_vt'): + parser.write_linker_vt(fp_vt) + else: + log.debug("Chosen parser does not support vector table linker file") + fp_vt.write('/* Empty */\n') + if hasattr(parser, 'write_linker_swi'): + parser.write_linker_swi(fp_swi) + else: + log.debug("Chosen parser does not support software interrupt linker file") + fp_swi.write('/* Empty */\n') if __name__ == "__main__": main() diff --git a/scripts/build/gen_isr_tables_parser_carrays.py b/scripts/build/gen_isr_tables_parser_carrays.py new file mode 100644 index 00000000000..e13ef19c1f8 --- /dev/null +++ b/scripts/build/gen_isr_tables_parser_carrays.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA +# +# SPDX-License-Identifier: Apache-2.0 +# + +import struct + +class gen_isr_parser: + source_header = """ +/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ + +#include +#include +#include +#include + +typedef void (* ISR)(const void *); +""" + + source_assembly_header = """ +#ifndef ARCH_IRQ_VECTOR_JUMP_CODE +#error "ARCH_IRQ_VECTOR_JUMP_CODE not defined" +#endif +""" + + def __init__(self, intlist_data, config, log): + """Initialize the parser. + + The function prepares parser to work. + Parameters: + - intlist_data: The binnary data from intlist section + - config: The configuration object + - log: The logging object, has to have error and debug methods + """ + self.__config = config + self.__log = log + intlist = self.__read_intlist(intlist_data) + self.__vt, self.__swt, self.__nv = self.__parse_intlist(intlist) + + def __read_intlist(self, intlist_data): + """read a binary file containing the contents of the kernel's .intList + section. This is an instance of a header created by + include/zephyr/linker/intlist.ld: + + struct { + uint32_t num_vectors; <- typically CONFIG_NUM_IRQS + struct _isr_list isrs[]; <- Usually of smaller size than num_vectors + } + + Followed by instances of struct _isr_list created by IRQ_CONNECT() + calls: + + struct _isr_list { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** ISR to call */ + void *func; + /** Parameter for non-direct IRQs */ + const void *param; + }; + """ + intlist = {} + prefix = self.__config.endian_prefix() + + # Extract header and the rest of the data + intlist_header_fmt = prefix + "II" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + self.__log.debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intdata = intlist_data[header_sz:] + + # Extract information about interrupts + if self.__config.check_64b(): + intlist_entry_fmt = prefix + "iiQQ" + else: + intlist_entry_fmt = prefix + "iiII" + + intlist["interrupts"] = [i for i in + struct.iter_unpack(intlist_entry_fmt, intdata)] + + self.__log.debug("Configured interrupt routing") + self.__log.debug("handler irq flags param") + self.__log.debug("--------------------------") + + for irq in intlist["interrupts"]: + self.__log.debug("{0:<10} {1:<3} {2:<3} {3}".format( + hex(irq[2]), irq[0], irq[1], hex(irq[3]))) + + return intlist + + def __parse_intlist(self, intlist): + """All the intlist data are parsed into swt and vt arrays. + + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). + + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. + + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) + + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ + nvec = intlist["num_vectors"] + offset = intlist["offset"] + + if nvec > pow(2, 15): + raise ValueError('nvec is too large, check endianness.') + + self.__log.debug('offset is ' + str(offset)) + self.__log.debug('num_vectors is ' + str(nvec)) + + # Set default entries in both tables + if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): + self.__log.error("one or both of -s or -V needs to be specified on command line") + if self.__config.args.vector_table: + vt = [None for i in range(nvec)] + else: + vt = None + if self.__config.args.sw_isr_table: + swt = [[] for i in range(nvec)] + else: + swt = None + + # Process intlist and write to the tables created + for irq, flags, func, param in intlist["interrupts"]: + if self.__config.test_isr_direct(flags): + if not vt: + self.__log.error("Direct Interrupt %d declared with parameter 0x%x " + "but no vector table in use" + % (irq, param)) + if param != 0: + self.__log.error("Direct irq %d declared, but has non-NULL parameter" + % irq) + if not 0 <= irq - offset < len(vt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" + % (irq - offset, offset, len(vt) - 1)) + vt[irq - offset] = func + else: + # Regular interrupt + if not swt: + self.__log.error("Regular Interrupt %d declared with parameter 0x%x " + "but no SW ISR_TABLE in use" + % (irq, param)) + + table_index = self.__config.get_swt_table_index(offset, irq) + + if not 0 <= table_index < len(swt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (table_index, offset, len(swt) - 1)) + if self.__config.check_shared_interrupts(): + lst = swt[table_index] + if (param, func) in lst: + self.__log.error("Attempting to register the same ISR/arg pair twice.") + if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): + self.__log.error(f"Reached shared interrupt client limit. Maybe increase" + + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + else: + if len(swt[table_index]) > 0: + self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + + f"\nExisting handler 0x{swt[table_index][0][1]:x}, new handler 0x{func:x}" + + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" + ) + swt[table_index].append((param, func)) + + return vt, swt, nvec + + def __write_code_irq_vector_table(self, fp): + fp.write(self.source_assembly_header) + + fp.write("void __irq_vector_table __attribute__((naked)) _irq_vector_table(void) {\n") + for i in range(self.__nv): + func = self.__vt[i] + + if func is None: + func = self.__config.vt_default_handler + + if isinstance(func, int): + func_as_string = self.__config.get_sym_from_addr(func) + else: + func_as_string = func + + fp.write("\t__asm(ARCH_IRQ_VECTOR_JUMP_CODE({}));\n".format(func_as_string)) + fp.write("}\n") + + def __write_address_irq_vector_table(self, fp): + fp.write("uintptr_t __irq_vector_table _irq_vector_table[%d] = {\n" % self.__nv) + for i in range(self.__nv): + func = self.__vt[i] + + if func is None: + func = self.__config.vt_default_handler + + if isinstance(func, int): + fp.write("\t{},\n".format(func)) + else: + fp.write("\t((uintptr_t)&{}),\n".format(func)) + + fp.write("};\n") + + def __write_shared_table(self, fp): + fp.write("struct z_shared_isr_table_entry __shared_sw_isr_table" + " z_shared_sw_isr_table[%d] = {\n" % self.__nv) + + for i in range(self.__nv): + if self.__swt[i] is None: + client_num = 0 + client_list = None + else: + client_num = len(self.__swt[i]) + client_list = self.__swt[i] + + if client_num <= 1: + fp.write("\t{ },\n") + else: + fp.write(f"\t{{ .client_num = {client_num}, .clients = {{ ") + for j in range(0, client_num): + routine = client_list[j][1] + arg = client_list[j][0] + + fp.write(f"{{ .isr = (ISR){ hex(routine) if isinstance(routine, int) else routine }, " + f".arg = (const void *){hex(arg)} }},") + + fp.write(" },\n},\n") + + fp.write("};\n") + + def write_source(self, fp): + fp.write(self.source_header) + + if self.__config.check_shared_interrupts(): + self.__write_shared_table(fp) + + if self.__vt: + if self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS"): + self.__write_address_irq_vector_table(fp) + elif self.__config.check_sym("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_CODE"): + self.__write_code_irq_vector_table(fp) + else: + self.__log.error("CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_{ADDRESS,CODE} not set") + + if not self.__swt: + return + + fp.write("struct _isr_table_entry __sw_isr_table _sw_isr_table[%d] = {\n" + % self.__nv) + + level2_offset = self.__config.get_irq_baseoffset(2) + level3_offset = self.__config.get_irq_baseoffset(3) + + for i in range(self.__nv): + if len(self.__swt[i]) == 0: + # Not used interrupt + param = "0x0" + func = self.__config.swt_spurious_handler + elif len(self.__swt[i]) == 1: + # Single interrupt + param = "{0:#x}".format(self.__swt[i][0][0]) + func = self.__swt[i][0][1] + else: + # Shared interrupt + param = "&z_shared_sw_isr_table[{0}]".format(i) + func = self.__config.swt_shared_handler + + if isinstance(func, int): + func_as_string = "{0:#x}".format(func) + else: + func_as_string = func + + if level2_offset is not None and i == level2_offset: + fp.write("\t/* Level 2 interrupts start here (offset: {}) */\n". + format(level2_offset)) + if level3_offset is not None and i == level3_offset: + fp.write("\t/* Level 3 interrupts start here (offset: {}) */\n". + format(level3_offset)) + + fp.write("\t{{(const void *){0}, (ISR){1}}}, /* {2} */\n".format(param, func_as_string, i)) + fp.write("};\n") diff --git a/scripts/build/gen_isr_tables_parser_local.py b/scripts/build/gen_isr_tables_parser_local.py new file mode 100644 index 00000000000..91bd4a65471 --- /dev/null +++ b/scripts/build/gen_isr_tables_parser_local.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2017 Intel Corporation +# Copyright (c) 2018 Foundries.io +# Copyright (c) 2023 Nordic Semiconductor NA +# +# SPDX-License-Identifier: Apache-2.0 +# + +import struct + +class gen_isr_parser: + source_header = """ +/* AUTO-GENERATED by gen_isr_tables.py, do not edit! */ + +#include +#include +#include +#include + +""" + + shared_isr_table_header = """ + +/* For this parser to work, we have to be sure that shared interrupts table entry + * and the normal isr table entry have exactly the same layout + */ +BUILD_ASSERT(sizeof(struct _isr_table_entry) + == + sizeof(struct z_shared_isr_table_entry), + "Shared ISR and ISR table entries layout do not match"); +BUILD_ASSERT(offsetof(struct _isr_table_entry, arg) + == + offsetof(struct z_shared_isr_table_entry, arg), + "Shared ISR and ISR table entries layout do not match"); +BUILD_ASSERT(offsetof(struct _isr_table_entry, isr) + == + offsetof(struct z_shared_isr_table_entry, isr), + "Shared ISR and ISR table entries layout do not match"); + +""" + + def __init__(self, intlist_data, config, log): + """Initialize the parser. + + The function prepares parser to work. + Parameters: + - intlist_data: The binnary data from intlist section + - config: The configuration object + - log: The logging object, has to have error and debug methods + """ + self.__config = config + self.__log = log + intlist = self.__read_intlist(intlist_data) + self.__vt, self.__swt, self.__nv, header = self.__parse_intlist(intlist) + self.__swi_table_entry_size = header["swi_table_entry_size"] + self.__shared_isr_table_entry_size = header["shared_isr_table_entry_size"] + self.__shared_isr_client_num_offset = header["shared_isr_client_num_offset"] + + def __read_intlist(self, intlist_data): + """read an intList section from the elf file. + This is version 2 of a header created by include/zephyr/linker/intlist.ld: + + struct { + uint32_t num_vectors; <- typically CONFIG_NUM_IRQS + uint8_t stream[]; <- the stream with the interrupt data + }; + + The stream is contained from variable length records in a form: + + struct _isr_list_sname { + /** IRQ line number */ + int32_t irq; + /** Flags for this IRQ, see ISR_FLAG_* definitions */ + int32_t flags; + /** The section name */ + const char sname[]; + }; + + The flexible array member here (sname) contains the name of the section where the structure + with interrupt data is located. + It is always Null-terminated string thus we have to search through the input data for the + structure end. + + """ + intlist = {} + prefix = self.__config.endian_prefix() + + # Extract header and the rest of the data + intlist_header_fmt = prefix + "IIIII" + header_sz = struct.calcsize(intlist_header_fmt) + header_raw = struct.unpack_from(intlist_header_fmt, intlist_data, 0) + self.__log.debug(str(header_raw)) + + intlist["num_vectors"] = header_raw[0] + intlist["offset"] = header_raw[1] + intlist["swi_table_entry_size"] = header_raw[2] + intlist["shared_isr_table_entry_size"] = header_raw[3] + intlist["shared_isr_client_num_offset"] = header_raw[4] + + intdata = intlist_data[header_sz:] + + # Extract information about interrupts + intlist_entry_fmt = prefix + "ii" + entry_sz = struct.calcsize(intlist_entry_fmt) + intlist["interrupts"] = [] + + while len(intdata) > entry_sz: + entry_raw = struct.unpack_from(intlist_entry_fmt, intdata, 0) + intdata = intdata[entry_sz:] + null_idx = intdata.find(0) + if null_idx < 0: + self.__log.error("Cannot find sname null termination at IRQ{}".format(entry_raw[0])) + bname = intdata[:null_idx] + # Next structure starts with 4B alignment + next_idx = null_idx + 1 + next_idx = (next_idx + 3) & ~3 + intdata = intdata[next_idx:] + sname = bname.decode() + intlist["interrupts"].append([entry_raw[0], entry_raw[1], sname]) + self.__log.debug("Unpacked IRQ{}, flags: {}, sname: \"{}\"\n".format( + entry_raw[0], entry_raw[1], sname)) + + # If any data left at the end - it has to be all the way 0 - this is just a check + if (len(intdata) and not all([d == 0 for d in intdata])): + self.__log.error("Non-zero data found at the end of the intList data.\n") + + self.__log.debug("Configured interrupt routing with linker") + self.__log.debug("irq flags sname") + self.__log.debug("--------------------------") + + for irq in intlist["interrupts"]: + self.__log.debug("{0:<3} {1:<5} {2}".format( + hex(irq[0]), irq[1], irq[2])) + + return intlist + + def __parse_intlist(self, intlist): + """All the intlist data are parsed into swt and vt arrays. + + The vt array is prepared for hardware interrupt table. + Every entry in the selected position would contain None or the name of the function pointer + (address or string). + + The swt is a little more complex. At every position it would contain an array of parameter and + function pointer pairs. If CONFIG_SHARED_INTERRUPTS is enabled there may be more than 1 entry. + If empty array is placed on selected position - it means that the application does not implement + this interrupt. + + Parameters: + - intlist: The preprocessed list of intlist section content (see read_intlist) + + Return: + vt, swt - parsed vt and swt arrays (see function description above) + """ + nvec = intlist["num_vectors"] + offset = intlist["offset"] + header = { + "swi_table_entry_size": intlist["swi_table_entry_size"], + "shared_isr_table_entry_size": intlist["shared_isr_table_entry_size"], + "shared_isr_client_num_offset": intlist["shared_isr_client_num_offset"] + } + + if nvec > pow(2, 15): + raise ValueError('nvec is too large, check endianness.') + + self.__log.debug('offset is ' + str(offset)) + self.__log.debug('num_vectors is ' + str(nvec)) + + # Set default entries in both tables + if not(self.__config.args.sw_isr_table or self.__config.args.vector_table): + self.__log.error("one or both of -s or -V needs to be specified on command line") + if self.__config.args.vector_table: + vt = [None for i in range(nvec)] + else: + vt = None + if self.__config.args.sw_isr_table: + swt = [[] for i in range(nvec)] + else: + swt = None + + # Process intlist and write to the tables created + for irq, flags, sname in intlist["interrupts"]: + if self.__config.test_isr_direct(flags): + if not 0 <= irq - offset < len(vt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (irq - offset, offset, len(vt) - 1)) + vt[irq - offset] = sname + else: + # Regular interrupt + if not swt: + self.__log.error("Regular Interrupt %d declared with section name %s " + "but no SW ISR_TABLE in use" + % (irq, sname)) + + table_index = self.__config.get_swt_table_index(offset, irq) + + if not 0 <= table_index < len(swt): + self.__log.error("IRQ %d (offset=%d) exceeds the maximum of %d" % + (table_index, offset, len(swt) - 1)) + # Check if the given section name does not repeat outside of current interrupt + for i in range(nvec): + if i == irq: + continue + if sname in swt[i]: + self.__log.error(("Attempting to register the same section name \"{}\"for" + + "different interrupts: {} and {}").format(sname, i, irq)) + if self.__config.check_shared_interrupts(): + lst = swt[table_index] + if len(lst) >= self.__config.get_sym("CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS"): + self.__log.error(f"Reached shared interrupt client limit. Maybe increase" + + f" CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS?") + else: + if len(swt[table_index]) > 0: + self.__log.error(f"multiple registrations at table_index {table_index} for irq {irq} (0x{irq:x})" + + f"\nExisting section {swt[table_index]}, new section {sname}" + + "\nHas IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?" + ) + swt[table_index].append(sname) + + return vt, swt, nvec, header + + @staticmethod + def __irq_spurious_section(irq): + return '.irq_spurious.0x{:x}'.format(irq) + + @staticmethod + def __isr_generated_section(irq): + return '.isr_generated.0x{:x}'.format(irq) + + @staticmethod + def __shared_entry_section(irq, ent): + return '.isr_shared.0x{:x}_0x{:x}'.format(irq, ent) + + @staticmethod + def __shared_client_num_section(irq): + return '.isr_shared.0x{:x}_client_num'.format(irq) + + def __isr_spurious_entry(self, irq): + return '_Z_ISR_TABLE_ENTRY({irq}, {func}, NULL, "{sect}");'.format( + irq = irq, + func = self.__config.swt_spurious_handler, + sect = self.__isr_generated_section(irq) + ) + + def __isr_shared_entry(self, irq): + return '_Z_ISR_TABLE_ENTRY({irq}, {func}, {arg}, "{sect}");'.format( + irq = irq, + arg = '&{}[{}]'.format(self.__config.shared_array_name, irq), + func = self.__config.swt_shared_handler, + sect = self.__isr_generated_section(irq) + ) + + def __irq_spurious_entry(self, irq): + return '_Z_ISR_DIRECT_TABLE_ENTRY({irq}, {func}, "{sect}");'.format( + irq = irq, + func = self.__config.vt_default_handler, + sect = self.__irq_spurious_section(irq) + ) + + def __write_isr_handlers(self, fp): + for i in range(self.__nv): + if len(self.__swt[i]) <= 0: + fp.write(self.__isr_spurious_entry(i) + '\n') + elif len(self.__swt[i]) > 1: + # Connect to shared handlers + fp.write(self.__isr_shared_entry(i) + '\n') + else: + fp.write('/* ISR: {} implemented in app in "{}" section. */\n'.format( + i, self.__swt[i][0])) + + def __write_irq_handlers(self, fp): + for i in range(self.__nv): + if self.__vt[i] is None: + fp.write(self.__irq_spurious_entry(i) + '\n') + else: + fp.write('/* ISR: {} implemented in app. */\n'.format(i)) + + def __write_shared_handlers(self, fp): + fp.write("extern struct z_shared_isr_table_entry " + "{}[{}];\n".format(self.__config.shared_array_name, self.__nv)) + + shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS') + for i in range(self.__nv): + swt_len = len(self.__swt[i]) + for j in range(shared_cnt): + if (swt_len <= 1) or (swt_len <= j): + # Add all unused entry + fp.write('static Z_DECL_ALIGN(struct _isr_table_entry)\n' + + '\tZ_GENERIC_SECTION({})\n'.format(self.__shared_entry_section(i, j)) + + '\t__used isr_shared_empty_entry_0x{:x}_0x{:x} = {{\n'.format(i, j) + + '\t\t.arg = (const void *)NULL,\n' + + '\t\t.isr = (void (*)(const void *))(void *)0\n' + + '};\n' + ) + else: + # Add information about entry implemented by application + fp.write('/* Shared isr {} entry {} implemented in "{}" section*/\n'.format( + i, j, self.__swt[i][j])) + + # Add information about clients count + fp.write(('static size_t Z_GENERIC_SECTION({}) __used\n' + + 'isr_shared_client_num_0x{:x} = {};\n\n').format( + self.__shared_client_num_section(i), + i, + 0 if swt_len < 2 else swt_len) + ) + + def write_source(self, fp): + fp.write(self.source_header) + + if self.__vt: + self.__write_irq_handlers(fp) + + if not self.__swt: + return + + if self.__config.check_shared_interrupts(): + self.__write_shared_handlers(fp) + + self.__write_isr_handlers(fp) + + def __write_linker_irq(self, fp): + fp.write('{} = .;\n'.format(self.__config.irq_vector_array_name)) + for i in range(self.__nv): + if self.__vt[i] is None: + sname = self.__irq_spurious_section(i) + else: + sname = self.__vt[i] + fp.write('KEEP(*("{}"))\n'.format(sname)) + + def __write_linker_shared(self, fp): + fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size)) + fp.write('{} = .;\n'.format(self.__config.shared_array_name)) + shared_cnt = self.__config.get_sym('CONFIG_SHARED_IRQ_MAX_NUM_CLIENTS') + client_num_pads = self.__shared_isr_client_num_offset - \ + shared_cnt * self.__swi_table_entry_size + if client_num_pads < 0: + self.__log.error("Invalid __shared_isr_client_num_offset header value") + for i in range(self.__nv): + swt_len = len(self.__swt[i]) + # Add all entries + for j in range(shared_cnt): + if (swt_len <= 1) or (swt_len <= j): + fp.write('KEEP(*("{}"))\n'.format(self.__shared_entry_section(i, j))) + else: + sname = self.__swt[i][j] + if (j != 0) and (sname in self.__swt[i][0:j]): + fp.write('/* Repetition of "{}" section */\n'.format(sname)) + else: + fp.write('KEEP(*("{}"))\n'.format(sname)) + fp.write('. = . + {};\n'.format(client_num_pads)) + fp.write('KEEP(*("{}"))\n'.format(self.__shared_client_num_section(i))) + fp.write(". = ALIGN({});\n".format(self.__shared_isr_table_entry_size)) + + def __write_linker_isr(self, fp): + fp.write(". = ALIGN({});\n".format(self.__swi_table_entry_size)) + fp.write('{} = .;\n'.format(self.__config.sw_isr_array_name)) + for i in range(self.__nv): + if (len(self.__swt[i])) == 1: + sname = self.__swt[i][0] + else: + sname = self.__isr_generated_section(i) + fp.write('KEEP(*("{}"))\n'.format(sname)) + + def write_linker_vt(self, fp): + if self.__vt: + self.__write_linker_irq(fp) + + def write_linker_swi(self, fp): + if self.__swt: + self.__write_linker_isr(fp) + + if self.__config.check_shared_interrupts(): + self.__write_linker_shared(fp) diff --git a/scripts/build/gen_relocate_app.py b/scripts/build/gen_relocate_app.py index 1d7783cd38a..f1bcccf1df6 100644 --- a/scripts/build/gen_relocate_app.py +++ b/scripts/build/gen_relocate_app.py @@ -33,6 +33,8 @@ ignored. - COPY/NOCOPY defines whether the script should generate the relocation code in code_relocation.c or not +- NOKEEP will suppress the default behavior of marking every relocated symbol + with KEEP() in the generated linker script. Multiple regions can be appended together like SRAM2_DATA_BSS this will place data and bss inside SRAM2. @@ -94,12 +96,17 @@ def for_section_named(cls, name: str): class OutputSection(NamedTuple): obj_file_name: str section_name: str + keep: bool = True PRINT_TEMPLATE = """ KEEP(*{obj_file_name}({section_name})) """ +PRINT_TEMPLATE_NOKEEP = """ + *{obj_file_name}({section_name}) +""" + SECTION_LOAD_MEMORY_SEQ = """ __{0}_{1}_rom_start = LOADADDR(.{0}_{1}_reloc); """ @@ -274,10 +281,16 @@ def assign_to_correct_mem_region( if align_size: mpu_align[memory_region] = int(align_size) + keep_sections = '|NOKEEP' not in memory_region + memory_region = memory_region.replace('|NOKEEP', '') + output_sections = {} for used_kind in use_section_kinds: # Pass through section kinds that go into this memory region - output_sections[used_kind] = full_list_of_sections[used_kind] + output_sections[used_kind] = [ + section._replace(keep=keep_sections) + for section in full_list_of_sections[used_kind] + ] return {MemoryRegion(memory_region): output_sections} @@ -308,10 +321,12 @@ def section_kinds_from_memory_region(memory_region: str) -> 'Tuple[set[SectionKi def print_linker_sections(list_sections: 'list[OutputSection]'): - return ''.join(PRINT_TEMPLATE.format(obj_file_name=section.obj_file_name, - section_name=section.section_name) - for section in sorted(list_sections)) - + out = '' + for section in sorted(list_sections): + template = PRINT_TEMPLATE if section.keep else PRINT_TEMPLATE_NOKEEP + out += template.format(obj_file_name=section.obj_file_name, + section_name=section.section_name) + return out def add_phdr(memory_type, phdrs): return f'{memory_type} {phdrs[memory_type] if memory_type in phdrs else ""}' @@ -485,20 +500,23 @@ def get_obj_filename(searchpath, filename): return fullname -# Extracts all possible components for the input strin: -# [\ :program_header]:: -# Returns a 4-tuple with them: (mem_region, program_header, flag, file_name) +# Extracts all possible components for the input string: +# [\ :program_header]:[;...]:[;...] +# Returns a 4-tuple with them: (mem_region, program_header, flags, files) # If no `program_header` is defined, returns an empty string def parse_input_string(line): - line = line.replace(' :', ':') + # Be careful when splitting by : to avoid breaking absolute paths on Windows + mem_region, rest = line.split(':', 1) - flag_sep = ':NOCOPY:' if ':NOCOPY' in line else ':COPY:' - mem_region_phdr, copy_flag, file_name = line.partition(flag_sep) - copy_flag = copy_flag.replace(':', '') + phdr = '' + if mem_region.endswith(' '): + mem_region = mem_region.rstrip() + phdr, rest = rest.split(':', 1) - mem_region, _, phdr = mem_region_phdr.partition(':') + # Split lists by semicolons, in part to support generator expressions + flag_list, file_list = (lst.split(';') for lst in rest.split(':', 1)) - return mem_region, phdr, copy_flag, file_name + return mem_region, phdr, flag_list, file_list # Create a dict with key as memory type and files as a list of values. @@ -515,17 +533,15 @@ def create_dict_wrt_mem(): if ':' not in line: continue - mem_region, phdr, copy_flag, file_list = parse_input_string(line) + mem_region, phdr, flag_list, file_list = parse_input_string(line) # Handle any program header if phdr != '': phdrs[mem_region] = f':{phdr}' - # Split file names by semicolons, to support generator expressions - file_glob_list = file_list.split(';') file_name_list = [] # Use glob matching on each file in the list - for file_glob in file_glob_list: + for file_glob in file_list: glob_results = glob.glob(file_glob) if not glob_results: warnings.warn("File: "+file_glob+" Not found") @@ -534,14 +550,13 @@ def create_dict_wrt_mem(): warnings.warn("Regex in file lists is deprecated, please use file(GLOB) instead") file_name_list.extend(glob_results) if len(file_name_list) == 0: - warnings.warn("No files in string: "+file_list+" found") continue if mem_region == '': continue if args.verbose: print("Memory region ", mem_region, " Selected for files:", file_name_list) - mem_region = "|".join((mem_region, copy_flag)) + mem_region = "|".join((mem_region, *flag_list)) if mem_region in rel_dict: rel_dict[mem_region].extend(file_name_list) diff --git a/scripts/build/parse_syscalls.py b/scripts/build/parse_syscalls.py index 636404950db..ebdb9bb73ab 100644 --- a/scripts/build/parse_syscalls.py +++ b/scripts/build/parse_syscalls.py @@ -84,6 +84,9 @@ def analyze_headers(include_dir, scan_dir, file_list): if scan_dir: multiple_directories |= set(scan_dir) + # Convert to a list to keep the output deterministic + multiple_directories = sorted(multiple_directories) + # Look for source files under various directories. # Due to "syscalls/*.h" being included unconditionally in various # other header files. We must generate the associated syscall diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 544fc4ea0e4..b3bfd180cca 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -389,6 +389,7 @@ sub hash_show_words { __always_unused| __noreturn| __used| + __unused| __cold| __pure| __noclone| @@ -3738,7 +3739,7 @@ sub process { # 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*\#/) { + if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[A-Z_]+|)FOR_EACH(?!_NONEMPTY_TERM)[A-Z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { my $pre_ctx = "$1$2"; my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); @@ -3784,7 +3785,7 @@ sub process { } # 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*/) { + if ($line =~ /\b(?:(?:if|while|for|(?:[A-Z_]+|)FOR_EACH(?!_NONEMPTY_TERM|_IDX|_FIXED_ARG|_IDX_FIXED_ARG)[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); @@ -5003,6 +5004,7 @@ sub process { # 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 =~ /^\+(.*)($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*(.*)($Constant|[A-Z_][A-Z0-9_]*)(.*)/) && $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { my $lead = $1; my $const = $2; diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index d8b147f8ab0..5e5e358d403 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -17,6 +17,7 @@ import traceback import shlex import shutil +import textwrap from yamllint import config, linter @@ -285,7 +286,7 @@ def run(self, full=True, no_modules=False): if full: self.check_no_undef_outside_kconfig(kconf) - def get_modules(self, modules_file): + def get_modules(self, modules_file, settings_file): """ Get a list of modules and put them in a file that is parsed by Kconfig @@ -303,7 +304,7 @@ def get_modules(self, modules_file): zephyr_module_path = os.path.join(ZEPHYR_BASE, "scripts", "zephyr_module.py") cmd = [sys.executable, zephyr_module_path, - '--kconfig-out', modules_file] + '--kconfig-out', modules_file, '--settings-out', settings_file] try: subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -341,7 +342,7 @@ def get_modules(self, modules_file): )) fp_module_file.write(content) - def get_kconfig_dts(self, kconfig_dts_file): + def get_kconfig_dts(self, kconfig_dts_file, settings_file): """ Generate the Kconfig.dts using dts/bindings as the source. @@ -352,9 +353,23 @@ def get_kconfig_dts(self, kconfig_dts_file): # not a module nor a pip-installed Python utility zephyr_drv_kconfig_path = os.path.join(ZEPHYR_BASE, "scripts", "dts", "gen_driver_kconfig_dts.py") - binding_path = os.path.join(ZEPHYR_BASE, "dts", "bindings") + binding_paths = [] + binding_paths.append(os.path.join(ZEPHYR_BASE, "dts", "bindings")) + + if os.path.exists(settings_file): + with open(settings_file, 'r') as fp_setting_file: + content = fp_setting_file.read() + + lines = content.strip().split('\n') + for line in lines: + if line.startswith('"DTS_ROOT":'): + _, dts_root_path = line.split(":") + binding_paths.append(os.path.join(dts_root_path.strip('"'), "dts", "bindings")) + cmd = [sys.executable, zephyr_drv_kconfig_path, - '--kconfig-out', kconfig_dts_file, '--bindings-dirs', binding_path] + '--kconfig-out', kconfig_dts_file, '--bindings-dirs'] + for binding_path in binding_paths: + cmd.append(binding_path) try: subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) @@ -398,9 +413,11 @@ def parse_kconfig(self): os.environ["GENERATED_DTS_BOARD_CONF"] = "dummy" # For multi repo support - self.get_modules(os.path.join(kconfiglib_dir, "Kconfig.modules")) + self.get_modules(os.path.join(kconfiglib_dir, "Kconfig.modules"), + os.path.join(kconfiglib_dir, "settings_file.txt")) # For Kconfig.dts support - self.get_kconfig_dts(os.path.join(kconfiglib_dir, "Kconfig.dts")) + self.get_kconfig_dts(os.path.join(kconfiglib_dir, "Kconfig.dts"), + os.path.join(kconfiglib_dir, "settings_file.txt")) # Tells Kconfiglib to generate warnings for all references to undefined # symbols within Kconfig files @@ -528,7 +545,7 @@ def check_no_pointless_menuconfigs(self, kconf): self.failure("""\ Found pointless 'menuconfig' symbols without children. Use regular 'config' symbols instead. See -https://docs.zephyrproject.org/latest/guides/kconfig/tips.html#menuconfig-symbols. +https://docs.zephyrproject.org/latest/build/kconfig/tips.html#menuconfig-symbols. """ + "\n".join(f"{node.item.name:35} {node.filename}:{node.linenr}" for node in bad_mconfs)) @@ -679,6 +696,7 @@ def check_no_undef_outside_kconfig(self, kconf): "FOO_LOG_LEVEL", "FOO_SETTING_1", "FOO_SETTING_2", + "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "LSM6DSO_INT_PIN", "LIBGCC_RTLIB", "LLVM_USE_LD", # Both LLVM_USE_* are in cmake/toolchain/llvm/Kconfig @@ -1192,13 +1210,28 @@ class KeepSorted(ComplianceTest): MARKER = "zephyr-keep-sorted" + def block_is_sorted(self, block_data): + lines = [] + + for line in textwrap.dedent(block_data).splitlines(): + if len(lines) > 0 and line.startswith((" ", "\t")): + # Fold back indented lines + lines[-1] += line.strip() + else: + lines.append(line.strip()) + + if lines != sorted(lines): + return False + + return True + def check_file(self, file, fp): mime_type = magic.from_file(file, mime=True) if not mime_type.startswith("text/"): return - lines = [] + block_data = "" in_block = False start_marker = f"{self.MARKER}-start" @@ -1211,7 +1244,7 @@ def check_file(self, file, fp): self.fmtd_failure("error", "KeepSorted", file, line_num, desc=desc) in_block = True - lines = [] + block_data = "" elif stop_marker in line: if not in_block: desc = f"{stop_marker} without {start_marker}" @@ -1219,18 +1252,15 @@ def check_file(self, file, fp): desc=desc) in_block = False - if lines != sorted(lines): + if not self.block_is_sorted(block_data): desc = f"sorted block is not sorted" self.fmtd_failure("error", "KeepSorted", file, line_num, - desc=desc) + desc=desc) elif not line.strip() or line.startswith("#"): # Ignore comments and blank lines continue elif in_block: - if line.startswith((" ", "\t")): - lines[-1] += line - else: - lines.append(line) + block_data += line if in_block: self.failure(f"unterminated {start_marker} in {file}") diff --git a/scripts/ci/guideline_check.py b/scripts/ci/guideline_check.py index 0d4266eb3a3..57c878f651f 100755 --- a/scripts/ci/guideline_check.py +++ b/scripts/ci/guideline_check.py @@ -11,13 +11,6 @@ if "ZEPHYR_BASE" not in os.environ: exit("$ZEPHYR_BASE environment variable undefined.") -repository_path = os.environ['ZEPHYR_BASE'] - -sh_special_args = { - '_tty_out': False, - '_cwd': repository_path -} - coccinelle_scripts = ["/scripts/coccinelle/reserved_names.cocci", "/scripts/coccinelle/same_identifier.cocci", #"/scripts/coccinelle/identifier_length.cocci", @@ -38,7 +31,9 @@ def parse_coccinelle(contents: str, violations: dict): def parse_args(): parser = argparse.ArgumentParser( - description="Check if change requires full twister", allow_abbrev=False) + description="Check commits against Cocccinelle rules", allow_abbrev=False) + parser.add_argument('-r', "--repository", required=False, + help="Path to repository") parser.add_argument('-c', '--commits', default=None, help="Commit range in the form: a..b") parser.add_argument("-o", "--output", required=False, @@ -51,6 +46,16 @@ def main(): if not args.commits: exit("missing commit range") + if args.repository is None: + repository_path = os.environ['ZEPHYR_BASE'] + else: + repository_path = args.repository + + sh_special_args = { + '_tty_out': False, + '_cwd': repository_path + } + # pylint does not like the 'sh' library # pylint: disable=too-many-function-args,unexpected-keyword-arg commit = sh.git("diff", args.commits, **sh_special_args) diff --git a/scripts/ci/stats/merged_prs.py b/scripts/ci/stats/merged_prs.py new file mode 100755 index 00000000000..3111912cc63 --- /dev/null +++ b/scripts/ci/stats/merged_prs.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corp. +# SPDX-License-Identifier: Apache-2.0 + +# Script that operates on a merged PR and sends data to elasticsearch for +# further insepctions using the PR dashboard at +# https://kibana.zephyrproject.io/ + +import sys +import os +from github import Github +import argparse +from elasticsearch import Elasticsearch +from elasticsearch.helpers import bulk +from datetime import timedelta +import pprint + + +date_format = '%Y-%m-%d %H:%M:%S' + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) + + parser.add_argument('--pull-request', help='pull request number', type=int) + parser.add_argument('--range', help='execute based on a date range, for example 2023-01-01..2023-01-05') + parser.add_argument('--repo', help='github repo', default='zephyrproject-rtos/zephyr') + parser.add_argument('--es-index', help='Elasticsearch index') + parser.add_argument('-y','--dry-run', action="store_true", help='dry run, do not upload data') + + return parser.parse_args() + +def gendata(data, index): + for t in data: + yield { + "_index": index, + "_source": t + } + +def process_pr(pr): + reviews = pr.get_reviews() + print(f'#{pr.number}: {pr.title} - {pr.comments} Comments, reviews: {reviews.totalCount}, {len(pr.assignees)} Assignees (Updated {pr.updated_at})') + assignee_reviews = 0 + prj = {} + + assignees = [] + labels = [] + for label in pr.labels: + labels.append(label.name) + + reviewers = set() + for review in reviews: + # get list of all approved reviews + if review.user and review.state == 'APPROVED': + reviewers.add(review.user.login) + + for assignee in pr.assignees: + # list assignees for later checks + assignees.append(assignee.login) + if assignee.login in reviewers: + assignee_reviews += 1 + + if assignee_reviews > 0 or pr.merged_by.login in assignees: + # in case of assignee reviews or if PR was merged by an assignee + prj['review_rule'] = "yes" + elif not pr.assignees or \ + (pr.user.login in assignees and len(assignees) == 1) or \ + ('Trivial' in labels or 'Hotfix' in labels): + # in case where no assignees set or if submitter is the only assignee + # or in case of trivial or hotfixes + prj['review_rule'] = "na" + else: + # everything else + prj['review_rule'] = "no" + + + created = pr.created_at + # if a PR was made ready for review from draft, calculate based on when it + # was moved out of draft. + for event in pr.get_issue_events(): + if event.event == 'ready_for_review': + created = event.created_at + + # calculate time the PR was in review, hours and business days. + delta = pr.closed_at - created + deltah = delta.total_seconds() / 3600 + prj['hours_open'] = deltah + + dates = (created + timedelta(idx + 1) for idx in range((pr.closed_at - created).days)) + + # Get number of business days per the guidelines, we need at least 2. + business_days = sum(1 for day in dates if day.weekday() < 5) + prj['business_days_open'] = business_days + + trivial = 'Trivial' in labels + hotfix = 'Hotfix' in labels + min_review_time_rule = "no" + + if hotfix or (trivial and deltah >= 4) or business_days >= 2: + min_review_time_rule = "yes" + + prj['time_rule'] = min_review_time_rule + + # This is all data we get easily though the Github API and serves as the basis + # for displaying some trends and metrics. + # Data can be extended in the future if we find more information that + # is useful through the API + + prj['nr'] = pr.number + prj['url'] = pr.url + prj['title'] = pr.title + prj['comments'] = pr.comments + prj['reviews'] = reviews.totalCount + prj['assignees'] = assignees + prj['updated'] = pr.updated_at.strftime("%Y-%m-%d %H:%M:%S") + prj['created'] = pr.created_at.strftime("%Y-%m-%d %H:%M:%S") + prj['closed'] = pr.closed_at.strftime("%Y-%m-%d %H:%M:%S") + prj['merged_by'] = pr.merged_by.login + prj['submitted_by'] = pr.user.login + prj['changed_files'] = pr.changed_files + prj['additions'] = pr.additions + prj['deletions'] = pr.deletions + prj['commits'] = pr.commits + # The branch we are targeting. main vs release branches. + prj['base'] = pr.base.ref + + # list all reviewers + prj['reviewers'] = list(reviewers) + prj['labels'] = labels + + return prj + +def main(): + args = parse_args() + token = os.environ.get('GITHUB_TOKEN') + if not token: + sys.exit('Github token not set in environment, please set the ' + 'GITHUB_TOKEN environment variable and retry.') + + gh = Github(token) + json_list = [] + gh_repo = gh.get_repo(args.repo) + + if args.pull_request: + pr = gh_repo.get_pull(args.pull_request) + prj = process_pr(pr) + json_list.append(prj) + elif args.range: + query = f'repo:{args.repo} merged:{args.range} is:pr is:closed sort:updated-desc base:main' + prs = gh.search_issues(query=f'{query}') + for _pr in prs: + pr = gh_repo.get_pull(_pr.number) + prj = process_pr(pr) + json_list.append(prj) + + if json_list and not args.dry_run: + # Send data over to elasticsearch. + es = Elasticsearch( + [os.environ['ELASTICSEARCH_SERVER']], + api_key=os.environ['ELASTICSEARCH_KEY'], + verify_certs=False + ) + + try: + if args.es_index: + index = args.es_index + else: + index = os.environ['PR_STAT_ES_INDEX'] + bulk(es, gendata(json_list, index)) + except KeyError as e: + print(f"Error: {e} not set.") + print(json_list) + if args.dry_run: + pprint.pprint(json_list) + +if __name__ == "__main__": + main() diff --git a/scripts/ci/version_mgr.py b/scripts/ci/version_mgr.py index 3957595d351..b800f36b42b 100755 --- a/scripts/ci/version_mgr.py +++ b/scripts/ci/version_mgr.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2020 Intel Corp. +# Copyright (c) 2020-2023 Intel Corp. # SPDX-License-Identifier: Apache-2.0 """ @@ -16,6 +16,7 @@ import argparse import urllib.request import os +import tempfile from git import Git from datetime import datetime @@ -34,6 +35,8 @@ def parse_args(): help="Get latest published version") parser.add_argument('-w', '--weekly', action="store_true", help="Mark as weekly") + parser.add_argument('-W', '--list-weekly', action="store_true", + help="List weekly commits") parser.add_argument('-v', '--verbose', action="store_true", help="Verbose output") return parser.parse_args() @@ -41,12 +44,12 @@ def parse_args(): def get_versions(): data = None + fo = tempfile.NamedTemporaryFile() if not os.path.exists('versions.json'): url = 'https://testing.zephyrproject.org/daily_tests/versions.json' - urllib.request.urlretrieve(url, 'versions.json') - with open("versions.json", "r") as fp: + urllib.request.urlretrieve(url, fo.name) + with open(fo.name, "r") as fp: data = json.load(fp) - return data def handle_compat(item): @@ -60,11 +63,13 @@ def handle_compat(item): return item_compat -def show_versions(): +def show_versions(weekly=False): data = get_versions() for item in data: item_compat = handle_compat(item) is_weekly = item_compat.get('weekly', False) + if weekly and not is_weekly: + continue wstr = "" datestr = "" if args.verbose: @@ -79,6 +84,7 @@ def show_versions(): print(f"{item_compat['version']}") + def show_latest(): data = get_versions() latest = data[-1] @@ -134,8 +140,8 @@ def main(): args = parse_args() if args.update: update(args.update, args.weekly) - elif args.list: - show_versions() + elif args.list or args.list_weekly: + show_versions(weekly=args.list_weekly) elif args.latest: show_latest() else: diff --git a/scripts/coredump/gdbstubs/arch/xtensa.py b/scripts/coredump/gdbstubs/arch/xtensa.py index fbe572ac16b..c8829408ee2 100644 --- a/scripts/coredump/gdbstubs/arch/xtensa.py +++ b/scripts/coredump/gdbstubs/arch/xtensa.py @@ -76,7 +76,7 @@ def get_gdb_reg_definition(soc, toolchain): class ExceptionCodes(Enum): - # Matches arch/xtensa/core/fatal.c->z_xtensa_exccause + # Matches arch/xtensa/core/fatal.c->xtensa_exccause ILLEGAL_INSTRUCTION = 0 # Syscall not fatal INSTR_FETCH_ERROR = 2 diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index 7721b5b4fe8..b23a4cb76fe 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -477,6 +477,23 @@ def map_arm_gic_irq_type(irq, irq_num): name_vals.append((name_macro, f"DT_{idx_macro}")) name_vals.append((name_macro + "_EXISTS", 1)) + idx_controller_macro = f"{path_id}_IRQ_IDX_{i}_CONTROLLER" + idx_controller_path = f"DT_{irq.controller.z_path_id}" + idx_vals.append((idx_controller_macro, idx_controller_path)) + if irq.name: + name_controller_macro = f"{path_id}_IRQ_NAME_{str2ident(irq.name)}_CONTROLLER" + name_vals.append((name_controller_macro, f"DT_{idx_controller_macro}")) + + # Interrupt controller info + irqs = [] + while node.interrupts is not None and len(node.interrupts) > 0: + irq = node.interrupts[0] + irqs.append(irq) + if node == irq.controller: + break + node = irq.controller + idx_vals.append((f"{path_id}_IRQ_LEVEL", len(irqs))) + for macro, val in idx_vals: out_dt_define(macro, val) for macro, val in name_vals: diff --git a/scripts/footprint/fpdiff.py b/scripts/footprint/fpdiff.py index fe9c40bc40d..c76bf4a5806 100755 --- a/scripts/footprint/fpdiff.py +++ b/scripts/footprint/fpdiff.py @@ -15,7 +15,7 @@ # ./scripts/footprint/fpdiff.py ram1.json ram2.json from anytree.importer import DictImporter -from anytree import PreOrderIter +from anytree import PreOrderIter, AnyNode from anytree.search import find import colorama @@ -46,7 +46,10 @@ def main(): for idx, ch in enumerate(data1['symbols']['children']): root1 = importer.import_(ch) - root2 = importer.import_(data2['symbols']['children'][idx]) + if idx >= len(data2['symbols']['children']): + root2 = AnyNode(identifier=None) + else: + root2 = importer.import_(data2['symbols']['children'][idx]) print(f"{root1.name}\n+++++++++++++++++++++") for node in PreOrderIter(root1): diff --git a/scripts/get_maintainer.py b/scripts/get_maintainer.py index 34db3708f50..8e2a09b2152 100755 --- a/scripts/get_maintainer.py +++ b/scripts/get_maintainer.py @@ -175,12 +175,12 @@ def __init__(self, filename=None): the top-level directory of the Git repository is used, and must exist. """ - self._toplevel = pathlib.Path(_git("rev-parse", "--show-toplevel")) - - if filename is None: - self.filename = self._toplevel / "MAINTAINERS.yml" - else: + if (filename is not None) and (pathlib.Path(filename).exists()): self.filename = pathlib.Path(filename) + self._toplevel = self.filename.parent + else: + self._toplevel = pathlib.Path(_git("rev-parse", "--show-toplevel")) + self.filename = self._toplevel / "MAINTAINERS.yml" self.areas = {} for area_name, area_dict in _load_maintainers(self.filename).items(): @@ -191,6 +191,8 @@ def __init__(self, filename=None): area.collaborators = area_dict.get("collaborators", []) area.inform = area_dict.get("inform", []) area.labels = area_dict.get("labels", []) + area.tests = area_dict.get("tests", []) + area.tags = area_dict.get("tags", []) area.description = area_dict.get("description") # area._match_fn(path) tests if the path matches files and/or @@ -403,12 +405,16 @@ def _print_areas(areas): \tcollaborators: {} \tinform: {} \tlabels: {} +\ttests: {} +\ttags: {} \tdescription: {}""".format(area.name, area.status, ", ".join(area.maintainers), ", ".join(area.collaborators), ", ".join(area.inform), ", ".join(area.labels), + ", ".join(area.tests), + ", ".join(area.tags), area.description or "")) @@ -479,7 +485,7 @@ def ferr(msg): ok_keys = {"status", "maintainers", "collaborators", "inform", "files", "files-exclude", "files-regex", "files-regex-exclude", - "labels", "description"} + "labels", "description", "tests", "tags"} ok_status = {"maintained", "odd fixes", "unmaintained", "obsolete"} ok_status_s = ", ".join('"' + s + '"' for s in ok_status) # For messages @@ -504,7 +510,7 @@ def ferr(msg): "for area '{}'".format(area_name)) for list_name in "maintainers", "collaborators", "inform", "files", \ - "files-regex", "labels": + "files-regex", "labels", "tags", "tests": if list_name in area_dict: lst = area_dict[list_name] if not (isinstance(lst, list) and diff --git a/scripts/kconfig/kconfigfunctions.py b/scripts/kconfig/kconfigfunctions.py index 621ec3cb3a8..71200b7f955 100644 --- a/scripts/kconfig/kconfigfunctions.py +++ b/scripts/kconfig/kconfigfunctions.py @@ -245,6 +245,33 @@ def _node_array_prop(node, prop, index=0, unit=None): return 0 return node.props[prop].val[int(index)] >> _dt_units_to_scale(unit) +def _node_ph_array_prop(node, prop, index, cell, unit=None): + """ + This function takes a 'node', a property name ('prop'), index ('index') and + a cell ('cell') and it will look to see if that node has a property + called 'prop' and if that 'prop' is an phandle-array type. + Then it will check if that phandle array has a cell matching the given index + and then return the value of the cell named 'cell' in this array index. + If not found it will return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + """ + if not node: + return 0 + + if prop not in node.props: + return 0 + if node.props[prop].type != "phandle-array": + return 0 + if int(index) >= len(node.props[prop].val): + return 0 + if cell not in node.props[prop].val[int(index)].data.keys(): + return 0 + return node.props[prop].val[int(index)].data[cell] >> _dt_units_to_scale(unit) def _dt_chosen_reg_addr(kconf, chosen, index=0, unit=None): """ @@ -309,6 +336,48 @@ def dt_chosen_reg(kconf, name, chosen, index=0, unit=None): return hex(_dt_chosen_reg_addr(kconf, chosen, index, unit)) +def _dt_chosen_partition_addr(kconf, chosen, index=0, unit=None): + """ + This function takes a 'chosen' property and treats that property as a path + to an EDT node. If it finds an EDT node, it will look to see if that + node has a register, and if that node has a grandparent that has a register + at the given 'index'. The addition of both addresses will be returned, if + not, we return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + 'kb' or 'Kb' divide by 8192 (1 << 13) + 'mb' or 'Mb' divide by 8,388,608 (1 << 23) + 'gb' or 'Gb' divide by 8,589,934,592 (1 << 33) + """ + if doc_mode or edt is None: + return 0 + + node = edt.chosen_node(chosen) + if not node: + return 0 + + p_node = node.parent + if not p_node: + return 0 + + return _node_reg_addr(p_node.parent, index, unit) + _node_reg_addr(node, 0, unit) + + +def dt_chosen_partition_addr(kconf, name, chosen, index=0, unit=None): + """ + This function just routes to the proper function and converts + the result to either a string int or string hex value. + """ + if name == "dt_chosen_partition_addr_int": + return str(_dt_chosen_partition_addr(kconf, chosen, index, unit)) + if name == "dt_chosen_partition_addr_hex": + return hex(_dt_chosen_partition_addr(kconf, chosen, index, unit)) + + def _dt_node_reg_addr(kconf, path, index=0, unit=None): """ This function takes a 'path' and looks for an EDT node at that path. If it @@ -559,6 +628,34 @@ def dt_node_array_prop(kconf, name, path, prop, index, unit=None): return hex(_node_array_prop(node, prop, index, unit)) +def dt_node_ph_array_prop(kconf, name, path, prop, index, cell, unit=None): + """ + This function takes a 'path', property name ('prop'), index ('index') and + a cell ('cell') and looks for an EDT node at that path. + If it finds an EDT node, it will look to see if that node has a property + called 'prop' and if that 'prop' is an phandle-array type. + Then it will check if that phandle array has a cell matching the given index + and ten return the value of the cell named 'cell' in this array index as + either a string int or string hex value. If not found we return 0. + + The function will divide the value based on 'unit': + None No division + 'k' or 'K' divide by 1024 (1 << 10) + 'm' or 'M' divide by 1,048,576 (1 << 20) + 'g' or 'G' divide by 1,073,741,824 (1 << 30) + """ + if doc_mode or edt is None: + return "0" + + try: + node = edt.get_node(path) + except edtlib.EDTError: + return "0" + if name == "dt_node_ph_array_prop_int": + return str(_node_ph_array_prop(node, prop, index, cell, unit)) + if name == "dt_node_ph_array_prop_hex": + return hex(_node_ph_array_prop(node, prop, index, cell, unit)) + def dt_node_str_prop_equals(kconf, _, path, prop, val): """ This function takes a 'path' and property name ('prop') looks for an EDT @@ -799,6 +896,8 @@ def shields_list_contains(kconf, _, shield): "dt_node_int_prop_hex": (dt_node_int_prop, 2, 3), "dt_node_array_prop_int": (dt_node_array_prop, 3, 4), "dt_node_array_prop_hex": (dt_node_array_prop, 3, 4), + "dt_node_ph_array_prop_int": (dt_node_ph_array_prop, 4, 5), + "dt_node_ph_array_prop_hex": (dt_node_ph_array_prop, 4, 5), "dt_node_str_prop_equals": (dt_node_str_prop_equals, 3, 3), "dt_nodelabel_has_compat": (dt_nodelabel_has_compat, 2, 2), "dt_node_has_compat": (dt_node_has_compat, 2, 2), @@ -806,5 +905,7 @@ def shields_list_contains(kconf, _, shield): "dt_node_parent": (dt_node_parent, 1, 1), "dt_nodelabel_array_prop_has_val": (dt_nodelabel_array_prop_has_val, 3, 3), "dt_gpio_hogs_enabled": (dt_gpio_hogs_enabled, 0, 0), + "dt_chosen_partition_addr_int": (dt_chosen_partition_addr, 1, 3), + "dt_chosen_partition_addr_hex": (dt_chosen_partition_addr, 1, 3), "shields_list_contains": (shields_list_contains, 1, 1), } diff --git a/scripts/logging/dictionary/dictionary_parser/mipi_syst.py b/scripts/logging/dictionary/dictionary_parser/mipi_syst.py index 467e74400c1..046a120d2fc 100644 --- a/scripts/logging/dictionary/dictionary_parser/mipi_syst.py +++ b/scripts/logging/dictionary/dictionary_parser/mipi_syst.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2022 - 2023 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 @@ -106,7 +106,7 @@ def __gen_syst_catalog(database): fmt = XML_CATALOG32_EACH for addr, one_str in database.get_string_mappings().items(): - xml += fmt.format(addr, escape(one_str)) + xml += fmt.format(addr, one_str) if database.is_tgt_64bit(): xml += XML_CATALOG64_FOOTER diff --git a/scripts/native_simulator/Makefile b/scripts/native_simulator/Makefile index e74b1c7bc69..a60218f45e9 100644 --- a/scripts/native_simulator/Makefile +++ b/scripts/native_simulator/Makefile @@ -60,7 +60,7 @@ NSI_OPT?=-O0 # Warnings switches (for the runner itself) NSI_WARNINGS?=-Wall -Wpedantic # Preprocessor flags -NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED +NSI_CPPFLAGS?=-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED NO_PIE_CO:=-fno-pie -fno-pic DEPENDFLAGS:=-MMD -MP diff --git a/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h b/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h index 7c7df5cd0c6..2289fcc7bd4 100644 --- a/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h +++ b/scripts/native_simulator/common/src/include/nsi_cmdline_main_if.h @@ -18,6 +18,7 @@ extern "C" { #endif void nsi_handle_cmd_line(int argc, char *argv[]); +void nsi_register_extra_args(int argc, char *argv[]); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h index f7f7dce877d..5262a5a6909 100644 --- a/scripts/native_simulator/common/src/include/nsi_host_trampolines.h +++ b/scripts/native_simulator/common/src/include/nsi_host_trampolines.h @@ -11,7 +11,7 @@ * to the embedded side, for example due to non-basic types being used in * function calls, as that would break the include path isolation * - * Naming convention: nsi_hots_() where is the name of the equivalent + * Naming convention: nsi_host_() where is the name of the equivalent * C library call we call thru. */ @@ -33,6 +33,7 @@ int nsi_host_open(const char *pathname, int flags); /* int nsi_host_printf (const char *fmt, ...); Use the nsi_tracing.h equivalents */ long nsi_host_random(void); long nsi_host_read(int fd, void *buffer, unsigned long size); +void *nsi_host_realloc(void *ptr, unsigned long size); void nsi_host_srandom(unsigned int seed); char *nsi_host_strdup(const char *s); long nsi_host_write(int fd, void *buffer, unsigned long size); diff --git a/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h index e5b4c64f3b8..edff33da8e1 100644 --- a/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h +++ b/scripts/native_simulator/common/src/include/nsi_hw_scheduler.h @@ -16,7 +16,11 @@ extern "C" { #define NSI_NEVER UINT64_MAX /* API intended for the native simulator specific embedded drivers: */ -uint64_t nsi_hws_get_time(void); +static inline uint64_t nsi_hws_get_time(void) +{ + extern uint64_t nsi_simu_time; + return nsi_simu_time; +} /* Internal APIs to the native_simulator and its HW models: */ void nsi_hws_init(void); diff --git a/scripts/native_simulator/common/src/include/nsi_main.h b/scripts/native_simulator/common/src/include/nsi_main.h index 83ba8cac433..33508edb7fe 100644 --- a/scripts/native_simulator/common/src/include/nsi_main.h +++ b/scripts/native_simulator/common/src/include/nsi_main.h @@ -7,6 +7,8 @@ #ifndef NSI_COMMON_SRC_INCL_NSI_MAIN_H #define NSI_COMMON_SRC_INCL_NSI_MAIN_H +#include "nsi_utils.h" + #ifdef __cplusplus extern "C" { #endif @@ -31,7 +33,7 @@ int nsi_exit_inner(int exit_code); * Note that other components may have requested a different * exit code which may have precedence if it was !=0 */ -void nsi_exit(int exit_code); +NSI_FUNC_NORETURN void nsi_exit(int exit_code); #ifdef __cplusplus } diff --git a/scripts/native_simulator/common/src/include/nsi_utils.h b/scripts/native_simulator/common/src/include/nsi_utils.h index f41fdf9ddc8..996ad635409 100644 --- a/scripts/native_simulator/common/src/include/nsi_utils.h +++ b/scripts/native_simulator/common/src/include/nsi_utils.h @@ -25,4 +25,8 @@ #define NSI_ARG_UNUSED(x) (void)(x) #endif +#define NSI_CODE_UNREACHABLE __builtin_unreachable() + +#define NSI_FUNC_NORETURN __attribute__((__noreturn__)) + #endif /* NSI_COMMON_SRC_INCL_NSI_UTILS_H */ diff --git a/scripts/native_simulator/common/src/main.c b/scripts/native_simulator/common/src/main.c index ffe1d3b93d1..9b5c566fae0 100644 --- a/scripts/native_simulator/common/src/main.c +++ b/scripts/native_simulator/common/src/main.c @@ -44,13 +44,13 @@ int nsi_exit_inner(int exit_code) return max_exit_code; } -void nsi_exit(int exit_code) +NSI_FUNC_NORETURN void nsi_exit(int exit_code) { exit(nsi_exit_inner(exit_code)); } /** - * Run all early native_posix initialization steps, including command + * Run all early native simulator initialization steps, including command * line parsing and CPU start, until we are ready to let the HW models * run via hwm_one_event() */ diff --git a/scripts/native_simulator/common/src/nsi_host_trampolines.c b/scripts/native_simulator/common/src/nsi_host_trampolines.c index 3feb8482c91..093a66d53ca 100644 --- a/scripts/native_simulator/common/src/nsi_host_trampolines.c +++ b/scripts/native_simulator/common/src/nsi_host_trampolines.c @@ -56,6 +56,11 @@ long nsi_host_read(int fd, void *buffer, unsigned long size) return read(fd, buffer, size); } +void *nsi_host_realloc(void *ptr, unsigned long size) +{ + return realloc(ptr, size); +} + void nsi_host_srandom(unsigned int seed) { srandom(seed); diff --git a/scripts/native_simulator/common/src/nsi_hw_scheduler.c b/scripts/native_simulator/common/src/nsi_hw_scheduler.c index 60cf06167c4..c936961bd0f 100644 --- a/scripts/native_simulator/common/src/nsi_hw_scheduler.c +++ b/scripts/native_simulator/common/src/nsi_hw_scheduler.c @@ -21,7 +21,7 @@ #include "nsi_hw_scheduler.h" #include "nsi_hws_models_if.h" -static uint64_t simu_time; /* The actual time as known by the HW models */ +uint64_t nsi_simu_time; /* The actual time as known by the HW models */ static uint64_t end_of_time = NSI_NEVER; /* When will this device stop */ extern struct nsi_hw_event_st __nsi_hw_events_start[]; @@ -55,7 +55,7 @@ static void nsi_hws_signal_end_handler(int sig) * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received * the default handler would be called to terminate the program no matter what. * - * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or + * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809L or * _XOPEN_SOURCE>=500 */ static void nsi_hws_set_sig_handler(void) @@ -74,21 +74,21 @@ static void nsi_hws_set_sig_handler(void) static void nsi_hws_sleep_until_next_event(void) { - if (next_timer_time >= simu_time) { /* LCOV_EXCL_BR_LINE */ - simu_time = next_timer_time; + if (next_timer_time >= nsi_simu_time) { /* LCOV_EXCL_BR_LINE */ + nsi_simu_time = next_timer_time; } else { /* LCOV_EXCL_START */ nsi_print_warning("next_timer_time corrupted (%"PRIu64"<= %" PRIu64", timer idx=%i)\n", (uint64_t)next_timer_time, - (uint64_t)simu_time, + (uint64_t)nsi_simu_time, next_timer_index); /* LCOV_EXCL_STOP */ } - if (signaled_end || (simu_time > end_of_time)) { + if (signaled_end || (nsi_simu_time > end_of_time)) { nsi_print_trace("\nStopped at %.3Lfs\n", - ((long double)simu_time)/1.0e6L); + ((long double)nsi_simu_time)/1.0e6L); nsi_exit(0); } } @@ -141,14 +141,6 @@ void nsi_hws_set_end_of_time(uint64_t new_end_of_time) end_of_time = new_end_of_time; } -/** - * Return the current simulated time as known by the device - */ -uint64_t nsi_hws_get_time(void) -{ - return simu_time; -} - /** * Function to initialize the HW scheduler * diff --git a/scripts/native_simulator/native/src/nsi_cmdline.c b/scripts/native_simulator/native/src/nsi_cmdline.c index e2fefb677fa..c2490aa85cb 100644 --- a/scripts/native_simulator/native/src/nsi_cmdline.c +++ b/scripts/native_simulator/native/src/nsi_cmdline.c @@ -18,6 +18,10 @@ static int s_argc, test_argc; static char **s_argv, **test_argv; +/* Extra "command line options" provided programmatically: */ +static int extra_argc; +static char **extra_argv; + static struct args_struct_t *args_struct; static int used_args; static int args_aval; @@ -119,6 +123,13 @@ void nsi_handle_cmd_line(int argc, char *argv[]) nsi_cmd_args_set_defaults(args_struct); + for (int i = 0; i < extra_argc; i++) { + if (!nsi_cmd_parse_one_arg(extra_argv[i], args_struct)) { + nsi_cmd_print_switches_help(args_struct); + print_invalid_opt_error(extra_argv[i]); + } + } + for (i = 1; i < argc; i++) { if ((nsi_cmd_is_option(argv[i], "testargs", 0))) { @@ -134,6 +145,24 @@ void nsi_handle_cmd_line(int argc, char *argv[]) } } +void nsi_register_extra_args(int argc, char *argv[]) +{ + int new_size = extra_argc + argc; + + extra_argv = realloc(extra_argv, new_size*sizeof(char *)); + for (int i = 0; i < argc; i++) { + memcpy(&extra_argv[extra_argc], argv, argc*sizeof(char *)); + } + extra_argc += argc; +} + +static void clear_extra_args(void) +{ + free(extra_argv); +} + +NSI_TASK(clear_extra_args, ON_EXIT_PRE, 100); + /** * The application/test can use this function to inspect all the command line * arguments diff --git a/scripts/native_simulator/native/src/timer_model.c b/scripts/native_simulator/native/src/timer_model.c index de74e6cac93..a25cc1c5e6e 100644 --- a/scripts/native_simulator/native/src/timer_model.c +++ b/scripts/native_simulator/native/src/timer_model.c @@ -126,7 +126,12 @@ static inline void host_clock_gettime(struct timespec *tv) #endif } -static uint64_t get_host_us_time(void) +/* + * This function is globally available only for tests purposes + * It should not be used for any functional purposes, + * and as such is not present in this component header. + */ +uint64_t get_host_us_time(void) { struct timespec tv; diff --git a/scripts/net/run-sample-tests.sh b/scripts/net/run-sample-tests.sh index 11162b30b5e..85f5d62efc9 100755 --- a/scripts/net/run-sample-tests.sh +++ b/scripts/net/run-sample-tests.sh @@ -157,7 +157,7 @@ start_zephyr () fi rm -rf build && mkdir build && \ - cmake -GNinja -DBOARD=native_posix -B build "$@" . && \ + cmake -GNinja -DBOARD=native_sim -B build "$@" . && \ ninja -C build # Run the binary directly so that ninja does not print errors that diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py index 59be6c52af9..b5560650c1b 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/device_adapter.py @@ -25,7 +25,11 @@ class DeviceAdapter(abc.ABC): - """Class defines an interface for all devices.""" + """ + This class defines a common interface for all device types (hardware, + simulator, QEMU) used in tests to gathering device output and send data to + it. + """ def __init__(self, device_config: DeviceConfig) -> None: """ @@ -54,19 +58,27 @@ def env(self) -> dict[str, str]: def launch(self) -> None: """ Start by closing previously running application (no effect if not - needed). Then, flash and run test application. Finally, start a reader - thread capturing an output from a device. + needed). Then, flash and run test application. Finally, start an + internal reader thread capturing an output from a device. """ self.close() self._clear_internal_resources() if not self.command: self.generate_command() - self._flash_and_run() + + if self.device_config.type != 'hardware': + self._flash_and_run() + self._device_run.set() self._start_reader_thread() self.connect() + if self.device_config.type == 'hardware': + # On hardware, flash after connecting to COM port, otherwise some messages + # from target can be lost. + self._flash_and_run() + def close(self) -> None: """Disconnect, close device and close reader thread.""" if not self._device_run.is_set(): @@ -100,7 +112,7 @@ def disconnect(self) -> None: def readline(self, timeout: float | None = None, print_output: bool = True) -> str: """ Read line from device output. If timeout is not provided, then use - base_timeout + base_timeout. """ timeout = timeout or self.base_timeout if self.is_device_connected() or not self._device_read_queue.empty(): @@ -125,13 +137,13 @@ def readlines_until( until following conditions: 1. If regex is provided - read until regex regex is found in read - line (or until timeout) + line (or until timeout). 2. If num_of_lines is provided - read until number of read lines is - equal to num_of_lines (or until timeout) + equal to num_of_lines (or until timeout). 3. If none of above is provided - return immediately lines collected so - far in internal queue + far in internal buffer. - If timeout is not provided, then use base_timeout + If timeout is not provided, then use base_timeout. """ timeout = timeout or self.base_timeout if regex: diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py index 3b7bf5d8214..4a6967b6372 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/device/hardware_adapter.py @@ -6,7 +6,8 @@ import logging import os -import pty +if os.name != 'nt': + import pty import re import subprocess import time @@ -150,7 +151,13 @@ def _open_serial_pty(self) -> str | None: """Open a pty pair, run process and return tty name""" if not self.device_config.serial_pty: return None - master, slave = pty.openpty() + + try: + master, slave = pty.openpty() + except NameError as exc: + logger.exception('PTY module is not available.') + raise exc + try: self._serial_pty_proc = subprocess.Popen( re.split(',| ', self.device_config.serial_pty), diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py index f2b1b53706c..a4819ca20c1 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py @@ -6,6 +6,7 @@ from typing import Generator, Type import pytest +import time from twister_harness.device.device_adapter import DeviceAdapter from twister_harness.device.factory import DeviceFactory @@ -58,7 +59,13 @@ def shell(dut: DeviceAdapter) -> Shell: """Return ready to use shell interface""" shell = Shell(dut, timeout=20.0) logger.info('Wait for prompt') - assert shell.wait_for_prompt() + if not shell.wait_for_prompt(): + pytest.fail('Prompt not found') + if dut.device_config.type == 'hardware': + # after booting up the device, there might appear additional logs + # after first prompt, so we need to wait and clear the buffer + time.sleep(0.5) + dut.clear_buffer() return shell diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py index b6cab6475c1..038c16a4fc8 100755 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/mcumgr.py @@ -54,8 +54,11 @@ def run_command(self, cmd: str) -> str: def reset_device(self): self.run_command('reset') - def image_upload(self, image: Path | str, timeout: int = 30): - self.run_command(f'-t {timeout} image upload {image}') + def image_upload(self, image: Path | str, slot: int | None = None, timeout: int = 30): + command = f'-t {timeout} image upload {image}' + if slot is not None: + command += f' -e -n {slot}' + self.run_command(command) logger.info('Image successfully uploaded') def get_image_list(self) -> list[MCUmgrImage]: @@ -88,10 +91,19 @@ def _parse_image_list(cmd_output: str) -> list[MCUmgrImage]: def get_hash_to_test(self) -> str: image_list = self.get_image_list() - if len(image_list) < 2: - logger.info(image_list) - raise MCUmgrException('Please check image list returned by mcumgr') - return image_list[1].hash + for image in image_list: + if 'active' not in image.flags: + return image.hash + logger.warning(f'Images returned by mcumgr (no not active):\n{image_list}') + raise MCUmgrException('No not active image found') + + def get_hash_to_confirm(self): + image_list = self.get_image_list() + for image in image_list: + if 'confirmed' not in image.flags: + return image.hash + logger.warning(f'Images returned by mcumgr (no not confirmed):\n{image_list}') + raise MCUmgrException('No not confirmed image found') def image_test(self, hash: str | None = None): if not hash: @@ -100,6 +112,5 @@ def image_test(self, hash: str | None = None): def image_confirm(self, hash: str | None = None): if not hash: - image_list = self.get_image_list() - hash = image_list[0].hash + hash = self.get_hash_to_confirm() self.run_command(f'image confirm {hash}') diff --git a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py index f6eb8074451..bf8b70cea91 100644 --- a/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py +++ b/scripts/pylib/pytest-twister-harness/src/twister_harness/helpers/shell.py @@ -45,8 +45,6 @@ def wait_for_prompt(self, timeout: float | None = None) -> bool: continue if self.prompt in line: logger.debug('Got prompt') - time.sleep(0.05) - self._device.clear_buffer() return True return False @@ -55,7 +53,7 @@ def exec_command(self, command: str, timeout: float | None = None, print_output: Send shell command to a device and return response. Passed command is extended by double enter sings - first one to execute this command on a device, second one to receive next prompt what is a signal that - execution was finished. + execution was finished. Method returns printout of the executed command. """ timeout = timeout or self.base_timeout command_ext = f'{command}\n\n' diff --git a/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py b/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py index f336311143a..e8aaabe8fe1 100644 --- a/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py +++ b/scripts/pylib/pytest-twister-harness/tests/fixtures/mcumgr_fixture_test.py @@ -27,6 +27,9 @@ def test_if_mcumgr_fixture_generate_proper_command( mcumgr.image_upload('/path/to/image', timeout=100) patched_run_command.assert_called_with('-t 100 image upload /path/to/image') + mcumgr.image_upload('/path/to/image', slot=2, timeout=100) + patched_run_command.assert_called_with('-t 100 image upload /path/to/image -e -n 2') + mcumgr.image_test(hash='ABCD') patched_run_command.assert_called_with('image test ABCD') @@ -55,12 +58,12 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: image=0 slot=0 version: 0.0.0 bootable: true - flags: + flags: active confirmed hash: 0000 image=0 slot=1 version: 1.1.1 bootable: true - flags: pending + flags: hash: 1111 Split status: N/A (0) """) @@ -69,12 +72,12 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: assert image_list[0].image == 0 assert image_list[0].slot == 0 assert image_list[0].version == '0.0.0' - assert image_list[0].flags == '' + assert image_list[0].flags == 'active confirmed' assert image_list[0].hash == '0000' assert image_list[1].image == 0 assert image_list[1].slot == 1 assert image_list[1].version == '1.1.1' - assert image_list[1].flags == 'pending' + assert image_list[1].flags == '' assert image_list[1].hash == '1111' # take second hash to test @@ -83,4 +86,4 @@ def test_if_mcumgr_fixture_parse_image_list(mcumgr: MCUmgr) -> None: # take first hash to confirm mcumgr.image_confirm() - mcumgr.run_command.assert_called_with('image confirm 0000') + mcumgr.run_command.assert_called_with('image confirm 1111') diff --git a/scripts/pylib/twister/twisterlib/config_parser.py b/scripts/pylib/twister/twisterlib/config_parser.py index 53732876247..843fce51a7c 100644 --- a/scripts/pylib/twister/twisterlib/config_parser.py +++ b/scripts/pylib/twister/twisterlib/config_parser.py @@ -70,6 +70,7 @@ class TwisterConfigParser: "platform_exclude": {"type": "set"}, "platform_allow": {"type": "set"}, "platform_key": {"type": "list", "default": []}, + "simulation_exclude": {"type": "list", "default": []}, "toolchain_exclude": {"type": "set"}, "toolchain_allow": {"type": "set"}, "filter": {"type": "str"}, diff --git a/scripts/pylib/twister/twisterlib/coverage.py b/scripts/pylib/twister/twisterlib/coverage.py index c1c9065d9ad..556f5b359ba 100644 --- a/scripts/pylib/twister/twisterlib/coverage.py +++ b/scripts/pylib/twister/twisterlib/coverage.py @@ -3,6 +3,7 @@ # Copyright (c) 2018-2022 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +import sys import os import logging import pathlib @@ -14,6 +15,12 @@ logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) +supported_coverage_formats = { + "gcovr": ["html", "xml", "csv", "txt", "coveralls", "sonarqube"], + "lcov": ["html", "lcov"] +} + + class CoverageTool: """ Base class for every supported coverage tool """ @@ -24,9 +31,9 @@ def __init__(self): self.output_formats = None @staticmethod - def factory(tool): + def factory(tool, jobs=None): if tool == 'lcov': - t = Lcov() + t = Lcov(jobs) elif tool == 'gcovr': t = Gcovr() else: @@ -134,10 +141,27 @@ def generate(self, outdir): class Lcov(CoverageTool): - def __init__(self): + def __init__(self, jobs=None): super().__init__() self.ignores = [] self.output_formats = "lcov,html" + self.version = self.get_version() + self.jobs = jobs + + def get_version(self): + try: + result = subprocess.run(['lcov', '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, check=True) + version_output = result.stdout.strip().replace('lcov: LCOV version ', '') + return version_output + except subprocess.CalledProcessError as e: + logger.error(f"Unable to determine lcov version: {e}") + sys.exit(1) + except FileNotFoundError as e: + logger.error(f"Unable to to find lcov tool: {e}") + sys.exit(1) def add_ignore_file(self, pattern): self.ignores.append('*' + pattern + '*') @@ -145,51 +169,82 @@ def add_ignore_file(self, pattern): def add_ignore_directory(self, pattern): self.ignores.append('*/' + pattern + '/*') + @property + def is_lcov_v2(self): + return self.version.startswith("2") + + def run_command(self, cmd, coveragelog): + if self.is_lcov_v2: + # The --ignore-errors source option is added for genhtml as well as + # lcov to avoid it exiting due to + # samples/application_development/external_lib/ + cmd += [ + "--ignore-errors", "inconsistent,inconsistent", + "--ignore-errors", "negative,negative", + "--ignore-errors", "unused,unused", + "--ignore-errors", "empty,empty", + "--ignore-errors", "mismatch,mismatch", + ] + + cmd_str = " ".join(cmd) + logger.debug(f"Running {cmd_str}...") + return subprocess.call(cmd, stdout=coveragelog) + + def run_lcov(self, args, coveragelog): + if self.is_lcov_v2: + branch_coverage = "branch_coverage=1" + if self.jobs is None: + # Default: --parallel=0 will autodetect appropriate parallelism + parallel = ["--parallel", "0"] + elif self.jobs == 1: + # Serial execution requested, don't parallelize at all + parallel = [] + else: + parallel = ["--parallel", str(self.jobs)] + else: + branch_coverage = "lcov_branch_coverage=1" + parallel = [] + + cmd = [ + "lcov", "--gcov-tool", self.gcov_tool, + "--rc", branch_coverage, + ] + parallel + args + return self.run_command(cmd, coveragelog) + def _generate(self, outdir, coveragelog): coveragefile = os.path.join(outdir, "coverage.info") ztestfile = os.path.join(outdir, "ztest.info") - cmd = ["lcov", "--gcov-tool", str(self.gcov_tool), - "--capture", "--directory", outdir, - "--rc", "lcov_branch_coverage=1", - "--output-file", coveragefile] - cmd_str = " ".join(cmd) - logger.debug(f"Running {cmd_str}...") - subprocess.call(cmd, stdout=coveragelog) + + cmd = ["--capture", "--directory", outdir, "--output-file", coveragefile] + self.run_lcov(cmd, coveragelog) + # We want to remove tests/* and tests/ztest/test/* but save tests/ztest - subprocess.call(["lcov", "--gcov-tool", self.gcov_tool, "--extract", - coveragefile, - os.path.join(self.base_dir, "tests", "ztest", "*"), - "--output-file", ztestfile, - "--rc", "lcov_branch_coverage=1"], stdout=coveragelog) + cmd = ["--extract", coveragefile, + os.path.join(self.base_dir, "tests", "ztest", "*"), + "--output-file", ztestfile] + self.run_lcov(cmd, coveragelog) if os.path.exists(ztestfile) and os.path.getsize(ztestfile) > 0: - subprocess.call(["lcov", "--gcov-tool", self.gcov_tool, "--remove", - ztestfile, - os.path.join(self.base_dir, "tests/ztest/test/*"), - "--output-file", ztestfile, - "--rc", "lcov_branch_coverage=1"], - stdout=coveragelog) + cmd = ["--remove", ztestfile, + os.path.join(self.base_dir, "tests/ztest/test/*"), + "--output-file", ztestfile] + self.run_lcov(cmd, coveragelog) + files = [coveragefile, ztestfile] else: files = [coveragefile] for i in self.ignores: - subprocess.call( - ["lcov", "--gcov-tool", self.gcov_tool, "--remove", - coveragefile, i, "--output-file", - coveragefile, "--rc", "lcov_branch_coverage=1"], - stdout=coveragelog) + cmd = ["--remove", coveragefile, i, "--output-file", coveragefile] + self.run_lcov(cmd, coveragelog) if 'html' not in self.output_formats.split(','): return 0 - # The --ignore-errors source option is added to avoid it exiting due to - # samples/application_development/external_lib/ - return subprocess.call(["genhtml", "--legend", "--branch-coverage", - "--ignore-errors", "source", - "-output-directory", - os.path.join(outdir, "coverage")] + files, - stdout=coveragelog) + cmd = ["genhtml", "--legend", "--branch-coverage", + "--prefix", self.base_dir, + "-output-directory", os.path.join(outdir, "coverage")] + files + return self.run_command(cmd, coveragelog) class Gcovr(CoverageTool): @@ -198,6 +253,24 @@ def __init__(self): super().__init__() self.ignores = [] self.output_formats = "html" + self.version = self.get_version() + + def get_version(self): + try: + result = subprocess.run(['gcovr', '--version'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, check=True) + version_lines = result.stdout.strip().split('\n') + if version_lines: + version_output = version_lines[0].replace('gcovr ', '') + return version_output + except subprocess.CalledProcessError as e: + logger.error(f"Unable to determine gcovr version: {e}") + sys.exit(1) + except FileNotFoundError as e: + logger.error(f"Unable to to find gcovr tool: {e}") + sys.exit(1) def add_ignore_file(self, pattern): self.ignores.append('.*' + pattern + '.*') @@ -220,12 +293,16 @@ def _generate(self, outdir, coveragelog): excludes = Gcovr._interleave_list("-e", self.ignores) + # Different ifdef-ed implementations of the same function should not be + # in conflict treated by GCOVR as separate objects for coverage statistics. + mode_options = ["--merge-mode-functions=separate"] + # We want to remove tests/* and tests/ztest/test/* but save tests/ztest cmd = ["gcovr", "-r", self.base_dir, "--gcov-ignore-parse-errors=negative_hits.warn_once_per_file", - "--gcov-executable", str(self.gcov_tool), + "--gcov-executable", self.gcov_tool, "-e", "tests/*"] - cmd += excludes + ["--json", "-o", coveragefile, outdir] + cmd += excludes + mode_options + ["--json", "-o", coveragefile, outdir] cmd_str = " ".join(cmd) logger.debug(f"Running {cmd_str}...") subprocess.call(cmd, stdout=coveragelog) @@ -233,7 +310,7 @@ def _generate(self, outdir, coveragelog): subprocess.call(["gcovr", "-r", self.base_dir, "--gcov-executable", self.gcov_tool, "-f", "tests/ztest", "-e", "tests/ztest/test/*", "--json", "-o", ztestfile, - outdir], stdout=coveragelog) + outdir] + mode_options, stdout=coveragelog) if os.path.exists(ztestfile) and os.path.getsize(ztestfile) > 0: files = [coveragefile, ztestfile] @@ -256,13 +333,14 @@ def _generate(self, outdir, coveragelog): } gcovr_options = self._flatten_list([report_options[r] for r in self.output_formats.split(',')]) - return subprocess.call(["gcovr", "-r", self.base_dir] + gcovr_options + tracefiles, + return subprocess.call(["gcovr", "-r", self.base_dir] + mode_options + gcovr_options + tracefiles, stdout=coveragelog) def run_coverage(testplan, options): use_system_gcov = False + gcov_tool = None for plat in options.coverage_platform: _plat = testplan.get_platform(plat) @@ -283,15 +361,21 @@ def run_coverage(testplan, options): os.symlink(llvm_cov, gcov_lnk) except OSError: shutil.copy(llvm_cov, gcov_lnk) - options.gcov_tool = gcov_lnk + gcov_tool = gcov_lnk elif use_system_gcov: - options.gcov_tool = "gcov" + gcov_tool = "gcov" elif os.path.exists(zephyr_sdk_gcov_tool): - options.gcov_tool = zephyr_sdk_gcov_tool + gcov_tool = zephyr_sdk_gcov_tool + else: + logger.error(f"Can't find a suitable gcov tool. Use --gcov-tool or set ZEPHYR_SDK_INSTALL_DIR.") + sys.exit(1) + else: + gcov_tool = str(options.gcov_tool) logger.info("Generating coverage files...") - coverage_tool = CoverageTool.factory(options.coverage_tool) - coverage_tool.gcov_tool = options.gcov_tool + logger.info(f"Using gcov tool: {gcov_tool}") + coverage_tool = CoverageTool.factory(options.coverage_tool, jobs=options.jobs) + coverage_tool.gcov_tool = gcov_tool coverage_tool.base_dir = os.path.abspath(options.coverage_basedir) # Apply output format default if options.coverage_formats is not None: diff --git a/scripts/pylib/twister/twisterlib/environment.py b/scripts/pylib/twister/twisterlib/environment.py index 16e19c85fec..03f6ab7f430 100644 --- a/scripts/pylib/twister/twisterlib/environment.py +++ b/scripts/pylib/twister/twisterlib/environment.py @@ -16,6 +16,7 @@ import re import argparse from datetime import datetime, timezone +from twisterlib.coverage import supported_coverage_formats logger = logging.getLogger('twister') logger.setLevel(logging.DEBUG) @@ -85,14 +86,14 @@ def add_parse_arguments(parser = None): "--save-tests", metavar="FILENAME", action="store", - help="Append list of tests and platforms to be run to file.") + help="Write a list of tests and platforms to be run to file.") case_select.add_argument( "-F", "--load-tests", metavar="FILENAME", action="store", - help="Load list of tests and platforms to be run from file.") + help="Load a list of tests and platforms to be run from file.") case_select.add_argument( "-T", "--testsuite-root", action="append", default=[], @@ -305,13 +306,15 @@ def add_parse_arguments(parser = None): "This option may be used multiple times. " "Default to what was selected with --platform.") - parser.add_argument("--coverage-tool", choices=['lcov', 'gcovr'], default='lcov', + parser.add_argument("--coverage-tool", choices=['lcov', 'gcovr'], default='gcovr', help="Tool to use to generate coverage report.") parser.add_argument("--coverage-formats", action="store", default=None, # default behavior is set in run_coverage - help="Output formats to use for generated coverage reports, as a comma-separated list. " - "Default to html. " - "Valid options are html, xml, csv, txt, coveralls, sonarqube, lcov.") + help="Output formats to use for generated coverage reports, as a comma-separated list. " + + "Valid options for 'gcovr' tool are: " + + ','.join(supported_coverage_formats['gcovr']) + " (html - default)." + + " Valid options for 'lcov' tool are: " + + ','.join(supported_coverage_formats['lcov']) + " (html,lcov - default).") parser.add_argument("--test-config", action="store", default=os.path.join(ZEPHYR_BASE, "tests", "test_config.yaml"), help="Path to file with plans and test configurations.") @@ -453,6 +456,15 @@ def add_parse_arguments(parser = None): help="Re-use the outdir before building. Will result in " "faster compilation since builds will be incremental.") + parser.add_argument( + "--aggressive-no-clean", action="store_true", + help="Re-use the outdir before building and do not re-run cmake. Will result in " + "much faster compilation since builds will be incremental. This option might " + " result in build failures and inconsistencies if dependencies change or when " + " applied on a significantly changed code base. Use on your own " + " risk. It is recommended to only use this option for local " + " development and when testing localized change in a subsystem.") + parser.add_argument( '--detailed-test-id', action='store_true', help="Include paths to tests' locations in tests' names. Names will follow " @@ -741,12 +753,22 @@ def parse_arguments(parser, args, options = None): if options.show_footprint or options.compare_report: options.enable_size_report = True + if options.aggressive_no_clean: + options.no_clean = True + if options.coverage: options.enable_coverage = True if not options.coverage_platform: options.coverage_platform = options.platform + if options.coverage_formats: + for coverage_format in options.coverage_formats.split(','): + if coverage_format not in supported_coverage_formats[options.coverage_tool]: + logger.error(f"Unsupported coverage report formats:'{options.coverage_formats}' " + f"for {options.coverage_tool}") + sys.exit(1) + if options.enable_valgrind and not shutil.which("valgrind"): logger.error("valgrind enabled but valgrind executable not found") sys.exit(1) @@ -841,6 +863,13 @@ def __init__(self, options=None) -> None: self.board_roots = None self.outdir = None + self.snippet_roots = [Path(ZEPHYR_BASE)] + modules = zephyr_module.parse_modules(ZEPHYR_BASE) + for module in modules: + snippet_root = module.meta.get("build", {}).get("settings", {}).get("snippet_root") + if snippet_root: + self.snippet_roots.append(Path(module.project) / snippet_root) + self.hwm = None self.test_config = options.test_config if options else None diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 3c6498a6ea4..3a13b819649 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -100,12 +100,19 @@ def get_test_timeout(self): def record(self, harness): if harness.recording: + if self.instance.recording is None: + self.instance.recording = harness.recording.copy() + else: + self.instance.recording.extend(harness.recording) + filename = os.path.join(self.build_dir, "recording.csv") with open(filename, "at") as csvfile: - cw = csv.writer(csvfile, harness.fieldnames, lineterminator=os.linesep) - cw.writerow(harness.fieldnames) - for instance in harness.recording: - cw.writerow(instance) + cw = csv.DictWriter(csvfile, + fieldnames = harness.recording[0].keys(), + lineterminator = os.linesep, + quoting = csv.QUOTE_NONNUMERIC) + cw.writeheader() + cw.writerows(harness.recording) def terminate(self, proc): terminate_process(proc) @@ -319,10 +326,6 @@ def handle(self, harness): handler_time = time.time() - start_time - if self.options.coverage: - subprocess.call(["GCOV_PREFIX=" + self.build_dir, - "gcov", self.sourcedir, "-b", "-s", self.build_dir], shell=True) - # FIXME: This is needed when killing the simulator, the console is # garbled and needs to be reset. Did not find a better way to do that. if sys.stdout.isatty(): @@ -360,7 +363,7 @@ def __init__(self, instance, type_str): def get_test_timeout(self): timeout = super().get_test_timeout() - if self.options.coverage: + if self.options.enable_coverage: # wait more for gcov data to be dumped on console timeout += 120 return timeout @@ -368,7 +371,7 @@ def get_test_timeout(self): def monitor_serial(self, ser, halt_event, harness): log_out_fp = open(self.log, "wb") - if self.options.coverage: + if self.options.enable_coverage: # Set capture_coverage to True to indicate that right after # test results we should get coverage data, otherwise we exit # from the test. @@ -988,6 +991,7 @@ def handle(self, harness): self.thread.daemon = True logger.debug("Spawning QEMUHandler Thread for %s" % self.name) self.thread.start() + thread_max_time = time.time() + self.get_test_timeout() if sys.stdout.isatty(): subprocess.call(["stty", "sane"], stdin=sys.stdout) @@ -1019,8 +1023,8 @@ def handle(self, harness): self.returncode = proc.returncode # Need to wait for harness to finish processing # output from QEMU. Otherwise it might miss some - # error messages. - self.thread.join(0) + # messages. + self.thread.join(max(thread_max_time - time.time(), 0)) if self.thread.is_alive(): logger.debug("Timed out while monitoring QEMU output") diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index a0ea7c59a8e..6e3750999f5 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -286,7 +286,7 @@ def readlink(link): serial_devices = list_ports.comports() logger.info("Scanning connected hardware...") for d in serial_devices: - if d.manufacturer in self.manufacturer: + if d.manufacturer and d.manufacturer.casefold() in [m.casefold() for m in self.manufacturer]: # TI XDS110 can have multiple serial devices for a single board # assume endpoint 0 is the serial, skip all others diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 8b8ad92fc51..2acec462fa6 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -12,6 +12,7 @@ import logging import threading import time +import shutil from twisterlib.error import ConfigurationError from twisterlib.environment import ZEPHYR_BASE, PYTEST_PLUGIN_INSTALLED @@ -55,8 +56,8 @@ def __init__(self): self.capture_coverage = False self.next_pattern = 0 self.record = None + self.record_pattern = None self.recording = [] - self.fieldnames = [] self.ztest = False self.detected_suite_names = [] self.run_id = None @@ -80,6 +81,18 @@ def configure(self, instance): self.repeat = config.get('repeat', 1) self.ordered = config.get('ordered', True) self.record = config.get('record', {}) + if self.record: + self.record_pattern = re.compile(self.record.get("regex", "")) + + def build(self): + pass + + def get_testcase_name(self): + """ + Get current TestCase name. + """ + return self.id + def process_test(self, line): @@ -172,7 +185,7 @@ def get_testcase_name(self): ''' if self.instance and len(self.instance.testcases) == 1: return self.instance.testcases[0].name - return self.id + return super(Console, self).get_testcase_name() def configure(self, instance): super(Console, self).configure(instance) @@ -240,19 +253,10 @@ def handle(self, line): elif self.GCOV_END in line: self.capture_coverage = False - - if self.record: - pattern = re.compile(self.record.get("regex", "")) - match = pattern.search(line) + if self.record_pattern: + match = self.record_pattern.search(line) if match: - csv = [] - if not self.fieldnames: - for k,v in match.groupdict().items(): - self.fieldnames.append(k) - - for k,v in match.groupdict().items(): - csv.append(v.strip()) - self.recording.append(csv) + self.recording.append({ k:v.strip() for k,v in match.groupdict(default="").items() }) self.process_test(line) # Reset the resulting test state to 'failed' when not all of the patterns were @@ -620,6 +624,12 @@ def handle(self, line): self._match = True result_match = result_re.match(line) + # some testcases are skipped based on predicates and do not show up + # during test execution, however they are listed in the summary. Parse + # the summary for status and use that status instead. + + summary_re = re.compile(r"- (PASS|FAIL|SKIP) - \[([^\.]*).(test_)?(\S*)\] duration = (\d*[.,]?\d*) seconds") + summary_match = summary_re.match(line) if result_match: matched_status = result_match.group(1) @@ -634,6 +644,20 @@ def handle(self, line): self.testcase_output = "" self._match = False self.ztest = True + elif summary_match: + matched_status = summary_match.group(1) + self.detected_suite_names.append(summary_match.group(2)) + name = "{}.{}".format(self.id, summary_match.group(4)) + tc = self.instance.get_case_or_create(name) + tc.status = self.ztest_to_status[matched_status] + if tc.status == "skipped": + tc.reason = "ztest skip" + tc.duration = float(summary_match.group(5)) + if tc.status == "failed": + tc.output = self.testcase_output + self.testcase_output = "" + self._match = False + self.ztest = True self.process_test(line) @@ -650,13 +674,51 @@ class Ztest(Test): pass +class Bsim(Harness): + + def build(self): + """ + Copying the application executable to BabbleSim's bin directory enables + running multidevice bsim tests after twister has built them. + """ + + if self.instance is None: + return + + original_exe_path: str = os.path.join(self.instance.build_dir, 'zephyr', 'zephyr.exe') + if not os.path.exists(original_exe_path): + logger.warning('Cannot copy bsim exe - cannot find original executable.') + return + + bsim_out_path: str = os.getenv('BSIM_OUT_PATH', '') + if not bsim_out_path: + logger.warning('Cannot copy bsim exe - BSIM_OUT_PATH not provided.') + return + + new_exe_name: str = self.instance.testsuite.harness_config.get('bsim_exe_name', '') + if new_exe_name: + new_exe_name = f'bs_{self.instance.platform.name}_{new_exe_name}' + else: + new_exe_name = self.instance.name + new_exe_name = new_exe_name.replace(os.path.sep, '_').replace('.', '_') + new_exe_name = f'bs_{new_exe_name}' + + new_exe_path: str = os.path.join(bsim_out_path, 'bin', new_exe_name) + logger.debug(f'Copying executable from {original_exe_path} to {new_exe_path}') + shutil.copy(original_exe_path, new_exe_path) + + class HarnessImporter: @staticmethod def get_harness(harness_name): thismodule = sys.modules[__name__] - if harness_name: - harness_class = getattr(thismodule, harness_name) - else: - harness_class = getattr(thismodule, 'Test') - return harness_class() + try: + if harness_name: + harness_class = getattr(thismodule, harness_name) + else: + harness_class = getattr(thismodule, 'Test') + return harness_class() + except AttributeError as e: + logger.debug(f"harness {harness_name} not implemented: {e}") + return None diff --git a/scripts/pylib/twister/twisterlib/reports.py b/scripts/pylib/twister/twisterlib/reports.py index be1bbb4dbd7..3d4b155fa9d 100644 --- a/scripts/pylib/twister/twisterlib/reports.py +++ b/scripts/pylib/twister/twisterlib/reports.py @@ -232,7 +232,7 @@ def xunit_report(self, json_file, filename, selected_platform=None, full_report= with open(filename, 'wb') as report: report.write(result) - def json_report(self, filename, version="NA"): + def json_report(self, filename, version="NA", platform=None): logger.info(f"Writing JSON report {filename}") report = {} report["environment"] = {"os": os.name, @@ -244,6 +244,8 @@ def json_report(self, filename, version="NA"): suites = [] for instance in self.instances.values(): + if platform and platform != instance.platform.name: + continue suite = {} handler_log = os.path.join(instance.build_dir, "handler.log") pytest_log = os.path.join(instance.build_dir, "twister_harness.log") @@ -304,6 +306,7 @@ def json_report(self, filename, version="NA"): if instance.status is not None: suite["execution_time"] = f"{float(handler_time):.2f}" + suite["build_time"] = f"{float(instance.build_time):.2f}" testcases = [] @@ -344,6 +347,10 @@ def json_report(self, filename, version="NA"): testcases.append(testcase) suite['testcases'] = testcases + + if instance.recording is not None: + suite['recording'] = instance.recording + suites.append(suite) report["testsuites"] = suites @@ -542,6 +549,9 @@ def target_report(self, json_file, outdir, suffix): for platform in platforms: if suffix: filename = os.path.join(outdir,"{}_{}.xml".format(platform, suffix)) + json_platform_file = os.path.join(outdir,"{}_{}.json".format(platform, suffix)) else: filename = os.path.join(outdir,"{}.xml".format(platform)) + json_platform_file = os.path.join(outdir,"{}.json".format(platform)) self.xunit_report(json_file, filename, platform, full_report=True) + self.json_report(json_platform_file, version=self.env.version, platform=platform) diff --git a/scripts/pylib/twister/twisterlib/runner.py b/scripts/pylib/twister/twisterlib/runner.py index 3471f6bf702..9ef53b386c9 100644 --- a/scripts/pylib/twister/twisterlib/runner.py +++ b/scripts/pylib/twister/twisterlib/runner.py @@ -263,27 +263,31 @@ def run_build(self, args=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) + logger.debug(f'Running {"".join(cmd)}') out, _ = p.communicate() - results = {} + ret = {} + duration = time.time() - start_time + self.instance.build_time += duration if p.returncode == 0: - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished building {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" + logger.debug(msg) self.instance.status = "passed" if not self.instance.run: self.instance.add_missing_case_status("skipped", "Test was built only") - results = {'msg': msg, "returncode": p.returncode, "instance": self.instance} + ret = {"returncode": p.returncode} if out: log_msg = out.decode(self.default_encoding) with open(os.path.join(self.build_dir, self.log), "a", encoding=self.default_encoding) as log: log.write(log_msg) - else: return None else: @@ -310,12 +314,11 @@ def run_build(self, args=[]): self.instance.status = "error" self.instance.reason = "Build failure" - results = { - "returncode": p.returncode, - "instance": self.instance, + ret = { + "returncode": p.returncode } - return results + return ret def run_cmake(self, args="", filter_stages=[]): @@ -384,18 +387,24 @@ def run_cmake(self, args="", filter_stages=[]): if self.cwd: kwargs['cwd'] = self.cwd + start_time = time.time() if sys.platform == 'linux': p = self.jobserver.popen(cmd, **kwargs) else: p = subprocess.Popen(cmd, **kwargs) out, _ = p.communicate() + duration = time.time() - start_time + self.instance.build_time += duration + if p.returncode == 0: filter_results = self.parse_generated(filter_stages) - msg = "Finished building %s for %s" % (self.source_dir, self.platform.name) + msg = f"Finished running cmake {self.source_dir} for {self.platform.name} in {duration:.2f} seconds" logger.debug(msg) - results = {'msg': msg, 'filter': filter_results} - + ret = { + 'returncode': p.returncode, + 'filter': filter_results + } else: self.instance.status = "error" self.instance.reason = "Cmake build failure" @@ -404,7 +413,7 @@ def run_cmake(self, args="", filter_stages=[]): tc.status = self.instance.status logger.error("Cmake build failure: %s for %s" % (self.source_dir, self.platform.name)) - results = {"returncode": p.returncode} + ret = {"returncode": p.returncode} if out: os.makedirs(self.build_dir, exist_ok=True) @@ -412,7 +421,7 @@ def run_cmake(self, args="", filter_stages=[]): log_msg = out.decode(self.default_encoding) log.write(log_msg) - return results + return ret class FilterBuilder(CMake): @@ -502,14 +511,14 @@ def parse_generated(self, filter_stages=[]): edt = pickle.load(f) else: edt = None - res = expr_parser.parse(self.testsuite.filter, filter_data, edt) + ret = expr_parser.parse(self.testsuite.filter, filter_data, edt) except (ValueError, SyntaxError) as se: sys.stderr.write( "Failed processing %s\n" % self.testsuite.yamlfile) raise se - if not res: + if not ret: return {os.path.join(self.platform.name, self.testsuite.name): True} else: return {os.path.join(self.platform.name, self.testsuite.name): False} @@ -584,12 +593,12 @@ def process(self, pipeline, done, message, lock, results): self.instance.setup_handler(self.env) if op == "filter": - res = self.cmake(filter_stages=self.instance.filter_stages) + ret = self.cmake(filter_stages=self.instance.filter_stages) if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the dt/kconfig filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -600,8 +609,8 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "cmake", "test": self.instance}) # The build process, call cmake and build with configured generator - if op == "cmake": - res = self.cmake() + elif op == "cmake": + ret = self.cmake() if self.instance.status in ["failed", "error"]: pipeline.put({"op": "report", "test": self.instance}) elif self.options.cmake_only: @@ -610,7 +619,7 @@ def process(self, pipeline, done, message, lock, results): pipeline.put({"op": "report", "test": self.instance}) else: # Here we check the runtime filter results coming from running cmake - if self.instance.name in res['filter'] and res['filter'][self.instance.name]: + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: logger.debug("filtering %s" % self.instance.name) self.instance.status = "filtered" self.instance.reason = "runtime filter" @@ -622,8 +631,8 @@ def process(self, pipeline, done, message, lock, results): elif op == "build": logger.debug("build test: %s" % self.instance.name) - res = self.build() - if not res: + ret = self.build() + if not ret: self.instance.status = "error" self.instance.reason = "Build Failure" pipeline.put({"op": "report", "test": self.instance}) @@ -634,7 +643,7 @@ def process(self, pipeline, done, message, lock, results): results.skipped_runtime += 1 self.instance.add_missing_case_status("skipped", self.instance.reason) - if res.get('returncode', 1) > 0: + if ret.get('returncode', 1) > 0: self.instance.add_missing_case_status("blocked", self.instance.reason) pipeline.put({"op": "report", "test": self.instance}) else: @@ -1040,13 +1049,21 @@ def cmake(self, filter_stages=[]): self.options.extra_args, # CMake extra args self.instance.build_dir, ) - - res = self.run_cmake(args,filter_stages) - return res + return self.run_cmake(args,filter_stages) def build(self): - res = self.run_build(['--build', self.build_dir]) - return res + harness = HarnessImporter.get_harness(self.instance.testsuite.harness.capitalize()) + build_result = self.run_build(['--build', self.build_dir]) + try: + if harness: + harness.instance = self.instance + harness.build() + except ConfigurationError as error: + self.instance.status = "error" + self.instance.reason = str(error) + logger.error(self.instance.reason) + return + return build_result def run(self): @@ -1244,12 +1261,17 @@ def add_tasks_to_queue(self, pipeline, build_only=False, test_only=False, retry_ instance.filter_stages = [] if instance.testsuite.filter: instance.filter_stages = self.get_cmake_filter_stages(instance.testsuite.filter, expr_parser.reserved.keys()) + if test_only and instance.run: pipeline.put({"op": "run", "test": instance}) elif instance.filter_stages and "full" not in instance.filter_stages: pipeline.put({"op": "filter", "test": instance}) else: - pipeline.put({"op": "cmake", "test": instance}) + cache_file = os.path.join(instance.build_dir, "CMakeCache.txt") + if os.path.exists(cache_file) and self.env.options.aggressive_no_clean: + pipeline.put({"op": "build", "test": instance}) + else: + pipeline.put({"op": "cmake", "test": instance}) def pipeline_mgr(self, pipeline, done_queue, lock, results): @@ -1289,11 +1311,11 @@ def execute(self, pipeline, done): processes = [] - for job in range(self.jobs): - logger.debug(f"Launch process {job}") + for _ in range(self.jobs): p = Process(target=self.pipeline_mgr, args=(pipeline, done, lock, self.results, )) processes.append(p) p.start() + logger.debug(f"Launched {self.jobs} jobs") try: for p in processes: diff --git a/scripts/pylib/twister/twisterlib/testinstance.py b/scripts/pylib/twister/twisterlib/testinstance.py index 958019b411a..3b307e41cf2 100644 --- a/scripts/pylib/twister/twisterlib/testinstance.py +++ b/scripts/pylib/twister/twisterlib/testinstance.py @@ -48,12 +48,13 @@ def __init__(self, testsuite, platform, outdir): self.reason = "Unknown" self.metrics = dict() self.handler = None + self.recording = None self.outdir = outdir self.execution_time = 0 + self.build_time = 0 self.retries = 0 self.name = os.path.join(platform.name, testsuite.name) - self.run_id = self._get_run_id() self.dut = None if testsuite.detailed_test_id: self.build_dir = os.path.join(outdir, platform.name, testsuite.name) @@ -62,6 +63,7 @@ def __init__(self, testsuite, platform, outdir): source_dir_rel = testsuite.source_dir_rel.rsplit(os.pardir+os.path.sep, 1)[-1] self.build_dir = os.path.join(outdir, platform.name, source_dir_rel, testsuite.name) + self.run_id = self._get_run_id() self.domains = None self.run = False @@ -83,12 +85,22 @@ def init_cases(self): def _get_run_id(self): """ generate run id from instance unique identifier and a random - number""" - - hash_object = hashlib.md5(self.name.encode()) - random_str = f"{random.getrandbits(64)}".encode() - hash_object.update(random_str) - return hash_object.hexdigest() + number + If exist, get cached run id from previous run.""" + run_id = "" + run_id_file = os.path.join(self.build_dir, "run_id.txt") + if os.path.exists(run_id_file): + with open(run_id_file, "r") as fp: + run_id = fp.read() + else: + hash_object = hashlib.md5(self.name.encode()) + random_str = f"{random.getrandbits(64)}".encode() + hash_object.update(random_str) + run_id = hash_object.hexdigest() + os.makedirs(self.build_dir, exist_ok=True) + with open(run_id_file, 'w+') as fp: + fp.write(run_id) + return run_id def add_missing_case_status(self, status, reason=None): for case in self.testcases: @@ -207,7 +219,8 @@ def check_runnable(self, enable_slow=False, filter='buildable', fixtures=[], har target_ready = bool(self.testsuite.type == "unit" or \ self.platform.type == "native" or \ - self.platform.simulation in SUPPORTED_SIMS or \ + (self.platform.simulation in SUPPORTED_SIMS and \ + self.platform.simulation not in self.testsuite.simulation_exclude) or \ filter == 'runnable') # check if test is runnable in pytest @@ -275,7 +288,7 @@ def create_overlay(self, platform, enable_asan=False, enable_ubsan=False, enable if content: os.makedirs(subdir, exist_ok=True) file = os.path.join(subdir, "testsuite_extra.conf") - with open(file, "w") as f: + with open(file, "w", encoding='utf-8') as f: f.write(content) return content diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 930d4573b19..f62aedab8cf 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -56,10 +56,12 @@ class Filters: CMD_LINE = 'command line filter' # filters in the testsuite yaml definition TESTSUITE = 'testsuite filter' - # filters realted to platform definition + # filters in the testplan yaml definition + TESTPLAN = 'testplan filter' + # filters related to platform definition PLATFORM = 'Platform related filter' # in case a test suite was quarantined. - QUARENTINE = 'Quarantine filter' + QUARANTINE = 'Quarantine filter' # in case a test suite is skipped intentionally . SKIP = 'Skip filter' # in case of incompatibility between selected and allowed toolchains. @@ -416,7 +418,6 @@ def add_configurations(self): self.platforms.append(platform) if not platform_config.get('override_default_platforms', False): if platform.default: - logger.debug(f"adding {platform.name} to default platforms") self.default_platforms.append(platform.name) else: if platform.name in platform_config.get('default_platforms', []): @@ -718,7 +719,7 @@ def apply_filters(self, **kwargs): tl = self.get_level(self.options.level) planned_scenarios = tl.scenarios if ts.id not in planned_scenarios and not set(ts.levels).intersection(set(tl.levels)): - instance.add_filter("Not part of requested test plan", Filters.TESTSUITE) + instance.add_filter("Not part of requested test plan", Filters.TESTPLAN) if runnable and not instance.run: instance.add_filter("Not runnable on device", Filters.CMD_LINE) @@ -805,7 +806,7 @@ def apply_filters(self, **kwargs): if ts.required_snippets: missing_snippet = False snippet_args = {"snippets": ts.required_snippets} - found_snippets = snippets.find_snippets_in_roots(snippet_args, [Path(ZEPHYR_BASE), Path(ts.source_dir)]) + found_snippets = snippets.find_snippets_in_roots(snippet_args, [*self.env.snippet_roots, Path(ts.source_dir)]) # Search and check that all required snippet files are found for this_snippet in snippet_args['snippets']: @@ -819,7 +820,7 @@ def apply_filters(self, **kwargs): if not missing_snippet: # Look for required snippets and check that they are applicable for these # platforms/boards - for this_snippet in found_snippets: + for this_snippet in snippet_args['snippets']: matched_snippet_board = False # If the "appends" key is present with at least one entry then this @@ -842,42 +843,47 @@ def apply_filters(self, **kwargs): instance.add_filter("Snippet not supported", Filters.PLATFORM) break + # handle quarantined tests + if self.quarantine: + matched_quarantine = self.quarantine.get_matched_quarantine( + instance.testsuite.id, plat.name, plat.arch, plat.simulation + ) + if matched_quarantine and not self.options.quarantine_verify: + instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARANTINE) + if not matched_quarantine and self.options.quarantine_verify: + instance.add_filter("Not under quarantine", Filters.QUARANTINE) + + # platform_key is a list of unique platform attributes that form a unique key a test # will match against to determine if it should be scheduled to run. A key containing a # field name that the platform does not have will filter the platform. # - # A simple example is keying on arch and simulation to run a test once per unique (arch, simulation) platform. + # A simple example is keying on arch and simulation + # to run a test once per unique (arch, simulation) platform. if not ignore_platform_key and hasattr(ts, 'platform_key') and len(ts.platform_key) > 0: - # form a key by sorting the key fields first, then fetching the key fields from plat if they exist - # if a field does not exist the test is still scheduled on that platform as its undeterminable. key_fields = sorted(set(ts.platform_key)) - key = [getattr(plat, key_field) for key_field in key_fields] - has_all_fields = True - for key_field in key_fields: - if key_field is None or key_field == 'na': - has_all_fields = False - if has_all_fields: - test_key = copy.deepcopy(key) - test_key.append(ts.name) - test_key = tuple(test_key) - keyed_test = keyed_tests.get(test_key) + keys = [getattr(plat, key_field) for key_field in key_fields] + for key in keys: + if key is None or key == 'na': + instance.add_filter( + f"Excluded platform missing key fields demanded by test {key_fields}", + Filters.PLATFORM + ) + break + else: + test_keys = copy.deepcopy(keys) + test_keys.append(ts.name) + test_keys = tuple(test_keys) + keyed_test = keyed_tests.get(test_keys) if keyed_test is not None: plat_key = {key_field: getattr(keyed_test['plat'], key_field) for key_field in key_fields} - instance.add_filter(f"Excluded test already covered for key {tuple(key)} by platform {keyed_test['plat'].name} having key {plat_key}", Filters.PLATFORM_KEY) + instance.add_filter(f"Already covered for key {tuple(key)} by platform {keyed_test['plat'].name} having key {plat_key}", Filters.PLATFORM_KEY) else: - keyed_tests[test_key] = {'plat': plat, 'ts': ts} - else: - instance.add_filter(f"Excluded platform missing key fields demanded by test {key_fields}", Filters.PLATFORM) - - # handle quarantined tests - if self.quarantine: - matched_quarantine = self.quarantine.get_matched_quarantine( - instance.testsuite.id, plat.name, plat.arch, plat.simulation - ) - if matched_quarantine and not self.options.quarantine_verify: - instance.add_filter("Quarantine: " + matched_quarantine, Filters.QUARENTINE) - if not matched_quarantine and self.options.quarantine_verify: - instance.add_filter("Not under quarantine", Filters.QUARENTINE) + # do not add a platform to keyed tests if previously filtered + if not instance.filters: + keyed_tests[test_keys] = {'plat': plat, 'ts': ts} + else: + instance.add_filter(f"Excluded platform missing key fields demanded by test {key_fields}", Filters.PLATFORM) # if nothing stopped us until now, it means this configuration # needs to be added. @@ -988,7 +994,7 @@ def _create_build_dir_link(self, links_dir_path, instance): link_path = os.path.join(links_dir_path, link_name) if os.name == "nt": # if OS is Windows - command = ["mklink", "/J", f"{link_path}", f"{instance.build_dir}"] + command = ["mklink", "/J", f"{link_path}", os.path.normpath(instance.build_dir)] subprocess.call(command, shell=True) else: # for Linux and MAC OS os.symlink(instance.build_dir, link_path) @@ -1002,12 +1008,12 @@ def _create_build_dir_link(self, links_dir_path, instance): def change_skip_to_error_if_integration(options, instance): ''' All skips on integration_platforms are treated as errors.''' - if instance.platform.name in instance.testsuite.integration_platforms \ - and "quarantine" not in instance.reason.lower(): - # Do not treat this as error if filter type is command line + if instance.platform.name in instance.testsuite.integration_platforms: + # Do not treat this as error if filter type is among ignore_filters filters = {t['type'] for t in instance.filters} ignore_filters ={Filters.CMD_LINE, Filters.SKIP, Filters.PLATFORM_KEY, - Filters.TOOLCHAIN, Filters.MODULE} + Filters.TOOLCHAIN, Filters.MODULE, Filters.TESTPLAN, + Filters.QUARANTINE} if filters.intersection(ignore_filters): return instance.status = "error" diff --git a/scripts/requirements-extras.txt b/scripts/requirements-extras.txt index f210f069de9..99fa4f16cf4 100644 --- a/scripts/requirements-extras.txt +++ b/scripts/requirements-extras.txt @@ -32,4 +32,4 @@ PyGithub graphviz # used to generate CBOR encoders and decoders, e.g. lwm2m_senml_cbor. -zcbor>=0.6.0 +zcbor>=0.8.0 diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 1e198173c72..454959fc608 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -8,178 +8,210 @@ # # The original spec comes from Zephyr's twister script # +schema;scenario-schema: + type: map + # has to be not-required, otherwise the parser gets + # confused and things it never found it + required: false + mapping: + "arch_exclude": + type: any + required: false + "arch_allow": + type: any + required: false + "testcases": + type: seq + required: false + sequence: + - type: str + "build_only": + type: bool + required: false + "build_on_all": + type: bool + required: false + "depends_on": + type: any + required: false + "extra_args": + type: any + required: false + "extra_configs": + type: seq + required: false + sequence: + - type: str + "extra_conf_files": + type: seq + required: false + sequence: + - type: str + "extra_overlay_confs": + type: seq + required: false + sequence: + - type: str + "extra_dtc_overlay_files": + type: seq + required: false + sequence: + - type: str + "extra_sections": + type: any + required: false + "required_snippets": + type: seq + required: false + sequence: + - type: str + "filter": + type: str + required: false + "levels": + type: seq + required: false + sequence: + - type: str + enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] + "integration_platforms": + type: seq + required: false + sequence: + - type: str + "ignore_faults": + type: bool + required: false + "ignore_qemu_crash": + type: bool + required: false + "harness": + type: str + required: false + "harness_config": + type: map + required: false + mapping: + "type": + type: str + required: false + "fixture": + type: str + required: false + "ordered": + type: bool + required: false + "repeat": + type: int + required: false + "pytest_root": + type: seq + required: false + sequence: + - type: str + "pytest_args": + type: seq + required: false + sequence: + - type: str + "pytest_dut_scope": + type: str + enum: ["function", "class", "module", "package", "session"] + required: false + "regex": + type: seq + required: false + sequence: + - type: str + "robot_test_path": + type: str + required: false + "record": + type: map + required: false + mapping: + "regex": + type: str + required: true + "bsim_exe_name": + type: str + required: false + "min_ram": + type: int + required: false + "min_flash": + type: int + required: false + "modules": + type: seq + required: false + sequence: + - type: str + "platform_exclude": + type: any + required: false + "platform_allow": + type: any + required: false + "platform_type": + type: seq + required: false + sequence: + - type: str + enum: ["mcu", "qemu", "sim", "unit", "native"] + "platform_key": + required: false + type: seq + matching: "all" + sequence: + - type: str + "simulation_exclude": + type: seq + required: false + sequence: + - type: str + enum: + [ + "qemu", + "simics", + "xt-sim", + "renode", + "nsim", + "mdb-nsim", + "tsim", + "armfvp", + "native", + "custom", + ] + "tags": + type: any + required: false + "timeout": + type: int + required: false + "toolchain_exclude": + type: any + required: false + "toolchain_allow": + type: any + required: false + "type": + type: str + enum: ["unit"] + "skip": + type: bool + required: false + "slow": + type: bool + required: false + "sysbuild": + type: bool + required: false + type: map mapping: "common": - type: map - required: false - mapping: - "arch_exclude": - type: any - required: false - "arch_allow": - type: any - required: false - "build_only": - type: bool - required: false - "build_on_all": - type: bool - required: false - "depends_on": - type: any - required: false - "extra_args": - type: any - required: false - "extra_conf_files": - type: seq - required: false - sequence: - - type: str - "extra_overlay_confs": - type: seq - required: false - sequence: - - type: str - "extra_dtc_overlay_files": - type: seq - required: false - sequence: - - type: str - "extra_sections": - type: any - required: false - "filter": - type: str - required: false - "integration_platforms": - type: seq - required: false - sequence: - - type: str - "ignore_faults": - type: bool - required: false - "ignore_qemu_crash": - type: bool - required: false - "levels": - type: seq - required: false - sequence: - - type: str - enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] - "testcases": - type: seq - required: false - sequence: - - type: str - "harness": - type: str - required: false - "harness_config": - type: map - required: false - mapping: - "type": - type: str - required: false - "fixture": - type: str - required: false - "ordered": - type: bool - required: false - "repeat": - type: int - required: false - "pytest_root": - type: seq - required: false - sequence: - - type: str - "pytest_args": - type: seq - required: false - sequence: - - type: str - "pytest_dut_scope": - type: str - enum: ["function", "class", "module", "package", "session"] - required: false - "regex": - type: seq - required: false - sequence: - - type: str - "robot_test_path": - type: str - required: false - "record": - type: map - required: false - mapping: - "regex": - type: str - required: false - "min_ram": - type: int - required: false - "min_flash": - type: int - required: false - "modules": - type: seq - required: false - sequence: - - type: str - "platform_exclude": - type: any - required: false - "platform_allow": - type: any - required: false - "platform_type": - type: seq - required: false - sequence: - - type: str - "platform_key": - required: false - type: seq - matching: "all" - sequence: - - type: str - "required_snippets": - type: seq - required: false - sequence: - - type: str - "tags": - type: any - required: false - "timeout": - type: int - required: false - "toolchain_exclude": - type: any - required: false - "toolchain_allow": - type: any - required: false - "type": - type: str - enum: ["unit"] - "skip": - type: bool - required: false - "slow": - type: bool - required: false - "sysbuild": - type: bool - required: false + include: scenario-schema # The sample descriptor, if present "sample": type: map @@ -203,179 +235,4 @@ mapping: # regex;(([a-zA-Z0-9_]+)) for this to work, note below we # make it required: false regex;(([a-zA-Z0-9_]+)): - type: map - # has to be not-required, otherwise the parser gets - # confused and things it never found it - required: false - mapping: - "arch_exclude": - type: any - required: false - "arch_allow": - type: any - required: false - "testcases": - type: seq - required: false - sequence: - - type: str - "build_only": - type: bool - required: false - "build_on_all": - type: bool - required: false - "depends_on": - type: any - required: false - "extra_args": - type: any - required: false - "extra_configs": - type: seq - required: false - sequence: - - type: str - "extra_conf_files": - type: seq - required: false - sequence: - - type: str - "extra_overlay_confs": - type: seq - required: false - sequence: - - type: str - "extra_dtc_overlay_files": - type: seq - required: false - sequence: - - type: str - "extra_sections": - type: any - required: false - "required_snippets": - type: seq - required: false - sequence: - - type: str - "filter": - type: str - required: false - "levels": - type: seq - required: false - sequence: - - type: str - enum: ["smoke", "unit", "integration", "acceptance", "system", "regression"] - "integration_platforms": - type: seq - required: false - sequence: - - type: str - "ignore_faults": - type: bool - required: false - "ignore_qemu_crash": - type: bool - required: false - "harness": - type: str - required: false - "harness_config": - type: map - required: false - mapping: - "type": - type: str - required: false - "fixture": - type: str - required: false - "ordered": - type: bool - required: false - "repeat": - type: int - required: false - "pytest_root": - type: seq - required: false - sequence: - - type: str - "pytest_args": - type: seq - required: false - sequence: - - type: str - "pytest_dut_scope": - type: str - enum: ["function", "class", "module", "package", "session"] - required: false - "regex": - type: seq - required: false - sequence: - - type: str - "robot_test_path": - type: str - required: false - "record": - type: map - required: false - mapping: - "regex": - type: str - required: false - "min_ram": - type: int - required: false - "min_flash": - type: int - required: false - "modules": - type: seq - required: false - sequence: - - type: str - "platform_exclude": - type: any - required: false - "platform_allow": - type: any - required: false - "platform_type": - type: seq - required: false - sequence: - - type: str - "platform_key": - required: false - type: seq - matching: "all" - sequence: - - type: str - "tags": - type: any - required: false - "timeout": - type: int - required: false - "toolchain_exclude": - type: any - required: false - "toolchain_allow": - type: any - required: false - "type": - type: str - enum: ["unit"] - "skip": - type: bool - required: false - "slow": - type: bool - required: false - "sysbuild": - type: bool - required: false + include: scenario-schema diff --git a/scripts/set_assignees.py b/scripts/set_assignees.py index 269bde82f54..17199ec52e6 100755 --- a/scripts/set_assignees.py +++ b/scripts/set_assignees.py @@ -78,7 +78,7 @@ def process_pr(gh, maintainer_file, number): # one liner PRs should be trivial if pr.commits == 1 and (pr.additions <= 1 and pr.deletions <= 1) and not manifest_change: - labels = {'trivial'} + labels = {'Trivial'} if len(fn) > 500: log(f"Too many files changed ({len(fn)}), skipping....") @@ -146,7 +146,7 @@ def process_pr(gh, maintainer_file, number): log("Submitter is same as Assignee, trying to find another assignee...") aff = list(area_counter.keys())[0] for area in all_areas: - if area.name == aff: + if area == aff: if len(area.maintainers) > 1: assignee = area.maintainers[1] else: @@ -181,14 +181,21 @@ def process_pr(gh, maintainer_file, number): existing_reviewers |= set(r.get_page(page)) page += 1 - for c in collab: + # check for reviewers that remove themselves from list of reviewer and + # do not attempt to add them again based on MAINTAINERS file. + self_removal = [] + for event in pr.get_issue_events(): + if event.event == 'review_request_removed' and event.actor == event.requested_reviewer: + self_removal.append(event.actor) + + for collaborator in collab: try: - u = gh.get_user(c) - if pr.user != u and gh_repo.has_in_collaborators(u): - if u not in existing_reviewers: - reviewers.append(c) + gh_user = gh.get_user(collaborator) + if pr.user != gh_user and gh_repo.has_in_collaborators(gh_user): + if gh_user not in existing_reviewers and gh_user not in self_removal: + reviewers.append(collaborator) except UnknownObjectException as e: - log(f"Can't get user '{c}', account does not exist anymore? ({e})") + log(f"Can't get user '{collaborator}', account does not exist anymore? ({e})") if len(existing_reviewers) < 15: reviewer_vacancy = 15 - len(existing_reviewers) diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index 6675c4ae451..d2e4b367a79 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -209,40 +209,35 @@ def test_handler_record(mocked_instance): instance.testcases = [mock.Mock()] handler = Handler(instance) - handler.suite_name_check = True - - harness = twisterlib.harness.Test() - harness.recording = ['dummy recording'] - type(harness).fieldnames = mock.PropertyMock(return_value=[]) - mock_writerow = mock.Mock() - mock_writer = mock.Mock(writerow=mock_writerow) + harness = twisterlib.harness.Harness() + harness.recording = [ {'field_1': 'recording_1_1', 'field_2': 'recording_1_2'}, + {'field_1': 'recording_2_1', 'field_2': 'recording_2_2'} + ] with mock.patch( 'builtins.open', mock.mock_open(read_data='') ) as mock_file, \ - mock.patch( - 'csv.writer', - mock.Mock(return_value=mock_writer) - ) as mock_writer_constructor: + mock.patch( + 'csv.DictWriter.writerow', + mock.Mock() + ) as mock_writeheader, \ + mock.patch( + 'csv.DictWriter.writerows', + mock.Mock() + ) as mock_writerows: handler.record(harness) + print(mock_file.mock_calls) + mock_file.assert_called_with( os.path.join(instance.build_dir, 'recording.csv'), 'at' ) - mock_writer_constructor.assert_called_with( - mock_file(), - harness.fieldnames, - lineterminator=os.linesep - ) - - mock_writerow.assert_has_calls( - [mock.call(harness.fieldnames)] + \ - [mock.call(recording) for recording in harness.recording] - ) + mock_writeheader.assert_has_calls([mock.call({ k:k for k in harness.recording[0].keys()})]) + mock_writerows.assert_has_calls([mock.call(harness.recording)]) def test_handler_terminate(mocked_instance): @@ -645,13 +640,6 @@ def mock_thread(target, *args, **kwargs): handler._update_instance_info.assert_called_once() handler._final_handle_actions.assert_called_once() - if coverage: - call_mock.assert_any_call( - ['GCOV_PREFIX=build_dir', 'gcov', 'source_dir', - '-b', '-s', 'build_dir'], - shell=True - ) - if isatty: call_mock.assert_any_call(['stty', 'sane'], stdin=mock.ANY) @@ -752,7 +740,7 @@ def test_devicehandler_monitor_serial( type(harness).state=mock.PropertyMock(side_effect=state_iter) handler = DeviceHandler(mocked_instance, 'build') - handler.options = mock.Mock(coverage=not end_by_state) + handler.options = mock.Mock(enable_coverage=not end_by_state) with mock.patch('builtins.open', mock.mock_open(read_data='')): handler.monitor_serial(ser, halt_event, harness) diff --git a/scripts/tests/twister/test_harness.py b/scripts/tests/twister/test_harness.py index 1da2aed3f46..925a738b8bc 100644 --- a/scripts/tests/twister/test_harness.py +++ b/scripts/tests/twister/test_harness.py @@ -10,12 +10,21 @@ import sys import os import pytest +import re +import logging as logger ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) -from twisterlib.harness import Gtest +from twisterlib.harness import Gtest, Bsim +from twisterlib.harness import Harness +from twisterlib.harness import Robot +from twisterlib.harness import Test from twisterlib.testinstance import TestInstance +from twisterlib.harness import Console +from twisterlib.harness import Pytest +from twisterlib.harness import PytestHarnessException +from twisterlib.harness import HarnessImporter GTEST_START_STATE = " RUN " GTEST_PASS_STATE = " OK " @@ -34,8 +43,404 @@ def process_logs(harness, logs): harness.handle(line) +TEST_DATA_1 = [('RunID: 12345', False, False, False, None, True), + ('PROJECT EXECUTION SUCCESSFUL', False, False, False, 'passed', False), + ('PROJECT EXECUTION SUCCESSFUL', True, False, False, 'failed', False), + ('PROJECT EXECUTION FAILED', False, False, False, 'failed', False), + ('ZEPHYR FATAL ERROR', False, True, False, None, False), + ('GCOV_COVERAGE_DUMP_START', None, None, True, None, False), + ('GCOV_COVERAGE_DUMP_END', None, None, False, None, False),] +@pytest.mark.parametrize( + "line, fault, fail_on_fault, cap_cov, exp_stat, exp_id", + TEST_DATA_1, + ids=["match id", "passed passed", "passed failed", "failed failed", "fail on fault", "GCOV START", "GCOV END"] +) +def test_harness_process_test(line, fault, fail_on_fault, cap_cov, exp_stat, exp_id): + #Arrange + harness = Harness() + harness.run_id = 12345 + harness.state = None + harness.fault = fault + harness.fail_on_fault = fail_on_fault + + #Act + harness.process_test(line) + + #Assert + assert harness.matched_run_id == exp_id + assert harness.state == exp_stat + assert harness.capture_coverage == cap_cov + + +def test_robot_configure(): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.testsuite.harness_config = { + 'robot_test_path': '/path/to/robot/test' + } + robot_harness = Robot() + + #Act + robot_harness.configure(instance) + + #Assert + assert robot_harness.instance == instance + assert robot_harness.path == '/path/to/robot/test' + + +def test_robot_handle(): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + handler = Robot() + handler.instance = instance + handler.id = 'test_case_1' + + line = 'Test case passed' + + #Act + handler.handle(line) + tc = instance.get_case_or_create('test_case_1') + + #Assert + assert instance.state == "passed" + assert tc.status == "passed" + + +TEST_DATA_2 = [("", 0, "passed"), ("Robot test failure: sourcedir for mock_platform", 1, "failed"),] +@pytest.mark.parametrize( + "exp_out, returncode, expected_status", + TEST_DATA_2, + ids=["passed", "failed"] +) +def test_robot_run_robot_test(caplog, exp_out, returncode, expected_status): + # Arrange + command = "command" + + handler = mock.Mock() + handler.sourcedir = "sourcedir" + handler.log = "handler.log" + + path = "path" + + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = [mock.Mock()]) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.build_dir = "build_dir" + + open_mock = mock.mock_open() + + robot = Robot() + robot.path = path + robot.instance = instance + proc_mock = mock.Mock( + returncode = returncode, + communicate = mock.Mock(return_value=(b"output", None)) + ) + popen_mock = mock.Mock(return_value = mock.Mock( + __enter__ = mock.Mock(return_value = proc_mock), + __exit__ = mock.Mock() + )) + + # Act + with mock.patch("subprocess.Popen", popen_mock) as mock.mock_popen, \ + mock.patch("builtins.open", open_mock): + robot.run_robot_test(command,handler) + + + # Assert + assert instance.status == expected_status + open_mock().write.assert_called_once_with("output") + assert exp_out in caplog.text + + +TEST_DATA_3 = [('one_line', None), ('multi_line', 2),] +@pytest.mark.parametrize( + "type, num_patterns", + TEST_DATA_3, + ids=["one line", "multi line"] +) +def test_console_configure(type, num_patterns): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.testsuite.harness_config = { + 'type': type, + 'regex': ['pattern1', 'pattern2'] + } + console = Console() + + #Act + console.configure(instance) + + #Assert + if num_patterns == 2: + assert len(console.patterns) == num_patterns + assert [pattern.pattern for pattern in console.patterns] == ['pattern1', 'pattern2'] + else: + assert console.pattern.pattern == 'pattern1' + + +TEST_DATA_4 = [("one_line", True, "passed", "line", False, False), + ("multi_line", True, "passed", "line", False, False), + ("multi_line", False, "passed", "line", False, False), + ("invalid_type", False, None, "line", False, False), + ("invalid_type", False, None, "ERROR", True, False), + ("invalid_type", False, None, "COVERAGE_START", False, True), + ("invalid_type", False, None, "COVERAGE_END", False, False)] +@pytest.mark.parametrize( + "line_type, ordered_val, exp_state, line, exp_fault, exp_capture", + TEST_DATA_4, + ids=["one line", "multi line ordered", "multi line not ordered", "logger error", "fail on fault", "GCOV START", "GCOV END"] +) +def test_console_handle(line_type, ordered_val, exp_state, line, exp_fault, exp_capture): + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + console = Console() + console.instance = instance + console.type = line_type + console.patterns = [re.compile("pattern1"), re.compile("pattern2")] + console.pattern = re.compile("pattern") + console.patterns_expected = 0 + console.state = None + console.fail_on_fault = True + console.FAULT = "ERROR" + console.GCOV_START = "COVERAGE_START" + console.GCOV_END = "COVERAGE_END" + console.record = {"regex": "RESULT: (.*)"} + console.fieldnames = [] + console.recording = [] + console.regex = ["regex1", "regex2"] + console.id = "test_case_1" + + instance.get_case_or_create('test_case_1') + instance.testsuite.id = "test_suite_1" + + console.next_pattern = 0 + console.ordered = ordered_val + line = line + console.handle(line) + + line1 = "pattern1" + line2 = "pattern2" + console.handle(line1) + console.handle(line2) + assert console.state == exp_state + with pytest.raises(Exception): + console.handle(line) + assert logger.error.called + assert console.fault == exp_fault + assert console.capture_coverage == exp_capture + + +TEST_DATA_5 = [("serial_pty", 0), (None, 0),(None, 1)] +@pytest.mark.parametrize( + "pty_value, hardware_value", + TEST_DATA_5, + ids=["hardware pty", "hardware", "non hardware"] +) + +def test_pytest__generate_parameters_for_hardware(pty_value, hardware_value): + #Arrange + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + handler = mock.Mock() + handler.instance = instance + + hardware = mock.Mock() + hardware.serial_pty = pty_value + hardware.serial = 'serial' + hardware.baud = 115200 + hardware.runner = "runner" + + options = handler.options + options.west_flash = "args" + + hardware.probe_id = '123' + hardware.product = 'product' + hardware.pre_script = 'pre_script' + hardware.post_flash_script = 'post_flash_script' + hardware.post_script = 'post_script' + + pytest_test = Pytest() + + #Act + if hardware_value == 0: + handler.get_hardware.return_value = hardware + command = pytest_test._generate_parameters_for_hardware(handler) + else: + handler.get_hardware.return_value = None + + #Assert + if hardware_value == 1: + with pytest.raises(PytestHarnessException) as exinfo: + pytest_test._generate_parameters_for_hardware(handler) + assert str(exinfo.value) == 'Hardware is not available' + else: + assert '--device-type=hardware' in command + if pty_value == "serial_pty": + assert '--device-serial-pty=serial_pty' in command + else: + assert '--device-serial=serial' in command + assert '--device-serial-baud=115200' in command + assert '--runner=runner' in command + assert '--west-flash-extra-args=args' in command + assert '--device-id=123' in command + assert '--device-product=product' in command + assert '--pre-script=pre_script' in command + assert '--post-flash-script=post_flash_script' in command + assert '--post-script=post_script' in command + + +def test__update_command_with_env_dependencies(): + cmd = ['cmd'] + pytest_test = Pytest() + mock.patch.object(Pytest, 'PYTEST_PLUGIN_INSTALLED', False) + + # Act + result_cmd, _ = pytest_test._update_command_with_env_dependencies(cmd) + + # Assert + assert result_cmd == ['cmd', '-p', 'twister_harness.plugin'] + + +def test_pytest_run(caplog): + # Arrange + timeout = 10 + cmd=['command'] + exp_out = 'Handling of handler handler_type not implemented yet' + + harness = Pytest() + harness = mock.create_autospec(harness) + + mock.patch.object(Pytest, 'generate_command', return_value=cmd) + mock.patch.object(Pytest, 'run_command') + + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = [], source_dir = 'source_dir', harness_config = {}) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + handler = mock.Mock( + options = mock.Mock(verbose= 0), + type_str = 'handler_type' + ) + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + instance.handler = handler + + test_obj = Pytest() + test_obj.configure(instance) + + # Act + test_obj.pytest_run(timeout) + # Assert + assert test_obj.state == 'failed' + assert exp_out in caplog.text + + +TEST_DATA_6 = [(None), ('Test')] +@pytest.mark.parametrize( + "name", + TEST_DATA_6, + ids=["no name", "provided name"] +) +def test_get_harness(name): + #Arrange + harnessimporter = HarnessImporter() + harness_name = name + + #Act + harness_class = harnessimporter.get_harness(harness_name) + + #Assert + assert isinstance(harness_class, Test) + + +TEST_DATA_7 = [("", "Running TESTSUITE suite_name", ['suite_name'], None, True, None), + ("", "START - test_testcase", [], "started", True, None), + ("", "PASS - test_example in 0 seconds", [], "passed", True, None), + ("", "SKIP - test_example in 0 seconds", [], "skipped", True, None), + ("", "FAIL - test_example in 0 seconds", [], "failed", True, None), + ("not a ztest and no state for test_id", "START - test_testcase", [], "passed", False, "passed"), + ("not a ztest and no state for test_id", "START - test_testcase", [], "failed", False, "failed")] +@pytest.mark.parametrize( + "exp_out, line, exp_suite_name, exp_status, ztest, state", + TEST_DATA_7, + ids=['testsuite', 'testcase', 'pass', 'skip', 'failed', 'ztest pass', 'ztest fail'] +) +def test_test_handle(caplog, exp_out, line, exp_suite_name, exp_status, ztest, state): + # Arrange + line = line + mock_platform = mock.Mock() + mock_platform.name = "mock_platform" + + mock_testsuite = mock.Mock(id = 'id', testcases = []) + mock_testsuite.name = "mock_testsuite" + mock_testsuite.harness_config = {} + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + + test_obj = Test() + test_obj.configure(instance) + test_obj.id = "test_id" + test_obj.ztest = ztest + test_obj.state = state + test_obj.id = 'test_id' + #Act + test_obj.handle(line) + + # Assert + assert test_obj.detected_suite_names == exp_suite_name + assert exp_out in caplog.text + if not "Running" in line and exp_out == "": + assert test_obj.instance.testcases[0].status == exp_status + if "ztest" in exp_out: + assert test_obj.instance.testcases[1].status == exp_status + + @pytest.fixture -def gtest(): +def gtest(tmp_path): mock_platform = mock.Mock() mock_platform.name = "mock_platform" mock_testsuite = mock.Mock() @@ -43,7 +448,11 @@ def gtest(): mock_testsuite.detailed_test_id = True mock_testsuite.id = "id" mock_testsuite.testcases = [] - instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir="") + mock_testsuite.harness_config = {} + outdir = tmp_path / 'gtest_out' + outdir.mkdir() + + instance = TestInstance(testsuite=mock_testsuite, platform=mock_platform, outdir=outdir) harness = Gtest() harness.configure(instance) @@ -248,3 +657,30 @@ def test_gtest_repeated_run(gtest): ), ], ) + + +def test_bsim_build(monkeypatch, tmp_path): + mocked_instance = mock.Mock() + build_dir = tmp_path / 'build_dir' + os.makedirs(build_dir) + mocked_instance.build_dir = str(build_dir) + mocked_instance.name = 'platform_name/test/dummy.test' + mocked_instance.testsuite.harness_config = {} + + harness = Bsim() + harness.instance = mocked_instance + + monkeypatch.setenv('BSIM_OUT_PATH', str(tmp_path)) + os.makedirs(os.path.join(tmp_path, 'bin'), exist_ok=True) + zephyr_exe_path = os.path.join(build_dir, 'zephyr', 'zephyr.exe') + os.makedirs(os.path.dirname(zephyr_exe_path), exist_ok=True) + with open(zephyr_exe_path, 'w') as file: + file.write('TEST_EXE') + + harness.build() + + new_exe_path = os.path.join(tmp_path, 'bin', 'bs_platform_name_test_dummy_test') + assert os.path.exists(new_exe_path) + with open(new_exe_path, 'r') as file: + exe_content = file.read() + assert 'TEST_EXE' in exe_content diff --git a/scripts/tests/twister/test_platform.py b/scripts/tests/twister/test_platform.py new file mode 100644 index 00000000000..c40a10a9b78 --- /dev/null +++ b/scripts/tests/twister/test_platform.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +''' +This test file contains tests for platform.py module of twister +''' +import sys +import os +import mock +import pytest + +ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") +sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) + +from twisterlib.platform import Platform + + +TESTDATA_1 = [ + ( +"""\ +identifier: dummy empty +arch: arch0 +""", + { + 'name': 'dummy empty', + 'arch': 'arch0', + 'twister': True, + 'ram': 128, + 'timeout_multiplier': 1.0, + 'ignore_tags': [], + 'only_tags': [], + 'default': False, + 'binaries': [], + 'flash': 512, + 'supported': set(), + 'vendor': '', + 'tier': -1, + 'type': 'na', + 'simulation': 'na', + 'simulation_exec': None, + 'supported_toolchains': [], + 'env': [], + 'env_satisfied': True + }, + '' + ), + ( +"""\ +identifier: dummy full +arch: riscv32 +twister: true +ram: 1024 +testing: + timeout_multiplier: 2.0 + ignore_tags: + - tag1 + - tag2 + only_tags: + - tag3 + default: true + binaries: + - dummy.exe + - dummy.bin +flash: 4096 +supported: + - ble + - netif:openthread + - gpio +vendor: vendor1 +tier: 1 +type: unit +simulation: nsim +simulation_exec: nsimdrv +toolchain: + - zephyr + - llvm +env: + - dummynonexistentvar +""", + { + 'name': 'dummy full', + 'arch': 'riscv32', + 'twister': True, + 'ram': 1024, + 'timeout_multiplier': 2.0, + 'ignore_tags': ['tag1', 'tag2'], + 'only_tags': ['tag3'], + 'default': True, + 'binaries': ['dummy.exe', 'dummy.bin'], + 'flash': 4096, + 'supported': set(['ble', 'netif', 'openthread', 'gpio']), + 'vendor': 'vendor1', + 'tier': 1, + 'type': 'unit', + 'simulation': 'nsim', + 'simulation_exec': 'nsimdrv', + 'supported_toolchains': ['zephyr', 'llvm', 'cross-compile', 'xtools'], + 'env': ['dummynonexistentvar'], + 'env_satisfied': False + }, + '' + ), +] + +@pytest.mark.parametrize( + 'platform_text, expected_data, expected_repr', + TESTDATA_1, + ids=['almost empty specification', 'full specification'] +) +def test_platform_load(platform_text, expected_data, expected_repr): + platform = Platform() + + with mock.patch('builtins.open', mock.mock_open(read_data=platform_text)): + platform.load('dummy.yaml') + + for k, v in expected_data.items(): + if not hasattr(platform, k): + assert False, f'No key {k} in platform {platform}' + att = getattr(platform, k) + if isinstance(v, list) and not isinstance(att, list): + assert False, f'Value mismatch in key {k} in platform {platform}' + if isinstance(v, list): + assert sorted(att) == sorted(v) + else: + assert att == v + + assert platform.__repr__() == expected_repr diff --git a/scripts/tests/twister/test_runner.py b/scripts/tests/twister/test_runner.py index f0c2cbb50cf..fcf6ccd2a01 100644 --- a/scripts/tests/twister/test_runner.py +++ b/scripts/tests/twister/test_runner.py @@ -250,20 +250,20 @@ def test_cmake_parse_generated(mocked_jobserver): ] TESTDATA_1_2 = [ (0, False, 'dummy out', - True, True, True, True, 'passed', None, False, True), + True, True, 'passed', None, False, True), (0, True, '', - False, False, False, False, 'passed', None, False, False), + False, False, 'passed', None, False, False), (1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, True, True, 'skipped', 'FLASH overflow', True, False), + True, True, 'skipped', 'FLASH overflow', True, False), (1, True, 'Error: Image size (99 B) + trailer (1 B) exceeds requested size', - False, True, True, True, 'skipped', 'imgtool overflow', True, False), + True, True, 'skipped', 'imgtool overflow', True, False), (1, True, 'mock.ANY', - False, True, True, True, 'error', 'Build failure', False, False) + True, True, 'error', 'Build failure', False, False) ] @pytest.mark.parametrize( - 'return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ - ' expect_instance, expect_writes, expected_status, expected_reason,' \ + 'return_code, is_instance_run, p_out, expect_returncode,' \ + ' expect_writes, expected_status, expected_reason,' \ ' expected_change_skip, expected_add_missing', TESTDATA_1_2, ids=['no error, no instance run', 'no error, instance run', @@ -275,9 +275,7 @@ def test_cmake_run_build( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, - expect_instance, expect_writes, expected_status, expected_reason, @@ -303,6 +301,7 @@ def mock_popen(*args, **kwargs): popen=mock.Mock(side_effect=mock_popen) ) instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) + instance_mock.build_time = 0 instance_mock.run = is_instance_run instance_mock.status = None instance_mock.reason = None @@ -328,14 +327,8 @@ def mock_popen(*args, **kwargs): result = cmake.run_build(args=['arg1', 'arg2']) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code - if expect_instance: - expected_results['instance'] = instance_mock if expected_results == {}: expected_results = None @@ -369,7 +362,7 @@ def mock_popen(*args, **kwargs): TESTDATA_2_2 = [ (True, ['dummy_stage_1', 'ds2'], 0, False, '', - True, False, True, False, + True, True, False, None, None, [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -383,7 +376,7 @@ def mock_popen(*args, **kwargs): '-Pzephyr_base/cmake/package_helper.cmake']), (False, [], 1, True, 'ERROR: region `FLASH\' overflowed by 123 MB', - False, True, False, True, + True, False, True, 'error', 'Cmake build failure', [os.path.join('dummy', 'cmake'), '-B' + os.path.join('build', 'dir'), '-DTC_RUNID=1', @@ -398,7 +391,7 @@ def mock_popen(*args, **kwargs): @pytest.mark.parametrize( 'error_warns, f_stages,' \ - ' return_code, is_instance_run, p_out, expect_msg, expect_returncode,' \ + ' return_code, is_instance_run, p_out, expect_returncode,' \ ' expect_filter, expect_writes, expected_status, expected_reason,' \ ' expected_cmd', TESTDATA_2_2, @@ -412,7 +405,6 @@ def test_cmake_run_cmake( return_code, is_instance_run, p_out, - expect_msg, expect_returncode, expect_filter, expect_writes, @@ -442,6 +434,7 @@ def mock_popen(*args, **kwargs): instance_mock = mock.Mock(add_missing_case_status=mock.Mock()) instance_mock.run = is_instance_run instance_mock.run_id = 1 + instance_mock.build_time = 0 instance_mock.status = None instance_mock.reason = None instance_mock.testsuite = mock.Mock() @@ -476,10 +469,6 @@ def mock_popen(*args, **kwargs): result = cmake.run_cmake(args=['arg1', 'arg2'], filter_stages=f_stages) expected_results = {} - if expect_msg: - expected_results['msg'] = 'Finished building %s for %s' % \ - (os.path.join('source', 'dir'), \ - '') if expect_returncode: expected_results['returncode'] = return_code if expect_filter: @@ -2082,6 +2071,7 @@ def test_projectbuilder_cmake(): def test_projectbuilder_build(mocked_jobserver): instance_mock = mock.Mock() + instance_mock.testsuite.harness = 'test' env_mock = mock.Mock() pb = ProjectBuilder(instance_mock, env_mock, mocked_jobserver) @@ -2540,11 +2530,11 @@ def mock_get_cmake_filter_stages(filter, keys): return [filter] instances = { - 'dummy1': mock.Mock(run=True, retries=0, status='passed'), - 'dummy2': mock.Mock(run=True, retries=0, status='skipped'), - 'dummy3': mock.Mock(run=True, retries=0, status='filtered'), - 'dummy4': mock.Mock(run=True, retries=0, status='error'), - 'dummy5': mock.Mock(run=True, retries=0, status='failed') + 'dummy1': mock.Mock(run=True, retries=0, status='passed', build_dir="/tmp"), + 'dummy2': mock.Mock(run=True, retries=0, status='skipped', build_dir="/tmp"), + 'dummy3': mock.Mock(run=True, retries=0, status='filtered', build_dir="/tmp"), + 'dummy4': mock.Mock(run=True, retries=0, status='error', build_dir="/tmp"), + 'dummy5': mock.Mock(run=True, retries=0, status='failed', build_dir="/tmp") } instances['dummy4'].testsuite.filter = 'some' instances['dummy5'].testsuite.filter = 'full' @@ -2650,11 +2640,6 @@ def mock_join(): with mock.patch('twisterlib.runner.Process', process_mock): tr.execute(pipeline_mock, done_mock) - assert 'Launch process 0' in caplog.text - assert 'Launch process 1' in caplog.text - assert 'Launch process 2' in caplog.text - assert 'Launch process 3' in caplog.text - assert 'Launch process 4' in caplog.text assert 'Execution interrupted' in caplog.text assert len(process_mock().start.call_args_list) == 5 diff --git a/scripts/tests/twister/test_testinstance.py b/scripts/tests/twister/test_testinstance.py index 73a3c8f7dfb..52c51b2b278 100644 --- a/scripts/tests/twister/test_testinstance.py +++ b/scripts/tests/twister/test_testinstance.py @@ -7,21 +7,23 @@ Tests for testinstance class """ +from contextlib import nullcontext import os import sys import pytest - -from unittest import mock +import mock ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) + from twisterlib.testinstance import TestInstance from twisterlib.error import BuildError from twisterlib.runner import TwisterRunner +from twisterlib.handlers import QEMUHandler from expr_parser import reserved -TESTDATA_1 = [ +TESTDATA_PART_1 = [ (False, False, "console", "na", "qemu", False, [], (False, True)), (False, False, "console", "native", "qemu", False, [], (False, True)), (True, False, "console", "native", "nsim", False, [], (True, False)), @@ -30,14 +32,30 @@ (False, False, "sensor", "na", "", False, [], (True, False)), (False, True, "sensor", "native", "", True, [], (True, False)), ] -@pytest.mark.parametrize("build_only, slow, harness, platform_type, platform_sim, device_testing,fixture, expected", TESTDATA_1) -def test_check_build_or_run(class_testplan, all_testsuites_dict, platforms_list, build_only, slow, harness, platform_type, platform_sim, device_testing, fixture, expected): +@pytest.mark.parametrize( + "build_only, slow, harness, platform_type, platform_sim, device_testing,fixture, expected", + TESTDATA_PART_1 +) +def test_check_build_or_run( + class_testplan, + all_testsuites_dict, + platforms_list, + build_only, + slow, + harness, + platform_type, + platform_sim, + device_testing, + fixture, + expected +): """" Test to check the conditions for build_only and run scenarios Scenario 1: Test when different parameters are passed, build_only and run are set correctly Scenario 2: Test if build_only is enabled when the OS is Windows""" class_testplan.testsuites = all_testsuites_dict - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1') + testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/' + 'test_a/test_a.check_1') print(testsuite) class_testplan.platforms = platforms_list @@ -57,27 +75,52 @@ def test_check_build_or_run(class_testplan, all_testsuites_dict, platforms_list, run = testinstance.check_runnable() assert not run -TESTDATA_2 = [ - (True, True, True, ["demo_board_2"], "native", None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y\nCONFIG_UBSAN=y'), - (True, False, True, ["demo_board_2"], "native", None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'), - (False, False, True, ["demo_board_2"], 'native', None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), - (True, False, True, ["demo_board_2"], 'mcu', None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), +TESTDATA_PART_2 = [ + (True, True, True, ["demo_board_2"], "native", + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y\nCONFIG_UBSAN=y'), + (True, False, True, ["demo_board_2"], "native", + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y\nCONFIG_ASAN=y'), + (False, False, True, ["demo_board_2"], 'native', + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), + (True, False, True, ["demo_board_2"], 'mcu', + None, '\nCONFIG_COVERAGE=y\nCONFIG_COVERAGE_DUMP=y'), (False, False, False, ["demo_board_2"], 'native', None, ''), (False, False, True, ['demo_board_1'], 'native', None, ''), (True, False, False, ["demo_board_2"], 'native', None, '\nCONFIG_ASAN=y'), (False, True, False, ["demo_board_2"], 'native', None, '\nCONFIG_UBSAN=y'), - (False, False, False, ["demo_board_2"], 'native', ["CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["arch:x86_demo:CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["arch:arm_demo:CONFIG_LOG=y"], ''), - (False, False, False, ["demo_board_2"], 'native', ["platform:demo_board_2:CONFIG_LOG=y"], 'CONFIG_LOG=y'), - (False, False, False, ["demo_board_2"], 'native', ["platform:demo_board_1:CONFIG_LOG=y"], ''), + (False, False, False, ["demo_board_2"], 'native', + ["CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["arch:x86_demo:CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["arch:arm_demo:CONFIG_LOG=y"], ''), + (False, False, False, ["demo_board_2"], 'native', + ["platform:demo_board_2:CONFIG_LOG=y"], 'CONFIG_LOG=y'), + (False, False, False, ["demo_board_2"], 'native', + ["platform:demo_board_1:CONFIG_LOG=y"], ''), ] -@pytest.mark.parametrize("enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, extra_configs, expected_content", TESTDATA_2) -def test_create_overlay(class_testplan, all_testsuites_dict, platforms_list, enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type, extra_configs, expected_content): +@pytest.mark.parametrize( + 'enable_asan, enable_ubsan, enable_coverage, coverage_platform, platform_type,' + ' extra_configs, expected_content', + TESTDATA_PART_2 +) +def test_create_overlay( + class_testplan, + all_testsuites_dict, + platforms_list, + enable_asan, + enable_ubsan, + enable_coverage, + coverage_platform, + platform_type, + extra_configs, + expected_content +): """Test correct content is written to testcase_extra.conf based on if conditions.""" class_testplan.testsuites = all_testsuites_dict - testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app') + testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/' + 'test_app/sample_test.app') if extra_configs: testcase.extra_configs = extra_configs @@ -92,7 +135,8 @@ def test_create_overlay(class_testplan, all_testsuites_dict, platforms_list, ena def test_calculate_sizes(class_testplan, all_testsuites_dict, platforms_list): """ Test Calculate sizes method for zephyr elf""" class_testplan.testsuites = all_testsuites_dict - testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app') + testcase = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/samples/' + 'test_app/sample_test.app') class_testplan.platforms = platforms_list platform = class_testplan.get_platform("demo_board_2") testinstance = TestInstance(testcase, platform, class_testplan.env.outdir) @@ -100,15 +144,452 @@ def test_calculate_sizes(class_testplan, all_testsuites_dict, platforms_list): with pytest.raises(BuildError): assert testinstance.calculate_sizes() == "Missing/multiple output ELF binary" -TESTDATA_3 = [ - ('CONFIG_ARCH_HAS_THREAD_LOCAL_STORAGE and CONFIG_TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE and not (CONFIG_TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE and CONFIG_USERSPACE)', ['kconfig']), - ('(dt_compat_enabled("st,stm32-flash-controller") or dt_compat_enabled("st,stm32h7-flash-controller")) and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")', ['dts']), - ('((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE) and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) or (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE and dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions"))', ['dts', 'kconfig']), - ('((CONFIG_CPU_AARCH32_CORTEX_R or CONFIG_CPU_CORTEX_M) and CONFIG_CPU_HAS_FPU and TOOLCHAIN_HAS_NEWLIB == 1) or CONFIG_ARCH_POSIX', ['full']) +TESTDATA_PART_3 = [ + ( + 'CONFIG_ARCH_HAS_THREAD_LOCAL_STORAGE and' \ + ' CONFIG_TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE and' \ + ' not (CONFIG_TOOLCHAIN_ARCMWDT_SUPPORTS_THREAD_LOCAL_STORAGE and CONFIG_USERSPACE)', + ['kconfig'] + ), + ( + '(dt_compat_enabled("st,stm32-flash-controller") or' \ + ' dt_compat_enabled("st,stm32h7-flash-controller")) and' \ + ' dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")', + ['dts'] + ), + ( + '((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE) and' \ + ' dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")) or' \ + ' (CONFIG_FLASH_HAS_DRIVER_ENABLED and CONFIG_TRUSTED_EXECUTION_NONSECURE and' \ + ' dt_label_with_parent_compat_enabled("slot1_ns_partition", "fixed-partitions"))', + ['dts', 'kconfig'] + ), + ( + '((CONFIG_CPU_AARCH32_CORTEX_R or CONFIG_CPU_CORTEX_M) and' \ + ' CONFIG_CPU_HAS_FPU and TOOLCHAIN_HAS_NEWLIB == 1) or CONFIG_ARCH_POSIX', + ['full'] + ) ] -@pytest.mark.parametrize("filter_expr, expected_stages", TESTDATA_3) +@pytest.mark.parametrize("filter_expr, expected_stages", TESTDATA_PART_3) def test_which_filter_stages(filter_expr, expected_stages): logic_keys = reserved.keys() stages = TwisterRunner.get_cmake_filter_stages(filter_expr, logic_keys) assert sorted(stages) == sorted(expected_stages) + + +@pytest.fixture(name='testinstance') +def sample_testinstance(all_testsuites_dict, class_testplan, platforms_list, request): + testsuite_path = 'scripts/tests/twister/test_data/testsuites' + if request.param['testsuite_kind'] == 'sample': + testsuite_path += '/samples/test_app/sample_test.app' + elif request.param['testsuite_kind'] == 'tests': + testsuite_path += '/tests/test_a/test_a.check_1' + + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform(request.param.get('board_name', 'demo_board_2')) + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + return testinstance + + +TESTDATA_1 = [ + (False), + (True), +] + +@pytest.mark.parametrize('detailed_test_id', TESTDATA_1) +def test_testinstance_init(all_testsuites_dict, class_testplan, platforms_list, detailed_test_id): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + testsuite.detailed_test_id = detailed_test_id + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + + if detailed_test_id: + assert testinstance.build_dir == os.path.join(class_testplan.env.outdir, platform.name, testsuite_path) + else: + assert testinstance.build_dir == os.path.join(class_testplan.env.outdir, platform.name, testsuite.source_dir_rel, testsuite.name) + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'sample'}], indirect=True) +def test_testinstance_add_filter(testinstance): + reason = 'dummy reason' + filter_type = 'dummy type' + + testinstance.add_filter(reason, filter_type) + + assert {'type': filter_type, 'reason': reason} in testinstance.filters + assert testinstance.status == 'filtered' + assert testinstance.reason == reason + assert testinstance.filter_type == filter_type + + +def test_testinstance_init_cases(all_testsuites_dict, class_testplan, platforms_list): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + + testinstance.init_cases() + + assert all( + [ + any( + [ + tcc.name == tc.name and tcc.freeform == tc.freeform \ + for tcc in testinstance.testsuite.testcases + ] + ) for tc in testsuite.testcases + ] + ) + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'sample'}], indirect=True) +def test_testinstance_get_run_id(testinstance): + res = testinstance._get_run_id() + + assert isinstance(res, str) + + +TESTDATA_2 = [ + ('another reason', 'another reason'), + (None, 'dummy reason'), +] + +@pytest.mark.parametrize('reason, expected_reason', TESTDATA_2) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_add_missing_case_status(testinstance, reason, expected_reason): + testinstance.reason = 'dummy reason' + + status = 'passed' + + assert len(testinstance.testcases) > 1, 'Selected testsuite does not have enough testcases.' + + testinstance.testcases[0].status = 'started' + testinstance.testcases[-1].status = None + + testinstance.add_missing_case_status(status, reason) + + assert testinstance.testcases[0].status == 'failed' + assert testinstance.testcases[-1].status == 'passed' + assert testinstance.testcases[-1].reason == expected_reason + + +def test_testinstance_dunders(all_testsuites_dict, class_testplan, platforms_list): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + class_testplan.platforms = platforms_list + platform = class_testplan.get_platform("demo_board_2") + + testinstance = TestInstance(testsuite, platform, class_testplan.env.outdir) + testinstance_copy = TestInstance(testsuite, platform, class_testplan.env.outdir) + + d = testinstance.__getstate__() + + d['name'] = 'dummy name' + testinstance_copy.__setstate__(d) + + d['name'] = 'another name' + testinstance.__setstate__(d) + + assert testinstance < testinstance_copy + + testinstance_copy.__setstate__(d) + + assert not testinstance < testinstance_copy + assert not testinstance_copy < testinstance + + assert testinstance.__repr__() == f'' + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_set_case_status_by_name(testinstance): + name = 'test_a.check_1.2a' + status = 'dummy status' + reason = 'dummy reason' + + tc = testinstance.set_case_status_by_name(name, status, reason) + + assert tc.name == name + assert tc.status == status + assert tc.reason == reason + + tc = testinstance.set_case_status_by_name(name, status, None) + + assert tc.reason == reason + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_add_testcase(testinstance): + name = 'test_a.check_1.3a' + freeform = True + + tc = testinstance.add_testcase(name, freeform) + + assert tc in testinstance.testcases + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_case_by_name(testinstance): + name = 'test_a.check_1.2a' + + tc = testinstance.get_case_by_name(name) + + assert tc.name == name + + name = 'test_a.check_1.3a' + + tc = testinstance.get_case_by_name(name) + + assert tc is None + + +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_case_or_create(caplog, testinstance): + name = 'test_a.check_1.2a' + + tc = testinstance.get_case_or_create(name) + + assert tc.name == name + + name = 'test_a.check_1.3a' + + tc = testinstance.get_case_or_create(name) + + assert tc.name == name + assert 'Could not find a matching testcase for test_a.check_1.3a' in caplog.text + + +TESTDATA_3 = [ + (None, 'nonexistent harness', False), + ('nonexistent fixture', 'console', False), + (None, 'console', True), + ('dummy fixture', 'console', True), +] + +@pytest.mark.parametrize( + 'fixture, harness, expected_can_run', + TESTDATA_3, + ids=['improper harness', 'fixture not in list', 'no fixture specified', 'fixture in list'] +) +def test_testinstance_testsuite_runnable( + all_testsuites_dict, + class_testplan, + fixture, + harness, + expected_can_run +): + testsuite_path = 'scripts/tests/twister/test_data/testsuites/samples/test_app/sample_test.app' + class_testplan.testsuites = all_testsuites_dict + testsuite = class_testplan.testsuites.get(testsuite_path) + + testsuite.harness = harness + testsuite.harness_config['fixture'] = fixture + + fixtures = ['dummy fixture'] + + can_run = TestInstance.testsuite_runnable(testsuite, fixtures)\ + + assert can_run == expected_can_run + + +TESTDATA_4 = [ + (True, mock.ANY, mock.ANY, mock.ANY, None, [], False), + (False, True, mock.ANY, mock.ANY, 'device', [], True), + (False, False, 'qemu', mock.ANY, 'qemu', ['QEMU_PIPE=1'], True), + (False, False, 'dummy sim', mock.ANY, 'dummy sim', [], True), + (False, False, 'na', 'unit', 'unit', ['COVERAGE=1'], True), + (False, False, 'na', 'dummy type', '', [], False), +] + +@pytest.mark.parametrize( + 'preexisting_handler, device_testing, platform_sim, testsuite_type,' \ + ' expected_handler_type, expected_handler_args, expected_handler_ready', + TESTDATA_4, + ids=['preexisting handler', 'device testing', 'qemu simulation', + 'non-qemu simulation with exec', 'unit teting', 'no handler'] +) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_setup_handler( + testinstance, + preexisting_handler, + device_testing, + platform_sim, + testsuite_type, + expected_handler_type, + expected_handler_args, + expected_handler_ready +): + testinstance.handler = mock.Mock() if preexisting_handler else None + testinstance.platform.simulation = platform_sim + testinstance.platform.simulation_exec = 'dummy exec' + testinstance.testsuite.type = testsuite_type + env = mock.Mock( + options=mock.Mock( + device_testing=device_testing, + enable_coverage=True + ) + ) + + with mock.patch.object(QEMUHandler, 'get_fifo', return_value=1), \ + mock.patch('shutil.which', return_value=True): + testinstance.setup_handler(env) + + if expected_handler_type: + assert testinstance.handler.type_str == expected_handler_type + assert testinstance.handler.ready == expected_handler_ready + assert all([arg in testinstance.handler.args for arg in expected_handler_args]) + + +TESTDATA_5 = [ + ('nt', 'renode', mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', mock.ANY, mock.ANY, mock.ANY, + True, mock.ANY, mock.ANY, + mock.ANY, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', mock.ANY, mock.ANY, mock.ANY, + False, True, mock.ANY, + False, mock.ANY, mock.ANY, mock.ANY, False), + ('linux', 'qemu', mock.ANY, mock.ANY, + False, mock.ANY, 'pytest', + mock.ANY, 'not runnable', mock.ANY, None, True), + ('linux', 'renode', 'renode', True, + False, mock.ANY, 'console', + mock.ANY, 'not runnable', [], None, True), + ('linux', 'renode', 'renode', False, + False, mock.ANY, 'not pytest', + mock.ANY, 'not runnable', mock.ANY, None, False), + ('linux', 'qemu', mock.ANY, mock.ANY, + False, mock.ANY, 'console', + mock.ANY, 'not runnable', ['?'], mock.Mock(duts=[mock.Mock(platform='demo_board_2', fixtures=[])]), True), +] + +@pytest.mark.parametrize( + 'os_name, platform_sim, platform_sim_exec, exec_exists,' \ + ' testsuite_build_only, testsuite_slow, testsuite_harness,' \ + ' enable_slow, filter, fixtures, hardware_map, expected', + TESTDATA_5, + ids=['windows', 'build only', 'skip slow', 'pytest harness', 'sim', 'no sim', 'hardware map'] +) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_check_runnable( + testinstance, + os_name, + platform_sim, + platform_sim_exec, + exec_exists, + testsuite_build_only, + testsuite_slow, + testsuite_harness, + enable_slow, + filter, + fixtures, + hardware_map, + expected +): + testinstance.platform.simulation = platform_sim + testinstance.platform.simulation_exec = platform_sim_exec + testinstance.testsuite.build_only = testsuite_build_only + testinstance.testsuite.slow = testsuite_slow + testinstance.testsuite.harness = testsuite_harness + + with mock.patch('os.name', os_name), \ + mock.patch('shutil.which', return_value=exec_exists): + res = testinstance.check_runnable(enable_slow, filter, fixtures, hardware_map) + + assert res == expected + + +TESTDATA_6 = [ + (True, 'build.log'), + (False, ''), +] + +@pytest.mark.parametrize('from_buildlog, expected_buildlog_filepath', TESTDATA_6) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_calculate_sizes(testinstance, from_buildlog, expected_buildlog_filepath): + expected_elf_filepath = 'dummy.elf' + expected_extra_sections = [] + expected_warning = True + testinstance.get_elf_file = mock.Mock(return_value='dummy.elf') + testinstance.get_buildlog_file = mock.Mock(return_value='build.log') + + sc_mock = mock.Mock() + mock_sc = mock.Mock(return_value=sc_mock) + + with mock.patch('twisterlib.testinstance.SizeCalculator', mock_sc): + res = testinstance.calculate_sizes(from_buildlog, expected_warning) + + assert res == sc_mock + mock_sc.assert_called_once_with( + elf_filename=expected_elf_filepath, + extra_sections=expected_extra_sections, + buildlog_filepath=expected_buildlog_filepath, + generate_warning=expected_warning + ) + + +TESTDATA_7 = [ + (True, None), + (False, BuildError), +] + +@pytest.mark.parametrize('sysbuild, expected_error', TESTDATA_7) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_elf_file(caplog, tmp_path, testinstance, sysbuild, expected_error): + sysbuild_dir = tmp_path / 'sysbuild' + sysbuild_dir.mkdir() + zephyr_dir = sysbuild_dir / 'zephyr' + zephyr_dir.mkdir() + sysbuild_elf = zephyr_dir / 'dummy.elf' + sysbuild_elf.write_bytes(b'0') + sysbuild_elf2 = zephyr_dir / 'dummy2.elf' + sysbuild_elf2.write_bytes(b'0') + + testinstance.testsuite.sysbuild = sysbuild + testinstance.domains = mock.Mock( + get_default_domain=mock.Mock( + return_value=mock.Mock( + build_dir=sysbuild_dir + ) + ) + ) + + with pytest.raises(expected_error) if expected_error else nullcontext(): + testinstance.get_elf_file() + + if expected_error is None: + assert 'multiple ELF files detected: ' in caplog.text + + +TESTDATA_8 = [ + (True, None), + (False, BuildError), +] + +@pytest.mark.parametrize('create_build_log, expected_error', TESTDATA_8) +@pytest.mark.parametrize('testinstance', [{'testsuite_kind': 'tests'}], indirect=True) +def test_testinstance_get_buildlog_file(tmp_path, testinstance, create_build_log, expected_error): + if create_build_log: + build_dir = tmp_path / 'build' + build_dir.mkdir() + build_log = build_dir / 'build.log' + build_log.write_text('') + testinstance.build_dir = build_dir + + with pytest.raises(expected_error) if expected_error else nullcontext(): + res = testinstance.get_buildlog_file() + + if expected_error is None: + assert res == str(build_log) diff --git a/scripts/tests/twister/test_testplan.py b/scripts/tests/twister/test_testplan.py new file mode 100644 index 00000000000..488c39ddf73 --- /dev/null +++ b/scripts/tests/twister/test_testplan.py @@ -0,0 +1,1781 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +''' +This test file contains testsuites for testsuite.py module of twister +''' +import sys +import os +import mock +import pytest + +from contextlib import nullcontext + +ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") +sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) + +from twisterlib.testplan import TestPlan, change_skip_to_error_if_integration +from twisterlib.testinstance import TestInstance +from twisterlib.testsuite import TestSuite +from twisterlib.platform import Platform +from twisterlib.quarantine import Quarantine +from twisterlib.error import TwisterRuntimeError + + +def test_testplan_add_testsuites_short(class_testplan): + """ Testing add_testcase function of Testsuite class in twister """ + # Test 1: Check the list of testsuites after calling add testsuites function is as expected + class_testplan.SAMPLE_FILENAME = 'test_sample_app.yaml' + class_testplan.TESTSUITE_FILENAME = 'test_data.yaml' + class_testplan.add_testsuites() + + tests_rel_dir = 'scripts/tests/twister/test_data/testsuites/tests/' + expected_testsuites = ['test_b.check_1', + 'test_b.check_2', + 'test_c.check_1', + 'test_c.check_2', + 'test_a.check_1', + 'test_a.check_2', + 'test_d.check_1', + 'test_e.check_1', + 'sample_test.app', + 'test_config.main'] + testsuite_list = [] + for key in sorted(class_testplan.testsuites.keys()): + testsuite_list.append(os.path.basename(os.path.normpath(key))) + assert sorted(testsuite_list) == sorted(expected_testsuites) + + # Test 2 : Assert Testcase name is expected & all testsuites values are testcase class objects + suite = class_testplan.testsuites.get(tests_rel_dir + 'test_a/test_a.check_1') + assert suite.name == tests_rel_dir + 'test_a/test_a.check_1' + assert all(isinstance(n, TestSuite) for n in class_testplan.testsuites.values()) + +@pytest.mark.parametrize("board_root_dir", [("board_config_file_not_exist"), ("board_config")]) +def test_add_configurations_short(test_data, class_env, board_root_dir): + """ Testing add_configurations function of TestPlan class in Twister + Test : Asserting on default platforms list + """ + class_env.board_roots = [os.path.abspath(test_data + board_root_dir)] + plan = TestPlan(class_env) + plan.parse_configuration(config_file=class_env.test_config) + if board_root_dir == "board_config": + plan.add_configurations() + assert sorted(plan.default_platforms) == sorted(['demo_board_1', 'demo_board_3']) + elif board_root_dir == "board_config_file_not_exist": + plan.add_configurations() + assert sorted(plan.default_platforms) != sorted(['demo_board_1']) + + +def test_get_all_testsuites_short(class_testplan, all_testsuites_dict): + """ Testing get_all_testsuites function of TestPlan class in Twister """ + plan = class_testplan + plan.testsuites = all_testsuites_dict + expected_tests = ['sample_test.app', 'test_a.check_1.1a', + 'test_a.check_1.1c', + 'test_a.check_1.2a', 'test_a.check_1.2b', + 'test_a.check_1.Unit_1c', 'test_a.check_1.unit_1a', + 'test_a.check_1.unit_1b', 'test_a.check_2.1a', + 'test_a.check_2.1c', 'test_a.check_2.2a', + 'test_a.check_2.2b', 'test_a.check_2.Unit_1c', + 'test_a.check_2.unit_1a', 'test_a.check_2.unit_1b', + 'test_b.check_1', 'test_b.check_2', 'test_c.check_1', + 'test_c.check_2', 'test_d.check_1.unit_1a', + 'test_d.check_1.unit_1b', + 'test_e.check_1.1a', 'test_e.check_1.1b', + 'test_config.main'] + + assert sorted(plan.get_all_tests()) == sorted(expected_tests) + +def test_get_platforms_short(class_testplan, platforms_list): + """ Testing get_platforms function of TestPlan class in Twister """ + plan = class_testplan + plan.platforms = platforms_list + platform = plan.get_platform("demo_board_1") + assert isinstance(platform, Platform) + assert platform.name == "demo_board_1" + +TESTDATA_PART1 = [ + ("toolchain_allow", ['gcc'], None, None, "Not in testsuite toolchain allow list"), + ("platform_allow", ['demo_board_1'], None, None, "Not in testsuite platform allow list"), + ("toolchain_exclude", ['zephyr'], None, None, "In test case toolchain exclude"), + ("platform_exclude", ['demo_board_2'], None, None, "In test case platform exclude"), + ("arch_exclude", ['x86_demo'], None, None, "In test case arch exclude"), + ("arch_allow", ['arm'], None, None, "Not in test case arch allow list"), + ("skip", True, None, None, "Skip filter"), + ("tags", set(['sensor', 'bluetooth']), "ignore_tags", ['bluetooth'], "Excluded tags per platform (exclude_tags)"), + ("min_flash", "2024", "flash", "1024", "Not enough FLASH"), + ("min_ram", "500", "ram", "256", "Not enough RAM"), + ("None", "None", "env", ['BSIM_OUT_PATH', 'demo_env'], "Environment (BSIM_OUT_PATH, demo_env) not satisfied"), + ("build_on_all", True, None, None, "Platform is excluded on command line."), + (None, None, "supported_toolchains", ['gcc'], "Not supported by the toolchain"), +] + + +@pytest.mark.parametrize("tc_attribute, tc_value, plat_attribute, plat_value, expected_discards", + TESTDATA_PART1) +def test_apply_filters_part1(class_testplan, all_testsuites_dict, platforms_list, + tc_attribute, tc_value, plat_attribute, plat_value, expected_discards): + """ Testing apply_filters function of TestPlan class in Twister + Part 1: Response of apply_filters function have + appropriate values according to the filters + """ + plan = class_testplan + if tc_attribute is None and plat_attribute is None: + plan.apply_filters() + + plan.platforms = platforms_list + plan.platform_names = [p.name for p in platforms_list] + plan.testsuites = all_testsuites_dict + for plat in plan.platforms: + if plat_attribute == "ignore_tags": + plat.ignore_tags = plat_value + if plat_attribute == "flash": + plat.flash = plat_value + if plat_attribute == "ram": + plat.ram = plat_value + if plat_attribute == "env": + plat.env = plat_value + plat.env_satisfied = False + if plat_attribute == "supported_toolchains": + plat.supported_toolchains = plat_value + for _, testcase in plan.testsuites.items(): + if tc_attribute == "toolchain_allow": + testcase.toolchain_allow = tc_value + if tc_attribute == "platform_allow": + testcase.platform_allow = tc_value + if tc_attribute == "toolchain_exclude": + testcase.toolchain_exclude = tc_value + if tc_attribute == "platform_exclude": + testcase.platform_exclude = tc_value + if tc_attribute == "arch_exclude": + testcase.arch_exclude = tc_value + if tc_attribute == "arch_allow": + testcase.arch_allow = tc_value + if tc_attribute == "skip": + testcase.skip = tc_value + if tc_attribute == "tags": + testcase.tags = tc_value + if tc_attribute == "min_flash": + testcase.min_flash = tc_value + if tc_attribute == "min_ram": + testcase.min_ram = tc_value + + if tc_attribute == "build_on_all": + for _, testcase in plan.testsuites.items(): + testcase.build_on_all = tc_value + plan.apply_filters(exclude_platform=['demo_board_1']) + elif plat_attribute == "supported_toolchains": + plan.apply_filters(force_toolchain=False, + exclude_platform=['demo_board_1'], + platform=['demo_board_2']) + elif tc_attribute is None and plat_attribute is None: + plan.apply_filters() + else: + plan.apply_filters(exclude_platform=['demo_board_1'], + platform=['demo_board_2']) + + filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) + for d in filtered_instances: + assert d.reason == expected_discards + +TESTDATA_PART2 = [ + ("runnable", "True", "Not runnable on device"), + ("exclude_tag", ['test_a'], "Command line testsuite exclude filter"), + ("run_individual_tests", ['scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1'], "TestSuite name filter"), + ("arch", ['arm_test'], "Command line testsuite arch filter"), + ("tag", ['test_d'], "Command line testsuite tag filter") + ] + + +@pytest.mark.parametrize("extra_filter, extra_filter_value, expected_discards", TESTDATA_PART2) +def test_apply_filters_part2(class_testplan, all_testsuites_dict, + platforms_list, extra_filter, extra_filter_value, expected_discards): + """ Testing apply_filters function of TestPlan class in Twister + Part 2 : Response of apply_filters function (discard dictionary) have + appropriate values according to the filters + """ + + class_testplan.platforms = platforms_list + class_testplan.platform_names = [p.name for p in platforms_list] + class_testplan.testsuites = all_testsuites_dict + kwargs = { + extra_filter : extra_filter_value, + "exclude_platform" : [ + 'demo_board_1' + ], + "platform" : [ + 'demo_board_2' + ] + } + class_testplan.apply_filters(**kwargs) + filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) + for d in filtered_instances: + assert d.reason == expected_discards + + +TESTDATA_PART3 = [ + (20, 20, -1, 0), + (-2, -1, 10, 20), + (0, 0, 0, 0) + ] + +@pytest.mark.parametrize("tc_min_flash, plat_flash, tc_min_ram, plat_ram", + TESTDATA_PART3) +def test_apply_filters_part3(class_testplan, all_testsuites_dict, platforms_list, + tc_min_flash, plat_flash, tc_min_ram, plat_ram): + """ Testing apply_filters function of TestPlan class in Twister + Part 3 : Testing edge cases for ram and flash values of platforms & testsuites + """ + class_testplan.platforms = platforms_list + class_testplan.platform_names = [p.name for p in platforms_list] + class_testplan.testsuites = all_testsuites_dict + + for plat in class_testplan.platforms: + plat.flash = plat_flash + plat.ram = plat_ram + for _, testcase in class_testplan.testsuites.items(): + testcase.min_ram = tc_min_ram + testcase.min_flash = tc_min_flash + class_testplan.apply_filters(exclude_platform=['demo_board_1'], + platform=['demo_board_2']) + + filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) + assert not filtered_instances + +def test_add_instances_short(tmp_path, class_env, all_testsuites_dict, platforms_list): + """ Testing add_instances() function of TestPlan class in Twister + Test 1: instances dictionary keys have expected values (Platform Name + Testcase Name) + Test 2: Values of 'instances' dictionary in Testsuite class are an + instance of 'TestInstance' class + Test 3: Values of 'instances' dictionary have expected values. + """ + class_env.outdir = tmp_path + plan = TestPlan(class_env) + plan.platforms = platforms_list + platform = plan.get_platform("demo_board_2") + instance_list = [] + for _, testcase in all_testsuites_dict.items(): + instance = TestInstance(testcase, platform, class_env.outdir) + instance_list.append(instance) + plan.add_instances(instance_list) + assert list(plan.instances.keys()) == \ + [platform.name + '/' + s for s in list(all_testsuites_dict.keys())] + assert all(isinstance(n, TestInstance) for n in list(plan.instances.values())) + assert list(plan.instances.values()) == instance_list + + +QUARANTINE_BASIC = { + 'demo_board_1/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'a1 on board_1 and board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'a1 on board_1 and board_3' +} + +QUARANTINE_WITH_REGEXP = { + 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_2' : 'a2 and c2 on x86', + 'demo_board_1/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', + 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', + 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_2' : 'a2 and c2 on x86' +} + +QUARANTINE_PLATFORM = { + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_2' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_b/test_b.check_1' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_b/test_b.check_2' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_2' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_e/test_e.check_1' : 'all on board_3', + 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_config/test_config.main' : 'all on board_3' +} + +QUARANTINE_MULTIFILES = { + **QUARANTINE_BASIC, + **QUARANTINE_WITH_REGEXP +} + +@pytest.mark.parametrize( + ("quarantine_files, quarantine_verify, expected_val"), + [ + (['basic.yaml'], False, QUARANTINE_BASIC), + (['with_regexp.yaml'], False, QUARANTINE_WITH_REGEXP), + (['with_regexp.yaml'], True, QUARANTINE_WITH_REGEXP), + (['platform.yaml'], False, QUARANTINE_PLATFORM), + (['basic.yaml', 'with_regexp.yaml'], False, QUARANTINE_MULTIFILES), + (['empty.yaml'], False, {}) + ], + ids=[ + 'basic', + 'with_regexp', + 'quarantine_verify', + 'platform', + 'multifiles', + 'empty' + ]) +def test_quarantine_short(class_testplan, platforms_list, test_data, + quarantine_files, quarantine_verify, expected_val): + """ Testing quarantine feature in Twister + """ + class_testplan.options.all = True + class_testplan.platforms = platforms_list + class_testplan.platform_names = [p.name for p in platforms_list] + class_testplan.TESTSUITE_FILENAME = 'test_data.yaml' + class_testplan.add_testsuites() + + quarantine_list = [ + os.path.join(test_data, 'quarantines', quarantine_file) for quarantine_file in quarantine_files + ] + class_testplan.quarantine = Quarantine(quarantine_list) + class_testplan.options.quarantine_verify = quarantine_verify + class_testplan.apply_filters() + + for testname, instance in class_testplan.instances.items(): + if quarantine_verify: + if testname in expected_val: + assert not instance.status + else: + assert instance.status == 'filtered' + assert instance.reason == "Not under quarantine" + else: + if testname in expected_val: + assert instance.status == 'filtered' + assert instance.reason == "Quarantine: " + expected_val[testname] + else: + assert not instance.status + + +TESTDATA_PART4 = [ + (os.path.join('test_d', 'test_d.check_1'), ['dummy'], + None, 'Snippet not supported'), + (os.path.join('test_c', 'test_c.check_1'), ['cdc-acm-console'], + 0, None), + (os.path.join('test_d', 'test_d.check_1'), ['dummy', 'cdc-acm-console'], + 2, 'Snippet not supported'), +] + +@pytest.mark.parametrize( + 'testpath, required_snippets, expected_filtered_len, expected_filtered_reason', + TESTDATA_PART4, + ids=['app', 'global', 'multiple'] +) +def test_required_snippets_short( + class_testplan, + all_testsuites_dict, + platforms_list, + testpath, + required_snippets, + expected_filtered_len, + expected_filtered_reason +): + """ Testing required_snippets function of TestPlan class in Twister """ + plan = class_testplan + testpath = os.path.join('scripts', 'tests', 'twister', 'test_data', + 'testsuites', 'tests', testpath) + testsuite = class_testplan.testsuites.get(testpath) + plan.platforms = platforms_list + plan.platform_names = [p.name for p in platforms_list] + plan.testsuites = {testpath: testsuite} + + print(plan.testsuites) + + for _, testcase in plan.testsuites.items(): + testcase.exclude_platform = [] + testcase.required_snippets = required_snippets + testcase.build_on_all = True + + plan.apply_filters() + + filtered_instances = list( + filter(lambda item: item.status == "filtered", plan.instances.values()) + ) + if expected_filtered_len is not None: + assert len(filtered_instances) == expected_filtered_len + if expected_filtered_reason is not None: + for d in filtered_instances: + assert d.reason == expected_filtered_reason + + +def test_testplan_get_level(): + testplan = TestPlan(env=mock.Mock()) + lvl1 = mock.Mock() + lvl1.name = 'a lvl' + lvl2 = mock.Mock() + lvl2.name = 'a lvl' + lvl3 = mock.Mock() + lvl3.name = 'other lvl' + testplan.levels.append(lvl1) + testplan.levels.append(lvl2) + testplan.levels.append(lvl3) + + name = 'a lvl' + + res = testplan.get_level(name) + assert res == lvl1 + + res = testplan.get_level(name) + assert res == lvl1 + + testplan.levels.remove(lvl1) + testplan.levels.remove(lvl2) + + res = testplan.get_level(name) + assert res is None + + +TESTDATA_1 = [ + ('', {}), + ( +"""\ +levels: + - name: lvl1 + adds: + - sc1 + - sc2 + inherits: [] + - name: lvl2 + adds: + - sc1-1 + - sc1-2 + inherits: [lvl1] +""", + { + 'lvl1': ['sc1', 'sc2'], + 'lvl2': ['sc1-1', 'sc1-2', 'sc1', 'sc2'] + } + ), +] + +@pytest.mark.parametrize( + 'config_yaml, expected_scenarios', + TESTDATA_1, + ids=['no config', 'valid config'] +) +def test_testplan_parse_configuration(tmp_path, config_yaml, expected_scenarios): + testplan = TestPlan(env=mock.Mock()) + testplan.scenarios = ['sc1', 'sc1-1', 'sc1-2', 'sc2'] + + tmp_config_file = tmp_path / 'config_file.yaml' + if config_yaml: + tmp_config_file.write_text(config_yaml) + + with pytest.raises(TwisterRuntimeError) if not config_yaml else nullcontext(): + testplan.parse_configuration(tmp_config_file) + + if not testplan.levels: + assert expected_scenarios == {} + for level in testplan.levels: + assert sorted(level.scenarios) == sorted(expected_scenarios[level.name]) + + +TESTDATA_2 = [ + ([], [], False), + (['ts1.tc3'], [], True), + (['ts2.tc2'], ['- ts2'], False), +] + +@pytest.mark.parametrize( + 'sub_tests, expected_outs, expect_error', + TESTDATA_2, + ids=['no subtests', 'subtests not found', 'valid subtests'] +) +def test_testplan_find_subtests( + capfd, + sub_tests, + expected_outs, + expect_error +): + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock(sub_test=sub_tests) + testplan.run_individual_testsuite = [] + testplan.testsuites = { + 'ts1': mock.Mock( + testcases=[ + mock.Mock(), + mock.Mock(), + ] + ), + 'ts2': mock.Mock( + testcases=[ + mock.Mock(), + mock.Mock(), + mock.Mock(), + ] + ) + } + testplan.testsuites['ts1'].name = 'ts1' + testplan.testsuites['ts1'].testcases[0].name = 'ts1.tc1' + testplan.testsuites['ts1'].testcases[1].name = 'ts1.tc2' + testplan.testsuites['ts2'].name = 'ts2' + testplan.testsuites['ts2'].testcases[0].name = 'ts2.tc1' + testplan.testsuites['ts2'].testcases[1].name = 'ts2.tc2' + testplan.testsuites['ts2'].testcases[2].name = 'ts2.tc3' + + with pytest.raises(TwisterRuntimeError) if expect_error else nullcontext(): + testplan.find_subtests() + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stdout.write(err) + + assert all([printout in out for printout in expected_outs]) + + +TESTDATA_3 = [ + (0, 0, [], False, [], TwisterRuntimeError, []), + (1, 1, [], False, [], TwisterRuntimeError, []), + (1, 0, [], True, [], TwisterRuntimeError, ['No quarantine list given to be verified']), +# (1, 0, ['qfile.yaml'], False, ['# empty'], None, ['Quarantine file qfile.yaml is empty']), + (1, 0, ['qfile.yaml'], False, ['- platforms:\n - demo_board_3\n comment: "board_3"'], None, []), +] + +@pytest.mark.parametrize( + 'added_testsuite_count, load_errors, ql, qv, ql_data, exception, expected_logs', + TESTDATA_3, + ids=['no tests', 'load errors', 'quarantine verify without quarantine list', +# 'empty quarantine file', + 'valid quarantine file'] +) +def test_testplan_discover( + tmp_path, + caplog, + added_testsuite_count, + load_errors, + ql, + qv, + ql_data, + exception, + expected_logs +): + for qf, data in zip(ql, ql_data): + tmp_qf = tmp_path / qf + tmp_qf.write_text(data) + + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock( + test='ts1', + quarantine_list=[tmp_path / qf for qf in ql], + quarantine_verify=qv, + ) + testplan.testsuites = { + 'ts1': mock.Mock(id=1), + 'ts2': mock.Mock(id=2), + } + testplan.run_individual_testsuite = 'ts0' + testplan.load_errors = load_errors + testplan.add_testsuites = mock.Mock(return_value=added_testsuite_count) + testplan.find_subtests = mock.Mock() + testplan.report_duplicates = mock.Mock() + testplan.parse_configuration = mock.Mock() + testplan.add_configurations = mock.Mock() + + with pytest.raises(exception) if exception else nullcontext(): + testplan.discover() + + testplan.add_testsuites.assert_called_once_with(testsuite_filter='ts1') + assert all([log in caplog.text for log in expected_logs]) + + +TESTDATA_4 = [ + (None, None, None, None, '00', + TwisterRuntimeError, [], []), + (None, True, None, None, '6/4', + TwisterRuntimeError, set(['t-p3', 't-p4', 't-p1', 't-p2']), []), + (None, None, 'load_tests.json', None, '0/4', + TwisterRuntimeError, set(['lt-p1', 'lt-p3', 'lt-p4', 'lt-p2']), []), + ('suffix', None, None, True, '2/4', + None, set(['ts-p4', 'ts-p2', 'ts-p3']), [2, 4]), +] + +@pytest.mark.parametrize( + 'report_suffix, only_failed, load_tests, test_only, subset,' \ + ' exception, expected_selected_platforms, expected_generate_subset_args', + TESTDATA_4, + ids=['apply_filters only', 'only failed', 'load tests', 'test only'] +) +def test_testplan_load( + tmp_path, + report_suffix, + only_failed, + load_tests, + test_only, + subset, + exception, + expected_selected_platforms, + expected_generate_subset_args +): + twister_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "t-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "t-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "t-p3", + "testcases": [] + }, + { + "name": "ts2", + "platform": "t-p4", + "testcases": [] + } + ] +} +""" + twister_file = tmp_path / 'twister.json' + twister_file.write_text(twister_json) + + twister_suffix_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "ts-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "ts-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "ts-p3", + "testcases": [] + }, + { + "name": "ts2", + "platform": "ts-p4", + "testcases": [] + } + ] +} +""" + twister_suffix_file = tmp_path / 'twister_suffix.json' + twister_suffix_file.write_text(twister_suffix_json) + + load_tests_json = """\ +{ + "testsuites": [ + { + "name": "ts1", + "platform": "lt-p1", + "testcases": [] + }, + { + "name": "ts1", + "platform": "lt-p2", + "testcases": [] + }, + { + "name": "ts2", + "platform": "lt-p3", + \"testcases": [] + }, + { + "name": "ts2", + "platform": "lt-p4", + "testcases": [] + } + ] +} +""" + load_tests_file = tmp_path / 'load_tests.json' + load_tests_file.write_text(load_tests_json) + + testplan = TestPlan(env=mock.Mock(outdir=tmp_path)) + testplan.testsuites = { + 'ts1': mock.Mock(testcases=[], extra_configs=[]), + 'ts2': mock.Mock(testcases=[], extra_configs=[]), + } + testplan.testsuites['ts1'].name = 'ts1' + testplan.testsuites['ts2'].name = 'ts2' + testplan.options = mock.Mock( + outdir=tmp_path, + report_suffix=report_suffix, + only_failed=only_failed, + load_tests=tmp_path / load_tests if load_tests else None, + test_only=test_only, + exclude_platform=['t-p0', 't-p1', + 'ts-p0', 'ts-p1', + 'lt-p0', 'lt-p1'], + platform=['t-p1', 't-p2', 't-p3', 't-p4', + 'ts-p1', 'ts-p2', 'ts-p3', 'ts-p4', + 'lt-p1', 'lt-p2', 'lt-p3', 'lt-p4'], + subset=subset + ) + testplan.platforms=[mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), + mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), + mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()] + testplan.platforms[0].name = 't-p1' + testplan.platforms[1].name = 't-p2' + testplan.platforms[2].name = 't-p3' + testplan.platforms[3].name = 't-p4' + testplan.platforms[4].name = 'ts-p1' + testplan.platforms[5].name = 'ts-p2' + testplan.platforms[6].name = 'ts-p3' + testplan.platforms[7].name = 'ts-p4' + testplan.platforms[8].name = 'lt-p1' + testplan.platforms[9].name = 'lt-p2' + testplan.platforms[10].name = 'lt-p3' + testplan.platforms[11].name = 'lt-p4' + testplan.generate_subset = mock.Mock() + testplan.apply_filters = mock.Mock() + + with mock.patch('twisterlib.testinstance.TestInstance.create_overlay', mock.Mock()), \ + pytest.raises(exception) if exception else nullcontext(): + testplan.load() + + assert testplan.selected_platforms == expected_selected_platforms + if expected_generate_subset_args: + testplan.generate_subset.assert_called_once_with(*expected_generate_subset_args) + else: + testplan.generate_subset.assert_not_called() + + +TESTDATA_5 = [ + (False, False, None, 1, 2, + ['plat1/testA', 'plat1/testB', 'plat1/testC', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (False, False, None, 1, 5, + ['plat1/testA', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (False, False, None, 2, 2, + ['plat2/testA', 'plat2/testB']), + (True, False, None, 1, 2, + ['plat1/testA', 'plat2/testA', 'plat1/testB', + 'plat3/testA', 'plat3/testB', 'plat3/testC']), + (True, False, None, 2, 2, + ['plat2/testB', 'plat1/testC']), + (True, True, 123, 1, 2, + ['plat2/testA', 'plat2/testB', 'plat1/testC', + 'plat3/testB', 'plat3/testA', 'plat3/testC']), + (True, True, 123, 2, 2, + ['plat1/testB', 'plat1/testA']), +] + +@pytest.mark.parametrize( + 'device_testing, shuffle, seed, subset, sets, expected_subset', + TESTDATA_5, + ids=['subset 1', 'subset 1 out of 5', 'subset 2', + 'device testing, subset 1', 'device testing, subset 2', + 'device testing, shuffle with seed, subset 1', + 'device testing, shuffle with seed, subset 2'] +) +def test_testplan_generate_subset( + device_testing, + shuffle, + seed, + subset, + sets, + expected_subset +): + testplan = TestPlan(env=mock.Mock()) + testplan.options = mock.Mock( + device_testing=device_testing, + shuffle_tests=shuffle, + shuffle_tests_seed=seed + ) + testplan.instances = { + 'plat1/testA': mock.Mock(status=None), + 'plat1/testB': mock.Mock(status=None), + 'plat1/testC': mock.Mock(status=None), + 'plat2/testA': mock.Mock(status=None), + 'plat2/testB': mock.Mock(status=None), + 'plat3/testA': mock.Mock(status='skipped'), + 'plat3/testB': mock.Mock(status='skipped'), + 'plat3/testC': mock.Mock(status='error'), + } + + testplan.generate_subset(subset, sets) + + assert [instance for instance in testplan.instances.keys()] == \ + expected_subset + + +def test_testplan_handle_modules(): + testplan = TestPlan(env=mock.Mock()) + + modules = [mock.Mock(meta={'name': 'name1'}), + mock.Mock(meta={'name': 'name2'})] + + with mock.patch('twisterlib.testplan.parse_modules', return_value=modules): + testplan.handle_modules() + + assert testplan.modules == ['name1', 'name2'] + + +TESTDATA_6 = [ + (True, False, False, 0, 'report_test_tree'), + (True, True, False, 0, 'report_test_tree'), + (True, False, True, 0, 'report_test_tree'), + (True, True, True, 0, 'report_test_tree'), + (False, True, False, 0, 'report_test_list'), + (False, True, True, 0, 'report_test_list'), + (False, False, True, 0, 'report_tag_list'), + (False, False, False, 1, None), +] + +@pytest.mark.parametrize( + 'test_tree, list_tests, list_tags, expected_res, expected_method', + TESTDATA_6, + ids=['test tree', 'test tree + test list', 'test tree + tag list', + 'test tree + test list + tag list', 'test list', + 'test list + tag list', 'tag list', 'no report'] +) +def test_testplan_report( + test_tree, + list_tests, + list_tags, + expected_res, + expected_method +): + testplan = TestPlan(env=mock.Mock()) + testplan.report_test_tree = mock.Mock() + testplan.report_test_list = mock.Mock() + testplan.report_tag_list = mock.Mock() + + testplan.options = mock.Mock( + test_tree=test_tree, + list_tests=list_tests, + list_tags=list_tags, + ) + + res = testplan.report() + + assert res == expected_res + + methods = ['report_test_tree', 'report_test_list', 'report_tag_list'] + if expected_method: + methods.remove(expected_method) + getattr(testplan, expected_method).assert_called_once() + for method in methods: + getattr(testplan, method).assert_not_called() + + +TESTDATA_7 = [ + ( + [ + mock.Mock( + yamlfile='a.yaml', + scenarios=['scenario1', 'scenario2'] + ), + mock.Mock( + yamlfile='b.yaml', + scenarios=['scenario1'] + ) + ], + TwisterRuntimeError, + 'Duplicated test scenarios found:\n' \ + '- scenario1 found in:\n' \ + ' - a.yaml\n' \ + ' - b.yaml\n', + [] + ), + ( + [ + mock.Mock( + yamlfile='a.yaml', + scenarios=['scenario.a.1', 'scenario.a.2'] + ), + mock.Mock( + yamlfile='b.yaml', + scenarios=['scenario.b.1'] + ) + ], + None, + None, + ['No duplicates found.'] + ), +] + +@pytest.mark.parametrize( + 'testsuites, expected_error, error_msg, expected_logs', + TESTDATA_7, + ids=['a duplicate', 'no duplicates'] +) +def test_testplan_report_duplicates( + capfd, + caplog, + testsuites, + expected_error, + error_msg, + expected_logs +): + def mock_get(name): + return list(filter(lambda x: name in x.scenarios, testsuites)) + + testplan = TestPlan(env=mock.Mock()) + testplan.scenarios = [scenario for testsuite in testsuites \ + for scenario in testsuite.scenarios] + testplan.get_testsuite = mock.Mock(side_effect=mock_get) + + with pytest.raises(expected_error) if expected_error is not None else \ + nullcontext() as err: + testplan.report_duplicates() + + if expected_error: + assert str(err._excinfo[1]) == error_msg + + assert all([log in caplog.text for log in expected_logs]) + + +def test_testplan_report_tag_list(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.testsuites = { + 'testsuite0': mock.Mock(tags=set(['tag1', 'tag2'])), + 'testsuite1': mock.Mock(tags=set(['tag1', 'tag2', 'tag3'])), + 'testsuite2': mock.Mock(tags=set(['tag1', 'tag3'])), + 'testsuite3': mock.Mock(tags=set(['tag'])) + } + + testplan.report_tag_list() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert '- tag' in out + assert '- tag1' in out + assert '- tag2' in out + assert '- tag3' in out + + +def test_testplan_report_test_tree(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.get_all_tests = mock.Mock( + return_value=['1.dummy.case.1', '1.dummy.case.2', + '2.dummy.case.1', '2.dummy.case.2', + '3.dummy.case.1', '3.dummy.case.2', + '4.dummy.case.1', '4.dummy.case.2', + '5.dummy.case.1', '5.dummy.case.2', + 'sample.group1.case1', 'sample.group1.case2', + 'sample.group2.case', 'sample.group3.case1', + 'sample.group3.case2', 'sample.group3.case3'] + ) + + testplan.report_test_tree() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + expected = """ +Testsuite +├── Samples +│ ├── group1 +│ │ ├── sample.group1.case1 +│ │ └── sample.group1.case2 +│ ├── group2 +│ │ └── sample.group2.case +│ └── group3 +│ ├── sample.group3.case1 +│ ├── sample.group3.case2 +│ └── sample.group3.case3 +└── Tests + ├── 1 + │ └── dummy + │ ├── 1.dummy.case.1 + │ └── 1.dummy.case.2 + ├── 2 + │ └── dummy + │ ├── 2.dummy.case.1 + │ └── 2.dummy.case.2 + ├── 3 + │ └── dummy + │ ├── 3.dummy.case.1 + │ └── 3.dummy.case.2 + ├── 4 + │ └── dummy + │ ├── 4.dummy.case.1 + │ └── 4.dummy.case.2 + └── 5 + └── dummy + ├── 5.dummy.case.1 + └── 5.dummy.case.2 +""" + expected = expected[1:] + + assert expected in out + + +def test_testplan_report_test_list(capfd): + testplan = TestPlan(env=mock.Mock()) + testplan.get_all_tests = mock.Mock( + return_value=['4.dummy.case.1', '4.dummy.case.2', + '3.dummy.case.2', '2.dummy.case.2', + '1.dummy.case.1', '1.dummy.case.2', + '3.dummy.case.1', '2.dummy.case.1', + '5.dummy.case.1', '5.dummy.case.2'] + ) + + testplan.report_test_list() + + out,err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert ' - 1.dummy.case.1\n' \ + ' - 1.dummy.case.2\n' \ + ' - 2.dummy.case.1\n' \ + ' - 2.dummy.case.2\n' \ + ' - 3.dummy.case.1\n' \ + ' - 3.dummy.case.2\n' \ + ' - 4.dummy.case.1\n' \ + ' - 4.dummy.case.2\n' \ + ' - 5.dummy.case.1\n' \ + ' - 5.dummy.case.2\n' \ + '10 total.' in out + + +def test_testplan_config(caplog): + testplan = TestPlan(env=mock.Mock()) + testplan.coverage_platform = 'dummy cov' + + testplan.config() + + assert 'coverage platform: dummy cov' in caplog.text + + +def test_testplan_info(capfd): + TestPlan.info('dummy text') + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert 'dummy text\n' in out + + +TESTDATA_8 = [ + (False, False, ['p1e2', 'p2', 'p3', 'p3@B'], ['p2']), + (False, True, None, None), + (True, False, ['p1e2', 'p2', 'p3', 'p3@B'], ['p3']), +] + +@pytest.mark.parametrize( + 'override_default_platforms, create_duplicate, expected_platform_names, expected_defaults', + TESTDATA_8, + ids=['no override defaults', 'create duplicate', 'override defaults'] +) +def test_testplan_add_configurations( + tmp_path, + override_default_platforms, + create_duplicate, + expected_platform_names, + expected_defaults +): + # tmp_path + # └ boards <- board root + # ├ arch1 + # │ ├ p1 + # │ | ├ p1e1.yaml + # │ | └ p1e2.yaml + # │ └ p2 + # │ ├ p2.yaml + # │ └ p2-1.yaml <- duplicate + # │ └ p2-2.yaml <- load error + # └ arch2 + # └ p3 + # ├ p3.yaml + # └ p3_B.conf + + tmp_board_root_dir = tmp_path / 'boards' + tmp_board_root_dir.mkdir() + + tmp_arch1_dir = tmp_board_root_dir / 'arch1' + tmp_arch1_dir.mkdir() + + tmp_p1_dir = tmp_arch1_dir / 'p1' + tmp_p1_dir.mkdir() + + p1e1_yaml = """\ +identifier: p1e1 +name: Platform 1 Edition 1 +type: native +arch: arch1 +vendor: vendor1 +toolchain: + - zephyr +twister: False +""" + p1e1_yamlfile = tmp_p1_dir / 'p1e1.yaml' + p1e1_yamlfile.write_text(p1e1_yaml) + + p1e2_yaml = """\ +identifier: p1e2 +name: Platform 1 Edition 2 +type: native +arch: arch1 +vendor: vendor1 +toolchain: + - zephyr +""" + p1e2_yamlfile = tmp_p1_dir / 'p1e2.yaml' + p1e2_yamlfile.write_text(p1e2_yaml) + + tmp_p2_dir = tmp_arch1_dir / 'p2' + tmp_p2_dir.mkdir() + + p2_yaml = """\ +identifier: p2 +name: Platform 2 +type: sim +arch: arch1 +vendor: vendor2 +toolchain: + - zephyr +testing: + default: True +""" + p2_yamlfile = tmp_p2_dir / 'p2.yaml' + p2_yamlfile.write_text(p2_yaml) + + if create_duplicate: + p2_yamlfile = tmp_p2_dir / 'p2-1.yaml' + p2_yamlfile.write_text(p2_yaml) + + p2_2_yaml = """\ +testing: + ć#@%!#!#^#@%@:1.0 +identifier: p2_2 +name: Platform 2 2 +type: sim +arch: arch1 +vendor: vendor2 +toolchain: + - zephyr +""" + p2_2_yamlfile = tmp_p2_dir / 'p2-2.yaml' + p2_2_yamlfile.write_text(p2_2_yaml) + + tmp_arch2_dir = tmp_board_root_dir / 'arch2' + tmp_arch2_dir.mkdir() + + tmp_p3_dir = tmp_arch2_dir / 'p3' + tmp_p3_dir.mkdir() + + p3_yaml = """\ +identifier: p3 +name: Platform 3 +type: unit +arch: arch2 +vendor: vendor3 +toolchain: + - zephyr +""" + p3_yamlfile = tmp_p3_dir / 'p3.yaml' + p3_yamlfile.write_text(p3_yaml) + p3_yamlfile = tmp_p3_dir / 'p3_B.conf' + p3_yamlfile.write_text('') + + env = mock.Mock(board_roots=[tmp_board_root_dir]) + + testplan = TestPlan(env=env) + + testplan.test_config = { + 'platforms': { + 'override_default_platforms': override_default_platforms, + 'default_platforms': ['p3', 'p1e1'] + } + } + + with pytest.raises(Exception) if create_duplicate else nullcontext(): + testplan.add_configurations() + + if expected_defaults is not None: + assert sorted(expected_defaults) == sorted(testplan.default_platforms) + if expected_platform_names is not None: + assert sorted(expected_platform_names) == sorted(testplan.platform_names) + + +def test_testplan_get_all_tests(): + testplan = TestPlan(env=mock.Mock()) + tc1 = mock.Mock() + tc1.name = 'tc1' + tc2 = mock.Mock() + tc2.name = 'tc2' + tc3 = mock.Mock() + tc3.name = 'tc3' + tc4 = mock.Mock() + tc4.name = 'tc4' + tc5 = mock.Mock() + tc5.name = 'tc5' + ts1 = mock.Mock(testcases=[tc1, tc2]) + ts2 = mock.Mock(testcases=[tc3, tc4, tc5]) + testplan.testsuites = { + 'ts1': ts1, + 'ts2': ts2 + } + + res = testplan.get_all_tests() + + assert sorted(res) == ['tc1', 'tc2', 'tc3', 'tc4', 'tc5'] + + +TESTDATA_9 = [ + ([], False, 7), + ([], True, 5), + (['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], False, 3), + (['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], True, 0), +] + +@pytest.mark.parametrize( + 'testsuite_filter, use_alt_root, expected_suite_count', + TESTDATA_9, + ids=['no testsuite filter', 'no testsuite filter, alt root', + 'testsuite filter', 'testsuite filter, alt root'] +) +def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expected_suite_count): + # tmp_path + # ├ tests <- test root + # │ ├ good_test + # │ │ └ testcase.yaml + # │ ├ wrong_test + # │ │ └ testcase.yaml + # │ ├ good_sample + # │ │ └ sample.yaml + # │ └ others + # │ └ other.txt + # └ other_tests <- alternate test root + # └ good_test + # └ testcase.yaml + tmp_test_root_dir = tmp_path / 'tests' + tmp_test_root_dir.mkdir() + + tmp_good_test_dir = tmp_test_root_dir / 'good_test' + tmp_good_test_dir.mkdir() + testcase_yaml_1 = """\ +tests: + dummy.common.1: + build_on_all: true + dummy.common.2: + build_on_all: true + dummy.common.3: + build_on_all: true + dummy.special: + build_on_all: false +""" + testfile_1 = tmp_good_test_dir / 'testcase.yaml' + testfile_1.write_text(testcase_yaml_1) + + tmp_bad_test_dir = tmp_test_root_dir / 'wrong_test' + tmp_bad_test_dir.mkdir() + testcase_yaml_2 = """\ +tests: + wrong: + yaml: {]} +""" + testfile_2 = tmp_bad_test_dir / 'testcase.yaml' + testfile_2.write_text(testcase_yaml_2) + + tmp_good_sample_dir = tmp_test_root_dir / 'good_sample' + tmp_good_sample_dir.mkdir() + samplecase_yaml_1 = """\ +tests: + sample.dummy.common.1: + tags: + - samples + sample.dummy.common.2: + tags: + - samples + sample.dummy.special.1: + tags: + - samples +""" + samplefile_1 = tmp_good_sample_dir / 'sample.yaml' + samplefile_1.write_text(samplecase_yaml_1) + + tmp_other_dir = tmp_test_root_dir / 'others' + tmp_other_dir.mkdir() + _ = tmp_other_dir / 'other.txt' + + tmp_alt_test_root_dir = tmp_path / 'other_tests' + tmp_alt_test_root_dir.mkdir() + + tmp_alt_good_test_dir = tmp_alt_test_root_dir / 'good_test' + tmp_alt_good_test_dir.mkdir() + testcase_yaml_3 = """\ +tests: + dummy.alt.1: + build_on_all: true + dummy.alt.2: + build_on_all: true +""" + testfile_3 = tmp_alt_good_test_dir / 'testcase.yaml' + testfile_3.write_text(testcase_yaml_3) + + env = mock.Mock( + test_roots=[tmp_test_root_dir], + alt_config_root=[tmp_alt_test_root_dir] if use_alt_root else [] + ) + + testplan = TestPlan(env=env) + + res = testplan.add_testsuites(testsuite_filter) + + assert res == expected_suite_count + + +def test_testplan_str(): + testplan = TestPlan(env=mock.Mock()) + testplan.name = 'my name' + + res = testplan.__str__() + + assert res == 'my name' + + +TESTDATA_10 = [ + ('a platform', True), + ('other platform', False), +] + +@pytest.mark.parametrize( + 'name, expect_found', + TESTDATA_10, + ids=['platform exists', 'no platform'] +) +def test_testplan_get_platform(name, expect_found): + testplan = TestPlan(env=mock.Mock()) + p1 = mock.Mock() + p1.name = 'some platform' + p2 = mock.Mock() + p2.name = 'a platform' + testplan.platforms = [p1, p2] + + res = testplan.get_platform(name) + + if expect_found: + assert res.name == name + else: + assert res is None + + +TESTDATA_11 = [ + (True, 'runnable'), + (False, 'buildable'), +] + +@pytest.mark.parametrize( + 'device_testing, expected_tfilter', + TESTDATA_11, + ids=['device testing', 'no device testing'] +) +def test_testplan_load_from_file(caplog, device_testing, expected_tfilter): + def get_platform(name): + p = mock.Mock() + p.name = name + return p + + ts1tc1 = mock.Mock() + ts1tc1.name = 'TS1.tc1' + ts1 = mock.Mock(testcases=[ts1tc1]) + ts1.name = 'TestSuite 1' + ts2 = mock.Mock(testcases=[]) + ts2.name = 'TestSuite 2' + ts3tc1 = mock.Mock() + ts3tc1.name = 'TS3.tc1' + ts3tc2 = mock.Mock() + ts3tc2.name = 'TS3.tc2' + ts3 = mock.Mock(testcases=[ts3tc1, ts3tc2]) + ts3.name = 'TestSuite 3' + ts4tc1 = mock.Mock() + ts4tc1.name = 'TS4.tc1' + ts4 = mock.Mock(testcases=[ts4tc1]) + ts4.name = 'TestSuite 4' + ts5 = mock.Mock(testcases=[]) + ts5.name = 'TestSuite 5' + + testplan = TestPlan(env=mock.Mock(outdir=os.path.join('out', 'dir'))) + testplan.options = mock.Mock(device_testing=device_testing, test_only=True) + testplan.testsuites = { + 'TestSuite 1': ts1, + 'TestSuite 2': ts2, + 'TestSuite 3': ts3, + 'TestSuite 4': ts4, + 'TestSuite 5': ts5 + } + + testplan.get_platform = mock.Mock(side_effect=get_platform) + + testplan_data = """\ +{ + "testsuites": [ + { + "name": "TestSuite 1", + "platform": "Platform 1", + "run_id": 1, + "execution_time": 60.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "passed", + "reason": "OK", + "testcases": [ + { + "identifier": "TS1.tc1", + "status": "passed", + "reason": "passed", + "execution_time": 60.00, + "log": "" + } + ] + }, + { + "name": "TestSuite 2", + "platform": "Platform 1" + }, + { + "name": "TestSuite 3", + "platform": "Platform 1", + "run_id": 1, + "execution_time": 360.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "error", + "reason": "File Not Found Error", + "testcases": [ + { + "identifier": "TS3.tc1", + "status": "error", + "reason": "File Not Found Error.", + "execution_time": 360.00, + "log": "[ERROR]: File 'dummy.yaml' not found!\\nClosing..." + }, + { + "identifier": "TS3.tc2" + } + ] + }, + { + "name": "TestSuite 4", + "platform": "Platform 1", + "execution_time": 360.00, + "used_ram": 4096, + "available_ram": 12278, + "used_rom": 1024, + "available_rom": 1047552, + "status": "skipped", + "reason": "Not in requested test list.", + "testcases": [ + { + "identifier": "TS4.tc1", + "status": "skipped", + "reason": "Not in requested test list.", + "execution_time": 360.00, + "log": "[INFO] Parsing..." + }, + { + "identifier": "TS3.tc2" + } + ] + }, + { + "name": "TestSuite 5", + "platform": "Platform 2" + } + ] +} +""" + + filter_platform = ['Platform 1'] + + check_runnable_mock = mock.Mock(return_value=True) + + with mock.patch('builtins.open', mock.mock_open(read_data=testplan_data)), \ + mock.patch('twisterlib.testinstance.TestInstance.check_runnable', check_runnable_mock), \ + mock.patch('twisterlib.testinstance.TestInstance.create_overlay', mock.Mock()): + testplan.load_from_file('dummy.yaml', filter_platform) + + expected_instances = { + 'Platform 1/TestSuite 1': { + 'metrics': { + 'handler_time': 60.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 0, + 'testcases': { + 'TS1.tc1': { + 'status': 'passed', + 'reason': None, + 'duration': 60.0, + 'output': '' + } + } + }, + 'Platform 1/TestSuite 2': { + 'metrics': { + 'handler_time': 0, + 'used_ram': 0, + 'used_rom': 0, + 'available_ram': 0, + 'available_rom': 0 + }, + 'retries': 0, + 'testcases': [] + }, + 'Platform 1/TestSuite 3': { + 'metrics': { + 'handler_time': 360.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 1, + 'testcases': { + 'TS3.tc1': { + 'status': 'error', + 'reason': None, + 'duration': 360.0, + 'output': '[ERROR]: File \'dummy.yaml\' not found!\nClosing...' + }, + 'TS3.tc2': { + 'status': None, + 'reason': None, + 'duration': 0, + 'output': '' + } + } + }, + 'Platform 1/TestSuite 4': { + 'metrics': { + 'handler_time': 360.0, + 'used_ram': 4096, + 'used_rom': 1024, + 'available_ram': 12278, + 'available_rom': 1047552 + }, + 'retries': 0, + 'testcases': { + 'TS4.tc1': { + 'status': 'skipped', + 'reason': 'Not in requested test list.', + 'duration': 360.0, + 'output': '[INFO] Parsing...' + } + } + }, + } + + for n, i in testplan.instances.items(): + assert expected_instances[n]['metrics'] == i.metrics + assert expected_instances[n]['retries'] == i.retries + for t in i.testcases: + assert expected_instances[n]['testcases'][str(t)]['status'] == t.status + assert expected_instances[n]['testcases'][str(t)]['reason'] == t.reason + assert expected_instances[n]['testcases'][str(t)]['duration'] == t.duration + assert expected_instances[n]['testcases'][str(t)]['output'] == t.output + + check_runnable_mock.assert_called_with(mock.ANY, expected_tfilter, mock.ANY, mock.ANY) + + expected_logs = [ + 'loading TestSuite 1...', + 'loading TestSuite 2...', + 'loading TestSuite 3...', + 'loading TestSuite 4...', + ] + assert all([log in caplog.text for log in expected_logs]) + + +def test_testplan_add_instances(): + testplan = TestPlan(env=mock.Mock()) + instance1 = mock.Mock() + instance1.name = 'instance 1' + instance2 = mock.Mock() + instance2.name = 'instance 2' + instance_list = [instance1, instance2] + + testplan.add_instances(instance_list) + + assert testplan.instances == { + 'instance 1': instance1, + 'instance 2': instance2, + } + + +def test_testplan_get_testsuite(): + testplan = TestPlan(env=mock.Mock()) + testplan.testsuites = { + 'testsuite0': mock.Mock(testcases=[mock.Mock(), mock.Mock()]), + 'testsuite1': mock.Mock(testcases=[mock.Mock()]), + 'testsuite2': mock.Mock(testcases=[mock.Mock(), mock.Mock()]), + 'testsuite3': mock.Mock(testcases=[]) + } + testplan.testsuites['testsuite0'].testcases[0].name = 'testcase name 0' + testplan.testsuites['testsuite0'].testcases[1].name = 'testcase name 1' + testplan.testsuites['testsuite1'].testcases[0].name = 'sample id' + testplan.testsuites['testsuite2'].testcases[0].name = 'dummy id' + testplan.testsuites['testsuite2'].testcases[1].name = 'sample id' + + id = 'sample id' + + res = testplan.get_testsuite(id) + + assert len(res) == 2 + assert testplan.testsuites['testsuite1'] in res + assert testplan.testsuites['testsuite2'] in res + + +def test_testplan_verify_platforms_existence(caplog): + testplan = TestPlan(env=mock.Mock()) + testplan.platform_names = ['a platform', 'other platform'] + + platform_names = ['other platform', 'some platform'] + log_info = 'PLATFORM ERROR' + + with pytest.raises(SystemExit) as se: + testplan.verify_platforms_existence(platform_names, log_info) + + assert str(se.value) == '2' + assert 'PLATFORM ERROR - unrecognized platform - some platform' + + +TESTDATA_12 = [ + (True), + (False) +] + +@pytest.mark.parametrize( + 'exists', + TESTDATA_12, + ids=['links dir exists', 'links dir does not exist'] +) +def test_testplan_create_build_dir_links(exists): + outdir = os.path.join('out', 'dir') + instances_linked = [] + + def mock_link(links_dir_path, instance): + assert links_dir_path == os.path.join(outdir, 'twister_links') + instances_linked.append(instance) + + instances = { + 'inst0': mock.Mock(status='passed'), + 'inst1': mock.Mock(status='skipped'), + 'inst2': mock.Mock(status='error'), + } + expected_instances = [instances['inst0'], instances['inst2']] + + testplan = TestPlan(env=mock.Mock(outdir=outdir)) + testplan._create_build_dir_link = mock.Mock(side_effect=mock_link) + testplan.instances = instances + + with mock.patch('os.path.exists', return_value=exists), \ + mock.patch('os.mkdir', mock.Mock()) as mkdir_mock: + testplan.create_build_dir_links() + + if not exists: + mkdir_mock.assert_called_once() + + assert expected_instances == instances_linked + + +TESTDATA_13 = [ + ('nt'), + ('Linux') +] + +@pytest.mark.parametrize( + 'os_name', + TESTDATA_13, +) +def test_testplan_create_build_dir_link(os_name): + def mock_makedirs(path, exist_ok=False): + assert exist_ok + assert path == instance_build_dir + + def mock_symlink(source, target): + assert source == instance_build_dir + assert target == os.path.join('links', 'path', 'test_0') + + def mock_call(cmd, shell=False): + assert shell + assert cmd == ['mklink', '/J', os.path.join('links', 'path', 'test_0'), + instance_build_dir] + + def mock_join(*paths): + slash = "\\" if os.name == 'nt' else "/" + return slash.join(paths) + + with mock.patch('os.name', os_name), \ + mock.patch('os.symlink', side_effect=mock_symlink), \ + mock.patch('os.makedirs', side_effect=mock_makedirs), \ + mock.patch('subprocess.call', side_effect=mock_call), \ + mock.patch('os.path.join', side_effect=mock_join): + + testplan = TestPlan(env=mock.Mock()) + links_dir_path = os.path.join('links', 'path') + instance_build_dir = os.path.join('some', 'far', 'off', 'build', 'dir') + instance = mock.Mock(build_dir=instance_build_dir) + testplan._create_build_dir_link(links_dir_path, instance) + + assert instance.build_dir == os.path.join('links', 'path', 'test_0') + assert testplan.link_dir_counter == 1 + + +TESTDATA_14 = [ + ('bad platform', 'dummy reason', [], + 'dummy status', 'dummy reason'), + ('good platform', 'quarantined', [], + 'error', 'quarantined but is one of the integration platforms'), + ('good platform', 'dummy reason', [{'type': 'command line filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Skip filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'platform key filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Toolchain filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'Module filter'}], + 'dummy status', 'dummy reason'), + ('good platform', 'dummy reason', [{'type': 'testsuite filter'}], + 'error', 'dummy reason but is one of the integration platforms'), +] + +@pytest.mark.parametrize( + 'platform_name, reason, filters,' \ + ' expected_status, expected_reason', + TESTDATA_14, + ids=['wrong platform', 'quarantined', 'command line filtered', + 'skip filtered', 'platform key filtered', 'toolchain filtered', + 'module filtered', 'skip to error change'] +) +def test_change_skip_to_error_if_integration( + platform_name, + reason, + filters, + expected_status, + expected_reason +): + options = mock.Mock() + platform = mock.Mock() + platform.name = platform_name + testsuite = mock.Mock(integration_platforms=['good platform', 'a platform']) + instance = mock.Mock( + testsuite=testsuite, + platform=platform, + filters=filters, + status='dummy status', + reason=reason + ) + + change_skip_to_error_if_integration(options, instance) + + assert instance.status == expected_status + assert instance.reason == expected_reason diff --git a/scripts/tests/twister/test_testplan_class.py b/scripts/tests/twister/test_testplan_class.py deleted file mode 100644 index f825bc82710..00000000000 --- a/scripts/tests/twister/test_testplan_class.py +++ /dev/null @@ -1,407 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2020 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 - -''' -This test file contains testsuites for Testsuite class of twister -''' -import sys -import os -import pytest - -ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") -sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) - -from twisterlib.testplan import TestPlan -from twisterlib.testinstance import TestInstance -from twisterlib.testsuite import TestSuite -from twisterlib.platform import Platform -from twisterlib.quarantine import Quarantine - - -def test_testplan_add_testsuites(class_testplan): - """ Testing add_testcase function of Testsuite class in twister """ - # Test 1: Check the list of testsuites after calling add testsuites function is as expected - class_testplan.SAMPLE_FILENAME = 'test_sample_app.yaml' - class_testplan.TESTSUITE_FILENAME = 'test_data.yaml' - class_testplan.add_testsuites() - - tests_rel_dir = 'scripts/tests/twister/test_data/testsuites/tests/' - expected_testsuites = ['test_b.check_1', - 'test_b.check_2', - 'test_c.check_1', - 'test_c.check_2', - 'test_a.check_1', - 'test_a.check_2', - 'test_d.check_1', - 'test_e.check_1', - 'sample_test.app', - 'test_config.main'] - testsuite_list = [] - for key in sorted(class_testplan.testsuites.keys()): - testsuite_list.append(os.path.basename(os.path.normpath(key))) - assert sorted(testsuite_list) == sorted(expected_testsuites) - - # Test 2 : Assert Testcase name is expected & all testsuites values are testcase class objects - suite = class_testplan.testsuites.get(tests_rel_dir + 'test_a/test_a.check_1') - assert suite.name == tests_rel_dir + 'test_a/test_a.check_1' - assert all(isinstance(n, TestSuite) for n in class_testplan.testsuites.values()) - -@pytest.mark.parametrize("board_root_dir", [("board_config_file_not_exist"), ("board_config")]) -def test_add_configurations(test_data, class_env, board_root_dir): - """ Testing add_configurations function of TestPlan class in Twister - Test : Asserting on default platforms list - """ - class_env.board_roots = [os.path.abspath(test_data + board_root_dir)] - plan = TestPlan(class_env) - plan.parse_configuration(config_file=class_env.test_config) - if board_root_dir == "board_config": - plan.add_configurations() - assert sorted(plan.default_platforms) == sorted(['demo_board_1', 'demo_board_3']) - elif board_root_dir == "board_config_file_not_exist": - plan.add_configurations() - assert sorted(plan.default_platforms) != sorted(['demo_board_1']) - - -def test_get_all_testsuites(class_testplan, all_testsuites_dict): - """ Testing get_all_testsuites function of TestPlan class in Twister """ - plan = class_testplan - plan.testsuites = all_testsuites_dict - expected_tests = ['sample_test.app', 'test_a.check_1.1a', - 'test_a.check_1.1c', - 'test_a.check_1.2a', 'test_a.check_1.2b', - 'test_a.check_1.Unit_1c', 'test_a.check_1.unit_1a', - 'test_a.check_1.unit_1b', 'test_a.check_2.1a', - 'test_a.check_2.1c', 'test_a.check_2.2a', - 'test_a.check_2.2b', 'test_a.check_2.Unit_1c', - 'test_a.check_2.unit_1a', 'test_a.check_2.unit_1b', - 'test_b.check_1', 'test_b.check_2', 'test_c.check_1', - 'test_c.check_2', 'test_d.check_1.unit_1a', - 'test_d.check_1.unit_1b', - 'test_e.check_1.1a', 'test_e.check_1.1b', - 'test_config.main'] - print(sorted(plan.get_all_tests())) - print(sorted(expected_tests)) - assert sorted(plan.get_all_tests()) == sorted(expected_tests) - -def test_get_platforms(class_testplan, platforms_list): - """ Testing get_platforms function of TestPlan class in Twister """ - plan = class_testplan - plan.platforms = platforms_list - platform = plan.get_platform("demo_board_1") - assert isinstance(platform, Platform) - assert platform.name == "demo_board_1" - -TESTDATA_PART1 = [ - ("toolchain_allow", ['gcc'], None, None, "Not in testsuite toolchain allow list"), - ("platform_allow", ['demo_board_1'], None, None, "Not in testsuite platform allow list"), - ("toolchain_exclude", ['zephyr'], None, None, "In test case toolchain exclude"), - ("platform_exclude", ['demo_board_2'], None, None, "In test case platform exclude"), - ("arch_exclude", ['x86_demo'], None, None, "In test case arch exclude"), - ("arch_allow", ['arm'], None, None, "Not in test case arch allow list"), - ("skip", True, None, None, "Skip filter"), - ("tags", set(['sensor', 'bluetooth']), "ignore_tags", ['bluetooth'], "Excluded tags per platform (exclude_tags)"), - ("min_flash", "2024", "flash", "1024", "Not enough FLASH"), - ("min_ram", "500", "ram", "256", "Not enough RAM"), - ("None", "None", "env", ['BSIM_OUT_PATH', 'demo_env'], "Environment (BSIM_OUT_PATH, demo_env) not satisfied"), - ("build_on_all", True, None, None, "Platform is excluded on command line."), - (None, None, "supported_toolchains", ['gcc'], "Not supported by the toolchain"), -] - - -@pytest.mark.parametrize("tc_attribute, tc_value, plat_attribute, plat_value, expected_discards", - TESTDATA_PART1) -def test_apply_filters_part1(class_testplan, all_testsuites_dict, platforms_list, - tc_attribute, tc_value, plat_attribute, plat_value, expected_discards): - """ Testing apply_filters function of TestPlan class in Twister - Part 1: Response of apply_filters function have - appropriate values according to the filters - """ - plan = class_testplan - if tc_attribute is None and plat_attribute is None: - plan.apply_filters() - - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = all_testsuites_dict - for plat in plan.platforms: - if plat_attribute == "ignore_tags": - plat.ignore_tags = plat_value - if plat_attribute == "flash": - plat.flash = plat_value - if plat_attribute == "ram": - plat.ram = plat_value - if plat_attribute == "env": - plat.env = plat_value - plat.env_satisfied = False - if plat_attribute == "supported_toolchains": - plat.supported_toolchains = plat_value - for _, testcase in plan.testsuites.items(): - if tc_attribute == "toolchain_allow": - testcase.toolchain_allow = tc_value - if tc_attribute == "platform_allow": - testcase.platform_allow = tc_value - if tc_attribute == "toolchain_exclude": - testcase.toolchain_exclude = tc_value - if tc_attribute == "platform_exclude": - testcase.platform_exclude = tc_value - if tc_attribute == "arch_exclude": - testcase.arch_exclude = tc_value - if tc_attribute == "arch_allow": - testcase.arch_allow = tc_value - if tc_attribute == "skip": - testcase.skip = tc_value - if tc_attribute == "tags": - testcase.tags = tc_value - if tc_attribute == "min_flash": - testcase.min_flash = tc_value - if tc_attribute == "min_ram": - testcase.min_ram = tc_value - - if tc_attribute == "build_on_all": - for _, testcase in plan.testsuites.items(): - testcase.build_on_all = tc_value - plan.apply_filters(exclude_platform=['demo_board_1']) - elif plat_attribute == "supported_toolchains": - plan.apply_filters(force_toolchain=False, - exclude_platform=['demo_board_1'], - platform=['demo_board_2']) - elif tc_attribute is None and plat_attribute is None: - plan.apply_filters() - else: - plan.apply_filters(exclude_platform=['demo_board_1'], - platform=['demo_board_2']) - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - for d in filtered_instances: - assert d.reason == expected_discards - -TESTDATA_PART2 = [ - ("runnable", "True", "Not runnable on device"), - ("exclude_tag", ['test_a'], "Command line testsuite exclude filter"), - ("run_individual_tests", ['scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1'], "TestSuite name filter"), - ("arch", ['arm_test'], "Command line testsuite arch filter"), - ("tag", ['test_d'], "Command line testsuite tag filter") - ] - - -@pytest.mark.parametrize("extra_filter, extra_filter_value, expected_discards", TESTDATA_PART2) -def test_apply_filters_part2(class_testplan, all_testsuites_dict, - platforms_list, extra_filter, extra_filter_value, expected_discards): - """ Testing apply_filters function of TestPlan class in Twister - Part 2 : Response of apply_filters function (discard dictionary) have - appropriate values according to the filters - """ - - class_testplan.platforms = platforms_list - class_testplan.platform_names = [p.name for p in platforms_list] - class_testplan.testsuites = all_testsuites_dict - kwargs = { - extra_filter : extra_filter_value, - "exclude_platform" : [ - 'demo_board_1' - ], - "platform" : [ - 'demo_board_2' - ] - } - class_testplan.apply_filters(**kwargs) - filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) - for d in filtered_instances: - assert d.reason == expected_discards - - -TESTDATA_PART3 = [ - (20, 20, -1, 0), - (-2, -1, 10, 20), - (0, 0, 0, 0) - ] - -@pytest.mark.parametrize("tc_min_flash, plat_flash, tc_min_ram, plat_ram", - TESTDATA_PART3) -def test_apply_filters_part3(class_testplan, all_testsuites_dict, platforms_list, - tc_min_flash, plat_flash, tc_min_ram, plat_ram): - """ Testing apply_filters function of TestPlan class in Twister - Part 3 : Testing edge cases for ram and flash values of platforms & testsuites - """ - class_testplan.platforms = platforms_list - class_testplan.platform_names = [p.name for p in platforms_list] - class_testplan.testsuites = all_testsuites_dict - - for plat in class_testplan.platforms: - plat.flash = plat_flash - plat.ram = plat_ram - for _, testcase in class_testplan.testsuites.items(): - testcase.min_ram = tc_min_ram - testcase.min_flash = tc_min_flash - class_testplan.apply_filters(exclude_platform=['demo_board_1'], - platform=['demo_board_2']) - - filtered_instances = list(filter(lambda item: item.status == "filtered", class_testplan.instances.values())) - assert not filtered_instances - -def test_add_instances(test_data, class_env, all_testsuites_dict, platforms_list): - """ Testing add_instances() function of TestPlan class in Twister - Test 1: instances dictionary keys have expected values (Platform Name + Testcase Name) - Test 2: Values of 'instances' dictionary in Testsuite class are an - instance of 'TestInstance' class - Test 3: Values of 'instances' dictionary have expected values. - """ - class_env.outdir = test_data - plan = TestPlan(class_env) - plan.platforms = platforms_list - platform = plan.get_platform("demo_board_2") - instance_list = [] - for _, testcase in all_testsuites_dict.items(): - instance = TestInstance(testcase, platform, class_env.outdir) - instance_list.append(instance) - plan.add_instances(instance_list) - assert list(plan.instances.keys()) == \ - [platform.name + '/' + s for s in list(all_testsuites_dict.keys())] - assert all(isinstance(n, TestInstance) for n in list(plan.instances.values())) - assert list(plan.instances.values()) == instance_list - - -QUARANTINE_BASIC = { - 'demo_board_1/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'a1 on board_1 and board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'a1 on board_1 and board_3' -} - -QUARANTINE_WITH_REGEXP = { - 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_2' : 'a2 and c2 on x86', - 'demo_board_1/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', - 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all test_d', - 'demo_board_2/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_2' : 'a2 and c2 on x86' -} - -QUARANTINE_PLATFORM = { - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_1' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_a/test_a.check_2' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_b/test_b.check_1' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_b/test_b.check_2' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_2' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_e/test_e.check_1' : 'all on board_3', - 'demo_board_3/scripts/tests/twister/test_data/testsuites/tests/test_config/test_config.main' : 'all on board_3' -} - -QUARANTINE_MULTIFILES = { - **QUARANTINE_BASIC, - **QUARANTINE_WITH_REGEXP -} - -@pytest.mark.parametrize( - ("quarantine_files, quarantine_verify, expected_val"), - [ - (['basic.yaml'], False, QUARANTINE_BASIC), - (['with_regexp.yaml'], False, QUARANTINE_WITH_REGEXP), - (['with_regexp.yaml'], True, QUARANTINE_WITH_REGEXP), - (['platform.yaml'], False, QUARANTINE_PLATFORM), - (['basic.yaml', 'with_regexp.yaml'], False, QUARANTINE_MULTIFILES), - (['empty.yaml'], False, {}) - ], - ids=[ - 'basic', - 'with_regexp', - 'quarantine_verify', - 'platform', - 'multifiles', - 'empty' - ]) -def test_quarantine(class_testplan, platforms_list, test_data, - quarantine_files, quarantine_verify, expected_val): - """ Testing quarantine feature in Twister - """ - class_testplan.options.all = True - class_testplan.platforms = platforms_list - class_testplan.platform_names = [p.name for p in platforms_list] - class_testplan.TESTSUITE_FILENAME = 'test_data.yaml' - class_testplan.add_testsuites() - - quarantine_list = [ - os.path.join(test_data, 'quarantines', quarantine_file) for quarantine_file in quarantine_files - ] - class_testplan.quarantine = Quarantine(quarantine_list) - class_testplan.options.quarantine_verify = quarantine_verify - class_testplan.apply_filters() - - for testname, instance in class_testplan.instances.items(): - if quarantine_verify: - if testname in expected_val: - assert not instance.status - else: - assert instance.status == 'filtered' - assert instance.reason == "Not under quarantine" - else: - print(testname) - if testname in expected_val: - assert instance.status == 'filtered' - assert instance.reason == "Quarantine: " + expected_val[testname] - else: - assert not instance.status - -def test_required_snippets_app(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that app snippets work and are only applied to boards that support the snippet - """ - plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1') - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1': testsuite} - - for _, testcase in plan.testsuites.items(): - testcase.exclude_platform = [] - testcase.required_snippets = ['dummy'] - testcase.build_on_all = True - - plan.apply_filters() - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - for d in filtered_instances: - assert d.reason == "Snippet not supported" - -def test_required_snippets_global(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that global snippets work and application does not fail - """ - plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1') - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_c/test_c.check_1': testsuite} - - for _, testcase in plan.testsuites.items(): - testcase.exclude_platform = [] - testcase.required_snippets = ['cdc-acm-console'] - testcase.build_on_all = True - - plan.apply_filters() - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - assert len(filtered_instances) == 0 - -def test_required_snippets_multiple(class_testplan, all_testsuites_dict, platforms_list): - """ Testing required_snippets function of TestPlan class in Twister - Ensure that multiple snippets can be used and are applied - """ - plan = class_testplan - testsuite = class_testplan.testsuites.get('scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1') - plan.platforms = platforms_list - plan.platform_names = [p.name for p in platforms_list] - plan.testsuites = {'scripts/tests/twister/test_data/testsuites/tests/test_d/test_d.check_1': testsuite} - - for _, testcase in plan.testsuites.items(): - testcase.exclude_platform = [] - testcase.required_snippets = ['dummy', 'cdc-acm-console'] - testcase.build_on_all = True - - plan.apply_filters() - - filtered_instances = list(filter(lambda item: item.status == "filtered", plan.instances.values())) - assert len(filtered_instances) == 2 - for d in filtered_instances: - assert d.reason == "Snippet not supported" diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index f07980a19bc..517af1a79b7 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -6,6 +6,7 @@ '''Common fixtures for use in testing the twister tool.''' import logging +import shutil import mock import os import pytest @@ -22,6 +23,10 @@ testsuite_filename_mock = mock.PropertyMock(return_value='test_data.yaml') +def pytest_configure(config): + config.addinivalue_line("markers", "noclearlog: disable the clear_log autouse fixture") + config.addinivalue_line("markers", "noclearout: disable the provide_out autouse fixture") + @pytest.fixture(name='zephyr_base') def zephyr_base_directory(): return ZEPHYR_BASE @@ -31,8 +36,18 @@ def zephyr_base_directory(): def zephyr_test_directory(): return TEST_DATA -@pytest.fixture -def clear_log(): +@pytest.fixture(autouse=True) +def clear_log(request): + # As this fixture is autouse, one can use the pytest.mark.noclearlog decorator + # in order to be sure that this fixture's code will not fire. + if 'noclearlog' in request.keywords: + return + + # clear_log is used by pytest fixture + # However, clear_log_in_test is prepared to be used directly in the code, wherever required + clear_log_in_test() + +def clear_log_in_test(): # Required to fix the pytest logging error # See: https://github.com/pytest-dev/pytest/issues/5502 loggers = [logging.getLogger()] \ @@ -43,3 +58,28 @@ def clear_log(): handlers = getattr(logger, 'handlers', []) for handler in handlers: logger.removeHandler(handler) + +# This fixture provides blackbox tests with an `out_path` parameter +# It should be used as the `-O` (`--out_dir`) parameter in blackbox tests +# APPRECIATED: method of using this out_path wholly outside of test code +@pytest.fixture(name='out_path', autouse=True) +def provide_out(tmp_path, request): + # As this fixture is autouse, one can use the pytest.mark.noclearout decorator + # in order to be sure that this fixture's code will not fire. + # Most of the time, just omitting the `out_path` parameter is sufficient. + if 'noclearout' in request.keywords: + yield + return + + # Before + out_container_path = tmp_path / 'blackbox-out-container' + out_container_path.mkdir() + out_path = os.path.join(out_container_path, "blackbox-out") + + # Test + yield out_path + + # After + # We're operating in temp, so it is not strictly necessary + # but the files can get large quickly as we do not need them after the test. + shutil.rmtree(out_container_path) diff --git a/scripts/tests/twister_blackbox/test_data/test_config.yaml b/scripts/tests/twister_blackbox/test_data/test_config.yaml new file mode 100644 index 00000000000..d7e4828350c --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/test_config.yaml @@ -0,0 +1,14 @@ +platforms: + override_default_platforms: false + increased_platform_scope: true +levels: + - name: smoke + description: > + A plan to be used verifying basic features + adds: + - dummy.agnostic.* + - name: acceptance + description: > + More coverage + adds: + - dummy.* diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/bc12/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/prj.conf similarity index 100% rename from tests/drivers/bc12/prj.conf rename to scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/prj.conf diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/src/main.c new file mode 100644 index 00000000000..6d3d4c63687 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/src/main.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + zassert_true(1, "1 was false") +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/test_data.yaml new file mode 100644 index 00000000000..af7ba6f7bd7 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_build_error/dummy/test_data.yaml @@ -0,0 +1,8 @@ +tests: + always_fail.dummy: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/sensor/accel/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/prj.conf similarity index 100% rename from tests/drivers/sensor/accel/prj.conf rename to scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/prj.conf diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/src/main.c new file mode 100644 index 00000000000..643b4301550 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/src/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + zassert_true(0, "1 was false"); + zassert_false(1, "0 was true"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/test_data.yaml new file mode 100644 index 00000000000..af7ba6f7bd7 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_fail/dummy/test_data.yaml @@ -0,0 +1,8 @@ +tests: + always_fail.dummy: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/src/main.c new file mode 100644 index 00000000000..3eab5b76c15 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/src/main.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + int i = 0; + + while (true) { + i++; + } +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/test_data.yaml new file mode 100644 index 00000000000..3c758a33b51 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/always_timeout/dummy/test_data.yaml @@ -0,0 +1,10 @@ +common: + timeout: 10 +tests: + always_timeout.dummy: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml index 1e468dc9b97..5bd1d3d4b06 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup1/test_data.yaml @@ -1,11 +1,11 @@ tests: dummy.agnostic.group1.subgroup1: platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: - agnostic - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml index 35f48d68648..9bf2f046885 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group1/subgroup2/test_data.yaml @@ -2,11 +2,11 @@ tests: dummy.agnostic.group1.subgroup2: build_only: true platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: - agnostic - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml index f0aa17acbde..f53a0d29948 100644 --- a/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml +++ b/scripts/tests/twister_blackbox/test_data/tests/dummy/agnostic/group2/test_data.yaml @@ -1,9 +1,9 @@ tests: dummy.agnostic.group2: platform_allow: - - native_posix + - native_sim - qemu_x86 - qemu_x86_64 integration_platforms: - - native_posix + - native_sim tags: agnostic diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/src/main.c new file mode 100644 index 00000000000..3c250486af6 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/src/main.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/test_data.yaml new file mode 100644 index 00000000000..035c275de68 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup1/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_one_pass.agnostic.group1.subgroup1: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/src/main.c new file mode 100644 index 00000000000..d896f500c9e --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/src/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(a1_2_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_2_tests, test_assert) +{ + zassert_true(0, "1 was false"); + zassert_false(1, "0 was true"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/test_data.yaml new file mode 100644 index 00000000000..a07e7e23347 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/one_fail_one_pass/agnostic/group1/subgroup2/test_data.yaml @@ -0,0 +1,11 @@ +tests: + one_fail_one_pass.agnostic.group1.subgroup2: + platform_allow: + - native_posix + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_posix + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/twister-quarantine-list.yml b/scripts/tests/twister_blackbox/test_data/twister-quarantine-list.yml new file mode 100644 index 00000000000..af5d30dddaa --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/twister-quarantine-list.yml @@ -0,0 +1,16 @@ +- scenarios: + - dummy.agnostic.group1.subgroup1 + comment: > + test all platforms + +- platforms: + - frdm_k64f + comment: > + test frdm_k64f + +- scenarios: + - dummy.agnostic.group1.subgroup2 + platforms: + - qemu_x86_64 + comment: > + test qemu_x86_64 diff --git a/scripts/tests/twister_blackbox/test_error.py b/scripts/tests/twister_blackbox/test_error.py new file mode 100644 index 00000000000..85cb726a313 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_error.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions - simple does-error-out or not tests +""" + +import importlib +import mock +import os +import pytest +import sys + +from conftest import ZEPHYR_BASE, TEST_DATA, testsuite_filename_mock +from twisterlib.testplan import TestPlan +from twisterlib.error import TwisterRuntimeError + + +class TestError: + TESTDATA_1 = [ + ( + os.path.join('scripts', 'tests', 'twister_blackbox', 'test_data', 'tests', + 'dummy', 'agnostic', 'group1', 'subgroup1', + 'dummy.agnostic.group1.subgroup1'), + SystemExit + ), + ('dummy.agnostic.group1.subgroup1', TwisterRuntimeError), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.parametrize( + 'test, expected_exception', + TESTDATA_1, + ids=['valid', 'invalid'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_test(self, out_path, test, expected_exception): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--test', test, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(expected_exception) as exc: + self.loader.exec_module(self.twister_module) + + if expected_exception == SystemExit: + assert str(exc.value) == '0' + assert True diff --git a/scripts/tests/twister_blackbox/test_hardwaremap.py b/scripts/tests/twister_blackbox/test_hardwaremap.py index c5dbd990377..c1f6ff1eaf8 100644 --- a/scripts/tests/twister_blackbox/test_hardwaremap.py +++ b/scripts/tests/twister_blackbox/test_hardwaremap.py @@ -5,14 +5,13 @@ """ Blackbox tests for twister's command line functions """ -import logging import importlib import mock import os import pytest import sys -from conftest import ZEPHYR_BASE, testsuite_filename_mock +from conftest import ZEPHYR_BASE, testsuite_filename_mock, clear_log_in_test from twisterlib.testplan import TestPlan sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister/twisterlib")) @@ -105,15 +104,14 @@ def setup_class(cls): def teardown_class(cls): pass - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'runner'), TESTDATA_1, ) - def test_generate(self, capfd, manufacturer, product, serial, runner): + def test_generate(self, capfd, out_path, manufacturer, product, serial, runner): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) @@ -156,24 +154,16 @@ def mocked_comports(): os.remove(path) assert str(sys_exit.value) == '0' - loggers = [logging.getLogger()] + \ - list(logging.Logger.manager.loggerDict.values()) + \ - [logging.getLogger(name) for \ - name in logging.root.manager.loggerDict] - for logger in loggers: - handlers = getattr(logger, 'handlers', []) - for handler in handlers: - logger.removeHandler(handler) - - @pytest.mark.usefixtures("clear_log") + clear_log_in_test() + @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'runner'), TESTDATA_2, ) - def test_few_generate(self, capfd, manufacturer, product, serial, runner): + def test_few_generate(self, capfd, out_path, manufacturer, product, serial, runner): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) @@ -247,15 +237,14 @@ def mocked_comports(): assert str(sys_exit.value) == '0' - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( ('manufacturer', 'product', 'serial', 'location'), TESTDATA_3, ) - def test_texas_exeption(self, capfd, manufacturer, product, serial, location): + def test_texas_exeption(self, capfd, out_path, manufacturer, product, serial, location): file_name = "test-map.yaml" path = os.path.join(ZEPHYR_BASE, file_name) - args = ['--generate-hardware-map', file_name] + args = ['--outdir', out_path, '--generate-hardware-map', file_name] if os.path.exists(path): os.remove(path) diff --git a/scripts/tests/twister_blackbox/test_printouts.py b/scripts/tests/twister_blackbox/test_printouts.py index 333bf2a090a..a548137595b 100644 --- a/scripts/tests/twister_blackbox/test_printouts.py +++ b/scripts/tests/twister_blackbox/test_printouts.py @@ -11,6 +11,7 @@ import os import pytest import sys +import re from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock from twisterlib.testplan import TestPlan @@ -73,6 +74,12 @@ class TestPrintOuts: ), ] + TESTDATA_4 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'] + ) + ] @classmethod def setup_class(cls): @@ -81,13 +88,10 @@ def setup_class(cls): cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) cls.twister_module = importlib.util.module_from_spec(cls.spec) - @classmethod def teardown_class(cls): pass - - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_1, @@ -96,11 +100,11 @@ def teardown_class(cls): 'tests/dummy/device', ] ) - def test_list_tags(self, capfd, test_path, expected): - args = ['-T', test_path, '--list-tags'] + def test_list_tags(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--list-tags'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -114,8 +118,6 @@ def test_list_tags(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_2, @@ -124,11 +126,11 @@ def test_list_tags(self, capfd, test_path, expected): 'tests/dummy/device', ] ) - def test_list_tests(self, capfd, test_path, expected): - args = ['-T', test_path, '--list-tests'] + def test_list_tests(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--list-tests'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -143,8 +145,6 @@ def test_list_tests(self, capfd, test_path, expected): assert str(sys_exit.value) == '0' - - @pytest.mark.usefixtures("clear_log") @pytest.mark.parametrize( 'test_path, expected', TESTDATA_3, @@ -153,11 +153,11 @@ def test_list_tests(self, capfd, test_path, expected): 'tests/dummy/device', ] ) - def test_tree(self, capfd, test_path, expected): - args = ['-T', test_path, '--test-tree'] + def test_tree(self, capfd, out_path, test_path, expected): + args = ['--outdir', out_path, '-T', test_path, '--test-tree'] with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: + pytest.raises(SystemExit) as sys_exit: self.loader.exec_module(self.twister_module) out, err = capfd.readouterr() @@ -166,3 +166,99 @@ def test_tree(self, capfd, test_path, expected): assert expected in out assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=['tests'] + ) + def test_timestamps(self, capfd, out_path, test_path, test_platforms): + + args = ['-i', '--outdir', out_path, '-T', test_path, '--timestamps', '-v'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + info_regex = r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} - (?:INFO|DEBUG|ERROR)' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + output = err.split('\n') + + err_lines = [] + for line in output: + if line.strip(): + + match = re.search(info_regex, line) + if match is None: + err_lines.append(line) + + if err_lines: + assert False, f'No timestamp in line {err_lines}' + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'flag', + ['--abcd', '--1234', '-%', '-1'] + ) + def test_broken_parameter(self, capfd, flag): + + args = [flag] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + if flag == '-1': + assert str(sys_exit.value) == '1' + else: + assert str(sys_exit.value) == '2' + + @pytest.mark.parametrize( + 'flag', + ['--help', '-h'] + ) + def test_help(self, capfd, flag): + args = [flag] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=['tests'] + ) + def test_force_color(self, capfd, out_path, test_path, test_platforms): + + args = ['-i', '--outdir', out_path, '-T', test_path, '--force-color'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' diff --git a/scripts/tests/twister_blackbox/test_qemu.py b/scripts/tests/twister_blackbox/test_qemu.py deleted file mode 100644 index a7f7d1c33ef..00000000000 --- a/scripts/tests/twister_blackbox/test_qemu.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2023 Intel Corporation -# -# SPDX-License-Identifier: Apache-2.0 -""" -Blackbox tests for twister's command line functions -""" - -import importlib -import mock -import os -import pytest -import re -import sys - - -from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock -from twisterlib.testplan import TestPlan - - -@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) -class TestQEMU: - TESTDATA_1 = [ - ( - os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), - ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], - { - 'selected_test_scenarios': 3, - 'selected_test_instances': 9, - 'skipped_configurations': 3, - 'skipped_by_static_filter': 3, - 'skipped_at_runtime': 0, - 'passed_configurations': 6, - 'failed_configurations': 0, - 'errored_configurations': 0, - 'executed_test_cases': 10, - 'skipped_test_cases': 5, - 'platform_count': 3, - 'executed_on_platform': 4, - 'only_built': 2 - } - ), - ( - os.path.join(TEST_DATA, 'tests', 'dummy', 'device'), - ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], - { - 'selected_test_scenarios': 1, - 'selected_test_instances': 3, - 'skipped_configurations': 3, - 'skipped_by_static_filter': 3, - 'skipped_at_runtime': 0, - 'passed_configurations': 0, - 'failed_configurations': 0, - 'errored_configurations': 0, - 'executed_test_cases': 0, - 'skipped_test_cases': 3, - 'platform_count': 3, - 'executed_on_platform': 0, - 'only_built': 0 - } - ), - ] - - - @classmethod - def setup_class(cls): - apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') - cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) - cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) - cls.twister_module = importlib.util.module_from_spec(cls.spec) - - - @classmethod - def teardown_class(cls): - pass - - - @pytest.mark.usefixtures("clear_log") - @pytest.mark.parametrize( - 'test_path, test_platforms, expected', - TESTDATA_1, - ids=[ - 'tests/dummy/agnostic', - 'tests/dummy/device', - ] - ) - def test_emulation_only(self, capfd, test_path, test_platforms, expected): - args = ['-i', '-T', test_path, '--emulation-only'] + \ - [val for pair in zip( - ['-p'] * len(test_platforms), test_platforms - ) for val in pair] - - with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ - pytest.raises(SystemExit) as sys_exit: - self.loader.exec_module(self.twister_module) - - select_regex = r'^INFO - (?P[0-9]+) test scenarios' \ - r' \((?P[0-9]+) test instances\) selected,' \ - r' (?P[0-9]+) configurations skipped' \ - r' \((?P[0-9]+) by static filter,' \ - r' (?P[0-9]+) at runtime\)\.$' - - pass_regex = r'^INFO - (?P[0-9]+) of' \ - r' (?P[0-9]+) test configurations passed' \ - r' \([0-9]+\.[0-9]+%\), (?P[0-9]+) failed,' \ - r' (?P[0-9]+) errored,' \ - r' (?P[0-9]+) skipped with' \ - r' [0-9]+ warnings in [0-9]+\.[0-9]+ seconds$' - - case_regex = r'^INFO - In total (?P[0-9]+)' \ - r' test cases were executed, (?P[0-9]+) skipped' \ - r' on (?P[0-9]+) out of total [0-9]+ platforms' \ - r' \([0-9]+\.[0-9]+%\)$' - - built_regex = r'^INFO - (?P[0-9]+)' \ - r' test configurations executed on platforms, (?P[0-9]+)' \ - r' test configurations were only built.$' - - out, err = capfd.readouterr() - sys.stdout.write(out) - sys.stderr.write(err) - - select_search = re.search(select_regex, err, re.MULTILINE) - - assert select_search - assert int(select_search.group('test_scenarios')) == \ - expected['selected_test_scenarios'] - assert int(select_search.group('test_instances')) == \ - expected['selected_test_instances'] - assert int(select_search.group('skipped_configurations')) == \ - expected['skipped_configurations'] - assert int(select_search.group('skipped_by_static_filter')) == \ - expected['skipped_by_static_filter'] - assert int(select_search.group('skipped_at_runtime')) == \ - expected['skipped_at_runtime'] - - pass_search = re.search(pass_regex, err, re.MULTILINE) - - assert pass_search - assert int(pass_search.group('passed_configurations')) == \ - expected['passed_configurations'] - assert int(pass_search.group('test_instances')) == \ - expected['selected_test_instances'] - assert int(pass_search.group('failed_configurations')) == \ - expected['failed_configurations'] - assert int(pass_search.group('errored_configurations')) == \ - expected['errored_configurations'] - assert int(pass_search.group('skipped_configurations')) == \ - expected['skipped_configurations'] - - case_search = re.search(case_regex, err, re.MULTILINE) - - assert case_search - assert int(case_search.group('executed_test_cases')) == \ - expected['executed_test_cases'] - assert int(case_search.group('skipped_test_cases')) == \ - expected['skipped_test_cases'] - assert int(case_search.group('platform_count')) == \ - expected['platform_count'] - - built_search = re.search(built_regex, err, re.MULTILINE) - - assert built_search - assert int(built_search.group('executed_on_platform')) == \ - expected['executed_on_platform'] - assert int(built_search.group('only_built')) == \ - expected['only_built'] - - assert str(sys_exit.value) == '0' diff --git a/scripts/tests/twister_blackbox/test_report.py b/scripts/tests/twister_blackbox/test_report.py new file mode 100644 index 00000000000..56d1bc3e098 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_report.py @@ -0,0 +1,407 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions +""" + +import importlib +import re + +import mock +import os +import shutil +import pytest +import sys +from lxml import etree +import json + +from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock +from twisterlib.testplan import TestPlan + + +@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) +class TestReport: + TESTDATA_1 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + [ + 'qemu_x86_64.xml', 'qemu_x86.xml', + 'testplan.json', 'twister.json', + 'twister.log', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ] + ), + ] + TESTDATA_2 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + [ + 'qemu_x86_64_TEST.xml', 'qemu_x86_TEST.xml', + 'twister_TEST.json', 'twister_TEST_report.xml', + 'twister_TEST_suite_report.xml', 'twister_TEST.xml' + ] + ), + ] + TESTDATA_3 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', 'abcd'], + [ + 'abcd.json', 'abcd_report.xml', + 'abcd_suite_report.xml', 'abcd.xml' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', '1234', '--platform-reports'], + [ + 'qemu_x86_64.xml', 'qemu_x86.xml', + '1234.json', '1234_report.xml', + '1234_suite_report.xml', '1234.xml' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + ['--report-name', 'Final', '--platform-reports', '--report-suffix=Test'], + [ + 'qemu_x86_64_Test.xml', 'qemu_x86_Test.xml', + 'Final_Test.json', 'Final_Test_report.xml', + 'Final_Test_suite_report.xml', 'Final_Test.xml' + ] + ), + ] + TESTDATA_4 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'twister.json', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ], + "TEST_DIR" + ), + ] + TESTDATA_5 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'testplan.json', 'twister.log', + 'twister.json', 'twister_report.xml', + 'twister_suite_report.xml', 'twister.xml' + ], + "OUT_DIR" + ), + ] + TESTDATA_6 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + "TEST_LOG_FILE.log" + ), + ] + TESTDATA_7 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'coverage.log', 'coverage.json', + 'coverage' + ], + ), + ] + TESTDATA_8 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + [ + 'GCOV_COVERAGE_DUMP_START', 'GCOV_COVERAGE_DUMP_END' + ], + ), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_1, + ids=[ + 'platform_reports' + ] + ) + def test_platform_reports(self, capfd, out_path, test_path, test_platforms, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path, '--platform-reports'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(out_path, f_name) + assert os.path.exists(path), 'file not found' + + if path.endswith(".json"): + with open(path, "r") as json_file: + data = json.load(json_file) + assert data, f"JSON file '{path}' is empty" + + elif path.endswith(".xml"): + tree = etree.parse(path) + xml_text = etree.tostring(tree, encoding="utf-8").decode("utf-8") + assert xml_text.strip(), f"XML file '{path}' is empty" + + elif path.endswith(".log"): + with open(path, "r") as log_file: + text_content = log_file.read() + assert text_content.strip(), f"LOG file '{path}' is empty" + + else: + pytest.fail(f"Unsupported file type: '{path}'") + + for f_platform in test_platforms: + platform_path = os.path.join(out_path, f_platform) + assert os.path.exists(platform_path), f'file not found {f_platform}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_2, + ids=[ + 'report_suffix', + ] + ) + def test_report_suffix(self, capfd, out_path, test_path, test_platforms, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path, '--platform-reports', '--report-suffix=TEST'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(out_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, report_arg, file_name', + TESTDATA_3, + ids=[ + 'only_report_name', + 'report_name + platform_reports', + 'report-name + platform-reports + report-suffix' + ] + ) + def test_report_name(self, capfd, out_path, test_path, test_platforms, report_arg, file_name): + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + \ + [val for pair in zip( + report_arg + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(out_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name, dir_name', + TESTDATA_4, + ids=[ + 'report_dir', + ] + ) + def test_report_dir(self, capfd, out_path, test_path, test_platforms, file_name, dir_name): + args = ['-i', '--outdir', out_path, '-T', test_path, "--report-dir", dir_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + try: + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + finally: + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + @pytest.mark.noclearout + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name, dir_name', + TESTDATA_5, + ids=[ + 'outdir', + ] + ) + def test_outdir(self, capfd, test_path, test_platforms, file_name, dir_name): + args = ['-i', '-T', test_path, "--outdir", dir_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + try: + for f_name in file_name: + path = os.path.join(twister_path, f_name) + assert os.path.exists(path), 'file not found {f_name}' + + for f_platform in test_platforms: + platform_path = os.path.join(twister_path, f_platform) + assert os.path.exists(platform_path), f'file not found {f_platform}' + + assert str(sys_exit.value) == '0' + finally: + twister_path = os.path.join(ZEPHYR_BASE, dir_name) + if os.path.exists(twister_path): + shutil.rmtree(twister_path) + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_6, + ids=[ + 'log_file', + ] + ) + def test_log_file(self, capfd, test_path, test_platforms, out_path, file_name): + args = ['-i','--outdir', out_path, '-T', test_path, "--log-file", file_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + file_path = os.path.join(ZEPHYR_BASE, file_name) + if os.path.exists(file_path): + os.remove(file_path) + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert os.path.exists(file_path), 'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_7, + ids=[ + 'coverage', + ] + ) + def test_coverage(self, capfd, test_path, test_platforms, out_path, file_name): + args = ['-i','--outdir', out_path, '-T', test_path, '--coverage', '--coverage-tool', 'gcovr'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for f_name in file_name: + path = os.path.join(out_path, f_name) + assert os.path.exists(path), f'file not found {f_name}' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_8, + ids=[ + 'enable_coverage', + ] + ) + def test_enable_coverage(self, capfd, test_path, test_platforms, out_path, expected): + args = ['-i','--outdir', out_path, '-T', test_path, '--enable-coverage', '-vv'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for line in expected: + match = re.search(line, err) + assert match, f'line not found: {line}' + + assert str(sys_exit.value) == '0' diff --git a/scripts/tests/twister_blackbox/test_runner.py b/scripts/tests/twister_blackbox/test_runner.py new file mode 100644 index 00000000000..eea5e706394 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_runner.py @@ -0,0 +1,989 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions +""" + +import importlib +import mock +import os +import pytest +import re +import sys +import time + +from conftest import TEST_DATA, ZEPHYR_BASE, testsuite_filename_mock, clear_log_in_test +from twisterlib.testplan import TestPlan + + +@mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) +class TestRunner: + TESTDATA_1 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + { + 'selected_test_scenarios': 3, + 'selected_test_instances': 9, + 'skipped_configurations': 3, + 'skipped_by_static_filter': 3, + 'skipped_at_runtime': 0, + 'passed_configurations': 6, + 'failed_configurations': 0, + 'errored_configurations': 0, + 'executed_test_cases': 10, + 'skipped_test_cases': 5, + 'platform_count': 3, + 'executed_on_platform': 4, + 'only_built': 2 + } + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'device'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + { + 'selected_test_scenarios': 1, + 'selected_test_instances': 3, + 'skipped_configurations': 3, + 'skipped_by_static_filter': 3, + 'skipped_at_runtime': 0, + 'passed_configurations': 0, + 'failed_configurations': 0, + 'errored_configurations': 0, + 'executed_test_cases': 0, + 'skipped_test_cases': 3, + 'platform_count': 3, + 'executed_on_platform': 0, + 'only_built': 0 + } + ), + ] + TESTDATA_2 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + { + 'executed_on_platform': 0, + 'only_built': 6 + } + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'device'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + { + 'executed_on_platform': 0, + 'only_built': 1 + } + ), + ] + TESTDATA_3 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + { + 'selected_test_scenarios': 3, + 'selected_test_instances': 9, + 'skipped_configurations': 3, + 'skipped_by_static_filter': 3, + 'skipped_at_runtime': 0, + 'passed_configurations': 4, + 'failed_configurations': 0, + 'errored_configurations': 0, + 'executed_test_cases': 8, + 'skipped_test_cases': 5, + 'platform_count': 0, + 'executed_on_platform': 4, + 'only_built': 2 + } + ) + ] + TESTDATA_4 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + ), + ] + TESTDATA_5 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + { + 'passed_configurations': 6, + 'selected_test_instances': 6, + 'executed_on_platform': 0, + 'only_built': 6, + } + ), + ] + TESTDATA_6 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86'], + os.path.join(TEST_DATA, "pre_script.sh") + ), + ] + TESTDATA_7 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64'], + { + 'passed_configurations': 3, + 'selected_test_instances': 6, + 'executed_on_platform': 2, + 'only_built': 1, + } + ), + ] + TESTDATA_8 = [ + ( + os.path.join(TEST_DATA, 'tests', 'always_fail', 'dummy'), + ['qemu_x86_64'], + '1', + ), + ( + os.path.join(TEST_DATA, 'tests', 'always_fail', 'dummy'), + ['qemu_x86'], + '2', + ), + ] + TESTDATA_9 = [ + ( + os.path.join(TEST_DATA, 'tests', 'always_fail', 'dummy'), + ['qemu_x86'], + '15', + ), + ( + os.path.join(TEST_DATA, 'tests', 'always_fail', 'dummy'), + ['qemu_x86'], + '30', + ), + ] + TESTDATA_10 = [ + ( + os.path.join(TEST_DATA, 'tests', 'always_timeout', 'dummy'), + ['qemu_x86'], + '2', + ), + ( + os.path.join(TEST_DATA, 'tests', 'always_timeout', 'dummy'), + ['qemu_x86'], + '0.5', + ), + ] + TESTDATA_11 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), + ['qemu_x86', 'qemu_x86_64', 'frdm_k64f'], + os.path.join(TEST_DATA, 'twister-quarantine-list.yml'), + ), + ] + TESTDATA_12 = [ + ( + os.path.join(TEST_DATA, 'tests', 'dummy'), + ['qemu_x86'], + ['device'], + ['dummy.agnostic.group2 SKIPPED: Command line testsuite tag filter', + 'dummy.agnostic.group1.subgroup2 SKIPPED: Command line testsuite tag filter', + 'dummy.agnostic.group1.subgroup1 SKIPPED: Command line testsuite tag filter', + r'0 of 4 test configurations passed \(0.00%\), 0 failed, 0 errored, 4 skipped' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy'), + ['qemu_x86'], + ['subgrouped'], + ['dummy.agnostic.group2 SKIPPED: Command line testsuite tag filter', + r'2 of 4 test configurations passed \(100.00%\), 0 failed, 0 errored, 2 skipped' + ] + ), + ( + os.path.join(TEST_DATA, 'tests', 'dummy'), + ['qemu_x86'], + ['agnostic', 'device'], + [r'3 of 4 test configurations passed \(100.00%\), 0 failed, 0 errored, 1 skipped'] + ), + ] + TESTDATA_13 = [ + ( + os.path.join(TEST_DATA, 'tests', 'one_fail_one_pass'), + ['qemu_x86'], + { + 'selected_test_instances': 2, + 'skipped_configurations': 0, + 'passed_configurations': 0, + 'failed_configurations': 1, + 'errored_configurations': 0, + } + ) + ] + + TESTDATA_14 = [ + ( + os.path.join(TEST_DATA, 'tests', 'always_build_error'), + ['qemu_x86_64'], + '1', + ), + ( + os.path.join(TEST_DATA, 'tests', 'always_build_error'), + ['qemu_x86'], + '4', + ), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_1, + ids=[ + 'emulation_only tests/dummy/agnostic', + 'emulation_only tests/dummy/device', + ] + ) + def test_emulation_only(self, capfd, out_path, test_path, test_platforms, expected): + args = ['-i', '--outdir', out_path, '-T', test_path, '--emulation-only'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + select_regex = r'^INFO - (?P[0-9]+) test scenarios' \ + r' \((?P[0-9]+) test instances\) selected,' \ + r' (?P[0-9]+) configurations skipped' \ + r' \((?P[0-9]+) by static filter,' \ + r' (?P[0-9]+) at runtime\)\.$' + + pass_regex = r'^INFO - (?P[0-9]+) of' \ + r' (?P[0-9]+) test configurations passed' \ + r' \([0-9]+\.[0-9]+%\), (?P[0-9]+) failed,' \ + r' (?P[0-9]+) errored,' \ + r' (?P[0-9]+) skipped with' \ + r' [0-9]+ warnings in [0-9]+\.[0-9]+ seconds$' + + case_regex = r'^INFO - In total (?P[0-9]+)' \ + r' test cases were executed, (?P[0-9]+) skipped' \ + r' on (?P[0-9]+) out of total [0-9]+ platforms' \ + r' \([0-9]+\.[0-9]+%\)$' + + built_regex = r'^INFO - (?P[0-9]+)' \ + r' test configurations executed on platforms, (?P[0-9]+)' \ + r' test configurations were only built.$' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + select_search = re.search(select_regex, err, re.MULTILINE) + + assert select_search + assert int(select_search.group('test_scenarios')) == \ + expected['selected_test_scenarios'] + assert int(select_search.group('test_instances')) == \ + expected['selected_test_instances'] + assert int(select_search.group('skipped_configurations')) == \ + expected['skipped_configurations'] + assert int(select_search.group('skipped_by_static_filter')) == \ + expected['skipped_by_static_filter'] + assert int(select_search.group('skipped_at_runtime')) == \ + expected['skipped_at_runtime'] + + pass_search = re.search(pass_regex, err, re.MULTILINE) + + assert pass_search + assert int(pass_search.group('passed_configurations')) == \ + expected['passed_configurations'] + assert int(pass_search.group('test_instances')) == \ + expected['selected_test_instances'] + assert int(pass_search.group('failed_configurations')) == \ + expected['failed_configurations'] + assert int(pass_search.group('errored_configurations')) == \ + expected['errored_configurations'] + assert int(pass_search.group('skipped_configurations')) == \ + expected['skipped_configurations'] + + case_search = re.search(case_regex, err, re.MULTILINE) + + assert case_search + assert int(case_search.group('executed_test_cases')) == \ + expected['executed_test_cases'] + assert int(case_search.group('skipped_test_cases')) == \ + expected['skipped_test_cases'] + assert int(case_search.group('platform_count')) == \ + expected['platform_count'] + + built_search = re.search(built_regex, err, re.MULTILINE) + + assert built_search + assert int(built_search.group('executed_on_platform')) == \ + expected['executed_on_platform'] + assert int(built_search.group('only_built')) == \ + expected['only_built'] + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_2, + ids=[ + 'build_only tests/dummy/agnostic', + 'build_only tests/dummy/device', + ], + ) + @pytest.mark.parametrize( + 'flag', + ['--build-only', '-b'] + ) + def test_build_only(self, capfd, out_path, test_path, test_platforms, expected, flag): + args = ['-i', '--outdir', out_path, '-T', test_path, flag] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + built_regex = r'^INFO - (?P[0-9]+)' \ + r' test configurations executed on platforms, (?P[0-9]+)' \ + r' test configurations were only built.$' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + built_search = re.search(built_regex, err, re.MULTILINE) + + assert built_search + assert int(built_search.group('executed_on_platform')) == \ + expected['executed_on_platform'] + assert int(built_search.group('only_built')) == \ + expected['only_built'] + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_3, + ids=[ + 'test_only' + ], + ) + def test_runtest_only(self, capfd, out_path, test_path, test_platforms, expected): + + args = ['--outdir', out_path,'-i', '-T', test_path, '--build-only'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + capfd.readouterr() + + clear_log_in_test() + + args = ['--outdir', out_path,'-i', '-T', test_path, '--test-only'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + + select_regex = r'^INFO - (?P[0-9]+) test scenarios' \ + r' \((?P[0-9]+) test instances\) selected,' \ + r' (?P[0-9]+) configurations skipped' \ + r' \((?P[0-9]+) by static filter,' \ + r' (?P[0-9]+) at runtime\)\.$' + + pass_regex = r'^INFO - (?P[0-9]+) of' \ + r' (?P[0-9]+) test configurations passed' \ + r' \([0-9]+\.[0-9]+%\), (?P[0-9]+) failed,' \ + r' (?P[0-9]+) errored,' \ + r' (?P[0-9]+) skipped with' \ + r' [0-9]+ warnings in [0-9]+\.[0-9]+ seconds$' + + case_regex = r'^INFO - In total (?P[0-9]+)' \ + r' test cases were executed, (?P[0-9]+) skipped' \ + r' on (?P[0-9]+) out of total [0-9]+ platforms' \ + r' \([0-9]+\.[0-9]+%\)$' + built_regex = r'^INFO - (?P[0-9]+)' \ + r' test configurations executed on platforms, (?P[0-9]+)' \ + r' test configurations were only built.$' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + path = os.path.join(out_path, 'twister.log') + with open(path, "r") as log_file: + text_content = log_file.read() + print(text_content) + + select_search = re.search(select_regex, err, re.MULTILINE) + + assert select_search + assert int(select_search.group('test_scenarios')) == \ + expected['selected_test_scenarios'] + assert int(select_search.group('test_instances')) == \ + expected['selected_test_instances'] + assert int(select_search.group('skipped_configurations')) == \ + expected['skipped_configurations'] + assert int(select_search.group('skipped_by_static_filter')) == \ + expected['skipped_by_static_filter'] + assert int(select_search.group('skipped_at_runtime')) == \ + expected['skipped_at_runtime'] + + pass_search = re.search(pass_regex, err, re.MULTILINE) + + assert pass_search + assert int(pass_search.group('passed_configurations')) == \ + expected['passed_configurations'] + assert int(pass_search.group('test_instances')) == \ + expected['selected_test_instances'] + assert int(pass_search.group('failed_configurations')) == \ + expected['failed_configurations'] + assert int(pass_search.group('errored_configurations')) == \ + expected['errored_configurations'] + assert int(pass_search.group('skipped_configurations')) == \ + expected['skipped_configurations'] + + case_search = re.search(case_regex, err, re.MULTILINE) + + assert case_search + assert int(case_search.group('executed_test_cases')) == \ + expected['executed_test_cases'] + assert int(case_search.group('skipped_test_cases')) == \ + expected['skipped_test_cases'] + assert int(case_search.group('platform_count')) == \ + expected['platform_count'] + + built_search = re.search(built_regex, err, re.MULTILINE) + + assert built_search + assert int(built_search.group('executed_on_platform')) == \ + expected['executed_on_platform'] + assert int(built_search.group('only_built')) == \ + expected['only_built'] + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=[ + 'ninja', + ] + ) + @pytest.mark.parametrize( + 'flag', + ['--ninja', '-N'] + ) + def test_ninja(self, capfd, out_path, test_path, test_platforms, flag): + args = ['--outdir', out_path, '-T', test_path, flag] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=[ + 'dry_run', + ], + ) + @pytest.mark.parametrize( + 'flag', + ['--dry-run', '-y'] + ) + def test_dry_run(self, capfd, out_path, test_path, test_platforms, flag): + args = ['--outdir', out_path, '-T', test_path, flag] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=[ + 'any_platform', + ], + ) + @pytest.mark.parametrize( + 'flag', + ['-l', '--all'] + ) + def test_any_platform(self, capfd, out_path, test_path, test_platforms, flag): + args = ['--outdir', out_path, '-T', test_path, flag] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_5, + ids=[ + 'cmake_only', + ], + ) + def test_cmake_only(self, capfd, out_path, test_path, test_platforms, expected): + args = ['--outdir', out_path, '-T', test_path, '--cmake-only'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + pass_regex = r'^INFO - (?P[0-9]+) of' \ + r' (?P[0-9]+) test configurations passed' + + built_regex = r'^INFO - (?P[0-9]+)' \ + r' test configurations executed on platforms, (?P[0-9]+)' \ + r' test configurations were only built.$' + + pass_search = re.search(pass_regex, err, re.MULTILINE) + + assert pass_search + assert int(pass_search.group('passed_configurations')) == \ + expected['passed_configurations'] + assert int(pass_search.group('test_instances')) == \ + expected['selected_test_instances'] + + built_search = re.search(built_regex, err, re.MULTILINE) + + assert built_search + assert int(built_search.group('executed_on_platform')) == \ + expected['executed_on_platform'] + assert int(built_search.group('only_built')) == \ + expected['only_built'] + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, file_name', + TESTDATA_6, + ids=[ + 'pre_script', + ], + ) + def test_pre_script(self, capfd, out_path, test_path, test_platforms, file_name): + args = ['--outdir', out_path, '-T', test_path, '--pre-script', file_name] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_7, + ids=[ + 'exclude_platform', + ], + ) + def test_exclude_platform(self, capfd, out_path, test_path, test_platforms, expected): + args = ['--outdir', out_path, '-T', test_path, '--exclude-platform', "qemu_x86"] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + pass_regex = r'^INFO - (?P[0-9]+) of' \ + r' (?P[0-9]+) test configurations passed' + + built_regex = r'^INFO - (?P[0-9]+)' \ + r' test configurations executed on platforms, (?P[0-9]+)' \ + r' test configurations were only built.$' + + pass_search = re.search(pass_regex, err, re.MULTILINE) + + assert pass_search + assert int(pass_search.group('passed_configurations')) == \ + expected['passed_configurations'] + assert int(pass_search.group('test_instances')) == \ + expected['selected_test_instances'] + + built_search = re.search(built_regex, err, re.MULTILINE) + + assert built_search + assert int(built_search.group('executed_on_platform')) == \ + expected['executed_on_platform'] + assert int(built_search.group('only_built')) == \ + expected['only_built'] + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms', + TESTDATA_4, + ids=[ + 'device_flash_timeout', + ], + ) + def test_device_flash_timeout(self, capfd, out_path, test_path, test_platforms): + args = ['--outdir', out_path, '-T', test_path, '--device-flash-timeout', "240"] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, iterations', + TESTDATA_8, + ids=[ + 'retry 2', + 'retry 3' + ], + ) + def test_retry(self, capfd, out_path, test_path, test_platforms, iterations): + args = ['--outdir', out_path, '-T', test_path, '--retry-failed', iterations, '--retry-interval', '1'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + pattern = re.compile(r'INFO\s+-\s+(\d+)\s+Iteration:[\s\S]*?ERROR\s+-\s+(\w+)') + matches = pattern.findall(err) + + if matches: + last_iteration = max(int(match[0]) for match in matches) + last_match = next(match for match in matches if int(match[0]) == last_iteration) + iteration_number, platform_name = int(last_match[0]), last_match[1] + assert int(iteration_number) == int(iterations) + 1 + assert [platform_name] == test_platforms + else: + assert 'Pattern not found in the output' + + assert str(sys_exit.value) == '1' + + @pytest.mark.parametrize( + 'test_path, test_platforms, interval', + TESTDATA_9, + ids=[ + 'retry interval 15', + 'retry interval 30' + ], + ) + def test_retry_interval(self, capfd, out_path, test_path, test_platforms, interval): + args = ['--outdir', out_path, '-T', test_path, '--retry-failed', '1', '--retry-interval', interval] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + start_time = time.time() + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + end_time = time.time() + elapsed_time = end_time - start_time + print(f"Time elapsed: {elapsed_time:.2f} seconds") + if elapsed_time < int(interval): + assert 'interval was too short' + + assert str(sys_exit.value) == '1' + + @pytest.mark.parametrize( + 'test_path, test_platforms, timeout', + TESTDATA_10, + ids=[ + 'timeout-multiplier 2 - 20s', + 'timeout-multiplier 0.5 - 5s' + ], + ) + def test_timeout_multiplier(self, capfd, out_path, test_path, test_platforms, timeout): + args = ['--outdir', out_path, '-T', test_path, '--timeout-multiplier', timeout, '-v'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + tolerance = 1.0 + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + elapsed_time = float(re.search(r'Timeout \(qemu (\d+\.\d+)s\)', err).group(1)) + + assert abs( + elapsed_time - float(timeout) * 10) <= tolerance, f"Time is different from expected" + + assert str(sys_exit.value) == '1' + + @pytest.mark.parametrize( + 'test_path, test_platforms, quarantine_directory', + TESTDATA_11, + ids=[ + 'quarantine', + ], + ) + def test_quarantine_list(self, capfd, out_path, test_path, test_platforms, quarantine_directory): + args = ['--outdir', out_path, '-T', test_path, '--quarantine-list', quarantine_directory, '-vv'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + frdm_match = re.search('agnostic/group2/dummy.agnostic.group2 SKIPPED: Quarantine: test ' + 'frdm_k64f', err) + frdm_match2 = re.search( + 'agnostic/group1/subgroup2/dummy.agnostic.group1.subgroup2 SKIPPED: Quarantine: test ' + 'frdm_k64f', + err) + qemu_64_match = re.search( + 'agnostic/group1/subgroup2/dummy.agnostic.group1.subgroup2 SKIPPED: Quarantine: test ' + 'qemu_x86_64', + err) + all_platforms_match = re.search( + 'agnostic/group1/subgroup1/dummy.agnostic.group1.subgroup1 SKIPPED: Quarantine: test ' + 'all platforms', + err) + all_platforms_match2 = re.search( + 'agnostic/group1/subgroup1/dummy.agnostic.group1.subgroup1 SKIPPED: Quarantine: test ' + 'all platforms', + err) + all_platforms_match3 = re.search( + 'agnostic/group1/subgroup1/dummy.agnostic.group1.subgroup1 SKIPPED: Quarantine: test ' + 'all platforms', + err) + + assert frdm_match and frdm_match2, 'platform quarantine not work properly' + assert qemu_64_match, 'platform quarantine on scenario not work properly' + assert all_platforms_match and all_platforms_match2 and all_platforms_match3, 'scenario ' \ + 'quarantine' \ + ' not work ' \ + 'properly' + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, tags, expected', + TESTDATA_12, + ids=[ + 'tags device', + 'tags subgruped', + 'tag agnostic and device' + ], + ) + def test_tag(self, capfd, out_path, test_path, test_platforms, tags, expected): + args = ['--outdir', out_path, '-T', test_path, '-vv'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + \ + [val for pairs in zip( + ['-t'] * len(tags), tags + ) for val in pairs] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + for line in expected: + print(line) + assert re.search(line, err) + + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'test_path, test_platforms, expected', + TESTDATA_13, + ids=[ + 'only_failed' + ], + ) + + def test_only_failed(self, capfd, out_path, test_path, test_platforms, expected): + args = ['--outdir', out_path,'-i', '-T', test_path, '-v'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + capfd.readouterr() + + clear_log_in_test() + + args = ['--outdir', out_path,'-i', '-T', test_path, '--only-failed'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + + pass_regex = r'^INFO - (?P[0-9]+) of' \ + r' (?P[0-9]+) test configurations passed' \ + r' \([0-9]+\.[0-9]+%\), (?P[0-9]+) failed,' \ + r' (?P[0-9]+) errored,' \ + r' (?P[0-9]+) skipped with' \ + r' [0-9]+ warnings in [0-9]+\.[0-9]+ seconds$' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + + assert re.search( + r'one_fail_one_pass.agnostic.group1.subgroup2 on qemu_x86 failed \(Failed\)', err) + + pass_search = re.search(pass_regex, err, re.MULTILINE) + + assert pass_search + assert int(pass_search.group('passed_configurations')) == \ + expected['passed_configurations'] + assert int(pass_search.group('test_instances')) == \ + expected['selected_test_instances'] + assert int(pass_search.group('failed_configurations')) == \ + expected['failed_configurations'] + assert int(pass_search.group('errored_configurations')) == \ + expected['errored_configurations'] + assert int(pass_search.group('skipped_configurations')) == \ + expected['skipped_configurations'] + + assert str(sys_exit.value) == '1' + + @pytest.mark.parametrize( + 'test_path, test_platforms, iterations', + TESTDATA_14, + ids=[ + 'retry 2', + 'retry 3' + ], + ) + def test_retry_build_errors(self, capfd, out_path, test_path, test_platforms, iterations): + args = ['--outdir', out_path, '-T', test_path, '--retry-build-errors', '--retry-failed', iterations, + '--retry-interval', '10'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + pattern = re.compile(r'INFO\s+-\s+(\d+)\s+Iteration:[\s\S]*?ERROR\s+-\s+(\w+)') + matches = pattern.findall(err) + + if matches: + last_iteration = max(int(match[0]) for match in matches) + last_match = next(match for match in matches if int(match[0]) == last_iteration) + iteration_number, platform_name = int(last_match[0]), last_match[1] + assert int(iteration_number) == int(iterations) + 1 + assert [platform_name] == test_platforms + else: + assert 'Pattern not found in the output' + + assert str(sys_exit.value) == '1' diff --git a/scripts/tests/twister_blackbox/test_testplan.py b/scripts/tests/twister_blackbox/test_testplan.py new file mode 100644 index 00000000000..7316209b1af --- /dev/null +++ b/scripts/tests/twister_blackbox/test_testplan.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions - those requiring testplan.json +""" + +import importlib +import mock +import os +import pytest +import sys +import json + +from conftest import ZEPHYR_BASE, TEST_DATA, testsuite_filename_mock +from twisterlib.testplan import TestPlan +from twisterlib.error import TwisterRuntimeError + + +class TestTestPlan: + TESTDATA_1 = [ + ('smoke', 5), + ('acceptance', 6), + ] + TESTDATA_2 = [ + ('dummy.agnostic.group2.assert1', SystemExit, 3), + ( + os.path.join('scripts', 'tests', 'twister_blackbox', 'test_data', 'tests', + 'dummy', 'agnostic', 'group1', 'subgroup1', + 'dummy.agnostic.group2.assert1'), + TwisterRuntimeError, + None + ), + ] + TESTDATA_3 = [ + ('buildable', 6), + ('runnable', 5), + ] + TESTDATA_4 = [ + (True, 1), + (False, 6), + ] + + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.parametrize( + 'level, expected_tests', + TESTDATA_1, + ids=['smoke', 'acceptance'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_level(self, out_path, level, expected_tests): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + config_path = os.path.join(TEST_DATA, 'test_config.yaml') + args = ['-i','--outdir', out_path, '-T', path, '--level', level, '-y', + '--test-config', config_path] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert str(sys_exit.value) == '0' + + assert expected_tests == len(filtered_j) + + @pytest.mark.parametrize( + 'test, expected_exception, expected_subtest_count', + TESTDATA_2, + ids=['valid', 'invalid'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_subtest(self, out_path, test, expected_exception, expected_subtest_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--sub-test', test, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(expected_exception) as exc: + self.loader.exec_module(self.twister_module) + + if expected_exception != SystemExit: + assert True + return + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert str(exc.value) == '0' + assert len(filtered_j) == expected_subtest_count + + @pytest.mark.parametrize( + 'filter, expected_count', + TESTDATA_3, + ids=['buildable', 'runnable'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_filter(self, out_path, filter, expected_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '--filter', filter, '-y'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as exc: + self.loader.exec_module(self.twister_module) + + assert str(exc.value) == '0' + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert expected_count == len(filtered_j) + + @pytest.mark.parametrize( + 'integration, expected_count', + TESTDATA_4, + ids=['integration', 'no integration'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + @mock.patch.object(TestPlan, 'SAMPLE_FILENAME', '') + def test_integration(self, out_path, integration, expected_count): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy') + args = ['-i', '--outdir', out_path, '-T', path, '-y'] + \ + (['--integration'] if integration else []) + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as exc: + self.loader.exec_module(self.twister_module) + + assert str(exc.value) == '0' + + with open(os.path.join(out_path, 'testplan.json')) as f: + j = json.load(f) + filtered_j = [ + (ts['platform'], ts['name'], tc['identifier']) \ + for ts in j['testsuites'] \ + for tc in ts['testcases'] if 'reason' not in tc + ] + + assert expected_count == len(filtered_j) diff --git a/scripts/twister b/scripts/twister index c66b81d84e1..aa075beb7a1 100755 --- a/scripts/twister +++ b/scripts/twister @@ -90,6 +90,9 @@ pairs: platform_exclude: Set of platforms that this test case should not run on. + simulation_exclude: + Set of simulators that this test case should not run on. + extra_sections: When computing sizes, twister will report errors if it finds extra, unexpected sections in the Zephyr binary unless they are named diff --git a/scripts/valgrind.supp b/scripts/valgrind.supp index b161e09fa01..330ec51fefd 100644 --- a/scripts/valgrind.supp +++ b/scripts/valgrind.supp @@ -18,7 +18,7 @@ { POSIX soc no cpu cleanup Memcheck:Leak - match-leak-kinds: reachable + match-leak-kinds: reachable,possible ... fun:posix_boot_cpu ... diff --git a/scripts/west_commands/runners/blackmagicprobe.py b/scripts/west_commands/runners/blackmagicprobe.py index 54fc22a7eda..1c2c8fa0d6a 100644 --- a/scripts/west_commands/runners/blackmagicprobe.py +++ b/scripts/west_commands/runners/blackmagicprobe.py @@ -116,6 +116,10 @@ def __init__(self, cfg, gdb_serial, connect_rst=False): # # https://github.com/zephyrproject-rtos/zephyr/issues/50789 self.elf_file = Path(cfg.elf_file).as_posix() + if cfg.hex_file is not None: + self.hex_file = Path(cfg.hex_file).as_posix() + else: + self.hex_file = None self.gdb_serial = blackmagicprobe_gdb_serial(gdb_serial) self.logger.info(f'using GDB serial: {self.gdb_serial}') if connect_rst: @@ -150,8 +154,20 @@ def do_add_parser(cls, parser): help='Assert SRST during connect? (default: no)') def bmp_flash(self, command, **kwargs): - if self.elf_file is None: - raise ValueError('Cannot debug; elf file is missing') + # if hex file is present and signed, use it else use elf file + if self.hex_file: + split = self.hex_file.split('.') + # eg zephyr.signed.hex + if len(split) >= 3 and split[-2] == 'signed': + flash_file = self.hex_file + else: + flash_file = self.elf_file + else: + flash_file = self.elf_file + + if flash_file is None: + raise ValueError('Cannot flash; elf file is missing') + command = (self.gdb + ['-ex', "set confirm off", '-ex', "target extended-remote {}".format( @@ -159,7 +175,7 @@ def bmp_flash(self, command, **kwargs): self.connect_rst_enable_arg + ['-ex', "monitor swdp_scan", '-ex', "attach 1", - '-ex', "load {}".format(self.elf_file), + '-ex', "load {}".format(flash_file), '-ex', "kill", '-ex', "quit", '-silent']) diff --git a/scripts/west_commands/runners/intel_adsp.py b/scripts/west_commands/runners/intel_adsp.py index 18b1462ef05..f7587331dc3 100644 --- a/scripts/west_commands/runners/intel_adsp.py +++ b/scripts/west_commands/runners/intel_adsp.py @@ -4,6 +4,7 @@ '''Runner for flashing with the Intel ADSP boards.''' +import argparse import os import sys import re @@ -14,11 +15,12 @@ from zephyr_ext_common import ZEPHYR_BASE DEFAULT_CAVSTOOL='soc/xtensa/intel_adsp/tools/cavstool_client.py' -DEFAULT_SOF_MOD_DIR=os.path.join(ZEPHYR_BASE, '../modules/audio/sof') -DEFAULT_RIMAGE_TOOL=shutil.which('rimage') -DEFAULT_CONFIG_DIR=os.path.join(DEFAULT_SOF_MOD_DIR, 'tools/rimage/config') -DEFAULT_KEY_DIR=os.path.join(DEFAULT_SOF_MOD_DIR, 'keys') +class SignParamError(argparse.Action): + 'User-friendly feedback when trying to sign with west flash' + def __call__(self, parser, namespace, values, option_string=None): + parser.error(f'Cannot use "west flash {option_string} ..." any more. ' + + '"west sign" is now called from CMake, see "west sign -h"') class IntelAdspBinaryRunner(ZephyrBinaryRunner): '''Runner front-end for the intel ADSP boards.''' @@ -26,32 +28,19 @@ class IntelAdspBinaryRunner(ZephyrBinaryRunner): def __init__(self, cfg, remote_host, - rimage_tool, - config_dir, - default_key, - key, pty, tool_opt, - do_sign, ): super().__init__(cfg) self.remote_host = remote_host - self.rimage_tool = rimage_tool - self.config_dir = config_dir self.bin_fw = os.path.join(cfg.build_dir, 'zephyr', 'zephyr.ri') self.cavstool = os.path.join(ZEPHYR_BASE, DEFAULT_CAVSTOOL) self.platform = os.path.basename(cfg.board_dir) self.pty = pty - if key: - self.key = key - else: - self.key = os.path.join(DEFAULT_KEY_DIR, default_key) - self.tool_opt_args = tool_opt - self.do_sign = do_sign @classmethod def name(cls): @@ -65,18 +54,14 @@ def capabilities(cls): def do_add_parser(cls, parser): parser.add_argument('--remote-host', help='hostname of the remote targeting ADSP board') - parser.add_argument('--rimage-tool', default=DEFAULT_RIMAGE_TOOL, - help='path to the rimage tool') - parser.add_argument('--config-dir', default=DEFAULT_CONFIG_DIR, - help='path to the toml config file') - parser.add_argument('--default-key', - help='the default basename of the key store in board.cmake') - parser.add_argument('--key', - help='specify where the signing key is') parser.add_argument('--pty', nargs='?', const="remote-host", type=str, help=''''Capture the output of cavstool.py running on --remote-host \ and stream it remotely to west's standard output.''') + for old_sign_param in [ '--rimage-tool', '--config-dir', '--default-key', '--key']: + parser.add_argument(old_sign_param, action=SignParamError, + help='do not use, "west sign" is now called from CMake, see "west sign -h"') + @classmethod def tool_opt_help(cls) -> str: return """Additional options for run/request service tool, @@ -84,35 +69,15 @@ def tool_opt_help(cls) -> str: @classmethod def do_create(cls, cfg, args): - # We now have `west flash` -> `west build` -> `west sign` so - # `west flash` -> `west sign` is not needed anymore; it's also - # slower because not concurrent. However, for backwards - # compatibility keep signing here if some explicit rimage - # --option was passed. Some of these options may differ from the - # current `west sign` configuration; we take "precedence" by - # running last. - do_sign = ( - args.rimage_tool != DEFAULT_RIMAGE_TOOL or - args.config_dir != DEFAULT_CONFIG_DIR or - args.key is not None - ) return IntelAdspBinaryRunner(cfg, remote_host=args.remote_host, - rimage_tool=args.rimage_tool, - config_dir=args.config_dir, - default_key=args.default_key, - key=args.key, pty=args.pty, tool_opt=args.tool_opt, - do_sign=do_sign, ) def do_run(self, command, **kwargs): self.logger.info('Starting Intel ADSP runner') - if self.do_sign: - self.sign(**kwargs) - if re.search("intel_adsp", self.platform): self.require(self.cavstool) self.flash(**kwargs) @@ -120,17 +85,8 @@ def do_run(self, command, **kwargs): self.logger.error("No suitable platform for running") sys.exit(1) - def sign(self, **kwargs): - path_opt = ['-p', f'{self.rimage_tool}'] if self.rimage_tool else [] - sign_cmd = ( - ['west', 'sign', '-d', f'{self.cfg.build_dir}', '-t', 'rimage'] - + path_opt + ['-D', f'{self.config_dir}', '--', '-k', f'{self.key}'] - ) - self.logger.info(" ".join(sign_cmd)) - self.check_call(sign_cmd) - def flash(self, **kwargs): - # Generate a hash string for appending to the sending ri file + 'Generate a hash string for appending to the sending ri file' hash_object = hashlib.md5(self.bin_fw.encode()) random_str = f"{random.getrandbits(64)}".encode() hash_object.update(random_str) diff --git a/scripts/west_commands/runners/jlink.py b/scripts/west_commands/runners/jlink.py index 4fa71720673..17d60787745 100644 --- a/scripts/west_commands/runners/jlink.py +++ b/scripts/west_commands/runners/jlink.py @@ -5,6 +5,7 @@ '''Runner for debugging with J-Link.''' import argparse +import ipaddress import logging import os from pathlib import Path @@ -25,6 +26,13 @@ DEFAULT_JLINK_EXE = 'JLink.exe' if sys.platform == 'win32' else 'JLinkExe' DEFAULT_JLINK_GDB_PORT = 2331 +def is_ip(ip): + try: + ipaddress.ip_address(ip) + except ValueError: + return False + return True + class ToggleAction(argparse.Action): def __call__(self, parser, args, ignored, option): @@ -80,7 +88,8 @@ def capabilities(cls): @classmethod def dev_id_help(cls) -> str: return '''Device identifier. Use it to select the J-Link Serial Number - of the device connected over USB.''' + of the device connected over USB. If the J-Link is connected over ip, + the Device identifier is the ip.''' @classmethod def tool_opt_help(cls) -> str: @@ -226,9 +235,9 @@ def do_run(self, command, **kwargs): 'RTOSPlugin_Zephyr') server_cmd = ([self.gdbserver] + - # only USB connections supported - ['-select', 'usb' + (f'={self.dev_id}' - if self.dev_id else ''), + ['-select', + ('ip' if is_ip(self.dev_id) else 'usb') + + (f'={self.dev_id}' if self.dev_id else ''), '-port', str(self.gdb_port), '-if', self.iface, '-speed', self.speed, @@ -355,8 +364,7 @@ def flash(self, **kwargs): loader_details = "?" + self.loader cmd = ([self.commander] + - # only USB connections supported - (['-USB', f'{self.dev_id}'] if self.dev_id else []) + + (['-IP', f'{self.dev_id}'] if is_ip(self.dev_id) else (['-USB', f'{self.dev_id}'] if self.dev_id else [])) + (['-nogui', '1'] if self.supports_nogui else []) + ['-if', self.iface, '-speed', self.speed, diff --git a/scripts/west_commands/runners/nrf_common.py b/scripts/west_commands/runners/nrf_common.py index 2ff51d7e85d..76662c72ea9 100644 --- a/scripts/west_commands/runners/nrf_common.py +++ b/scripts/west_commands/runners/nrf_common.py @@ -24,11 +24,26 @@ ErrNotAvailableBecauseProtection = 24 ErrVerify = 25 +UICR_RANGES = { + 'NRF53_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800), + 'NRFDL_DEVICE_CORE_NETWORK': (0x01FF8000, 0x01FF8800), + }, + 'NRF54H_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x0FFF8000, 0x0FFF8800), + 'NRFDL_DEVICE_CORE_NETWORK': (0x0FFFA000, 0x0FFFA800), + }, + 'NRF91_FAMILY': { + 'NRFDL_DEVICE_CORE_APPLICATION': (0x00FF8000, 0x00FF8800), + } +} + class NrfBinaryRunner(ZephyrBinaryRunner): '''Runner front-end base class for nrf tools.''' def __init__(self, cfg, family, softreset, dev_id, erase=False, - reset=True, tool_opt=[], force=False, recover=False): + reset=True, tool_opt=[], force=False, recover=False, + erase_all_uicrs=False): super().__init__(cfg) self.hex_ = cfg.hex_file if family and not family.endswith('_FAMILY'): @@ -40,6 +55,7 @@ def __init__(self, cfg, family, softreset, dev_id, erase=False, self.reset = bool(reset) self.force = force self.recover = bool(recover) + self.erase_all_uicrs = bool(erase_all_uicrs) self.tool_opt = [] for opts in [shlex.split(opt) for opt in tool_opt]: @@ -59,7 +75,8 @@ def dev_id_help(cls) -> str: @classmethod def do_add_parser(cls, parser): parser.add_argument('--nrf-family', - choices=['NRF51', 'NRF52', 'NRF53', 'NRF91'], + choices=['NRF51', 'NRF52', 'NRF53', 'NRF54L', + 'NRF54H', 'NRF91'], help='''MCU family; still accepted for compatibility only''') parser.add_argument('--softreset', required=False, @@ -75,6 +92,11 @@ def do_add_parser(cls, parser): help='''erase all user available non-volatile memory and disable read back protection before flashing (erases flash for both cores on nRF53)''') + parser.add_argument('--erase-all-uicrs', required=False, + action='store_true', + help='''Erase all UICR registers before flashing + (nRF54H only). When not set, only UICR registers + present in the hex file will be erased.''') parser.set_defaults(reset=True) @@ -161,6 +183,10 @@ def ensure_family(self): self.family = 'NRF52_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF53X'): self.family = 'NRF53_FAMILY' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54LX'): + self.family = 'NRF54L_FAMILY' + elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF54HX'): + self.family = 'NRF54H_FAMILY' elif self.build_conf.getboolean('CONFIG_SOC_SERIES_NRF91X'): self.family = 'NRF91_FAMILY' else: @@ -172,21 +198,15 @@ def hex_refers_region(self, region_start, region_end): return True return False - def hex_has_uicr_content(self): - # A map from SoCs which need this check to their UICR address - # ranges. If self.family isn't in here, do nothing. - uicr_ranges = { - 'NRF53': ((0x00FF8000, 0x00FF8800), - (0x01FF8000, 0x01FF8800)), - 'NRF91': ((0x00FF8000, 0x00FF8800),), - } + def hex_get_uicrs(self): + hex_uicrs = {} - if self.family not in uicr_ranges: - return + if self.family in UICR_RANGES: + for uicr_core, uicr_range in UICR_RANGES[self.family].items(): + if self.hex_refers_region(*uicr_range): + hex_uicrs[uicr_core] = uicr_range - for region_start, region_end in uicr_ranges[self.family]: - if self.hex_refers_region(region_start, region_end): - return True + return hex_uicrs def flush(self, force=False): try: @@ -211,7 +231,7 @@ def flush(self, force=False): # If there are data in the UICR region it is likely that the # verify failed du to the UICR not been erased before, so giving # a warning here will hopefully enhance UX. - if self.hex_has_uicr_content(): + if self.hex_get_uicrs(): self.logger.warning( 'The hex file contains data placed in the UICR, which ' 'may require a full erase before reprogramming. Run ' @@ -264,11 +284,24 @@ def program_hex(self): if self.family == 'NRF53_FAMILY': # nRF53 requires special treatment due to the extra coprocessor. self.program_hex_nrf53(erase_arg, qspi_erase_opt) + elif self.family == 'NRF54H_FAMILY': + self.program_hex_nrf54h() else: self.op_program(self.hex_, erase_arg, qspi_erase_opt, defer=True) self.flush(force=False) + def program_hex_nrf54h(self): + if self.erase_all_uicrs: + uicrs = UICR_RANGES['NRF54H_FAMILY'] + else: + uicrs = self.hex_get_uicrs() + + for uicr_core, range in uicrs.items(): + self.exec_op('erasepage', defer=True, core=uicr_core, page=range[0]) + + self.op_program(self.hex_, 'NO_ERASE', None, defer=True) + def program_hex_nrf53(self, erase_arg, qspi_erase_opt): # program_hex() helper for nRF53. diff --git a/scripts/west_commands/runners/nrfjprog.py b/scripts/west_commands/runners/nrfjprog.py index 8762ce0e740..723080d56c3 100644 --- a/scripts/west_commands/runners/nrfjprog.py +++ b/scripts/west_commands/runners/nrfjprog.py @@ -32,7 +32,8 @@ def do_create(cls, cfg, args): args.dev_id, erase=args.erase, reset=args.reset, tool_opt=args.tool_opt, force=args.force, - recover=args.recover) + recover=args.recover, + erase_all_uicrs=args.erase_all_uicrs) def do_get_boards(self): snrs = self.check_output(['nrfjprog', '--ids']) @@ -46,7 +47,8 @@ def do_exec_op(self, op, force=False): # Translate the op families = {'NRF51_FAMILY': 'NRF51', 'NRF52_FAMILY': 'NRF52', - 'NRF53_FAMILY': 'NRF53', 'NRF91_FAMILY': 'NRF91'} + 'NRF53_FAMILY': 'NRF53', 'NRF54L_FAMILY': 'NRF54L', + 'NRF54H_FAMILY': 'NRF54H', 'NRF91_FAMILY': 'NRF91'} cores = {'NRFDL_DEVICE_CORE_APPLICATION': 'CP_APPLICATION', 'NRFDL_DEVICE_CORE_NETWORK': 'CP_NETWORK'} @@ -69,6 +71,8 @@ def do_exec_op(self, op, force=False): cmd.append('--sectorerase') elif erase == 'ERASE_PAGES_INCLUDING_UICR': cmd.append('--sectoranduicrerase') + elif erase == 'NO_ERASE': + pass else: raise RuntimeError(f'Invalid erase mode: {erase}') @@ -85,6 +89,9 @@ def do_exec_op(self, op, force=False): cmd.append('--reset') if _op['option'] == 'RESET_PIN': cmd.append('--pinreset') + elif op_type == 'erasepage': + cmd.append('--erasepage') + cmd.append(f"0x{_op['page']:08x}") else: raise RuntimeError(f'Invalid operation: {op_type}') diff --git a/scripts/west_commands/sign.py b/scripts/west_commands/sign.py index bdf9d353685..fb1de570974 100644 --- a/scripts/west_commands/sign.py +++ b/scripts/west_commands/sign.py @@ -34,9 +34,11 @@ west sign -t your_tool -- ARGS_FOR_YOUR_TOOL -The "ARGS_FOR_YOUR_TOOL" value can be any additional -arguments you want to pass to the tool, such as the location of a -signing key etc. +The "ARGS_FOR_YOUR_TOOL" value can be any additional arguments you want to +pass to the tool, such as the location of a signing key etc. Depending on +which sort of ARGS_FOR_YOUR_TOOLS you use, the `--` separator/sentinel may +not always be required. To avoid ambiguity and having to find and +understand POSIX 12.2 Guideline 10, always use `--`. See tool-specific help below for details.''' @@ -420,11 +422,53 @@ def edt_flash_params(flash): class RimageSigner(Signer): + def rimage_config_dir(self): + 'Returns the rimage/config/ directory with the highest precedence' + args = self.command.args + if args.tool_data: + conf_dir = pathlib.Path(args.tool_data) + elif self.cmake_cache.get('RIMAGE_CONFIG_PATH'): + conf_dir = pathlib.Path(self.cmake_cache['RIMAGE_CONFIG_PATH']) + else: + conf_dir = self.sof_src_dir / 'tools' / 'rimage' / 'config' + self.command.dbg(f'rimage config directory={conf_dir}') + return conf_dir + + def preprocess_toml(self, config_dir, toml_basename, subdir): + 'Runs the C pre-processor on config_dir/toml_basename.h' + + compiler_path = self.cmake_cache.get("CMAKE_C_COMPILER") + preproc_cmd = [compiler_path, '-E', str(config_dir / (toml_basename + '.h'))] + # -P removes line markers to keep the .toml output reproducible. To + # trace #includes, temporarily comment out '-P' (-f*-prefix-map + # unfortunately don't seem to make any difference here and they're + # gcc-specific) + preproc_cmd += ['-P'] + + # "REM" escapes _leading_ '#' characters from cpp and allows + # such comments to be preserved in generated/*.toml files: + # + # REM # my comment... + # + # Note _trailing_ '#' characters and comments are ignored by cpp + # and don't need any REM trick. + preproc_cmd += ['-DREM='] + + preproc_cmd += ['-I', str(self.sof_src_dir / 'src')] + preproc_cmd += ['-imacros', + str(pathlib.Path('zephyr') / 'include' / 'generated' / 'autoconf.h')] + preproc_cmd += ['-o', str(subdir / 'rimage_config.toml')] + self.command.inf(quote_sh_list(preproc_cmd)) + subprocess.run(preproc_cmd, check=True, cwd=self.build_dir) + def sign(self, command, build_dir, build_conf, formats): + self.command = command args = command.args b = pathlib.Path(build_dir) + self.build_dir = b cache = CMakeCache.from_build_dir(build_dir) + self.cmake_cache = cache # Warning: RIMAGE_TARGET in Zephyr is a duplicate of # CONFIG_RIMAGE_SIGNING_SCHEMA in SOF. @@ -441,7 +485,7 @@ def sign(self, command, build_dir, build_conf, formats): kernel_name = build_conf.get('CONFIG_KERNEL_BIN_NAME', 'zephyr') # TODO: make this a new sign.py --bootloader option. - if target in ('imx8', 'imx8m'): + if target in ('imx8', 'imx8m', 'imx8ulp'): bootloader = None kernel = str(b / 'zephyr' / f'{kernel_name}.elf') out_bin = str(b / 'zephyr' / f'{kernel_name}.ri') @@ -481,8 +525,6 @@ def sign(self, command, build_dir, build_conf, formats): #### -c sof/rimage/config/signing_schema.toml #### - cmake_toml = target + '.toml' - if not args.quiet: log.inf('Signing with tool {}'.format(tool_path)) @@ -492,19 +534,8 @@ def sign(self, command, build_dir, build_conf, formats): except ValueError: # sof is the manifest sof_src_dir = pathlib.Path(manifest.manifest_path()).parent - if '-c' in args.tool_args: - # Precedence to the arguments passed after '--': west sign ... -- -c ... - if args.tool_data: - log.wrn('--tool-data ' + args.tool_data + ' ignored, overridden by: -- -c ... ') - conf_dir = None - elif args.tool_data: - conf_dir = pathlib.Path(args.tool_data) - elif cache.get('RIMAGE_CONFIG_PATH'): - conf_dir = pathlib.Path(cache['RIMAGE_CONFIG_PATH']) - else: - conf_dir = sof_src_dir / 'tools' / 'rimage' / 'config' + self.sof_src_dir = sof_src_dir - conf_path_cmd = ['-c', str(conf_dir / cmake_toml)] if conf_dir else [] log.inf('Signing for SOC target ' + target) @@ -531,7 +562,8 @@ def sign(self, command, build_dir, build_conf, formats): sign_base = [tool_path] - # Sub-command arg '-q' takes precedence over west '-v' + # Align rimage verbosity. + # Sub-command arg 'west sign -q' takes precedence over west '-v' if not args.quiet and args.verbose: sign_base += ['-v'] * args.verbose @@ -545,8 +577,23 @@ def sign(self, command, build_dir, build_conf, formats): cmake_default_key = cache.get('RIMAGE_SIGN_KEY', 'key placeholder from sign.py') extra_ri_args += [ '-k', str(sof_src_dir / 'keys' / cmake_default_key) ] + if args.tool_data and '-c' in args.tool_args: + log.wrn('--tool-data ' + args.tool_data + ' ignored! Overridden by: -- -c ... ') + if '-c' not in sign_config_extra_args + args.tool_args: - extra_ri_args += conf_path_cmd + conf_dir = self.rimage_config_dir() + toml_basename = target + '.toml' + if ((conf_dir / toml_basename).exists() and + (conf_dir / (toml_basename + '.h')).exists()): + command.die(f"Cannot have both {toml_basename + '.h'} and {toml_basename} in {conf_dir}") + + if (conf_dir / (toml_basename + '.h')).exists(): + generated_subdir = pathlib.Path('zephyr') / 'misc' / 'generated' + self.preprocess_toml(conf_dir, toml_basename, generated_subdir) + extra_ri_args += ['-c', str(b / generated_subdir / 'rimage_config.toml')] + else: + toml_dir = conf_dir + extra_ri_args += ['-c', str(toml_dir / toml_basename)] # Warning: while not officially supported (yet?), the rimage --option that is last # on the command line currently wins in case of duplicate options. So pay @@ -554,8 +601,7 @@ def sign(self, command, build_dir, build_conf, formats): sign_base += (['-o', out_bin] + sign_config_extra_args + extra_ri_args + args.tool_args + components) - if not args.quiet: - log.inf(quote_sh_list(sign_base)) + command.inf(quote_sh_list(sign_base)) subprocess.check_call(sign_base) if no_manifest: diff --git a/scripts/west_commands/zspdx/walker.py b/scripts/west_commands/zspdx/walker.py index c809ac40318..0c6469444ed 100644 --- a/scripts/west_commands/zspdx/walker.py +++ b/scripts/west_commands/zspdx/walker.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 import os +import yaml from west import log from west.util import west_topdir, WestNotFound @@ -74,6 +75,11 @@ def makeDocuments(self): log.inf("parsing CMake Cache file") self.getCacheFile() + # check if meta file is generated + if not self.metaFile: + log.err("CONFIG_BUILD_OUTPUT_META must be enabled to generate spdx files; bailing") + return False + # parse codemodel from Walker cfg's build dir log.inf("parsing CMake Codemodel files") self.cm = self.getCodemodel() @@ -108,6 +114,7 @@ def getCacheFile(self): if self.cmakeCache: self.compilerPath = self.cmakeCache.get("CMAKE_C_COMPILER", "") self.sdkPath = self.cmakeCache.get("ZEPHYR_SDK_INSTALL_DIR", "") + self.metaFile = self.cmakeCache.get("KERNEL_META_PATH", "") # determine path from build dir to CMake file-based API index file, then # parse it and return the Codemodel @@ -138,10 +145,35 @@ def getCodemodel(self): # parse it return parseReply(indexFilePath) - # set up Documents before beginning - def setupDocuments(self): - log.dbg("setting up placeholder documents") + def setupAppDocument(self): + # set up app document + cfgApp = DocumentConfig() + cfgApp.name = "app-sources" + cfgApp.namespace = self.cfg.namespacePrefix + "/app" + cfgApp.docRefID = "DocumentRef-app" + self.docApp = Document(cfgApp) + + # also set up app sources package + cfgPackageApp = PackageConfig() + cfgPackageApp.name = "app-sources" + cfgPackageApp.spdxID = "SPDXRef-app-sources" + # relativeBaseDir is app sources dir + cfgPackageApp.relativeBaseDir = self.cm.paths_source + pkgApp = Package(cfgPackageApp, self.docApp) + self.docApp.pkgs[pkgApp.cfg.spdxID] = pkgApp + # create DESCRIBES relationship data + rd = RelationshipData() + rd.ownerType = RelationshipDataElementType.DOCUMENT + rd.ownerDocument = self.docApp + rd.otherType = RelationshipDataElementType.PACKAGEID + rd.otherPackageID = cfgPackageApp.spdxID + rd.rlnType = "DESCRIBES" + + # add it to pending relationships queue + self.pendingRelationships.append(rd) + + def setupBuildDocument(self): # set up build document cfgBuild = DocumentConfig() cfgBuild.name = "build" @@ -163,6 +195,7 @@ def setupDocuments(self): # add it to pending relationships queue self.pendingRelationships.append(rd) + def setupZephyrDocument(self, modules): # set up zephyr document cfgZephyr = DocumentConfig() cfgZephyr.name = "zephyr-sources" @@ -170,19 +203,42 @@ def setupDocuments(self): cfgZephyr.docRefID = "DocumentRef-zephyr" self.docZephyr = Document(cfgZephyr) - # also set up zephyr sources package - cfgPackageZephyr = PackageConfig() - cfgPackageZephyr.name = "zephyr-sources" - cfgPackageZephyr.spdxID = "SPDXRef-zephyr-sources" # relativeBaseDir is Zephyr sources topdir try: - cfgPackageZephyr.relativeBaseDir = west_topdir(self.cm.paths_source) + relativeBaseDir = west_topdir(self.cm.paths_source) except WestNotFound: log.err(f"cannot find west_topdir for CMake Codemodel sources path {self.cm.paths_source}; bailing") return False + + # set up zephyr sources package + cfgPackageZephyr = PackageConfig() + cfgPackageZephyr.name = "zephyr-sources" + cfgPackageZephyr.spdxID = "SPDXRef-zephyr-sources" + cfgPackageZephyr.relativeBaseDir = relativeBaseDir + pkgZephyr = Package(cfgPackageZephyr, self.docZephyr) self.docZephyr.pkgs[pkgZephyr.cfg.spdxID] = pkgZephyr + for module in modules: + module_name = module.get("name", None) + module_path = module.get("path", None) + + if not module_name: + log.err(f"cannot find module name in meta file; bailing") + return False + + # Replace "_" by "-" since it's not allowed in spdx ID + module_name = module_name.replace("_", "-") + + # set up zephyr sources package + cfgPackageZephyrModule = PackageConfig() + cfgPackageZephyrModule.name = module_name + cfgPackageZephyrModule.spdxID = "SPDXRef-" + module_name + "-sources" + cfgPackageZephyrModule.relativeBaseDir = module_path + + pkgZephyrModule = Package(cfgPackageZephyrModule, self.docZephyr) + self.docZephyr.pkgs[pkgZephyrModule.cfg.spdxID] = pkgZephyrModule + # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT @@ -194,60 +250,52 @@ def setupDocuments(self): # add it to pending relationships queue self.pendingRelationships.append(rd) - # set up app document - cfgApp = DocumentConfig() - cfgApp.name = "app-sources" - cfgApp.namespace = self.cfg.namespacePrefix + "/app" - cfgApp.docRefID = "DocumentRef-app" - self.docApp = Document(cfgApp) - - # also set up app sources package - cfgPackageApp = PackageConfig() - cfgPackageApp.name = "app-sources" - cfgPackageApp.spdxID = "SPDXRef-app-sources" - # relativeBaseDir is app sources dir - cfgPackageApp.relativeBaseDir = self.cm.paths_source - pkgApp = Package(cfgPackageApp, self.docApp) - self.docApp.pkgs[pkgApp.cfg.spdxID] = pkgApp + def setupSDKDocument(self): + # set up SDK document + cfgSDK = DocumentConfig() + cfgSDK.name = "sdk" + cfgSDK.namespace = self.cfg.namespacePrefix + "/sdk" + cfgSDK.docRefID = "DocumentRef-sdk" + self.docSDK = Document(cfgSDK) + + # also set up zephyr sdk package + cfgPackageSDK = PackageConfig() + cfgPackageSDK.name = "sdk" + cfgPackageSDK.spdxID = "SPDXRef-sdk" + # relativeBaseDir is SDK dir + cfgPackageSDK.relativeBaseDir = self.sdkPath + pkgSDK = Package(cfgPackageSDK, self.docSDK) + self.docSDK.pkgs[pkgSDK.cfg.spdxID] = pkgSDK # create DESCRIBES relationship data rd = RelationshipData() rd.ownerType = RelationshipDataElementType.DOCUMENT - rd.ownerDocument = self.docApp + rd.ownerDocument = self.docSDK rd.otherType = RelationshipDataElementType.PACKAGEID - rd.otherPackageID = cfgPackageApp.spdxID + rd.otherPackageID = cfgPackageSDK.spdxID rd.rlnType = "DESCRIBES" # add it to pending relationships queue self.pendingRelationships.append(rd) - if self.cfg.includeSDK: - # set up SDK document - cfgSDK = DocumentConfig() - cfgSDK.name = "sdk" - cfgSDK.namespace = self.cfg.namespacePrefix + "/sdk" - cfgSDK.docRefID = "DocumentRef-sdk" - self.docSDK = Document(cfgSDK) - - # also set up zephyr sdk package - cfgPackageSDK = PackageConfig() - cfgPackageSDK.name = "sdk" - cfgPackageSDK.spdxID = "SPDXRef-sdk" - # relativeBaseDir is SDK dir - cfgPackageSDK.relativeBaseDir = self.sdkPath - pkgSDK = Package(cfgPackageSDK, self.docSDK) - self.docSDK.pkgs[pkgSDK.cfg.spdxID] = pkgSDK - - # create DESCRIBES relationship data - rd = RelationshipData() - rd.ownerType = RelationshipDataElementType.DOCUMENT - rd.ownerDocument = self.docSDK - rd.otherType = RelationshipDataElementType.PACKAGEID - rd.otherPackageID = cfgPackageSDK.spdxID - rd.rlnType = "DESCRIBES" + # set up Documents before beginning + def setupDocuments(self): + log.dbg("setting up placeholder documents") - # add it to pending relationships queue - self.pendingRelationships.append(rd) + self.setupBuildDocument() + + try: + with open(self.metaFile) as file: + content = yaml.load(file.read(), yaml.SafeLoader) + self.setupZephyrDocument(content["modules"]) + except (FileNotFoundError, yaml.YAMLError): + log.err(f"cannot find a valid zephyr_meta.yml required for SPDX generation; bailing") + return False + + self.setupAppDocument() + + if self.cfg.includeSDK: + self.setupSDKDocument() return True @@ -497,6 +545,7 @@ def walkPendingSources(self): # not yet assigned; figure out where it goes pkgBuild = self.findBuildPackage(srcAbspath) + pkgZephyr = self.findZephyrPackage(srcAbspath) if pkgBuild: log.dbg(f" - {srcAbspath}: assigning to build document, package {pkgBuild.cfg.name}") @@ -510,7 +559,7 @@ def walkPendingSources(self): log.dbg(f" - {srcAbspath}: assigning to app document") srcDoc = self.docApp srcPkg = pkgApp - elif os.path.commonpath([srcAbspath, pkgZephyr.cfg.relativeBaseDir]) == pkgZephyr.cfg.relativeBaseDir: + elif pkgZephyr: log.dbg(f" - {srcAbspath}: assigning to zephyr document") srcDoc = self.docZephyr srcPkg = pkgZephyr @@ -533,16 +582,16 @@ def walkPendingSources(self): srcDoc.fileLinks[sf.abspath] = sf self.allFileLinks[sf.abspath] = srcDoc - # figure out which build Package contains the given file, if any + # figure out which Package contains the given file, if any # call with: # 1) absolute path for source filename being searched - def findBuildPackage(self, srcAbspath): + def findPackageFromSrcAbsPath(self, document, srcAbspath): # Multiple target Packages might "contain" the file path, if they # are nested. If so, the one with the longest path would be the # most deeply-nested target directory, so that's the one which # should get the file path. pkgLongestMatch = None - for pkg in self.docBuild.pkgs.values(): + for pkg in document.pkgs.values(): if os.path.commonpath([srcAbspath, pkg.cfg.relativeBaseDir]) == pkg.cfg.relativeBaseDir: # the package does contain this file; is it the deepest? if pkgLongestMatch: @@ -554,6 +603,12 @@ def findBuildPackage(self, srcAbspath): return pkgLongestMatch + def findBuildPackage(self, srcAbspath): + return self.findPackageFromSrcAbsPath(self.docBuild, srcAbspath) + + def findZephyrPackage(self, srcAbspath): + return self.findPackageFromSrcAbsPath(self.docZephyr, srcAbspath) + # walk through pending RelationshipData entries, create corresponding # Relationships, and assign them to the applicable Files / Packages def walkRelationships(self): diff --git a/share/sysbuild/CMakeLists.txt b/share/sysbuild/CMakeLists.txt index 8a15da9cef5..9133fe874ef 100644 --- a/share/sysbuild/CMakeLists.txt +++ b/share/sysbuild/CMakeLists.txt @@ -38,7 +38,9 @@ get_property(IMAGES GLOBAL PROPERTY sysbuild_images) sysbuild_module_call(PRE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) sysbuild_images_order(IMAGES_CONFIGURATION_ORDER CONFIGURE IMAGES ${IMAGES}) foreach(image ${IMAGES_CONFIGURATION_ORDER}) + sysbuild_module_call(PRE_IMAGE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES} IMAGE ${image}) ExternalZephyrProject_Cmake(APPLICATION ${image}) + sysbuild_module_call(POST_IMAGE_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES} IMAGE ${image}) endforeach() sysbuild_module_call(POST_CMAKE MODULES ${SYSBUILD_MODULE_NAMES} IMAGES ${IMAGES}) diff --git a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake index 9250c209c50..fea359f475b 100644 --- a/share/sysbuild/cmake/modules/sysbuild_extensions.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_extensions.cmake @@ -268,14 +268,12 @@ function(ExternalZephyrProject_Add) ) endif() - # Check for sysbuild related configuration fragments. - # The contents of these are appended to the image existing configuration - # when user is not specifying custom fragments. - if(NOT "${CONF_FILE_BUILD_TYPE}" STREQUAL "") - set(sysbuild_image_conf_fragment ${sysbuild_image_conf_dir}/${ZBUILD_APPLICATION}_${CONF_FILE_BUILD_TYPE}.conf) - else() - set(sysbuild_image_conf_fragment ${sysbuild_image_conf_dir}/${ZBUILD_APPLICATION}.conf) - endif() + # Check for sysbuild related configuration fragments. + # The contents of these are appended to the image existing configuration + # when user is not specifying custom fragments. + zephyr_file(CONF_FILES ${sysbuild_image_conf_dir} KCONF sysbuild_image_conf_fragment + NAMES ${ZBUILD_APPLICATION}.conf SUFFIX ${FILE_SUFFIX} + ) if (NOT (${ZBUILD_APPLICATION}_OVERLAY_CONFIG OR ${ZBUILD_APPLICATION}_EXTRA_CONF_FILE) AND EXISTS ${sysbuild_image_conf_fragment} @@ -511,34 +509,55 @@ function(ExternalZephyrProject_Cmake) endfunction() # Usage: -# sysbuild_module_call( MODULES [IMAGES ] [EXTRA_ARGS ]) +# sysbuild_module_call( MODULES IMAGES [IMAGE ] [EXTRA_ARGS ]) # # This function invokes the sysbuild hook provided as for . # -# If `IMAGES` is passed, then the provided list of of images will be passed to -# the hook. +# `IMAGES` contains the list of images to the hook, if `IMAGE` is passed, this will be provided +# to the hook. # # `EXTRA_ARGS` can be used to pass extra arguments to the hook. # # Valid values: -# PRE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for images -# POST_CMAKE : Invoke post-CMake call for modules after CMake configure has been invoked for images -# PRE_DOMAINS : Invoke pre-domains call for modules before creating domains yaml. -# POST_DOMAINS: Invoke post-domains call for modules after creation of domains yaml. +# PRE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for images +# POST_CMAKE : Invoke post-CMake call for modules after CMake configure has been invoked for +# PRE_IMAGE_CMAKE : Invoke pre-CMake call for modules before CMake configure is invoked for each +# image +# POST_IMAGE_CMAKE: Invoke post-CMake call for modules after CMake configure has been invoked for +# each image +# PRE_DOMAINS : Invoke pre-domains call for modules before creating domains yaml +# POST_DOMAINS : Invoke post-domains call for modules after creation of domains yaml +# +# For the `PRE_IMAGE_CMAKE` and `POST_IMAGE_CMAKE` hooks, `IMAGE` is provided # function(sysbuild_module_call) - set(options "PRE_CMAKE;POST_CMAKE;PRE_DOMAINS;POST_DOMAINS") - set(multi_args "MODULES;IMAGES;EXTRA_ARGS") + set(options "PRE_CMAKE;POST_CMAKE;PRE_IMAGE_CMAKE;POST_IMAGE_CMAKE;PRE_DOMAINS;POST_DOMAINS") + set(multi_args "MODULES;IMAGES;IMAGE;EXTRA_ARGS") cmake_parse_arguments(SMC "${options}" "${test_args}" "${multi_args}" ${ARGN}) zephyr_check_flags_required("sysbuild_module_call" SMC ${options}) zephyr_check_flags_exclusive("sysbuild_module_call" SMC ${options}) + if(NOT DEFINED SMC_IMAGES) + message(FATAL_ERROR + "sysbuild_module_call(...) missing required IMAGES option") + endif() + + if(DEFINED SMC_IMAGE) + set(IMAGE_ARG IMAGE ${SMC_IMAGE}) + elseif(SMC_PRE_IMAGE_CMAKE) + message(FATAL_ERROR + "sysbuild_module_call(PRE_IMAGE_CMAKE ...) missing required IMAGE option") + elseif(SMC_POST_IMAGE_CMAKE) + message(FATAL_ERROR + "sysbuild_module_call(POST_IMAGE_CMAKE ...) missing required IMAGE option") + endif() + foreach(call ${options}) if(SMC_${call}) foreach(module ${SMC_MODULES}) if(COMMAND ${module}_${call}) - cmake_language(CALL ${module}_${call} IMAGES ${SMC_IMAGES} ${SMC_EXTRA_ARGS}) + cmake_language(CALL ${module}_${call} IMAGES ${SMC_IMAGES} ${IMAGE_ARG} ${SMC_EXTRA_ARGS}) endif() endforeach() endif() diff --git a/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake b/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake index 12ab32e55c2..23932d4494f 100644 --- a/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake +++ b/share/sysbuild/cmake/modules/sysbuild_kconfig.cmake @@ -67,6 +67,9 @@ if(DEFINED BOARD_REVISION) set(BOARD_REVISION_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/empty.conf") endif() +# Unset shield configuration files if set to prevent including in sysbuild +set(shield_conf_files) + list(APPEND ZEPHYR_KCONFIG_MODULES_DIR BOARD=${BOARD}) set(KCONFIG_NAMESPACE SB_CONFIG) diff --git a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake index 5594109668b..0da5a89ce11 100644 --- a/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake +++ b/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake @@ -27,11 +27,3 @@ foreach(loopkeytype ${keytypes}) set_config_bool(${ZCMAKE_APPLICATION} ${loopkeytype} n) endif() endforeach() - -if(SB_CONFIG_BOOTLOADER_MCUBOOT) - if("${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE") - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE y) - else() - set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE n) - endif() -endif() diff --git a/share/sysbuild/images/bootloader/CMakeLists.txt b/share/sysbuild/images/bootloader/CMakeLists.txt index 2a0f12f958d..c82f0808c66 100644 --- a/share/sysbuild/images/bootloader/CMakeLists.txt +++ b/share/sysbuild/images/bootloader/CMakeLists.txt @@ -10,8 +10,8 @@ if(SB_CONFIG_BOOTLOADER_MCUBOOT) SOURCE_DIR ${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/zephyr/ APP_TYPE BOOTLOADER ) - # MCUBoot default configuration is to perform a full chip erase. - # Placing MCUBoot first in list to ensure it is flashed before other images. + # Place MCUBoot first in list to ensure it is configured and flashed before other images. + sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} ${image}) sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} ${image}) set_config_string(${image} CONFIG_BOOT_SIGNATURE_KEY_FILE "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}") diff --git a/share/sysbuild/images/bootloader/Kconfig b/share/sysbuild/images/bootloader/Kconfig index e8c788f72c5..d8e1bf70d75 100644 --- a/share/sysbuild/images/bootloader/Kconfig +++ b/share/sysbuild/images/bootloader/Kconfig @@ -56,7 +56,7 @@ config BOOT_SIGNATURE_TYPE_ED25519 endchoice config BOOT_SIGNATURE_KEY_FILE - string "Signing PEM key file" + string "Signing PEM key file" if !BOOT_SIGNATURE_TYPE_NONE default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-ed25519.pem" if BOOT_SIGNATURE_TYPE_ED25519 default "$(ZEPHYR_MCUBOOT_MODULE_DIR)/root-rsa-2048.pem" if BOOT_SIGNATURE_TYPE_RSA diff --git a/share/zephyr-package/cmake/zephyr_export.cmake b/share/zephyr-package/cmake/zephyr_export.cmake index a9493f683b8..8d89483ad9d 100644 --- a/share/zephyr-package/cmake/zephyr_export.cmake +++ b/share/zephyr-package/cmake/zephyr_export.cmake @@ -8,15 +8,7 @@ # # Create the reference by running `cmake -P zephyr_export.cmake` in this directory. -set(MD5_INFILE "current_path.txt") - -# We write CMAKE_CURRENT_LIST_DIR into MD5_INFILE, as the content of that file will be used for MD5 calculation. -# This means we effectively get the MD5 of CMAKE_CURRENT_LIST_DIR which must be used for CMake user package registry. -file(WRITE ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} ${CMAKE_CURRENT_LIST_DIR}) -execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} - OUTPUT_VARIABLE MD5_SUM -) -string(SUBSTRING ${MD5_SUM} 0 32 MD5_SUM) +string(MD5 MD5_SUM ${CMAKE_CURRENT_LIST_DIR}) if(WIN32) execute_process(COMMAND ${CMAKE_COMMAND} -E write_regv diff --git a/share/zephyrunittest-package/cmake/zephyr_export.cmake b/share/zephyrunittest-package/cmake/zephyr_export.cmake index a0a65b2e090..de395c3112f 100644 --- a/share/zephyrunittest-package/cmake/zephyr_export.cmake +++ b/share/zephyrunittest-package/cmake/zephyr_export.cmake @@ -8,15 +8,7 @@ # # Create the reference by running `cmake -P zephyr_export.cmake` in this directory. -set(MD5_INFILE "current_path.txt") - -# We write CMAKE_CURRENT_LIST_DIR into MD5_INFILE, as the content of that file will be used for MD5 calculation. -# This means we effectively get the MD5 of CMAKE_CURRENT_LIST_DIR which must be used for CMake user package registry. -file(WRITE ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} ${CMAKE_CURRENT_LIST_DIR}) -execute_process(COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_LIST_DIR}/${MD5_INFILE} - OUTPUT_VARIABLE MD5_SUM -) -string(SUBSTRING ${MD5_SUM} 0 32 MD5_SUM) +string(MD5 MD5_SUM ${CMAKE_CURRENT_LIST_DIR}) if(WIN32) execute_process(COMMAND ${CMAKE_COMMAND} -E write_regv diff --git a/snippets/nordic-ppr/README.rst b/snippets/nordic-ppr/README.rst new file mode 100644 index 00000000000..36eb74d193f --- /dev/null +++ b/snippets/nordic-ppr/README.rst @@ -0,0 +1,10 @@ +.. _nordic-ppr: + +Nordic PPR snippet (nordic-ppr) +############################### + +Overview +******** + +This snippet allows users to build Zephyr with the capability to boot Nordic PPR +(Peripheral Processor) from another core. diff --git a/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay b/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..75128f42a13 --- /dev/null +++ b/snippets/nordic-ppr/boards/nrf54h20pdk_nrf54h20_cpuapp.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuppr_ram3x_region { + status = "okay"; +}; + +&uart135 { + status = "reserved"; +}; diff --git a/snippets/nordic-ppr/nordic-ppr.overlay b/snippets/nordic-ppr/nordic-ppr.overlay new file mode 100644 index 00000000000..e33885fc10d --- /dev/null +++ b/snippets/nordic-ppr/nordic-ppr.overlay @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor + * SPDX-License-Identifier: Apache-2.0 + */ + +&cpuppr_vpr { + status = "okay"; +}; diff --git a/snippets/nordic-ppr/snippet.yml b/snippets/nordic-ppr/snippet.yml new file mode 100644 index 00000000000..9e1f20bb757 --- /dev/null +++ b/snippets/nordic-ppr/snippet.yml @@ -0,0 +1,8 @@ +name: nordic-ppr +append: + EXTRA_DTC_OVERLAY_FILE: nordic-ppr.overlay + +boards: + nrf54h20pdk_nrf54h20_cpuapp: + append: + EXTRA_DTC_OVERLAY_FILE: boards/nrf54h20pdk_nrf54h20_cpuapp.overlay diff --git a/snippets/xen_dom0/xen_dom0.overlay b/snippets/xen_dom0/xen_dom0.overlay index 98fe1e39d67..74642eb6b82 100644 --- a/snippets/xen_dom0/xen_dom0.overlay +++ b/snippets/xen_dom0/xen_dom0.overlay @@ -19,7 +19,7 @@ }; xen_consoleio_hvc: hvc { - compatible = "xen,uart_hvc"; + compatible = "xen,hvc-consoleio"; status = "okay"; }; }; diff --git a/soc/CMakeLists.txt b/soc/CMakeLists.txt index 6706168281e..d55bd63f496 100644 --- a/soc/CMakeLists.txt +++ b/soc/CMakeLists.txt @@ -9,6 +9,8 @@ if(_SOC_IS_IN_TREE) endif() unset(_SOC_IS_IN_TREE) +add_subdirectory(common) + if(EXISTS ${SOC_DIR}/${ARCH}/CMakeLists.txt) add_subdirectory(${SOC_DIR}/${ARCH} soc/${ARCH}) else() diff --git a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc index be4331ad48b..6354c659d30 100644 --- a/soc/arc/snps_arc_hsdk4xd/Kconfig.soc +++ b/soc/arc/snps_arc_hsdk4xd/Kconfig.soc @@ -5,4 +5,4 @@ config SOC_ARC_HSDK4XD bool "Synopsys ARC HSDK4XD SoC" select ARC select CPU_HAS_FPU - select ARC_HAS_DSP + select CPU_HAS_DSP diff --git a/soc/arc/snps_emsdp/Kconfig.soc b/soc/arc/snps_emsdp/Kconfig.soc index a1358b8ad9d..ed0a2f88e20 100644 --- a/soc/arc/snps_emsdp/Kconfig.soc +++ b/soc/arc/snps_emsdp/Kconfig.soc @@ -4,4 +4,3 @@ config SOC_ARC_EMSDP bool "Synopsys ARC EM Software Development Platform" select ARC - select HAS_SPI_DW if SPI diff --git a/soc/arc/snps_emsk/Kconfig.soc b/soc/arc/snps_emsk/Kconfig.soc index 9b6e50abe60..d172c4144a7 100644 --- a/soc/arc/snps_emsk/Kconfig.soc +++ b/soc/arc/snps_emsk/Kconfig.soc @@ -5,4 +5,3 @@ config SOC_EMSK bool "Synopsys ARC EM Starter Kit SoC" select ARC - select HAS_SPI_DW if SPI diff --git a/soc/arc/snps_nsim/Kconfig b/soc/arc/snps_nsim/Kconfig index 62b74e8a743..cdf2ec69cae 100644 --- a/soc/arc/snps_nsim/Kconfig +++ b/soc/arc/snps_nsim/Kconfig @@ -18,7 +18,7 @@ config SOC_NSIM_EM7D_V22 config SOC_NSIM_EM11D bool "Synopsys ARC EM11D in nSIM" select CPU_HAS_MPU - select ARC_HAS_DSP + select CPU_HAS_DSP config SOC_NSIM_SEM bool "Synopsys ARC SEM in nSIM" diff --git a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p index 2d672184b4b..3e465e71ddb 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p +++ b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p @@ -7,12 +7,4 @@ if SOC_APOLLO4P config NUM_IRQS default 83 -DT_NODE_SRAM := /memory@0 - -config SRAM_NC_SIZE - default $(dt_node_reg_size_int,$(DT_NODE_SRAM),1,K) - -config SRAM_NC_BASE_ADDRESS - default $(dt_node_reg_addr_hex,$(DT_NODE_SRAM),1) - endif # SOC_APOLLO4P diff --git a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue index 2d791dd4a46..3a96b8b6022 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue +++ b/soc/arm/ambiq/apollo4x/Kconfig.defconfig.apollo4p_blue @@ -7,12 +7,4 @@ if SOC_APOLLO4P_BLUE config NUM_IRQS default 83 -DT_NODE_SRAM := /memory@0 - -config SRAM_NC_SIZE - default $(dt_node_reg_size_int,$(DT_NODE_SRAM),1,K) - -config SRAM_NC_BASE_ADDRESS - default $(dt_node_reg_addr_hex,$(DT_NODE_SRAM),1) - endif # SOC_APOLLO4P_BLUE diff --git a/soc/arm/ambiq/apollo4x/Kconfig.series b/soc/arm/ambiq/apollo4x/Kconfig.series index b7982d3609e..a9e72567206 100644 --- a/soc/arm/ambiq/apollo4x/Kconfig.series +++ b/soc/arm/ambiq/apollo4x/Kconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES_APOLLO4X select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select CPU_HAS_ARM_MPU select SOC_FAMILY_AMBIQ select HAS_SWO select AMBIQ_HAL diff --git a/soc/arm/arm/designstart/soc.h b/soc/arm/arm/designstart/soc.h index ec58467f923..a9bcdb4e9cd 100644 --- a/soc/arm/arm/designstart/soc.h +++ b/soc/arm/arm/designstart/soc.h @@ -7,7 +7,6 @@ #ifndef _SOC_H_ #define _SOC_H_ - -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include #endif /* _SOC_H_ */ diff --git a/soc/arm/arm/mps2/soc.h b/soc/arm/arm/mps2/soc.h index 594d3d084c1..822c7ee01bd 100644 --- a/soc/arm/arm/mps2/soc.h +++ b/soc/arm/arm/mps2/soc.h @@ -7,15 +7,7 @@ #ifndef _SOC_H_ #define _SOC_H_ -#define __MPU_PRESENT 1 - -#if defined(CONFIG_SOC_MPS2_AN521) -#define __SAUREGION_PRESENT CONFIG_CPU_HAS_ARM_SAU -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __DSP_PRESENT CONFIG_ARMV8_M_DSP - -#endif - +#include #include extern void wakeup_cpu1(void); diff --git a/soc/arm/arm/mps3/Kconfig.soc b/soc/arm/arm/mps3/Kconfig.soc index 86970e288cc..ae577fa549b 100644 --- a/soc/arm/arm/mps3/Kconfig.soc +++ b/soc/arm/arm/mps3/Kconfig.soc @@ -14,5 +14,10 @@ config SOC_MPS3_AN547 select ARMV8_M_DSP select ARMV8_1_M_MVEI select ARMV8_1_M_MVEF + select ARMV8_1_M_PMU endchoice + +config ARMV8_1_M_PMU_EVENTCNT + int + default 8 if SOC_MPS3_AN547 diff --git a/soc/arm/arm/mps3/soc.h b/soc/arm/arm/mps3/soc.h index 6a325074cf2..c3a59da1c0d 100644 --- a/soc/arm/arm/mps3/soc.h +++ b/soc/arm/arm/mps3/soc.h @@ -7,19 +7,6 @@ #ifndef _SOC_H_ #define _SOC_H_ -#define __MPU_PRESENT 1 - -#if defined(CONFIG_SOC_MPS3_AN547) -#define __SAUREGION_PRESENT 1U /* SAU regions present */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __DSP_PRESENT 1U /* DSP extension present */ -#define __MVE_PRESENT 1U /* MVE extensions present */ -#define __MVE_FP 1U /* MVE floating point present */ -#define __ICACHE_PRESENT 1U /* ICACHE present */ -#define __DCACHE_PRESENT 1U /* DCACHE present */ -#define __PMU_PRESENT 1U /* PMU present */ -#define __PMU_NUM_EVENTCNT 8U /* PMU Event Counters */ -#endif - +#include #endif /* _SOC_H_ */ diff --git a/soc/arm/arm/musca_s1/Kconfig.soc b/soc/arm/arm/musca_s1/Kconfig.soc index 9bf02614308..0c0763fae2a 100644 --- a/soc/arm/arm/musca_s1/Kconfig.soc +++ b/soc/arm/arm/musca_s1/Kconfig.soc @@ -11,5 +11,7 @@ config SOC_V2M_MUSCA_S1 select CPU_HAS_ARM_SAU select CPU_HAS_ARM_MPU select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select ARMV8_M_DSP endchoice diff --git a/soc/arm/aspeed/ast10x0/soc.h b/soc/arm/aspeed/ast10x0/soc.h index f45df84c128..be1cced5da2 100644 --- a/soc/arm/aspeed/ast10x0/soc.h +++ b/soc/arm/aspeed/ast10x0/soc.h @@ -25,4 +25,6 @@ void aspeed_print_sysrst_info(void); +#include + #endif /* ZEPHYR_SOC_ARM_ASPEED_AST10X0_SOC_H_*/ diff --git a/soc/arm/atmel_sam/common/CMakeLists.txt b/soc/arm/atmel_sam/common/CMakeLists.txt index 2d5a6c35a33..3fe8bdd1d6d 100644 --- a/soc/arm/atmel_sam/common/CMakeLists.txt +++ b/soc/arm/atmel_sam/common/CMakeLists.txt @@ -4,6 +4,7 @@ zephyr_include_directories(.) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_pmc.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_gpio.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_supc.c) +zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_power.c) zephyr_library_sources_ifndef(CONFIG_SOC_SERIES_SAM4L soc_poweroff.c) zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_SAM4L soc_sam4l_pm.c) diff --git a/soc/arm/atmel_sam/common/soc_pmc.h b/soc/arm/atmel_sam/common/soc_pmc.h index 8f31e24dbbe..3be251a3d09 100644 --- a/soc/arm/atmel_sam/common/soc_pmc.h +++ b/soc/arm/atmel_sam/common/soc_pmc.h @@ -1,5 +1,7 @@ /* * Copyright (c) 2016 Piotr Mienkowski + * Copyright (c) 2023 Basalte bv + * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,7 +13,11 @@ #ifndef _ATMEL_SAM_SOC_PMC_H_ #define _ATMEL_SAM_SOC_PMC_H_ +#include +#include +#include #include +#include /** * @brief Enable the clock of specified peripheral module. @@ -35,4 +41,483 @@ void soc_pmc_peripheral_disable(uint32_t id); */ uint32_t soc_pmc_peripheral_is_enabled(uint32_t id); +#if !defined(CONFIG_SOC_SERIES_SAM4L) + +enum soc_pmc_fast_rc_freq { +#if defined(CKGR_MOR_MOSCRCF_4_MHz) + SOC_PMC_FAST_RC_FREQ_4MHZ = CKGR_MOR_MOSCRCF_4_MHz, +#endif +#if defined(CKGR_MOR_MOSCRCF_8_MHz) + SOC_PMC_FAST_RC_FREQ_8MHZ = CKGR_MOR_MOSCRCF_8_MHz, +#endif +#if defined(CKGR_MOR_MOSCRCF_12_MHz) + SOC_PMC_FAST_RC_FREQ_12MHZ = CKGR_MOR_MOSCRCF_12_MHz, +#endif +}; + +enum soc_pmc_mck_src { +#if defined(PMC_MCKR_CSS_SLOW_CLK) + SOC_PMC_MCK_SRC_SLOW_CLK = PMC_MCKR_CSS_SLOW_CLK, +#endif +#if defined(PMC_MCKR_CSS_MAIN_CLK) + SOC_PMC_MCK_SRC_MAIN_CLK = PMC_MCKR_CSS_MAIN_CLK, +#endif +#if defined(PMC_MCKR_CSS_PLLA_CLK) + SOC_PMC_MCK_SRC_PLLA_CLK = PMC_MCKR_CSS_PLLA_CLK, +#endif +#if defined(PMC_MCKR_CSS_PLLB_CLK) + SOC_PMC_MCK_SRC_PLLB_CLK = PMC_MCKR_CSS_PLLB_CLK, +#endif +#if defined(PMC_MCKR_CSS_UPLL_CLK) + SOC_PMC_MCK_SRC_UPLL_CLK = PMC_MCKR_CSS_UPLL_CLK, +#endif +}; + +/** + * @brief Set the prescaler of the Master clock. + * + * @param prescaler the prescaler value. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_prescaler(uint32_t prescaler) +{ + uint32_t reg_val; + + switch (prescaler) { + case 1: + reg_val = PMC_MCKR_PRES_CLK_1; + break; + case 2: + reg_val = PMC_MCKR_PRES_CLK_2; + break; + case 4: + reg_val = PMC_MCKR_PRES_CLK_4; + break; + case 8: + reg_val = PMC_MCKR_PRES_CLK_8; + break; + case 16: + reg_val = PMC_MCKR_PRES_CLK_16; + break; + case 32: + reg_val = PMC_MCKR_PRES_CLK_32; + break; + case 64: + reg_val = PMC_MCKR_PRES_CLK_64; + break; + case 3: + reg_val = PMC_MCKR_PRES_CLK_3; + break; + default: + __ASSERT(false, "Invalid MCK prescaler"); + reg_val = PMC_MCKR_PRES_CLK_1; + break; + } + + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_PRES_Msk)) | reg_val; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +#if defined(CONFIG_SOC_SERIES_SAME70) || defined(CONFIG_SOC_SERIES_SAMV71) + +/** + * @brief Set the divider of the Master clock. + * + * @param divider the divider value. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_divider(uint32_t divider) +{ + uint32_t reg_val; + + switch (divider) { + case 1: + reg_val = PMC_MCKR_MDIV_EQ_PCK; + break; + case 2: + reg_val = PMC_MCKR_MDIV_PCK_DIV2; + break; + case 3: + reg_val = PMC_MCKR_MDIV_PCK_DIV3; + break; + case 4: + reg_val = PMC_MCKR_MDIV_PCK_DIV4; + break; + default: + __ASSERT(false, "Invalid MCK divider"); + reg_val = PMC_MCKR_MDIV_EQ_PCK; + break; + } + + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_MDIV_Msk)) | reg_val; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +#endif /* CONFIG_SOC_SERIES_SAME70 || CONFIG_SOC_SERIES_SAMV71 */ + +/** + * @brief Set the source of the Master clock. + * + * @param source the source identifier. + */ +static ALWAYS_INLINE void soc_pmc_mck_set_source(enum soc_pmc_mck_src source) +{ + PMC->PMC_MCKR = (PMC->PMC_MCKR & (~PMC_MCKR_CSS_Msk)) | (uint32_t)source; + + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { + } +} + +/** + * @brief Switch main clock source selection to internal fast RC. + * + * @param freq the internal fast RC desired frequency 4/8/12MHz. + */ +static ALWAYS_INLINE void soc_pmc_switch_mainck_to_fastrc(enum soc_pmc_fast_rc_freq freq) +{ + /* Enable Fast RC oscillator but DO NOT switch to RC now */ + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Change Fast RC oscillator frequency */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD + | (uint32_t)freq; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Switch to Fast RC */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) + | CKGR_MOR_KEY_PASSWD; +} + +/** + * @brief Enable internal fast RC oscillator. + * + * @param freq the internal fast RC desired frequency 4/8/12MHz. + */ +static ALWAYS_INLINE void soc_pmc_osc_enable_fastrc(enum soc_pmc_fast_rc_freq freq) +{ + /* Enable Fast RC oscillator but DO NOT switch to RC */ + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCRCEN; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } + + /* Change Fast RC oscillator frequency */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD + | (uint32_t)freq; + + /* Wait for the Fast RC to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { + } +} + +/** + * @brief Disable internal fast RC oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_fastrc(void) +{ + /* Disable Fast RC oscillator */ + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN & ~CKGR_MOR_MOSCRCF_Msk) + | CKGR_MOR_KEY_PASSWD; +} + +/** + * @brief Check if the internal fast RC is ready. + * + * @return true if internal fast RC is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_fastrc(void) +{ + return (PMC->PMC_SR & PMC_SR_MOSCRCS); +} + +/** + * @brief Enable the external crystal oscillator. + * + * @param xtal_startup_time crystal start-up time, in number of slow clocks. + */ +static ALWAYS_INLINE void soc_pmc_osc_enable_main_xtal(uint32_t xtal_startup_time) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + mor |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCXTST(xtal_startup_time); + + PMC->CKGR_MOR = mor; + + /* Wait the main Xtal to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { + } +} + +/** + * @brief Bypass the external crystal oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_bypass_main_xtal(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + mor |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY; + + /* Enable Crystal oscillator but DO NOT switch now. Keep MOSCSEL to 0 */ + PMC->CKGR_MOR = mor; + /* The MOSCXTS in PMC_SR is automatically set */ +} + +/** + * @brief Disable the external crystal oscillator. + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_main_xtal(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + mor &= ~(CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCXTEN); + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor; +} + +/** + * @brief Check if the external crystal oscillator is bypassed. + * + * @return true if external crystal oscillator is bypassed, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_bypassed_main_xtal(void) +{ + return (PMC->CKGR_MOR & CKGR_MOR_MOSCXTBY); +} + +/** + * @brief Check if the external crystal oscillator is ready. + * + * @return true if external crystal oscillator is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_main_xtal(void) +{ + return (PMC->PMC_SR & PMC_SR_MOSCXTS); +} + +/** + * @brief Switch main clock source selection to external crystal oscillator. + * + * @param bypass select bypass or xtal + * @param xtal_startup_time crystal start-up time, in number of slow clocks + */ +static ALWAYS_INLINE void soc_pmc_switch_mainck_to_xtal(bool bypass, uint32_t xtal_startup_time) +{ + soc_pmc_osc_enable_main_xtal(xtal_startup_time); + + /* Enable Main Xtal oscillator */ + if (bypass) { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) + | CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTBY + | CKGR_MOR_MOSCSEL; + } else { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) + | CKGR_MOR_KEY_PASSWD + | CKGR_MOR_MOSCXTEN + | CKGR_MOR_MOSCXTST(xtal_startup_time); + + /* Wait for the Xtal to stabilize */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { + } + + PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL; + } +} + +/** + * @brief Disable the external crystal oscillator. + * + * @param bypass select bypass or xtal + */ +static ALWAYS_INLINE void soc_pmc_osc_disable_xtal(bool bypass) +{ + /* Disable xtal oscillator */ + if (bypass) { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) + | CKGR_MOR_KEY_PASSWD; + } else { + PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) + | CKGR_MOR_KEY_PASSWD; + } +} + +/** + * @brief Check if the main clock is ready. Depending on MOSCEL, main clock can be one + * of external crystal, bypass or internal RC. + * + * @return true if main clock is ready, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_osc_is_ready_mainck(void) +{ + return PMC->PMC_SR & PMC_SR_MOSCSELS; +} + +/** + * @brief Enable Wait Mode. + */ +static ALWAYS_INLINE void soc_pmc_enable_waitmode(void) +{ + PMC->PMC_FSMR |= PMC_FSMR_LPM; +} + +/** + * @brief Enable Clock Failure Detector. + */ +static ALWAYS_INLINE void soc_pmc_enable_clock_failure_detector(void) +{ + uint32_t mor = PMC->CKGR_MOR; + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_CFDEN | mor; +} + +/** + * @brief Disable Clock Failure Detector. + */ +static ALWAYS_INLINE void soc_pmc_disable_clock_failure_detector(void) +{ + uint32_t mor = PMC->CKGR_MOR & (~CKGR_MOR_CFDEN); + + PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor; +} + +#if defined(PMC_MCKR_CSS_PLLA_CLK) + +/** + * @brief Disable the PLLA clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_pllack(void) +{ + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | CKGR_PLLAR_MULA(0); +} + +/** + * @brief Enable the PLLA clock. + * + * @param mula PLLA multiplier + * @param pllacount PLLA lock counter, in number of slow clocks + * @param diva PLLA Divider + */ +static ALWAYS_INLINE void soc_pmc_enable_pllack(uint32_t mula, uint32_t pllacount, uint32_t diva) +{ + __ASSERT(diva > 0, "Invalid PLLA divider"); + + /* first disable the PLL to unlock the lock */ + soc_pmc_disable_pllack(); + + PMC->CKGR_PLLAR = CKGR_PLLAR_ONE + | CKGR_PLLAR_DIVA(diva) + | CKGR_PLLAR_PLLACOUNT(pllacount) + | CKGR_PLLAR_MULA(mula); + + while ((PMC->PMC_SR & PMC_SR_LOCKA) == 0) { + } +} + +/** + * @brief Check if the PLLA is locked. + * + * @return true if PLLA is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_pllack(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKA); +} + +#endif /* PMC_MCKR_CSS_PLLA_CLK */ + +#if defined(PMC_MCKR_CSS_PLLB_CLK) + +/** + * @brief Disable the PLLB clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_pllbck(void) +{ + PMC->CKGR_PLLBR = CKGR_PLLBR_MULB(0); +} + +/** + * @brief Enable the PLLB clock. + * + * @param mulb PLLB multiplier + * @param pllbcount PLLB lock counter, in number of slow clocks + * @param divb PLLB Divider + */ +static ALWAYS_INLINE void soc_pmc_enable_pllbck(uint32_t mulb, uint32_t pllbcount, uint32_t divb) +{ + __ASSERT(divb > 0, "Invalid PLLB divider"); + + /* first disable the PLL to unlock the lock */ + soc_pmc_disable_pllbck(); + + PMC->CKGR_PLLBR = CKGR_PLLBR_DIVB(divb) + | CKGR_PLLBR_PLLBCOUNT(pllbcount) + | CKGR_PLLBR_MULB(mulb); + + while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) { + } +} + +/** + * @brief Check if the PLLB is locked. + * + * @return true if PLLB is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_pllbck(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKB); +} + +#endif /* PMC_MCKR_CSS_PLLB_CLK */ + +#if defined(PMC_MCKR_CSS_UPLL_CLK) + +/** + * @brief Enable the UPLL clock. + */ +static ALWAYS_INLINE void soc_pmc_enable_upllck(uint32_t upllcount) +{ + PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(upllcount) + | CKGR_UCKR_UPLLEN; + + /* Wait UTMI PLL Lock Status */ + while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { + } +} + +/** + * @brief Disable the UPLL clock. + */ +static ALWAYS_INLINE void soc_pmc_disable_upllck(void) +{ + PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN; +} + +/** + * @brief Check if the UPLL is locked. + * + * @return true if UPLL is locked, false otherwise + */ +static ALWAYS_INLINE bool soc_pmc_is_locked_upllck(void) +{ + return (PMC->PMC_SR & PMC_SR_LOCKU); +} + +#endif /* PMC_MCKR_CSS_UPLL_CLK */ + +#endif /* !CONFIG_SOC_SERIES_SAM4L */ + #endif /* _ATMEL_SAM_SOC_PMC_H_ */ diff --git a/soc/arm/atmel_sam/common/soc_power.c b/soc/arm/atmel_sam/common/soc_power.c new file mode 100644 index 00000000000..08499b98b10 --- /dev/null +++ b/soc/arm/atmel_sam/common/soc_power.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Basalte bv + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define SAM_DT_RSTC_DRIVER DT_INST(0, atmel_sam_rstc) + +#include +#if defined(CONFIG_REBOOT) +#include +#endif + +#if defined(CONFIG_REBOOT) +#if DT_NODE_HAS_STATUS(SAM_DT_RSTC_DRIVER, okay) + +void sys_arch_reboot(int type) +{ + Rstc *regs = (Rstc *)DT_REG_ADDR(SAM_DT_RSTC_DRIVER); + + switch (type) { + case SYS_REBOOT_COLD: + regs->RSTC_CR = RSTC_CR_KEY_PASSWD + | RSTC_CR_PROCRST +#if defined(CONFIG_SOC_SERIES_SAM3X) || defined(CONFIG_SOC_SERIES_SAM4S) || \ + defined(CONFIG_SOC_SERIES_SAM4E) + | RSTC_CR_PERRST +#endif /* CONFIG_SOC_SERIES_SAM3X || CONFIG_SOC_SERIES_SAM4S || CONFIG_SOC_SERIES_SAM4E */ + ; + break; + default: + break; + } +} + +#endif /* DT_NODE_HAS_STATUS */ +#endif /* CONFIG_REBOOT */ diff --git a/soc/arm/atmel_sam/sam3x/soc.c b/soc/arm/atmel_sam/sam3x/soc.c index 6f85c2c69d7..9a20d566375 100644 --- a/soc/arm/atmel_sam/sam3x/soc.c +++ b/soc/arm/atmel_sam/sam3x/soc.c @@ -2,6 +2,7 @@ * Copyright (c) 2013-2015 Wind River Systems, Inc. * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,25 +15,9 @@ * for the Atmel SAM3X series processor. */ -#include -#include -#include #include - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 6, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (6 + 1) / 1 = 84 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK) = 84 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA)) +#include +#include /** * @brief Setup various clocks on SoC at boot time. @@ -42,167 +27,86 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK */ + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); -#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK - /* - * Setup main external crystal oscillator - */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(0); + EFC1->EEFC_FMR = EEFC_FMR_FWS(0); - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC Oscillator Frequency is at 4 MHz (default) */ - | CKGR_MOR_MOSCRCF_4_MHz - /* We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* - * Setup main fast RC oscillator - */ - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDCORE value + * rather than maximum supported 84 MHz at standard VDDCORE=1.8V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(4); + EFC1->EEFC_FMR = EEFC_FMR_FWS(4); /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 6, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (6 + 1) / 1 = 84 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK) = 84 MHz. */ - - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDCORE value - * rather than maximum supported 84 MHz at standard VDDCORE=1.8V - */ - EFC0->EEFC_FMR = EEFC_FMR_FWS(4); - EFC1->EEFC_FMR = EEFC_FMR_FWS(4); - + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks */ clock_init(); } diff --git a/soc/arm/atmel_sam/sam4e/soc.c b/soc/arm/atmel_sam/sam4e/soc.c index 33a8dd0d25f..b1c8174fddc 100644 --- a/soc/arm/atmel_sam/sam4e/soc.c +++ b/soc/arm/atmel_sam/sam4e/soc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2017 Justin Watson * Copyright (c) 2019-2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,9 +16,9 @@ * for the Atmel SAM4E series processor. */ -#include -#include #include +#include +#include /** * @brief Setup various clock on SoC at boot time. @@ -29,168 +30,75 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); -#ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK - /* Switch slow clock to the external 32 KHz crystal oscillator. */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized. */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } - -#endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK - /* - * Setup main external crystal oscillator. - */ + EFC->EEFC_FMR = EEFC_FMR_FWS(0); - /* Start the external crystal oscillator. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC oscillator frequency is at 4 MHz. */ - | CKGR_MOR_MOSCRCF_4_MHz - /* - * We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical right now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC oscillator must stay on. */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCSEL; - - /* Wait for external oscillator to be selected. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC oscillator, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for the RC oscillator to be turned off. */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM4E_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG. - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Setup main fast RC oscillator. */ - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case. + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet. + * This is set to the highest number of read cycles because it won't + * hurt lower clock frequencies. However, a high frequency with too + * few read cycles could cause flash read problems. FWS 5 (6 cycles) + * is the safe setting for all of this SoCs usable frequencies. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for RC oscillator to stabilize. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5); /* * Setup PLLA */ - - /* Switch MCK (Master Clock) to the main clock first. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA. */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM4E_PLLA_MULA) - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM4E_PLLA_DIVA); - - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. - */ - - /* Wait for PLL lock. */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM4E_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM4E_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK). */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Finally select PLL as Master Clock source. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. Look at table 44.73 in the SAM4E datasheet. - * This is set to the highest number of read cycles because it won't - * hurt lower clock frequencies. However, a high frequency with too - * few read cycles could cause flash read problems. FWS 5 (6 cycles) - * is the safe setting for all of this SoCs usable frequencies. - */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5); - + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4E_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks. */ clock_init(); } diff --git a/soc/arm/atmel_sam/sam4s/soc.c b/soc/arm/atmel_sam/sam4s/soc.c index e1041f8a2fc..5efaa35e894 100644 --- a/soc/arm/atmel_sam/sam4s/soc.c +++ b/soc/arm/atmel_sam/sam4s/soc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016 Intel Corporation. * Copyright (c) 2017 Justin Watson * Copyright (c) 2023 Gerson Fernando Budke + * Copyright (c) 2023 Basalte bv * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,9 +16,9 @@ * for the Atmel SAM4S series processor. */ -#include -#include #include +#include +#include /** * @brief Setup various clock on SoC at boot time. @@ -29,168 +30,81 @@ */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); -#ifdef CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK - /* Switch slow clock to the external 32 KHz crystal oscillator. */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL_CRYSTAL_SEL; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized. */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } - -#endif /* CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK - /* - * Setup main external crystal oscillator. - */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(0); +#if defined(ID_EFC1) + EFC1->EEFC_FMR = EEFC_FMR_FWS(0); +#endif - /* Start the external crystal oscillator. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* Fast RC oscillator frequency is at 4 MHz. */ - | CKGR_MOR_MOSCRCF_4_MHz - /* - * We select maximum setup time. While start up time - * could be shortened this optimization is not deemed - * critical right now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC oscillator must stay on. */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; - - /* Wait for oscillator to be stabilized. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + soc_pmc_enable_clock_failure_detector(); - /* Select the external crystal oscillator as the main clock source. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_4_MHz - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCSEL; - - /* Wait for external oscillator to be selected. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC oscillator, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - - /* Wait for the RC oscillator to be turned off. */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ + + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); } -#ifdef CONFIG_SOC_ATMEL_SAM4S_WAIT_MODE /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG. + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. Look at table 44.73 in the SAM4S datasheet. + * This is set to the highest number of read cycles because it won't + * hurt lower clock frequencies. However, a high frequency with too + * few read cycles could cause flash read problems. FWS 5 (6 cycles) + * is the safe setting for all of this SoCs usable frequencies. */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; + EFC0->EEFC_FMR = EEFC_FMR_FWS(5); +#if defined(ID_EFC1) + EFC1->EEFC_FMR = EEFC_FMR_FWS(5); #endif -#else - /* Setup main fast RC oscillator. */ - - /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case. - */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz. */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for RC oscillator to stabilize. */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK */ /* * Setup PLLA */ - - /* Switch MCK (Master Clock) to the main clock first. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA. */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM4S_PLLA_MULA) - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM4S_PLLA_DIVA); - - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. - */ - - /* Wait for PLL lock. */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAM4S_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAM4S_PLLA_DIVA); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ + /* prescaler has to be set before PLL lock */ + soc_pmc_mck_set_prescaler(1); - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK). */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; + /* Select PLL as Master Clock source. */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source. */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete. */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. Look at table 44.73 in the SAM4S datasheet. - * This is set to the highest number of read cycles because it won't - * hurt lower clock frequencies. However, a high frequency with too - * few read cycles could cause flash read problems. FWS 5 (6 cycles) - * is the safe setting for all of this SoCs usable frequencies. - * TODO: Add code to handle SAM4SD devices that have 2 EFCs. - */ - EFC0->EEFC_FMR = EEFC_FMR_FWS(5); + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAM4S_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); + } /* Setup system clocks. */ clock_init(); diff --git a/soc/arm/atmel_sam/same70/Kconfig.series b/soc/arm/atmel_sam/same70/Kconfig.series index 0e19a2197ba..4e7d6aa396e 100644 --- a/soc/arm/atmel_sam/same70/Kconfig.series +++ b/soc/arm/atmel_sam/same70/Kconfig.series @@ -11,7 +11,10 @@ config SOC_SERIES_SAME70 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select CPU_HAS_FPU_DOUBLE_PRECISION + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_SAM + select INIT_ARCH_HW_AT_BOOT select PLATFORM_SPECIFIC_INIT select ASF select HAS_SWO diff --git a/soc/arm/atmel_sam/same70/soc.c b/soc/arm/atmel_sam/same70/soc.c index 79d7c9fa830..02ebce73c6d 100644 --- a/soc/arm/atmel_sam/same70/soc.c +++ b/soc/arm/atmel_sam/same70/soc.c @@ -14,42 +14,17 @@ #include #include #include +#include +#include #include +#include +#include #include #include #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -/* Power Manager Controller */ - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 24, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (24 + 1) / 1 = 300 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK)=300 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAME70_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAME70_PLLA_DIVA)) - -#if CONFIG_SOC_ATMEL_SAME70_MDIV == 1 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_EQ_PCK -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 2 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV2 -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 3 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV3 -#elif CONFIG_SOC_ATMEL_SAME70_MDIV == 4 -#define SOC_ATMEL_SAME70_MDIV PMC_MCKR_MDIV_PCK_DIV4 -#else -#error "Invalid CONFIG_SOC_ATMEL_SAME70_MDIV define value" -#endif - /** * @brief Setup various clocks on SoC at boot time. * @@ -58,192 +33,102 @@ LOG_MODULE_REGISTER(soc); */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAME70_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; - - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAME70_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK - /* - * Setup main external crystal oscillator if not already done - * by a previous program i.e. bootloader - */ + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL_Msk)) { - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* We select maximum setup time. - * While start up time could be shortened - * this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE; - /* Select the external crystal oscillator as main clock */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + soc_pmc_enable_clock_failure_detector(); - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ -#ifdef CONFIG_SOC_ATMEL_SAME70_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Attempt to change main fast RC oscillator frequency */ + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); + } /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDIO value + * rather than maximum supported 150 MHz at standard VDDIO=2.7V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 24, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (24 + 1) / 1 = 300 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK)=300 MHz. */ + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAME70_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAME70_PLLA_DIVA); - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } - /* Setup UPLL */ - PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN; - - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { - ; - } + soc_pmc_enable_upllck(0x3Fu); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS, MDIV or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } + /* Setting PLLA as MCK, first prescaler, then divider and source last */ + soc_pmc_mck_set_prescaler(1); + soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAME70_MDIV); + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Setup divider - Processor Clock (HCLK) / Master Clock (MCK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk; - PMC->PMC_MCKR = reg_val | SOC_ATMEL_SAME70_MDIV; - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } else { - SCB_DisableICache(); - } - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } else { - SCB_DisableDCache(); + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAME70_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); } /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDIO value - * rather than maximum supported 150 MHz at standard VDDIO=2.7V + * DTCM is enabled by default at reset, therefore we have to disable + * it first to get the caches into a state where then the + * sys_cache*-functions can enable them, if requested by the + * configuration. */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; + SCB_DisableDCache(); + + /* + * Enable the caches only if configured to do so. + */ + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Setup system clocks */ clock_init(); diff --git a/soc/arm/atmel_sam/samv71/Kconfig.series b/soc/arm/atmel_sam/samv71/Kconfig.series index 49de040aff8..cadee35acb5 100644 --- a/soc/arm/atmel_sam/samv71/Kconfig.series +++ b/soc/arm/atmel_sam/samv71/Kconfig.series @@ -11,7 +11,10 @@ config SOC_SERIES_SAMV71 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU select CPU_HAS_FPU_DOUBLE_PRECISION + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_SAM + select INIT_ARCH_HW_AT_BOOT select PLATFORM_SPECIFIC_INIT select ASF select HAS_SWO diff --git a/soc/arm/atmel_sam/samv71/soc.c b/soc/arm/atmel_sam/samv71/soc.c index 7571ce46dc7..6e82b9fe2f6 100644 --- a/soc/arm/atmel_sam/samv71/soc.c +++ b/soc/arm/atmel_sam/samv71/soc.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -21,35 +23,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -/* Power Manager Controller */ - -/* - * PLL clock = Main * (MULA + 1) / DIVA - * - * By default, MULA == 24, DIVA == 1. - * With main crystal running at 12 MHz, - * PLL = 12 * (24 + 1) / 1 = 300 MHz - * - * With Processor Clock prescaler at 1 - * Processor Clock (HCLK)=300 MHz. - */ -#define PMC_CKGR_PLLAR_MULA \ - (CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA)) -#define PMC_CKGR_PLLAR_DIVA \ - (CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA)) - -#if CONFIG_SOC_ATMEL_SAMV71_MDIV == 1 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_EQ_PCK -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 2 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV2 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 3 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV3 -#elif CONFIG_SOC_ATMEL_SAMV71_MDIV == 4 -#define SOC_ATMEL_SAMV71_MDIV PMC_MCKR_MDIV_PCK_DIV4 -#else -#error "Invalid CONFIG_SOC_ATMEL_SAMV71_MDIV define value" -#endif - /** * @brief Setup various clocks on SoC at boot time. * @@ -58,192 +31,101 @@ LOG_MODULE_REGISTER(soc); */ static ALWAYS_INLINE void clock_init(void) { - uint32_t reg_val; - -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK - /* Switch slow clock to the external 32 kHz crystal oscillator */ - SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL; - - /* Wait for oscillator to be stabilized */ - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK */ - -#ifdef CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK - /* - * Setup main external crystal oscillator if not already done - * by a previous program i.e. bootloader - */ + /* Switch the main clock to the internal OSC with 12MHz */ + soc_pmc_switch_mainck_to_fastrc(SOC_PMC_FAST_RC_FREQ_12MHZ); - if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL_Msk)) { - /* Start the external crystal oscillator */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - /* We select maximum setup time. - * While start up time could be shortened - * this optimization is not deemed - * critical now. - */ - | CKGR_MOR_MOSCXTST(0xFFu) - /* RC OSC must stay on */ - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + /* Switch MCK (Master Clock) to the main clock */ + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_MAIN_CLK); - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { - ; - } + EFC->EEFC_FMR = EEFC_FMR_FWS(0) | EEFC_FMR_CLOE; - /* Select the external crystal oscillator as main clock */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCRCEN - | CKGR_MOR_MOSCXTEN; + soc_pmc_enable_clock_failure_detector(); - /* Wait for external oscillator to be selected */ - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_SLCK)) { + soc_supc_slow_clock_select_crystal_osc(); } - /* Turn off RC OSC, not used any longer, to save power */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCSEL - | CKGR_MOR_MOSCXTST(0xFFu) - | CKGR_MOR_MOSCXTEN; - /* Wait for RC OSC to be turned off */ - while (PMC->PMC_SR & PMC_SR_MOSCRCS) { - ; - } + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + /* + * Setup main external crystal oscillator. + */ -#ifdef CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE - /* - * Instruct CPU to enter Wait mode instead of Sleep mode to - * keep Processor Clock (HCLK) and thus be able to debug - * CPU using JTAG - */ - PMC->PMC_FSMR |= PMC_FSMR_LPM; -#endif -#else - /* Attempt to change main fast RC oscillator frequency */ + /* We select maximum setup time. + * While start up time could be shortened + * this optimization is not deemed + * critical now. + */ + soc_pmc_switch_mainck_to_xtal(false, 0xff); + } /* - * NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR - * register, should normally be the case here + * Set FWS (Flash Wait State) value before increasing Master Clock + * (MCK) frequency. + * TODO: set FWS based on the actual MCK frequency and VDDIO value + * rather than maximum supported 150 MHz at standard VDDIO=2.7V */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } - - /* Set main fast RC oscillator to 12 MHz */ - PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD - | CKGR_MOR_MOSCRCF_12_MHz - | CKGR_MOR_MOSCRCEN; - - /* Wait for oscillator to be stabilized */ - while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) { - ; - } -#endif /* CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK */ + EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; /* * Setup PLLA */ - /* Switch MCK (Master Clock) to the main clock first */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK; - - /* Wait for clock selection to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup PLLA */ - PMC->CKGR_PLLAR = CKGR_PLLAR_ONE - | PMC_CKGR_PLLAR_MULA - | CKGR_PLLAR_PLLACOUNT(0x3Fu) - | PMC_CKGR_PLLAR_DIVA; - /* - * NOTE: Both MULA and DIVA must be set to a value greater than 0 or - * otherwise PLL will be disabled. In this case we would get stuck in - * the following loop. + * PLL clock = Main * (MULA + 1) / DIVA + * + * By default, MULA == 24, DIVA == 1. + * With main crystal running at 12 MHz, + * PLL = 12 * (24 + 1) / 1 = 300 MHz + * + * With Processor Clock prescaler at 1 + * Processor Clock (HCLK)=300 MHz. */ + soc_pmc_enable_pllack(CONFIG_SOC_ATMEL_SAMV71_PLLA_MULA, 0x3Fu, + CONFIG_SOC_ATMEL_SAMV71_PLLA_DIVA); - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { - ; - } - - /* Setup UPLL */ - PMC->CKGR_UCKR = CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN; - /* Wait for PLL lock */ - while (!(PMC->PMC_SR & PMC_SR_LOCKU)) { - ; - } + soc_pmc_enable_upllck(0x3Fu); /* * Final setup of the Master Clock */ - /* - * NOTE: PMC_MCKR must not be programmed in a single write operation. - * If CSS, MDIV or PRES are modified we must wait for MCKRDY bit to be - * set again. - */ - - /* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Setup divider - Processor Clock (HCLK) / Master Clock (MCK) */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk; - PMC->PMC_MCKR = reg_val | SOC_ATMEL_SAMV71_MDIV; + /* Setting PLLA as MCK, first prescaler, then divider and source last */ + soc_pmc_mck_set_prescaler(1); + soc_pmc_mck_set_divider(CONFIG_SOC_ATMEL_SAMV71_MDIV); + soc_pmc_mck_set_source(SOC_PMC_MCK_SRC_PLLA_CLK); - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; - } - - /* Finally select PLL as Master Clock source */ - reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk; - PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK; - - /* Wait for Master Clock setup to complete */ - while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { - ; + /* Disable internal fast RC if we have an external crystal oscillator */ + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_EXT_MAINCK)) { + soc_pmc_osc_disable_fastrc(); } } void z_arm_platform_init(void) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_ICACHE)) { - SCB_EnableICache(); - } else { - SCB_DisableICache(); - } - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT) && IS_ENABLED(CONFIG_DCACHE)) { - SCB_EnableDCache(); - } else { - SCB_DisableDCache(); + if (IS_ENABLED(CONFIG_SOC_ATMEL_SAMV71_WAIT_MODE)) { + /* + * Instruct CPU to enter Wait mode instead of Sleep mode to + * keep Processor Clock (HCLK) and thus be able to debug + * CPU using JTAG. + */ + soc_pmc_enable_waitmode(); } /* - * Set FWS (Flash Wait State) value before increasing Master Clock - * (MCK) frequency. - * TODO: set FWS based on the actual MCK frequency and VDDIO value - * rather than maximum supported 150 MHz at standard VDDIO=2.7V + * DTCM is enabled by default at reset, therefore we have to disable + * it first to get the caches into a state where then the + * sys_cache*-functions can enable them, if requested by the + * configuration. */ - EFC->EEFC_FMR = EEFC_FMR_FWS(5) | EEFC_FMR_CLOE; + SCB_DisableDCache(); + + /* + * Enable the caches only if configured to do so. + */ + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Setup system clocks */ clock_init(); diff --git a/soc/arm/atmel_sam0/common/Kconfig.defconfig.series b/soc/arm/atmel_sam0/common/Kconfig.defconfig.series index ef6e1e0ff83..8d9068424fd 100644 --- a/soc/arm/atmel_sam0/common/Kconfig.defconfig.series +++ b/soc/arm/atmel_sam0/common/Kconfig.defconfig.series @@ -10,8 +10,8 @@ config HWINFO_SAM0 if USB_DEVICE_DRIVER -config HEAP_MEM_POOL_SIZE - default 1024 +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 1024 endif # USB_DEVICE_DRIVER diff --git a/soc/arm/atmel_sam0/common/soc_samd2x.c b/soc/arm/atmel_sam0/common/soc_samd2x.c index bc488ab724c..6f86ac1a8a7 100644 --- a/soc/arm/atmel_sam0/common/soc_samd2x.c +++ b/soc/arm/atmel_sam0/common/soc_samd2x.c @@ -38,9 +38,6 @@ #define FUSES_OSC32K_CAL_Msk FUSES_OSC32KCAL_Msk #endif -#if !CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN -#define osc8m_init() -#else static inline void osc8m_init(void) { uint32_t reg; @@ -56,8 +53,24 @@ static inline void osc8m_init(void) while (!SYSCTRL->PCLKSR.bit.OSC8MRDY) { } + + /* Use 8Mhz clock as gclk_main to allow switching between clocks + * when using bootloaders + */ + GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) + | GCLK_GENDIV_DIV(0); + + while (GCLK->STATUS.bit.SYNCBUSY) { + } + + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) + | GCLK_GENCTRL_SRC_OSC8M + | GCLK_GENCTRL_IDC + | GCLK_GENCTRL_GENEN; + + while (GCLK->STATUS.bit.SYNCBUSY) { + } } -#endif #if !CONFIG_SOC_ATMEL_SAMD_OSC32K || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN #define osc32k_init() @@ -246,6 +259,24 @@ static inline void gclk_adc_configure(void) } #endif +#if !CONFIG_WDT_SAM0 +#define gclk_wdt_configure() +#else +static inline void gclk_wdt_configure(void) +{ + GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) + | GCLK_GENDIV_DIV(4); + + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) + | GCLK_GENCTRL_GENEN + | GCLK_GENCTRL_SRC_OSCULP32K + | GCLK_GENCTRL_DIVSEL; + + while (GCLK->STATUS.bit.SYNCBUSY) { + } +} +#endif + #if CONFIG_SOC_ATMEL_SAMD_OSC8M || CONFIG_SOC_ATMEL_SAMD_DEFAULT_AS_MAIN #define osc8m_disable() #else @@ -265,5 +296,6 @@ void z_arm_platform_init(void) flash_waitstates_init(); gclk_main_configure(); gclk_adc_configure(); + gclk_wdt_configure(); osc8m_disable(); } diff --git a/soc/arm/atmel_sam0/common/soc_saml2x.c b/soc/arm/atmel_sam0/common/soc_saml2x.c index c4c1a659dd6..6f29f9c525d 100644 --- a/soc/arm/atmel_sam0/common/soc_saml2x.c +++ b/soc/arm/atmel_sam0/common/soc_saml2x.c @@ -215,6 +215,18 @@ static inline void gclk_main_configure(void) GCLK->GENCTRL[0].bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val; } +#if !CONFIG_USB_DC_SAM0 +#define gclk_usb_configure() +#else +static inline void gclk_usb_configure(void) +{ + GCLK->GENCTRL[2].reg = 0 + | GCLK_GENCTRL_SRC_DFLL48M + | GCLK_GENCTRL_DIV(1) + | GCLK_GENCTRL_GENEN; +} +#endif + #if !CONFIG_ADC_SAM0 #define gclk_adc_configure() #else @@ -255,5 +267,6 @@ void z_arm_platform_init(void) flash_waitstates_init(); pm_init(); gclk_main_configure(); + gclk_usb_configure(); gclk_adc_configure(); } diff --git a/soc/arm/atmel_sam0/samc21/Kconfig.series b/soc/arm/atmel_sam0/samc21/Kconfig.series index 044a7aea229..acb83679e18 100644 --- a/soc/arm/atmel_sam0/samc21/Kconfig.series +++ b/soc/arm/atmel_sam0/samc21/Kconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES_SAMC21 select CPU_CORTEX_M0PLUS select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU select SOC_FAMILY_SAM0 select PLATFORM_SPECIFIC_INIT select ASF diff --git a/soc/arm/atmel_sam0/same51/soc.h b/soc/arm/atmel_sam0/same51/soc.h index 64550333855..746a001be69 100644 --- a/soc/arm/atmel_sam0/same51/soc.h +++ b/soc/arm/atmel_sam0/same51/soc.h @@ -37,6 +37,7 @@ #include "../common/atmel_sam0_dt.h" #define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768 +#define SOC_ATMEL_SAM0_DFLL48_FREQ_HZ 48000000 /** Processor Clock (HCLK) Frequency */ #define SOC_ATMEL_SAM0_HCLK_FREQ_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/arm/atmel_sam0/same54/soc.h b/soc/arm/atmel_sam0/same54/soc.h index 4f49e68c31f..b62eead707e 100644 --- a/soc/arm/atmel_sam0/same54/soc.h +++ b/soc/arm/atmel_sam0/same54/soc.h @@ -36,6 +36,7 @@ #include "../common/atmel_sam0_dt.h" #define SOC_ATMEL_SAM0_OSC32K_FREQ_HZ 32768 +#define SOC_ATMEL_SAM0_DFLL48_FREQ_HZ 48000000 /** Processor Clock (HCLK) Frequency */ #define SOC_ATMEL_SAM0_HCLK_FREQ_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC diff --git a/soc/arm/bcm_vk/valkyrie/soc.h b/soc/arm/bcm_vk/valkyrie/soc.h index 26863fbfea0..c3e21a89581 100644 --- a/soc/arm/bcm_vk/valkyrie/soc.h +++ b/soc/arm/bcm_vk/valkyrie/soc.h @@ -292,4 +292,6 @@ typedef enum IRQn { #define PCIE0_PERST_FE_INTR BIT(1) #define PCIE0_PERST_INB_FE_INTR BIT(3) +#include + #endif diff --git a/soc/arm/bcm_vk/viper/soc.h b/soc/arm/bcm_vk/viper/soc.h index 6695e92ef5c..06bf59fb24d 100644 --- a/soc/arm/bcm_vk/viper/soc.h +++ b/soc/arm/bcm_vk/viper/soc.h @@ -9,10 +9,10 @@ #include #include +#include #ifndef _ASMLANGUAGE - /* Interrupt Number Definition */ typedef enum IRQn { /* CORTEX-M7 Processor Exceptions Numbers */ @@ -301,4 +301,6 @@ typedef enum IRQn { #define LS_ICFG_PMON_LITE_SW_RESETN 0x482f0120 #define PCIE_PMON_LITE_SW_RESETN BIT(0) +#include + #endif diff --git a/soc/arm/cypress/Kconfig b/soc/arm/cypress/Kconfig index 352c66b4e76..cb76ccb1090 100644 --- a/soc/arm/cypress/Kconfig +++ b/soc/arm/cypress/Kconfig @@ -12,12 +12,15 @@ config SOC_PSOC6_M0 select CPU_CORTEX_M0PLUS select CPU_CORTEX_M_HAS_SYSTICK select CPU_CORTEX_M_HAS_VTOR + select CPU_HAS_ARM_MPU config SOC_PSOC6_M4 bool "SOC_PSOC6_M4" select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_CORTEX_M_HAS_SYSTICK + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU endchoice diff --git a/soc/arm/gigadevice/CMakeLists.txt b/soc/arm/gd_gd32/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/CMakeLists.txt rename to soc/arm/gd_gd32/CMakeLists.txt diff --git a/soc/arm/gd_gd32/Kconfig b/soc/arm/gd_gd32/Kconfig new file mode 100644 index 00000000000..69f21b210d0 --- /dev/null +++ b/soc/arm/gd_gd32/Kconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_GD32 + bool + select HAS_GD32_HAL + select BUILD_OUTPUT_HEX + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + +config SOC_FAMILY + string + default "gd_gd32" + depends on SOC_FAMILY_GD32 + +config SOC_FAMILY_GD32_ARM + bool + select SOC_FAMILY_GD32 + +if SOC_FAMILY_GD32_ARM + +source "soc/arm/gd_gd32/*/Kconfig.soc" + +endif # SOC_FAMILY_GD32_ARM diff --git a/soc/arm/gd_gd32/Kconfig.defconfig b/soc/arm/gd_gd32/Kconfig.defconfig new file mode 100644 index 00000000000..b6fae5d43ec --- /dev/null +++ b/soc/arm/gd_gd32/Kconfig.defconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_GD32 + +source "soc/arm/gd_gd32/*/Kconfig.defconfig.series" + +config PINCTRL + default y + +config RESET + default y + +config CLOCK_CONTROL + default y + +endif # SOC_FAMILY_GD32 diff --git a/soc/arm/gd_gd32/Kconfig.soc b/soc/arm/gd_gd32/Kconfig.soc new file mode 100644 index 00000000000..20a2f4c8cb4 --- /dev/null +++ b/soc/arm/gd_gd32/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +source "soc/arm/gd_gd32/*/Kconfig.series" diff --git a/soc/arm/gigadevice/common/CMakeLists.txt b/soc/arm/gd_gd32/common/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/common/CMakeLists.txt rename to soc/arm/gd_gd32/common/CMakeLists.txt diff --git a/soc/arm/gigadevice/common/pinctrl_soc.h b/soc/arm/gd_gd32/common/pinctrl_soc.h similarity index 100% rename from soc/arm/gigadevice/common/pinctrl_soc.h rename to soc/arm/gd_gd32/common/pinctrl_soc.h diff --git a/soc/arm/gigadevice/gd32a50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32a50x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32a50x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32a50x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32a503 b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32a503 similarity index 100% rename from soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32a503 rename to soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32a503 diff --git a/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series new file mode 100644 index 00000000000..0b250325c45 --- /dev/null +++ b/soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2022 YuLong Yao +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32A50X + +source "soc/arm/gd_gd32/gd32a50x/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32a50x" + +endif # SOC_SERIES_GD32A50X diff --git a/soc/arm/gd_gd32/gd32a50x/Kconfig.series b/soc/arm/gd_gd32/gd32a50x/Kconfig.series new file mode 100644 index 00000000000..2488c643727 --- /dev/null +++ b/soc/arm/gd_gd32/gd32a50x/Kconfig.series @@ -0,0 +1,16 @@ +# Copyright (c) 2022 YuLong Yao +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_GD32A50X + bool "GigaDevice GD32A50X series Cortex-M33 MCU" + select ARM + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select ARMV8_M_DSP + select CPU_CORTEX_M33 + select SOC_FAMILY_GD32_ARM + select GD32_HAS_AF_PINMUX + select GD32_HAS_IRC_40K + select PLATFORM_SPECIFIC_INIT + help + Enable support for GigaDevice GD32A50X MCU series diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.soc b/soc/arm/gd_gd32/gd32a50x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32a50x/Kconfig.soc rename to soc/arm/gd_gd32/gd32a50x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32a50x/gd32_regs.h b/soc/arm/gd_gd32/gd32a50x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32a50x/gd32_regs.h rename to soc/arm/gd_gd32/gd32a50x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32a50x/soc.c b/soc/arm/gd_gd32/gd32a50x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32a50x/soc.c rename to soc/arm/gd_gd32/gd32a50x/soc.c diff --git a/soc/arm/gigadevice/gd32a50x/soc.h b/soc/arm/gd_gd32/gd32a50x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32a50x/soc.h rename to soc/arm/gd_gd32/gd32a50x/soc.h diff --git a/soc/arm/gigadevice/gd32e10x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e10x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32e10x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32e10x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32e103 b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32e103 similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32e103 rename to soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32e103 diff --git a/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series new file mode 100644 index 00000000000..f16328e1e70 --- /dev/null +++ b/soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021 YuLong Yao +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32E10X + +source "soc/arm/gd_gd32/gd32e10x/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32e10x" + +endif # SOC_SERIES_GD32E10X diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.series b/soc/arm/gd_gd32/gd32e10x/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.series rename to soc/arm/gd_gd32/gd32e10x/Kconfig.series diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.soc b/soc/arm/gd_gd32/gd32e10x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32e10x/Kconfig.soc rename to soc/arm/gd_gd32/gd32e10x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32e10x/gd32_regs.h b/soc/arm/gd_gd32/gd32e10x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32e10x/gd32_regs.h rename to soc/arm/gd_gd32/gd32e10x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32e10x/soc.c b/soc/arm/gd_gd32/gd32e10x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32e10x/soc.c rename to soc/arm/gd_gd32/gd32e10x/soc.c diff --git a/soc/arm/gigadevice/gd32e10x/soc.h b/soc/arm/gd_gd32/gd32e10x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32e10x/soc.h rename to soc/arm/gd_gd32/gd32e10x/soc.h diff --git a/soc/arm/gigadevice/gd32e50x/CMakeLists.txt b/soc/arm/gd_gd32/gd32e50x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32e50x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32e50x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32e507 b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32e507 similarity index 100% rename from soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32e507 rename to soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32e507 diff --git a/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series new file mode 100644 index 00000000000..f771aea44d9 --- /dev/null +++ b/soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2022, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32E50X + +source "soc/arm/gd_gd32/gd32e50x/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32e50x" + +endif # SOC_SERIES_GD32E50X diff --git a/soc/arm/gd_gd32/gd32e50x/Kconfig.series b/soc/arm/gd_gd32/gd32e50x/Kconfig.series new file mode 100644 index 00000000000..546ca456793 --- /dev/null +++ b/soc/arm/gd_gd32/gd32e50x/Kconfig.series @@ -0,0 +1,15 @@ +# Copyright (c) 2022, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_GD32E50X + bool "GigaDevice GD32E50X series Cortex-M33 MCU" + select ARM + select CPU_HAS_ARM_MPU + select CPU_HAS_FPU + select CPU_CORTEX_M33 + select ARMV8_M_DSP + select SOC_FAMILY_GD32_ARM + select GD32_HAS_AFIO_PINMUX + select GD32_HAS_IRC_40K + help + Enable support for GigaDevice GD32E50X MCU series diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.soc b/soc/arm/gd_gd32/gd32e50x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32e50x/Kconfig.soc rename to soc/arm/gd_gd32/gd32e50x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32e50x/gd32_regs.h b/soc/arm/gd_gd32/gd32e50x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32e50x/gd32_regs.h rename to soc/arm/gd_gd32/gd32e50x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32e50x/soc.c b/soc/arm/gd_gd32/gd32e50x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32e50x/soc.c rename to soc/arm/gd_gd32/gd32e50x/soc.c diff --git a/soc/arm/gigadevice/gd32e50x/soc.h b/soc/arm/gd_gd32/gd32e50x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32e50x/soc.h rename to soc/arm/gd_gd32/gd32e50x/soc.h diff --git a/soc/arm/gigadevice/gd32f3x0/CMakeLists.txt b/soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f3x0/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32f350 b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32f350 similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32f350 rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32f350 diff --git a/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series new file mode 100644 index 00000000000..4852255d255 --- /dev/null +++ b/soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32F3X0 + +source "soc/arm/gd_gd32/gd32f3x0/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32f3x0" + +endif # SOC_SERIES_GD32F3X0 diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.series b/soc/arm/gd_gd32/gd32f3x0/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.series rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.soc b/soc/arm/gd_gd32/gd32f3x0/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/Kconfig.soc rename to soc/arm/gd_gd32/gd32f3x0/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f3x0/gd32_regs.h b/soc/arm/gd_gd32/gd32f3x0/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/gd32_regs.h rename to soc/arm/gd_gd32/gd32f3x0/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f3x0/soc.c b/soc/arm/gd_gd32/gd32f3x0/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/soc.c rename to soc/arm/gd_gd32/gd32f3x0/soc.c diff --git a/soc/arm/gigadevice/gd32f3x0/soc.h b/soc/arm/gd_gd32/gd32f3x0/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f3x0/soc.h rename to soc/arm/gd_gd32/gd32f3x0/soc.h diff --git a/soc/arm/gigadevice/gd32f403/CMakeLists.txt b/soc/arm/gd_gd32/gd32f403/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f403/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f403/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403 b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403 similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403 rename to soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403 diff --git a/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series new file mode 100644 index 00000000000..8923e1582a3 --- /dev/null +++ b/soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021, ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32F403 + +source "soc/arm/gd_gd32/gd32f403/Kconfig.defconfig.gd32f403" + +config SOC_SERIES + default "gd32f403" + +endif # SOC_SERIES_GD32F403 diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.series b/soc/arm/gd_gd32/gd32f403/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.series rename to soc/arm/gd_gd32/gd32f403/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.soc b/soc/arm/gd_gd32/gd32f403/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f403/Kconfig.soc rename to soc/arm/gd_gd32/gd32f403/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f403/gd32_regs.h b/soc/arm/gd_gd32/gd32f403/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f403/gd32_regs.h rename to soc/arm/gd_gd32/gd32f403/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f403/soc.c b/soc/arm/gd_gd32/gd32f403/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f403/soc.c rename to soc/arm/gd_gd32/gd32f403/soc.c diff --git a/soc/arm/gigadevice/gd32f403/soc.h b/soc/arm/gd_gd32/gd32f403/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f403/soc.h rename to soc/arm/gd_gd32/gd32f403/soc.h diff --git a/soc/arm/gigadevice/gd32f4xx/CMakeLists.txt b/soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/CMakeLists.txt rename to soc/arm/gd_gd32/gd32f4xx/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f405 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f405 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f405 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f405 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f407 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f407 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f407 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f407 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f450 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f450 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f450 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f450 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f470 b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f470 similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32f470 rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32f470 diff --git a/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series new file mode 100644 index 00000000000..a4ccaed4e80 --- /dev/null +++ b/soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021, Teslabs Engineering S.L. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32F4XX + +source "soc/arm/gd_gd32/gd32f4xx/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32f4xx" + +endif # SOC_SERIES_GD32F4XX diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.series b/soc/arm/gd_gd32/gd32f4xx/Kconfig.series similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.series rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.series diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.soc b/soc/arm/gd_gd32/gd32f4xx/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/Kconfig.soc rename to soc/arm/gd_gd32/gd32f4xx/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32f4xx/gd32_regs.h b/soc/arm/gd_gd32/gd32f4xx/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/gd32_regs.h rename to soc/arm/gd_gd32/gd32f4xx/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32f4xx/soc.c b/soc/arm/gd_gd32/gd32f4xx/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/soc.c rename to soc/arm/gd_gd32/gd32f4xx/soc.c diff --git a/soc/arm/gigadevice/gd32f4xx/soc.h b/soc/arm/gd_gd32/gd32f4xx/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32f4xx/soc.h rename to soc/arm/gd_gd32/gd32f4xx/soc.h diff --git a/soc/arm/gigadevice/gd32l23x/CMakeLists.txt b/soc/arm/gd_gd32/gd32l23x/CMakeLists.txt similarity index 100% rename from soc/arm/gigadevice/gd32l23x/CMakeLists.txt rename to soc/arm/gd_gd32/gd32l23x/CMakeLists.txt diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32l233 b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32l233 similarity index 100% rename from soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32l233 rename to soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32l233 diff --git a/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series new file mode 100644 index 00000000000..36a6476dbfb --- /dev/null +++ b/soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2022 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32L23X + +source "soc/arm/gd_gd32/gd32l23x/Kconfig.defconfig.gd32*" + +config SOC_SERIES + default "gd32l23x" + +endif # SOC_SERIES_GD32L23X diff --git a/soc/arm/gd_gd32/gd32l23x/Kconfig.series b/soc/arm/gd_gd32/gd32l23x/Kconfig.series new file mode 100644 index 00000000000..d6125ca4152 --- /dev/null +++ b/soc/arm/gd_gd32/gd32l23x/Kconfig.series @@ -0,0 +1,14 @@ +# Copyright (c) 2022 BrainCo Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_GD32L23X + bool "GigaDevice GD32L23X series Cortex-M23 MCU" + select ARM + select CPU_CORTEX_M23 + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR + select SOC_FAMILY_GD32_ARM + select GD32_HAS_AF_PINMUX + select GD32_HAS_IRC_32K + help + Enable support for GigaDevice GD32L23X MCU series diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.soc b/soc/arm/gd_gd32/gd32l23x/Kconfig.soc similarity index 100% rename from soc/arm/gigadevice/gd32l23x/Kconfig.soc rename to soc/arm/gd_gd32/gd32l23x/Kconfig.soc diff --git a/soc/arm/gigadevice/gd32l23x/gd32_regs.h b/soc/arm/gd_gd32/gd32l23x/gd32_regs.h similarity index 100% rename from soc/arm/gigadevice/gd32l23x/gd32_regs.h rename to soc/arm/gd_gd32/gd32l23x/gd32_regs.h diff --git a/soc/arm/gigadevice/gd32l23x/soc.c b/soc/arm/gd_gd32/gd32l23x/soc.c similarity index 100% rename from soc/arm/gigadevice/gd32l23x/soc.c rename to soc/arm/gd_gd32/gd32l23x/soc.c diff --git a/soc/arm/gigadevice/gd32l23x/soc.h b/soc/arm/gd_gd32/gd32l23x/soc.h similarity index 100% rename from soc/arm/gigadevice/gd32l23x/soc.h rename to soc/arm/gd_gd32/gd32l23x/soc.h diff --git a/soc/arm/gigadevice/Kconfig b/soc/arm/gigadevice/Kconfig deleted file mode 100644 index 1facd4ceeda..00000000000 --- a/soc/arm/gigadevice/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_GD32 - bool - select HAS_GD32_HAL - select BUILD_OUTPUT_HEX - select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE - -config SOC_FAMILY - string - default "gigadevice" - depends on SOC_FAMILY_GD32 - -config SOC_FAMILY_GD32_ARM - bool - select SOC_FAMILY_GD32 - -if SOC_FAMILY_GD32_ARM - -source "soc/arm/gigadevice/*/Kconfig.soc" - -endif # SOC_FAMILY_GD32_ARM diff --git a/soc/arm/gigadevice/Kconfig.defconfig b/soc/arm/gigadevice/Kconfig.defconfig deleted file mode 100644 index 1aa25966163..00000000000 --- a/soc/arm/gigadevice/Kconfig.defconfig +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -if SOC_FAMILY_GD32 - -source "soc/arm/gigadevice/*/Kconfig.defconfig.series" - -config PINCTRL - default y - -config RESET - default y - -config CLOCK_CONTROL - default y - -endif # SOC_FAMILY_GD32 diff --git a/soc/arm/gigadevice/Kconfig.soc b/soc/arm/gigadevice/Kconfig.soc deleted file mode 100644 index 897238ff3fb..00000000000 --- a/soc/arm/gigadevice/Kconfig.soc +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -source "soc/arm/gigadevice/*/Kconfig.series" diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series deleted file mode 100644 index d9e48ae18c2..00000000000 --- a/soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2022 YuLong Yao -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32A50X - -source "soc/arm/gigadevice/gd32a50x/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32a50x" - -endif # SOC_SERIES_GD32A50X diff --git a/soc/arm/gigadevice/gd32a50x/Kconfig.series b/soc/arm/gigadevice/gd32a50x/Kconfig.series deleted file mode 100644 index 96fc8c1d0af..00000000000 --- a/soc/arm/gigadevice/gd32a50x/Kconfig.series +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2022 YuLong Yao -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_GD32A50X - bool "GigaDevice GD32A50X series Cortex-M33 MCU" - select ARM - select CPU_HAS_ARM_MPU - select CPU_HAS_FPU - select CPU_CORTEX_M33 - select SOC_FAMILY_GD32_ARM - select GD32_HAS_AF_PINMUX - select GD32_HAS_IRC_40K - select PLATFORM_SPECIFIC_INIT - help - Enable support for GigaDevice GD32A50X MCU series diff --git a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series deleted file mode 100644 index 5a17c08d864..00000000000 --- a/soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2021 YuLong Yao -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32E10X - -source "soc/arm/gigadevice/gd32e10x/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32e10x" - -endif # SOC_SERIES_GD32E10X diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series deleted file mode 100644 index 3a05359fd4a..00000000000 --- a/soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2022, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32E50X - -source "soc/arm/gigadevice/gd32e50x/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32e50x" - -endif # SOC_SERIES_GD32E50X diff --git a/soc/arm/gigadevice/gd32e50x/Kconfig.series b/soc/arm/gigadevice/gd32e50x/Kconfig.series deleted file mode 100644 index 8bc3f71118e..00000000000 --- a/soc/arm/gigadevice/gd32e50x/Kconfig.series +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2022, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_GD32E50X - bool "GigaDevice GD32E50X series Cortex-M33 MCU" - select ARM - select CPU_HAS_ARM_MPU - select CPU_HAS_FPU - select CPU_CORTEX_M33 - select SOC_FAMILY_GD32_ARM - select GD32_HAS_AFIO_PINMUX - select GD32_HAS_IRC_40K - help - Enable support for GigaDevice GD32E50X MCU series diff --git a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series deleted file mode 100644 index dc9607f1149..00000000000 --- a/soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2021 BrainCo Inc. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32F3X0 - -source "soc/arm/gigadevice/gd32f3x0/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32f3x0" - -endif # SOC_SERIES_GD32F3X0 diff --git a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series deleted file mode 100644 index dbec480c299..00000000000 --- a/soc/arm/gigadevice/gd32f403/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2021, ATL Electronics -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32F403 - -source "soc/arm/gigadevice/gd32f403/Kconfig.defconfig.gd32f403" - -config SOC_SERIES - default "gd32f403" - -endif # SOC_SERIES_GD32F403 diff --git a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series deleted file mode 100644 index f5ef03cd276..00000000000 --- a/soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2021, Teslabs Engineering S.L. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32F4XX - -source "soc/arm/gigadevice/gd32f4xx/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32f4xx" - -endif # SOC_SERIES_GD32F4XX diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series b/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series deleted file mode 100644 index da16d8f287c..00000000000 --- a/soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2022 BrainCo Inc. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32L23X - -source "soc/arm/gigadevice/gd32l23x/Kconfig.defconfig.gd32*" - -config SOC_SERIES - default "gd32l23x" - -endif # SOC_SERIES_GD32L23X diff --git a/soc/arm/gigadevice/gd32l23x/Kconfig.series b/soc/arm/gigadevice/gd32l23x/Kconfig.series deleted file mode 100644 index 5bdb0dba7d3..00000000000 --- a/soc/arm/gigadevice/gd32l23x/Kconfig.series +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2022 BrainCo Inc. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_GD32L23X - bool "GigaDevice GD32L23X series Cortex-M23 MCU" - select ARM - select CPU_CORTEX_M23 - select CPU_CORTEX_M_HAS_SYSTICK - select SOC_FAMILY_GD32_ARM - select GD32_HAS_AF_PINMUX - select GD32_HAS_IRC_32K - help - Enable support for GigaDevice GD32L23X MCU series diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 53312dfaf7b..7c7f9a85496 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -21,5 +21,7 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_I2C select HAS_XMCLIB_CCU select HAS_XMCLIB_WDT + select HAS_XMCLIB_ETH + select HAS_XMCLIB_CAN help Enable support for XMC 4xxx MCU series diff --git a/soc/arm/infineon_xmc/4xxx/soc.c b/soc/arm/infineon_xmc/4xxx/soc.c index 0d4060568a3..44e83a63c6f 100644 --- a/soc/arm/infineon_xmc/4xxx/soc.c +++ b/soc/arm/infineon_xmc/4xxx/soc.c @@ -37,6 +37,9 @@ void z_arm_platform_init(void) #endif #ifdef CONFIG_PWM_XMC4XXX_CCU8 | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_CCU +#endif +#ifdef CONFIG_ETH_XMC4XXX + | XMC_SCU_CLOCK_SLEEP_MODE_CONFIG_ENABLE_ETH #endif ); diff --git a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series index cb0dc6984e3..e9fba7bdba2 100644 --- a/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series +++ b/soc/arm/intel_socfpga_std/cyclonev/Kconfig.series @@ -9,7 +9,6 @@ config SOC_SERIES_CYCLONE5 select CPU_CORTEX_A9 select SOC_FAMILY_INTEL_SOCFPGA_STD select ARM_ARCH_TIMER_ERRATUM_740657 if ARM_ARCH_TIMER - select HAS_SPI_DW if SPI select ARCH_HAS_RESERVED_PAGE_FRAMES help Support for Intel SoC FPGA Series diff --git a/soc/arm/microchip_mec/mec1501/Kconfig.series b/soc/arm/microchip_mec/mec1501/Kconfig.series index d3b679bb557..92dc6f3f8f9 100644 --- a/soc/arm/microchip_mec/mec1501/Kconfig.series +++ b/soc/arm/microchip_mec/mec1501/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_MEC1501X select ARM select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ARM_MPU select SOC_FAMILY_MEC select HAS_PM help diff --git a/soc/arm/microchip_mec/mec172x/soc.h b/soc/arm/microchip_mec/mec172x/soc.h index 3bf4f533fdb..19afc4e920a 100644 --- a/soc/arm/microchip_mec/mec172x/soc.h +++ b/soc/arm/microchip_mec/mec172x/soc.h @@ -242,6 +242,8 @@ typedef enum { MAX_IRQn } IRQn_Type; +#include + #include /* chip specific register defines */ diff --git a/soc/arm/nordic_nrf/CMakeLists.txt b/soc/arm/nordic_nrf/CMakeLists.txt index 3b097d73569..bd7725404b8 100644 --- a/soc/arm/nordic_nrf/CMakeLists.txt +++ b/soc/arm/nordic_nrf/CMakeLists.txt @@ -1,9 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_library() + add_subdirectory(${SOC_SERIES}) add_subdirectory(common) -zephyr_sources( +zephyr_library_sources( validate_base_addresses.c validate_enabled_instances.c ) diff --git a/soc/arm/nordic_nrf/Kconfig b/soc/arm/nordic_nrf/Kconfig index 0372492cd7d..b2d164e7c78 100644 --- a/soc/arm/nordic_nrf/Kconfig +++ b/soc/arm/nordic_nrf/Kconfig @@ -13,11 +13,12 @@ config SOC_FAMILY string default "nordic_nrf" -source "soc/arm/nordic_nrf/Kconfig.peripherals" +source "soc/common/nordic_nrf/Kconfig.peripherals" source "soc/arm/nordic_nrf/*/Kconfig.soc" config NRF_SOC_SECURE_SUPPORTED def_bool !TRUSTED_EXECUTION_NONSECURE || (BUILD_WITH_TFM && TFM_PARTITION_PLATFORM) + depends on !SOC_SERIES_NRF54HX help Hidden function to indicate that that the soc_secure functions are available. @@ -171,17 +172,4 @@ config NRF_TRACE_PORT Unit) for tracing using a hardware probe. If disabled, the trace pins will be used as GPIO. -config NRF_STORE_REBOOT_TYPE_GPREGRET - bool "Set GPREGRET to reboot type (DEPRECATED)" - depends on SOC_SERIES_NRF51X || SOC_SERIES_NRF52X - depends on REBOOT - depends on !RETENTION_BOOT_MODE - select DEPRECATED - help - If this option is enabled, then the parameter supplied to the - sys_reboot() function will be set in the GPREGRET register. - - This has been replaced with the bootmode part of the retention - subsystem, which should be used instead. - endif # SOC_FAMILY_NRF diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index 3eedcf350c6..ad3c97443ff 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -7,22 +7,21 @@ if SOC_FAMILY_NRF source "soc/arm/nordic_nrf/*/Kconfig.defconfig.series" -# If the kernel has timer support, enable both clock control and timer +# If the kernel has timer support, enable clock control if SYS_CLOCK_EXISTS config CLOCK_CONTROL - default y - -config NRF_RTC_TIMER - default y + default y if !SOC_SERIES_NRF54HX endif # SYS_CLOCK_EXISTS config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 if NRF_GRTC_TIMER default 32768 config SYS_CLOCK_TICKS_PER_SEC default 128 if !TICKLESS_KERNEL + default 10000 if NRF_GRTC_TIMER default 32768 config ARCH_HAS_CUSTOM_BUSY_WAIT @@ -40,4 +39,7 @@ config GPIO default y depends on SPI +config UART_USE_RUNTIME_CONFIGURE + default n + endif # SOC_FAMILY_NRF diff --git a/soc/arm/nordic_nrf/common/CMakeLists.txt b/soc/arm/nordic_nrf/common/CMakeLists.txt index eb074dd0548..ea05f3d369e 100644 --- a/soc/arm/nordic_nrf/common/CMakeLists.txt +++ b/soc/arm/nordic_nrf/common/CMakeLists.txt @@ -3,11 +3,14 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_NRF soc_nrf_common.S) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) + zephyr_include_directories(.) +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + if (CONFIG_TFM_PARTITION_PLATFORM) - zephyr_sources(soc_secure.c) + zephyr_library_sources(soc_secure.c) zephyr_library_include_directories( - $/install/interface/include + $/api_ns/interface/include ) endif() diff --git a/soc/arm/nordic_nrf/common/soc_nrf_common.h b/soc/arm/nordic_nrf/common/soc_nrf_common.h index 4c00d7c0237..1e5e603967b 100644 --- a/soc/arm/nordic_nrf/common/soc_nrf_common.h +++ b/soc/arm/nordic_nrf/common/soc_nrf_common.h @@ -149,6 +149,52 @@ (NRF_DT_GPIOS_TO_PSEL(node_id, prop)), \ (default_value)) +/** + * @brief Convert a devicetree GPIO phandle+specifier to GPIOTE instance number. + * + * Some of nRF SoCs may have more instances of GPIOTE. + * To handle this, we use the "gpiote-instance" property of the GPIO node. + * + * This macro converts a devicetree GPIO phandle array value + * "<&gpioX pin ...>" to a GPIOTE instance number. + * + * Examples: + * + * &gpiote0 { + * instance = <0>; + * }; + * + * &gpiote20 { + * instance = <20>; + * }; + * + * &gpio0 { + * gpiote-instance = <&gpiote0>; + * } + * + * &gpio1 { + * gpiote-instance = <&gpiote20>; + * } + * + * foo: my-node { + * tx-gpios = <&gpio0 4 ...>; + * rx-gpios = <&gpio0 5 ...>, <&gpio1 5 ...>; + * }; + * + * NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), tx_gpios, 0) // = 0 + * NRF_DT_GPIOTE_INST_BY_IDX(DT_NODELABEL(foo), rx_gpios, 1) // = 20 + */ +#define NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, idx) \ + DT_PROP(DT_PHANDLE(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx), \ + gpiote_instance), \ + instance) + +/** + * @brief Equivalent to NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0) + */ +#define NRF_DT_GPIOTE_INST(node_id, prop) \ + NRF_DT_GPIOTE_INST_BY_IDX(node_id, prop, 0) + /** * Error out the build if 'prop' is set on node 'node_id' and * DT_GPIO_CTLR(node_id, prop) is not an SoC GPIO controller, diff --git a/soc/arm/nordic_nrf/common/soc_secure.h b/soc/arm/nordic_nrf/common/soc_secure.h index 948f38547aa..d38d66ab488 100644 --- a/soc/arm/nordic_nrf/common/soc_secure.h +++ b/soc/arm/nordic_nrf/common/soc_secure.h @@ -59,7 +59,7 @@ static inline void soc_secure_gpio_pin_mcu_select(uint32_t pin_number, #if defined(CONFIG_SOC_HFXO_CAP_INTERNAL) static inline uint32_t soc_secure_read_xosc32mtrim(void) { - return NRF_FICR_S->XOSC32MTRIM; + return NRF_FICR->XOSC32MTRIM; } #endif /* defined(CONFIG_SOC_HFXO_CAP_INTERNAL) */ diff --git a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt index 44d139e422a..35d47fb252b 100644 --- a/soc/arm/nordic_nrf/nrf51/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf51/CMakeLists.txt @@ -1,14 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_library() - -zephyr_library_sources( - soc.c - ) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ZEPHYR_BASE}/arch/arm/include - ) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") +zephyr_library_sources(soc.c) diff --git a/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series index 8c0bc74c02f..a4053bf7fed 100644 --- a/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf51/Kconfig.defconfig.series @@ -14,4 +14,8 @@ config SOC_SERIES config NUM_IRQS default 26 +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF51X diff --git a/soc/arm/nordic_nrf/nrf51/soc.c b/soc/arm/nordic_nrf/nrf51/soc.c index 2b22c95679f..af14f6f3003 100644 --- a/soc/arm/nordic_nrf/nrf51/soc.c +++ b/soc/arm/nordic_nrf/nrf51/soc.c @@ -21,19 +21,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -#ifdef CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET -/* Overrides the weak ARM implementation: - * Set general purpose retention register and reboot - * This is deprecated and has been replaced with the boot mode retention - * subsystem - */ -void sys_arch_reboot(int type) -{ - nrf_power_gpregret_set(NRF_POWER, 0, (uint8_t)type); - NVIC_SystemReset(); -} -#endif - #define DELAY_CALL_OVERHEAD_US 2 void arch_busy_wait(uint32_t time_us) diff --git a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt index 04e255a3eb1..1b7d4d5257a 100644 --- a/soc/arm/nordic_nrf/nrf52/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf52/CMakeLists.txt @@ -1,15 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_library() - -zephyr_library_sources( - soc.c - ) - -zephyr_library_include_directories( - ${ZEPHYR_BASE}/kernel/include - ${ZEPHYR_BASE}/arch/arm/include - ) +zephyr_library_sources(soc.c) if(CONFIG_SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 AND CONFIG_SPI_NRFX_SPIM) message(WARNING "Both SOC_NRF52832_ALLOW_SPIM_DESPITE_PAN_58 and an NRF SPIM driver are enabled, therefore PAN 58 will apply if RXD.MAXCNT == 1 and TXD.MAXCNT <= 1") @@ -22,5 +13,3 @@ if(CONFIG_SOC_NRF52832) endif() endif() endif() - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series index 4a7edf2aa95..2e89a5130a6 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf52/Kconfig.defconfig.nrf52*" config SOC_SERIES default "nrf52" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF52X diff --git a/soc/arm/nordic_nrf/nrf52/soc.c b/soc/arm/nordic_nrf/nrf52/soc.c index 5f310e5f945..a6ef22468b1 100644 --- a/soc/arm/nordic_nrf/nrf52/soc.c +++ b/soc/arm/nordic_nrf/nrf52/soc.c @@ -23,19 +23,6 @@ #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL LOG_MODULE_REGISTER(soc); -#ifdef CONFIG_NRF_STORE_REBOOT_TYPE_GPREGRET -/* Overrides the weak ARM implementation: - * Set general purpose retention register and reboot - * This is deprecated and has been replaced with the boot mode retention - * subsystem - */ -void sys_arch_reboot(int type) -{ - nrf_power_gpregret_set(NRF_POWER, 0, (uint8_t)type); - NVIC_SystemReset(); -} -#endif - static int nordicsemi_nrf52_init(void) { #ifdef CONFIG_NRF_ENABLE_ICACHE diff --git a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt index b4e82f52c28..be275df68f5 100644 --- a/soc/arm/nordic_nrf/nrf53/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf53/CMakeLists.txt @@ -1,12 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - ) +zephyr_library_sources(soc.c) -zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC - sync_rtc.c - ) +zephyr_library_sources_ifdef(CONFIG_NRF53_SYNC_RTC sync_rtc.c) if (CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED AND NOT CONFIG_SYS_CLOCK_EXISTS) @@ -19,5 +15,3 @@ if (CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED AND At your own risk, you can suppress this warning by setting CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED=n.") endif() - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA index 0c0f9f05926..f0f7f5a7d84 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUAPP_QKAA @@ -14,8 +14,9 @@ config NUM_IRQS config IEEE802154_NRF5 default IEEE802154 -config HEAP_MEM_POOL_SIZE - default 4096 if NRF_802154_SER_HOST +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 4096 + depends on NRF_802154_SER_HOST if IPC_SERVICE_BACKEND_RPMSG diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA index 88d53a3a0f7..0c60adc04f3 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf5340_CPUNET_QKAA @@ -15,8 +15,9 @@ config IEEE802154_NRF5 default y depends on IEEE802154 -config HEAP_MEM_POOL_SIZE - default 4096 if NRF_802154_SER_RADIO +config HEAP_MEM_POOL_ADD_SIZE_SOC + def_int 4096 + depends on NRF_802154_SER_RADIO config LOG_DOMAIN_NAME default "net" diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series index 2857d5dd25d..7e5660cf514 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf53/Kconfig.defconfig.nrf53*" config SOC_SERIES default "nrf53" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF53X diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index f72ae5ab004..b3ca2661675 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -12,13 +12,14 @@ config SOC_NRF5340_CPUAPP select HAS_POWEROFF select SOC_COMPATIBLE_NRF5340_CPUAPP imply SOC_NRF53_RTC_PRETICK + imply SOC_NRF53_ANOMALY_168_WORKAROUND config SOC_NRF5340_CPUNET bool - select ARM_ON_EXIT_CPU_IDLE select SOC_COMPATIBLE_NRF5340_CPUNET imply SOC_NRF53_ANOMALY_160_WORKAROUND_NEEDED imply SOC_NRF53_RTC_PRETICK if !WDT_NRFX + imply SOC_NRF53_ANOMALY_168_WORKAROUND choice prompt "nRF53x MCU Selection" @@ -79,6 +80,25 @@ config SOC_NRF53_RTC_PRETICK_IPC_CH_TO_NET endif +config SOC_NRF53_ANOMALY_168_WORKAROUND + bool "Workaround for nRF5340 anomaly 168" + select ARM_ON_EXIT_CPU_IDLE + help + Indicates that the workaround for the anomaly 168 that affects + the nRF5340 SoC should be applied. + The workaround involves execution of 8 NOP instructions when the CPU + exist its idle state (when the WFI/WFE instruction returns) and it is + enabled by default for both the application and network core. + +config SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM + bool "Extend the workaround to execution at 128 MHz from RAM" + depends on SOC_NRF53_ANOMALY_168_WORKAROUND && SOC_NRF5340_CPUAPP + help + Indicates that the anomaly 168 workaround is to be extended to cover + also a specific case when the WFI/WFE instruction is executed at 128 + MHz from RAM. Then, 26 instead of 8 NOP instructions needs to be + executed after WFI/WFE. This extension is not enabled by default. + if SOC_NRF5340_CPUAPP config SOC_DCDC_NRF53X_APP diff --git a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h index b6cd92ca092..c02c9451419 100644 --- a/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h +++ b/soc/arm/nordic_nrf/nrf53/soc_cpu_idle.h @@ -11,10 +11,16 @@ #if defined(_ASMLANGUAGE) +#if defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND_FOR_EXECUTION_FROM_RAM) #define SOC_ON_EXIT_CPU_IDLE \ + .rept 26; \ nop; \ + .endr +#elif defined(CONFIG_SOC_NRF53_ANOMALY_168_WORKAROUND) +#define SOC_ON_EXIT_CPU_IDLE \ + .rept 8; \ nop; \ - nop; \ - nop; + .endr +#endif #endif /* _ASMLANGUAGE */ diff --git a/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt new file mode 100644 index 00000000000..8b4df42fa55 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources(soc.c) + +# Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes +# for the image correctly +zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp new file mode 100644 index 00000000000..d90f87c0b89 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpuapp @@ -0,0 +1,17 @@ +# Nordic Semiconductor nRF54H20 Application MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPUAPP + +config SOC + default "nrf54h20_enga_cpuapp" + +config NUM_IRQS + default 471 + +config NRF_REGTOOL_GENERATE_UICR + default y + +endif # SOC_NRF54H20_ENGA_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad new file mode 100644 index 00000000000..6aae8c3a105 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_cpurad @@ -0,0 +1,17 @@ +# Nordic Semiconductor nRF54H20 Radio MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPURAD + +config SOC + default "nrf54h20_enga_cpurad" + +config NUM_IRQS + default 471 + +config NRF_REGTOOL_GENERATE_UICR + default y + +endif # SOC_NRF54H20_ENGA_CPURAD diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series new file mode 100644 index 00000000000..ddc902d213e --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.defconfig.series @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54HX + +rsource "Kconfig.defconfig.nrf54h*" + +config SOC_SERIES + default "nrf54h" + +config CACHE_NRF_CACHE + default y if EXTERNAL_CACHE + +endif # SOC_SERIES_NRF54HX diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.series b/soc/arm/nordic_nrf/nrf54h/Kconfig.series new file mode 100644 index 00000000000..0b896f477ac --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.series @@ -0,0 +1,16 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54HX + bool "Nordic Semiconductor nRF54H series MCU" + select ARM + select ARMV8_M_DSP + select CPU_CORTEX_M33 + select SOC_FAMILY_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + help + Enable support for nRF54H MCU series diff --git a/soc/arm/nordic_nrf/nrf54h/Kconfig.soc b/soc/arm/nordic_nrf/nrf54h/Kconfig.soc new file mode 100644 index 00000000000..9c065e79eaf --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/Kconfig.soc @@ -0,0 +1,37 @@ +# Nordic Semiconductor nRF54H MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NRF54H20 + bool "nRF54H20" + depends on SOC_SERIES_NRF54HX + +if SOC_NRF54H20 + +choice + prompt "nRF54H20 MCU Selection" + +config SOC_NRF54H20_ENGA_CPUAPP + bool "nRF54H20 ENGA CPUAPP" + select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CPU_HAS_FPU + +config SOC_NRF54H20_ENGA_CPURAD + bool "nRF54H20 ENGA CPURAD" + select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select CPU_HAS_FPU + +endchoice + +config NRF_ENABLE_ICACHE + bool "Instruction cache (I-Cache)" + default y + +endif # SOC_NRF54H20 diff --git a/soc/arm/nordic_nrf/nrf54h/align.ld b/soc/arm/nordic_nrf/nrf54h/align.ld new file mode 100644 index 00000000000..0905aa7f7bc --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/align.ld @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_PROLOGUE(.align16,,) +{ + . = (ALIGN(16) > 0 ? ALIGN(16) : 16) - 1; + BYTE(0); +} GROUP_LINK_IN(ROMABLE_REGION) diff --git a/soc/arm/nordic_nrf/nrf54h/soc.c b/soc/arm/nordic_nrf/nrf54h/soc.c new file mode 100644 index 00000000000..9fefd414152 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/soc.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#if defined(NRF_APPLICATION) +#define HSFLL_NODE DT_NODELABEL(cpuapp_hsfll) +#elif defined(NRF_RADIOCORE) +#define HSFLL_NODE DT_NODELABEL(cpurad_hsfll) +#endif + +#define FICR_ADDR_GET(node_id, name) \ + DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) + \ + DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset) + +static void power_domain_init(void) +{ + /* + * Set: + * - LRCCONF010.POWERON.MAIN: 1 + * - LRCCONF010.POWERON.ACT: 1 + * - LRCCONF010.RETAIN.MAIN: 1 + * - LRCCONF010.RETAIN.ACT: 1 + * + * This is done here at boot so that when the idle routine will hit + * WFI the power domain will be correctly retained. + */ + + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); + nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); + + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true); + nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); + +#if defined(CONFIG_SOC_NRF54H20_ENGA_CPUAPP) + nrf_lrcconf_poweron_force_set(NRF_LRCCONF000, NRF_LRCCONF_POWER_DOMAIN_0, true); +#endif +} + +static int trim_hsfll(void) +{ + NRF_HSFLL_Type *hsfll = (NRF_HSFLL_Type *)DT_REG_ADDR(HSFLL_NODE); + nrf_hsfll_trim_t trim = { + .vsup = sys_read32(FICR_ADDR_GET(HSFLL_NODE, vsup)), + .coarse = sys_read32(FICR_ADDR_GET(HSFLL_NODE, coarse)), + .fine = sys_read32(FICR_ADDR_GET(HSFLL_NODE, fine)) + }; + + LOG_DBG("Trim: HSFLL VSUP: 0x%.8x", trim.vsup); + LOG_DBG("Trim: HSFLL COARSE: 0x%.8x", trim.coarse); + LOG_DBG("Trim: HSFLL FINE: 0x%.8x", trim.fine); + + nrf_hsfll_clkctrl_mult_set(hsfll, + DT_PROP(HSFLL_NODE, clock_frequency) / + DT_PROP(DT_CLOCKS_CTLR(HSFLL_NODE), clock_frequency)); + nrf_hsfll_trim_set(hsfll, &trim); + + nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE); +#if defined(CONFIG_SOC_NRF54H20_ENGA_CPUAPP) || defined(CONFIG_SOC_NRF54H20_ENGA_CPURAD) + /* In this HW revision, HSFLL task frequency change needs to be + * triggered additional time to take effect. + */ + nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE); +#endif + + LOG_DBG("NRF_HSFLL->TRIM.VSUP = %d", hsfll->TRIM.VSUP); + LOG_DBG("NRF_HSFLL->TRIM.COARSE = %d", hsfll->TRIM.COARSE); + LOG_DBG("NRF_HSFLL->TRIM.FINE = %d", hsfll->TRIM.FINE); + + return 0; +} + +static int nordicsemi_nrf54h_init(void) +{ +#if defined(CONFIG_NRF_ENABLE_ICACHE) + sys_cache_instr_enable(); +#endif + + power_domain_init(); + + trim_hsfll(); + + return 0; +} + +void arch_busy_wait(uint32_t time_us) +{ + nrfx_coredep_delay_us(time_us); +} + +SYS_INIT(nordicsemi_nrf54h_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nordic_nrf/nrf54h/soc.h b/soc/arm/nordic_nrf/nrf54h/soc.h new file mode 100644 index 00000000000..9a44ab24982 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54h/soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ +#define SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ + +#include + +#endif /* SOC_ARM_NORDIC_NRF_NRF54H_SOC_H_ */ diff --git a/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt new file mode 100644 index 00000000000..33036acce8f --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources( + soc.c + ../validate_rram_partitions.c) + +if (CONFIG_ELV_GRTC_LFXO_ALLOWED) + message(WARNING "WARNING! ELV mode feature is EXPERIMENTAL and may brick your device!") +endif() diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp new file mode 100644 index 00000000000..d19df604c02 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.nrf54l15_enga_cpuapp @@ -0,0 +1,18 @@ +# Nordic Semiconductor nRF54L15 MCU + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54L15_ENGA_CPUAPP + +config SOC + string + default "nrf54l15_cpuapp" + +config NUM_IRQS + default 271 + +config IEEE802154_NRF5 + default IEEE802154 + +endif # SOC_NRF54L15_ENGA_CPUAPP diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series new file mode 100644 index 00000000000..6c0a5bc606d --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Nordic Semiconductor nRF54L MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54LX + +rsource "Kconfig.defconfig.nrf54l*" + +config SOC_SERIES + default "nrf54l" + +config CORTEX_M_SYSTICK + default !NRF_GRTC_TIMER + +config CACHE_NRF_CACHE + default y if EXTERNAL_CACHE + +endif # SOC_SERIES_NRF54LX diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.series b/soc/arm/nordic_nrf/nrf54l/Kconfig.series new file mode 100644 index 00000000000..a9367a0bf36 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.series @@ -0,0 +1,13 @@ +# Nordic Semiconductor nRF54L MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54LX + bool "Nordic Semiconductor nRF54L series MCU" + select HAS_NRFX + select HAS_NORDIC_DRIVERS + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select SOC_FAMILY_NRF + help + Enable support for nRF54L MCU series diff --git a/soc/arm/nordic_nrf/nrf54l/Kconfig.soc b/soc/arm/nordic_nrf/nrf54l/Kconfig.soc new file mode 100644 index 00000000000..c42c8cfc9b3 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/Kconfig.soc @@ -0,0 +1,70 @@ +# Nordic Semiconductor nRF54 MCU line + +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54LX + +config SOC_NRF54L15 + bool "NRF54L15" + +config SOC_NRF54L15_ENGA + bool "NRF54L15 ENGA" + select SOC_NRF54L15 + +config SOC_NRF54L15_ENGA_CPUAPP + bool "NRF54L15 ENGA CPUAPP" + select ARM + select ARMV8_M_DSP + select CPU_CORTEX_M33 + select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_ARM_SAU + select CPU_HAS_FPU + select HAS_HW_NRF_RADIO_IEEE802154 + select HAS_POWEROFF + select SOC_NRF54L15_ENGA + +config SOC_NRF54LX_SKIP_CLOCK_CONFIG + bool "Skip clock frequency configuration in system initialization" + help + With this option, the CPU clock frequency is not set during system initialization. + The CPU runs with the default, hardware-selected frequency. + +config SOC_NRF_FORCE_CONSTLAT + bool "Force constant-latency mode" + help + In constant latency mode the CPU wakeup latency and the PPI task response + will be constant and kept at a minimum. This is secured by forcing a set + of base resources on while in sleep. The advantage of having a constant + and predictable latency will be at the cost of having increased power consumption. + +config SOC_NRF54L_VREG_MAIN_DCDC + bool "NRF54L DC/DC converter." + help + To enable, an inductor must be connected to the DC/DC converter pin. + +config SOC_NRF54L_NORMAL_VOLTAGE_MODE + bool "NRF54L Normal Voltage Mode." + +config SOC_NRF54L_GLITCHDET_WORKAROUND + bool "Workaround that disables glitch detector" + default y + help + Temporary workaround - disabling glitch detector to limit power consumption. + +if NRF_GRTC_TIMER + +config ELV_GRTC_LFXO_ALLOWED + bool + depends on NRF_GRTC_SLEEP_ALLOWED + select EXPERIMENTAL + help + This feature allows using ELV mode when GRTC operates with the LFXO as + a low-frequency clock source. The LFXO is automatically activated when + preparing to system-off. + WARNING! This feature is EXPERIMENTAL and may brick your device! + +endif # NRF_GRTC_TIMER + +endif # SOC_SERIES_NRF54LX diff --git a/soc/arm/nordic_nrf/nrf54l/soc.c b/soc/arm/nordic_nrf/nrf54l/soc.c new file mode 100644 index 00000000000..a7b286fa048 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/soc.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief System/hardware module for Nordic Semiconductor nRF54L family processor + * + * This module provides routines to initialize and support board-level hardware + * for the Nordic Semiconductor nRF54L family processor. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); + +#define LFXO_NODE DT_NODELABEL(lfxo) +#define HFXO_NODE DT_NODELABEL(hfxo) + +static int nordicsemi_nrf54l_init(void) +{ + /* Update the SystemCoreClock global variable with current core clock + * retrieved from hardware state. + */ + SystemCoreClockUpdate(); + + /* Enable ICACHE */ + sys_cache_instr_enable(); + + if (IS_ENABLED(CONFIG_SOC_NRF54L_GLITCHDET_WORKAROUND)) { + nrf_glitchdet_enable_set(NRF_GLITCHDET, false); + } + +#if DT_ENUM_HAS_VALUE(LFXO_NODE, load_capacitors, internal) + uint32_t xosc32ktrim = NRF_FICR->XOSC32KTRIM; + + uint32_t offset_k = + (xosc32ktrim & FICR_XOSC32KTRIM_OFFSET_Msk) >> FICR_XOSC32KTRIM_OFFSET_Pos; + + uint32_t slope_field_k = + (xosc32ktrim & FICR_XOSC32KTRIM_SLOPE_Msk) >> FICR_XOSC32KTRIM_SLOPE_Pos; + uint32_t slope_mask_k = FICR_XOSC32KTRIM_SLOPE_Msk >> FICR_XOSC32KTRIM_SLOPE_Pos; + uint32_t slope_sign_k = (slope_mask_k - (slope_mask_k >> 1)); + int32_t slope_k = (int32_t)(slope_field_k ^ slope_sign_k) - (int32_t)slope_sign_k; + + /* As specified in the nRF54L15 PS: + * CAPVALUE = round( (CAPACITANCE - 4) * (FICR->XOSC32KTRIM.SLOPE + 0.765625 * 2^9)/(2^9) + * + FICR->XOSC32KTRIM.OFFSET/(2^6) ); + * where CAPACITANCE is the desired capacitor value in pF, holding any + * value between 4 pF and 18 pF in 0.5 pF steps. + */ + uint32_t mid_val = + (((DT_PROP(LFXO_NODE, load_capacitance_femtofarad) * 2UL) / 1000UL - 8UL) * + (uint32_t)(slope_k + 392)) + (offset_k << 4UL); + uint32_t capvalue_k = mid_val >> 10UL; + + /* Round. */ + if ((mid_val % 1024UL) >= 512UL) { + capvalue_k++; + } + nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS, (nrf_oscillators_lfxo_cap_t)capvalue_k); +#elif DT_ENUM_HAS_VALUE(LFXO_NODE, load_capacitors, external) + nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS, (nrf_oscillators_lfxo_cap_t)0); +#endif + +#if DT_ENUM_HAS_VALUE(HFXO_NODE, load_capacitors, internal) + uint32_t xosc32mtrim = NRF_FICR->XOSC32MTRIM; + /* The SLOPE field is in the two's complement form, hence this special + * handling. Ideally, it would result in just one SBFX instruction for + * extracting the slope value, at least gcc is capable of producing such + * output, but since the compiler apparently tries first to optimize + * additions and subtractions, it generates slightly less than optimal + * code. + */ + uint32_t slope_field = + (xosc32mtrim & FICR_XOSC32MTRIM_SLOPE_Msk) >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_mask = FICR_XOSC32MTRIM_SLOPE_Msk >> FICR_XOSC32MTRIM_SLOPE_Pos; + uint32_t slope_sign = (slope_mask - (slope_mask >> 1)); + int32_t slope_m = (int32_t)(slope_field ^ slope_sign) - (int32_t)slope_sign; + uint32_t offset_m = + (xosc32mtrim & FICR_XOSC32MTRIM_OFFSET_Msk) >> FICR_XOSC32MTRIM_OFFSET_Pos; + /* As specified in the nRF54L15 PS: + * CAPVALUE = (((CAPACITANCE-5.5)*(FICR->XOSC32MTRIM.SLOPE+791)) + + * FICR->XOSC32MTRIM.OFFSET<<2)>>8; + * where CAPACITANCE is the desired total load capacitance value in pF, + * holding any value between 4.0 pF and 17.0 pF in 0.25 pF steps. + */ + uint32_t capvalue = + (((((DT_PROP(HFXO_NODE, load_capacitance_femtofarad) * 4UL) / 1000UL) - 22UL) * + (uint32_t)(slope_m + 791) / 4UL) + (offset_m << 2UL)) >> 8UL; + + nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, true, capvalue); +#elif DT_ENUM_HAS_VALUE(HFXO_NODE, load_capacitors, external) + nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, false, 0); +#endif + + if (IS_ENABLED(CONFIG_SOC_NRF_FORCE_CONSTLAT)) { + nrf_power_task_trigger(NRF_POWER, NRF_POWER_TASK_CONSTLAT); + } + + if (IS_ENABLED(CONFIG_SOC_NRF54L_VREG_MAIN_DCDC)) { + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_MAIN, true); + } + + if (IS_ENABLED(CONFIG_SOC_NRF54L_NORMAL_VOLTAGE_MODE)) { + nrf_regulators_vreg_enable_set(NRF_REGULATORS, NRF_REGULATORS_VREG_MEDIUM, false); + } + +#if defined(CONFIG_ELV_GRTC_LFXO_ALLOWED) + nrf_regulators_elv_mode_allow_set(NRF_REGULATORS, NRF_REGULATORS_ELV_ELVGRTCLFXO_MASK); +#endif /* CONFIG_ELV_GRTC_LFXO_ALLOWED */ + + return 0; +} + +void arch_busy_wait(uint32_t time_us) +{ + nrfx_coredep_delay_us(time_us); +} + +SYS_INIT(nordicsemi_nrf54l_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nordic_nrf/nrf54l/soc.h b/soc/arm/nordic_nrf/nrf54l/soc.h new file mode 100644 index 00000000000..b775fa9d0f3 --- /dev/null +++ b/soc/arm/nordic_nrf/nrf54l/soc.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the Nordic Semiconductor NRF54L family processors. + */ + +#ifndef _NORDICSEMI_NRF54L_SOC_H_ +#define _NORDICSEMI_NRF54L_SOC_H_ + +#include + +#define FLASH_PAGE_ERASE_MAX_TIME_US 8000UL +#define FLASH_PAGE_MAX_CNT 381UL + +#endif /* _NORDICSEMI_NRF54L_SOC_H_ */ diff --git a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt index 7424bb9f7b9..35d47fb252b 100644 --- a/soc/arm/nordic_nrf/nrf91/CMakeLists.txt +++ b/soc/arm/nordic_nrf/nrf91/CMakeLists.txt @@ -1,7 +1,3 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - ) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") +zephyr_library_sources(soc.c) diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series index 9612555a4c8..6d6cccab999 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.series @@ -10,4 +10,8 @@ source "soc/arm/nordic_nrf/nrf91/Kconfig.defconfig.nrf91*" config SOC_SERIES default "nrf91" +# If the kernel has timer support, enable the timer +config NRF_RTC_TIMER + default y if SYS_CLOCK_EXISTS + endif # SOC_SERIES_NRF91X diff --git a/soc/arm/nordic_nrf/validate_base_addresses.c b/soc/arm/nordic_nrf/validate_base_addresses.c index 58aaa5a7513..28ec231b132 100644 --- a/soc/arm/nordic_nrf/validate_base_addresses.c +++ b/soc/arm/nordic_nrf/validate_base_addresses.c @@ -16,6 +16,10 @@ #define NRF_CTRLAP NRF_CTRL_AP_PERI #endif +#if !defined(NRF_GPIOTE0) && defined(NRF_GPIOTE) +#define NRF_GPIOTE0 NRF_GPIOTE +#endif + #if !defined(NRF_I2S0) && defined(NRF_I2S) #define NRF_I2S0 NRF_I2S #endif @@ -141,6 +145,12 @@ CHECK_DT_REG(flash_controller, NRF_NVMC); CHECK_DT_REG(gpio0, NRF_P0); CHECK_DT_REG(gpio1, NRF_P1); CHECK_DT_REG(gpiote, NRF_GPIOTE); +CHECK_DT_REG(gpiote0, NRF_GPIOTE0); +CHECK_DT_REG(gpiote1, NRF_GPIOTE1); +CHECK_DT_REG(gpiote20, NRF_GPIOTE20); +CHECK_DT_REG(gpiote30, NRF_GPIOTE30); +CHECK_DT_REG(gpiote130, NRF_GPIOTE130); +CHECK_DT_REG(gpiote131, NRF_GPIOTE131); CHECK_I2C_REG(i2c0, 0); CHECK_I2C_REG(i2c1, 1); CHECK_DT_REG(i2c2, NRF_TWIM2); @@ -188,10 +198,31 @@ CHECK_DT_REG(timer1, NRF_TIMER1); CHECK_DT_REG(timer2, NRF_TIMER2); CHECK_DT_REG(timer3, NRF_TIMER3); CHECK_DT_REG(timer4, NRF_TIMER4); +CHECK_DT_REG(timer00, NRF_TIMER00); +CHECK_DT_REG(timer10, NRF_TIMER10); +CHECK_DT_REG(timer20, NRF_TIMER20); +CHECK_DT_REG(timer21, NRF_TIMER21); +CHECK_DT_REG(timer22, NRF_TIMER22); +CHECK_DT_REG(timer23, NRF_TIMER23); +CHECK_DT_REG(timer24, NRF_TIMER24); CHECK_UART_REG(uart0, 0); CHECK_DT_REG(uart1, NRF_UARTE1); CHECK_DT_REG(uart2, NRF_UARTE2); CHECK_DT_REG(uart3, NRF_UARTE3); +CHECK_DT_REG(uart00, NRF_UARTE00); +CHECK_DT_REG(uart20, NRF_UARTE20); +CHECK_DT_REG(uart21, NRF_UARTE21); +CHECK_DT_REG(uart22, NRF_UARTE22); +CHECK_DT_REG(uart30, NRF_UARTE30); +CHECK_DT_REG(uart120, NRF_UARTE120); +CHECK_DT_REG(uart130, NRF_UARTE130); +CHECK_DT_REG(uart131, NRF_UARTE131); +CHECK_DT_REG(uart132, NRF_UARTE132); +CHECK_DT_REG(uart133, NRF_UARTE133); +CHECK_DT_REG(uart134, NRF_UARTE134); +CHECK_DT_REG(uart135, NRF_UARTE135); +CHECK_DT_REG(uart136, NRF_UARTE136); +CHECK_DT_REG(uart137, NRF_UARTE137); CHECK_DT_REG(uicr, NRF_UICR); CHECK_DT_REG(usbd, NRF_USBD); CHECK_DT_REG(usbreg, NRF_USBREGULATOR); @@ -199,6 +230,8 @@ CHECK_DT_REG(vmc, NRF_VMC); CHECK_DT_REG(wdt, NRF_WDT0); /* this should be the same node as wdt0 */ CHECK_DT_REG(wdt0, NRF_WDT0); CHECK_DT_REG(wdt1, NRF_WDT1); +CHECK_DT_REG(wdt30, NRF_WDT30); +CHECK_DT_REG(wdt31, NRF_WDT31); /* nRF51/nRF52-specific addresses */ #if defined(CONFIG_SOC_SERIES_NRF51X) || defined(CONFIG_SOC_SERIES_NRF52X) diff --git a/soc/arm/nordic_nrf/validate_rram_partitions.c b/soc/arm/nordic_nrf/validate_rram_partitions.c new file mode 100644 index 00000000000..f35d9cf73f3 --- /dev/null +++ b/soc/arm/nordic_nrf/validate_rram_partitions.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define PAIR__(f, sep, arg_first, ...) FOR_EACH_FIXED_ARG(f, sep, arg_first, __VA_ARGS__) +#define PAIR_(f, sep, args_to_expand) PAIR__(f, sep, args_to_expand) +#define PAIR(n, f, sep, ...) PAIR_(f, sep, GET_ARGS_LESS_N(n, __VA_ARGS__)) + +/** + * @brief Call a macro on every unique pair of the given variadic arguments. + * + * For example, FOR_EACH_PAIR(f, (,), 1, 2, 3, 4) should expand to: + * + * f(2, 1) , f(3, 1) , f(4, 1) , f(3, 2) , f(4, 2) , f(4, 3) + * + * @param f Macro to call. Must accept two arguments. + * @param sep Separator between macro calls. Must be in parentheses. + * + * @see FOR_EACH + */ +#define FOR_EACH_PAIR(f, sep, ...) \ + LISTIFY(NUM_VA_ARGS_LESS_1(__VA_ARGS__), PAIR, sep, f, sep, __VA_ARGS__) + +/** + * @brief Get a node's non-secure register block start address. + * + * @param node_id Node identifier. + */ +#define REG_ADDR_NS(node_id) (DT_REG_ADDR(node_id) & 0xEFFFFFFFUL) + +/** + * @brief Get a node's non-secure register block end address. + * + * @param node_id Node identifier. + */ +#define REG_END_NS(node_id) (REG_ADDR_NS(node_id) + DT_REG_SIZE(node_id)) + +/* clang-format off */ + +#define RRAM_BASE REG_ADDR_NS(DT_NODELABEL(rram0)) +#define RRAM_CONTROLLER DT_NODELABEL(rram_controller) + +#if !DT_NODE_EXISTS(RRAM_CONTROLLER) +#error "Missing \"rram-controller\" node" +#endif + +#define CHECK_RRAM_NODE_COMPATIBLE(node_id) \ + BUILD_ASSERT(DT_NODE_HAS_COMPAT(node_id, soc_nv_flash), \ + "Missing compatible \"soc-nv-flash\" from " DT_NODE_FULL_NAME(node_id) \ + " (required for all children of " DT_NODE_PATH(RRAM_CONTROLLER) ")") + +#define CHECK_RRAM_PARTITION_WITHIN_PARENT(node_id) \ + BUILD_ASSERT(RRAM_BASE + REG_ADDR_NS(node_id) >= REG_ADDR_NS(DT_GPARENT(node_id)) && \ + RRAM_BASE + REG_END_NS(node_id) <= REG_END_NS(DT_GPARENT(node_id)), \ + DT_NODE_FULL_NAME(node_id) " is not fully contained within its parent " \ + DT_NODE_PATH(DT_GPARENT(node_id))) + +#define CHECK_NODES_NON_OVERLAPPING(node_id_1, node_id_2) \ + BUILD_ASSERT(REG_ADDR_NS(node_id_1) >= REG_END_NS(node_id_2) || \ + REG_ADDR_NS(node_id_2) >= REG_END_NS(node_id_1), \ + DT_NODE_PATH(node_id_1) " and " DT_NODE_PATH(node_id_2) " are overlapping") + +/* Retrieve all RRAM nodes that are children of "rram-controller". */ +#define COMMA(x) x, +#define RRAM_NODES_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD(RRAM_CONTROLLER, COMMA)) + +#if !IS_EMPTY(RRAM_NODES_LIST) + +/* Check that every RRAM node matches the "soc-nv-flash" compatible. */ +FOR_EACH(CHECK_RRAM_NODE_COMPATIBLE, (;), RRAM_NODES_LIST); + +/* Check that no two RRAM nodes are overlapping. */ +FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_NODES_LIST); + +#endif + +/* Retrieve all RRAM partitions by looking for "fixed-partitions" compatibles in each RRAM node. */ +#define PARTITION_(x) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(x, fixed_partitions), (DT_FOREACH_CHILD(x, COMMA)), ()) +#define PARTITION(x, ...) DT_FOREACH_CHILD_STATUS_OKAY(x, PARTITION_) +#define RRAM_PARTITION_LIST LIST_DROP_EMPTY(DT_FOREACH_CHILD_VARGS(RRAM_CONTROLLER, PARTITION)) + +#if !IS_EMPTY(RRAM_PARTITION_LIST) + +/* Check that every RRAM partition is within the bounds of its parent RRAM node. */ +FOR_EACH(CHECK_RRAM_PARTITION_WITHIN_PARENT, (;), RRAM_PARTITION_LIST); + +/* Check that no two RRAM partitions are overlapping. */ +FOR_EACH_PAIR(CHECK_NODES_NON_OVERLAPPING, (;), RRAM_PARTITION_LIST); + +#endif diff --git a/soc/arm/nuvoton_npcx/Kconfig b/soc/arm/nuvoton_npcx/Kconfig index 27b260025cc..1e27a6c4608 100644 --- a/soc/arm/nuvoton_npcx/Kconfig +++ b/soc/arm/nuvoton_npcx/Kconfig @@ -42,6 +42,7 @@ config NPCX_HEADER_CHIP default "npcx9m3" if SOC_NPCX9M3F default "npcx9m6" if SOC_NPCX9M6F default "npcx9m7" if SOC_NPCX9M7F + default "npcx9mfp" if SOC_NPCX9MFP default "npcx4m3" if SOC_NPCX4M3F default "npcx4m8" if SOC_NPCX4M8F diff --git a/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py b/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py index e580758f274..ab1aad770d8 100755 --- a/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py +++ b/soc/arm/nuvoton_npcx/common/ecst/ecst_args.py @@ -53,6 +53,7 @@ 'npcx9m3': {'ram_address': 0x10080000, 'ram_size': 0x50000}, 'npcx9m6': {'ram_address': 0x10090000, 'ram_size': 0x40000}, 'npcx9m7': {'ram_address': 0x10070000, 'ram_size': 0x60000}, + 'npcx9mfp': {'ram_address': 0x10058000, 'ram_size': 0x80000}, 'npcx4m3': {'ram_address': 0x10088000, 'ram_size': 0x50000}, 'npcx4m8': {'ram_address': 0x10060000, 'ram_size': 0x7c800}, } diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_access.h b/soc/arm/nuvoton_npcx/common/reg/reg_access.h index 4f302f51461..ae1d6a61694 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_access.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_access.h @@ -27,4 +27,12 @@ ((reg) = ((reg) & (~(((1 << (f_size))-1) << (f_pos)))) \ | ((value) << (f_pos))) +#define GET_FIELD_POS(field) \ + _GET_FIELD_POS_(FIELD_POS(field)) +#define _GET_FIELD_POS_(f_ops) f_ops + +#define GET_FIELD_SZ(field) \ + _GET_FIELD_SZ_(FIELD_SIZE(field)) +#define _GET_FIELD_SZ_(f_ops) f_ops + #endif /* _NUVOTON_NPCX_REG_ACCESS_H */ diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index e9ef3460e63..a4a23e543e6 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -625,14 +625,35 @@ struct espi_reg { volatile uint32_t reserved8[11]; /* 0x3FC: OOB Channel Control used in 'direct' mode */ volatile uint32_t OOBCTL_DIRECT; - /* 0x400 - 443: Flash Receive Buffer 0-16 */ - volatile uint32_t FLASHRXBUF[17]; - volatile uint32_t reserved9[15]; - /* 0x480 - 497: Flash Transmit Buffer 0-5 */ - volatile uint32_t FLASHTXBUF[6]; - volatile uint32_t reserved10[25]; + /* 0x400 - 443: Flash Receive Buffer 0-17 */ + volatile uint32_t FLASHRXBUF[18]; + volatile uint32_t reserved9[14]; + /* 0x480 - 497: Flash Transmit Buffer 0-16 */ + volatile uint32_t FLASHTXBUF[17]; + volatile uint32_t reserved10[14]; /* 0x4FC: Flash Channel Control used in 'direct' mode */ volatile uint32_t FLASHCTL_DIRECT; + volatile uint32_t reserved12[64]; + /* 0x600 - 63F */ + volatile uint32_t FLASH_PRTR_BADDR[16]; + /* 0x640 - 67F */ + volatile uint32_t FLASH_PRTR_HADDR[16]; + /* 0x680 - 6BF */ + volatile uint32_t FLASH_RGN_TAG_OVR[16]; + volatile uint32_t reserved13[80]; + /* 0x800 */ + volatile uint32_t FLASH_RPMC_CFG_1; + /* 0x804 */ + volatile uint32_t FLASH_RPMC_CFG_2; + /* 0x808 */ + volatile uint32_t RMAP_FLASH_OFFS; + /* 0x80C */ + volatile uint32_t RMAP_DST_BASE; + /* 0x810 */ + volatile uint32_t RMAP_WIN_SIZE; + /* 0x814 */ + volatile uint32_t FLASHBASE; + volatile uint32_t reserved14[58]; }; /* eSPI register fields */ @@ -648,6 +669,7 @@ struct espi_reg { #define NPCX_ESPICFG_HCHANS_FIELD FIELD(4, 4) #define NPCX_ESPICFG_IOMODE_FIELD FIELD(8, 2) #define NPCX_ESPICFG_MAXFREQ_FIELD FIELD(10, 3) +#define NPCX_ESPICFG_FLCHANMODE 16 #define NPCX_ESPICFG_PCCHN_SUPP 24 #define NPCX_ESPICFG_VWCHN_SUPP 25 #define NPCX_ESPICFG_OOBCHN_SUPP 26 @@ -657,7 +679,7 @@ struct espi_reg { #define NPCX_ESPIIE_BERRIE 2 #define NPCX_ESPIIE_OOBRXIE 3 #define NPCX_ESPIIE_FLASHRXIE 4 -#define NPCX_ESPIIE_SFLASHRDIE 5 +#define NPCX_ESPIIE_FLNACSIE 5 #define NPCX_ESPIIE_PERACCIE 6 #define NPCX_ESPIIE_DFRDIE 7 #define NPCX_ESPIIE_VWUPDIE 8 @@ -675,6 +697,7 @@ struct espi_reg { #define NPCX_ESPIWE_BERRWE 2 #define NPCX_ESPIWE_OOBRXWE 3 #define NPCX_ESPIWE_FLASHRXWE 4 +#define NPCX_ESPIWE_FLNACSWE 5 #define NPCX_ESPIWE_PERACCWE 6 #define NPCX_ESPIWE_DFRDWE 7 #define NPCX_ESPIWE_VWUPDWE 8 @@ -686,6 +709,7 @@ struct espi_reg { #define NPCX_ESPISTS_BERR 2 #define NPCX_ESPISTS_OOBRX 3 #define NPCX_ESPISTS_FLASHRX 4 +#define NPCX_ESPISTS_FLNACS 5 #define NPCX_ESPISTS_PERACC 6 #define NPCX_ESPISTS_DFRD 7 #define NPCX_ESPISTS_VWUPD 8 @@ -700,6 +724,14 @@ struct espi_reg { #define NPCX_ESPISTS_BMBURSTERR 22 #define NPCX_ESPISTS_BMBURSTDONE 23 #define NPCX_ESPISTS_ESPIRST_LVL 24 +#define NPCX_VWSWIRQ_IRQ_NUM FIELD(0, 7) +#define NPCX_VWSWIRQ_IRQ_LVL 7 +#define NPCX_VWSWIRQ_INDEX FIELD(8, 7) +#define NPCX_VWSWIRQ_INDEX_EN 15 +#define NPCX_VWSWIRQ_DIRTY 16 +#define NPCX_VWSWIRQ_ENPLTRST 17 +#define NPCX_VWSWIRQ_ENCDRST 19 +#define NPCX_VWSWIRQ_EDGE_IRQ 28 #define NPCX_VWEVMS_WIRE FIELD(0, 4) #define NPCX_VWEVMS_VALID FIELD(4, 4) #define NPCX_VWEVMS_IE 18 @@ -716,6 +748,9 @@ struct espi_reg { #define NPCX_FLASHCFG_FLASHBLERSSIZE FIELD(7, 3) #define NPCX_FLASHCFG_FLASHPLSIZE FIELD(10, 3) #define NPCX_FLASHCFG_FLASHREQSIZE FIELD(13, 3) +#define NPCX_FLASHCFG_FLCAPA FIELD(24, 2) +#define NPCX_FLASHCFG_TRGFLEBLKSIZE FIELD(16, 8) +#define NPCX_FLASHCFG_FLREQSUP FIELD(0, 3) #define NPCX_FLASHCTL_FLASH_NP_FREE 0 #define NPCX_FLASHCTL_FLASH_TX_AVAIL 1 #define NPCX_FLASHCTL_STRPHDR 2 @@ -725,10 +760,21 @@ struct espi_reg { #define NPCX_FLASHCTL_CRCEN 14 #define NPCX_FLASHCTL_CHKSUMSEL 15 #define NPCX_FLASHCTL_AMTEN 16 - +#define NPCX_FLASHCTL_SAF_AUTO_READ 18 +#define NPCX_FLASHCTL_AUTO_RD_DIS_CTL 19 +#define NPCX_FLASHCTL_BLK_FLASH_NP_FREE 20 +#define NPCX_FLASHBASE_FLBASE_ADDR FIELD(12, 15) +#define NPCX_FLASH_PRTR_BADDR FIELD(12, 15) +#define NPCX_FRGN_WPR 29 +#define SAF_PROT_LCK 31 +#define NPCX_FRGN_RPR 30 +#define NPCX_FLASH_PRTR_HADDR FIELD(12, 15) +#define NPCX_FLASH_TAG_OVR_RPR FIELD(16, 16) +#define NPCX_FLASH_TAG_OVR_WPR FIELD(0, 16) #define NPCX_ONLY_ESPI_REG1_UNLOCK_REG2 0x55 #define NPCX_ONLY_ESPI_REG1_LOCK_REG2 0 #define NPCX_ONLY_ESPI_REG2_TRANS_END_CONFIG 4 + /* * Mobile System Wake-Up Control (MSWC) device registers */ @@ -1619,7 +1665,11 @@ struct shi_reg { volatile uint8_t EVSTAT2; /* 0x010: Event Enable 2 */ volatile uint8_t EVENABLE2; - volatile uint8_t reserved4[15]; + /* 0x011: SHI Configuration 6 - only in chips which support enhanced buffer mode */ + volatile uint8_t SHICFG6; + /* 0x012: Single Byte Output Buffer - only in chips which support enhanced buffer mode */ + volatile uint8_t SBOBUF; + volatile uint8_t reserved4[13]; /* 0x20~0x9F: Output Buffer */ volatile uint8_t OBUF[128]; /* 0xA0~0x11F: Input Buffer */ @@ -1670,5 +1720,30 @@ struct shi_reg { #define NPCX_EVENABLE2_IBHF2EN 0 #define NPCX_EVENABLE2_CSNREEN 1 #define NPCX_EVENABLE2_CSNFEEN 2 +#define NPCX_SHICFG6_EBUFMD 0 +#define NPCX_SHICFG6_OBUF_SL 1 + +#define IBF_IBHF_EN_MASK (BIT(NPCX_EVENABLE_IBFEN) | BIT(NPCX_EVENABLE_IBHFEN)) + +/* SPIP (SPI Peripheral Interface) registers */ +struct spip_reg { + /* 0x000: SPIP Data In/Out */ + volatile uint16_t SPIP_DATA; + /* 0x002: SPIP Control 1 */ + volatile uint16_t SPIP_CTL1; + /* 0x004: SPIP Status */ + volatile uint8_t SPIP_STAT; + volatile uint8_t reserved1; +}; + +#define NPCX_SPIP_CTL1_SPIEN 0 +#define NPCX_SPIP_CTL1_MOD 2 +#define NPCX_SPIP_CTL1_EIR 5 +#define NPCX_SPIP_CTL1_EIW 6 +#define NPCX_SPIP_CTL1_SCM 7 +#define NPCX_SPIP_CTL1_SCIDL 8 +#define NPCX_SPIP_CTL1_SCDV FIELD(9, 7) +#define NPCX_SPIP_STAT_BSY 0 +#define NPCX_SPIP_STAT_RBF 1 #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/soc/arm/nuvoton_npcx/common/registers.c b/soc/arm/nuvoton_npcx/common/registers.c index 0405bee3567..8c4ed132b46 100644 --- a/soc/arm/nuvoton_npcx/common/registers.c +++ b/soc/arm/nuvoton_npcx/common/registers.c @@ -62,7 +62,7 @@ NPCX_REG_OFFSET_CHECK(twd_reg, TWMWD, 0x00e); NPCX_REG_OFFSET_CHECK(twd_reg, WDCP, 0x010); /* ESPI register structure check */ -NPCX_REG_SIZE_CHECK(espi_reg, 0x500); +NPCX_REG_SIZE_CHECK(espi_reg, 0x900); NPCX_REG_OFFSET_CHECK(espi_reg, FLASHCFG, 0x034); NPCX_REG_OFFSET_CHECK(espi_reg, NPCX_ONLY_ESPI_REG1, 0x0f0); NPCX_REG_OFFSET_CHECK(espi_reg, VWEVMS, 0x140); @@ -185,3 +185,7 @@ NPCX_REG_SIZE_CHECK(kbs_reg, 0x010); NPCX_REG_OFFSET_CHECK(kbs_reg, KBSIN, 0x004); NPCX_REG_OFFSET_CHECK(kbs_reg, KBSOUT0, 0x006); NPCX_REG_OFFSET_CHECK(kbs_reg, KBS_BUF_INDX, 0x00a); + +/* SPIP register structure check */ +NPCX_REG_SIZE_CHECK(spip_reg, 0x006); +NPCX_REG_OFFSET_CHECK(spip_reg, SPIP_CTL1, 0x002); diff --git a/soc/arm/nuvoton_npcx/common/soc_espi_taf.h b/soc/arm/nuvoton_npcx/common/soc_espi_taf.h new file mode 100644 index 00000000000..a8755e080f7 --- /dev/null +++ b/soc/arm/nuvoton_npcx/common/soc_espi_taf.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NUVOTON_NPCX_SOC_ESPI_TAF_H_ +#define _NUVOTON_NPCX_SOC_ESPI_TAF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Transmit buffer for eSPI TAF transaction on NPCX */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Byte 3 | Byte 2 | Byte 1 | Byte 0 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Length | Tag |Length | Type | PKT_LEN | */ +/* | [7:0] | |[11:8] | | | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 3 | Data 2 | Data 1 | Data 0 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 7 | Data 6 | Data 5 | Data 4 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | ... | ... | ... | ... | */ +/* +-------------+--------------+--------------+---------------+ */ +/* | Data 63 | Data 62 | Data 61 | Data 60 | */ +/* +-------------+--------------+--------------+---------------+ */ +/* PKT_LEN holds the sum of header (Type, Tag and Length) length */ +/* and data length */ + +/* + * NPCX_TAF_CMP_HEADER_LEN is the preamble length of Type, Length + * and Tag (i.e. byte 1~byte 3) for flash access completion packet + * on NPCX + */ +#define NPCX_TAF_CMP_HEADER_LEN 3 + +/* Successful Completion Without Data */ +#define CYC_SCS_CMP_WITHOUT_DATA 0x06 +/* Successful middle Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_MIDDLE 0x09 +/* Successful first Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_FIRST 0x0B +/* Successful last Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_LAST 0x0D +/* Successful only Completion With Data */ +#define CYC_SCS_CMP_WITH_DATA_ONLY 0x0F +/* Unsuccessful Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA 0x08 +/* Unsuccessful Last Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA_LAST 0x0C +/* Unsuccessful Only Completion Without Data */ +#define CYC_UNSCS_CMP_WITHOUT_DATA_ONLY 0x0E + +/* Timeout for checking transmit buffer available and no completion was sent */ +#define NPCX_FLASH_CHK_TIMEOUT 10000 + +/* Clear RSTBUFHEADS, FLASH_ACC_TX_AVAIL, and FLASH_ACC_NP_FREE */ +#define NPCX_FLASHCTL_ACCESS_MASK (~(BIT(NPCX_FLASHCTL_RSTBUFHEADS) | \ + BIT(NPCX_FLASHCTL_FLASH_NP_FREE) | \ + BIT(NPCX_FLASHCTL_FLASH_TX_AVAIL))) + +/* Flash Sharing Capability Support */ +#define NPCX_FLASH_SHARING_CAP_SUPP_CAF 0 +#define NPCX_FLASH_SHARING_CAP_SUPP_TAF 2 +#define NPCX_FLASH_SHARING_CAP_SUPP_TAF_AND_CAF 3 + +enum NPCX_ESPI_TAF_REQ { + NPCX_ESPI_TAF_REQ_READ, + NPCX_ESPI_TAF_REQ_WRITE, + NPCX_ESPI_TAF_REQ_ERASE, + NPCX_ESPI_TAF_REQ_RPMC_OP1, + NPCX_ESPI_TAF_REQ_RPMC_OP2, + NPCX_ESPI_TAF_REQ_UNKNOWN, +}; + +/* NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB is default */ +enum NPCX_ESPI_TAF_ERASE_BLOCK_SIZE { + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_1KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_2KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_4KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_8KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_16KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_32KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_64KB, + NPCX_ESPI_TAF_ERASE_BLOCK_SIZE_128KB, +}; + +/* NPCX_ESPI_TAF_MAX_READ_REQ_64B is default */ +enum NPCX_ESPI_TAF_MAX_READ_REQ { + NPCX_ESPI_TAF_MAX_READ_REQ_64B = 1, + NPCX_ESPI_TAF_MAX_READ_REQ_128B, + NPCX_ESPI_TAF_MAX_READ_REQ_256B, + NPCX_ESPI_TAF_MAX_READ_REQ_512B, + NPCX_ESPI_TAF_MAX_READ_REQ_1024B, + NPCX_ESPI_TAF_MAX_READ_REQ_2048B, + NPCX_ESPI_TAF_MAX_READ_REQ_4096B, +}; + +/* + * The configurations of SPI flash are set in FIU module. + * Thus, eSPI TAF driver of NPCX does not need additional hardware configuarations. + * Therefore, define an empty structure here to comply with espi_saf.h + */ +struct espi_saf_hw_cfg { +}; + +struct espi_saf_pr { + uint32_t start; + uint32_t end; + uint16_t override_r; + uint16_t override_w; + uint8_t master_bm_we; + uint8_t master_bm_rd; + uint8_t pr_num; + uint8_t flags; +}; + +struct espi_saf_protection { + size_t nregions; + const struct espi_saf_pr *pregions; +}; + +struct espi_taf_npcx_pckt { + uint8_t tag; + uint8_t *data; +}; + +struct espi_taf_pckt { + uint8_t type; + uint8_t tag; + uint32_t addr; + uint16_t len; + uint32_t src[16]; +}; + +struct npcx_taf_head { + uint8_t pkt_len; + uint8_t type; + uint8_t tag_hlen; + uint8_t llen; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series index 018a38cc14b..1b692cf7621 100644 --- a/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.series @@ -14,9 +14,9 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX +config ESPI_TAF_NPCX default y - depends on ESPI + depends on ESPI_SAF source "soc/arm/nuvoton_npcx/npcx4/Kconfig.defconfig.npcx4*" diff --git a/soc/arm/nuvoton_npcx/npcx4/soc.h b/soc/arm/nuvoton_npcx/npcx4/soc.h index a9d4e88424b..4ada738102c 100644 --- a/soc/arm/nuvoton_npcx/npcx4/soc.h +++ b/soc/arm/nuvoton_npcx/npcx4/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX4 SCFG multi-registers */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) @@ -55,6 +53,7 @@ #include #include #include +#include #include #include diff --git a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series index 4af311aebcb..9b12678dc8e 100644 --- a/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.series @@ -14,10 +14,6 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX - default y - depends on ESPI - source "soc/arm/nuvoton_npcx/npcx7/Kconfig.defconfig.npcx7*" endif # SOC_SERIES_NPCX7 diff --git a/soc/arm/nuvoton_npcx/npcx7/soc.h b/soc/arm/nuvoton_npcx/npcx7/soc.h index 7099552cec3..9b523ce1b8f 100644 --- a/soc/arm/nuvoton_npcx/npcx7/soc.h +++ b/soc/arm/nuvoton_npcx/npcx7/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX7 SCFG multi-registers offset */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp new file mode 100644 index 00000000000..170c3deceaa --- /dev/null +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9mfp @@ -0,0 +1,11 @@ +# Nuvoton Cortex-M4 Embedded Controller + +# Copyright (c) 2023 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NPCX9MFP + +config SOC + default "npcx9mfp" + +endif # SOC_NPCX9MFP diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series index b5ffb594eed..6487b70cf59 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.series @@ -14,10 +14,6 @@ config NUM_IRQS config CORTEX_M_SYSTICK default !NPCX_ITIM_TIMER -config ESPI_NPCX - default y - depends on ESPI - source "soc/arm/nuvoton_npcx/npcx9/Kconfig.defconfig.npcx9*" endif # SOC_SERIES_NPCX9 diff --git a/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc b/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc index e198c44698a..dbebc40d52d 100644 --- a/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc +++ b/soc/arm/nuvoton_npcx/npcx9/Kconfig.soc @@ -16,4 +16,7 @@ config SOC_NPCX9M6F config SOC_NPCX9M7F bool "NPCX9M7F" +config SOC_NPCX9MFP + bool "NPCX9MFP" + endchoice diff --git a/soc/arm/nuvoton_npcx/npcx9/soc.h b/soc/arm/nuvoton_npcx/npcx9/soc.h index 6b6c3f30a44..2ce745650fb 100644 --- a/soc/arm/nuvoton_npcx/npcx9/soc.h +++ b/soc/arm/nuvoton_npcx/npcx9/soc.h @@ -7,9 +7,7 @@ #ifndef _NUVOTON_NPCX_SOC_H_ #define _NUVOTON_NPCX_SOC_H_ -/* CMSIS required definitions */ -#define __FPU_PRESENT CONFIG_CPU_HAS_FPU -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include /* NPCX9 SCFG multi-registers */ #define NPCX_DEVALT_OFFSET(n) (0x010 + n) diff --git a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series index ac0428eff53..7279ac8596e 100644 --- a/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mcimx6x_m4/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_IMX_6X_M4 select HAS_IMX_HAL select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU select CLOCK_CONTROL help Enable support for M4 core of i.MX 6SoloX MCU series diff --git a/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series b/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series index be0065cb373..e7ae54bcbda 100644 --- a/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mcimx7_m4/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_IMX7_M4 select SOC_FAMILY_IMX select CLOCK_CONTROL select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX7 M4 MCU series diff --git a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series index fc55afd4aae..f1eb1fd40fd 100644 --- a/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8ml8_m7/Kconfig.series @@ -9,6 +9,8 @@ config SOC_SERIES_IMX8ML_M7 select CPU_CORTEX_M7 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_VIDEO_PLL help Enable support for i.MX8ML M7 MCU series diff --git a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series index dddb12d1b70..f860a7fbd26 100644 --- a/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8mm6_m4/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_IMX8MM_M4 select CPU_CORTEX_M4 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX8MM M4 MCU series diff --git a/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series b/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series index c4b16d3fb5c..3933037c3a0 100644 --- a/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series +++ b/soc/arm/nxp_imx/mimx8mq6_m4/Kconfig.series @@ -9,5 +9,6 @@ config SOC_SERIES_IMX8MQ_M4 select CPU_CORTEX_M4 select SOC_FAMILY_IMX select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for i.MX8MQ M4 MCU series diff --git a/soc/arm/nxp_imx/rt/CMakeLists.txt b/soc/arm/nxp_imx/rt/CMakeLists.txt index 92ab665a0ef..a8f1d00765a 100644 --- a/soc/arm/nxp_imx/rt/CMakeLists.txt +++ b/soc/arm/nxp_imx/rt/CMakeLists.txt @@ -28,9 +28,19 @@ if(CONFIG_PM) zephyr_sources_ifdef(CONFIG_SOC_SERIES_IMX_RT11XX power_rt11xx.c) endif() -if (CONFIG_FLASH_MCUX_FLEXSPI_XIP AND CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC) +if (CONFIG_SOC_SERIES_IMX_RT10XX AND CONFIG_MEMC_MCUX_FLEXSPI) zephyr_sources(flexspi_rt10xx.c) - zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt10xx.c LOCATION ITCM_TEXT) + endif() +endif () + + +if (CONFIG_SOC_SERIES_IMX_RT11XX AND CONFIG_MEMC_MCUX_FLEXSPI) + zephyr_sources(flexspi_rt11xx.c) + if (CONFIG_FLASH_MCUX_FLEXSPI_XIP) + zephyr_code_relocate(FILES flexspi_rt11xx.c LOCATION ITCM_TEXT) + endif() endif () if (CONFIG_PM AND CONFIG_SOC_SERIES_IMX_RT10XX) diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index b4e8aeb7422..61f537a402d 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -75,6 +75,13 @@ config PM_MCUX_PMU endif # SOC_SERIES_IMX_RT10XX && PM +if ETH_NXP_ENET + +config SYSTEM_WORKQUEUE_STACK_SIZE + default 1560 + +endif # ETH_NXP_ENET + DT_CHOSEN_Z_FLASH := zephyr,flash DT_COMPAT_FLEXSPI := nxp,imx-flexspi @@ -129,6 +136,11 @@ config TEST_EXTRA_STACK_SIZE default 1024 endif # MBEDTLS +# Enable cache management features when using M7 core, since these parts +# have L1 instruction and data caches that should be enabled at boot +config CACHE_MANAGEMENT + default y if CPU_CORTEX_M7 + source "soc/arm/nxp_imx/rt/Kconfig.defconfig.mimxrt*" endif # SOC_SERIES_IMX_RT diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 0058993e825..cbc00915046 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -21,7 +21,10 @@ config SOC_MIMXRT1011 select HAS_MCUX_LPUART select HAS_MCUX_GPT select HAS_MCUX_TRNG + select CPU_HAS_FPU select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_ENET_PLL select HAS_MCUX_USB_EHCI select HAS_MCUX_EDMA @@ -45,6 +48,7 @@ config SOC_MIMXRT1015 select HAS_MCUX_LPUART select HAS_MCUX_GPT select HAS_MCUX_TRNG + select CPU_HAS_FPU select CPU_HAS_FPU_DOUBLE_PRECISION select CPU_HAS_ARM_MPU select INIT_ENET_PLL @@ -338,6 +342,8 @@ config SOC_MIMXRT1176_CM7 select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL select HAS_MCUX_EDMA + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION select BYPASS_LDO_LPSR select ADJUST_LDO @@ -368,6 +374,7 @@ config SOC_MIMXRT1176_CM4 select HAS_MCUX_FLEXSPI select HAS_MCUX_LPUART select HAS_MCUX_GPT + select CPU_HAS_FPU select CPU_HAS_ARM_MPU select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER @@ -402,6 +409,8 @@ config SOC_MIMXRT1166_CM7 select HAS_MCUX_GPT select HAS_MCUX_FLEXCAN select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL @@ -435,6 +444,7 @@ config SOC_MIMXRT1166_CM4 select HAS_MCUX_FLEXSPI select HAS_MCUX_GPT select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select INIT_ARM_PLL select INIT_ENET_PLL if NET_L2_ETHERNET && ETH_DRIVER select INIT_VIDEO_PLL @@ -659,6 +669,8 @@ config SOC_SERIES_IMX_RT10XX bool "i.MX RT 10XX Series" select CPU_CORTEX_M7 select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select PLATFORM_SPECIFIC_INIT config SOC_SERIES_IMX_RT11XX @@ -822,16 +834,4 @@ config SECOND_CORE_MCUX generated header specifying the VMA and LMA of each memory section to load -config IMXRT1XXX_CODE_CACHE - bool "Code cache" - default y - help - Enable Code cache at boot for IMXRT1xxx series - -config IMXRT1XXX_DATA_CACHE - bool "Data cache" - default y - help - Enable Data cache at boot for IMXRT1xxx series - endif # SOC_SERIES_IMX_RT diff --git a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c index b6335f0c256..a6a6239e9e7 100644 --- a/soc/arm/nxp_imx/rt/flexspi_rt10xx.c +++ b/soc/arm/nxp_imx/rt/flexspi_rt10xx.c @@ -5,50 +5,63 @@ */ #include +#include #include +#include +#include +#include -/* reimplementation of non-inline CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) */ -static uint32_t clock_get_usb1_pll_pfd0_clk(void) +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) { - uint32_t freq; + uint8_t divider; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_div_t div_sel; + clock_ip_name_t clk_name; - if (!CLOCK_IsPllEnabled(CCM_ANALOG, kCLOCK_PllUsb1)) { - return 0; + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot) * + (CLOCK_GetDiv(kCLOCK_FlexspiDiv) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + div_sel = kCLOCK_FlexspiDiv; + clk_name = kCLOCK_FlexSpi; + break; +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi2), okay) + case IMX_CCM_FLEXSPI2_CLK: + /* Get clock root frequency */ + root_rate = CLOCK_GetClockRootFreq(kCLOCK_Flexspi2ClkRoot) * + (CLOCK_GetDiv(kCLOCK_Flexspi2Div) + 1); + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + div_sel = kCLOCK_Flexspi2Div; + clk_name = kCLOCK_FlexSpi2; + break; +#endif + default: + return -ENOTSUP; } + /* Select a divider based on root frequency. + * if we can't get an exact divider, round down + */ + divider = ((root_rate + (rate - 1)) / rate) - 1; + /* Cap divider to max value */ + divider = MIN(divider, kCLOCK_FlexspiDivBy8); - freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, kCLOCK_PllUsb1); - - if (CLOCK_IsPllBypassed(CCM_ANALOG, kCLOCK_PllUsb1)) { - return freq; + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ } + FLEXSPI_Enable(flexspi, false); - freq *= ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0) ? 22 : 20; - - /* get current USB1 PLL PFD output frequency */ - freq /= (CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> - CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT; - freq *= 18; + CLOCK_DisableClock(clk_name); - return freq; -} - -void flexspi_clock_set_div(uint32_t value) -{ - CLOCK_DisableClock(kCLOCK_FlexSpi); + CLOCK_SetDiv(div_sel, divider); - CLOCK_SetDiv(kCLOCK_FlexspiDiv, value); - - CLOCK_EnableClock(kCLOCK_FlexSpi); -} - -uint32_t flexspi_clock_get_freq(void) -{ - uint32_t divider; - uint32_t frequency; + CLOCK_EnableClock(clk_name); - divider = CLOCK_GetDiv(kCLOCK_FlexspiDiv); + FLEXSPI_Enable(flexspi, true); - frequency = clock_get_usb1_pll_pfd0_clk() / (divider + 1); + FLEXSPI_SoftwareReset(flexspi); - return frequency; + return 0; } diff --git a/soc/arm/nxp_imx/rt/flexspi_rt11xx.c b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c new file mode 100644 index 00000000000..8b8b34d8682 --- /dev/null +++ b/soc/arm/nxp_imx/rt/flexspi_rt11xx.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate) +{ + clock_name_t root; + uint32_t root_rate; + FLEXSPI_Type *flexspi; + clock_root_t flexspi_clk; + clock_ip_name_t clk_gate; + uint32_t divider; + + switch (clock_name) { + case IMX_CCM_FLEXSPI_CLK: + flexspi_clk = kCLOCK_Root_Flexspi1; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi)); + clk_gate = kCLOCK_Flexspi1; + break; + case IMX_CCM_FLEXSPI2_CLK: + flexspi_clk = kCLOCK_Root_Flexspi2; + flexspi = (FLEXSPI_Type *)DT_REG_ADDR(DT_NODELABEL(flexspi2)); + clk_gate = kCLOCK_Flexspi2; + break; + default: + return -ENOTSUP; + } + root = CLOCK_GetRootClockSource(flexspi_clk, + CLOCK_GetRootClockMux(flexspi_clk)); + /* Get clock root frequency */ + root_rate = CLOCK_GetFreq(root); + /* Select a divider based on root frequency */ + divider = MIN((root_rate / rate), CCM_CLOCK_ROOT_CONTROL_DIV_MASK); + + while (FLEXSPI_GetBusIdleStatus(flexspi) == false) { + /* Spin */ + } + FLEXSPI_Enable(flexspi, false); + + CLOCK_DisableClock(clk_gate); + + CLOCK_SetRootClockDiv(flexspi_clk, divider); + + CLOCK_EnableClock(clk_gate); + + FLEXSPI_Enable(flexspi, true); + + FLEXSPI_SoftwareReset(flexspi); + + return 0; +} diff --git a/soc/arm/nxp_imx/rt/soc.h b/soc/arm/nxp_imx/rt/soc.h index d7e52ba751d..e5129c947d0 100644 --- a/soc/arm/nxp_imx/rt/soc.h +++ b/soc/arm/nxp_imx/rt/soc.h @@ -32,8 +32,9 @@ void imxrt_pre_init_display_interface(void); void imxrt_post_init_display_interface(void); #endif -void flexspi_clock_set_div(uint32_t value); -uint32_t flexspi_clock_get_freq(void); +#ifdef CONFIG_MEMC +uint32_t flexspi_clock_set_freq(uint32_t clock_name, uint32_t rate); +#endif #ifdef __cplusplus } diff --git a/soc/arm/nxp_imx/rt/soc_rt10xx.c b/soc/arm/nxp_imx/rt/soc_rt10xx.c index 91ec748a61a..dd6e534be23 100644 --- a/soc/arm/nxp_imx/rt/soc_rt10xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt10xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #ifdef CONFIG_NXP_IMX_RT_BOOT_HEADER #include @@ -55,7 +56,7 @@ const clock_enet_pll_config_t ethPllConfig = { defined(CONFIG_SOC_MIMXRT1024) .enableClkOutput500M = true, #endif -#ifdef CONFIG_ETH_MCUX +#if defined(CONFIG_ETH_NXP_ENET) || defined(CONFIG_ETH_MCUX) #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) .enableClkOutput = true, #endif @@ -318,23 +319,8 @@ void imxrt_audio_codec_pll_init(uint32_t clock_name, uint32_t clk_src, static int imxrt_init(void) { -#ifndef CONFIG_IMXRT1XXX_CODE_CACHE - /* SystemInit enables code cache, disable it here */ - SCB_DisableICache(); -#else - /* z_arm_init_arch_hw_at_boot() disables code cache if CONFIG_ARCH_CACHE is enabled, - * enable it here. - */ - SCB_EnableICache(); -#endif - - if (IS_ENABLED(CONFIG_IMXRT1XXX_DATA_CACHE)) { - if ((SCB->CCR & SCB_CCR_DC_Msk) == 0) { - SCB_EnableDCache(); - } - } else { - SCB_DisableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Initialize system clock */ clock_init(); diff --git a/soc/arm/nxp_imx/rt/soc_rt11xx.c b/soc/arm/nxp_imx/rt/soc_rt11xx.c index f9eb7b7e381..3adedde8d38 100644 --- a/soc/arm/nxp_imx/rt/soc_rt11xx.c +++ b/soc/arm/nxp_imx/rt/soc_rt11xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -277,7 +278,7 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd2, 24); /* Init System Pll2 pfd3. */ -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 24); #else CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 32); @@ -324,7 +325,7 @@ static ALWAYS_INLINE void clock_init(void) #endif /* Configure BUS using SYS_PLL3_CLK */ -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET /* Configure root bus clock at 198M */ rootCfg.mux = kCLOCK_BUS_ClockRoot_MuxSysPll2Pfd3; rootCfg.div = 2; @@ -396,16 +397,22 @@ static ALWAYS_INLINE void clock_init(void) #endif -#ifdef CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet), okay) /* 50 MHz ENET clock */ rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR4 &= ~IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR4 |= IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U); +#else /* Set ENET_REF_CLK as an output driven by ENET1_CLK_ROOT */ IOMUXC_GPR->GPR4 |= (IOMUXC_GPR_GPR4_ENET_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL(0x1U)); #endif +#endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(enet1g), okay) /* * 50 MHz clock for 10/100Mbit RMII PHY - @@ -414,11 +421,17 @@ static ALWAYS_INLINE void clock_init(void) rootCfg.mux = kCLOCK_ENET2_ClockRoot_MuxSysPll1Div2; rootCfg.div = 10; CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg); +#if CONFIG_ETH_MCUX_RMII_EXT_CLK + /* Set ENET1G_REF_CLK as an input driven by PHY */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U); + IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U); +#else /* Set ENET1G_REF_CLK as an output driven by ENET2_CLK_ROOT */ IOMUXC_GPR->GPR5 |= (IOMUXC_GPR_GPR5_ENET1G_REF_CLK_DIR(0x01U) | IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL(0x1U)); #endif #endif +#endif #ifdef CONFIG_PTP_CLOCK_MCUX /* 24MHz PTP clock */ @@ -661,23 +674,8 @@ static int imxrt_init(void) #if defined(CONFIG_SOC_MIMXRT1176_CM7) || defined(CONFIG_SOC_MIMXRT1166_CM7) -#ifndef CONFIG_IMXRT1XXX_CODE_CACHE - /* SystemInit enables code cache, disable it here */ - SCB_DisableICache(); -#else - /* z_arm_init_arch_hw_at_boot() disables code cache if CONFIG_ARCH_CACHE is enabled, - * enable it here. - */ - SCB_EnableICache(); -#endif - - if (IS_ENABLED(CONFIG_IMXRT1XXX_DATA_CACHE)) { - if ((SCB->CCR & SCB_CCR_DC_Msk) == 0) { - SCB_EnableDCache(); - } - } else { - SCB_DisableDCache(); - } + sys_cache_instr_enable(); + sys_cache_data_enable(); #endif /* Initialize system clock */ diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series index 31b6a2c70db..b277f621d0a 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.defconfig.series @@ -1,6 +1,6 @@ # i.MX RT5XX series configuration options -# Copyright (c) 2022-2023, NXP +# Copyright (c) 2022-2024, NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_IMX_RT5XX @@ -11,8 +11,10 @@ config SOC_SERIES config ROM_START_OFFSET default 0x1200 if NXP_IMX_RT5XX_BOOT_HEADER +# The PVT Sensor uses IRQ #75. For more details, see +# https://www.nxp.com/design/design-center/software/embedded-software/application-software-packs/application-software-pack-dynamic-voltage-scaling-using-pvt-sensor:APP-SW-PACK-DVS-PVT-SENSOR config NUM_IRQS - default 74 + default 76 config ZTEST_NO_YIELD default y if (PM && ZTEST) diff --git a/soc/arm/nxp_imx/rt5xx/Kconfig.soc b/soc/arm/nxp_imx/rt5xx/Kconfig.soc index 2c82c533de9..35b86c2e903 100644 --- a/soc/arm/nxp_imx/rt5xx/Kconfig.soc +++ b/soc/arm/nxp_imx/rt5xx/Kconfig.soc @@ -1,6 +1,6 @@ # i.MX RT5XX Series -# Copyright (c) 2022, NXP +# Copyright 2022-2023, NXP # SPDX-License-Identifier: Apache-2.0 choice @@ -129,4 +129,28 @@ config IMXRT5XX_CODE_CACHE Enable code cache for FlexSPI region at boot. If this Kconfig is cleared, the CACHE64 controller will be disabled during SOC init +choice FLEXCOMM0_CLK_SRC + prompt "Clock source for Flexcomm0" + default FLEXCOMM0_CLK_SRC_FRG + +config FLEXCOMM0_CLK_SRC_FRG + bool "FRG is source of Flexcomm0 clock" + +config FLEXCOMM0_CLK_SRC_FRO + bool "FRO_DIV4 is source of Flexcomm0 clock" + +endchoice + +choice MIPI_DPHY_CLK_SRC + prompt "Clock source for MIPI DPHY" + default MIPI_DPHY_CLK_SRC_AUX1_PLL + +config MIPI_DPHY_CLK_SRC_AUX1_PLL + bool "AUX1_PLL is source of MIPI_DPHY clock" + +config MIPI_DPHY_CLK_SRC_FRO + bool "FRO 192/96M is source of MIPI_DPHY clock" + +endchoice + endif # SOC_SERIES_IMX_RT5XX diff --git a/soc/arm/nxp_imx/rt5xx/power.c b/soc/arm/nxp_imx/rt5xx/power.c index 69b60936fb4..3599dcfa646 100644 --- a/soc/arm/nxp_imx/rt5xx/power.c +++ b/soc/arm/nxp_imx/rt5xx/power.c @@ -16,32 +16,9 @@ LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); #define EXCLUDE_FROM_DEEPSLEEP ((const uint32_t[]) \ DT_PROP_OR(NODE_ID, deep_sleep_config, {})) -static uint32_t isp_pin[3]; - /* System clock frequency. */ extern uint32_t SystemCoreClock; -__ramfunc void set_deepsleep_pin_config(void) -{ - /* Backup Pin configuration. */ - isp_pin[0] = IOPCTL->PIO[1][15]; - isp_pin[1] = IOPCTL->PIO[3][28]; - isp_pin[2] = IOPCTL->PIO[3][29]; - - /* Disable ISP Pin pull-ups and input buffers to avoid current leakage */ - IOPCTL->PIO[1][15] = 0; - IOPCTL->PIO[3][28] = 0; - IOPCTL->PIO[3][29] = 0; -} - -__ramfunc void restore_deepsleep_pin_config(void) -{ - /* Restore the Pin configuration. */ - IOPCTL->PIO[1][15] = isp_pin[0]; - IOPCTL->PIO[3][28] = isp_pin[1]; - IOPCTL->PIO[3][29] = isp_pin[2]; -} - /* Invoke Low Power/System Off specific Tasks */ void pm_state_set(enum pm_state state, uint8_t substate_id) { @@ -65,9 +42,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) POWER_EnterSleep(); break; case PM_STATE_SUSPEND_TO_IDLE: - set_deepsleep_pin_config(); POWER_EnterDeepSleep(EXCLUDE_FROM_DEEPSLEEP); - restore_deepsleep_pin_config(); break; default: LOG_DBG("Unsupported power state %u", state); diff --git a/soc/arm/nxp_imx/rt5xx/soc.c b/soc/arm/nxp_imx/rt5xx/soc.c index d834d3e55bc..ca2a89cd553 100644 --- a/soc/arm/nxp_imx/rt5xx/soc.c +++ b/soc/arm/nxp_imx/rt5xx/soc.c @@ -281,8 +281,12 @@ void __weak rt5xx_clock_init(void) /* Switch SYSTICK_CLK to MAIN_CLK_DIV */ CLOCK_AttachClk(kMAIN_CLK_DIV_to_SYSTICK_CLK); #if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm0), nxp_lpc_usart, okay) - /* Switch FLEXCOMM0 to FRG */ - CLOCK_AttachClk(kFRG_to_FLEXCOMM0); + #ifdef CONFIG_FLEXCOMM0_CLK_SRC_FRG + /* Switch FLEXCOMM0 to FRG */ + CLOCK_AttachClk(kFRG_to_FLEXCOMM0); + #elif defined(CONFIG_FLEXCOMM0_CLK_SRC_FRO) + CLOCK_AttachClk(kFRO_DIV4_to_FLEXCOMM0); + #endif #endif #if CONFIG_USB_DC_NXP_LPCIP3511 usb_device_clock_init(); @@ -423,6 +427,19 @@ void __weak rt5xx_clock_init(void) RESET_PeripheralReset(kMRT0_RST_SHIFT_RSTn); #endif +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(dmic0), nxp_dmic, okay) + /* Using the Audio PLL as input clock leads to better clock dividers + * for typical PCM sample rates ({8,16,24,32,48,96} kHz. + */ + /* DMIC source from audio pll, divider 8, 24.576M/8=3.072MHZ + * Select Audio PLL as clock source. This should produce a bit clock + * of 3.072MHZ + */ + CLOCK_AttachClk(kAUDIO_PLL_to_DMIC); + CLOCK_SetClkDiv(kCLOCK_DivDmicClk, 8); + +#endif + /* Set SystemCoreClock variable. */ SystemCoreClock = CLOCK_INIT_CORE_CLOCK; @@ -458,12 +475,21 @@ void __weak imxrt_pre_init_display_interface(void) * We set the divider of the PFD3 output of the SYSPLL, which has a * fixed multiplied of 18, and use this output frequency for the DPHY. */ + +#ifdef CONFIG_MIPI_DPHY_CLK_SRC_AUX1_PLL + /* Note: AUX1 PLL clock is system pll clock * 18 / pfd. + * system pll clock is configured at 528MHz by default. + */ CLOCK_AttachClk(kAUX1_PLL_to_MIPI_DPHY_CLK); CLOCK_InitSysPfd(kCLOCK_Pfd3, ((CLOCK_GetSysPllFreq() * 18ull) / ((unsigned long long)(DT_PROP(DT_NODELABEL(mipi_dsi), phy_clock))))); CLOCK_SetClkDiv(kCLOCK_DivDphyClk, 1); - +#elif defined(CONFIG_MIPI_DPHY_CLK_SRC_FRO) + CLOCK_AttachClk(kFRO_DIV1_to_MIPI_DPHY_CLK); + CLOCK_SetClkDiv(kCLOCK_DivDphyClk, + (CLK_FRO_CLK / DT_PROP(DT_NODELABEL(mipi_dsi), phy_clock))); +#endif /* Clear DSI control reset (Note that DPHY reset is cleared later)*/ RESET_ClearPeripheralReset(kMIPI_DSI_CTRL_RST_SHIFT_RSTn); } @@ -504,6 +530,14 @@ static int nxp_rt500_init(void) CACHE64_DisableCache(CACHE64_CTRL0); #endif + /* Some ROM versions may have errata leaving these pins in a non-reset state, + * which can often cause power leakage on most expected board designs, + * restore the reset state here and leave the pin configuration up to board/user DT + */ + IOPCTL->PIO[1][15] = 0; + IOPCTL->PIO[3][28] = 0; + IOPCTL->PIO[3][29] = 0; + return 0; } diff --git a/soc/arm/nxp_imx/rt6xx/soc.c b/soc/arm/nxp_imx/rt6xx/soc.c index 2d4eab6854d..165cf92e234 100644 --- a/soc/arm/nxp_imx/rt6xx/soc.c +++ b/soc/arm/nxp_imx/rt6xx/soc.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt index 017787396e4..8ff38d089ce 100644 --- a/soc/arm/nxp_kinetis/k2x/CMakeLists.txt +++ b/soc/arm/nxp_kinetis/k2x/CMakeLists.txt @@ -9,4 +9,9 @@ zephyr_sources( soc.c ) +if(DEFINED CONFIG_ARM_MPU AND DEFINED CONFIG_CPU_HAS_NXP_MPU) + # MK22F12 series MCUs have NXP MPU + zephyr_sources(nxp_mpu_regions.c) +endif() + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 index 3e2e2f50ef7..01f0ec78f2f 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22f12 @@ -11,4 +11,7 @@ config SOC config GPIO default y +config NUM_IRQS + default 74 + endif # SOC_MK22F12 diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 new file mode 100644 index 00000000000..963fdf87162 --- /dev/null +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk22fx12 @@ -0,0 +1,17 @@ +# Copyright 2023 Daniel DeGrasse +# SPDX-License-Identifier: Apache-2.0 + +# Kinetis MK22FX12 configuration options + +if SOC_MK22F12 + +config SOC + default "mk22f12" + +config NUM_IRQS + default 81 + +config CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + default y + +endif # SOC_MK22F12 diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series index 4cec6645964..254fd251014 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.series @@ -12,9 +12,6 @@ if SOC_SERIES_KINETIS_K2X config SOC_SERIES default "k2x" -config NUM_IRQS - default 74 - source "soc/arm/nxp_kinetis/k2x/Kconfig.defconfig.mk*" endif # SOC_SERIES_KINETIS_K2X diff --git a/soc/arm/nxp_kinetis/k2x/Kconfig.soc b/soc/arm/nxp_kinetis/k2x/Kconfig.soc index 5653d6cd75a..0535ac2e684 100644 --- a/soc/arm/nxp_kinetis/k2x/Kconfig.soc +++ b/soc/arm/nxp_kinetis/k2x/Kconfig.soc @@ -26,6 +26,24 @@ config SOC_MK22F51212 select HAS_MCUX_DAC select HAS_MCUX_RCM +# Note- the MK22F12 SKU is a legacy SOC, no longer officially supported by +# NXP's MCUX SDK, and not recommended for new designs. +config SOC_MK22F12 + bool "SOC_MK22F12" + select HAS_MCUX + select HAS_MCUX_SMC + select HAS_MCUX_ADC16 + select HAS_MCUX_FTFX + select HAS_MCUX_FTM + select HAS_MCUX_RNGA + select HAS_MCUX_SIM + select HAS_OSC + select HAS_MCG + select CPU_HAS_FPU + select HAS_MCUX_DAC + select HAS_MCUX_RCM + select CPU_HAS_NXP_MPU + endchoice if SOC_SERIES_KINETIS_K2X @@ -36,9 +54,13 @@ config SOC_PART_NUMBER_MK22FN512VLH12 config SOC_PART_NUMBER_MK22FX512AVLK12 bool +config SOC_PART_NUMBER_MK22FX512VLQ12 + bool + config SOC_PART_NUMBER_KINETIS_K2X string default "MK22FN512VLH12" if SOC_PART_NUMBER_MK22FN512VLH12 + default "MK22FX512VLQ12" if SOC_PART_NUMBER_MK22FX512VLQ12 help This string holds the full part number of the SoC. It is a hidden option that you should not set directly. The part number selection choice defines diff --git a/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c b/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c new file mode 100644 index 00000000000..30a5cff42ea --- /dev/null +++ b/soc/arm/nxp_kinetis/k2x/nxp_mpu_regions.c @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Daniel DeGrasse + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +static const struct nxp_mpu_region mpu_regions[] = { + /* Region 0 */ + /* Debugger access can't be disabled; ENET and USB devices will not be able + * to access RAM when their regions are dynamically disabled in NXP MPU. + */ + MPU_REGION_ENTRY("DEBUGGER_0", + 0, + 0xFFFFFFFF, + REGION_DEBUGGER_AND_DEVICE_ATTR), + + /* The NXP MPU does not give precedence to memory regions like the ARM + * MPU, which means that if one region grants access then another + * region cannot revoke access. If an application enables hardware + * stack protection, we need to disable supervisor writes from the core + * to the stack guard region. As a result, we cannot have a single + * background region that enables supervisor read/write access from the + * core to the entire address space, and instead define two background + * regions that together cover the entire address space except for + * SRAM. + */ + + /* Region 1 */ + MPU_REGION_ENTRY("BACKGROUND_0", + 0, + CONFIG_SRAM_BASE_ADDRESS-1, + REGION_BACKGROUND_ATTR), + /* Region 2 */ + MPU_REGION_ENTRY("BACKGROUND_1", + CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024), + 0xFFFFFFFF, + REGION_BACKGROUND_ATTR), + /* Region 3 */ + MPU_REGION_ENTRY("FLASH_0", + CONFIG_FLASH_BASE_ADDRESS, + (CONFIG_FLASH_BASE_ADDRESS + + (CONFIG_FLASH_SIZE * 1024) - 1), + REGION_FLASH_ATTR), + /* Region 4 */ + MPU_REGION_ENTRY("RAM_U_0", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_RAM_ATTR), +}; + +const struct nxp_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, + .sram_region = 4, +}; diff --git a/soc/arm/nxp_kinetis/k2x/soc.c b/soc/arm/nxp_kinetis/k2x/soc.c index 67ea1183401..d5108fb49d9 100644 --- a/soc/arm/nxp_kinetis/k2x/soc.c +++ b/soc/arm/nxp_kinetis/k2x/soc.c @@ -49,7 +49,9 @@ static const osc_config_t oscConfig = { .oscerConfig = { .enableMode = 0U, /* Disable external reference clock */ +#if FSL_FEATURE_OSC_HAS_EXT_REF_CLOCK_DIVIDER .erclkDiv = 0U, +#endif }, }; diff --git a/soc/arm/nxp_kinetis/k2x/soc.h b/soc/arm/nxp_kinetis/k2x/soc.h index cb88009a49d..88a93b62ef6 100644 --- a/soc/arm/nxp_kinetis/k2x/soc.h +++ b/soc/arm/nxp_kinetis/k2x/soc.h @@ -33,9 +33,6 @@ extern "C" { #ifndef _ASMLANGUAGE #include -#include -#include -#include #endif /* !_ASMLANGUAGE */ diff --git a/soc/arm/nxp_kinetis/k6x/soc.c b/soc/arm/nxp_kinetis/k6x/soc.c index 083f695db32..2463b5ddc28 100644 --- a/soc/arm/nxp_kinetis/k6x/soc.c +++ b/soc/arm/nxp_kinetis/k6x/soc.c @@ -105,7 +105,7 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_SetLpuartClock(LPUART0SRC_OSCERCLK); #endif -#if CONFIG_ETH_MCUX +#if CONFIG_ETH_MCUX || CONFIG_ETH_NXP_ENET CLOCK_SetEnetTime0Clock(TIMESRC_OSCERCLK); #endif #if CONFIG_ETH_MCUX_RMII_EXT_CLK diff --git a/soc/arm/nxp_kinetis/kl2x/Kconfig.series b/soc/arm/nxp_kinetis/kl2x/Kconfig.series index 53558c81648..3c606c7db27 100644 --- a/soc/arm/nxp_kinetis/kl2x/Kconfig.series +++ b/soc/arm/nxp_kinetis/kl2x/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_KINETIS_KL2X select CPU_CORTEX_M0PLUS select SOC_FAMILY_KINETIS select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select CLOCK_CONTROL select PLATFORM_SPECIFIC_INIT help diff --git a/soc/arm/nxp_kinetis/kv5x/Kconfig.series b/soc/arm/nxp_kinetis/kv5x/Kconfig.series index 009d31ea350..0df355a5823 100644 --- a/soc/arm/nxp_kinetis/kv5x/Kconfig.series +++ b/soc/arm/nxp_kinetis/kv5x/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_KINETIS_KV5X select SOC_FAMILY_KINETIS select CPU_HAS_ARM_MPU select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CLOCK_CONTROL select HAS_MCUX select HAS_MCUX_ADC16 diff --git a/soc/arm/nxp_kinetis/kv5x/Kconfig.soc b/soc/arm/nxp_kinetis/kv5x/Kconfig.soc index 3a9a6d3adf2..dd69ca523b0 100644 --- a/soc/arm/nxp_kinetis/kv5x/Kconfig.soc +++ b/soc/arm/nxp_kinetis/kv5x/Kconfig.soc @@ -57,12 +57,4 @@ config SOC_PART_NUMBER_KINETIS_KV5X number selection choice defines the default value for this string. -config KINETIS_KV5X_ENABLE_CODE_CACHE - bool "Code cache" - default y - -config KINETIS_KV5X_ENABLE_DATA_CACHE - bool "Data cache" - default y - endif # SOC_SERIES_KINETIS_KV5X diff --git a/soc/arm/nxp_kinetis/kv5x/soc.c b/soc/arm/nxp_kinetis/kv5x/soc.c index 4c566dadcd0..59b77f1c172 100644 --- a/soc/arm/nxp_kinetis/kv5x/soc.c +++ b/soc/arm/nxp_kinetis/kv5x/soc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -90,14 +91,8 @@ static int kv5x_init(void) /* Initialize system clocks and PLL */ clk_init(); -#ifndef CONFIG_KINETIS_KV5X_ENABLE_CODE_CACHE - /* SystemInit will have enabled the code cache. Disable it here */ - SCB_DisableICache(); -#endif -#ifndef CONFIG_KINETIS_KV5X_ENABLE_DATA_CACHE - /* SystemInit will have enabled the data cache. Disable it here */ - SCB_DisableDCache(); -#endif + sys_cache_instr_enable(); + sys_cache_data_enable(); return 0; } diff --git a/soc/arm/nxp_kinetis/kwx/Kconfig.series b/soc/arm/nxp_kinetis/kwx/Kconfig.series index 4b00dd997a9..36ba7b54c21 100644 --- a/soc/arm/nxp_kinetis/kwx/Kconfig.series +++ b/soc/arm/nxp_kinetis/kwx/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_KINETIS_KWX select ARM select SOC_FAMILY_KINETIS select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select CLOCK_CONTROL select PLATFORM_SPECIFIC_INIT help diff --git a/soc/arm/nxp_lpc/lpc11u6x/soc.h b/soc/arm/nxp_lpc/lpc11u6x/soc.h index fd7ffbd5400..ec0abb4faf1 100644 --- a/soc/arm/nxp_lpc/lpc11u6x/soc.h +++ b/soc/arm/nxp_lpc/lpc11u6x/soc.h @@ -19,6 +19,7 @@ #ifndef _ASMLANGUAGE #include +#include #endif /* !_ASMLANGUAGE */ diff --git a/soc/arm/nxp_lpc/lpc51u68/Kconfig.series b/soc/arm/nxp_lpc/lpc51u68/Kconfig.series index 6995de0917a..8b1a9dd18b1 100644 --- a/soc/arm/nxp_lpc/lpc51u68/Kconfig.series +++ b/soc/arm/nxp_lpc/lpc51u68/Kconfig.series @@ -13,6 +13,7 @@ config SOC_SERIES_LPC51U68 select HAS_MCUX_SCTIMER select SOC_FAMILY_LPC select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select PLATFORM_SPECIFIC_INIT help Enable support for LPC LPC51U68 MCU Series diff --git a/soc/arm/nxp_lpc/lpc51u68/soc.h b/soc/arm/nxp_lpc/lpc51u68/soc.h index 45355fb148e..9135c3fed71 100644 --- a/soc/arm/nxp_lpc/lpc51u68/soc.h +++ b/soc/arm/nxp_lpc/lpc51u68/soc.h @@ -10,6 +10,8 @@ #ifndef _ASMLANGUAGE #include +#include + #endif /* !_ASMLANGUAGE*/ #define IOCON_PIO_DIGITAL_EN 0x80u diff --git a/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc index 099dc832d5b..e71bc8f451e 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc54xxx/Kconfig.soc @@ -12,6 +12,7 @@ config SOC_LPC54114_M4 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select PLATFORM_SPECIFIC_INIT select CLOCK_CONTROL select HAS_MCUX_IAP_LEGACY diff --git a/soc/arm/nxp_lpc/lpc54xxx/soc.c b/soc/arm/nxp_lpc/lpc54xxx/soc.c index bbc689dbc68..20f2022cd56 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc54xxx/soc.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc index c0341a8e9c5..c8c3cae3c49 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc +++ b/soc/arm/nxp_lpc/lpc55xxx/Kconfig.soc @@ -35,6 +35,7 @@ config SOC_LPC55S16 config SOC_LPC55S28 bool "SOC_LPC55S28 M33" select CPU_CORTEX_M33 + select CPU_HAS_ARM_SAU select CPU_HAS_ARM_MPU select CPU_HAS_FPU select ARMV8_M_DSP @@ -123,7 +124,7 @@ config INIT_PLL0 config INIT_PLL1 bool "Initialize PLL1" default "y" - depends on !(SOC_LPC55S06 || FLASH) + depends on !(SOC_LPC55S06 || FLASH || BUILD_WITH_TFM) help In the LPC55XXX Family, this is currently being used to set the core clock value at it's highest frequency which clocks at 150MHz. diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 6730c6cfcff..a26aae34d9b 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h b/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h new file mode 100644 index 00000000000..ab2bcd971f0 --- /dev/null +++ b/soc/arm/nxp_s32/common/cmsis_rtos_v2_adapt.h @@ -0,0 +1,19 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ +#define ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ + +/* + * The HAL is defining these symbols already. To avoid interference + * between HAL and the CMSIS RTOS wrapper, redefine them under an enum. + */ +#undef TRUE +#undef FALSE + +enum { FALSE, TRUE}; + +#endif /* ZEPHYR_SOC_ARM_NXP_S32_COMMON_CMSIS_RTOS_V2_ADAPT_H_ */ diff --git a/soc/arm/nxp_s32/common/osif.c b/soc/arm/nxp_s32/common/osif.c index 970e127fe13..73b5c6c1d1f 100644 --- a/soc/arm/nxp_s32/common/osif.c +++ b/soc/arm/nxp_s32/common/osif.c @@ -8,6 +8,12 @@ #include #include +#if defined(CONFIG_SOC_SERIES_S32K1XX) +/* Aliases needed to build with different SoC-specific HAL versions */ +#define CPXNUM CPxNUM +#define MSCM_CPXNUM_CPN_MASK MSCM_CPxNUM_CPN_MASK +#endif + /* Required by OsIf timer initialization but not used with Zephyr, so no values configured */ static const OsIf_ConfigType osif_config; const OsIf_ConfigType *const OsIf_apxPredefinedConfig[OSIF_MAX_COREIDX_SUPPORTED] = { diff --git a/soc/arm/nxp_s32/s32k1/CMakeLists.txt b/soc/arm/nxp_s32/s32k1/CMakeLists.txt new file mode 100644 index 00000000000..ff8085fc5c1 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") + +zephyr_sources(soc.c) +zephyr_sources_ifdef(CONFIG_ARM_MPU nxp_mpu_regions.c) + +zephyr_sources_ifdef(CONFIG_NXP_S32_FLASH_CONFIG flash_configuration.c) +zephyr_linker_sources_ifdef(CONFIG_NXP_S32_FLASH_CONFIG ROM_START SORT_KEY 0x1 flash_config.ld) diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 new file mode 100644 index 00000000000..522710112dc --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k146 @@ -0,0 +1,14 @@ +# NXP S32K146 + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_S32K146 + +config SOC + default "s32k146" + +config FPU + default y + +endif # SOC_S32K146 diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series new file mode 100644 index 00000000000..49dfd9f31cf --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# NXP S32K1XX MCU series + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_S32K1XX + +config SOC_SERIES + default "s32k1" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 80000000 + +config NUM_IRQS + default 239 if CPU_CORTEX_M4 + default 47 if CPU_CORTEX_M0PLUS + +if !XIP +config FLASH_SIZE + default 0 +config FLASH_BASE_ADDRESS + default 0 +endif + +# The S32K1xx have 8 MPU regions, which is not enough for both HW stack protection +# and userspace. Only enable HW stack protection if userspace is not enabled. +config HW_STACK_PROTECTION + default y if !USERSPACE + +source "soc/arm/nxp_s32/s32k1/Kconfig.defconfig.s32k1*" + +endif # SOC_SERIES_S32K1XX diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.series b/soc/arm/nxp_s32/s32k1/Kconfig.series new file mode 100644 index 00000000000..31102f347fd --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.series @@ -0,0 +1,24 @@ +# NXP S32K1XX MCU series + +# Copyright 2023-2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_S32K1XX + bool "NXP S32K1XX MCU series" + select ARM + select SOC_FAMILY_NXP_S32 + select HAS_NXP_S32_HAL + select HAS_MCUX + select CPU_HAS_NXP_MPU + select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS + select MPU_ALLOW_FLASH_WRITE if !XIP + select CLOCK_CONTROL + select HAS_MCUX_LPUART + select HAS_MCUX_LPI2C + select HAS_MCUX_LPSPI + select HAS_MCUX_FTM + select HAS_MCUX_FLEXCAN + select HAS_MCUX_WDOG32 + select HAS_MCUX_RTC + help + Enable support for NXP S32K1XX MCU series. diff --git a/soc/arm/nxp_s32/s32k1/Kconfig.soc b/soc/arm/nxp_s32/s32k1/Kconfig.soc new file mode 100644 index 00000000000..78caf49f677 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/Kconfig.soc @@ -0,0 +1,445 @@ +# NXP S32K1XX MCUs line + +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP S32K1XX MCU selection" + depends on SOC_SERIES_S32K1XX + +config SOC_S32K116 + bool "S32K116" + select CPU_CORTEX_M0PLUS + +config SOC_S32K118 + bool "S32K118" + select CPU_CORTEX_M0PLUS + +config SOC_S32K142 + bool "S32K142" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +config SOC_S32K142W + bool "S32K142W" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +config SOC_S32K144 + bool "S32K144" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +config SOC_S32K144W + bool "S32K144W" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +config SOC_S32K146 + bool "S32K146" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +config SOC_S32K148 + bool "S32K148" + select CPU_CORTEX_M4 + select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_FPU + select HAS_MCUX_CACHE + +endchoice + +if SOC_SERIES_S32K1XX + +config SOC_PART_NUMBER_FS32K116LAT0MFMT + bool + +config SOC_PART_NUMBER_FS32K116LAT0MLFR + bool + +config SOC_PART_NUMBER_FS32K116LAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K116LIT0VFMT + bool + +config SOC_PART_NUMBER_FS32K116LIT0VLFT + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLFR + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K118LAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K118LIT0VLFT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K142HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K142HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLFT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLLR + bool + +config SOC_PART_NUMBER_FS32K142UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K142UIT0VLHT + bool + +config SOC_PART_NUMBER_FS32K142WAT0WLFT + bool + +config SOC_PART_NUMBER_FS32K142WAT0WLHT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLFT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K144HAT0MMHR + bool + +config SOC_PART_NUMBER_FS32K144HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K144HVT0VLHR + bool + +config SOC_PART_NUMBER_FS32K144HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144HXT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144HXT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLFT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144UAT0VMHR + bool + +config SOC_PART_NUMBER_FS32K144UAT0VMHT + bool + +config SOC_PART_NUMBER_FS32K144UIT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLHT + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLLR + bool + +config SOC_PART_NUMBER_FS32K144ULT0VLLT + bool + +config SOC_PART_NUMBER_FS32K144WAT0WLFT + bool + +config SOC_PART_NUMBER_FS32K144WAT0WLHT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLHR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLHT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLQR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MLQT + bool + +config SOC_PART_NUMBER_FS32K146HAT0MMHR + bool + +config SOC_PART_NUMBER_FS32K146HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K146HVT0VLHT + bool + +config SOC_PART_NUMBER_FS32K146HXT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLHR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLHT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLLR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLQR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VLQT + bool + +config SOC_PART_NUMBER_FS32K146UAT0VMHR + bool + +config SOC_PART_NUMBER_FS32K146UAT0VMHT + bool + +config SOC_PART_NUMBER_FS32K146UIT0VLLT + bool + +config SOC_PART_NUMBER_FS32K146ULT0VLLT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLLR + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLLT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLQR + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLQT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MLUT + bool + +config SOC_PART_NUMBER_FS32K148HAT0MMHT + bool + +config SOC_PART_NUMBER_FS32K148UGT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UIT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLLT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLQT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VLUT + bool + +config SOC_PART_NUMBER_FS32K148UJT0VMHR + bool + +config SOC_PART_NUMBER_FS32K148UJT0VMHT + bool + +config SOC_PART_NUMBER_S32K1XX + string + default "FS32K116LAT0MFMT" if SOC_PART_NUMBER_FS32K116LAT0MFMT + default "FS32K116LAT0MLFR" if SOC_PART_NUMBER_FS32K116LAT0MLFR + default "FS32K116LAT0MLFT" if SOC_PART_NUMBER_FS32K116LAT0MLFT + default "FS32K116LIT0VFMT" if SOC_PART_NUMBER_FS32K116LIT0VFMT + default "FS32K116LIT0VLFT" if SOC_PART_NUMBER_FS32K116LIT0VLFT + default "FS32K118LAT0MLFR" if SOC_PART_NUMBER_FS32K118LAT0MLFR + default "FS32K118LAT0MLFT" if SOC_PART_NUMBER_FS32K118LAT0MLFT + default "FS32K118LAT0MLHR" if SOC_PART_NUMBER_FS32K118LAT0MLHR + default "FS32K118LAT0MLHT" if SOC_PART_NUMBER_FS32K118LAT0MLHT + default "FS32K118LIT0VLFT" if SOC_PART_NUMBER_FS32K118LIT0VLFT + default "FS32K142HAT0MLFT" if SOC_PART_NUMBER_FS32K142HAT0MLFT + default "FS32K142HAT0MLHT" if SOC_PART_NUMBER_FS32K142HAT0MLHT + default "FS32K142HAT0MLLR" if SOC_PART_NUMBER_FS32K142HAT0MLLR + default "FS32K142HAT0MLLT" if SOC_PART_NUMBER_FS32K142HAT0MLLT + default "FS32K142HVT0VLHT" if SOC_PART_NUMBER_FS32K142HVT0VLHT + default "FS32K142UAT0VLFT" if SOC_PART_NUMBER_FS32K142UAT0VLFT + default "FS32K142UAT0VLHR" if SOC_PART_NUMBER_FS32K142UAT0VLHR + default "FS32K142UAT0VLHT" if SOC_PART_NUMBER_FS32K142UAT0VLHT + default "FS32K142UAT0VLLR" if SOC_PART_NUMBER_FS32K142UAT0VLLR + default "FS32K142UAT0VLLT" if SOC_PART_NUMBER_FS32K142UAT0VLLT + default "FS32K142UIT0VLHT" if SOC_PART_NUMBER_FS32K142UIT0VLHT + default "FS32K142WAT0WLFT" if SOC_PART_NUMBER_FS32K142WAT0WLFT + default "FS32K142WAT0WLHT" if SOC_PART_NUMBER_FS32K142WAT0WLHT + default "FS32K144HAT0MLFT" if SOC_PART_NUMBER_FS32K144HAT0MLFT + default "FS32K144HAT0MLHR" if SOC_PART_NUMBER_FS32K144HAT0MLHR + default "FS32K144HAT0MLHT" if SOC_PART_NUMBER_FS32K144HAT0MLHT + default "FS32K144HAT0MLLR" if SOC_PART_NUMBER_FS32K144HAT0MLLR + default "FS32K144HAT0MLLT" if SOC_PART_NUMBER_FS32K144HAT0MLLT + default "FS32K144HAT0MMHR" if SOC_PART_NUMBER_FS32K144HAT0MMHR + default "FS32K144HAT0MMHT" if SOC_PART_NUMBER_FS32K144HAT0MMHT + default "FS32K144HVT0VLHR" if SOC_PART_NUMBER_FS32K144HVT0VLHR + default "FS32K144HVT0VLHT" if SOC_PART_NUMBER_FS32K144HVT0VLHT + default "FS32K144HXT0VLHT" if SOC_PART_NUMBER_FS32K144HXT0VLHT + default "FS32K144HXT0VLLT" if SOC_PART_NUMBER_FS32K144HXT0VLLT + default "FS32K144UAT0VLFT" if SOC_PART_NUMBER_FS32K144UAT0VLFT + default "FS32K144UAT0VLHR" if SOC_PART_NUMBER_FS32K144UAT0VLHR + default "FS32K144UAT0VLHT" if SOC_PART_NUMBER_FS32K144UAT0VLHT + default "FS32K144UAT0VLLT" if SOC_PART_NUMBER_FS32K144UAT0VLLT + default "FS32K144UAT0VMHR" if SOC_PART_NUMBER_FS32K144UAT0VMHR + default "FS32K144UAT0VMHT" if SOC_PART_NUMBER_FS32K144UAT0VMHT + default "FS32K144UIT0VLHT" if SOC_PART_NUMBER_FS32K144UIT0VLHT + default "FS32K144ULT0VLHT" if SOC_PART_NUMBER_FS32K144ULT0VLHT + default "FS32K144ULT0VLLR" if SOC_PART_NUMBER_FS32K144ULT0VLLR + default "FS32K144ULT0VLLT" if SOC_PART_NUMBER_FS32K144ULT0VLLT + default "FS32K144WAT0WLFT" if SOC_PART_NUMBER_FS32K144WAT0WLFT + default "FS32K144WAT0WLHT" if SOC_PART_NUMBER_FS32K144WAT0WLHT + default "FS32K146HAT0MLHR" if SOC_PART_NUMBER_FS32K146HAT0MLHR + default "FS32K146HAT0MLHT" if SOC_PART_NUMBER_FS32K146HAT0MLHT + default "FS32K146HAT0MLLR" if SOC_PART_NUMBER_FS32K146HAT0MLLR + default "FS32K146HAT0MLLT" if SOC_PART_NUMBER_FS32K146HAT0MLLT + default "FS32K146HAT0MLQR" if SOC_PART_NUMBER_FS32K146HAT0MLQR + default "FS32K146HAT0MLQT" if SOC_PART_NUMBER_FS32K146HAT0MLQT + default "FS32K146HAT0MMHR" if SOC_PART_NUMBER_FS32K146HAT0MMHR + default "FS32K146HAT0MMHT" if SOC_PART_NUMBER_FS32K146HAT0MMHT + default "FS32K146HVT0VLHT" if SOC_PART_NUMBER_FS32K146HVT0VLHT + default "FS32K146HXT0VLLT" if SOC_PART_NUMBER_FS32K146HXT0VLLT + default "FS32K146UAT0VLHR" if SOC_PART_NUMBER_FS32K146UAT0VLHR + default "FS32K146UAT0VLHT" if SOC_PART_NUMBER_FS32K146UAT0VLHT + default "FS32K146UAT0VLLR" if SOC_PART_NUMBER_FS32K146UAT0VLLR + default "FS32K146UAT0VLLT" if SOC_PART_NUMBER_FS32K146UAT0VLLT + default "FS32K146UAT0VLQR" if SOC_PART_NUMBER_FS32K146UAT0VLQR + default "FS32K146UAT0VLQT" if SOC_PART_NUMBER_FS32K146UAT0VLQT + default "FS32K146UAT0VMHR" if SOC_PART_NUMBER_FS32K146UAT0VMHR + default "FS32K146UAT0VMHT" if SOC_PART_NUMBER_FS32K146UAT0VMHT + default "FS32K146UIT0VLLT" if SOC_PART_NUMBER_FS32K146UIT0VLLT + default "FS32K146ULT0VLLT" if SOC_PART_NUMBER_FS32K146ULT0VLLT + default "FS32K148HAT0MLLR" if SOC_PART_NUMBER_FS32K148HAT0MLLR + default "FS32K148HAT0MLLT" if SOC_PART_NUMBER_FS32K148HAT0MLLT + default "FS32K148HAT0MLQR" if SOC_PART_NUMBER_FS32K148HAT0MLQR + default "FS32K148HAT0MLQT" if SOC_PART_NUMBER_FS32K148HAT0MLQT + default "FS32K148HAT0MLUT" if SOC_PART_NUMBER_FS32K148HAT0MLUT + default "FS32K148HAT0MMHT" if SOC_PART_NUMBER_FS32K148HAT0MMHT + default "FS32K148UGT0VLQT" if SOC_PART_NUMBER_FS32K148UGT0VLQT + default "FS32K148UIT0VLQT" if SOC_PART_NUMBER_FS32K148UIT0VLQT + default "FS32K148UJT0VLLT" if SOC_PART_NUMBER_FS32K148UJT0VLLT + default "FS32K148UJT0VLQT" if SOC_PART_NUMBER_FS32K148UJT0VLQT + default "FS32K148UJT0VLUT" if SOC_PART_NUMBER_FS32K148UJT0VLUT + default "FS32K148UJT0VMHR" if SOC_PART_NUMBER_FS32K148UJT0VMHR + default "FS32K148UJT0VMHT" if SOC_PART_NUMBER_FS32K148UJT0VMHT + help + This string holds the full part number of the SoC. It is a hidden option + that you should not set directly. The part number selection choice defines + the default value for this string. + +config WDOG_INIT + bool + default y + +config NXP_S32_FLASH_CONFIG + bool "NXP S32 flash configuration field" + default y if XIP && !BOOTLOADER_MCUBOOT + help + Include the 16-byte flash configuration field that stores default + protection settings (loaded on reset) and security information that + allows the MCU to restrict access to the FTFx module. + +if NXP_S32_FLASH_CONFIG + +config NXP_S32_FLASH_CONFIG_OFFSET + hex "NXP S32 flash configuration field offset" + default 0x400 + +config NXP_S32_FLASH_CONFIG_FSEC + hex "Flash security byte (FSEC)" + range 0 0xff + default 0xfe + help + Configures the reset value of the FSEC register, which includes + backdoor key access, mass erase, factory access, and flash security + options. + +config NXP_S32_FLASH_CONFIG_FOPT + hex "Flash nonvolatile option byte (FOPT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FOPT register, which includes boot, + NMI, and EzPort options. + +config NXP_S32_FLASH_CONFIG_FEPROT + hex "EEPROM protection byte (FEPROT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FEPROT register for FlexNVM + devices. For program flash only devices, this byte is reserved. + +config NXP_S32_FLASH_CONFIG_FDPROT + hex "Data flash protection byte (FDPROT)" + range 0 0xff + default 0xff + help + Configures the reset value of the FDPROT register for FlexNVM + devices. For program flash only devices, this byte is reserved. + +endif # NXP_S32_FLASH_CONFIG + +config NXP_S32_ENABLE_CODE_CACHE + bool "Code cache" + default y + depends on HAS_MCUX_CACHE + +endif # SOC_SERIES_S32K1XX diff --git a/soc/arm/nxp_s32/s32k1/flash_config.ld b/soc/arm/nxp_s32/s32k1/flash_config.ld new file mode 100644 index 00000000000..6ff64221be4 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/flash_config.ld @@ -0,0 +1,9 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +. = CONFIG_NXP_S32_FLASH_CONFIG_OFFSET; +KEEP(*(.kinetis_flash_config)) +KEEP(*(".kinetis_flash_config.*")) diff --git a/soc/arm/nxp_s32/s32k1/flash_configuration.c b/soc/arm/nxp_s32/s32k1/flash_configuration.c new file mode 100644 index 00000000000..af1ec998ebb --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/flash_configuration.c @@ -0,0 +1,32 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +uint8_t __kinetis_flash_config_section __kinetis_flash_config[] = { + /* Backdoor Comparison Key (unused) */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + + /* Program flash protection; 1 bit/region - 0=protected, 1=unprotected */ + 0xFF, 0xFF, 0xFF, 0xFF, + + /* Flash security register (FSEC) enables/disables backdoor key access, + * mass erase, factory access, and flash security + */ + CONFIG_NXP_S32_FLASH_CONFIG_FSEC, + + /* Flash nonvolatile option register (FOPT) enables/disables NMI, + * EzPort, and boot options + */ + CONFIG_NXP_S32_FLASH_CONFIG_FOPT, + + /* EEPROM protection register (FEPROT) for FlexNVM devices */ + CONFIG_NXP_S32_FLASH_CONFIG_FEPROT, + + /* Data flash protection register (FDPROT) for FlexNVM devices */ + CONFIG_NXP_S32_FLASH_CONFIG_FDPROT, +}; diff --git a/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c b/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c new file mode 100644 index 00000000000..5c8ac8de3b9 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/nxp_mpu_regions.c @@ -0,0 +1,60 @@ +/* + * Copyright 2023 NXP + * + * Based on soc/arm/nxp_kinetis/ke1xf/nxp_mpu_regions.c, which is: + * Copyright (c) 2017 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static const struct nxp_mpu_region mpu_regions[] = { + /* Region 0 */ + MPU_REGION_ENTRY("DEBUGGER", + 0, + 0xFFFFFFFF, + REGION_DEBUGGER_AND_DEVICE_ATTR), + + /* Region 1 */ + MPU_REGION_ENTRY("BACKGROUND_0", + 0, + CONFIG_SRAM_BASE_ADDRESS-1, + REGION_BACKGROUND_ATTR), + /* Region 2 */ + MPU_REGION_ENTRY("BACKGROUND_1", + CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024), + 0xFFFFFFFF, + REGION_BACKGROUND_ATTR), + +#if defined(CONFIG_XIP) + /* Region 3 */ + MPU_REGION_ENTRY("SRAM", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_RAM_ATTR), + + /* Region 4 */ + MPU_REGION_ENTRY("FLASH", + CONFIG_FLASH_BASE_ADDRESS, + (CONFIG_FLASH_BASE_ADDRESS + + (CONFIG_FLASH_SIZE * 1024) - 1), + REGION_FLASH_ATTR), +#else + /* Region 3 */ + MPU_REGION_ENTRY("SRAM", + CONFIG_SRAM_BASE_ADDRESS, + (CONFIG_SRAM_BASE_ADDRESS + + (CONFIG_SRAM_SIZE * 1024) - 1), + REGION_FLASH_ATTR), +#endif +}; + +const struct nxp_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, + .sram_region = 3, +}; diff --git a/soc/arm/nxp_s32/s32k1/pinctrl_soc.h b/soc/arm/nxp_s32/s32k1/pinctrl_soc.h new file mode 100644 index 00000000000..fde3c12954f --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/pinctrl_soc.h @@ -0,0 +1,48 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * @file + * NXP S32K1 SOC specific helpers for pinctrl driver + */ + +#ifndef ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +typedef uint32_t pinctrl_soc_pin_t; + +#define Z_PINCTRL_KINETIS_PINCFG(node_id) \ + (PORT_PCR_DSE(DT_ENUM_IDX(node_id, drive_strength)) | \ + PORT_PCR_PS(DT_PROP(node_id, bias_pull_up)) | \ + PORT_PCR_PE(DT_PROP(node_id, bias_pull_up)) | \ + PORT_PCR_PE(DT_PROP(node_id, bias_pull_down)) | \ + PORT_PCR_PFE(DT_PROP(node_id, nxp_passive_filter))) + +#define Z_PINCTRL_KINETIS_PCR_MASK \ + (PORT_PCR_MUX_MASK | PORT_PCR_DSE_MASK | PORT_PCR_PFE_MASK | \ + PORT_PCR_PE_MASK | PORT_PCR_PS_MASK) + +#define Z_PINCTRL_STATE_PIN_INIT(group, pin_prop, idx) \ + DT_PROP_BY_IDX(group, pin_prop, idx) | Z_PINCTRL_KINETIS_PINCFG(group), + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, Z_PINCTRL_STATE_PIN_INIT)}; + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_SOC_ARM_NXP_S32_S32K1_PINCTRL_SOC_H_ */ diff --git a/soc/arm/nxp_s32/s32k1/soc.c b/soc/arm/nxp_s32/s32k1/soc.c new file mode 100644 index 00000000000..bed85dbc91d --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/soc.c @@ -0,0 +1,78 @@ +/* + * Copyright 2023 NXP + * + * Based on zephyr/soc/arm/nxp_kinetis/ke1xf/soc.c, which is: + * Copyright (c) 2019-2021 Vestas Wind Systems A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_HAS_MCUX_CACHE) +#include +#endif + +#if defined(CONFIG_WDOG_INIT) +void z_arm_watchdog_init(void) +{ + /* + * NOTE: DO NOT SINGLE STEP THROUGH THIS SECTION!!! Watchdog + * reconfiguration must take place within 128 bus clocks from + * unlocking. Single stepping through the code will cause the + * watchdog to close the unlock window again. + */ + if ((IP_WDOG->CS & WDOG_CS_CMD32EN_MASK) != 0U) { + IP_WDOG->CNT = WDOG_UPDATE_KEY; + } else { + IP_WDOG->CNT = WDOG_UPDATE_KEY & 0xFFFFU; + IP_WDOG->CNT = (WDOG_UPDATE_KEY >> 16U) & 0xFFFFU; + } + while (!(IP_WDOG->CS & WDOG_CS_ULK_MASK)) { + ; + } + + IP_WDOG->TOVAL = 0xFFFFU; + IP_WDOG->CS = (uint32_t) ((IP_WDOG->CS) & ~WDOG_CS_EN_MASK) | WDOG_CS_UPDATE_MASK; + + /* Wait for new configuration to take effect */ + while (!(IP_WDOG->CS & WDOG_CS_RCS_MASK)) { + ; + } +} +#endif /* CONFIG_WDOG_INIT */ + +static int soc_init(void) +{ +#if !defined(CONFIG_ARM_MPU) + uint32_t tmp; + + /* + * Disable memory protection and clear slave port errors. + * Note that the S32K1xx does not implement the optional Arm MPU but + * instead the Soc includes its own NXP MPU module. + */ + tmp = IP_MPU->CESR; + tmp &= ~MPU_CESR_VLD_MASK; + tmp |= MPU_CESR_SPERR0_MASK | MPU_CESR_SPERR1_MASK + | MPU_CESR_SPERR2_MASK | MPU_CESR_SPERR3_MASK; + IP_MPU->CESR = tmp; +#endif /* !CONFIG_ARM_MPU */ + +#if defined(CONFIG_HAS_MCUX_CACHE) && defined(CONFIG_NXP_S32_ENABLE_CODE_CACHE) + L1CACHE_EnableCodeCache(); + barrier_isync_fence_full(); +#endif + + OsIf_Init(NULL); + + return 0; +} + +SYS_INIT(soc_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/nxp_s32/s32k1/soc.h b/soc/arm/nxp_s32/s32k1/soc.h new file mode 100644 index 00000000000..b58a49ab256 --- /dev/null +++ b/soc/arm/nxp_s32/s32k1/soc.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NXP_S32_S32K1_SOC_H_ +#define _NXP_S32_S32K1_SOC_H_ + +#include + +#if defined(CONFIG_SOC_S32K116) +#include +#elif defined(CONFIG_SOC_S32K118) +#include +#elif defined(CONFIG_SOC_S32K142) +#include +#elif defined(CONFIG_SOC_S32K142W) +#include +#elif defined(CONFIG_SOC_S32K144) +#include +#elif defined(CONFIG_SOC_S32K144W) +#include +#elif defined(CONFIG_SOC_S32K146) +#include +#elif defined(CONFIG_SOC_S32K148) +#include +#else +#error "SoC not supported" +#endif + +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + +/* GPIO setting for the Port Mux Register */ +#define PORT_MUX_GPIO kPORT_MuxAsGpio + +#endif /* _NXP_S32_S32K1_SOC_H_ */ diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series index 04d54fdc666..2307571611a 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.defconfig.series @@ -1,6 +1,6 @@ # NXP S32K3XX MCU series -# Copyright 2023 NXP +# Copyright 2023-2024 NXP # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_S32K3XX @@ -32,6 +32,9 @@ config NET_UDP_CHECKSUM endif # NET_L2_ETHERNET +config CACHE_MANAGEMENT + default y + source "soc/arm/nxp_s32/s32k3/Kconfig.defconfig.s32k*" endif # SOC_SERIES_S32K3XX diff --git a/soc/arm/nxp_s32/s32k3/Kconfig.series b/soc/arm/nxp_s32/s32k3/Kconfig.series index 50be01fe690..ac90439b644 100644 --- a/soc/arm/nxp_s32/s32k3/Kconfig.series +++ b/soc/arm/nxp_s32/s32k3/Kconfig.series @@ -11,6 +11,8 @@ config SOC_SERIES_S32K3XX select HAS_NXP_S32_HAL select CPU_HAS_FPU select CPU_HAS_ARM_MPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS select PLATFORM_SPECIFIC_INIT if XIP select USE_DT_CODE_PARTITION if XIP diff --git a/soc/arm/nxp_s32/s32k3/soc.c b/soc/arm/nxp_s32/s32k3/soc.c index 5db4204a89c..be822677189 100644 --- a/soc/arm/nxp_s32/s32k3/soc.c +++ b/soc/arm/nxp_s32/s32k3/soc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -50,13 +51,8 @@ const struct ivt ivt_header __attribute__((section(".ivt_header"))) = { static int soc_init(void) { - SCB_EnableICache(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } - } + sys_cache_instr_enable(); + sys_cache_data_enable(); OsIf_Init(NULL); diff --git a/soc/arm/nxp_s32/s32k3/soc.h b/soc/arm/nxp_s32/s32k3/soc.h index bbc53e18023..86af70cc9c6 100644 --- a/soc/arm/nxp_s32/s32k3/soc.h +++ b/soc/arm/nxp_s32/s32k3/soc.h @@ -8,14 +8,10 @@ #define _NXP_S32_S32K_SOC_H_ #include +#include #if defined(CONFIG_CMSIS_RTOS_V2) -/* - * The HAL is defining these symbols already. To avoid redefinitions, - * let CMSIS RTOS wrapper define them. - */ -#undef TRUE -#undef FALSE +#include #endif /* Aliases for peripheral base addresses */ diff --git a/soc/arm/nxp_s32/s32ze/soc.h b/soc/arm/nxp_s32/s32ze/soc.h index f7c96aa2ed9..e042ebe8af9 100644 --- a/soc/arm/nxp_s32/s32ze/soc.h +++ b/soc/arm/nxp_s32/s32ze/soc.h @@ -16,6 +16,10 @@ #error "SoC not supported" #endif +#if defined(CONFIG_CMSIS_RTOS_V2) +#include +#endif + /* Aliases for peripheral base addresses */ /* SIUL2 */ diff --git a/soc/arm/quicklogic_eos_s3/Kconfig.soc b/soc/arm/quicklogic_eos_s3/Kconfig.soc index cb5fd170870..e555933430b 100644 --- a/soc/arm/quicklogic_eos_s3/Kconfig.soc +++ b/soc/arm/quicklogic_eos_s3/Kconfig.soc @@ -7,4 +7,5 @@ config SOC_EOS_S3 select CPU_CORTEX_M4 select CPU_CORTEX_M_HAS_SYSTICK select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select EOS_S3_HAL diff --git a/soc/arm/renesas_ra/common/pinctrl_ra.h b/soc/arm/renesas_ra/common/pinctrl_ra.h index d61f1e418d5..ed80b3fda18 100644 --- a/soc/arm/renesas_ra/common/pinctrl_ra.h +++ b/soc/arm/renesas_ra/common/pinctrl_ra.h @@ -56,7 +56,8 @@ struct pinctrl_ra_pin { uint8_t pin: 4; uint8_t port: 3; uint32_t UNUSED24: 5; - uint8_t port4: 3; + uint8_t port4: 1; + uint32_t UNUSED30: 2; }; }; }; @@ -90,4 +91,4 @@ extern int pinctrl_ra_query_config(uint32_t port, uint32_t pin, Z_PINCTRL_STATE_PIN_INIT) \ } -#endif /* ZEPHYR_SOC_ARM_RENESAS_RA_RA6E1_PINCTRL_SOC_H_ */ +#endif /* ZEPHYR_SOC_ARM_RENESAS_RA_COMMON_RA_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_ra/common/ra_common_soc.h b/soc/arm/renesas_ra/common/ra_common_soc.h index 60559793743..f76c4c26fc0 100644 --- a/soc/arm/renesas_ra/common/ra_common_soc.h +++ b/soc/arm/renesas_ra/common/ra_common_soc.h @@ -11,6 +11,8 @@ extern "C" { #endif +#include + #ifdef __cplusplus } #endif diff --git a/soc/arm/renesas_rcar/CMakeLists.txt b/soc/arm/renesas_rcar/CMakeLists.txt index 226f3bd626f..20bed32f36a 100644 --- a/soc/arm/renesas_rcar/CMakeLists.txt +++ b/soc/arm/renesas_rcar/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory(${SOC_SERIES}) +zephyr_include_directories(common) diff --git a/soc/arm/renesas_rcar/common/pinctrl_rcar.h b/soc/arm/renesas_rcar/common/pinctrl_rcar.h new file mode 100644 index 00000000000..c3563e014ba --- /dev/null +++ b/soc/arm/renesas_rcar/common/pinctrl_rcar.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ + +#include +#include +#include +#include + +struct rcar_pin_func { + uint8_t bank:5; /* bank number 0 - 18 */ + uint8_t shift:5; /* bit shift 0 - 28 */ + uint8_t func:4; /* choice from 0x0 to 0xF */ +}; + +/** Pull-up, pull-down, or bias disable is requested */ +#define RCAR_PIN_FLAGS_PULL_SET BIT(0) +/** Performs on/off control of the pull resistors */ +#define RCAR_PIN_FLAGS_PUEN BIT(1) +/** Select pull-up resistor if set pull-down otherwise */ +#define RCAR_PIN_FLAGS_PUD BIT(2) +/** Alternate function for the pin is requested */ +#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) + +#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) +#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) +#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET + +/** Type for R-Car pin. */ +typedef struct pinctrl_soc_pin { + uint16_t pin; + struct rcar_pin_func func; + uint8_t flags; + uint8_t drive_strength; + uint8_t voltage; +} pinctrl_soc_pin_t; + +#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) +#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) + +/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ +#define RCAR_PIN_FUNC(node_id) \ + { \ + ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ + ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ + ((RCAR_IPSR(node_id) & 0xFU)) \ + } + +#define RCAR_PIN_FLAGS(node_id) \ + DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ + DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ + DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ + RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET + +#define RCAR_DT_PIN(node_id) \ + { \ + .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ + .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ + (RCAR_PIN_FUNC(node_id)), {0}), \ + .flags = RCAR_PIN_FLAGS(node_id), \ + .drive_strength = \ + COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ + (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ + }, + +/** + * @brief Utility macro to initialize each pin. + * + * @param node_id Node identifier. + * @param state_prop State property name. + * @param idx State property entry index. + */ +#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ + RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) + +/** + * @brief Utility macro to initialize state pins contained in a given property. + * + * @param node_id Node identifier. + * @param prop Property name describing state pins. + */ +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } + +struct pfc_drive_reg_field { + uint16_t pin; + uint8_t offset; + uint8_t size; +}; + +struct pfc_drive_reg { + uint32_t reg; + const struct pfc_drive_reg_field fields[8]; +}; + +struct pfc_bias_reg { + uint32_t puen; /** Pull-enable or pull-up control register */ + uint32_t pud; /** Pull-up/down or pull-down control register */ + const uint16_t pins[32]; +}; + +/** + * @brief Utility macro to check if a pin is GPIO capable + * + * @param pin + * @return true if pin is GPIO capable false otherwise + */ +#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_COMMON_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6f..c5fb3ab967b 100644 --- a/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm/renesas_rcar/gen3/pfc_r8a77951.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -528,6 +528,7 @@ const struct pfc_bias_reg pfc_bias_regs[] = { } }, { /* sentinel */ }, }; + const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) { return pfc_bias_regs; @@ -536,3 +537,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a4..b4f5da3bff0 100644 --- a/soc/arm/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm/renesas_rcar/gen3/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 IoT.bzh + * Copyright (c) 2021-2023 IoT.bzh * * SPDX-License-Identifier: Apache-2.0 * @@ -7,111 +7,6 @@ #ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ #define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ - -#include -#include -#include -#include - -struct rcar_pin_func { - uint8_t bank:5; /* bank number 0 - 18 */ - uint8_t shift:5; /* bit shift 0 - 28 */ - uint8_t func:4; /* choice from 0x0 to 0xF */ -}; -/** Pull-up, pull-down, or bias disable is requested */ -#define RCAR_PIN_FLAGS_PULL_SET BIT(0) -/** Performs on/off control of the pull resistors */ -#define RCAR_PIN_FLAGS_PUEN BIT(1) -/** Select pull-up resistor if set pull-down otherwise */ -#define RCAR_PIN_FLAGS_PUD BIT(2) -/** Alternate function for the pin is requested */ -#define RCAR_PIN_FLAGS_FUNC_SET BIT(3) - -#define RCAR_PIN_PULL_UP (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN | RCAR_PIN_FLAGS_PUD) -#define RCAR_PIN_PULL_DOWN (RCAR_PIN_FLAGS_PULL_SET | RCAR_PIN_FLAGS_PUEN) -#define RCAR_PIN_PULL_DISABLE RCAR_PIN_FLAGS_PULL_SET - -/** Type for R-Car pin. */ -typedef struct pinctrl_soc_pin { - uint16_t pin; - struct rcar_pin_func func; - uint8_t flags; - uint8_t drive_strength; -} pinctrl_soc_pin_t; - -#define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) -#define RCAR_HAS_IPSR(node_id) DT_PROP_HAS_IDX(node_id, pin, 1) - -/* Offsets are defined in dt-bindings pinctrl-rcar-common.h */ -#define RCAR_PIN_FUNC(node_id) \ - { \ - ((RCAR_IPSR(node_id) >> 10U) & 0x1FU), \ - ((RCAR_IPSR(node_id) >> 4U) & 0x1FU), \ - ((RCAR_IPSR(node_id) & 0xFU)) \ - } - -#define RCAR_PIN_FLAGS(node_id) \ - DT_PROP(node_id, bias_pull_up) * RCAR_PIN_PULL_UP | \ - DT_PROP(node_id, bias_pull_down) * RCAR_PIN_PULL_DOWN | \ - DT_PROP(node_id, bias_disable) * RCAR_PIN_PULL_DISABLE | \ - RCAR_HAS_IPSR(node_id) * RCAR_PIN_FLAGS_FUNC_SET - -#define RCAR_DT_PIN(node_id) \ - { \ - .pin = DT_PROP_BY_IDX(node_id, pin, 0), \ - .func = COND_CODE_1(RCAR_HAS_IPSR(node_id), \ - (RCAR_PIN_FUNC(node_id)), (0)), \ - .flags = RCAR_PIN_FLAGS(node_id), \ - .drive_strength = \ - COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ - (DT_PROP(node_id, drive_strength)), (0)), \ - }, - -/** - * @brief Utility macro to initialize each pin. - * - * @param node_id Node identifier. - * @param state_prop State property name. - * @param idx State property entry index. - */ -#define Z_PINCTRL_STATE_PIN_INIT(node_id, state_prop, idx) \ - RCAR_DT_PIN(DT_PROP_BY_IDX(node_id, state_prop, idx)) - -/** - * @brief Utility macro to initialize state pins contained in a given property. - * - * @param node_id Node identifier. - * @param prop Property name describing state pins. - */ -#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ - { DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT) } - -struct pfc_drive_reg_field { - uint16_t pin; - uint8_t offset; - uint8_t size; -}; - -struct pfc_drive_reg { - uint32_t reg; - const struct pfc_drive_reg_field fields[8]; -}; - -struct pfc_bias_reg { - uint32_t puen; /** Pull-enable or pull-up control register */ - uint32_t pud; /** Pull-up/down or pull-down control register */ - const uint16_t pins[32]; -}; - -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - -/** - * @brief Utility macro to check if a pin is GPIO capable - * - * @param pin - * @return true if pin is GPIO capable false otherwise - */ -#define RCAR_IS_GP_PIN(pin) (pin < PIN_NOGPSR_START) +#include #endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN3_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/CMakeLists.txt b/soc/arm/renesas_rcar/gen4/CMakeLists.txt new file mode 100644 index 00000000000..906bfdecfba --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SOC_R8A779F0 pfc_r8a779f0.c) diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 new file mode 100644 index 00000000000..6da34845bf9 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779f0 @@ -0,0 +1,15 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_R8A779F0 + +config SOC + default "r8a779f0" + +config NUM_IRQS + default 1216 #960 SPI + 256 LPI + +config PINCTRL + default y + +endif # SOC_R8A779F0 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series new file mode 100644 index 00000000000..36218fe504f --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.defconfig.series @@ -0,0 +1,13 @@ +# Renesas R-Car Gen4 SoC line + +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_RCAR_GEN4 + +source "soc/arm/renesas_rcar/gen4/Kconfig.defconfig.r8a779*" + +config SOC_SERIES + default "gen4" + +endif # SOC_SERIES_RCAR_GEN4 diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.series b/soc/arm/renesas_rcar/gen4/Kconfig.series new file mode 100644 index 00000000000..606b2c50e43 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_RCAR_GEN4 + bool "Renesas R-Car Gen4 Cortex R52" + select ARM + select CPU_CORTEX_R52 + select GIC_SINGLE_SECURITY_STATE + select SOC_FAMILY_RCAR + select CLOCK_CONTROL_RCAR_CPG_MSSR if CLOCK_CONTROL + select ARM_ARCH_TIMER + help + Enable support for Renesas R-Car Gen4 SoC series diff --git a/soc/arm/renesas_rcar/gen4/Kconfig.soc b/soc/arm/renesas_rcar/gen4/Kconfig.soc new file mode 100644 index 00000000000..5c443d6101e --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 IoT.bzh +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Renesas RCar SoC Selection" + depends on SOC_SERIES_RCAR_GEN4 + +config SOC_R8A779F0 + bool "r8a779f0" + +endchoice diff --git a/soc/arm/renesas_rcar/gen4/linker.ld b/soc/arm/renesas_rcar/gen4/linker.ld new file mode 100644 index 00000000000..a51ff84991f --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c new file mode 100644 index 00000000000..25eba334d77 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pfc_r8a779f0.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include "pinctrl_soc.h" +#include + +const struct pfc_drive_reg pfc_drive_regs[] = { + /* DRV0CTRL0 */ + { 0x80, { + { RCAR_GP_PIN(0, 7), 28, 3 }, /* TX0 */ + { RCAR_GP_PIN(0, 6), 24, 3 }, /* RX0 */ + { RCAR_GP_PIN(0, 5), 20, 3 }, /* HRTS0_N */ + { RCAR_GP_PIN(0, 4), 16, 3 }, /* HCTS0_N */ + { RCAR_GP_PIN(0, 3), 12, 3 }, /* HTX0 */ + { RCAR_GP_PIN(0, 2), 8, 3 }, /* HRX0 */ + { RCAR_GP_PIN(0, 1), 4, 3 }, /* HSCK0 */ + { RCAR_GP_PIN(0, 0), 0, 3 }, /* SCIF_CLK */ + } }, + /* DRV1CTRL0 */ + { 0x84, { + { RCAR_GP_PIN(0, 15), 28, 3 }, /* MSIOF0_SS1 */ + { RCAR_GP_PIN(0, 14), 24, 3 }, /* MSIOF0_SCK */ + { RCAR_GP_PIN(0, 13), 20, 3 }, /* MSIOF0_TXD */ + { RCAR_GP_PIN(0, 12), 16, 3 }, /* MSIOF0_RXD */ + { RCAR_GP_PIN(0, 11), 12, 3 }, /* MSIOF0_SYNC */ + { RCAR_GP_PIN(0, 10), 8, 3 }, /* CTS0_N */ + { RCAR_GP_PIN(0, 9), 4, 3 }, /* RTS0_N */ + { RCAR_GP_PIN(0, 8), 0, 3 }, /* SCK0 */ + } }, + /* DRV2CTRL0 */ + { 0x88, { + { RCAR_GP_PIN(0, 20), 16, 3 }, /* IRQ3 */ + { RCAR_GP_PIN(0, 19), 12, 3 }, /* IRQ2 */ + { RCAR_GP_PIN(0, 18), 8, 3 }, /* IRQ1 */ + { RCAR_GP_PIN(0, 17), 4, 3 }, /* IRQ0 */ + { RCAR_GP_PIN(0, 16), 0, 3 }, /* MSIOF0_SS2 */ + } }, + /* DRV3CTRL0 is empty */ + /* DRV0CTRL1 */ + { 0x80, { + { RCAR_GP_PIN(1, 7), 28, 3 }, /* GP1_07 */ + { RCAR_GP_PIN(1, 6), 24, 3 }, /* GP1_06 */ + { RCAR_GP_PIN(1, 5), 20, 3 }, /* GP1_05 */ + { RCAR_GP_PIN(1, 4), 16, 3 }, /* GP1_04 */ + { RCAR_GP_PIN(1, 3), 12, 3 }, /* GP1_03 */ + { RCAR_GP_PIN(1, 2), 8, 3 }, /* GP1_02 */ + { RCAR_GP_PIN(1, 1), 4, 3 }, /* GP1_01 */ + { RCAR_GP_PIN(1, 0), 0, 3 }, /* GP1_00 */ + } }, + /* DRV1CTRL1 */ + { 0x84, { + { RCAR_GP_PIN(1, 15), 28, 3 }, /* MMC_SD_D2 */ + { RCAR_GP_PIN(1, 14), 24, 3 }, /* MMC_SD_D1 */ + { RCAR_GP_PIN(1, 13), 20, 3 }, /* MMC_SD_D0 */ + { RCAR_GP_PIN(1, 12), 16, 3 }, /* MMC_SD_CLK */ + { RCAR_GP_PIN(1, 11), 12, 3 }, /* GP1_11 */ + { RCAR_GP_PIN(1, 10), 8, 3 }, /* GP1_10 */ + { RCAR_GP_PIN(1, 9), 4, 3 }, /* GP1_09 */ + { RCAR_GP_PIN(1, 8), 0, 3 }, /* GP1_08 */ + } }, + /* DRV2CTRL1 */ + { 0x88, { + { RCAR_GP_PIN(1, 23), 28, 3 }, /* SD_CD */ + { RCAR_GP_PIN(1, 22), 24, 3 }, /* MMC_SD_CMD */ + { RCAR_GP_PIN(1, 21), 20, 3 }, /* MMC_D7 */ + { RCAR_GP_PIN(1, 20), 16, 3 }, /* MMC_DS */ + { RCAR_GP_PIN(1, 19), 12, 3 }, /* MMC_D6 */ + { RCAR_GP_PIN(1, 18), 8, 3 }, /* MMC_D4 */ + { RCAR_GP_PIN(1, 17), 4, 3 }, /* MMC_D5 */ + { RCAR_GP_PIN(1, 16), 0, 3 }, /* MMC_SD_D3 */ + } }, + /* DRV3CTRL1 */ + { 0x8c, { + { RCAR_GP_PIN(1, 24), 0, 3 }, /* SD_WP */ + } }, + /* DRV0CTRL2 */ + { 0x80, { + { RCAR_GP_PIN(2, 7), 28, 2 }, /* QSPI1_MOSI_IO0 */ + { RCAR_GP_PIN(2, 6), 24, 2 }, /* QSPI1_IO2 */ + { RCAR_GP_PIN(2, 5), 20, 2 }, /* QSPI1_MISO_IO1 */ + { RCAR_GP_PIN(2, 4), 16, 2 }, /* QSPI1_IO3 */ + { RCAR_GP_PIN(2, 3), 12, 2 }, /* QSPI1_SSL */ + { RCAR_GP_PIN(2, 2), 8, 2 }, /* RPC_RESET_N */ + { RCAR_GP_PIN(2, 1), 4, 2 }, /* RPC_WP_N */ + { RCAR_GP_PIN(2, 0), 0, 2 }, /* RPC_INT_N */ + } }, + /* DRV1CTRL2 */ + { 0x84, { + { RCAR_GP_PIN(2, 15), 28, 3 }, /* PCIE0_CLKREQ_N */ + { RCAR_GP_PIN(2, 14), 24, 2 }, /* QSPI0_IO3 */ + { RCAR_GP_PIN(2, 13), 20, 2 }, /* QSPI0_SSL */ + { RCAR_GP_PIN(2, 12), 16, 2 }, /* QSPI0_MISO_IO1 */ + { RCAR_GP_PIN(2, 11), 12, 2 }, /* QSPI0_IO2 */ + { RCAR_GP_PIN(2, 10), 8, 2 }, /* QSPI0_SPCLK */ + { RCAR_GP_PIN(2, 9), 4, 2 }, /* QSPI0_MOSI_IO0 */ + { RCAR_GP_PIN(2, 8), 0, 2 }, /* QSPI1_SPCLK */ + } }, + /* DRV2CTRL2 */ + { 0x88, { + { RCAR_GP_PIN(2, 16), 0, 3 }, /* PCIE1_CLKREQ_N */ + } }, + /* DRV3CTRL2 is empty */ + /* DRV0CTRL3 */ + { 0x80, { + { RCAR_GP_PIN(3, 7), 28, 3 }, /* TSN2_LINK_B */ + { RCAR_GP_PIN(3, 6), 24, 3 }, /* TSN1_LINK_B */ + { RCAR_GP_PIN(3, 5), 20, 3 }, /* TSN1_MDC_B */ + { RCAR_GP_PIN(3, 4), 16, 3 }, /* TSN0_MDC_B */ + { RCAR_GP_PIN(3, 3), 12, 3 }, /* TSN2_MDC_B */ + { RCAR_GP_PIN(3, 2), 8, 3 }, /* TSN0_MDIO_B */ + { RCAR_GP_PIN(3, 1), 4, 3 }, /* TSN2_MDIO_B */ + { RCAR_GP_PIN(3, 0), 0, 3 }, /* TSN1_MDIO_B */ + } }, + /* DRV1CTRL3 */ + { 0x84, { + { RCAR_GP_PIN(3, 15), 28, 3 }, /* TSN1_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 14), 24, 3 }, /* TSN1_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 13), 20, 3 }, /* TSN1_AVTP_PPS */ + { RCAR_GP_PIN(3, 12), 16, 3 }, /* TSN0_MAGIC_B */ + { RCAR_GP_PIN(3, 11), 12, 3 }, /* TSN1_PHY_INT_B */ + { RCAR_GP_PIN(3, 10), 8, 3 }, /* TSN0_PHY_INT_B */ + { RCAR_GP_PIN(3, 9), 4, 3 }, /* TSN2_PHY_INT_B */ + { RCAR_GP_PIN(3, 8), 0, 3 }, /* TSN0_LINK_B */ + } }, + /* DRV2CTRL3 */ + { 0x88, { + { RCAR_GP_PIN(3, 18), 8, 3 }, /* TSN0_AVTP_CAPTURE_B */ + { RCAR_GP_PIN(3, 17), 4, 3 }, /* TSN0_AVTP_MATCH_B */ + { RCAR_GP_PIN(3, 16), 0, 3 }, /* TSN0_AVTP_PPS */ + } }, + /* DRV3CTRL3 is empty */ + /* DRV0CTRL4 */ + { 0x80, { + { RCAR_GP_PIN(4, 7), 28, 3 }, /* GP4_07 */ + { RCAR_GP_PIN(4, 6), 24, 3 }, /* GP4_06 */ + { RCAR_GP_PIN(4, 5), 20, 3 }, /* GP4_05 */ + { RCAR_GP_PIN(4, 4), 16, 3 }, /* GP4_04 */ + { RCAR_GP_PIN(4, 3), 12, 3 }, /* GP4_03 */ + { RCAR_GP_PIN(4, 2), 8, 3 }, /* GP4_02 */ + { RCAR_GP_PIN(4, 1), 4, 3 }, /* GP4_01 */ + { RCAR_GP_PIN(4, 0), 0, 3 }, /* GP4_00 */ + } }, + /* DRV1CTRL4 */ + { 0x84, { + { RCAR_GP_PIN(4, 15), 28, 3 }, /* GP4_15 */ + { RCAR_GP_PIN(4, 14), 24, 3 }, /* GP4_14 */ + { RCAR_GP_PIN(4, 13), 20, 3 }, /* GP4_13 */ + { RCAR_GP_PIN(4, 12), 16, 3 }, /* GP4_12 */ + { RCAR_GP_PIN(4, 11), 12, 3 }, /* GP4_11 */ + { RCAR_GP_PIN(4, 10), 8, 3 }, /* GP4_10 */ + { RCAR_GP_PIN(4, 9), 4, 3 }, /* GP4_09 */ + { RCAR_GP_PIN(4, 8), 0, 3 }, /* GP4_08 */ + } }, + /* DRV2CTRL4 */ + { 0x88, { + { RCAR_GP_PIN(4, 23), 28, 3 }, /* MSPI0CSS1 */ + { RCAR_GP_PIN(4, 22), 24, 3 }, /* MPSI0SO/MSPI0DCS */ + { RCAR_GP_PIN(4, 21), 20, 3 }, /* MPSI0SI */ + { RCAR_GP_PIN(4, 20), 16, 3 }, /* MSPI0SC */ + { RCAR_GP_PIN(4, 19), 12, 3 }, /* GP4_19 */ + { RCAR_GP_PIN(4, 18), 8, 3 }, /* GP4_18 */ + { RCAR_GP_PIN(4, 17), 4, 3 }, /* GP4_17 */ + { RCAR_GP_PIN(4, 16), 0, 3 }, /* GP4_16 */ + } }, + /* DRV3CTRL4 */ + { 0x8c, { + { RCAR_GP_PIN(4, 30), 24, 3 }, /* MSPI1CSS1 */ + { RCAR_GP_PIN(4, 29), 20, 3 }, /* MSPI1CSS2 */ + { RCAR_GP_PIN(4, 28), 16, 3 }, /* MSPI1SC */ + { RCAR_GP_PIN(4, 27), 12, 3 }, /* MSPI1CSS0 */ + { RCAR_GP_PIN(4, 26), 8, 3 }, /* MPSI1SO/MSPI1DCS */ + { RCAR_GP_PIN(4, 25), 4, 3 }, /* MSPI1SI */ + { RCAR_GP_PIN(4, 24), 0, 3 }, /* MSPI0CSS0 */ + } }, + /* DRV0CTRL5 */ + { 0x80, { + { RCAR_GP_PIN(5, 7), 28, 3 }, /* ETNB0RXD3 */ + { RCAR_GP_PIN(5, 6), 24, 3 }, /* ETNB0RXER */ + { RCAR_GP_PIN(5, 5), 20, 3 }, /* ETNB0MDC */ + { RCAR_GP_PIN(5, 4), 16, 3 }, /* ETNB0LINKSTA */ + { RCAR_GP_PIN(5, 3), 12, 3 }, /* ETNB0WOL */ + { RCAR_GP_PIN(5, 2), 8, 3 }, /* ETNB0MD */ + { RCAR_GP_PIN(5, 1), 4, 3 }, /* RIIC0SDA */ + { RCAR_GP_PIN(5, 0), 0, 3 }, /* RIIC0SCL */ + } }, + /* DRV1CTRL5 */ + { 0x84, { + { RCAR_GP_PIN(5, 15), 28, 3 }, /* ETNB0TXCLK */ + { RCAR_GP_PIN(5, 14), 24, 3 }, /* ETNB0TXD3 */ + { RCAR_GP_PIN(5, 13), 20, 3 }, /* ETNB0TXER */ + { RCAR_GP_PIN(5, 12), 16, 3 }, /* ETNB0RXCLK */ + { RCAR_GP_PIN(5, 11), 12, 3 }, /* ETNB0RXD0 */ + { RCAR_GP_PIN(5, 10), 8, 3 }, /* ETNB0RXDV */ + { RCAR_GP_PIN(5, 9), 4, 3 }, /* ETNB0RXD2 */ + { RCAR_GP_PIN(5, 8), 0, 3 }, /* ETNB0RXD1 */ + } }, + /* DRV2CTRL5 */ + { 0x88, { + { RCAR_GP_PIN(5, 19), 12, 3 }, /* ETNB0TXD0 */ + { RCAR_GP_PIN(5, 18), 8, 3 }, /* ETNB0TXEN */ + { RCAR_GP_PIN(5, 17), 4, 3 }, /* ETNB0TXD2 */ + { RCAR_GP_PIN(5, 16), 0, 3 }, /* ETNB0TXD1 */ + } }, + /* DRV3CTRL5 is empty */ + /* DRV0CTRL6 */ + { 0x80, { + { RCAR_GP_PIN(6, 7), 28, 3 }, /* RLIN34RX/INTP20 */ + { RCAR_GP_PIN(6, 6), 24, 3 }, /* RLIN34TX */ + { RCAR_GP_PIN(6, 5), 20, 3 }, /* RLIN35RX/INTP21 */ + { RCAR_GP_PIN(6, 4), 16, 3 }, /* RLIN35TX */ + { RCAR_GP_PIN(6, 3), 12, 3 }, /* RLIN36RX/INTP22 */ + { RCAR_GP_PIN(6, 2), 8, 3 }, /* RLIN36TX */ + { RCAR_GP_PIN(6, 1), 4, 3 }, /* RLIN37RX/INTP23 */ + { RCAR_GP_PIN(6, 0), 0, 3 }, /* RLIN37TX */ + } }, + /* DRV1CTRL6 */ + { 0x84, { + { RCAR_GP_PIN(6, 15), 28, 3 }, /* RLIN30RX/INTP16 */ + { RCAR_GP_PIN(6, 14), 24, 3 }, /* RLIN30TX */ + { RCAR_GP_PIN(6, 13), 20, 3 }, /* RLIN31RX/INTP17 */ + { RCAR_GP_PIN(6, 12), 16, 3 }, /* RLIN31TX */ + { RCAR_GP_PIN(6, 11), 12, 3 }, /* RLIN32RX/INTP18 */ + { RCAR_GP_PIN(6, 10), 8, 3 }, /* RLIN32TX */ + { RCAR_GP_PIN(6, 9), 4, 3 }, /* RLIN33RX/INTP19 */ + { RCAR_GP_PIN(6, 8), 0, 3 }, /* RLIN33TX */ + } }, + /* DRV2CTRL6 */ + { 0x88, { + { RCAR_GP_PIN(6, 22), 24, 3 }, /* NMI1 */ + { RCAR_GP_PIN(6, 21), 20, 3 }, /* INTP32 */ + { RCAR_GP_PIN(6, 20), 16, 3 }, /* INTP33 */ + { RCAR_GP_PIN(6, 19), 12, 3 }, /* INTP34 */ + { RCAR_GP_PIN(6, 18), 8, 3 }, /* INTP35 */ + { RCAR_GP_PIN(6, 17), 4, 3 }, /* INTP36 */ + { RCAR_GP_PIN(6, 16), 0, 3 }, /* INTP37 */ + } }, + /* DRV3CTRL6 */ + { 0x8c, { + { RCAR_GP_PIN(6, 31), 28, 3 }, /* PRESETOUT1# */ + } }, + /* DRV0CTRL7 */ + { 0x80, { + { RCAR_GP_PIN(7, 7), 28, 3 }, /* CAN3RX/INTP3 */ + { RCAR_GP_PIN(7, 6), 24, 3 }, /* CAN3TX */ + { RCAR_GP_PIN(7, 5), 20, 3 }, /* CAN2RX/INTP2 */ + { RCAR_GP_PIN(7, 4), 16, 3 }, /* CAN2TX */ + { RCAR_GP_PIN(7, 3), 12, 3 }, /* CAN1RX/INTP1 */ + { RCAR_GP_PIN(7, 2), 8, 3 }, /* CAN1TX */ + { RCAR_GP_PIN(7, 1), 4, 3 }, /* CAN0RX/INTP0 */ + { RCAR_GP_PIN(7, 0), 0, 3 }, /* CAN0TX */ + } }, + /* DRV1CTRL7 */ + { 0x84, { + { RCAR_GP_PIN(7, 15), 28, 3 }, /* CAN7RX/INTP7 */ + { RCAR_GP_PIN(7, 14), 24, 3 }, /* CAN7TX */ + { RCAR_GP_PIN(7, 13), 20, 3 }, /* CAN6RX/INTP6 */ + { RCAR_GP_PIN(7, 12), 16, 3 }, /* CAN6TX */ + { RCAR_GP_PIN(7, 11), 12, 3 }, /* CAN5RX/INTP5 */ + { RCAR_GP_PIN(7, 10), 8, 3 }, /* CAN5TX */ + { RCAR_GP_PIN(7, 9), 4, 3 }, /* CAN4RX/INTP4 */ + { RCAR_GP_PIN(7, 8), 0, 3 }, /* CAN4TX */ + } }, + /* DRV2CTRL7 */ + { 0x88, { + { RCAR_GP_PIN(7, 23), 28, 3 }, /* CAN11RX/INTP11 */ + { RCAR_GP_PIN(7, 22), 24, 3 }, /* CAN11TX */ + { RCAR_GP_PIN(7, 21), 20, 3 }, /* CAN10RX/INTP10 */ + { RCAR_GP_PIN(7, 20), 16, 3 }, /* CAN10TX */ + { RCAR_GP_PIN(7, 19), 12, 3 }, /* CAN9RX/INTP9 */ + { RCAR_GP_PIN(7, 18), 8, 3 }, /* CAN9TX */ + { RCAR_GP_PIN(7, 17), 4, 3 }, /* CAN8RX/INTP8 */ + { RCAR_GP_PIN(7, 16), 0, 3 }, /* CAN8TX */ + } }, + /* DRV3CTRL7 */ + { 0x8c, { + { RCAR_GP_PIN(7, 31), 28, 3 }, /* CAN15RX/INTP15 */ + { RCAR_GP_PIN(7, 30), 24, 3 }, /* CAN15TX */ + { RCAR_GP_PIN(7, 29), 20, 3 }, /* CAN14RX/INTP14 */ + { RCAR_GP_PIN(7, 28), 16, 3 }, /* CAN14TX */ + { RCAR_GP_PIN(7, 27), 12, 3 }, /* CAN13RX/INTP13 */ + { RCAR_GP_PIN(7, 26), 8, 3 }, /* CAN13TX */ + { RCAR_GP_PIN(7, 25), 4, 3 }, /* CAN12RX/INTP12 */ + { RCAR_GP_PIN(7, 24), 0, 3 }, /* CAN12TX */ + } }, + /* DRV0CTRLSYS0 */ + { 0x80, { + { RCAR_GP_PIN(8, 0), 0, 3 }, /* PRESETOUT0# */ + } }, + /* DRV1CTRLSYS0 */ + { 0x84, { + { RCAR_GP_PIN(8, 12), 16, 2 }, /* DCUTCK0 */ + { RCAR_GP_PIN(8, 11), 12, 2 }, /* DCUTDO0 */ + { RCAR_GP_PIN(8, 10), 8, 2 }, /* DCUTDI0 */ + { RCAR_GP_PIN(8, 9), 4, 2 }, /* DCUTDY0# */ + { RCAR_GP_PIN(8, 8), 0, 2 }, /* DCUTMS0 */ + } }, + { }, +}; + +#define PFC_BIAS_REG(r1, r2) \ + .puen = r1, \ + .pud = r2, \ + .pins = + +const struct pfc_bias_reg pfc_bias_regs[] = { + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN0, PUD0 */ + [0] = RCAR_GP_PIN(0, 0), /* SCIF_CLK */ + [1] = RCAR_GP_PIN(0, 1), /* HSCK0 */ + [2] = RCAR_GP_PIN(0, 2), /* HRX0 */ + [3] = RCAR_GP_PIN(0, 3), /* HTX0 */ + [4] = RCAR_GP_PIN(0, 4), /* HCTS0_N */ + [5] = RCAR_GP_PIN(0, 5), /* HRTS0_N */ + [6] = RCAR_GP_PIN(0, 6), /* RX0 */ + [7] = RCAR_GP_PIN(0, 7), /* TX0 */ + [8] = RCAR_GP_PIN(0, 8), /* SCK0 */ + [9] = RCAR_GP_PIN(0, 9), /* RTS0_N */ + [10] = RCAR_GP_PIN(0, 10), /* CTS0_N */ + [11] = RCAR_GP_PIN(0, 11), /* MSIOF0_SYNC */ + [12] = RCAR_GP_PIN(0, 12), /* MSIOF0_RXD */ + [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_TXD */ + [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_SCK */ + [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_SS1 */ + [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SS2 */ + [17] = RCAR_GP_PIN(0, 17), /* IRQ0 */ + [18] = RCAR_GP_PIN(0, 18), /* IRQ1 */ + [19] = RCAR_GP_PIN(0, 19), /* IRQ2 */ + [20] = RCAR_GP_PIN(0, 20), /* IRQ3 */ + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN1, PUD1 */ + [0] = RCAR_GP_PIN(1, 0), /* GP1_00 */ + [1] = RCAR_GP_PIN(1, 1), /* GP1_01 */ + [2] = RCAR_GP_PIN(1, 2), /* GP1_02 */ + [3] = RCAR_GP_PIN(1, 3), /* GP1_03 */ + [4] = RCAR_GP_PIN(1, 4), /* GP1_04 */ + [5] = RCAR_GP_PIN(1, 5), /* GP1_05 */ + [6] = RCAR_GP_PIN(1, 6), /* GP1_06 */ + [7] = RCAR_GP_PIN(1, 7), /* GP1_07 */ + [8] = RCAR_GP_PIN(1, 8), /* GP1_08 */ + [9] = RCAR_GP_PIN(1, 9), /* GP1_09 */ + [10] = RCAR_GP_PIN(1, 10), /* GP1_10 */ + [11] = RCAR_GP_PIN(1, 11), /* GP1_11 */ + [12] = RCAR_GP_PIN(1, 12), /* MMC_SD_CLK */ + [13] = RCAR_GP_PIN(1, 13), /* MMC_SD_D0 */ + [14] = RCAR_GP_PIN(1, 14), /* MMC_SD_D1 */ + [15] = RCAR_GP_PIN(1, 15), /* MMC_SD_D2 */ + [16] = RCAR_GP_PIN(1, 16), /* MMC_SD_D3 */ + [17] = RCAR_GP_PIN(1, 17), /* MMC_D5 */ + [18] = RCAR_GP_PIN(1, 18), /* MMC_D4 */ + [19] = RCAR_GP_PIN(1, 19), /* MMC_D6 */ + [20] = RCAR_GP_PIN(1, 20), /* MMC_DS */ + [21] = RCAR_GP_PIN(1, 21), /* MMC_D7 */ + [22] = RCAR_GP_PIN(1, 22), /* MMC_SD_CMD */ + [23] = RCAR_GP_PIN(1, 23), /* SD_CD */ + [24] = RCAR_GP_PIN(1, 24), /* SD_WP */ + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN2, PUD2 */ + [0] = RCAR_GP_PIN(2, 0), /* RPC_INT_N */ + [1] = RCAR_GP_PIN(2, 1), /* RPC_WP_N */ + [2] = RCAR_GP_PIN(2, 2), /* RPC_RESET_N */ + [3] = RCAR_GP_PIN(2, 3), /* QSPI1_SSL */ + [4] = RCAR_GP_PIN(2, 4), /* QSPI1_IO3 */ + [5] = RCAR_GP_PIN(2, 5), /* QSPI1_MISO_IO1 */ + [6] = RCAR_GP_PIN(2, 6), /* QSPI1_IO2 */ + [7] = RCAR_GP_PIN(2, 7), /* QSPI1_MOSI_IO0 */ + [8] = RCAR_GP_PIN(2, 8), /* QSPI1_SPCLK */ + [9] = RCAR_GP_PIN(2, 9), /* QSPI0_MOSI_IO0 */ + [10] = RCAR_GP_PIN(2, 10), /* QSPI0_SPCLK */ + [11] = RCAR_GP_PIN(2, 11), /* QSPI0_IO2 */ + [12] = RCAR_GP_PIN(2, 12), /* QSPI0_MISO_IO1 */ + [13] = RCAR_GP_PIN(2, 13), /* QSPI0_SSL */ + [14] = RCAR_GP_PIN(2, 14), /* QSPI0_IO3 */ + [15] = RCAR_GP_PIN(2, 15), /* PCIE0_CLKREQ_N */ + [16] = RCAR_GP_PIN(2, 16), /* PCIE1_CLKREQ_N */ + [17] = PIN_NONE, + [18] = PIN_NONE, + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN3, PUD3 */ + [0] = RCAR_GP_PIN(3, 0), /* TSN1_MDIO_B */ + [1] = RCAR_GP_PIN(3, 1), /* TSN2_MDIO_B */ + [2] = RCAR_GP_PIN(3, 2), /* TSN0_MDIO_B */ + [3] = RCAR_GP_PIN(3, 3), /* TSN2_MDC_B */ + [4] = RCAR_GP_PIN(3, 4), /* TSN0_MDC_B */ + [5] = RCAR_GP_PIN(3, 5), /* TSN1_MDC_B */ + [6] = RCAR_GP_PIN(3, 6), /* TSN1_LINK_B */ + [7] = RCAR_GP_PIN(3, 7), /* TSN2_LINK_B */ + [8] = RCAR_GP_PIN(3, 8), /* TSN0_LINK_B */ + [9] = RCAR_GP_PIN(3, 9), /* TSN2_PHY_INT_B */ + [10] = RCAR_GP_PIN(3, 10), /* TSN0_PHY_INT_B */ + [11] = RCAR_GP_PIN(3, 11), /* TSN1_PHY_INT_B */ + [12] = RCAR_GP_PIN(3, 12), /* TSN0_MAGIC_B */ + [13] = RCAR_GP_PIN(3, 13), /* TSN1_AVTP_PPS */ + [14] = RCAR_GP_PIN(3, 14), /* TSN1_AVTP_MATCH_B */ + [15] = RCAR_GP_PIN(3, 15), /* TSN1_AVTP_CAPTURE_B */ + [16] = RCAR_GP_PIN(3, 16), /* TSN0_AVTP_PPS */ + [17] = RCAR_GP_PIN(3, 17), /* TSN0_AVTP_MATCH_B */ + [18] = RCAR_GP_PIN(3, 18), /* TSN0_AVTP_CAPTURE_B */ + [19] = PIN_NONE, + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN4, PUD4 */ + [0] = RCAR_GP_PIN(4, 0), /* GP4_00 */ + [1] = RCAR_GP_PIN(4, 1), /* GP4_01 */ + [2] = RCAR_GP_PIN(4, 2), /* GP4_02 */ + [3] = RCAR_GP_PIN(4, 3), /* GP4_03 */ + [4] = RCAR_GP_PIN(4, 4), /* GP4_04 */ + [5] = RCAR_GP_PIN(4, 5), /* GP4_05 */ + [6] = RCAR_GP_PIN(4, 6), /* GP4_06 */ + [7] = RCAR_GP_PIN(4, 7), /* GP4_07 */ + [8] = RCAR_GP_PIN(4, 8), /* GP4_08 */ + [9] = RCAR_GP_PIN(4, 9), /* GP4_09 */ + [10] = RCAR_GP_PIN(4, 10), /* GP4_10 */ + [11] = RCAR_GP_PIN(4, 11), /* GP4_11 */ + [12] = RCAR_GP_PIN(4, 12), /* GP4_12 */ + [13] = RCAR_GP_PIN(4, 13), /* GP4_13 */ + [14] = RCAR_GP_PIN(4, 14), /* GP4_14 */ + [15] = RCAR_GP_PIN(4, 15), /* GP4_15 */ + [16] = RCAR_GP_PIN(4, 16), /* GP4_16 */ + [17] = RCAR_GP_PIN(4, 17), /* GP4_17 */ + [18] = RCAR_GP_PIN(4, 18), /* GP4_18 */ + [19] = RCAR_GP_PIN(4, 19), /* GP4_19 */ + [20] = RCAR_GP_PIN(4, 20), /* MSPI0SC */ + [21] = RCAR_GP_PIN(4, 21), /* MSPI0SI */ + [22] = RCAR_GP_PIN(4, 22), /* MSPI0SO/MSPI0DCS */ + [23] = RCAR_GP_PIN(4, 23), /* MSPI0CSS1 */ + [24] = RCAR_GP_PIN(4, 24), /* MSPI0CSS0 */ + [25] = RCAR_GP_PIN(4, 25), /* MSPI1SI */ + [26] = RCAR_GP_PIN(4, 26), /* MSPI1SO/MSPI1DCS */ + [27] = RCAR_GP_PIN(4, 27), /* MSPI1CSS0 */ + [28] = RCAR_GP_PIN(4, 28), /* MSPI1SC */ + [29] = RCAR_GP_PIN(4, 29), /* MSPI1CSS2 */ + [30] = RCAR_GP_PIN(4, 30), /* MSPI1CSS1 */ + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN5, PUD5 */ + [0] = RCAR_GP_PIN(5, 0), /* RIIC0SCL */ + [1] = RCAR_GP_PIN(5, 1), /* RIIC0SDA */ + [2] = RCAR_GP_PIN(5, 2), /* ETNB0MD */ + [3] = RCAR_GP_PIN(5, 3), /* ETNB0WOL */ + [4] = RCAR_GP_PIN(5, 4), /* ETNB0LINKSTA */ + [5] = RCAR_GP_PIN(5, 5), /* ETNB0MDC */ + [6] = RCAR_GP_PIN(5, 6), /* ETNB0RXER */ + [7] = RCAR_GP_PIN(5, 7), /* ETNB0RXD3 */ + [8] = RCAR_GP_PIN(5, 8), /* ETNB0RXD1 */ + [9] = RCAR_GP_PIN(5, 9), /* ETNB0RXD2 */ + [10] = RCAR_GP_PIN(5, 10), /* ETNB0RXDV */ + [11] = RCAR_GP_PIN(5, 11), /* ETNB0RXD0 */ + [12] = RCAR_GP_PIN(5, 12), /* ETNB0RXCLK */ + [13] = RCAR_GP_PIN(5, 13), /* ETNB0TXER */ + [14] = RCAR_GP_PIN(5, 14), /* ETNB0TXD3 */ + [15] = RCAR_GP_PIN(5, 15), /* ETNB0TXCLK */ + [16] = RCAR_GP_PIN(5, 16), /* ETNB0TXD1 */ + [17] = RCAR_GP_PIN(5, 17), /* ETNB0TXD2 */ + [18] = RCAR_GP_PIN(5, 18), /* ETNB0TXEN */ + [19] = RCAR_GP_PIN(5, 19), /* ETNB0TXD0 */ + [20] = PIN_NONE, + [21] = PIN_NONE, + [22] = PIN_NONE, + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN6, PUD6 */ + [0] = RCAR_GP_PIN(6, 0), /* RLIN37TX */ + [1] = RCAR_GP_PIN(6, 1), /* RLIN37RX/INTP23 */ + [2] = RCAR_GP_PIN(6, 2), /* RLIN36TX */ + [3] = RCAR_GP_PIN(6, 3), /* RLIN36RX/INTP22 */ + [4] = RCAR_GP_PIN(6, 4), /* RLIN35TX */ + [5] = RCAR_GP_PIN(6, 5), /* RLIN35RX/INTP21 */ + [6] = RCAR_GP_PIN(6, 6), /* RLIN34TX */ + [7] = RCAR_GP_PIN(6, 7), /* RLIN34RX/INTP20 */ + [8] = RCAR_GP_PIN(6, 8), /* RLIN33TX */ + [9] = RCAR_GP_PIN(6, 9), /* RLIN33RX/INTP19 */ + [10] = RCAR_GP_PIN(6, 10), /* RLIN32TX */ + [11] = RCAR_GP_PIN(6, 11), /* RLIN32RX/INTP18 */ + [12] = RCAR_GP_PIN(6, 12), /* RLIN31TX */ + [13] = RCAR_GP_PIN(6, 13), /* RLIN31RX/INTP17 */ + [14] = RCAR_GP_PIN(6, 14), /* RLIN30TX */ + [15] = RCAR_GP_PIN(6, 15), /* RLIN30RX/INTP16 */ + [16] = RCAR_GP_PIN(6, 16), /* INTP37 */ + [17] = RCAR_GP_PIN(6, 17), /* INTP36 */ + [18] = RCAR_GP_PIN(6, 18), /* INTP35 */ + [19] = RCAR_GP_PIN(6, 19), /* INTP34 */ + [20] = RCAR_GP_PIN(6, 20), /* INTP33 */ + [21] = RCAR_GP_PIN(6, 21), /* INTP32 */ + [22] = RCAR_GP_PIN(6, 22), /* NMI1 */ + [23] = PIN_NONE, + [24] = PIN_NONE, + [25] = PIN_NONE, + [26] = PIN_NONE, + [27] = PIN_NONE, + [28] = PIN_NONE, + [29] = PIN_NONE, + [30] = PIN_NONE, + [31] = PIN_NONE, + } }, + { PFC_BIAS_REG(0xc0, 0xe0) { /* PUEN7, PUD7 */ + [0] = RCAR_GP_PIN(7, 0), /* CAN0TX */ + [1] = RCAR_GP_PIN(7, 1), /* CAN0RX/INTP0 */ + [2] = RCAR_GP_PIN(7, 2), /* CAN1TX */ + [3] = RCAR_GP_PIN(7, 3), /* CAN1RX/INTP1 */ + [4] = RCAR_GP_PIN(7, 4), /* CAN2TX */ + [5] = RCAR_GP_PIN(7, 5), /* CAN2RX/INTP2 */ + [6] = RCAR_GP_PIN(7, 6), /* CAN3TX */ + [7] = RCAR_GP_PIN(7, 7), /* CAN3RX/INTP3 */ + [8] = RCAR_GP_PIN(7, 8), /* CAN4TX */ + [9] = RCAR_GP_PIN(7, 9), /* CAN4RX/INTP4 */ + [10] = RCAR_GP_PIN(7, 10), /* CAN5TX */ + [11] = RCAR_GP_PIN(7, 11), /* CAN5RX/INTP5 */ + [12] = RCAR_GP_PIN(7, 12), /* CAN6TX */ + [13] = RCAR_GP_PIN(7, 13), /* CAN6RX/INTP6 */ + [14] = RCAR_GP_PIN(7, 14), /* CAN7TX */ + [15] = RCAR_GP_PIN(7, 15), /* CAN7RX/INTP7 */ + [16] = RCAR_GP_PIN(7, 16), /* CAN8TX */ + [17] = RCAR_GP_PIN(7, 17), /* CAN8RX/INTP8 */ + [18] = RCAR_GP_PIN(7, 18), /* CAN9TX */ + [19] = RCAR_GP_PIN(7, 19), /* CAN9RX/INTP9 */ + [20] = RCAR_GP_PIN(7, 20), /* CAN10TX */ + [21] = RCAR_GP_PIN(7, 21), /* CAN10RX/INTP10 */ + [22] = RCAR_GP_PIN(7, 22), /* CAN11TX */ + [23] = RCAR_GP_PIN(7, 23), /* CAN11RX/INTP11 */ + [24] = RCAR_GP_PIN(7, 24), /* CAN12TX */ + [25] = RCAR_GP_PIN(7, 25), /* CAN12RX/INTP12 */ + [26] = RCAR_GP_PIN(7, 26), /* CAN13TX */ + [27] = RCAR_GP_PIN(7, 27), /* CAN13RX/INTP13 */ + [28] = RCAR_GP_PIN(7, 28), /* CAN14TX */ + [29] = RCAR_GP_PIN(7, 29), /* CAN14RX/INTP14 */ + [30] = RCAR_GP_PIN(7, 30), /* CAN15TX */ + [31] = RCAR_GP_PIN(7, 31), /* CAN15RX/INTP15 */ + } }, + { /* sentinel */ }, +}; + +const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void) +{ + return pfc_bias_regs; +} + +const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) +{ + return pfc_drive_regs; +} + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + if (RCAR_IS_GP_PIN(pin) == false) + return -EINVAL; + + *reg_index = pin / 32; + + return 0; +} diff --git a/soc/arm/renesas_rcar/gen4/pinctrl_soc.h b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h new file mode 100644 index 00000000000..f55b114cddb --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/pinctrl_soc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#define ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ +#include + +#endif /* ZEPHYR_SOC_ARM_RENESAS_RCAR_GEN4_PINCTRL_SOC_H_ */ diff --git a/soc/arm/renesas_rcar/gen4/soc.h b/soc/arm/renesas_rcar/gen4/soc.h new file mode 100644 index 00000000000..3717fb8a8a8 --- /dev/null +++ b/soc/arm/renesas_rcar/gen4/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 IoT.bzh + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef _SOC__H_ +#define _SOC__H_ + +/* Define CMSIS configurations */ +#define __CR_REV 1U + +/* Do not let CMSIS to handle GIC and Timer */ +#define __GIC_PRESENT 0 +#define __TIM_PRESENT 0 + +#endif /* _SOC__H_ */ diff --git a/soc/arm/renesas_smartbond/da1469x/Kconfig.series b/soc/arm/renesas_smartbond/da1469x/Kconfig.series index a3a9e569460..c3672a9ecaf 100644 --- a/soc/arm/renesas_smartbond/da1469x/Kconfig.series +++ b/soc/arm/renesas_smartbond/da1469x/Kconfig.series @@ -8,6 +8,7 @@ config SOC_SERIES_DA1469X select CPU_HAS_FPU select CPU_HAS_ARM_MPU select CPU_CORTEX_M_HAS_SYSTICK + select ARMV8_M_DSP select SOC_FAMILY_SMARTBOND select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select CLOCK_CONTROL diff --git a/soc/arm/rpi_pico/rp2/soc.c b/soc/arm/rpi_pico/rp2/soc.c index d953436f77e..012f5431283 100644 --- a/soc/arm/rpi_pico/rp2/soc.c +++ b/soc/arm/rpi_pico/rp2/soc.c @@ -26,24 +26,6 @@ LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); -static int rp2040_init(void) -{ - reset_block(~(RESETS_RESET_IO_QSPI_BITS | RESETS_RESET_PADS_QSPI_BITS | - RESETS_RESET_PLL_USB_BITS | RESETS_RESET_PLL_SYS_BITS)); - - unreset_block_wait(RESETS_RESET_BITS & - ~(RESETS_RESET_ADC_BITS | RESETS_RESET_RTC_BITS | - RESETS_RESET_SPI0_BITS | RESETS_RESET_SPI1_BITS | - RESETS_RESET_UART0_BITS | RESETS_RESET_UART1_BITS | - RESETS_RESET_USBCTRL_BITS | RESETS_RESET_PWM_BITS)); - - clocks_init(); - - unreset_block_wait(RESETS_RESET_BITS); - - return 0; -} - /* * Some pico-sdk drivers call panic on fatal error. * This alternative implementation of panic handles the panic @@ -57,5 +39,3 @@ void __attribute__((noreturn)) panic(const char *fmt, ...) vprintf(fmt, args); k_fatal_halt(K_ERR_CPU_EXCEPTION); } - -SYS_INIT(rp2040_init, PRE_KERNEL_1, 0); diff --git a/soc/arm/rpi_pico/rp2/soc.h b/soc/arm/rpi_pico/rp2/soc.h index b38d2edf461..0eef4cf92a2 100644 --- a/soc/arm/rpi_pico/rp2/soc.h +++ b/soc/arm/rpi_pico/rp2/soc.h @@ -12,8 +12,6 @@ #ifndef _RPI_PICO_RP2040_SOC_H_ #define _RPI_PICO_RP2040_SOC_H_ - -#define __VTOR_PRESENT CONFIG_CPU_CORTEX_M_HAS_VTOR -#define __MPU_PRESENT CONFIG_CPU_HAS_ARM_MPU +#include #endif /* _RPI_PICO_RP2040_SOC_H_ */ diff --git a/soc/arm/silabs_exx32/Kconfig b/soc/arm/silabs_exx32/Kconfig index d0bbf68c885..60bda813903 100644 --- a/soc/arm/silabs_exx32/Kconfig +++ b/soc/arm/silabs_exx32/Kconfig @@ -340,4 +340,13 @@ config SOC_GECKO_USE_RAIL hardware. This option enable the proper set of features to allow to properly compile with the RAIL blob. +config SOC_GECKO_CUSTOM_RADIO_PHY + bool "Use RAIL for custom radio phy packet sending and receiving" + depends on SOC_GECKO_HAS_RADIO + select SOC_GECKO_USE_RAIL + help + If enabled, RAIL can be used for user generated custom radio phy + management, sending and receiving packets on radio phy. User has + to provide the radio_config.c and radio_config.h files for the phy. + endif # SOC_FAMILY_EXX32 diff --git a/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h index 533a591fbde..14a59b29612 100644 --- a/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h +++ b/soc/arm/silabs_exx32/common/sl_device_init_hfxo_config.h @@ -12,5 +12,6 @@ #define SL_DEVICE_INIT_HFXO_MODE cmuHfxoOscMode_Crystal #define SL_DEVICE_INIT_HFXO_FREQ DT_PROP(DT_NODELABEL(clk_hfxo), clock_frequency) #define SL_DEVICE_INIT_HFXO_CTUNE DT_PROP(DT_NODELABEL(clk_hfxo), ctune) +#define SL_DEVICE_INIT_HFXO_PRECISION DT_PROP(DT_NODELABEL(clk_hfxo), precision) #endif /* SL_DEVICE_INIT_HFXO_CONFIG_H */ diff --git a/soc/arm/silabs_exx32/efm32hg/Kconfig.series b/soc/arm/silabs_exx32/efm32hg/Kconfig.series index 33793b5386d..d17c24fbcdb 100644 --- a/soc/arm/silabs_exx32/efm32hg/Kconfig.series +++ b/soc/arm/silabs_exx32/efm32hg/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_EFM32HG select CPU_CORTEX_M0PLUS select SOC_FAMILY_EXX32 select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR select HAS_SILABS_GECKO select SOC_GECKO_CMU select SOC_GECKO_GPIO diff --git a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series index a6881d77861..6f20bfbe57e 100644 --- a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series +++ b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.defconfig.series @@ -10,6 +10,7 @@ config SOC_SERIES config SOC_PART_NUMBER default "EFR32MG12P332F1024GL125" if SOC_PART_NUMBER_EFR32MG12P332F1024GL125 + default "EFR32MG12P432F1024GL125" if SOC_PART_NUMBER_EFR32MG12P432F1024GL125 default "EFR32MG12P433F1024GM68" if SOC_PART_NUMBER_EFR32MG12P433F1024GM68 config NUM_IRQS diff --git a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.soc b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.soc index 8f2f260730d..b171553e638 100644 --- a/soc/arm/silabs_exx32/efr32mg12p/Kconfig.soc +++ b/soc/arm/silabs_exx32/efr32mg12p/Kconfig.soc @@ -10,3 +10,7 @@ config SOC_PART_NUMBER_EFR32MG12P332F1024GL125 config SOC_PART_NUMBER_EFR32MG12P433F1024GM68 bool depends on SOC_SERIES_EFR32MG12P + +config SOC_PART_NUMBER_EFR32MG12P432F1024GL125 + bool + depends on SOC_SERIES_EFR32MG12P diff --git a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series index 146493469e8..731658d29e3 100644 --- a/soc/arm/silabs_exx32/efr32mg21/Kconfig.series +++ b/soc/arm/silabs_exx32/efr32mg21/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_EFR32MG21 select ARMV8_M_DSP select CPU_HAS_FPU select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU select SOC_FAMILY_EXX32 select SOC_GECKO_HAS_RADIO select SOC_GECKO_SERIES2 diff --git a/soc/arm/st_stm32/common/CMakeLists.txt b/soc/arm/st_stm32/common/CMakeLists.txt index 70dd8c865c9..af898951cc5 100644 --- a/soc/arm/st_stm32/common/CMakeLists.txt +++ b/soc/arm/st_stm32/common/CMakeLists.txt @@ -8,3 +8,7 @@ zephyr_sources_ifdef(CONFIG_STM32_BACKUP_SRAM stm32_backup_sram.c) zephyr_linker_sources_ifdef(CONFIG_STM32_BACKUP_SRAM SECTIONS stm32_backup_sram.ld) zephyr_sources(soc_config.c) + +if (NOT CONFIG_DEBUG AND CONFIG_PM) + zephyr_sources_ifdef(CONFIG_DT_HAS_SWJ_CONNECTOR_ENABLED pm_debug_swj.c) +endif() diff --git a/soc/arm/st_stm32/common/Kconfig.defconfig.series b/soc/arm/st_stm32/common/Kconfig.defconfig.series index 40dda7b6fa0..5b586516d83 100644 --- a/soc/arm/st_stm32/common/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/common/Kconfig.defconfig.series @@ -13,6 +13,9 @@ config CORTEX_M_SYSTICK DT_STM32_RCC_PATH := $(dt_nodelabel_path,rcc) DT_STM32_RCC_CLOCK_FREQ := $(dt_node_int_prop_int,$(DT_STM32_RCC_PATH),clock-frequency) +DT_ST_PRESCALER := st,prescaler +DT_STM32_LPTIM_PATH := $(dt_nodelabel_path,stm32_lp_tick_source) + config SYS_CLOCK_HW_CYCLES_PER_SEC default "$(DT_STM32_RCC_CLOCK_FREQ)" if "$(dt_nodelabel_enabled,rcc)" @@ -24,9 +27,28 @@ config LOG_BACKEND_SWO_REF_FREQ_HZ endif # LOG_BACKEND_SWO # set the tick per sec as a divider of the LPTIM clock source +# with a minimum value of 4096 for SYS_CLOCK_TICKS_PER_SEC to keep +# SYS_CLOCK_TICKS_PER_SEC not too high compared to the LPTIM counter clock +config SYS_CLOCK_TICKS_PER_SEC + default 4096 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16 + default 2048 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16 + default 1024 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32 + default 512 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64 + default 256 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128 + depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE + config SYS_CLOCK_TICKS_PER_SEC - default 4096 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSE - default 4000 if STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI + default 4000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" < 16 + default 2000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 16 + default 1000 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 32 + default 500 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 64 + default 250 if "$(dt_node_int_prop_int,$(DT_STM32_LPTIM_PATH),$(DT_ST_PRESCALER))" = 128 + depends on STM32_LPTIM_TIMER && STM32_LPTIM_CLOCK_LSI + +choice STM32_LPTIM_CLOCK + default STM32_LPTIM_CLOCK_LSE if "$(dt_node_ph_array_prop_int,$(DT_STM32_LPTIM_PATH),clocks,1,bus)" = 2 + default STM32_LPTIM_CLOCK_LSI if "$(dt_node_ph_array_prop_int,$(DT_STM32_LPTIM_PATH),clocks,1,bus)" = 3 +endchoice config CLOCK_CONTROL_STM32_CUBE default y diff --git a/soc/arm/st_stm32/common/Kconfig.soc b/soc/arm/st_stm32/common/Kconfig.soc index 07b2122cefd..2fd9084cc55 100644 --- a/soc/arm/st_stm32/common/Kconfig.soc +++ b/soc/arm/st_stm32/common/Kconfig.soc @@ -21,10 +21,19 @@ config USE_STM32_ASSERT help Enable asserts in STM32Cube HAL and LL drivers. +config SWJ_ANALOG_PRIORITY + int "SWJ DP port to analog routine initialization priority" + default 49 + help + Initialization priority of the routine within the PRE_KERNEL1 level. + This priority must be greater than GPIO_INIT_PRIORITY and lower than + UART_INIT_PRIORITY. + choice POWER_SUPPLY_CHOICE prompt "STM32 power supply configuration" default POWER_SUPPLY_LDO - depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32U5X + depends on SOC_SERIES_STM32H7X || SOC_SERIES_STM32U5X || \ + SOC_STM32WBA55XX config POWER_SUPPLY_LDO bool "LDO supply" @@ -34,30 +43,30 @@ config POWER_SUPPLY_DIRECT_SMPS config POWER_SUPPLY_SMPS_1V8_SUPPLIES_LDO bool "SMPS 1.8V supplies LDO (no external supply)" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_LDO bool "SMPS 2.5V supplies LDO (no external supply)" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_1V8_SUPPLIES_EXT_AND_LDO bool "External SMPS 1.8V supply, supplies LDO" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_EXT_AND_LDO bool "External SMPS 2.5V supply, supplies LDO" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_1V8_SUPPLIES_EXT bool "External SMPS 1.8V supply and bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_SMPS_2V5_SUPPLIES_EXT bool "External SMPS 2.5V supply and bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX config POWER_SUPPLY_EXTERNAL_SOURCE bool "Bypass" - depends on !SOC_SERIES_STM32U5X + depends on !SOC_SERIES_STM32U5X && !SOC_SERIES_STM32WBAX endchoice diff --git a/soc/arm/st_stm32/common/pm_debug_swj.c b/soc/arm/st_stm32/common/pm_debug_swj.c new file mode 100644 index 00000000000..5897670e5f6 --- /dev/null +++ b/soc/arm/st_stm32/common/pm_debug_swj.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define SWJ_NODE DT_NODELABEL(swj_port) + +PINCTRL_DT_DEFINE(SWJ_NODE); + +const struct pinctrl_dev_config *swj_pcfg = PINCTRL_DT_DEV_CONFIG_GET(SWJ_NODE); + +/* + * Serial Wire / JTAG port pins are enabled as part of SoC default configuration. + * When debug access is not needed and in case power consumption performance is + * expected, configure matching pins to analog in order to save power. + */ + +static int swj_to_analog(void) +{ + int err; + + /* Set Serial Wire / JTAG port pins to analog mode */ + err = pinctrl_apply_state(swj_pcfg, PINCTRL_STATE_SLEEP); + if (err < 0) { + __ASSERT(0, "SWJ pinctrl setup failed"); + return err; + } + + return 0; +} + +/* Run this routine as the earliest pin configuration in the target, + * to avoid potential conflicts with devices accessing SWJ-DG pins for + * their own needs. + */ +SYS_INIT(swj_to_analog, PRE_KERNEL_1, CONFIG_SWJ_ANALOG_PRIORITY); diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) new file mode 100644 index 00000000000..752bef89690 --- /dev/null +++ b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303x(b-c) @@ -0,0 +1,16 @@ +# ST Microelectronics STM32F303XC MCU + +# Copyright (c) 2016 RnDity Sp. z o.o. +# SPDX-License-Identifier: Apache-2.0 + +# The HAL expects STM32F302XC to be defined for both the xB and xC variants (only RAM- and Flash- +# size differ). +if SOC_STM32F303XB || SOC_STM32F303XC + +config SOC + default "stm32f303xc" + +config NUM_IRQS + default 82 + +endif # SOC_STM32F303XB || SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc b/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc deleted file mode 100644 index 875ed373a69..00000000000 --- a/soc/arm/st_stm32/stm32f3/Kconfig.defconfig.stm32f303xc +++ /dev/null @@ -1,14 +0,0 @@ -# ST Microelectronics STM32F303XC MCU - -# Copyright (c) 2016 RnDity Sp. z o.o. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_STM32F303XC - -config SOC - default "stm32f303xc" - -config NUM_IRQS - default 82 - -endif # SOC_STM32F303XC diff --git a/soc/arm/st_stm32/stm32f3/Kconfig.soc b/soc/arm/st_stm32/stm32f3/Kconfig.soc index 6dde4dfd8cf..20af2538ba5 100644 --- a/soc/arm/st_stm32/stm32f3/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f3/Kconfig.soc @@ -17,6 +17,10 @@ config SOC_STM32F302XC config SOC_STM32F303X8 bool "STM32F303X8" +config SOC_STM32F303XB + bool "STM32F303XB" + select CPU_HAS_ARM_MPU + config SOC_STM32F303XC bool "STM32F303XC" select CPU_HAS_ARM_MPU diff --git a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series index 28ed9cc3a55..63725609480 100644 --- a/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32f4/Kconfig.defconfig.series @@ -17,8 +17,17 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 -config PM - select COUNTER - select COUNTER_RTC_STM32_SUBSECONDS +if PM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y if DT_HAS_ST_STM32_RTC_ENABLED + +config IDLE_STACK_SIZE + default 512 + +endif # PM endif # SOC_SERIES_STM32F4X diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx b/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx new file mode 100644 index 00000000000..5b85551f939 --- /dev/null +++ b/soc/arm/st_stm32/stm32f7/Kconfig.defconfig.stm32f722xx @@ -0,0 +1,15 @@ +# ST STM32F722XE Configuration options +# +# Copyright (c) 2023 Evan Perry Grove +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32F722XX + +config SOC + default "stm32f722xx" + +config NUM_IRQS + default 104 + +endif # SOC_STM32F722XX diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.series b/soc/arm/st_stm32/stm32f7/Kconfig.series index 860aea7e716..a298fa2b579 100644 --- a/soc/arm/st_stm32/stm32f7/Kconfig.series +++ b/soc/arm/st_stm32/stm32f7/Kconfig.series @@ -9,6 +9,8 @@ config SOC_SERIES_STM32F7X select CPU_CORTEX_M7 select CPU_CORTEX_M_HAS_DWT select CPU_HAS_FPU + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_HAS_ARM_MPU diff --git a/soc/arm/st_stm32/stm32f7/Kconfig.soc b/soc/arm/st_stm32/stm32f7/Kconfig.soc index 727ed908813..c83a9962a60 100644 --- a/soc/arm/st_stm32/stm32f7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32f7/Kconfig.soc @@ -3,12 +3,16 @@ # Copyright (c) 2018 Yurii Hamann # Copyright (c) 2022, Rtone. # Copyright (c) 2023, Rahul Arasikere. +# Copyright (c) 2023 Evan Perry Grove # SPDX-License-Identifier: Apache-2.0 choice prompt "STM32F7x MCU Selection" depends on SOC_SERIES_STM32F7X +config SOC_STM32F722XX + bool "STM32F722XX" + config SOC_STM32F723XX bool "STM32F723XX" diff --git a/soc/arm/st_stm32/stm32f7/soc.c b/soc/arm/st_stm32/stm32f7/soc.c index b06a894197a..4a9cc72a78d 100644 --- a/soc/arm/st_stm32/stm32f7/soc.c +++ b/soc/arm/st_stm32/stm32f7/soc.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -30,13 +31,8 @@ static int st_stm32f7_init(void) /* Enable ART Flash cache accelerator */ LL_FLASH_EnableART(); - SCB_EnableICache(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 16 MHz from HSI */ diff --git a/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx b/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx index 86c47b158e9..767cea2556c 100644 --- a/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx +++ b/soc/arm/st_stm32/stm32g0/Kconfig.defconfig.stm32g0b1xx @@ -11,4 +11,11 @@ config SOC config NUM_IRQS default 31 +if CAN_STM32_FDCAN + +config SHARED_INTERRUPTS + default y if $(dt_nodelabel_enabled,fdcan1) && $(dt_nodelabel_enabled,fdcan2) + +endif # CAN_STM32_FDCAN + endif # SOC_STM32G0B1XX diff --git a/soc/arm/st_stm32/stm32g4/Kconfig.series b/soc/arm/st_stm32/stm32g4/Kconfig.series index 6d81e3f1fc1..f04432c3ee3 100644 --- a/soc/arm/st_stm32/stm32g4/Kconfig.series +++ b/soc/arm/st_stm32/stm32g4/Kconfig.series @@ -14,5 +14,6 @@ config SOC_SERIES_STM32G4X select CPU_HAS_ARM_MPU select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select HAS_PM + select HAS_SWO help Enable support for STM32G4 MCU series diff --git a/soc/arm/st_stm32/stm32h5/CMakeLists.txt b/soc/arm/st_stm32/stm32h5/CMakeLists.txt index c8d32ef22aa..e02052e3946 100644 --- a/soc/arm/st_stm32/stm32h5/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32h5/CMakeLists.txt @@ -4,6 +4,5 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers) zephyr_sources( soc.c ) -zephyr_linker_sources(SECTIONS sections.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32h5/sections.ld b/soc/arm/st_stm32/stm32h5/sections.ld deleted file mode 100644 index ead1bcd811b..00000000000 --- a/soc/arm/st_stm32/stm32h5/sections.ld +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 Mario Jaun - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(mac), okay) - -SECTION_DATA_PROLOGUE(eth_stm32,(NOLOAD),) -{ -#if DT_NODE_HAS_STATUS(DT_NODELABEL(sram3), okay) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))); - *(.eth_stm32_desc) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 256; - *(.eth_stm32_buf) - . = ABSOLUTE(DT_REG_ADDR(DT_NODELABEL(sram3))) + 16K; -} GROUP_DATA_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3)), LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram3))) -#endif -#endif diff --git a/soc/arm/st_stm32/stm32h7/Kconfig.soc b/soc/arm/st_stm32/stm32h7/Kconfig.soc index 7856c52652a..4f7441a6fdc 100644 --- a/soc/arm/st_stm32/stm32h7/Kconfig.soc +++ b/soc/arm/st_stm32/stm32h7/Kconfig.soc @@ -16,81 +16,113 @@ choice config SOC_STM32H723XX bool "STM32H723XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H725XX bool "STM32H725XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H730XX bool "STM32H730XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H730XXQ bool "STM32H730XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H735XX bool "STM32H735XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H743XX bool "STM32H743XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H745XX bool "STM32H745XX" select CPU_HAS_FPU_DOUBLE_PRECISION if CPU_CORTEX_M7 + select CPU_HAS_ICACHE if CPU_CORTEX_M7 + select CPU_HAS_DCACHE if CPU_CORTEX_M7 select STM32H7_DUAL_CORE config SOC_STM32H747XX bool "STM32H747XX" select CPU_HAS_FPU_DOUBLE_PRECISION if CPU_CORTEX_M7 + select CPU_HAS_ICACHE if CPU_CORTEX_M7 + select CPU_HAS_DCACHE if CPU_CORTEX_M7 select STM32H7_DUAL_CORE config SOC_STM32H750XX bool "STM32H750XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H753XX bool "STM32H753XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7A3XX bool "STM32H7A3XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7A3XXQ bool "STM32H7A3XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B0XX bool "STM32H7B0XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B0XXQ bool "STM32H7B0XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B3XX bool "STM32H7B3XX" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION config SOC_STM32H7B3XXQ bool "STM32H7B3XXQ" select CPU_CORTEX_M7 + select CPU_HAS_ICACHE + select CPU_HAS_DCACHE select CPU_HAS_FPU_DOUBLE_PRECISION endchoice diff --git a/soc/arm/st_stm32/stm32h7/soc_m7.c b/soc/arm/st_stm32/stm32h7/soc_m7.c index 8e72b3ee390..39c1d917c34 100644 --- a/soc/arm/st_stm32/stm32h7/soc_m7.c +++ b/soc/arm/st_stm32/stm32h7/soc_m7.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -54,13 +55,8 @@ static int stm32h7_m4_wakeup(void) */ static int stm32h7_init(void) { - SCB_EnableICache(); - - if (IS_ENABLED(CONFIG_DCACHE)) { - if (!(SCB->CCR & SCB_CCR_DC_Msk)) { - SCB_EnableDCache(); - } - } + sys_cache_instr_enable(); + sys_cache_data_enable(); /* Update CMSIS SystemCoreClock variable (HCLK) */ /* At reset, system core clock is set to 64 MHz from HSI */ diff --git a/soc/arm/st_stm32/stm32mp1/Kconfig.series b/soc/arm/st_stm32/stm32mp1/Kconfig.series index 0c6580e84cc..c1576a7ee17 100644 --- a/soc/arm/st_stm32/stm32mp1/Kconfig.series +++ b/soc/arm/st_stm32/stm32mp1/Kconfig.series @@ -11,6 +11,7 @@ config SOC_SERIES_STM32MP1X select SOC_FAMILY_STM32 select HAS_STM32CUBE select CPU_HAS_ARM_MPU + select CPU_HAS_FPU select OPENAMP_RSC_TABLE if RAM_CONSOLE help Enable support for STM32MP1 MPU series diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt index 0fd5073770d..d26c143f8f6 100644 --- a/soc/arm/st_stm32/stm32wba/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -9,4 +9,14 @@ zephyr_sources_ifdef(CONFIG_PM power.c ) +if(CONFIG_BT_STM32WBA) + zephyr_include_directories(hci_if) + + zephyr_sources(hci_if/linklayer_plat.c) + zephyr_sources(hci_if/bleplat.c) + zephyr_sources(hci_if/host_stack_if.c) + zephyr_sources(hci_if/ll_sys_if.c) + zephyr_sources(hci_if/stm32_timer.c) +endif() + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index e6d57729a09..340b62049e8 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -13,4 +13,52 @@ config SOC_SERIES config STM32_LPTIM_TIMER default y if PM +choice BT_HCI_BUS_TYPE + default BT_STM32WBA + depends on BT +endchoice + +config BT_STM32WBA + select DYNAMIC_INTERRUPTS + select DYNAMIC_DIRECT_INTERRUPTS + select ENTROPY_GENERATOR + select USE_STM32_HAL_RAMCFG + +if BT_STM32WBA + +choice LIBC_IMPLEMENTATION + default NEWLIB_LIBC +endchoice + +choice LINKER_ORPHAN_CONFIGURATION + default LINKER_ORPHAN_SECTION_PLACE +endchoice + +config ENTROPY_STM32_CLK_CHECK + default n + +endif + +if PM_S2RAM + +config COUNTER + default y + +config COUNTER_RTC_STM32_SUBSECONDS + default y + +config STM32_LPTIM_STDBY_TIMER + default y + +config TICKLESS_KERNEL + default y + +config COUNTER_RTC_STM32_SAVE_VALUE_BETWEEN_RESETS + default y + +config IDLE_STACK_SIZE + default 512 + +endif + endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx new file mode 100644 index 00000000000..ca745f87471 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.stm32wba55xx @@ -0,0 +1,14 @@ +# ST Microelectronics STM32WBA55XX MCU + +# Copyright (c) 2023 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +if SOC_STM32WBA55XX + +config SOC + default "stm32wba55xx" + +config NUM_IRQS + default 70 + +endif # SOC_STM32WBA55XX diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.series index 28edaf07790..5cdaaa7e672 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.series @@ -15,6 +15,7 @@ config SOC_SERIES_STM32WBAX select ARMV8_M_DSP select CPU_CORTEX_M_HAS_DWT select HAS_STM32CUBE + select USE_STM32_HAL_PWR_EX select HAS_PM help Enable support for STM32WBA MCU series diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.soc b/soc/arm/st_stm32/stm32wba/Kconfig.soc index 6e8586d8f3d..75f48454b1c 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.soc +++ b/soc/arm/st_stm32/stm32wba/Kconfig.soc @@ -10,4 +10,7 @@ depends on SOC_SERIES_STM32WBAX config SOC_STM32WBA52XX bool "STM32WBA52XX" +config SOC_STM32WBA55XX + bool "STM32WBA55XX" + endchoice diff --git a/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c new file mode 100644 index 00000000000..d7d66b34514 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include + +#include "bleplat.h" +#include "bpka.h" +#include "linklayer_plat.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ble_plat); + +RAMCFG_HandleTypeDef hramcfg_SRAM1; +const struct device *rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + +struct entropy_stm32_rng_dev_data { + RNG_TypeDef *rng; +}; + +struct entropy_stm32_rng_dev_cfg { + struct stm32_pclken *pclken; +}; + +void BLEPLAT_Init(void) +{ + BPKA_Reset(); + + rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + if (!device_is_ready(rng_dev)) { + LOG_ERR("error: random device not ready"); + } +} + +void BLEPLAT_RngGet(uint8_t n, uint32_t *val) +{ + LINKLAYER_PLAT_GetRNG((uint8_t *)val, 4 * n); +} + +int BLEPLAT_PkaStartP256Key(const uint32_t *local_private_key) +{ + return BPKA_StartP256Key(local_private_key); +} + +void BLEPLAT_PkaReadP256Key(uint32_t *local_public_key) +{ + BPKA_ReadP256Key(local_public_key); +} + +int BLEPLAT_PkaStartDhKey(const uint32_t *local_private_key, + const uint32_t *remote_public_key) +{ + return BPKA_StartDhKey(local_private_key, remote_public_key); +} + +int BLEPLAT_PkaReadDhKey(uint32_t *dh_key) +{ + return BPKA_ReadDhKey(dh_key); +} + +void BPKACB_Complete(void) +{ + BLEPLATCB_PkaComplete(); +} + +void MX_RAMCFG_Init(void) +{ + /* Initialize RAMCFG SRAM1 */ + hramcfg_SRAM1.Instance = RAMCFG_SRAM1; + if (HAL_RAMCFG_Init(&hramcfg_SRAM1) != HAL_OK) { + LOG_ERR("Could not init RAMCFG"); + } +} + +void *ble_memcpy(void *dst, const void *src, uint8_t n) +{ + memcpy(dst, src, (size_t)n); + + return dst; +} + +void *ble_memset(void *dst, uint8_t c, uint16_t n) +{ + memset((void *)dst, (int)c, (size_t)n); + + return dst; +} + +int8_t ble_memcmp(const void *a, const void *b, uint16_t n) +{ + return (int8_t)memcmp(a, b, (size_t)n); +} + +void Error_Handler(void) +{ + LOG_ERR(""); +} + +void enable_rng_clock(bool enable) +{ + const struct entropy_stm32_rng_dev_cfg *dev_cfg = rng_dev->config; + struct entropy_stm32_rng_dev_data *dev_data = rng_dev->data; + struct stm32_pclken *rng_pclken; + const struct device *rcc; + unsigned int key; + + rcc = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + rng_pclken = (clock_control_subsys_t)&dev_cfg->pclken[0]; + + key = irq_lock(); + + /* Enable/Disable RNG clock only if not in use */ + if (!LL_RNG_IsEnabled((RNG_TypeDef *)dev_data->rng)) { + if (enable) { + clock_control_on(rcc, rng_pclken); + } else { + clock_control_off(rcc, rng_pclken); + } + } + + irq_unlock(key); +} + +/* PKA IP requires RNG clock to be enabled + * These APIs are used by BLE controller to enable/disable RNG clock, + * based on PKA needs. + */ +void HW_RNG_DisableClock(uint8_t user_mask) +{ + ARG_UNUSED(user_mask); + + enable_rng_clock(false); +} + +void HW_RNG_EnableClock(uint8_t user_mask) +{ + ARG_UNUSED(user_mask); + + enable_rng_clock(true); +} + +/* BLE ctlr should not disable HSI on its own */ +void SCM_HSI_CLK_OFF(void) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c new file mode 100644 index 00000000000..6cc224cc60a --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "app_conf.h" +#include "blestack.h" +#include "bpka.h" +#include "ll_intf.h" + +K_MUTEX_DEFINE(ble_ctlr_stack_mutex); +struct k_work_q ble_ctlr_work_q, ll_work_q; +struct k_work ble_ctlr_stack_work, bpka_work; + +uint8_t ll_state_busy; + +#define BLE_CTLR_TASK_STACK_SIZE (256 * 7) +#define LL_TASK_STACK_SIZE (256 * 7) +#define BLE_CTLR_TASK_PRIO (14) +#define LL_TASK_PRIO (14) + +K_THREAD_STACK_DEFINE(ble_ctlr_work_area, BLE_CTLR_TASK_STACK_SIZE); +K_THREAD_STACK_DEFINE(ll_work_area, LL_TASK_STACK_SIZE); + +void HostStack_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &ble_ctlr_stack_work); +} + +static void ble_ctlr_stack_handler(struct k_work *work) +{ + uint8_t running = 0x0; + change_state_options_t options; + + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + running = BleStack_Process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); + + if (ll_state_busy == 1) { + options.combined_value = 0x0F; + ll_intf_chng_evnt_hndlr_state(options); + ll_state_busy = 0; + } + + if (running == BLE_SLEEPMODE_RUNNING) { + HostStack_Process(); + } +} + +void BPKACB_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &bpka_work); +} + +static void bpka_work_handler(struct k_work *work) +{ + BPKA_BG_Process(); +} + +static int stm32wba_ble_ctlr_init(void) +{ + k_work_queue_init(&ble_ctlr_work_q); + k_work_queue_start(&ble_ctlr_work_q, ble_ctlr_work_area, + K_THREAD_STACK_SIZEOF(ble_ctlr_work_area), + BLE_CTLR_TASK_PRIO, NULL); + + k_work_queue_init(&ll_work_q); + k_work_queue_start(&ll_work_q, ll_work_area, + K_THREAD_STACK_SIZEOF(ll_work_area), + LL_TASK_PRIO, NULL); + + k_work_init(&ble_ctlr_stack_work, &ble_ctlr_stack_handler); + k_work_init(&bpka_work, &bpka_work_handler); + + return 0; +} + +SYS_INIT(stm32wba_ble_ctlr_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c new file mode 100644 index 00000000000..1e890949147 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "scm.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(linklayer_plat); + +#define RADIO_INTR_PRIO_HIGH_Z (RADIO_INTR_PRIO_HIGH + _IRQ_PRIO_OFFSET) +#define RADIO_INTR_PRIO_LOW_Z (RADIO_INTR_PRIO_LOW + _IRQ_PRIO_OFFSET) + +/* 2.4GHz RADIO ISR callbacks */ +typedef void (*radio_isr_cb_t) (void); + +radio_isr_cb_t radio_callback; +radio_isr_cb_t low_isr_callback; + +extern const struct device *rng_dev; + +/* Radio critical sections */ +volatile int32_t prio_high_isr_counter; +volatile int32_t prio_low_isr_counter; +volatile int32_t prio_sys_isr_counter; +volatile int32_t irq_counter; +volatile uint32_t local_basepri_value; + +/* Radio SW low ISR global variable */ +volatile uint8_t radio_sw_low_isr_is_running_high_prio; + +void LINKLAYER_PLAT_ClockInit(void) +{ + LL_PWR_EnableBkUpAccess(); + + /* Select LSE as Sleep CLK */ + __HAL_RCC_RADIOSLPTIM_CONFIG(RCC_RADIOSTCLKSOURCE_LSE); + + LL_PWR_DisableBkUpAccess(); + + /* Enable AHB5ENR peripheral clock (bus CLK) */ + __HAL_RCC_RADIO_CLK_ENABLE(); +} + +void LINKLAYER_PLAT_DelayUs(uint32_t delay) +{ + k_busy_wait(delay); +} + +void LINKLAYER_PLAT_WaitHclkRdy(void) +{ + while (HAL_RCCEx_GetRadioBusClockReadiness() != RCC_RADIO_BUS_CLOCK_READY) { + } +} + +void LINKLAYER_PLAT_AclkCtrl(uint8_t enable) +{ + LOG_DBG("enable: %d", enable); + if (enable) { + /* Enable RADIO baseband clock (active CLK) */ + HAL_RCCEx_EnableRadioBBClock(); + + /* Polling on HSE32 activation */ + while (LL_RCC_HSE_IsReady() == 0) { + } + } else { + /* Disable RADIO baseband clock (active CLK) */ + HAL_RCCEx_DisableRadioBBClock(); + } +} + +void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len) +{ + int ret; + + /* Read 32-bit random values from HW driver */ + ret = entropy_get_entropy_isr(rng_dev, (char *)ptr_rnd, len, 0); + if (ret < 0) { + LOG_ERR("Error: entropy_get_entropy failed: %d", ret); + } + LOG_DBG("n %d, val: %p", len, (void *)ptr_rnd); +} + +void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)()) +{ + radio_callback = intr_cb; +} + +void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)()) +{ + low_isr_callback = intr_cb; +} + +void radio_high_prio_isr(void) +{ + radio_callback(); + + HAL_RCCEx_DisableRequestUponRadioWakeUpEvent(); + + __ISB(); + + ISR_DIRECT_PM(); +} + +void radio_low_prio_isr(void) +{ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + low_isr_callback(); + + /* Check if nested SW radio low interrupt has been requested*/ + if (radio_sw_low_isr_is_running_high_prio != 0) { + NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_INTR_PRIO_LOW); + radio_sw_low_isr_is_running_high_prio = 0; + } + + /* Re-enable SW radio low interrupt */ + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + ISR_DIRECT_PM(); +} + + +void link_layer_register_isr(void) +{ + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z, + (void (*)(const void *))radio_high_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_INTR_NUM); + + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_SW_LOW_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO, + (void (*)(const void *))radio_low_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + + +void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority) +{ + uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW_Z; + + LOG_DBG("Priotity: %d", priority); + + /* Check if a SW low interrupt as already been raised. + * Nested call far radio low isr are not supported + **/ + + if (NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0) { + /* No nested SW low ISR, default behavior */ + + if (priority == 0) { + low_isr_priority = RADIO_SW_LOW_INTR_PRIO; + } + + NVIC_SetPriority((IRQn_Type)RADIO_SW_LOW_INTR_NUM, low_isr_priority); + } else { + /* Nested call detected */ + /* No change for SW radio low interrupt priority for the moment */ + + if (priority != 0) { + /* At the end of current SW radio low ISR, this pending SW + * low interrupt will run with RADIO_INTR_PRIO_LOW_Z priority + **/ + radio_sw_low_isr_is_running_high_prio = 1; + } + } + + NVIC_SetPendingIRQ((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + +void LINKLAYER_PLAT_EnableIRQ(void) +{ + irq_counter = MAX(0, irq_counter - 1); + + if (irq_counter == 0) { + __enable_irq(); + } +} + +void LINKLAYER_PLAT_DisableIRQ(void) +{ + __disable_irq(); + + irq_counter++; +} + +void LINKLAYER_PLAT_Assert(uint8_t condition) +{ + __ASSERT_NO_MSG(condition); +} + +void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter--; + if (prio_high_isr_counter == 0) { + irq_enable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter--; + if (prio_low_isr_counter == 0) { + irq_enable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter--; + if (prio_sys_isr_counter == 0) { + __set_BASEPRI(local_basepri_value); + } + } +} + +void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter++; + if (prio_high_isr_counter == 1) { + irq_disable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter++; + if (prio_low_isr_counter == 1) { + irq_disable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter++; + if (prio_sys_isr_counter == 1) { + local_basepri_value = __get_BASEPRI(); + __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW_Z << 4); + } + } +} + +void LINKLAYER_PLAT_EnableRadioIT(void) +{ + irq_enable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_DisableRadioIT(void) +{ + irq_disable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_StartRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_ENABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z); + + scm_notifyradiostate(SCM_RADIO_ACTIVE); +} + +void LINKLAYER_PLAT_StopRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_DISABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW_Z); + + scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE); +} + +void LINKLAYER_PLAT_RequestTemperature(void) {} + +void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t *p_evnt_timing) {} + +void LINKLAYER_PLAT_EnableOSContextSwitch(void) {} + +void LINKLAYER_PLAT_DisableOSContextSwitch(void) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h new file mode 100644 index 00000000000..1cf621b89de --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ +#define _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ + +void link_layer_register_isr(void); + +#endif /* _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ */ diff --git a/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c new file mode 100644 index 00000000000..8607cbbafd8 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ll_sys_if); + +#include "ll_intf.h" +#include "ll_sys.h" +#include "linklayer_plat.h" +#include "app_conf.h" + +extern struct k_mutex ble_ctlr_stack_mutex; +extern struct k_work_q ll_work_q; +struct k_work ll_sys_work; + +void ll_sys_schedule_bg_process(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +void ll_sys_schedule_bg_process_isr(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +static void ll_sys_bg_process_handler(struct k_work *work) +{ + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + ll_sys_bg_process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); +} + +void ll_sys_bg_process_init(void) +{ + k_work_init(&ll_sys_work, &ll_sys_bg_process_handler); +} + +void ll_sys_config_params(void) +{ + ll_intf_config_ll_ctx_params(USE_RADIO_LOW_ISR, NEXT_EVENT_SCHEDULING_FROM_ISR); +} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c new file mode 100644 index 00000000000..45c3f1b3782 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "stm32_timer.h" + +#define TICKS_PER_MS (CONFIG_SYS_CLOCK_TICKS_PER_SEC / MSEC_PER_SEC) + +static struct k_timer timer; + +UTIL_TIMER_Status_t UTIL_TIMER_Create(UTIL_TIMER_Object_t *timer_object, + uint32_t period, UTIL_TIMER_Mode_t mode, + void (*callback)(void *), void *argument) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + timer_object->ReloadValue = period * TICKS_PER_MS; + timer_object->Mode = mode; + timer_object->Callback = callback; + timer_object->argument = argument; + timer_object->IsRunning = false; + timer_object->IsReloadStopped = false; + timer_object->Next = NULL; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Start(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_user_data_set(&timer, timer_object); + k_timer_start(&timer, K_TICKS(timer_object->ReloadValue), + K_TICKS(timer_object->ReloadValue)); + timer_object->IsRunning = true; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Stop(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_stop(&timer); + timer_object->IsRunning = false; + + return UTIL_TIMER_OK; +} diff --git a/soc/arm/st_stm32/stm32wba/power.c b/soc/arm/st_stm32/stm32wba/power.c index 018c27ee0b8..1565c59cfc6 100644 --- a/soc/arm/st_stm32/stm32wba/power.c +++ b/soc/arm/st_stm32/stm32wba/power.c @@ -7,20 +7,63 @@ #include #include #include +#include +#include -#include #include #include #include +#include #include #include #include +#ifdef CONFIG_BT_STM32WBA +#include "scm.h" +#endif + #include + LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); -void set_mode_stop(uint8_t substate_id) +static int stm32_power_init(void); + +static void disable_cache(void) +{ + /* Disabling ICACHE */ + LL_ICACHE_Disable(); + while (LL_ICACHE_IsEnabled() == 1U) { + } + + /* Wait until ICACHE_SR.BUSYF is cleared */ + while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) { + } + + /* Wait until ICACHE_SR.BSYENDF is set */ + while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) { + } +} + +static void set_mode_stop(uint8_t substate_id) { + + LL_PWR_ClearFlag_STOP(); + LL_RCC_ClearResetFlags(); + + /* Erratum 2.2.15: + * Disabling ICACHE is required before entering stop mode + */ + disable_cache(); + +#ifdef CONFIG_BT_STM32WBA + scm_setwaitstates(LP); +#endif + /* Set SLEEPDEEP bit of Cortex System Control Register */ + LL_LPM_EnableDeepSleep(); + + while (LL_PWR_IsActiveFlag_ACTVOS() == 0) { + } + switch (substate_id) { case 1: /* enter STOP0 mode */ LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0); @@ -34,12 +77,50 @@ void set_mode_stop(uint8_t substate_id) } } -void set_mode_standby(uint8_t substate_id) +#if defined(CONFIG_PM_S2RAM) +static int suspend_to_ram(void) +{ + LL_LPM_EnableDeepSleep(); + + while (LL_PWR_IsActiveFlag_ACTVOS() == 0) { + } + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + + return 0; +} + +static void set_mode_suspend_to_ram(void) { - ARG_UNUSED(substate_id); + /* Enable SRAM full retention */ + LL_PWR_SetSRAM1SBRetention(LL_PWR_SRAM1_SB_FULL_RETENTION); + LL_PWR_SetSRAM2SBRetention(LL_PWR_SRAM2_SB_FULL_RETENTION); + + /* Enable RTC wakeup + * This configures an internal pin that generates an event to wakeup the system + */ + LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN7); + LL_PWR_SetWakeUpPinSignal3Selection(LL_PWR_WAKEUP_PIN7); + + /* Clear flags */ + LL_PWR_ClearFlag_SB(); + LL_PWR_ClearFlag_WU(); + LL_RCC_ClearResetFlags(); + + disable_cache(); + /* Select standby mode */ LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + + /* Save context and enter Standby mode */ + arch_pm_s2ram_suspend(suspend_to_ram); + + /* Execution is restored at this point after wake up */ + /* Restore system clock as soon as we exit standby mode */ + sys_clock_idle_exit(); } +#endif /* Invoke Low Power/System Off specific Tasks */ void pm_state_set(enum pm_state state, uint8_t substate_id) @@ -47,39 +128,63 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) switch (state) { case PM_STATE_SUSPEND_TO_IDLE: set_mode_stop(substate_id); + + /* Select mode entry : WFE or WFI and enter the CPU selected mode */ + k_cpu_idle(); + break; - case PM_STATE_STANDBY: - /* To be tested */ - set_mode_standby(substate_id); +#if defined(CONFIG_PM_S2RAM) + case PM_STATE_SUSPEND_TO_RAM: + set_mode_suspend_to_ram(); break; +#endif default: LOG_DBG("Unsupported power state %u", state); return; } - - /* Set SLEEPDEEP bit of Cortex System Control Register */ - LL_LPM_EnableDeepSleep(); - - /* Select mode entry : WFE or WFI and enter the CPU selected mode */ - k_cpu_idle(); } /* Handle SOC specific activity after Low Power Mode Exit */ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { +#ifdef CONFIG_BT_STM32WBA + if (LL_PWR_IsActiveFlag_STOP() == 1U) { + scm_setup(); + } else { + scm_setwaitstates(RUN); + } +#endif + switch (state) { case PM_STATE_SUSPEND_TO_IDLE: if (substate_id <= 2) { + /* Erratum 2.2.15: + * Enable ICACHE when exiting stop mode + */ + LL_ICACHE_SetMode(LL_ICACHE_1WAY); + LL_ICACHE_Enable(); + while (LL_ICACHE_IsEnabled() == 0U) { + } + LL_LPM_DisableSleepOnExit(); LL_LPM_EnableSleep(); } else { LOG_DBG("Unsupported power substate-id %u", substate_id); } - case PM_STATE_STANDBY: - /* To be tested */ - LL_LPM_EnableSleep(); + break; case PM_STATE_SUSPEND_TO_RAM: +#if defined(CONFIG_PM_S2RAM) + stm32wba_init(); + stm32_power_init(); + + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); +#else + LOG_DBG("Suspend to RAM needs CONFIG_PM_S2RAM to be enabled"); +#endif + break; + case PM_STATE_STANDBY: __fallthrough; case PM_STATE_SUSPEND_TO_DISK: __fallthrough; @@ -87,8 +192,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) LOG_DBG("Unsupported power state %u", state); break; } - /* need to restore the clock */ + + /* When BLE is enabled, clock restoration is performed by SCM */ +#if !defined(CONFIG_BT_STM32WBA) stm32_clock_control_init(NULL); +#endif /* * System is now in active mode. @@ -101,9 +209,26 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) /* Initialize STM32 Power */ static int stm32_power_init(void) { - /* enable Power clock */ + +#ifdef CONFIG_BT_STM32WBA + scm_init(); +#endif + LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); +#ifdef CONFIG_DEBUG + LL_DBGMCU_EnableDBGStandbyMode(); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_RTC_STOP); + LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_LPTIM1_STOP); +#else + LL_DBGMCU_DisableDBGStandbyMode(); +#endif + + /* Enabling Ultra Low power mode */ + LL_PWR_EnableUltraLowPowerMode(); + + LL_FLASH_EnableSleepPowerDown(); + return 0; } diff --git a/soc/arm/st_stm32/stm32wba/soc.c b/soc/arm/st_stm32/stm32wba/soc.c index 9d027af604f..c3f12078e8d 100644 --- a/soc/arm/st_stm32/stm32wba/soc.c +++ b/soc/arm/st_stm32/stm32wba/soc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ LOG_MODULE_REGISTER(soc); * * @return 0 */ -static int stm32wba_init(void) +int stm32wba_init(void) { /* Enable instruction cache in 1-way (direct mapped cache) */ LL_ICACHE_SetMode(LL_ICACHE_1WAY); @@ -44,6 +45,12 @@ static int stm32wba_init(void) /* Enable PWR */ LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR); +#if defined(CONFIG_POWER_SUPPLY_DIRECT_SMPS) + LL_PWR_SetRegulatorSupply(LL_PWR_SMPS_SUPPLY); +#elif defined(CONFIG_POWER_SUPPLY_LDO) + LL_PWR_SetRegulatorSupply(LL_PWR_LDO_SUPPLY); +#endif + return 0; } diff --git a/soc/arm/st_stm32/stm32wba/soc.h b/soc/arm/st_stm32/stm32wba/soc.h index ef41f7adf8a..0c337ea9e22 100644 --- a/soc/arm/st_stm32/stm32wba/soc.h +++ b/soc/arm/st_stm32/stm32wba/soc.h @@ -17,6 +17,9 @@ #include +/* function exported to the soc power.c */ +int stm32wba_init(void); + #endif /* !_ASMLANGUAGE */ #endif /* _STM32WBA_SOC_H_ */ diff --git a/soc/arm/ti_k3/am62x_m4/soc.h b/soc/arm/ti_k3/am62x_m4/soc.h index 01ff4b07080..2fd6537b984 100644 --- a/soc/arm/ti_k3/am62x_m4/soc.h +++ b/soc/arm/ti_k3/am62x_m4/soc.h @@ -7,6 +7,8 @@ #ifndef __SOC_H_ #define __SOC_H_ +#include + #include #endif /* __SOC_H */ diff --git a/soc/arm/ti_lm3s6965/soc.h b/soc/arm/ti_lm3s6965/soc.h index bef939013ba..3c353b1a79b 100644 --- a/soc/arm/ti_lm3s6965/soc.h +++ b/soc/arm/ti_lm3s6965/soc.h @@ -15,6 +15,7 @@ #ifndef _BOARD__H_ #define _BOARD__H_ +#include #include /* default system clock */ diff --git a/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h b/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h index a1d3504b986..fdc9214732c 100644 --- a/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h +++ b/soc/arm/ti_simplelink/cc13x2_cc26x2/soc.h @@ -7,6 +7,8 @@ #ifndef TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ #define TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ +#include + /* CMSIS required values */ typedef enum { Reset_IRQn = -15, @@ -27,4 +29,6 @@ typedef enum { #define __Vendor_SysTickConfig 0 #define __FPU_PRESENT 1 +#include + #endif /* TI_SIMPLELINK_CC13X2_CC26X2_SOC_H_ */ diff --git a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf index e082df05a80..461802f2155 100644 --- a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf +++ b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3220sf @@ -19,10 +19,6 @@ config ROM_START_OFFSET default 0x800 if XIP default 0x0 if !XIP -# Override the setting in misc/Kconfig to allow full use of SRAM: -config BOOTLOADER_SRAM_SIZE - default 0 if !XIP - if !XIP config FLASH_SIZE default 0 diff --git a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf index 86c881a40f9..37852a154a0 100644 --- a/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf +++ b/soc/arm/ti_simplelink/cc32xx/Kconfig.defconfig.cc3235sf @@ -20,10 +20,6 @@ config ROM_START_OFFSET default 0x800 if XIP default 0x0 if !XIP -# Override the setting in misc/Kconfig to allow full use of SRAM: -config BOOTLOADER_SRAM_SIZE - default 0 if !XIP - if !XIP config FLASH_SIZE default 0 diff --git a/soc/arm/ti_simplelink/cc32xx/soc.h b/soc/arm/ti_simplelink/cc32xx/soc.h index 9c841e0e4b0..e18dfce626a 100644 --- a/soc/arm/ti_simplelink/cc32xx/soc.h +++ b/soc/arm/ti_simplelink/cc32xx/soc.h @@ -7,6 +7,8 @@ #ifndef TI_SIMPLELINK_CC32XX_SOC_H_ #define TI_SIMPLELINK_CC32XX_SOC_H_ +#include + #include #include @@ -38,4 +40,6 @@ typedef enum { #define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS #define __Vendor_SysTickConfig 0 /* Default to standard SysTick */ +#include + #endif /* TI_SIMPLELINK_CC32XX_SOC_H_ */ diff --git a/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series b/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series index 6bb0043ff90..8af48672ed2 100644 --- a/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series +++ b/soc/arm/ti_simplelink/msp432p4xx/Kconfig.series @@ -11,5 +11,6 @@ config SOC_SERIES_MSP432P4XX select DYNAMIC_INTERRUPTS select SOC_FAMILY_TISIMPLELINK select CPU_HAS_FPU + select CPU_HAS_ARM_MPU help Enable support for TI SimpleLink MSP432P4XX. diff --git a/soc/arm/xilinx_zynqmp/arm_mpu_regions.c b/soc/arm/xilinx_zynqmp/arm_mpu_regions.c index 5a6f8dc6c21..a4f36402d2c 100644 --- a/soc/arm/xilinx_zynqmp/arm_mpu_regions.c +++ b/soc/arm/xilinx_zynqmp/arm_mpu_regions.c @@ -22,11 +22,12 @@ | MPU_RASR_B_Msk) \ } -#define MPUTYPE_PRIV_WBWACACHE \ +#define MPUTYPE_PRIV_WBWACACHE_XN \ { \ .rasr = (P_RW_U_NA_Msk \ | (5 << MPU_RASR_TEX_Pos) \ - | MPU_RASR_B_Msk) \ + | MPU_RASR_B_Msk \ + | MPU_RASR_XN_Msk) \ } #define MPUTYPE_PRIV_DEVICE \ @@ -45,7 +46,7 @@ static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("SRAM_PRIV", 0x00000000, REGION_2G, - MPUTYPE_PRIV_WBWACACHE), + MPUTYPE_PRIV_WBWACACHE_XN), MPU_REGION_ENTRY("SRAM", 0x00000000, diff --git a/soc/arm/xilinx_zynqmp/pinctrl_soc.h b/soc/arm/xilinx_zynqmp/pinctrl_soc.h new file mode 100644 index 00000000000..90b6d2acac3 --- /dev/null +++ b/soc/arm/xilinx_zynqmp/pinctrl_soc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_ARM_XLNX_ZYNQMP_SOC_PINCTRL_H_ +#define ZEPHYR_SOC_ARM_XLNX_ZYNQMP_SOC_PINCTRL_H_ + +#include +#include +#include + +#define MIO_L0_SEL BIT(1) +#define MIO_L1_SEL BIT(2) +#define MIO_L2_SEL GENMASK(4, 3) +#define MIO_L3_SEL GENMASK(7, 5) + +/* All other selectors should be zeroed and FIELD_PREP does that */ +#define UARTX_SEL FIELD_PREP(MIO_L3_SEL, 6) + +/* + * Each peripheral PINCTRL mask is defined as such: + * [7 ... 0] MIO register number + * [15 ... 8] Function, mapped as: + * 1 - UART + * + * The function numbers serve as an enumerator in the pinctrl driver + * and the defines controling those are listed in `pinctrl-zynqmp.h`. + * Currently, one function for UART is specified and subsequent ones + * can be added when the need arises. + */ + +typedef struct pinctrl_soc_pin_t { + uint32_t pin; + uint32_t func; +} pinctrl_soc_pin_t; + + +#define ZYNQMP_GET_PIN(pinctrl) (pinctrl & 0xff) +#define ZYNQMP_GET_FUNC(pinctrl) ((pinctrl >> 8) & 0xff) + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + { \ + .pin = ZYNQMP_GET_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ + .func = ZYNQMP_GET_FUNC(DT_PROP_BY_IDX(node_id, prop, idx)), \ + }, + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) { \ + DT_FOREACH_CHILD_VARGS(DT_PHANDLE(node_id, prop), \ + DT_FOREACH_PROP_ELEM, pinmux, \ + Z_PINCTRL_STATE_PIN_INIT)} + +#endif diff --git a/soc/arm64/intel_socfpga/common/socfpga_system_manager.h b/soc/arm64/intel_socfpga/common/socfpga_system_manager.h index 4e56ee5af4f..58f9e0d2c56 100644 --- a/soc/arm64/intel_socfpga/common/socfpga_system_manager.h +++ b/soc/arm64/intel_socfpga/common/socfpga_system_manager.h @@ -8,7 +8,7 @@ #define SOCFPGA_SYSTEMMANAGER_H /* System Manager Register Map */ -#define SOCFPGA_SYSMGR_REG_BASE 0xffd12000 +#define SOCFPGA_SYSMGR_REG_BASE DT_REG_ADDR(DT_NODELABEL(sysmgr)) #define SOCFPGA_SYSMGR_SDMMC 0x28 diff --git a/soc/arm64/nxp_imx/mimx8m/mmu_regions.c b/soc/arm64/nxp_imx/mimx8m/mmu_regions.c index 4add4386ef5..e6dd90ecc28 100644 --- a/soc/arm64/nxp_imx/mimx8m/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx8m/mmu_regions.c @@ -25,25 +25,18 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(ccm)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART2", - DT_REG_ADDR(DT_NODELABEL(uart2)), - DT_REG_SIZE(DT_NODELABEL(uart2)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("ANA_PLL", DT_REG_ADDR(DT_NODELABEL(ana_pll)), DT_REG_SIZE(DT_NODELABEL(ana_pll)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART4", - DT_REG_ADDR(DT_NODELABEL(uart4)), - DT_REG_SIZE(DT_NODELABEL(uart4)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("IOMUXC", DT_REG_ADDR(DT_NODELABEL(iomuxc)), DT_REG_SIZE(DT_NODELABEL(iomuxc)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + + MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_imx_iuart, + (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) }; const struct arm_mmu_config mmu_config = { diff --git a/soc/arm64/nxp_imx/mimx9/mmu_regions.c b/soc/arm64/nxp_imx/mimx9/mmu_regions.c index 6dd767c2c9c..4305d8ff7e2 100644 --- a/soc/arm64/nxp_imx/mimx9/mmu_regions.c +++ b/soc/arm64/nxp_imx/mimx9/mmu_regions.c @@ -30,42 +30,20 @@ static const struct arm_mmu_region mmu_regions[] = { DT_REG_SIZE(DT_NODELABEL(ana_pll)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("UART1", - DT_REG_ADDR(DT_NODELABEL(lpuart1)), - DT_REG_SIZE(DT_NODELABEL(lpuart1)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("UART2", - DT_REG_ADDR(DT_NODELABEL(lpuart2)), - DT_REG_SIZE(DT_NODELABEL(lpuart2)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("IOMUXC", DT_REG_ADDR(DT_NODELABEL(iomuxc)), DT_REG_SIZE(DT_NODELABEL(iomuxc)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), + MMU_REGION_DT_COMPAT_FOREACH_FLAT_ENTRY(nxp_kinetis_lpuart, + (MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS)) + #if CONFIG_SOF MMU_REGION_FLAT_ENTRY("MU2_A", DT_REG_ADDR(DT_NODELABEL(mu2_a)), DT_REG_SIZE(DT_NODELABEL(mu2_a)), MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("SAI3", - DT_REG_ADDR(DT_NODELABEL(sai3)), - DT_REG_SIZE(DT_NODELABEL(sai3)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("EDMA2_CH0", - DT_REG_ADDR(DT_NODELABEL(edma2_ch0)), - DT_REG_SIZE(DT_NODELABEL(edma2_ch0)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - - MMU_REGION_FLAT_ENTRY("EDMA2_CH1", - DT_REG_ADDR(DT_NODELABEL(edma2_ch1)), - DT_REG_SIZE(DT_NODELABEL(edma2_ch1)), - MT_DEVICE_nGnRnE | MT_P_RW_U_NA | MT_NS), - MMU_REGION_FLAT_ENTRY("OUTBOX", DT_REG_ADDR(DT_NODELABEL(outbox)), DT_REG_SIZE(DT_NODELABEL(outbox)), diff --git a/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h b/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h index c3c66d532ec..bd9496ec582 100644 --- a/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h +++ b/soc/arm64/nxp_imx/mimx9/pinctrl_soc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, NXP + * Copyright (c) 2022-2023, NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,7 +19,6 @@ extern "C" { #define MCUX_IMX_DRIVE_OPEN_DRAIN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_OD_SHIFT #define MCUX_IMX_BIAS_PULL_DOWN_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PD_SHIFT #define MCUX_IMX_BIAS_PULL_UP_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PU_SHIFT -#define MCUX_IMX_BIAS_PULL_ENABLE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_PE_SHIFT #define MCUX_IMX_SLEW_RATE_SHIFT IOMUXC1_SW_PAD_CTL_PAD_FSEL1_SHIFT #define MCUX_IMX_DRIVE_STRENGTH_SHIFT IOMUXC1_SW_PAD_CTL_PAD_DSE_SHIFT #define MCUX_IMX_INPUT_ENABLE_SHIFT 23 /* Shift to a bit not used by IOMUXC_SW_PAD_CTL */ diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c index c59be6cfe6f..2d5c02316ef 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77951.c @@ -536,3 +536,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c index c130dd510a8..b219e626e44 100644 --- a/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c +++ b/soc/arm64/renesas_rcar/gen3/pfc_r8a77961.c @@ -144,3 +144,10 @@ const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void) { return pfc_drive_regs; } + +int pfc_rcar_get_reg_index(uint8_t pin, uint8_t *reg_index) +{ + /* There is only one register on Gen 3 */ + *reg_index = 0; + return 0; +} diff --git a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h index 92f7aa507a4..0b80eb46634 100644 --- a/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h +++ b/soc/arm64/renesas_rcar/gen3/pinctrl_soc.h @@ -37,6 +37,7 @@ typedef struct pinctrl_soc_pin { struct rcar_pin_func func; uint8_t flags; uint8_t drive_strength; + uint8_t voltage; } pinctrl_soc_pin_t; #define RCAR_IPSR(node_id) DT_PROP_BY_IDX(node_id, pin, 1) @@ -65,6 +66,10 @@ typedef struct pinctrl_soc_pin { .drive_strength = \ COND_CODE_1(DT_NODE_HAS_PROP(node_id, drive_strength), \ (DT_PROP(node_id, drive_strength)), (0)), \ + .voltage = COND_CODE_1(DT_NODE_HAS_PROP(node_id, \ + power_source), \ + (DT_PROP(node_id, power_source)), \ + (PIN_VOLTAGE_NONE)), \ }, /** @@ -103,9 +108,6 @@ struct pfc_bias_reg { const uint16_t pins[32]; }; -const struct pfc_bias_reg *pfc_rcar_get_bias_regs(void); -const struct pfc_drive_reg *pfc_rcar_get_drive_regs(void); - /** * @brief Utility macro to check if a pin is GPIO capable * diff --git a/soc/common/CMakeLists.txt b/soc/common/CMakeLists.txt new file mode 100644 index 00000000000..d9abad218cd --- /dev/null +++ b/soc/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_SOC_FAMILY_NRF nordic_nrf) diff --git a/soc/common/nordic_nrf/CMakeLists.txt b/soc/common/nordic_nrf/CMakeLists.txt new file mode 100644 index 00000000000..6f397a07fab --- /dev/null +++ b/soc/common/nordic_nrf/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/common/nordic_nrf/Kconfig.peripherals similarity index 80% rename from soc/arm/nordic_nrf/Kconfig.peripherals rename to soc/common/nordic_nrf/Kconfig.peripherals index 2b7791bf5e6..b8b1198ca02 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/common/nordic_nrf/Kconfig.peripherals @@ -71,8 +71,23 @@ config HAS_HW_NRF_GPIO0 config HAS_HW_NRF_GPIO1 def_bool $(dt_nodelabel_enabled_with_compat,gpio1,$(DT_COMPAT_NORDIC_NRF_GPIO)) -config HAS_HW_NRF_GPIOTE - def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) +config HAS_HW_NRF_GPIOTE0 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote0,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE1 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote1,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE20 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote20,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE30 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote30,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE130 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote130,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) + +config HAS_HW_NRF_GPIOTE131 + def_bool $(dt_nodelabel_enabled_with_compat,gpiote131,$(DT_COMPAT_NORDIC_NRF_GPIOTE)) config HAS_HW_NRF_I2S0 def_bool $(dt_nodelabel_enabled_with_compat,i2s0,$(DT_COMPAT_NORDIC_NRF_I2S)) @@ -305,6 +320,27 @@ config HAS_HW_NRF_TIMER3 config HAS_HW_NRF_TIMER4 def_bool $(dt_nodelabel_enabled_with_compat,timer4,$(DT_COMPAT_NORDIC_NRF_TIMER)) +config HAS_HW_NRF_TIMER00 + def_bool $(dt_nodelabel_enabled_with_compat,timer00,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER10 + def_bool $(dt_nodelabel_enabled_with_compat,timer10,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER20 + def_bool $(dt_nodelabel_enabled_with_compat,timer20,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER21 + def_bool $(dt_nodelabel_enabled_with_compat,timer21,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER22 + def_bool $(dt_nodelabel_enabled_with_compat,timer22,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER23 + def_bool $(dt_nodelabel_enabled_with_compat,timer23,$(DT_COMPAT_NORDIC_NRF_TIMER)) + +config HAS_HW_NRF_TIMER24 + def_bool $(dt_nodelabel_enabled_with_compat,timer24,$(DT_COMPAT_NORDIC_NRF_TIMER)) + config HAS_HW_NRF_TWI0 def_bool $(dt_nodelabel_enabled_with_compat,i2c0,$(DT_COMPAT_NORDIC_NRF_TWI)) @@ -389,6 +425,48 @@ config HAS_HW_NRF_UARTE2 config HAS_HW_NRF_UARTE3 def_bool $(dt_nodelabel_enabled_with_compat,uart3,$(DT_COMPAT_NORDIC_NRF_UARTE)) +config HAS_HW_NRF_UARTE00 + def_bool $(dt_nodelabel_enabled_with_compat,uart00,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE20 + def_bool $(dt_nodelabel_enabled_with_compat,uart20,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE21 + def_bool $(dt_nodelabel_enabled_with_compat,uart21,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE22 + def_bool $(dt_nodelabel_enabled_with_compat,uart22,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE30 + def_bool $(dt_nodelabel_enabled_with_compat,uart30,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE120 + def_bool $(dt_nodelabel_enabled_with_compat,uart120,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE130 + def_bool $(dt_nodelabel_enabled_with_compat,uart130,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE131 + def_bool $(dt_nodelabel_enabled_with_compat,uart131,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE132 + def_bool $(dt_nodelabel_enabled_with_compat,uart132,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE133 + def_bool $(dt_nodelabel_enabled_with_compat,uart133,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE134 + def_bool $(dt_nodelabel_enabled_with_compat,uart134,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE135 + def_bool $(dt_nodelabel_enabled_with_compat,uart135,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE136 + def_bool $(dt_nodelabel_enabled_with_compat,uart136,$(DT_COMPAT_NORDIC_NRF_UARTE)) + +config HAS_HW_NRF_UARTE137 + def_bool $(dt_nodelabel_enabled_with_compat,uart137,$(DT_COMPAT_NORDIC_NRF_UARTE)) + config HAS_HW_NRF_USBD def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_USBD)) @@ -403,3 +481,12 @@ config HAS_HW_NRF_WDT0 config HAS_HW_NRF_WDT1 def_bool $(dt_nodelabel_enabled_with_compat,wdt1,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT30 + def_bool $(dt_nodelabel_enabled_with_compat,wdt30,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT31 + def_bool $(dt_nodelabel_enabled_with_compat,wdt31,$(DT_COMPAT_NORDIC_NRF_WDT)) + +config HAS_HW_NRF_WDT130 + def_bool $(dt_nodelabel_enabled_with_compat,wdt130,$(DT_COMPAT_NORDIC_NRF_WDT)) diff --git a/soc/arm/nordic_nrf/common/pinctrl_soc.h b/soc/common/nordic_nrf/pinctrl_soc.h similarity index 100% rename from soc/arm/nordic_nrf/common/pinctrl_soc.h rename to soc/common/nordic_nrf/pinctrl_soc.h diff --git a/soc/posix/inf_clock/Kconfig b/soc/posix/inf_clock/Kconfig index 9e5f5ccc89f..27a5d511ec5 100644 --- a/soc/posix/inf_clock/Kconfig +++ b/soc/posix/inf_clock/Kconfig @@ -35,7 +35,7 @@ config NATIVE_SIMULATOR_EXTRA_IMAGE_PATHS help This option can be used to provide the native simulator with other MCUs/Cores images which have been produced by either other Zephyr builds or different OS builds. - So you can, for ex., use this application build produce one core image, and at the same time + So you can, for ex., use this application build to produce one core image, and at the same time have it produce the final link with the native simulator runner and the other MCU images. config NATIVE_SIMULATOR_AUTOSTART_MCU diff --git a/soc/posix/inf_clock/posix_board_if.h b/soc/posix/inf_clock/posix_board_if.h index 1d851fb3935..49384530e14 100644 --- a/soc/posix/inf_clock/posix_board_if.h +++ b/soc/posix/inf_clock/posix_board_if.h @@ -7,6 +7,7 @@ #define _POSIX_CORE_BOARD_PROVIDED_IF_H #include +#include /* * This file lists the functions the posix "inf_clock" soc @@ -22,7 +23,7 @@ extern "C" { #endif void posix_irq_handler(void); -void posix_exit(int exit_code); +FUNC_NORETURN void posix_exit(int exit_code); uint64_t posix_get_hw_cycle(void); void posix_cpu_hold(uint32_t usec_to_waste); diff --git a/soc/posix/inf_clock/posix_native_task.h b/soc/posix/inf_clock/posix_native_task.h index cb6fded1ccd..3cb5e310ee1 100644 --- a/soc/posix/inf_clock/posix_native_task.h +++ b/soc/posix/inf_clock/posix_native_task.h @@ -16,8 +16,8 @@ extern "C" { /** * NATIVE_TASK * - * For native_posix, register a function to be called at particular moments - * during the native_posix execution. + * For native targets (POSIX arch based), register a function to be called at particular moments + * during the native target execution. * * There is 5 choices for when the function will be called (level): * * PRE_BOOT_1: Will be called before the command line parameters are parsed, diff --git a/soc/riscv/CMakeLists.txt b/soc/riscv/CMakeLists.txt index b826da926ca..79d115704b2 100644 --- a/soc/riscv/CMakeLists.txt +++ b/soc/riscv/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +add_subdirectory(common) + if(SOC_FAMILY) add_subdirectory(${SOC_FAMILY}) else() diff --git a/soc/riscv/andes_v5/CMakeLists.txt b/soc/riscv/andes_v5/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/andes_v5/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/andes_v5/Kconfig b/soc/riscv/andes_v5/Kconfig new file mode 100644 index 00000000000..f3c78ab7f81 --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ANDES_V5 + bool + +if SOC_FAMILY_ANDES_V5 + +config SOC_FAMILY + string + default "andes_v5" + +source "soc/riscv/andes_v5/*/Kconfig.soc" + +endif # SOC_FAMILY_ANDES_V5 diff --git a/soc/riscv/andes_v5/Kconfig.defconfig b/soc/riscv/andes_v5/Kconfig.defconfig new file mode 100644 index 00000000000..6213f28d2cb --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/andes_v5/*/Kconfig.defconfig.series" diff --git a/soc/riscv/andes_v5/Kconfig.soc b/soc/riscv/andes_v5/Kconfig.soc new file mode 100644 index 00000000000..9efb4781934 --- /dev/null +++ b/soc/riscv/andes_v5/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/andes_v5/*/Kconfig.series" diff --git a/soc/riscv/andes_v5/ae350/CMakeLists.txt b/soc/riscv/andes_v5/ae350/CMakeLists.txt new file mode 100644 index 00000000000..b8eac026dfb --- /dev/null +++ b/soc/riscv/andes_v5/ae350/CMakeLists.txt @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources( + start.S + soc_irq.S +) + +zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_PMA pma.c) +zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_L2C l2_cache.c) +zephyr_linker_sources(ROM_START SORT_KEY 0x0 common_linker/init.ld) +zephyr_linker_sources_ifdef(CONFIG_SOC_ANDES_V5_EXECIT RODATA SORT_KEY 0x0 common_linker/execit.ld) +zephyr_linker_sources_ifdef(CONFIG_XIP RAM_SECTIONS SORT_KEY 0x0 common_linker/ram_start_nonzero.ld) + +# Note: AndeStar V5 DSP needs custom Andes V5 toolchain +if(CONFIG_SOC_ANDES_V5_HWDSP) + zephyr_cc_option(-mext-dsp) +endif() + +# Note: AndeStar V5 EXEC.IT needs custom Andes V5 toolchain +if(CONFIG_SOC_ANDES_V5_EXECIT) + zephyr_cc_option(-mexecit) + zephyr_ld_options(-Wl,--mexecit) +endif() + +if(CONFIG_SOC_ANDES_AE350) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") +endif() diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 similarity index 88% rename from soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 rename to soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 index 5d652057a38..fee73684b71 100644 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae350 +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae350 @@ -1,7 +1,7 @@ # Copyright (c) 2021 Andes Technology Corporation # SPDX-License-Identifier: Apache-2.0 -if SOC_RISCV_ANDES_AE350 +if SOC_ANDES_AE350 config SOC default "ae350" @@ -25,4 +25,4 @@ config MP_MAX_NUM_CPUS default 1 range 1 8 -endif # SOC_RISCV_ANDES_AE350 +endif # SOC_ANDES_AE350 diff --git a/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series new file mode 100644 index 00000000000..7b9bbc3eadb --- /dev/null +++ b/soc/riscv/andes_v5/ae350/Kconfig.defconfig.series @@ -0,0 +1,42 @@ +# Copyright (c) 2021 Andes Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_ANDES_AE350 + +# Kconfig picks the first default with a satisfied condition. +# SoC defaults should be parsed before SoC Series defaults, because SoCs usually +# overrides SoC Series values. +source "soc/riscv/andes_v5/ae350/Kconfig.defconfig.ae*" + +config SOC_SERIES + default "ae350" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 60000000 + +config KERNEL_ENTRY + default "entry" + +config RISCV_GENERIC_TOOLCHAIN + default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" + default n + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +endif # SOC_SERIES_ANDES_AE350 diff --git a/soc/riscv/andes_v5/ae350/Kconfig.series b/soc/riscv/andes_v5/ae350/Kconfig.series new file mode 100644 index 00000000000..c2e9b40bfb7 --- /dev/null +++ b/soc/riscv/andes_v5/ae350/Kconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Andes Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ANDES_AE350 + bool "Andes V5 AE350 SoC Series Implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + select SOC_FAMILY_ANDES_V5 + help + Enable support for Andes V5 AE350 SoC Series diff --git a/soc/riscv/andes_v5/ae350/Kconfig.soc b/soc/riscv/andes_v5/ae350/Kconfig.soc new file mode 100644 index 00000000000..1731cc08f51 --- /dev/null +++ b/soc/riscv/andes_v5/ae350/Kconfig.soc @@ -0,0 +1,124 @@ +# Copyright (c) 2021 Andes Technology Corporation +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "Andes V5 SoC Selection" +depends on SOC_SERIES_ANDES_AE350 + +config SOC_ANDES_AE350 + bool "Andes AE350 SoC implementation" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE + select RISCV_PMP + +endchoice + +if SOC_SERIES_ANDES_AE350 + +choice +prompt "Base CPU ISA options" +default RV32I_CPU + +config RV32I_CPU + bool "RISCV32 CPU ISA" + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +config RV32E_CPU + bool "RISCV32E CPU ISA" + select RISCV_ISA_RV32E + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +config RV64I_CPU + bool "RISCV64 CPU ISA" + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select 64BIT + +endchoice + +choice +prompt "FPU options" +default NO_FPU + +config NO_FPU + bool "No FPU" + +config SINGLE_PRECISION_FPU + bool "Single precision FPU" + select CPU_HAS_FPU + +config DOUBLE_PRECISION_FPU + bool "Double precision FPU" + select CPU_HAS_FPU_DOUBLE_PRECISION + +endchoice + +config SOC_ANDES_V5_HWDSP + bool "AndeStar V5 DSP ISA" + select RISCV_SOC_CONTEXT_SAVE + depends on !RISCV_GENERIC_TOOLCHAIN + help + This option enables the AndeStar v5 hardware DSP, in order to + support using the DSP instructions. + +config SOC_ANDES_V5_PFT + bool "Andes V5 PowerBrake extension" + default y + select RISCV_SOC_CONTEXT_SAVE + help + The PowerBrake extension throttles performance by reducing instruction + executing rate. + +config SOC_ANDES_V5_EXECIT + bool "Andes V5 EXEC.IT extension" + depends on RISCV_ISA_EXT_C + depends on !RISCV_GENERIC_TOOLCHAIN + depends on !LINKER_USE_NO_RELAX + help + The EXEC.IT extension (Execution on Instruction Table) generate + a look-up table and replaces suitable 32-bit instructions with + the 16-bit "exec.it ". + +config SOC_ANDES_V5_PMA + bool "Andes V5 Physical Memory Attribute (PMA)" + select ARCH_HAS_NOCACHE_MEMORY_SUPPORT + help + This option enables the Andes V5 PMA, in order to support SW to + configure physical memory attribute by PMA CSRs. The address + matching of Andes V5 PMA is like RISC-V PMP NAPOT mode + (power-of-two alignment). + +config SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE + int + depends on SOC_ANDES_V5_PMA + default 4096 + help + Minimum size (and alignment) of an PMA region. Use this symbol + to guarantee minimum size and alignment of PMA regions. + +# Workaround for not being able to have commas in macro arguments +DT_ANDESTECH_L2C := andestech,l2c + +config SOC_ANDES_V5_L2C + bool + default $(dt_compat_enabled,$(DT_ANDESTECH_L2C)) + +config SOC_ANDES_V5_IOCP + bool "Andes V5 I/O Coherence Port (IOCP)" + depends on SOC_ANDES_V5_L2C + depends on DCACHE + help + Support Andes V5 I/O Coherence Port to handle cache coherency + between cache and external non-caching master, such as DMA + controller. + +endif # SOC_SERIES_ANDES_AE350 diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld b/soc/riscv/andes_v5/ae350/common_linker/execit.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/execit.ld rename to soc/riscv/andes_v5/ae350/common_linker/execit.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld b/soc/riscv/andes_v5/ae350/common_linker/init.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/init.ld rename to soc/riscv/andes_v5/ae350/common_linker/init.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld b/soc/riscv/andes_v5/ae350/common_linker/ram_start_nonzero.ld similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/common_linker/ram_start_nonzero.ld rename to soc/riscv/andes_v5/ae350/common_linker/ram_start_nonzero.ld diff --git a/soc/riscv/riscv-privileged/andes_v5/l2_cache.c b/soc/riscv/andes_v5/ae350/l2_cache.c similarity index 99% rename from soc/riscv/riscv-privileged/andes_v5/l2_cache.c rename to soc/riscv/andes_v5/ae350/l2_cache.c index 69e8d00b947..83a048ca896 100644 --- a/soc/riscv/riscv-privileged/andes_v5/l2_cache.c +++ b/soc/riscv/andes_v5/ae350/l2_cache.c @@ -10,6 +10,8 @@ * @brief Andes V5 L2 Cache Controller driver */ +#include "soc_v5.h" + #include #include #include diff --git a/soc/riscv/andes_v5/ae350/linker.ld b/soc/riscv/andes_v5/ae350/linker.ld new file mode 100644 index 00000000000..041d0aad530 --- /dev/null +++ b/soc/riscv/andes_v5/ae350/linker.ld @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2016-2017 Jean-Paul Etienne + * Copyright (c) 2021 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the ae350 platform + */ + +#include + +#include +#include + +#include +#include + +#ifdef CONFIG_XIP +#define ROMABLE_REGION ROM +#else +#define ROMABLE_REGION RAM +#endif +#define RAMABLE_REGION RAM + +#define _EXCEPTION_SECTION_NAME exceptions +#define _RESET_SECTION_NAME reset + +#ifdef CONFIG_XIP +#if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) +#ifdef CONFIG_FLASH_LOAD_OFFSET +#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + \ + CONFIG_FLASH_LOAD_OFFSET) +#else /* !CONFIG_FLASH_LOAD_OFFSET */ +#define ROM_BASE DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) +#endif /* CONFIG_FLASH_LOAD_OFFSET */ +#define ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) +#elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), jedec_spi_nor) +/* For jedec,spi-nor we expect the spi controller to memory map the flash + * and for that mapping to be the second register property of the spi + * controller. + */ +#define SPI_CTRL DT_PARENT(DT_CHOSEN(zephyr_flash)) +#define ROM_BASE DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) +#define ROM_SIZE DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) +#endif +#else /* CONFIG_XIP */ +#define ROM_BASE CONFIG_SRAM_BASE_ADDRESS +#define ROM_SIZE KB(CONFIG_SRAM_SIZE) +#endif /* CONFIG_XIP */ + +#define RAM_BASE CONFIG_SRAM_BASE_ADDRESS +#define RAM_SIZE KB(CONFIG_SRAM_SIZE) + +#ifdef CONFIG_RISCV_PMP + #define MPU_MIN_SIZE CONFIG_PMP_GRANULARITY + #define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE); + #if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) + #define MPU_ALIGN(region_size) \ + . = ALIGN(MPU_MIN_SIZE); \ + . = ALIGN( 1 << LOG2CEIL(region_size)) + #else + #define MPU_ALIGN(region_size) \ + . = ALIGN(MPU_MIN_SIZE) + #endif +#else + #define MPU_MIN_SIZE_ALIGN + #define MPU_ALIGN(region_size) . = ALIGN(4) +#endif + +MEMORY +{ +#ifdef CONFIG_XIP + ROM (rx) : ORIGIN = ROM_BASE, LENGTH = ROM_SIZE +#endif + RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_SIZE + + LINKER_DT_REGIONS() + + /* Used by and documented in include/linker/intlist.ld */ + IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K +} + +ENTRY(CONFIG_KERNEL_ENTRY) + +SECTIONS + { + +#include + + /* + * The .plt and .iplt are here according to + * 'riscv32-zephyr-elf-ld --verbose', before text section. + */ + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + GROUP_START(ROMABLE_REGION) + + SECTION_PROLOGUE(rom_start,,) + { + . = ALIGN(16); + MPU_ALIGN(__rom_region_size); + __rom_region_start = .; +/* Located in generated directory. This file is populated by calling + * zephyr_linker_sources(ROM_START ...). + */ +#include + } GROUP_LINK_IN(ROMABLE_REGION) + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + SECTION_PROLOGUE(_RESET_SECTION_NAME,,) + { + KEEP(*(.reset.*)) + } GROUP_LINK_IN(ROMABLE_REGION) + + SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) + { + KEEP(*(".exception.entry.*")) + *(".exception.other.*") + } GROUP_LINK_IN(ROMABLE_REGION) + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + . = ALIGN(4); + KEEP(*(.openocd_debug)) + KEEP(*(".openocd_debug.*")) + + __text_region_start = .; + + *(.text) + *(".text.*") + *(.gnu.linkonce.t.*) +#include + } GROUP_LINK_IN(ROMABLE_REGION) + + __text_region_end = .; + + __rodata_region_start = .; +#include +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + . = ALIGN(4); + *(.srodata) + *(".srodata.*") + *(.rodata) + *(".rodata.*") + *(.gnu.linkonce.r.*) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include +#include + . = ALIGN(4); + } GROUP_LINK_IN(ROMABLE_REGION) + +#include + __rodata_region_end = .; + + /* For non-XIP system, __rom_region_end symbol should be set to + * the end of common ROMABLE_REGIONs (text and rodata) instead of + * the linker script end, so it wouldn't mistakenly contain + * RAMABLE_REGION in it. + */ +#ifndef CONFIG_XIP +#ifdef CONFIG_RISCV_PMP + SECTION_PROLOGUE(rom_mpu_padding,,) + { + MPU_ALIGN(__rodata_region_end - __rom_region_start); + } GROUP_LINK_IN(ROMABLE_REGION) +#endif /* CONFIG_RISCV_PMP */ + + __rom_region_end = .; + __rom_region_size = __rom_region_end - __rom_region_start; +#endif /* CONFIG_XIP */ + GROUP_END(ROMABLE_REGION) + + GROUP_START(RAMABLE_REGION) + + . = RAM_BASE; + _image_ram_start = .; + +#ifdef CONFIG_SOC_ANDES_V5_PMA +#pragma push_macro("MPU_ALIGN") +#undef MPU_ALIGN +/* Make linker section alignment comply with PMA granularity. */ +#define MPU_ALIGN(region_size) \ + . = ALIGN(CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE); \ + . = ALIGN( 1 << LOG2CEIL(region_size)) +#endif + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#ifdef CONFIG_SOC_ANDES_V5_PMA +#pragma pop_macro("MPU_ALIGN") +#endif + +#if defined(CONFIG_USERSPACE) +#define APP_SHARED_ALIGN MPU_MIN_SIZE_ALIGN +#define SMEM_PARTITION_ALIGN MPU_ALIGN + +#include + + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); +#endif /* CONFIG_USERSPACE */ + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + MPU_MIN_SIZE_ALIGN + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes + */ + . = ALIGN(4); + __bss_start = .; + __kernel_ram_start = .; + *(.sbss) + *(".sbss.*") + *(.bss) + *(".bss.*") + COMMON_SYMBOLS + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + /* + * As memory is cleared in words only, it is simpler to ensure the BSS + * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. + */ + __bss_end = ALIGN(4); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + +#include + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + . = ALIGN(4); + /* _image_ram_start = .; */ + __data_region_start = .; + __data_start = .; + + *(.data) + *(".data.*") + +#ifdef CONFIG_RISCV_GP + /* + * RISC-V architecture has 12-bit signed immediate offsets in the + * instructions. If we can put the most commonly accessed globals + * in a special 4K span of memory addressed by the GP register, then + * we can access those values in a single instruction, saving both + * codespace and runtime. + * + * Since these immediate offsets are signed, place gp 0x800 past the + * beginning of .sdata so that we can use both positive and negative + * offsets. + */ + . = ALIGN(8); + PROVIDE (__global_pointer$ = . + 0x800); +#endif + + *(.sdata .sdata.* .gnu.linkonce.s.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + __data_end = .; + + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + __data_size = __data_end - __data_start; + __data_load_start = LOADADDR(_DATA_SECTION_NAME); + + __data_region_load_start = LOADADDR(_DATA_SECTION_NAME); + +#include +#include +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + __data_region_end = .; + + __kernel_ram_end = .; + __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) +GROUP_START(ITCM) + + SECTION_PROLOGUE(_ITCM_SECTION_NAME,,SUBALIGN(8)) + { + __itcm_start = .; + *(.itcm) + *(".itcm.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + + __itcm_end = .; + } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) + + __itcm_size = __itcm_end - __itcm_start; + __itcm_load_start = LOADADDR(_ITCM_SECTION_NAME); + +GROUP_END(ITCM) +#endif + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) +GROUP_START(DTCM) + + SECTION_PROLOGUE(_DTCM_BSS_SECTION_NAME, (NOLOAD),SUBALIGN(8)) + { + __dtcm_start = .; + __dtcm_bss_start = .; + *(.dtcm_bss) + *(".dtcm_bss.*") + __dtcm_bss_end = .; + } GROUP_LINK_IN(DTCM) + + SECTION_PROLOGUE(_DTCM_NOINIT_SECTION_NAME, (NOLOAD),SUBALIGN(8)) + { + __dtcm_noinit_start = .; + *(.dtcm_noinit) + *(".dtcm_noinit.*") + __dtcm_noinit_end = .; + } GROUP_LINK_IN(DTCM) + + SECTION_PROLOGUE(_DTCM_DATA_SECTION_NAME,,SUBALIGN(8)) + { + __dtcm_data_start = .; + *(.dtcm_data) + *(".dtcm_data.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. */ +#include + + __dtcm_data_end = .; + } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) + + __dtcm_end = .; + + __dtcm_data_load_start = LOADADDR(_DTCM_DATA_SECTION_NAME); + +GROUP_END(DTCM) +#endif + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#define LAST_RAM_ALIGN MPU_MIN_SIZE_ALIGN + +#include + + GROUP_END(RAMABLE_REGION) + +#include + + /DISCARD/ : { *(.note.GNU-stack) } + + SECTION_PROLOGUE(.riscv.attributes, 0,) + { + KEEP(*(.riscv.attributes)) + KEEP(*(.gnu.attributes)) + } + + /* Sections generated from 'zephyr,memory-region' nodes */ + LINKER_DT_SECTIONS() + +/* Because ROMABLE_REGION != RAMABLE_REGION in XIP-system, it is valid + * to set __rom_region_end symbol at the end of linker script and + * doesn't mistakenly contain the RAMABLE_REGION in it. + */ +#ifdef CONFIG_XIP +/* Must be last in romable region */ +SECTION_PROLOGUE(.last_section,,) +{ +#ifdef CONFIG_LINKER_LAST_SECTION_ID + /* Fill last section with a word to ensure location counter and actual rom + * region data usage match. */ + LONG(CONFIG_LINKER_LAST_SECTION_ID_PATTERN) +#endif +} GROUP_LINK_IN(ROMABLE_REGION) + +#ifndef CONFIG_RISCV_PMP +/* To provide the image size as a const expression, + * calculate this value here. */ +__rom_region_end = LOADADDR(.last_section) + SIZEOF(.last_section); +#else +SECTION_PROLOGUE(rom_mpu_padding,(NOLOAD),) +{ + MPU_ALIGN(__rom_region_size); + __rom_region_end = .; +} GROUP_LINK_IN(ROMABLE_REGION) +#endif /* !CONFIG_RISCV_PMP */ +__rom_region_size = __rom_region_end - __rom_region_start; +#endif + +} diff --git a/soc/riscv/riscv-privileged/andes_v5/pma.c b/soc/riscv/andes_v5/ae350/pma.c similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/pma.c rename to soc/riscv/andes_v5/ae350/pma.c diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_context.h b/soc/riscv/andes_v5/ae350/soc_context.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_context.h rename to soc/riscv/andes_v5/ae350/soc_context.h diff --git a/soc/riscv/andes_v5/ae350/soc_irq.S b/soc/riscv/andes_v5/ae350/soc_irq.S new file mode 100644 index 00000000000..f057cd8804f --- /dev/null +++ b/soc/riscv/andes_v5/ae350/soc_irq.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc_v5.h" + +#include +#include + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + +/* Exports */ +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) + +SECTION_FUNC(exception.other, __soc_save_context) + +#ifdef CONFIG_SOC_ANDES_V5_PFT + csrr t0, NDS_MXSTATUS +#endif +#ifdef CONFIG_SOC_ANDES_V5_HWDSP + csrr t1, NDS_UCODE +#endif + +#ifdef CONFIG_SOC_ANDES_V5_PFT + sw t0, __soc_esf_t_mxstatus_OFFSET(a0) +#endif +#ifdef CONFIG_SOC_ANDES_V5_HWDSP + sw t1, __soc_esf_t_ucode_OFFSET(a0) +#endif + ret + +SECTION_FUNC(exception.other, __soc_restore_context) + +#ifdef CONFIG_SOC_ANDES_V5_PFT + lw t0, __soc_esf_t_mxstatus_OFFSET(a0) +#endif +#ifdef CONFIG_SOC_ANDES_V5_HWDSP + lw t1, __soc_esf_t_ucode_OFFSET(a0) +#endif + +#ifdef CONFIG_SOC_ANDES_V5_PFT + csrw NDS_MXSTATUS, t0 +#endif +#ifdef CONFIG_SOC_ANDES_V5_HWDSP + csrw NDS_UCODE, t1 +#endif + ret + +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_offsets.h b/soc/riscv/andes_v5/ae350/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_offsets.h rename to soc/riscv/andes_v5/ae350/soc_offsets.h diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_v5.h b/soc/riscv/andes_v5/ae350/soc_v5.h similarity index 100% rename from soc/riscv/riscv-privileged/andes_v5/soc_v5.h rename to soc/riscv/andes_v5/ae350/soc_v5.h diff --git a/soc/riscv/riscv-privileged/andes_v5/start.S b/soc/riscv/andes_v5/ae350/start.S similarity index 98% rename from soc/riscv/riscv-privileged/andes_v5/start.S rename to soc/riscv/andes_v5/ae350/start.S index 84e0d91cb91..9f0ac85caa3 100644 --- a/soc/riscv/riscv-privileged/andes_v5/start.S +++ b/soc/riscv/andes_v5/ae350/start.S @@ -4,8 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "soc_v5.h" + #include -#include /* exports */ GTEXT(entry) diff --git a/soc/riscv/common/CMakeLists.txt b/soc/riscv/common/CMakeLists.txt new file mode 100644 index 00000000000..91ef5c975b9 --- /dev/null +++ b/soc/riscv/common/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory_ifdef(CONFIG_RISCV_PRIVILEGED riscv-privileged) diff --git a/soc/riscv/common/Kconfig b/soc/riscv/common/Kconfig new file mode 100644 index 00000000000..91f2c5cf80a --- /dev/null +++ b/soc/riscv/common/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 +# +source "soc/riscv/common/riscv-privileged/Kconfig" diff --git a/soc/riscv/common/riscv-privileged/CMakeLists.txt b/soc/riscv/common/riscv-privileged/CMakeLists.txt new file mode 100644 index 00000000000..80be64cf2a9 --- /dev/null +++ b/soc/riscv/common/riscv-privileged/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_sources( + soc_irq.S + soc_common_irq.c + vector.S + ) diff --git a/soc/riscv/common/riscv-privileged/Kconfig b/soc/riscv/common/riscv-privileged/Kconfig new file mode 100644 index 00000000000..10c2e37712b --- /dev/null +++ b/soc/riscv/common/riscv-privileged/Kconfig @@ -0,0 +1,11 @@ +# Configuration options for riscv SOCs supporting the riscv privileged +# architecture specification + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config RISCV_VECTORED_MODE + bool "Should the SOC use vectored mode" + depends on RISCV_PRIVILEGED + help + Should the SOC use vectored mode. diff --git a/soc/riscv/riscv-privileged/common/soc_common_irq.c b/soc/riscv/common/riscv-privileged/soc_common_irq.c similarity index 100% rename from soc/riscv/riscv-privileged/common/soc_common_irq.c rename to soc/riscv/common/riscv-privileged/soc_common_irq.c diff --git a/soc/riscv/common/riscv-privileged/soc_irq.S b/soc/riscv/common/riscv-privileged/soc_irq.S new file mode 100644 index 00000000000..acf7e724aea --- /dev/null +++ b/soc/riscv/common/riscv-privileged/soc_irq.S @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * common interrupt management code for riscv SOCs supporting the riscv + * privileged architecture specification + */ +#include +#include +#include +#include +#include + +/* + * __soc_handle_irq is defined as .weak to allow re-implementation by + * SOCs that do not truly follow the riscv privilege specification. + */ +WTEXT(__soc_handle_irq) + +/* + * SOC-specific function to handle pending IRQ number generating the interrupt. + * Exception number is given as parameter via register a0. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + /* Clear exception number from CSR mip register */ + li t1, 1 + sll t0, t1, a0 + csrrc t1, mip, t0 + + /* Return */ + ret diff --git a/soc/riscv/common/riscv-privileged/vector.S b/soc/riscv/common/riscv-privileged/vector.S new file mode 100644 index 00000000000..bb113457874 --- /dev/null +++ b/soc/riscv/common/riscv-privileged/vector.S @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * Contributors: 2018 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* exports */ +GTEXT(__start) + +/* imports */ +GTEXT(__initialize) +GTEXT(_isr_wrapper) + +SECTION_FUNC(vectors, __start) +#if defined(CONFIG_RISCV_GP) + /* Initialize global pointer */ + .option push + .option norelax + la gp, __global_pointer$ + .option pop +#endif + + .option norvc; + +#if defined(CONFIG_RISCV_VECTORED_MODE) +#if defined(CONFIG_RISCV_HAS_CLIC) + + /* + * CLIC vectored mode + * + * CLIC vectored mode uses mtvec exclusively for exception handling and + * mtvec.base must be aligned to 64 bytes (this is done using + * CONFIG_ARCH_SW_ISR_TABLE_ALIGN) + */ + la t0, _isr_wrapper + addi t0, t0, 0x03 /* Enable CLIC vectored mode by setting LSB */ + csrw mtvec, t0 + + /* + * CLIC vectored mode has a similar concept to CLINT vectored mode, + * where an interrupt vector table is used for specific interrupts. + * However, in CLIC vectored mode, the handler table contains the + * address of the interrupt handler instead of an opcode containing a + * jump instruction, this is done by leveraging + * CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS. + * When an interrupt occurs in CLIC vectored mode, the address of the + * handler entry from the vector table is loaded and then jumped to in + * hardware. This time mtvt is used as the base address for the + * interrupt table. + */ + la t0, _irq_vector_table + csrw 0x307, t0 /* mtvt */ + +#else /* !CONFIG_RISCV_HAS_CLIC */ + + /* + * CLINT vectored mode + * + * Set mtvec (Machine Trap-Vector Base-Address Register) + * to _irq_vector_table (interrupt vector table). Add 1 to base + * address of _irq_vector_table to indicate that vectored mode + * is used (LSB = 0x1). CPU will mask the LSB out of + * the address so that base address of _irq_vector_table is used. + * + * NOTE: _irq_vector_table is 256-byte aligned. Incorrect alignment + * of _irq_vector_table breaks this code. + */ + la t0, _irq_vector_table /* Load address of interrupt vector table */ + addi t0, t0, 0x01 /* Enable vectored mode by setting LSB */ + csrw mtvec, t0 + +#endif /* CONFIG_RISCV_HAS_CLIC */ + +#else /* !CONFIG_RISCV_VECTORED_MODE */ + +#if defined(CONFIG_RISCV_HAS_CLIC) && !defined(CONFIG_LEGACY_CLIC) + + la t0, _isr_wrapper + addi t0, t0, 0x03 /* Set mode bits to 3, signifying CLIC. Everything else is reserved. */ + csrw mtvec, t0 + +#else /* !CONFIG_RISCV_HAS_CLIC || CONFIG_LEGACY_CLIC */ + + /* + * CLINT direct mode + * + * Set mtvec (Machine Trap-Vector Base-Address Register) + * to _isr_wrapper. + */ + la t0, _isr_wrapper + csrw mtvec, t0 + +#endif /* CONFIG_RISCV_HAS_CLIC&& !CONFIG_LEGACY_CLIC */ + +#endif /* CONFIG_RISCV_VECTORED_MODE */ + + /* Jump to __reset */ + tail __reset diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt b/soc/riscv/efinix_sapphire/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/efinix-sapphire/CMakeLists.txt rename to soc/riscv/efinix_sapphire/CMakeLists.txt diff --git a/soc/riscv/efinix_sapphire/Kconfig.defconfig b/soc/riscv/efinix_sapphire/Kconfig.defconfig new file mode 100644 index 00000000000..95a33b4ab82 --- /dev/null +++ b/soc/riscv/efinix_sapphire/Kconfig.defconfig @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_EFINIX_SAPPHIRE + +config SOC + default "efinix_sapphire" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +config NUM_IRQS + int + default 36 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +endif # SOC_EFINIX_SAPPHIRE diff --git a/soc/riscv/efinix_sapphire/Kconfig.soc b/soc/riscv/efinix_sapphire/Kconfig.soc new file mode 100644 index 00000000000..4bad3b5cb79 --- /dev/null +++ b/soc/riscv/efinix_sapphire/Kconfig.soc @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Efinix Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_EFINIX_SAPPHIRE + bool "Efinix Sapphire VexRiscv system implementation" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC diff --git a/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt index e97f71751ef..d6772eacbfc 100644 --- a/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt +++ b/soc/riscv/espressif_esp32/esp32c3/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_sources( - idle.c vectors.S soc_irq.S soc_irq.c diff --git a/soc/riscv/espressif_esp32/esp32c3/default.ld b/soc/riscv/espressif_esp32/esp32c3/default.ld index 0884e3d7d3a..65984b4fd7b 100644 --- a/soc/riscv/espressif_esp32/esp32c3/default.ld +++ b/soc/riscv/espressif_esp32/esp32c3/default.ld @@ -142,8 +142,8 @@ SECTIONS #include . = ALIGN(4); - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) + *(EXCLUDE_FILE (*libarch__riscv__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) + *(EXCLUDE_FILE (*libarch__riscv__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) @@ -175,18 +175,12 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.srodata) *(.srodata.*) *(.rodata) *(.rodata.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -197,6 +191,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. @@ -233,6 +228,7 @@ SECTIONS *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) *libesp32.a:panic.*(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) + *libarch__riscv__core.a:(.literal .text .literal.* .text.*) *libsubsys__net__l2__ethernet.a:(.literal .text .literal.* .text.*) *libsubsys__net__lib__config.a:(.literal .text .literal.* .text.*) *libsubsys__net__ip.a:(.literal .text .literal.* .text.*) diff --git a/soc/riscv/espressif_esp32/esp32c3/idle.c b/soc/riscv/espressif_esp32/esp32c3/idle.c deleted file mode 100644 index 1bfb2832187..00000000000 --- a/soc/riscv/espressif_esp32/esp32c3/idle.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -/** - * @brief Power save idle routine - * - * This function will be called by the kernel idle loop or possibly within - * an implementation of _pm_save_idle in the kernel when the - * '_pm_save_flag' variable is non-zero. - */ -void arch_cpu_idle(void) -{ - /* curiously it arrives here with the interrupts masked - * so umask it before wait for an event - */ - arch_irq_unlock(MSTATUS_IEN); - - /* Wait for interrupt */ - __asm__ volatile("wfi"); -} diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.c b/soc/riscv/espressif_esp32/esp32c3/soc.c index 8bb32a5febd..c125450a4d9 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.c +++ b/soc/riscv/espressif_esp32/esp32c3/soc.c @@ -30,6 +30,8 @@ #include "bootloader_init.h" #endif /* CONFIG_MCUBOOT */ +extern void esp_reset_reason_init(void); + /* * This is written in C rather than assembly since, during the port bring up, * Zephyr is being booted by the Espressif bootloader. With it, the C stack @@ -56,6 +58,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) /* Disable normal interrupts. */ csr_read_clear(mstatus, MSTATUS_MIE); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ diff --git a/soc/riscv/espressif_esp32/esp32c3/soc.h b/soc/riscv/espressif_esp32/esp32c3/soc.h index a3709819abc..68fb6fdb1ce 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc.h +++ b/soc/riscv/espressif_esp32/esp32c3/soc.h @@ -16,20 +16,6 @@ #include "esp32c3/clk.h" #endif -/* IRQ numbers */ -#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ -#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ -#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ - -/* ECALL Exception numbers */ -#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ -#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ - -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 31) -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF - #ifndef _ASMLANGUAGE void __esp_platform_start(void); diff --git a/soc/riscv/espressif_esp32/esp32c3/soc_irq.S b/soc/riscv/espressif_esp32/esp32c3/soc_irq.S index c1ad164c153..6ce11ae6a81 100644 --- a/soc/riscv/espressif_esp32/esp32c3/soc_irq.S +++ b/soc/riscv/espressif_esp32/esp32c3/soc_irq.S @@ -7,15 +7,9 @@ #include /* Exports */ -GTEXT(__soc_is_irq) GTEXT(__soc_handle_irq) GTEXT(soc_intr_get_next_source) -SECTION_FUNC(exception.other, __soc_is_irq) - csrr a0, mcause - srli a0, a0, 31 - ret - SECTION_FUNC(exception.other, __soc_handle_irq) addi sp, sp,-4 sw ra, 0x00(sp) diff --git a/soc/riscv/gd_gd32/CMakeLists.txt b/soc/riscv/gd_gd32/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/gd_gd32/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/gd_gd32/Kconfig b/soc/riscv/gd_gd32/Kconfig new file mode 100644 index 00000000000..46f2dd0b1d6 --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_GD32 + bool + +if SOC_FAMILY_GD32 + +config SOC_FAMILY + string + default "gd_gd32" + +source "soc/riscv/gd_gd32/*/Kconfig.soc" + +endif # SOC_FAMILY_GIGADEVICE_GD32 diff --git a/soc/riscv/gd_gd32/Kconfig.defconfig b/soc/riscv/gd_gd32/Kconfig.defconfig new file mode 100644 index 00000000000..2be284db7ea --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/gd_gd32/*/Kconfig.defconfig.series" diff --git a/soc/riscv/gd_gd32/Kconfig.soc b/soc/riscv/gd_gd32/Kconfig.soc new file mode 100644 index 00000000000..09d7d5d627e --- /dev/null +++ b/soc/riscv/gd_gd32/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/gd_gd32/*/Kconfig.series" diff --git a/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt b/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt new file mode 100644 index 00000000000..9fa5868a2a6 --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2021 Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(entry.S) +zephyr_sources(soc.c) + +zephyr_linker_sources(ROM_START SORT_KEY 0x0 init.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 similarity index 76% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 index 1e93f2703b2..d37b27ffbf0 100644 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103 +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103 @@ -14,21 +14,15 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC # The CPU frequency is set to the maximum value of 108MHz by default. default 27000000 -config RISCV_SOC_MCAUSE_EXCEPTION_MASK - default $(dt_node_int_prop_hex,/cpus/cpu@0,mcause-exception-mask) +config RISCV_MCAUSE_EXCEPTION_MASK + default 0xFFF config RISCV_SOC_INTERRUPT_INIT default y -config RISCV_HAS_CPU_IDLE - default y - config RISCV_GP default y -config RISCV_HAS_PLIC - default n - config NUM_IRQS default 87 if NUCLEI_ECLIC default 16 if !NUCLEI_ECLIC @@ -45,4 +39,10 @@ config RESET config CLOCK_CONTROL default y +config ARCH_IRQ_VECTOR_TABLE_ALIGN + default 512 if NUCLEI_ECLIC + +config RISCV_TRAP_HANDLER_ALIGNMENT + default 64 if NUCLEI_ECLIC && !RISCV_VECTORED_MODE + endif # GD32VF103 diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series new file mode 100644 index 00000000000..17ab7a87c39 --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.series @@ -0,0 +1,11 @@ +# Copyright (c) 2021 Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_GD32VF103 + +source "soc/riscv/gd_gd32/gd32vf103/Kconfig.defconfig.gd32vf103*" + +config SOC_SERIES + default "gd32vf103" + +endif # SOC_SERIES_GD32VF103 diff --git a/soc/riscv/gd_gd32/gd32vf103/Kconfig.series b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series new file mode 100644 index 00000000000..e50567e0798 --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/Kconfig.series @@ -0,0 +1,20 @@ +# GD32VF103 SOC implementation + +# Copyright (c) 2021 Tokita, Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_GD32VF103 + bool "GigaDevice GD32VF103 series SoC implementation" + select RISCV + select RISCV_PRIVILEGED + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select BUILD_OUTPUT_HEX + select XIP + select GD32_HAS_AFIO_PINMUX + select GD32_HAS_IRC_40K + select HAS_GD32_HAL + select RISCV_HAS_CLIC + select SOC_FAMILY_GD32 + help + Enable support for GigaDevice GD32VF1 series SoC diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc b/soc/riscv/gd_gd32/gd32vf103/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/Kconfig.soc rename to soc/riscv/gd_gd32/gd32vf103/Kconfig.soc diff --git a/soc/riscv/gd_gd32/gd32vf103/entry.S b/soc/riscv/gd_gd32/gd32vf103/entry.S new file mode 100644 index 00000000000..10e29a4ba3e --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/entry.S @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Tokita, Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nuclei_csr.h" + +#include +#include + +GTEXT(__nuclei_start) +SECTION_FUNC(init, __nuclei_start) + /* Disable Global Interrupt */ + csrc mstatus, MSTATUS_MIE + /* Jump to logical address first to ensure correct operation of RAM region */ + la a0, __nuclei_start + li a1, 1 + slli a1, a1, 29 # 0x2000 0000 + bleu a1, a0, _start0800 + srli a1, a1, 2 # 0x0800 0000 + bleu a1, a0, _start0800 + la a0, _start0800 + add a0, a0, a1 + jr a0 + +_start0800: + /* Set the the NMI base to share with mtvec by setting CSR_MMISC_CTL */ + li t0, 0x200 + csrs CSR_MMISC_CTL, t0 + + /* Disable performance counter */ + csrsi mcountinhibit, 0x5 + + /* Jump to common start */ + tail __start diff --git a/soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h b/soc/riscv/gd_gd32/gd32vf103/gd32_regs.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/gd32_regs.h rename to soc/riscv/gd_gd32/gd32vf103/gd32_regs.h diff --git a/soc/riscv/gd_gd32/gd32vf103/init.ld b/soc/riscv/gd_gd32/gd32vf103/init.ld new file mode 100644 index 00000000000..0feb828931b --- /dev/null +++ b/soc/riscv/gd_gd32/gd32vf103/init.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2023 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +KEEP(*(.init.*)) diff --git a/soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h b/soc/riscv/gd_gd32/gd32vf103/nuclei_csr.h similarity index 100% rename from soc/riscv/riscv-privileged/common/nuclei/nuclei_csr.h rename to soc/riscv/gd_gd32/gd32vf103/nuclei_csr.h diff --git a/soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h b/soc/riscv/gd_gd32/gd32vf103/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/pinctrl_soc.h rename to soc/riscv/gd_gd32/gd32vf103/pinctrl_soc.h diff --git a/soc/riscv/riscv-privileged/gd32vf103/soc.c b/soc/riscv/gd_gd32/gd32vf103/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/gd32vf103/soc.c rename to soc/riscv/gd_gd32/gd32vf103/soc.c diff --git a/soc/riscv/intel_niosv/CMakeLists.txt b/soc/riscv/intel_niosv/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/intel_niosv/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/intel_niosv/Kconfig b/soc/riscv/intel_niosv/Kconfig new file mode 100644 index 00000000000..b841d19c922 --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_INTEL_NIOSV + bool + +if SOC_FAMILY_INTEL_NIOSV + +config SOC_FAMILY + string + default "intel_niosv" + +source "soc/riscv/intel_niosv/*/Kconfig.soc" + +endif # SOC_FAMILY_INTEL_NIOSV diff --git a/soc/riscv/intel_niosv/Kconfig.defconfig b/soc/riscv/intel_niosv/Kconfig.defconfig new file mode 100644 index 00000000000..2afa0f7e0e6 --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/intel_niosv/*/Kconfig.defconfig.series" diff --git a/soc/riscv/intel_niosv/Kconfig.soc b/soc/riscv/intel_niosv/Kconfig.soc new file mode 100644 index 00000000000..8567429c61f --- /dev/null +++ b/soc/riscv/intel_niosv/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/intel_niosv/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/niosv/CMakeLists.txt b/soc/riscv/intel_niosv/niosv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/niosv/CMakeLists.txt rename to soc/riscv/intel_niosv/niosv/CMakeLists.txt diff --git a/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series new file mode 100644 index 00000000000..15e98314c89 --- /dev/null +++ b/soc/riscv/intel_niosv/niosv/Kconfig.defconfig.series @@ -0,0 +1,21 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NIOSV + +config SOC_SERIES + default "niosv" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +config NUM_IRQS # Platform interrupts IRQs index start from index 16 + default 32 + +config RISCV_GP + default y + +config RISCV_SOC_INTERRUPT_INIT + default y + +endif # SOC_NIOSV diff --git a/soc/riscv/intel_niosv/niosv/Kconfig.series b/soc/riscv/intel_niosv/niosv/Kconfig.series new file mode 100644 index 00000000000..9d7aa492692 --- /dev/null +++ b/soc/riscv/intel_niosv/niosv/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright (C) 2023, Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NIOSV + bool "INTEL FPGA NIOSV" + select RISCV + select RISCV_PRIVILEGED + select SOC_FAMILY_INTEL_NIOSV + help + Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.soc b/soc/riscv/intel_niosv/niosv/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/niosv/Kconfig.soc rename to soc/riscv/intel_niosv/niosv/Kconfig.soc diff --git a/soc/riscv/riscv-privileged/niosv/linker.ld b/soc/riscv/intel_niosv/niosv/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/niosv/linker.ld rename to soc/riscv/intel_niosv/niosv/linker.ld diff --git a/soc/riscv/riscv-ite/CMakeLists.txt b/soc/riscv/ite_ec/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/CMakeLists.txt rename to soc/riscv/ite_ec/CMakeLists.txt diff --git a/soc/riscv/ite_ec/Kconfig b/soc/riscv/ite_ec/Kconfig new file mode 100644 index 00000000000..54628029a4e --- /dev/null +++ b/soc/riscv/ite_ec/Kconfig @@ -0,0 +1,17 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_ITE_EC + bool + help + ITE Embedded Controller SoC family + +if SOC_FAMILY_ITE_EC + +config SOC_FAMILY + string + default "ite_ec" + +source "soc/riscv/ite_ec/*/Kconfig.soc" + +endif # SOC_FAMILY_ITE_EC diff --git a/soc/riscv/ite_ec/Kconfig.defconfig b/soc/riscv/ite_ec/Kconfig.defconfig new file mode 100644 index 00000000000..8994f47abd9 --- /dev/null +++ b/soc/riscv/ite_ec/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/ite_ec/*/Kconfig.defconfig.series" diff --git a/soc/riscv/ite_ec/Kconfig.soc b/soc/riscv/ite_ec/Kconfig.soc new file mode 100644 index 00000000000..13f951c0466 --- /dev/null +++ b/soc/riscv/ite_ec/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/ite_ec/*/Kconfig.series" diff --git a/soc/riscv/riscv-ite/common/CMakeLists.txt b/soc/riscv/ite_ec/common/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/common/CMakeLists.txt rename to soc/riscv/ite_ec/common/CMakeLists.txt diff --git a/soc/riscv/riscv-ite/common/check_regs.c b/soc/riscv/ite_ec/common/check_regs.c similarity index 99% rename from soc/riscv/riscv-ite/common/check_regs.c rename to soc/riscv/ite_ec/common/check_regs.c index c655f850dac..2fb6dcb4128 100644 --- a/soc/riscv/riscv-ite/common/check_regs.c +++ b/soc/riscv/ite_ec/common/check_regs.c @@ -198,7 +198,7 @@ IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSIGDAT, 0x08); IT8XXX2_REG_OFFSET_CHECK(kscan_it8xxx2_regs, KBS_KSOLGOEN, 0x0e); /* ADC register structure check */ -IT8XXX2_REG_SIZE_CHECK(adc_it8xxx2_regs, 0x6d); +IT8XXX2_REG_SIZE_CHECK(adc_it8xxx2_regs, 0xf1); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCGCR, 0x03); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, VCH0DATM, 0x19); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCIVMFSCS1, 0x55); @@ -207,6 +207,7 @@ IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCIVMFSCS3, 0x57); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, adc_vchs_ctrl[0].VCHCTL, 0x60); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, adc_vchs_ctrl[2].VCHDATM, 0x67); IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCDVSTS2, 0x6c); +IT8XXX2_REG_OFFSET_CHECK(adc_it8xxx2_regs, ADCCTL1, 0xf0); /* Watchdog register structure check */ IT8XXX2_REG_SIZE_CHECK(wdt_it8xxx2_regs, 0x0f); diff --git a/soc/riscv/ite_ec/common/chip_chipregs.h b/soc/riscv/ite_ec/common/chip_chipregs.h new file mode 100644 index 00000000000..c7d640fee33 --- /dev/null +++ b/soc/riscv/ite_ec/common/chip_chipregs.h @@ -0,0 +1,2231 @@ +/* + * Copyright (c) 2020 ITE Corporation. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CHIP_CHIPREGS_H +#define CHIP_CHIPREGS_H + +#include + +#define EC_REG_BASE_ADDR 0x00f00000 + +#ifdef _ASMLANGUAGE +#define ECREG(x) x +#else + +/* + * Macros for hardware registers access. + */ +#define ECREG(x) (*((volatile unsigned char *)(x))) +#define ECREG_u16(x) (*((volatile unsigned short *)(x))) +#define ECREG_u32(x) (*((volatile unsigned long *)(x))) + +/* + * MASK operation macros + */ +#define SET_MASK(reg, bit_mask) ((reg) |= (bit_mask)) +#define CLEAR_MASK(reg, bit_mask) ((reg) &= (~(bit_mask))) +#define IS_MASK_SET(reg, bit_mask) (((reg) & (bit_mask)) != 0) +#endif /* _ASMLANGUAGE */ + +#ifndef REG_BASE_ADDR +#define REG_BASE_ADDR EC_REG_BASE_ADDR +#endif + +/* Common definition */ +/* + * EC clock frequency (PWM and tachometer driver need it to reply + * to api or calculate RPM) + */ +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ +#define EC_FREQ MHZ(24) +#else +#define EC_FREQ MHZ(8) + +#endif + +/* --- General Control (GCTRL) --- */ +#define IT8XXX2_GCTRL_BASE 0x00F02000 +#define IT8XXX2_GCTRL_EIDSR ECREG(IT8XXX2_GCTRL_BASE + 0x31) + +/* --- External GPIO Control (EGPIO) --- */ +#define IT8XXX2_EGPIO_BASE 0x00F02100 +#define IT8XXX2_EGPIO_EGCR ECREG(IT8XXX2_EGPIO_BASE + 0x04) + +/* EGPIO register fields */ +/* + * 0x04: External GPIO Control + * BIT(4): EXGPIO EGAD Pin Output Driving Disable + */ +#define IT8XXX2_EGPIO_EEPODD BIT(4) + +/** + * + * (11xxh) Interrupt controller (INTC) + * + */ +#define ISR0 ECREG(EC_REG_BASE_ADDR + 0x3F00) +#define ISR1 ECREG(EC_REG_BASE_ADDR + 0x3F01) +#define ISR2 ECREG(EC_REG_BASE_ADDR + 0x3F02) +#define ISR3 ECREG(EC_REG_BASE_ADDR + 0x3F03) +#define ISR4 ECREG(EC_REG_BASE_ADDR + 0x3F14) +#define ISR5 ECREG(EC_REG_BASE_ADDR + 0x3F18) +#define ISR6 ECREG(EC_REG_BASE_ADDR + 0x3F1C) +#define ISR7 ECREG(EC_REG_BASE_ADDR + 0x3F20) +#define ISR8 ECREG(EC_REG_BASE_ADDR + 0x3F24) +#define ISR9 ECREG(EC_REG_BASE_ADDR + 0x3F28) +#define ISR10 ECREG(EC_REG_BASE_ADDR + 0x3F2C) +#define ISR11 ECREG(EC_REG_BASE_ADDR + 0x3F30) +#define ISR12 ECREG(EC_REG_BASE_ADDR + 0x3F34) +#define ISR13 ECREG(EC_REG_BASE_ADDR + 0x3F38) +#define ISR14 ECREG(EC_REG_BASE_ADDR + 0x3F3C) +#define ISR15 ECREG(EC_REG_BASE_ADDR + 0x3F40) +#define ISR16 ECREG(EC_REG_BASE_ADDR + 0x3F44) +#define ISR17 ECREG(EC_REG_BASE_ADDR + 0x3F48) +#define ISR18 ECREG(EC_REG_BASE_ADDR + 0x3F4C) +#define ISR19 ECREG(EC_REG_BASE_ADDR + 0x3F50) +#define ISR20 ECREG(EC_REG_BASE_ADDR + 0x3F54) +#define ISR21 ECREG(EC_REG_BASE_ADDR + 0x3F58) +#define ISR22 ECREG(EC_REG_BASE_ADDR + 0x3F5C) +#define ISR23 ECREG(EC_REG_BASE_ADDR + 0x3F90) + +#define IER0 ECREG(EC_REG_BASE_ADDR + 0x3F04) +#define IER1 ECREG(EC_REG_BASE_ADDR + 0x3F05) +#define IER2 ECREG(EC_REG_BASE_ADDR + 0x3F06) +#define IER3 ECREG(EC_REG_BASE_ADDR + 0x3F07) +#define IER4 ECREG(EC_REG_BASE_ADDR + 0x3F15) +#define IER5 ECREG(EC_REG_BASE_ADDR + 0x3F19) +#define IER6 ECREG(EC_REG_BASE_ADDR + 0x3F1D) +#define IER7 ECREG(EC_REG_BASE_ADDR + 0x3F21) +#define IER8 ECREG(EC_REG_BASE_ADDR + 0x3F25) +#define IER9 ECREG(EC_REG_BASE_ADDR + 0x3F29) +#define IER10 ECREG(EC_REG_BASE_ADDR + 0x3F2D) +#define IER11 ECREG(EC_REG_BASE_ADDR + 0x3F31) +#define IER12 ECREG(EC_REG_BASE_ADDR + 0x3F35) +#define IER13 ECREG(EC_REG_BASE_ADDR + 0x3F39) +#define IER14 ECREG(EC_REG_BASE_ADDR + 0x3F3D) +#define IER15 ECREG(EC_REG_BASE_ADDR + 0x3F41) +#define IER16 ECREG(EC_REG_BASE_ADDR + 0x3F45) +#define IER17 ECREG(EC_REG_BASE_ADDR + 0x3F49) +#define IER18 ECREG(EC_REG_BASE_ADDR + 0x3F4D) +#define IER19 ECREG(EC_REG_BASE_ADDR + 0x3F51) +#define IER20 ECREG(EC_REG_BASE_ADDR + 0x3F55) +#define IER21 ECREG(EC_REG_BASE_ADDR + 0x3F59) +#define IER22 ECREG(EC_REG_BASE_ADDR + 0x3F5D) +#define IER23 ECREG(EC_REG_BASE_ADDR + 0x3F91) + +#define IELMR0 ECREG(EC_REG_BASE_ADDR + 0x3F08) +#define IELMR1 ECREG(EC_REG_BASE_ADDR + 0x3F09) +#define IELMR2 ECREG(EC_REG_BASE_ADDR + 0x3F0A) +#define IELMR3 ECREG(EC_REG_BASE_ADDR + 0x3F0B) +#define IELMR4 ECREG(EC_REG_BASE_ADDR + 0x3F16) +#define IELMR5 ECREG(EC_REG_BASE_ADDR + 0x3F1A) +#define IELMR6 ECREG(EC_REG_BASE_ADDR + 0x3F1E) +#define IELMR7 ECREG(EC_REG_BASE_ADDR + 0x3F22) +#define IELMR8 ECREG(EC_REG_BASE_ADDR + 0x3F26) +#define IELMR9 ECREG(EC_REG_BASE_ADDR + 0x3F2A) +#define IELMR10 ECREG(EC_REG_BASE_ADDR + 0x3F2E) +#define IELMR11 ECREG(EC_REG_BASE_ADDR + 0x3F32) +#define IELMR12 ECREG(EC_REG_BASE_ADDR + 0x3F36) +#define IELMR13 ECREG(EC_REG_BASE_ADDR + 0x3F3A) +#define IELMR14 ECREG(EC_REG_BASE_ADDR + 0x3F3E) +#define IELMR15 ECREG(EC_REG_BASE_ADDR + 0x3F42) +#define IELMR16 ECREG(EC_REG_BASE_ADDR + 0x3F46) +#define IELMR17 ECREG(EC_REG_BASE_ADDR + 0x3F4A) +#define IELMR18 ECREG(EC_REG_BASE_ADDR + 0x3F4E) +#define IELMR19 ECREG(EC_REG_BASE_ADDR + 0x3F52) +#define IELMR20 ECREG(EC_REG_BASE_ADDR + 0x3F56) +#define IELMR21 ECREG(EC_REG_BASE_ADDR + 0x3F5A) +#define IELMR22 ECREG(EC_REG_BASE_ADDR + 0x3F5E) +#define IELMR23 ECREG(EC_REG_BASE_ADDR + 0x3F92) + +#define IPOLR0 ECREG(EC_REG_BASE_ADDR + 0x3F0C) +#define IPOLR1 ECREG(EC_REG_BASE_ADDR + 0x3F0D) +#define IPOLR2 ECREG(EC_REG_BASE_ADDR + 0x3F0E) +#define IPOLR3 ECREG(EC_REG_BASE_ADDR + 0x3F0F) +#define IPOLR4 ECREG(EC_REG_BASE_ADDR + 0x3F17) +#define IPOLR5 ECREG(EC_REG_BASE_ADDR + 0x3F1B) +#define IPOLR6 ECREG(EC_REG_BASE_ADDR + 0x3F1F) +#define IPOLR7 ECREG(EC_REG_BASE_ADDR + 0x3F23) +#define IPOLR8 ECREG(EC_REG_BASE_ADDR + 0x3F27) +#define IPOLR9 ECREG(EC_REG_BASE_ADDR + 0x3F2B) +#define IPOLR10 ECREG(EC_REG_BASE_ADDR + 0x3F2F) +#define IPOLR11 ECREG(EC_REG_BASE_ADDR + 0x3F33) +#define IPOLR12 ECREG(EC_REG_BASE_ADDR + 0x3F37) +#define IPOLR13 ECREG(EC_REG_BASE_ADDR + 0x3F3B) +#define IPOLR14 ECREG(EC_REG_BASE_ADDR + 0x3F3F) +#define IPOLR15 ECREG(EC_REG_BASE_ADDR + 0x3F43) +#define IPOLR16 ECREG(EC_REG_BASE_ADDR + 0x3F47) +#define IPOLR17 ECREG(EC_REG_BASE_ADDR + 0x3F4B) +#define IPOLR18 ECREG(EC_REG_BASE_ADDR + 0x3F4F) +#define IPOLR19 ECREG(EC_REG_BASE_ADDR + 0x3F53) +#define IPOLR20 ECREG(EC_REG_BASE_ADDR + 0x3F57) +#define IPOLR21 ECREG(EC_REG_BASE_ADDR + 0x3F5B) +#define IPOLR22 ECREG(EC_REG_BASE_ADDR + 0x3F5F) +#define IPOLR23 ECREG(EC_REG_BASE_ADDR + 0x3F93) + +#define IVECT ECREG(EC_REG_BASE_ADDR + 0x3F10) + + +/* + * TODO: use pinctrl node instead of following register declarations + * to fix in tcpm\it83xx_pd.h. + */ +/* GPIO control register */ +#define GPCRF4 ECREG(EC_REG_BASE_ADDR + 0x163C) +#define GPCRF5 ECREG(EC_REG_BASE_ADDR + 0x163D) +#define GPCRH1 ECREG(EC_REG_BASE_ADDR + 0x1649) +#define GPCRH2 ECREG(EC_REG_BASE_ADDR + 0x164A) + +/* + * IT8XXX2 register structure size/offset checking macro function to mitigate + * the risk of unexpected compiling results. + */ +#define IT8XXX2_REG_SIZE_CHECK(reg_def, size) \ + BUILD_ASSERT(sizeof(struct reg_def) == size, \ + "Failed in size check of register structure!") +#define IT8XXX2_REG_OFFSET_CHECK(reg_def, member, offset) \ + BUILD_ASSERT(offsetof(struct reg_def, member) == offset, \ + "Failed in offset check of register structure member!") + +/** + * + * (18xxh) PWM & SmartAuto Fan Control (PWM) + * + */ +#ifndef __ASSEMBLER__ +struct pwm_it8xxx2_regs { + /* 0x000: Channel0 Clock Prescaler */ + volatile uint8_t C0CPRS; + /* 0x001: Cycle Time0 */ + volatile uint8_t CTR; + /* 0x002~0x00A: Reserved1 */ + volatile uint8_t Reserved1[9]; + /* 0x00B: Prescaler Clock Frequency Select */ + volatile uint8_t PCFSR; + /* 0x00C~0x00F: Reserved2 */ + volatile uint8_t Reserved2[4]; + /* 0x010: Cycle Time1 MSB */ + volatile uint8_t CTR1M; + /* 0x011~0x022: Reserved3 */ + volatile uint8_t Reserved3[18]; + /* 0x023: PWM Clock Control */ + volatile uint8_t ZTIER; + /* 0x024~0x026: Reserved4 */ + volatile uint8_t Reserved4[3]; + /* 0x027: Channel4 Clock Prescaler */ + volatile uint8_t C4CPRS; + /* 0x028: Channel4 Clock Prescaler MSB */ + volatile uint8_t C4MCPRS; + /* 0x029~0x02A: Reserved5 */ + volatile uint8_t Reserved5[2]; + /* 0x02B: Channel6 Clock Prescaler */ + volatile uint8_t C6CPRS; + /* 0x02C: Channel6 Clock Prescaler MSB */ + volatile uint8_t C6MCPRS; + /* 0x02D: Channel7 Clock Prescaler */ + volatile uint8_t C7CPRS; + /* 0x02E: Channel7 Clock Prescaler MSB */ + volatile uint8_t C7MCPRS; + /* 0x02F~0x040: Reserved6 */ + volatile uint8_t reserved6[18]; + /* 0x041: Cycle Time1 */ + volatile uint8_t CTR1; + /* 0x042: Cycle Time2 */ + volatile uint8_t CTR2; + /* 0x043: Cycle Time3 */ + volatile uint8_t CTR3; + /* 0x044~0x048: Reserved7 */ + volatile uint8_t reserved7[5]; + /* 0x049: PWM Output Open-Drain Enable */ + volatile uint8_t PWMODENR; +}; +#endif /* !__ASSEMBLER__ */ + +/* PWM register fields */ +/* 0x023: PWM Clock Control */ +#define IT8XXX2_PWM_PCCE BIT(1) +/* 0x048: Tachometer Switch Control */ +#define IT8XXX2_PWM_T0DVS BIT(3) +#define IT8XXX2_PWM_T0CHSEL BIT(2) +#define IT8XXX2_PWM_T1DVS BIT(1) +#define IT8XXX2_PWM_T1CHSEL BIT(0) + + +/* --- Wake-Up Control (WUC) --- */ +#define IT8XXX2_WUC_BASE 0x00F01B00 + +/* TODO: should a defined interface for configuring wake-up interrupts */ +#define IT8XXX2_WUC_WUEMR1 (IT8XXX2_WUC_BASE + 0x00) +#define IT8XXX2_WUC_WUEMR5 (IT8XXX2_WUC_BASE + 0x0c) +#define IT8XXX2_WUC_WUESR1 (IT8XXX2_WUC_BASE + 0x04) +#define IT8XXX2_WUC_WUESR5 (IT8XXX2_WUC_BASE + 0x0d) +#define IT8XXX2_WUC_WUBEMR1 (IT8XXX2_WUC_BASE + 0x3c) +#define IT8XXX2_WUC_WUBEMR5 (IT8XXX2_WUC_BASE + 0x0f) + +/** + * + * (1Dxxh) Keyboard Matrix Scan control (KSCAN) + * + */ +#ifndef __ASSEMBLER__ +struct kscan_it8xxx2_regs { + /* 0x000: Keyboard Scan Out */ + volatile uint8_t KBS_KSOL; + /* 0x001: Keyboard Scan Out */ + volatile uint8_t KBS_KSOH1; + /* 0x002: Keyboard Scan Out Control */ + volatile uint8_t KBS_KSOCTRL; + /* 0x003: Keyboard Scan Out */ + volatile uint8_t KBS_KSOH2; + /* 0x004: Keyboard Scan In */ + volatile uint8_t KBS_KSI; + /* 0x005: Keyboard Scan In Control */ + volatile uint8_t KBS_KSICTRL; + /* 0x006: Keyboard Scan In [7:0] GPIO Control */ + volatile uint8_t KBS_KSIGCTRL; + /* 0x007: Keyboard Scan In [7:0] GPIO Output Enable */ + volatile uint8_t KBS_KSIGOEN; + /* 0x008: Keyboard Scan In [7:0] GPIO Data */ + volatile uint8_t KBS_KSIGDAT; + /* 0x009: Keyboard Scan In [7:0] GPIO Data Mirror */ + volatile uint8_t KBS_KSIGDMRR; + /* 0x00A: Keyboard Scan Out [15:8] GPIO Control */ + volatile uint8_t KBS_KSOHGCTRL; + /* 0x00B: Keyboard Scan Out [15:8] GPIO Output Enable */ + volatile uint8_t KBS_KSOHGOEN; + /* 0x00C: Keyboard Scan Out [15:8] GPIO Data Mirror */ + volatile uint8_t KBS_KSOHGDMRR; + /* 0x00D: Keyboard Scan Out [7:0] GPIO Control */ + volatile uint8_t KBS_KSOLGCTRL; + /* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */ + volatile uint8_t KBS_KSOLGOEN; +}; +#endif /* !__ASSEMBLER__ */ + +/* KBS register fields */ +/* 0x002: Keyboard Scan Out Control */ +#define IT8XXX2_KBS_KSOPU BIT(2) +#define IT8XXX2_KBS_KSOOD BIT(0) +/* 0x005: Keyboard Scan In Control */ +#define IT8XXX2_KBS_KSIPU BIT(2) +/* 0x00D: Keyboard Scan Out [7:0] GPIO Control */ +#define IT8XXX2_KBS_KSO2GCTRL BIT(2) +/* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */ +#define IT8XXX2_KBS_KSO2GOEN BIT(2) + + +/** + * + * (1Fxxh) External Timer & External Watchdog (ETWD) + * + */ +#ifndef __ASSEMBLER__ +struct wdt_it8xxx2_regs { + /* 0x000: Reserved1 */ + volatile uint8_t reserved1; + /* 0x001: External Timer1/WDT Configuration */ + volatile uint8_t ETWCFG; + /* 0x002: External Timer1 Prescaler */ + volatile uint8_t ET1PSR; + /* 0x003: External Timer1 Counter High Byte */ + volatile uint8_t ET1CNTLHR; + /* 0x004: External Timer1 Counter Low Byte */ + volatile uint8_t ET1CNTLLR; + /* 0x005: External Timer1/WDT Control */ + volatile uint8_t ETWCTRL; + /* 0x006: External WDT Counter Low Byte */ + volatile uint8_t EWDCNTLR; + /* 0x007: External WDT Key */ + volatile uint8_t EWDKEYR; + /* 0x008: Reserved2 */ + volatile uint8_t reserved2; + /* 0x009: External WDT Counter High Byte */ + volatile uint8_t EWDCNTHR; + /* 0x00A: External Timer2 Prescaler */ + volatile uint8_t ET2PSR; + /* 0x00B: External Timer2 Counter High Byte */ + volatile uint8_t ET2CNTLHR; + /* 0x00C: External Timer2 Counter Low Byte */ + volatile uint8_t ET2CNTLLR; + /* 0x00D: Reserved3 */ + volatile uint8_t reserved3; + /* 0x00E: External Timer2 Counter High Byte2 */ + volatile uint8_t ET2CNTLH2R; +}; +#endif /* !__ASSEMBLER__ */ + +/* WDT register fields */ +/* 0x001: External Timer1/WDT Configuration */ +#define IT8XXX2_WDT_EWDKEYEN BIT(5) +#define IT8XXX2_WDT_EWDSRC BIT(4) +#define IT8XXX2_WDT_LEWDCNTL BIT(3) +#define IT8XXX2_WDT_LET1CNTL BIT(2) +#define IT8XXX2_WDT_LET1PS BIT(1) +#define IT8XXX2_WDT_LETWCFG BIT(0) +/* 0x002: External Timer1 Prescaler */ +#define IT8XXX2_WDT_ETPS_32P768_KHZ 0x00 +#define IT8XXX2_WDT_ETPS_1P024_KHZ 0x01 +#define IT8XXX2_WDT_ETPS_32_HZ 0x02 +/* 0x005: External Timer1/WDT Control */ +#define IT8XXX2_WDT_EWDSCEN BIT(5) +#define IT8XXX2_WDT_EWDSCMS BIT(4) +#define IT8XXX2_WDT_ET2TC BIT(3) +#define IT8XXX2_WDT_ET2RST BIT(2) +#define IT8XXX2_WDT_ET1TC BIT(1) +#define IT8XXX2_WDT_ET1RST BIT(0) + +/* External Timer register fields */ +/* External Timer 3~8 control */ +#define IT8XXX2_EXT_ETX_COMB_RST_EN (IT8XXX2_EXT_ETXCOMB | \ + IT8XXX2_EXT_ETXRST | \ + IT8XXX2_EXT_ETXEN) +#define IT8XXX2_EXT_ETXCOMB BIT(3) +#define IT8XXX2_EXT_ETXRST BIT(1) +#define IT8XXX2_EXT_ETXEN BIT(0) + +/* Control external timer3~8 */ +#define IT8XXX2_EXT_TIMER_BASE DT_REG_ADDR(DT_NODELABEL(timer)) /*0x00F01F10*/ +#define IT8XXX2_EXT_CTRLX(n) ECREG(IT8XXX2_EXT_TIMER_BASE + (n << 3)) +#define IT8XXX2_EXT_PSRX(n) ECREG(IT8XXX2_EXT_TIMER_BASE + 0x01 + (n << 3)) +#define IT8XXX2_EXT_CNTX(n) ECREG_u32(IT8XXX2_EXT_TIMER_BASE + 0x04 + \ + (n << 3)) +#define IT8XXX2_EXT_CNTOX(n) ECREG_u32(IT8XXX2_EXT_TIMER_BASE + 0x38 + \ + (n << 2)) + +/* Free run timer configurations */ +#define FREE_RUN_TIMER EXT_TIMER_4 +#define FREE_RUN_TIMER_IRQ DT_IRQ_BY_IDX(DT_NODELABEL(timer), 1, irq) +/* Free run timer configurations */ +#define FREE_RUN_TIMER_FLAG DT_IRQ_BY_IDX(DT_NODELABEL(timer), 1, flags) +/* Free run timer max count is 36.4 hr (base on clock source 32768Hz) */ +#define FREE_RUN_TIMER_MAX_CNT 0xFFFFFFFFUL + +#ifndef __ASSEMBLER__ +enum ext_clk_src_sel { + EXT_PSR_32P768K = 0, + EXT_PSR_1P024K, + EXT_PSR_32, + EXT_PSR_EC_CLK, +}; +/* + * 24-bit timers: external timer 3, 5, and 7 + * 32-bit timers: external timer 4, 6, and 8 + */ +enum ext_timer_idx { + EXT_TIMER_3 = 0, /* Event timer */ + EXT_TIMER_4, /* Free run timer */ + EXT_TIMER_5, /* Busy wait low timer */ + EXT_TIMER_6, /* Busy wait high timer */ + EXT_TIMER_7, + EXT_TIMER_8, +}; +#endif + + +/* + * + * (2Cxxh) Platform Environment Control Interface (PECI) + * + */ +#ifndef __ASSEMBLER__ +struct peci_it8xxx2_regs { + /* 0x00: Host Status */ + volatile uint8_t HOSTAR; + /* 0x01: Host Control */ + volatile uint8_t HOCTLR; + /* 0x02: Host Command */ + volatile uint8_t HOCMDR; + /* 0x03: Host Target Address */ + volatile uint8_t HOTRADDR; + /* 0x04: Host Write Length */ + volatile uint8_t HOWRLR; + /* 0x05: Host Read Length */ + volatile uint8_t HORDLR; + /* 0x06: Host Write Data */ + volatile uint8_t HOWRDR; + /* 0x07: Host Read Data */ + volatile uint8_t HORDDR; + /* 0x08: Host Control 2 */ + volatile uint8_t HOCTL2R; + /* 0x09: Received Write FCS value */ + volatile uint8_t RWFCSV; + /* 0x0A: Received Read FCS value */ + volatile uint8_t RRFCSV; + /* 0x0B: Write FCS Value */ + volatile uint8_t WFCSV; + /* 0x0C: Read FCS Value */ + volatile uint8_t RFCSV; + /* 0x0D: Assured Write FCS Value */ + volatile uint8_t AWFCSV; + /* 0x0E: Pad Control */ + volatile uint8_t PADCTLR; +}; +#endif /* !__ASSEMBLER__ */ + +/** + * + * (2Fxxh) USB Device Controller (USBDC) Registers + * + */ +#define EP_EXT_REGS_9X 1 +#define EP_EXT_REGS_BX 2 +#define EP_EXT_REGS_DX 3 + +#ifndef __ASSEMBLER__ + +/* EP0 to EP15 Enumeration */ +enum usb_dc_endpoints { + EP0, + EP1, + EP2, + EP3, + EP4, + EP5, + EP6, + EP7, + EP8, + EP9, + EP10, + EP11, + EP12, + EP13, + EP14, + EP15, + MAX_NUM_ENDPOINTS +}; + +union ep_ctrl_reg { + volatile uint8_t value; + struct { + volatile uint8_t enable_bit: 1; + volatile uint8_t ready_bit: 1; + volatile uint8_t outdata_sequence_bit: 1; + volatile uint8_t send_stall_bit: 1; + volatile uint8_t iso_enable_bit: 1; + volatile uint8_t direction_bit: 1; + volatile uint8_t reserved: 2; + } __packed fields; +} __packed; + +struct it82xx2_usb_ep_regs { + union ep_ctrl_reg ep_ctrl; + volatile uint8_t ep_status; + volatile uint8_t ep_transtype_sts; + volatile uint8_t ep_nak_transtype_sts; +}; + +/* Reserved EP Extended Registers */ +struct ep_ext_regs_7x { + /* 0x75 Reserved */ + volatile uint8_t ep_ext_ctrl_75; + /* 0x76 Reserved */ + volatile uint8_t ep_ext_ctrl_76; + /* 0x77 Reserved */ + volatile uint8_t ep_ext_ctrl_77; + /* 0x78 Reserved */ + volatile uint8_t ep_ext_ctrl_78; + /* 0x79 Reserved */ + volatile uint8_t ep_ext_ctrl_79; + /* 0x7A Reserved */ + volatile uint8_t ep_ext_ctrl_7a; + /* 0x7B Reserved */ + volatile uint8_t ep_ext_ctrl_7b; + /* 0x7C Reserved */ + volatile uint8_t ep_ext_ctrl_7c; + /* 0x7D Reserved */ + volatile uint8_t ep_ext_ctrl_7d; + /* 0x7E Reserved */ + volatile uint8_t ep_ext_ctrl_7e; + /* 0x7F Reserved */ + volatile uint8_t ep_ext_ctrl_7f; +}; + +/* From 98h to 9Dh, the EP45/67/89/1011/1213/1415 Extended Control Registers + * are defined, and their bits definitions are as follows: + * + * Bit Description + * 7 Reserved + * 6 EPPOINT5_ISO_ENABLE + * 5 EPPOINT5_SEND_STALL + * 4 EPPOINT5_OUT_DATA_SEQUENCE + * 3 Reserved + * 2 EPPOINT4_ISO_ENABLE + * 1 EPPOINT4_SEND_STALL + * 0 EPPOINT4_OUT_DATA_SEQUENCE + * + * Apparently, we can tell that the EP4 and EP5 share the same register, and + * the EP6 and EP7 share the same one, and the rest EPs are defined in the + * same way. + */ +union epn0n1_extend_ctrl_reg { + volatile uint8_t value; + struct { + volatile uint8_t epn0_outdata_sequence_bit: 1; + volatile uint8_t epn0_send_stall_bit: 1; + volatile uint8_t epn0_iso_enable_bit: 1; + volatile uint8_t reserved0: 1; + volatile uint8_t epn1_outdata_sequence_bit: 1; + volatile uint8_t epn1_send_stall_bit: 1; + volatile uint8_t epn1_iso_enable_bit: 1; + volatile uint8_t reserved1: 1; + } __packed fields; +} __packed; + +struct ep_ext_regs_9x { + /* 0x95 Reserved */ + volatile uint8_t ep_ext_ctrl_95; + /* 0x96 Reserved */ + volatile uint8_t ep_ext_ctrl_96; + /* 0x97 Reserved */ + volatile uint8_t ep_ext_ctrl_97; + /* 0x98 ~ 0x9D EP45/67/89/1011/1213/1415 Extended Control Registers */ + union epn0n1_extend_ctrl_reg epn0n1_ext_ctrl[6]; + /* 0x9E Reserved */ + volatile uint8_t ep_ext_ctrl_9e; + /* 0x9F Reserved */ + volatile uint8_t ep_ext_ctrl_9f; +}; + +/* From BXh to BDh are EP FIFO 1-3 Control 0/1 Registers, and their + * definitions as as follows: + * B8h: EP_FIFO1_CONTROL0_REG + * B9h: EP_FIFO1_CONTROL1_REG + * BAh: EP_FIFO2_CONTROL0_REG + * BBh: EP_FIFO2_CONTROL1_REG + * BCh: EP_FIFO3_CONTROL0_REG + * BDh: EP_FIFO3_CONTROL1_REG + * + * For each one, its bits definitions are as follows: + * (take EP_FIFO1_CONTROL1_REG as example, which controls from EP8 to EP15) + * + * Bit Description + * + * 7 EP15 select FIFO1 as data buffer + * 6 EP14 select FIFO1 as data buffer + * 5 EP13 select FIFO1 as data buffer + * 4 EP12 select FIFO1 as data buffer + * 3 EP11 select FIFO1 as data buffer + * 2 EP10 select FIFO1 as data buffer + * 1 EP9 select FIFO1 as data buffer + * 0 EP8 select FIFO1 as data buffer + * + * 1: Select + * 0: Not select + */ +struct ep_ext_regs_bx { + /* 0xB5 Reserved */ + volatile uint8_t ep_ext_ctrl_b5; + /* 0xB6 Reserved */ + volatile uint8_t ep_ext_ctrl_b6; + /* 0xB7 Reserved */ + volatile uint8_t ep_ext_ctrl_b7; + /* 0xB8 ~ 0xBD EP FIFO 1-3 Control 0/1 Registers */ + volatile uint8_t ep_fifo_ctrl[6]; + /* 0xBE Reserved */ + volatile uint8_t ep_ext_ctrl_be; + /* 0xBF Reserved */ + volatile uint8_t ep_ext_ctrl_bf; +}; + + +/* From D6h to DDh are EP Extended Control Registers, and their + * definitions as as follows: + * D6h: EP0_EXT_CTRL1 + * D7h: EP0_EXT_CTRL2 + * D8h: EP1_EXT_CTRL1 + * D9h: EP1_EXT_CTRL2 + * DAh: EP2_EXT_CTRL1 + * DBh: EP2_EXT_CTRL2 + * DCh: EP3_EXT_CTRL1 + * DDh: EP3_EXT_CTRL2 + * + * We classify them into 4 groups which each of them contains Control 1 and 2 + * according to the EP number as follows: + */ +union epn_extend_ctrl1_reg { + volatile uint8_t value; + struct { + volatile uint8_t epn0_enable_bit: 1; + volatile uint8_t epn0_direction_bit: 1; + volatile uint8_t epn3_enable_bit: 1; + volatile uint8_t epn3_direction_bit: 1; + volatile uint8_t epn6_enable_bit: 1; + volatile uint8_t epn6_direction_bit: 1; + volatile uint8_t epn9_enable_bit: 1; + volatile uint8_t epn9_direction_bit: 1; + } __packed fields; +} __packed; + +struct epn_ext_ctrl_regs { + /* 0xD6/0xD8/0xDA/0xDC EPN Extended Control1 Register */ + union epn_extend_ctrl1_reg epn_ext_ctrl1; + /* 0xD7/0xD9/0xDB/0xDD EPB Extended Control2 Register */ + volatile uint8_t epn_ext_ctrl2; +}; + +struct ep_ext_regs_dx { + /* 0xD5 Reserved */ + volatile uint8_t ep_ext_ctrl_d5; + /* 0xD6 ~ 0xDD EPN Extended Control 1/2 Registers */ + struct epn_ext_ctrl_regs epn_ext_ctrl[4]; + /* 0xDE Reserved */ + volatile uint8_t ep_ext_ctrl_de; + /* 0xDF Reserved */ + volatile uint8_t ep_ext_ctrl_df; +}; + + +/* The USB EPx FIFO Registers Definitions + * EP0: 60h ~ 74h + * EP1: 80h ~ 94h + * EP2: A0h ~ B4h + * EP3: C0h ~ D4h (D6h to DDh will be defined as marcos for usage) + */ +struct it82xx2_usb_ep_fifo_regs { + /* 0x60 + ep * 0x20 : EP RX FIFO Data Register */ + volatile uint8_t ep_rx_fifo_data; + /* 0x61 + ep * 0x20 : EP RX FIFO DMA Count Register */ + volatile uint8_t ep_rx_fifo_dma_count; + /* 0x62 + ep * 0x20 : EP RX FIFO Data Count MSB */ + volatile uint8_t ep_rx_fifo_dcnt_msb; + /* 0x63 + ep * 0x20 : EP RX FIFO Data Count LSB */ + volatile uint8_t ep_rx_fifo_dcnt_lsb; + /* 0x64 + ep * 0x20 : EP RX FIFO Control Register */ + volatile uint8_t ep_rx_fifo_ctrl; + /* (0x65 ~ 0x6F) + ep * 0x20 */ + volatile uint8_t reserved_65_6f_add_20[11]; + /* 0x70 + ep * 0x20 : EP TX FIFO Data Register */ + volatile uint8_t ep_tx_fifo_data; + /* (0x71 ~ 0x73) + ep * 0x20 */ + volatile uint8_t reserved_71_73_add_20[3]; + /* 0x74 + ep * 0x20 : EP TX FIFO Control Register */ + volatile uint8_t ep_tx_fifo_ctrl; + /* (0x75 ~ 0x7F) + ep * 0x20 */ + union { + struct ep_ext_regs_7x ep_res; + struct ep_ext_regs_9x ext_4_15; + struct ep_ext_regs_bx fifo_ctrl; + struct ep_ext_regs_dx ext_0_3; + }; + +}; + +/* USB Control registers */ +#define USB_IT82XX2_REGS_BASE \ + ((struct usb_it82xx2_regs *)DT_REG_ADDR(DT_NODELABEL(usb0))) + +/* Bit definitions of the register Port0/Port1 MISC Control: 0XE4/0xE8 */ +#define PULL_DOWN_EN BIT(4) + +struct usb_it82xx2_regs { + /* 0x00: Host TX Contrl Register */ + volatile uint8_t host_tx_ctrl; + /* 0x01: Host TX Transaction Type Register */ + volatile uint8_t host_tx_trans_type; + /* 0x02: Host TX Line Control Register */ + volatile uint8_t host_tx_line_ctrl; + /* 0x03: Host TX SOF Enable Register */ + volatile uint8_t host_tx_sof_enable; + /* 0x04: Host TX Address Register */ + volatile uint8_t host_tx_addr; + /* 0x05: Host TX EP Number Register */ + volatile uint8_t host_tx_endp; + /* 0x06: Host Frame Number MSP Register */ + volatile uint8_t host_frame_num_msp; + /* 0x07: Host Frame Number LSP Register */ + volatile uint8_t host_frame_num_lsp; + /* 0x08: Host Interrupt Status Register */ + volatile uint8_t host_interrupt_status; + /* 0x09: Host Interrupt Mask Register */ + volatile uint8_t host_interrupt_mask; + /* 0x0A: Host RX Status Register */ + volatile uint8_t host_rx_status; + /* 0x0B: Host RX PID Register */ + volatile uint8_t host_rx_pid; + /* 0x0C: MISC Control Register */ + volatile uint8_t misc_control; + /* 0x0D: MISC Status Register */ + volatile uint8_t misc_status; + /* 0x0E: Host RX Connect State Register */ + volatile uint8_t host_rx_connect_state; + /* 0x0F: Host SOF Timer MSB Register */ + volatile uint8_t host_sof_timer_msb; + /* 0x10 ~ 0x1F: Reserved Registers 10h - 1Fh */ + volatile uint8_t reserved_10_1f[16]; + /* 0x20: Host RX FIFO Data Port Register */ + volatile uint8_t host_rx_fifo_data; + /* 0x21: Host RX FIFO DMA Input Data Count Register */ + volatile uint8_t host_rx_fifo_dma_data_count; + /* 0x22: Host TX FIFO Data Count MSB Register */ + volatile uint8_t host_rx_fifo_data_count_msb; + /* 0x23: Host TX FIFO Data Count LSB Register */ + volatile uint8_t host_rx_fifo_data_count_lsb; + /* 0x24: Host RX FIFO Data Port Register */ + volatile uint8_t host_rx_fifo_control; + /* 0x25 ~ 0x2F: Reserved Registers 25h - 2Fh */ + volatile uint8_t reserved_25_2f[11]; + /* 0x30: Host TX FIFO Data Port Register */ + volatile uint8_t host_tx_fifo_data; + /* 0x31 ~ 0x3F: Reserved Registers 31h - 3Fh */ + volatile uint8_t reserved_31_3f[15]; + /* 0x40 ~ 0x4F: Endpoint Registers 40h - 4Fh */ + struct it82xx2_usb_ep_regs usb_ep_regs[4]; + /* 0x50: Device Controller Control Register */ + volatile uint8_t dc_control; + /* 0x51: Device Controller LINE Status Register */ + volatile uint8_t dc_line_status; + /* 0x52: Device Controller Interrupt Status Register */ + volatile uint8_t dc_interrupt_status; + /* 0x53: Device Controller Interrupt Mask Register */ + volatile uint8_t dc_interrupt_mask; + /* 0x54: Device Controller Address Register */ + volatile uint8_t dc_address; + /* 0x55: Device Controller Frame Number MSP Register */ + volatile uint8_t dc_frame_num_msp; + /* 0x56: Device Controller Frame Number LSP Register */ + volatile uint8_t dc_frame_num_lsp; + /* 0x57 ~ 0x5F: Reserved Registers 57h - 5Fh */ + volatile uint8_t reserved_57_5f[9]; + /* 0x60 ~ 0xDF: EP FIFO Registers 60h - DFh */ + struct it82xx2_usb_ep_fifo_regs fifo_regs[4]; + /* 0xE0: Host/Device Control Register */ + volatile uint8_t host_device_control; + /* 0xE1 ~ 0xE3: Reserved Registers E1h - E3h */ + volatile uint8_t reserved_e1_e3[3]; + /* 0xE4: Port0 MISC Control Register */ + volatile uint8_t port0_misc_control; + /* 0xE5 ~ 0xE7: Reserved Registers E5h - E7h */ + volatile uint8_t reserved_e5_e7[3]; + /* 0xE8: Port1 MISC Control Register */ + volatile uint8_t port1_misc_control; +}; +#endif /* #ifndef __ASSEMBLER__ */ + +/** + * + * (37xxh, 38xxh) USBPD Controller + * + */ +#ifndef __ASSEMBLER__ +struct usbpd_it8xxx2_regs { + /* 0x000~0x003: Reserved1 */ + volatile uint8_t Reserved1[4]; + /* 0x004: CC General Configuration */ + volatile uint8_t CCGCR; + /* 0x005: CC Channel Setting */ + volatile uint8_t CCCSR; + /* 0x006: CC Pad Setting */ + volatile uint8_t CCPSR; +}; +#endif /* !__ASSEMBLER__ */ + +/* USBPD controller register fields */ +/* 0x004: CC General Configuration */ +#define IT8XXX2_USBPD_DISABLE_CC BIT(7) +#define IT8XXX2_USBPD_DISABLE_CC_VOL_DETECTOR BIT(6) +#define IT8XXX2_USBPD_CC_SELECT_RP_RESERVED (BIT(3) | BIT(2) | BIT(1)) +#define IT8XXX2_USBPD_CC_SELECT_RP_DEF (BIT(3) | BIT(2)) +#define IT8XXX2_USBPD_CC_SELECT_RP_1A5 BIT(3) +#define IT8XXX2_USBPD_CC_SELECT_RP_3A0 BIT(2) +#define IT8XXX2_USBPD_CC1_CC2_SELECTION BIT(0) +/* 0x005: CC Channel Setting */ +#define IT8XXX2_USBPD_CC2_DISCONNECT BIT(7) +#define IT8XXX2_USBPD_CC2_DISCONNECT_5_1K_TO_GND BIT(6) +#define IT8XXX2_USBPD_CC1_DISCONNECT BIT(3) +#define IT8XXX2_USBPD_CC1_DISCONNECT_5_1K_TO_GND BIT(2) +#define IT8XXX2_USBPD_CC1_CC2_RP_RD_SELECT (BIT(1) | BIT(5)) +/* 0x006: CC Pad Setting */ +#define IT8XXX2_USBPD_DISCONNECT_5_1K_CC2_DB BIT(6) +#define IT8XXX2_USBPD_DISCONNECT_POWER_CC2 BIT(5) +#define IT8XXX2_USBPD_DISCONNECT_5_1K_CC1_DB BIT(2) +#define IT8XXX2_USBPD_DISCONNECT_POWER_CC1 BIT(1) + + +/** + * + * (10xxh) Shared Memory Flash Interface Bridge (SMFI) registers + * + */ +#ifndef __ASSEMBLER__ +struct smfi_it8xxx2_regs { + volatile uint8_t reserved1[59]; + /* 0x3B: EC-Indirect memory address 0 */ + volatile uint8_t SMFI_ECINDAR0; + /* 0x3C: EC-Indirect memory address 1 */ + volatile uint8_t SMFI_ECINDAR1; + /* 0x3D: EC-Indirect memory address 2 */ + volatile uint8_t SMFI_ECINDAR2; + /* 0x3E: EC-Indirect memory address 3 */ + volatile uint8_t SMFI_ECINDAR3; + /* 0x3F: EC-Indirect memory data */ + volatile uint8_t SMFI_ECINDDR; + /* 0x40: Scratch SRAM 0 address low byte */ + volatile uint8_t SMFI_SCAR0L; + /* 0x41: Scratch SRAM 0 address middle byte */ + volatile uint8_t SMFI_SCAR0M; + /* 0x42: Scratch SRAM 0 address high byte */ + volatile uint8_t SMFI_SCAR0H; + volatile uint8_t reserved1_1[23]; + /* 0x5A: Host RAM Window Control */ + volatile uint8_t SMFI_HRAMWC; + /* 0x5B: Host RAM Window 0 Base Address [11:4] */ + volatile uint8_t SMFI_HRAMW0BA; + /* 0x5C: Host RAM Window 1 Base Address [11:4] */ + volatile uint8_t SMFI_HRAMW1BA; + /* 0x5D: Host RAM Window 0 Access Allow Size */ + volatile uint8_t SMFI_HRAMW0AAS; + /* 0x5E: Host RAM Window 1 Access Allow Size */ + volatile uint8_t SMFI_HRAMW1AAS; + volatile uint8_t reserved2[67]; + /* 0xA2: Flash control 6 */ + volatile uint8_t SMFI_FLHCTRL6R; + volatile uint8_t reserved3[46]; +}; +#endif /* !__ASSEMBLER__ */ + +/* SMFI register fields */ +/* EC-Indirect read internal flash */ +#define EC_INDIRECT_READ_INTERNAL_FLASH BIT(6) +/* Enable EC-indirect page program command */ +#define IT8XXX2_SMFI_MASK_ECINDPP BIT(3) +/* Scratch SRAM 0 address(BIT(19)) */ +#define IT8XXX2_SMFI_SC0A19 BIT(7) +/* Scratch SRAM enable */ +#define IT8XXX2_SMFI_SCAR0H_ENABLE BIT(3) + +/* H2RAM Path Select. 1b: H2RAM through LPC IO cycle. */ +#define SMFI_H2RAMPS BIT(4) +/* H2RAM Window 1 Enable */ +#define SMFI_H2RAMW1E BIT(1) +/* H2RAM Window 0 Enable */ +#define SMFI_H2RAMW0E BIT(0) + +/* Host RAM Window x Write Protect Enable (All protected) */ +#define SMFI_HRAMWXWPE_ALL (BIT(5) | BIT(4)) + + +/** + * + * (16xxh) General Purpose I/O Port (GPIO) registers + * + */ +#define GPIO_IT8XXX2_REG_BASE \ + ((struct gpio_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gpiogcr))) + +#ifndef __ASSEMBLER__ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 +struct gpio_it8xxx2_regs { + /* 0x00: General Control */ + volatile uint8_t GPIO_GCR; + /* 0x01-D0: Reserved1 */ + volatile uint8_t reserved1[208]; + /* 0xD1: General Control 25 */ + volatile uint8_t GPIO_GCR25; + /* 0xD2: General Control 26 */ + volatile uint8_t GPIO_GCR26; + /* 0xD3: General Control 27 */ + volatile uint8_t GPIO_GCR27; + /* 0xD4: General Control 28 */ + volatile uint8_t GPIO_GCR28; + /* 0xD5: General Control 31 */ + volatile uint8_t GPIO_GCR31; + /* 0xD6: General Control 32 */ + volatile uint8_t GPIO_GCR32; + /* 0xD7: General Control 33 */ + volatile uint8_t GPIO_GCR33; + /* 0xD8-0xDF: Reserved2 */ + volatile uint8_t reserved2[8]; + /* 0xE0: General Control 16 */ + volatile uint8_t GPIO_GCR16; + /* 0xE1: General Control 17 */ + volatile uint8_t GPIO_GCR17; + /* 0xE2: General Control 18 */ + volatile uint8_t GPIO_GCR18; + /* 0xE3: Reserved3 */ + volatile uint8_t reserved3; + /* 0xE4: General Control 19 */ + volatile uint8_t GPIO_GCR19; + /* 0xE5: General Control 20 */ + volatile uint8_t GPIO_GCR20; + /* 0xE6: General Control 21 */ + volatile uint8_t GPIO_GCR21; + /* 0xE7: General Control 22 */ + volatile uint8_t GPIO_GCR22; + /* 0xE8: General Control 23 */ + volatile uint8_t GPIO_GCR23; + /* 0xE9: General Control 24 */ + volatile uint8_t GPIO_GCR24; + /* 0xEA-0xEC: Reserved4 */ + volatile uint8_t reserved4[3]; + /* 0xED: General Control 30 */ + volatile uint8_t GPIO_GCR30; + /* 0xEE: General Control 29 */ + volatile uint8_t GPIO_GCR29; + /* 0xEF: Reserved5 */ + volatile uint8_t reserved5; + /* 0xF0: General Control 1 */ + volatile uint8_t GPIO_GCR1; + /* 0xF1: General Control 2 */ + volatile uint8_t GPIO_GCR2; + /* 0xF2: General Control 3 */ + volatile uint8_t GPIO_GCR3; + /* 0xF3: General Control 4 */ + volatile uint8_t GPIO_GCR4; + /* 0xF4: General Control 5 */ + volatile uint8_t GPIO_GCR5; + /* 0xF5: General Control 6 */ + volatile uint8_t GPIO_GCR6; + /* 0xF6: General Control 7 */ + volatile uint8_t GPIO_GCR7; + /* 0xF7: General Control 8 */ + volatile uint8_t GPIO_GCR8; + /* 0xF8: General Control 9 */ + volatile uint8_t GPIO_GCR9; + /* 0xF9: General Control 10 */ + volatile uint8_t GPIO_GCR10; + /* 0xFA: General Control 11 */ + volatile uint8_t GPIO_GCR11; + /* 0xFB: General Control 12 */ + volatile uint8_t GPIO_GCR12; + /* 0xFC: General Control 13 */ + volatile uint8_t GPIO_GCR13; + /* 0xFD: General Control 14 */ + volatile uint8_t GPIO_GCR14; + /* 0xFE: General Control 15 */ + volatile uint8_t GPIO_GCR15; + /* 0xFF: Power Good Watch Control */ + volatile uint8_t GPIO_PGWCR; +}; +#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 +struct gpio_it8xxx2_regs { + /* 0x00: General Control */ + volatile uint8_t GPIO_GCR; + /* 0x01-0x0F: Reserved1 */ + volatile uint8_t reserved1[15]; + /* 0x10: General Control 1 */ + volatile uint8_t GPIO_GCR1; + /* 0x11: General Control 2 */ + volatile uint8_t GPIO_GCR2; + /* 0x12: General Control 3 */ + volatile uint8_t GPIO_GCR3; + /* 0x13: General Control 4 */ + volatile uint8_t GPIO_GCR4; + /* 0x14: General Control 5 */ + volatile uint8_t GPIO_GCR5; + /* 0x15: General Control 6 */ + volatile uint8_t GPIO_GCR6; + /* 0x16: General Control 7 */ + volatile uint8_t GPIO_GCR7; + /* 0x17: General Control 8 */ + volatile uint8_t GPIO_GCR8; + /* 0x18: General Control 9 */ + volatile uint8_t GPIO_GCR9; + /* 0x19: General Control 10 */ + volatile uint8_t GPIO_GCR10; + /* 0x1A: General Control 11 */ + volatile uint8_t GPIO_GCR11; + /* 0x1B: General Control 12 */ + volatile uint8_t GPIO_GCR12; + /* 0x1C: General Control 13 */ + volatile uint8_t GPIO_GCR13; + /* 0x1D: General Control 14 */ + volatile uint8_t GPIO_GCR14; + /* 0x1E: General Control 15 */ + volatile uint8_t GPIO_GCR15; + /* 0x1F: Power Good Watch Control */ + volatile uint8_t GPIO_PGWCR; + /* 0x20: General Control 16 */ + volatile uint8_t GPIO_GCR16; + /* 0x21: General Control 17 */ + volatile uint8_t GPIO_GCR17; + /* 0x22: General Control 18 */ + volatile uint8_t GPIO_GCR18; + /* 0x23: Reserved2 */ + volatile uint8_t reserved2; + /* 0x24: General Control 19 */ + volatile uint8_t GPIO_GCR19; + /* 0x25: Reserved3 */ + volatile uint8_t reserved3; + /* 0x26: General Control 21 */ + volatile uint8_t GPIO_GCR21; + /* 0x27-0x28: Reserved4 */ + volatile uint8_t reserved4[2]; + /* 0x29: General Control 24 */ + volatile uint8_t GPIO_GCR24; + /* 0x2A-0x2C: Reserved5 */ + volatile uint8_t reserved5[3]; + /* 0x2D: General Control 30 */ + volatile uint8_t GPIO_GCR30; + /* 0x2E: General Control 29 */ + volatile uint8_t GPIO_GCR29; +}; + +/* GPIO register fields */ +/* 0x16: General Control 7 */ +#define IT8XXX2_GPIO_SMB2PS BIT(7) +#define IT8XXX2_GPIO_SMB3PS BIT(6) +#define IT8XXX2_GPIO_SMB5PS BIT(5) + +#endif +#endif /* !__ASSEMBLER__ */ + +/* GPIO register fields */ +/* 0x00: General Control */ +#define IT8XXX2_GPIO_LPCRSTEN (BIT(2) | BIT(1)) +#define IT8XXX2_GPIO_GCR_ESPI_RST_D2 0x2 +#define IT8XXX2_GPIO_GCR_ESPI_RST_POS 1 +#define IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK (0x3 << IT8XXX2_GPIO_GCR_ESPI_RST_POS) +/* 0xF0: General Control 1 */ +#define IT8XXX2_GPIO_U2CTRL_SIN1_SOUT1_EN BIT(2) +#define IT8XXX2_GPIO_U1CTRL_SIN0_SOUT0_EN BIT(0) +/* 0xE6: General Control 21 */ +#define IT8XXX2_GPIO_GPH1VS BIT(1) +#define IT8XXX2_GPIO_GPH2VS BIT(0) + +#define KSIX_KSOX_KBS_GPIO_MODE BIT(7) +#define KSIX_KSOX_GPIO_OUTPUT BIT(6) +#define KSIX_KSOX_GPIO_PULLUP BIT(2) +#define KSIX_KSOX_GPIO_PULLDOWN BIT(1) + +#define GPCR_PORT_PIN_MODE_INPUT BIT(7) +#define GPCR_PORT_PIN_MODE_OUTPUT BIT(6) +#define GPCR_PORT_PIN_MODE_PULLUP BIT(2) +#define GPCR_PORT_PIN_MODE_PULLDOWN BIT(1) + +/* + * If both PULLUP and PULLDOWN are set to 1b, the corresponding port would be + * configured as tri-state. + */ +#define GPCR_PORT_PIN_MODE_TRISTATE (GPCR_PORT_PIN_MODE_INPUT | \ + GPCR_PORT_PIN_MODE_PULLUP | \ + GPCR_PORT_PIN_MODE_PULLDOWN) + +/* --- GPIO --- */ +#define IT8XXX2_GPIO_BASE 0x00F01600 +#define IT8XXX2_GPIO2_BASE 0x00F03E00 + +#define IT8XXX2_GPIO_GCRX(offset) ECREG(IT8XXX2_GPIO_BASE + (offset)) +#define IT8XXX2_GPIO_GCR25_OFFSET 0xd1 +#define IT8XXX2_GPIO_GCR26_OFFSET 0xd2 +#define IT8XXX2_GPIO_GCR27_OFFSET 0xd3 +#define IT8XXX2_GPIO_GCR28_OFFSET 0xd4 +#define IT8XXX2_GPIO_GCR31_OFFSET 0xd5 +#define IT8XXX2_GPIO_GCR32_OFFSET 0xd6 +#define IT8XXX2_GPIO_GCR33_OFFSET 0xd7 +#define IT8XXX2_GPIO_GCR19_OFFSET 0xe4 +#define IT8XXX2_GPIO_GCR20_OFFSET 0xe5 +#define IT8XXX2_GPIO_GCR21_OFFSET 0xe6 +#define IT8XXX2_GPIO_GCR22_OFFSET 0xe7 +#define IT8XXX2_GPIO_GCR23_OFFSET 0xe8 +#define IT8XXX2_GPIO_GCR24_OFFSET 0xe9 +#define IT8XXX2_GPIO_GCR30_OFFSET 0xed +#define IT8XXX2_GPIO_GCR29_OFFSET 0xee + +/* + * TODO: use pinctrl node instead of following register declarations + * to fix in tcpm\it83xx_pd.h. + */ +#define IT8XXX2_GPIO_GPCRP0 ECREG(IT8XXX2_GPIO2_BASE + 0x18) +#define IT8XXX2_GPIO_GPCRP1 ECREG(IT8XXX2_GPIO2_BASE + 0x19) + + +/** + * + * (19xxh) Analog to Digital Converter (ADC) registers + * + */ +#ifndef __ASSEMBLER__ + +/* Data structure to define ADC channel 13-16 control registers. */ +struct adc_vchs_ctrl_t { + /* 0x60: Voltage Channel Control */ + volatile uint8_t VCHCTL; + /* 0x61: Voltage Channel Data Buffer MSB */ + volatile uint8_t VCHDATM; + /* 0x62: Voltage Channel Data Buffer LSB */ + volatile uint8_t VCHDATL; +}; + +struct adc_it8xxx2_regs { + /* 0x00: ADC Status */ + volatile uint8_t ADCSTS; + /* 0x01: ADC Configuration */ + volatile uint8_t ADCCFG; + /* 0x02: ADC Clock Control */ + volatile uint8_t ADCCTL; + /* 0x03: General Control */ + volatile uint8_t ADCGCR; + /* 0x04: Voltage Channel 0 Control */ + volatile uint8_t VCH0CTL; + /* 0x05: Calibration Data Control */ + volatile uint8_t KDCTL; + /* 0x06-0x17: Reserved1 */ + volatile uint8_t reserved1[18]; + /* 0x18: Voltage Channel 0 Data Buffer LSB */ + volatile uint8_t VCH0DATL; + /* 0x19: Voltage Channel 0 Data Buffer MSB */ + volatile uint8_t VCH0DATM; + /* 0x1a-0x43: Reserved2 */ + volatile uint8_t reserved2[42]; + /* 0x44: ADC Data Valid Status */ + volatile uint8_t ADCDVSTS; + /* 0x45-0x54: Reserved2-1 */ + volatile uint8_t reserved2_1[16]; + /* 0x55: ADC Input Voltage Mapping Full-Scale Code Selection 1 */ + volatile uint8_t ADCIVMFSCS1; + /* 0x56: ADC Input Voltage Mapping Full-Scale Code Selection 2 */ + volatile uint8_t ADCIVMFSCS2; + /* 0x57: ADC Input Voltage Mapping Full-Scale Code Selection 3 */ + volatile uint8_t ADCIVMFSCS3; + /* 0x58-0x5f: Reserved3 */ + volatile uint8_t reserved3[8]; + /* 0x60-0x6b: ADC channel 13~16 controller */ + struct adc_vchs_ctrl_t adc_vchs_ctrl[4]; + /* 0x6c: ADC Data Valid Status 2 */ + volatile uint8_t ADCDVSTS2; + /* 0x6d-0xef: Reserved4 */ + volatile uint8_t reserved4[131]; + /* 0xf0: ADC Clock Control Register 1 */ + volatile uint8_t ADCCTL1; +}; +#endif /* !__ASSEMBLER__ */ + +/* ADC conversion time select 1 */ +#define IT8XXX2_ADC_ADCCTS1 BIT(7) +/* Analog accuracy initialization */ +#define IT8XXX2_ADC_AINITB BIT(3) +/* ADC conversion time select 0 */ +#define IT8XXX2_ADC_ADCCTS0 BIT(5) +/* ADC module enable */ +#define IT8XXX2_ADC_ADCEN BIT(0) +/* ADC data buffer keep enable */ +#define IT8XXX2_ADC_DBKEN BIT(7) +/* W/C data valid flag */ +#define IT8XXX2_ADC_DATVAL BIT(7) +/* Data valid interrupt of adc */ +#define IT8XXX2_ADC_INTDVEN BIT(5) +/* Voltage channel enable (Channel 4~7 and 13~16) */ +#define IT8XXX2_ADC_VCHEN BIT(4) +/* Automatic hardware calibration enable */ +#define IT8XXX2_ADC_AHCE BIT(7) +/* 0x046, 0x049, 0x04c, 0x06e, 0x071, 0x074: Voltage comparator x control */ +#define IT8XXX2_VCMP_CMPEN BIT(7) +#define IT8XXX2_VCMP_CMPINTEN BIT(6) +#define IT8XXX2_VCMP_GREATER_THRESHOLD BIT(5) +#define IT8XXX2_VCMP_EDGE_TRIGGER BIT(4) +#define IT8XXX2_VCMP_GPIO_ACTIVE_LOW BIT(3) +/* 0x077~0x07c: Voltage comparator x channel select MSB */ +#define IT8XXX2_VCMP_VCMPXCSELM BIT(0) + +/** + * + * (1Exxh) Clock and Power Management (ECPM) registers + * + */ +#define IT8XXX2_ECPM_BASE 0x00F01E00 + +#ifndef __ASSEMBLER__ +enum chip_pll_mode { + CHIP_PLL_DOZE = 0, + CHIP_PLL_SLEEP = 1, + CHIP_PLL_DEEP_DOZE = 3, +}; +#endif +/* + * TODO: use ecpm_it8xxx2_regs instead of following register declarations + * to fix in soc.c. + */ +#define IT8XXX2_ECPM_PLLCTRL ECREG(IT8XXX2_ECPM_BASE + 0x03) +#define IT8XXX2_ECPM_AUTOCG ECREG(IT8XXX2_ECPM_BASE + 0x04) +#define IT8XXX2_ECPM_CGCTRL3R ECREG(IT8XXX2_ECPM_BASE + 0x05) +#define IT8XXX2_ECPM_PLLFREQR ECREG(IT8XXX2_ECPM_BASE + 0x06) +#define IT8XXX2_ECPM_PLLCSS ECREG(IT8XXX2_ECPM_BASE + 0x08) +#define IT8XXX2_ECPM_SCDCR0 ECREG(IT8XXX2_ECPM_BASE + 0x0c) +#define IT8XXX2_ECPM_SCDCR1 ECREG(IT8XXX2_ECPM_BASE + 0x0d) +#define IT8XXX2_ECPM_SCDCR2 ECREG(IT8XXX2_ECPM_BASE + 0x0e) +#define IT8XXX2_ECPM_SCDCR3 ECREG(IT8XXX2_ECPM_BASE + 0x0f) +#define IT8XXX2_ECPM_SCDCR4 ECREG(IT8XXX2_ECPM_BASE + 0x10) + +/* + * The count number of the counter for 25 ms register. + * The 25 ms register is calculated by (count number *1.024 kHz). + */ + +#define I2C_CLK_LOW_TIMEOUT 255 /* ~=249 ms */ + +/** + * + * (1Cxxh) SMBus Interface (SMB) registers + * + */ +#define IT8XXX2_SMB_BASE 0x00F01C00 +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 +#define IT8XXX2_SMB_4P7USL ECREG(IT8XXX2_SMB_BASE + 0x00) +#define IT8XXX2_SMB_4P0USL ECREG(IT8XXX2_SMB_BASE + 0x01) +#define IT8XXX2_SMB_300NS ECREG(IT8XXX2_SMB_BASE + 0x02) +#define IT8XXX2_SMB_250NS ECREG(IT8XXX2_SMB_BASE + 0x03) +#define IT8XXX2_SMB_25MS ECREG(IT8XXX2_SMB_BASE + 0x04) +#define IT8XXX2_SMB_45P3USL ECREG(IT8XXX2_SMB_BASE + 0x05) +#define IT8XXX2_SMB_45P3USH ECREG(IT8XXX2_SMB_BASE + 0x06) +#define IT8XXX2_SMB_4P7A4P0H ECREG(IT8XXX2_SMB_BASE + 0x07) +#define IT8XXX2_SMB_SLVISELR ECREG(IT8XXX2_SMB_BASE + 0x08) +#define IT8XXX2_SMB_SCLKTS(ch) ECREG(IT8XXX2_SMB_BASE + 0x09 + ch) +#define IT8XXX2_SMB_MSTFCTRL1 ECREG(IT8XXX2_SMB_BASE + 0x0D) +#define IT8XXX2_SMB_MSTFSTS1 ECREG(IT8XXX2_SMB_BASE + 0x0E) +#define IT8XXX2_SMB_MSTFCTRL2 ECREG(IT8XXX2_SMB_BASE + 0x0F) +#define IT8XXX2_SMB_MSTFSTS2 ECREG(IT8XXX2_SMB_BASE + 0x10) +#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x11) +#define IT8XXX2_SMB_I2CW2RF ECREG(IT8XXX2_SMB_BASE + 0x12) +#define IT8XXX2_SMB_IWRFISTA ECREG(IT8XXX2_SMB_BASE + 0x13) +#define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x20) +#define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x21) +#define IT8XXX2_SMB_SFFCTL ECREG(IT8XXX2_SMB_BASE + 0x55) +#define IT8XXX2_SMB_HOSTA(base) ECREG(base + 0x00) +#define IT8XXX2_SMB_HOCTL(base) ECREG(base + 0x01) +#define IT8XXX2_SMB_HOCMD(base) ECREG(base + 0x02) +#define IT8XXX2_SMB_TRASLA(base) ECREG(base + 0x03) +#define IT8XXX2_SMB_D0REG(base) ECREG(base + 0x04) +#define IT8XXX2_SMB_D1REG(base) ECREG(base + 0x05) +#define IT8XXX2_SMB_HOBDB(base) ECREG(base + 0x06) +#define IT8XXX2_SMB_PECERC(base) ECREG(base + 0x07) +#define IT8XXX2_SMB_SMBPCTL(base) ECREG(base + 0x0A) +#define IT8XXX2_SMB_HOCTL2(base) ECREG(base + 0x10) +#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 +#define IT8XXX2_SMB_SLVISEL ECREG(IT8XXX2_SMB_BASE + 0x08) +#define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x09) +#define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x0A) +#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x0B) +#define IT8XXX2_SMB_SCLKTS_BRGS ECREG(IT8XXX2_SMB_BASE + 0x80) +#define IT8XXX2_SMB_SCLKTS_BRGM ECREG(IT8XXX2_SMB_BASE + 0x81) +#define IT8XXX2_SMB_CHSBRG ECREG(IT8XXX2_SMB_BASE + 0x82) +#define IT8XXX2_SMB_CHSMOT ECREG(IT8XXX2_SMB_BASE + 0x83) + +/* SMBus register fields */ +/* 0x80: SMCLK Timing Setting Register Bridge Slave */ +#define IT8XXX2_SMB_PREDEN BIT(7) +#endif + +/** + * Enhanced SMBus/I2C Interface + * Ch_D: 0x00F03680, Ch_E: 0x00F03500, Ch_F: 0x00F03580 + * Ch_D: ch = 0x03, Ch_E: ch = 0x00, Ch_F: ch = 0x01 + */ +#define IT8XXX2_I2C_DRR(base) ECREG(base + 0x00) +#define IT8XXX2_I2C_PSR(base) ECREG(base + 0x01) +#define IT8XXX2_I2C_HSPR(base) ECREG(base + 0x02) +#define IT8XXX2_I2C_STR(base) ECREG(base + 0x03) +#define IT8XXX2_I2C_DHTR(base) ECREG(base + 0x04) +#define IT8XXX2_I2C_TOR(base) ECREG(base + 0x05) +#define IT8XXX2_I2C_DTR(base) ECREG(base + 0x08) +#define IT8XXX2_I2C_CTR(base) ECREG(base + 0x09) +#define IT8XXX2_I2C_CTR1(base) ECREG(base + 0x0A) +#define IT8XXX2_I2C_BYTE_CNT_H(base) ECREG(base + 0x0B) +#define IT8XXX2_I2C_BYTE_CNT_L(base) ECREG(base + 0x0C) +#define IT8XXX2_I2C_IRQ_ST(base) ECREG(base + 0x0D) +#define IT8XXX2_I2C_IDR(base) ECREG(base + 0x06) +#define IT8XXX2_I2C_TOS(base) ECREG(base + 0x07) +#define IT8XXX2_I2C_SLV_NUM_H(base) ECREG(base + 0x10) +#define IT8XXX2_I2C_SLV_NUM_L(base) ECREG(base + 0x11) +#define IT8XXX2_I2C_STR2(base) ECREG(base + 0x12) +#define IT8XXX2_I2C_NST(base) ECREG(base + 0x13) +#define IT8XXX2_I2C_TO_ARB_ST(base) ECREG(base + 0x18) +#define IT8XXX2_I2C_ERR_ST(base) ECREG(base + 0x19) +#define IT8XXX2_I2C_FST(base) ECREG(base + 0x1B) +#define IT8XXX2_I2C_EM(base) ECREG(base + 0x1C) +#define IT8XXX2_I2C_MODE_SEL(base) ECREG(base + 0x1D) +#define IT8XXX2_I2C_IDR2(base) ECREG(base + 0x1F) +#define IT8XXX2_I2C_CTR2(base) ECREG(base + 0x20) +#define IT8XXX2_I2C_RAMHA(base) ECREG(base + 0x23) +#define IT8XXX2_I2C_RAMLA(base) ECREG(base + 0x24) +#define IT8XXX2_I2C_RAMHA2(base) ECREG(base + 0x2C) +#define IT8XXX2_I2C_RAMLA2(base) ECREG(base + 0x2D) +#define IT8XXX2_I2C_CMD_ADDH(base) ECREG(base + 0x25) +#define IT8XXX2_I2C_CMD_ADDL(base) ECREG(base + 0x26) +#define IT8XXX2_I2C_RAMH2A(base) ECREG(base + 0x50) +#define IT8XXX2_I2C_CMD_ADDH2(base) ECREG(base + 0x52) + +/* SMBus/I2C register fields */ +/* 0x09-0xB: SMCLK Timing Setting */ +#define IT8XXX2_SMB_SMCLKS_1M 4 +#define IT8XXX2_SMB_SMCLKS_400K 3 +#define IT8XXX2_SMB_SMCLKS_100K 2 +#define IT8XXX2_SMB_SMCLKS_50K 1 + +/* 0x0E: SMBus FIFO Status 1 */ +#define IT8XXX2_SMB_FIFO1_EMPTY BIT(7) +#define IT8XXX2_SMB_FIFO1_FULL BIT(6) +/* 0x0D: SMBus FIFO Control 1 */ +/* 0x0F: SMBus FIFO Control 2 */ +#define IT8XXX2_SMB_BLKDS BIT(4) +#define IT8XXX2_SMB_FFEN BIT(3) +#define IT8XXX2_SMB_FFCHSEL2_B 0 +#define IT8XXX2_SMB_FFCHSEL2_C BIT(0) +/* 0x10: SMBus FIFO Status 2 */ +#define IT8XXX2_SMB_FIFO2_EMPTY BIT(7) +#define IT8XXX2_SMB_FIFO2_FULL BIT(6) +/* 0x12: I2C Wr To Rd FIFO */ +#define IT8XXX2_SMB_MAIF BIT(7) +#define IT8XXX2_SMB_MBCIF BIT(6) +#define IT8XXX2_SMB_MCIFI BIT(2) +#define IT8XXX2_SMB_MBIFI BIT(1) +#define IT8XXX2_SMB_MAIFI BIT(0) +/* 0x13: I2C Wr To Rd FIFO Interrupt Status */ +#define IT8XXX2_SMB_MCIFID BIT(2) +#define IT8XXX2_SMB_MAIFID BIT(0) +/* 0x41 0x81 0xC1: Host Control */ +#define IT8XXX2_SMB_SRT BIT(6) +#define IT8XXX2_SMB_LABY BIT(5) +#define IT8XXX2_SMB_SMCD_EXTND BIT(4) | BIT(3) | BIT(2) +#define IT8XXX2_SMB_KILL BIT(1) +#define IT8XXX2_SMB_INTREN BIT(0) +/* 0x43 0x83 0xC3: Transmit Slave Address */ +#define IT8XXX2_SMB_DIR BIT(0) +/* 0x4A 0x8A 0xCA: SMBus Pin Control */ +#define IT8XXX2_SMB_SMBDCS BIT(1) +#define IT8XXX2_SMB_SMBCS BIT(0) +/* 0x50 0x90 0xD0: Host Control 2 */ +#define IT8XXX2_SMB_SMD_TO_EN BIT(4) +#define IT8XXX2_SMB_I2C_SW_EN BIT(3) +#define IT8XXX2_SMB_I2C_SW_WAIT BIT(2) +#define IT8XXX2_SMB_I2C_EN BIT(1) +#define IT8XXX2_SMB_SMHEN BIT(0) +/* 0x55: Slave A FIFO Control */ +#define IT8XXX2_SMB_HSAPE BIT(1) +/* 0x03: Status Register */ +#define IT8XXX2_I2C_BYTE_DONE BIT(7) +#define IT8XXX2_I2C_RW BIT(2) +#define IT8XXX2_I2C_INT_PEND BIT(1) +/* 0x04: Data Hold Time */ +#define IT8XXX2_I2C_SOFT_RST BIT(7) +/* 0x07: Time Out Status */ +#define IT8XXX2_I2C_CLK_STRETCH BIT(7) +#define IT8XXX2_I2C_SCL_IN BIT(2) +#define IT8XXX2_I2C_SDA_IN BIT(0) +/* 0x09: Control Register */ +#define IT8XXX2_I2C_INT_EN BIT(6) +#define IT8XXX2_I2C_ACK BIT(3) +#define IT8XXX2_I2C_HALT BIT(0) +/* 0x0A: Control 1 */ +#define IT8XXX2_I2C_COMQ_EN BIT(7) +#define IT8XXX2_I2C_MDL_EN BIT(1) +/* 0x0C: Byte count */ +#define IT8XXX2_I2C_DMA_ADDR_RELOAD BIT(5) +#define IT8XXX2_I2C_BYTE_CNT_ENABLE BIT(3) +/* 0x0D: Interrupt Status */ +#define IT8XXX2_I2C_CNT_HOLD BIT(4) +#define IT8XXX2_I2C_IDW_CLR BIT(3) +#define IT8XXX2_I2C_IDR_CLR BIT(2) +#define IT8XXX2_I2C_SLVDATAFLG BIT(1) +#define IT8XXX2_I2C_P_CLR BIT(0) +/* 0x13: Nack Status */ +#define IT8XXX2_I2C_NST_CNS BIT(7) +#define IT8XXX2_I2C_NST_ID_NACK BIT(3) +/* 0x18: Timeout and Arbiter Status */ +#define IT8XXX2_I2C_SCL_TIMEOUT_EN BIT(7) +#define IT8XXX2_I2C_SDA_TIMEOUT_EN BIT(6) +/* 0x19: Error Status */ +#define IT8XXX2_I2C_ERR_ST_DEV1_EIRQ BIT(0) +/* 0x1B: Finish Status */ +#define IT8XXX2_I2C_FST_DEV1_IRQ BIT(4) +/* 0x1C: Error Mask */ +#define IT8XXX2_I2C_EM_DEV1_IRQ BIT(4) + +/* + * TODO: use gctrl_it8xxx2_regs instead of following register declarations + * to fix in cros_flash_it8xxx2.c, cros_shi_it8xxx2.c and tcpm\it8xxx2.c. + */ +/* --- General Control (GCTRL) --- */ +#define IT83XX_GCTRL_BASE 0x00F02000 + +#define IT83XX_GCTRL_CHIPID1 ECREG(IT83XX_GCTRL_BASE + 0x85) +#define IT83XX_GCTRL_CHIPID2 ECREG(IT83XX_GCTRL_BASE + 0x86) +#define IT83XX_GCTRL_CHIPVER ECREG(IT83XX_GCTRL_BASE + 0x02) +#define IT83XX_GCTRL_MCCR3 ECREG(IT83XX_GCTRL_BASE + 0x20) +#define IT83XX_GCTRL_SPISLVPFE BIT(6) +#define IT83XX_GCTRL_EWPR0PFH(i) ECREG(IT83XX_GCTRL_BASE + 0x60 + i) +#define IT83XX_GCTRL_EWPR0PFD(i) ECREG(IT83XX_GCTRL_BASE + 0xA0 + i) +#define IT83XX_GCTRL_EWPR0PFEC(i) ECREG(IT83XX_GCTRL_BASE + 0xC0 + i) + +/* + * TODO: use spisc_it8xxx2_regs instead of following register declarations + * to fix in cros_shi_it8xxx2.c. + */ +/* Serial Peripheral Interface (SPI) */ +#define IT83XX_SPI_BASE 0x00F03A00 + +#define IT83XX_SPI_SPISGCR ECREG(IT83XX_SPI_BASE + 0x00) +#define IT83XX_SPI_SPISCEN BIT(0) +#define IT83XX_SPI_TXRXFAR ECREG(IT83XX_SPI_BASE + 0x01) +#define IT83XX_SPI_CPURXF2A BIT(4) +#define IT83XX_SPI_CPURXF1A BIT(3) +#define IT83XX_SPI_CPUTFA BIT(1) +#define IT83XX_SPI_TXFCR ECREG(IT83XX_SPI_BASE + 0x02) +#define IT83XX_SPI_TXFCMR BIT(2) +#define IT83XX_SPI_TXFR BIT(1) +#define IT83XX_SPI_TXFS BIT(0) +#define IT83XX_SPI_GCR2 ECREG(IT83XX_SPI_BASE + 0x03) +#define IT83XX_SPI_RXF2OC BIT(4) +#define IT83XX_SPI_RXF1OC BIT(3) +#define IT83XX_SPI_RXFAR BIT(0) +#define IT83XX_SPI_IMR ECREG(IT83XX_SPI_BASE + 0x04) +#define IT83XX_SPI_RX_FIFO_FULL BIT(7) +#define IT83XX_SPI_RX_REACH BIT(5) +#define IT83XX_SPI_EDIM BIT(2) +#define IT83XX_SPI_ISR ECREG(IT83XX_SPI_BASE + 0x05) +#define IT83XX_SPI_TXFSR ECREG(IT83XX_SPI_BASE + 0x06) +#define IT83XX_SPI_ENDDETECTINT BIT(2) +#define IT83XX_SPI_RXFSR ECREG(IT83XX_SPI_BASE + 0x07) +#define IT83XX_SPI_RXFFSM (BIT(4) | BIT(3)) +#define IT83XX_SPI_RXF2FS BIT(2) +#define IT83XX_SPI_RXF1FS BIT(1) +#ifdef CHIP_VARIANT_IT83202BX +#define IT83XX_SPI_SPISRDR ECREG(IT83XX_SPI_BASE + 0x08) +#else +#define IT83XX_SPI_SPISRDR ECREG(IT83XX_SPI_BASE + 0x0b) +#endif +#define IT83XX_SPI_CPUWTFDB0 ECREG_u32(IT83XX_SPI_BASE + 0x08) +#define IT83XX_SPI_FCR ECREG(IT83XX_SPI_BASE + 0x09) +#define IT83XX_SPI_SPISRTXF BIT(2) +#define IT83XX_SPI_RXFR BIT(1) +#define IT83XX_SPI_RXFCMR BIT(0) +#define IT83XX_SPI_RXFRDRB0 ECREG_u32(IT83XX_SPI_BASE + 0x0C) +#define IT83XX_SPI_FTCB0R ECREG(IT83XX_SPI_BASE + 0x18) +#define IT83XX_SPI_FTCB1R ECREG(IT83XX_SPI_BASE + 0x19) +#define IT83XX_SPI_TCCB0 ECREG(IT83XX_SPI_BASE + 0x1A) +#define IT83XX_SPI_TCCB1 ECREG(IT83XX_SPI_BASE + 0x1B) +#define IT83XX_SPI_HPR2 ECREG(IT83XX_SPI_BASE + 0x1E) +#define IT83XX_SPI_EMMCBMR ECREG(IT83XX_SPI_BASE + 0x21) +#define IT83XX_SPI_EMMCABM BIT(1) /* eMMC Alternative Boot Mode */ +#define IT83XX_SPI_RX_VLISMR ECREG(IT83XX_SPI_BASE + 0x26) +#define IT83XX_SPI_RVLIM BIT(0) +#define IT83XX_SPI_RX_VLISR ECREG(IT83XX_SPI_BASE + 0x27) +#define IT83XX_SPI_RVLI BIT(0) + +/** + * + * (20xxh) General Control (GCTRL) registers + * + */ +#define GCTRL_IT8XXX2_REGS_BASE \ + ((struct gctrl_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gctrl))) + +#ifndef __ASSEMBLER__ +struct gctrl_it8xxx2_regs { + /* 0x00-0x01: Reserved_00_01 */ + volatile uint8_t reserved_00_01[2]; + /* 0x02: Chip Version */ + volatile uint8_t GCTRL_ECHIPVER; + /* 0x03-0x05: Reserved_03_05 */ + volatile uint8_t reserved_03_05[3]; + /* 0x06: Reset Status */ + volatile uint8_t GCTRL_RSTS; + /* 0x07-0x09: Reserved_07_09 */ + volatile uint8_t reserved_07_09[3]; + /* 0x0A: Base Address Select */ + volatile uint8_t GCTRL_BADRSEL; + /* 0x0B: Wait Next Clock Rising */ + volatile uint8_t GCTRL_WNCKR; + /* 0x0C: reserved_0c */ + volatile uint8_t reserved_0c; + /* 0x0D: Special Control 1 */ + volatile uint8_t GCTRL_SPCTRL1; + /* 0x0E-0x0F: reserved_0e_0f */ + volatile uint8_t reserved_0e_0f[2]; + /* 0x10: Reset Control DMM */ + volatile uint8_t GCTRL_RSTDMMC; + /* 0x11: Reset Control 4 */ + volatile uint8_t GCTRL_RSTC4; + /* 0x12-0x1B: reserved_12_1b */ + volatile uint8_t reserved_12_1b[10]; + /* 0x1C: Special Control 4 */ + volatile uint8_t GCTRL_SPCTRL4; + /* 0x1D-0x1F: reserved_1d_1f */ + volatile uint8_t reserved_1d_1f[3]; + /* 0x20: Memory Controller Configuration 3 */ + volatile uint8_t GCTRL_MCCR3; + /* 0x21: Reset Control 5 */ + volatile uint8_t GCTRL_RSTC5; + /* 0x22-0x2F: reserved_22_2f */ + volatile uint8_t reserved_22_2f[14]; + /* 0x30: Memory Controller Configuration */ + volatile uint8_t GCTRL_MCCR; + /* 0x31: Externel ILM/DLM Size */ + volatile uint8_t GCTRL_EIDSR; + /* 0x32: Reserved_32 */ + volatile uint8_t reserved_32; + /* 0x33: Pin Multi-function Enable 2 */ + volatile uint8_t gctrl_pmer2; + /* 0x34-0x36: Reserved_34_36 */ + volatile uint8_t reserved_34_36[3]; + /* 0x37: Eflash Protect Lock */ + volatile uint8_t GCTRL_EPLR; + /* 0x38-0x40: Reserved_38_40 */ + volatile uint8_t reserved_38_40[9]; + /* 0x41: Interrupt Vector Table Base Address */ + volatile uint8_t GCTRL_IVTBAR; + /* 0x42-0x43: Reserved_42_43 */ + volatile uint8_t reserved_42_43[2]; + /* 0x44: Memory Controller Configuration 2 */ + volatile uint8_t GCTRL_MCCR2; + /* 0x45: Reserved_45 */ + volatile uint8_t reserved_45; + /* 0x46: Pin Multi-function Enable 3 */ + volatile uint8_t GCTRL_PMER3; + /* 0x47-0x4A: reserved_47_4a */ + volatile uint8_t reserved_47_4a[4]; + /* 0x4B: ETWD and UART Control */ + volatile uint8_t GCTRL_ETWDUARTCR; + /* 0x4C: Wakeup MCU Control */ + volatile uint8_t GCTRL_WMCR; + /* 0x4D-0x4F: reserved_4d_4f */ + volatile uint8_t reserved_4d_4f[3]; + /* 0x50: Port 80h/81h Status Register */ + volatile uint8_t GCTRL_P80H81HSR; + /* 0x51: Port 80h Data Register */ + volatile uint8_t GCTRL_P80HDR; + /* 0x52: Port 81h Data Register */ + volatile uint8_t GCTRL_P81HDR; + /* 0x53: H2RAM Offset Register */ + volatile uint8_t GCTRL_H2ROFSR; + /* 0x54-0x5C: reserved_54_5c */ + volatile uint8_t reserved_54_5c[9]; + /* 0x5D: RISCV ILM Configuration 0 */ + volatile uint8_t GCTRL_RVILMCR0; + /* 0x5E-0x84: reserved_5e_84 */ + volatile uint8_t reserved_5e_84[39]; + /* 0x85: Chip ID Byte 1 */ + volatile uint8_t GCTRL_ECHIPID1; + /* 0x86: Chip ID Byte 2 */ + volatile uint8_t GCTRL_ECHIPID2; + /* 0x87: Chip ID Byte 3 */ + volatile uint8_t GCTRL_ECHIPID3; +}; +#endif /* !__ASSEMBLER__ */ + +/* GCTRL register fields */ +/* 0x06: Reset Status */ +#define IT8XXX2_GCTRL_LRS (BIT(1) | BIT(0)) +#define IT8XXX2_GCTRL_IWDTR BIT(1) +/* 0x10: Reset Control DMM */ +#define IT8XXX2_GCTRL_UART1SD BIT(3) +#define IT8XXX2_GCTRL_UART2SD BIT(2) +/* 0x11: Reset Control 4 */ +#define IT8XXX2_GCTRL_RPECI BIT(4) +#define IT8XXX2_GCTRL_RUART2 BIT(2) +#define IT8XXX2_GCTRL_RUART1 BIT(1) +/* 0x1C: Special Control 4 */ +#define IT8XXX2_GCTRL_LRSIWR BIT(2) +#define IT8XXX2_GCTRL_LRSIPWRSWTR BIT(1) +#define IT8XXX2_GCTRL_LRSIPGWR BIT(0) +/* 0x20: Memory Controller Configuration 3 */ +#define IT8XXX2_GCTRL_SPISLVPFE BIT(6) +/* 0x30: Memory Controller Configuration */ +#define IT8XXX2_GCTRL_ICACHE_RESET BIT(4) +/* 0x37: Eflash Protect Lock */ +#define IT8XXX2_GCTRL_EPLR_ENABLE BIT(0) +/* 0x46: Pin Multi-function Enable 3 */ +#define IT8XXX2_GCTRL_SMB3PSEL BIT(6) +/* 0x4B: ETWD and UART Control */ +#define IT8XXX2_GCTRL_ETWD_HW_RST_EN BIT(0) +/* 0x5D: RISCV ILM Configuration 0 */ +#define IT8XXX2_GCTRL_ILM0_ENABLE BIT(0) +/* Accept Port 80h Cycle */ +#define IT8XXX2_GCTRL_ACP80 BIT(6) +/* USB Debug Enable */ +#define IT8XXX2_GCTRL_MCCR_USB_EN BIT(7) +/* USB Pad Power-On Enable */ +#define IT8XXX2_GCTRL_PMER2_USB_PAD_EN BIT(7) + +/* + * VCC Detector Option. + * bit[7-6] = 1: The VCC power status is treated as power-on. + * The VCC supply of eSPI and related functions (EC2I, KBC, PMC and + * PECI). It means VCC should be logic high before using these + * functions, or firmware treats VCC logic high. + */ +#define IT8XXX2_GCTRL_VCCDO_MASK (BIT(6) | BIT(7)) +#define IT8XXX2_GCTRL_VCCDO_VCC_ON BIT(6) +/* + * bit[3] = 0: The reset source of PNPCFG is RSTPNP bit in RSTCH + * register and WRST#. + */ +#define IT8XXX2_GCTRL_HGRST BIT(3) +/* bit[2] = 1: Enable global reset. */ +#define IT8XXX2_GCTRL_GRST BIT(2) + +/** + * + * (22xxh) Battery-backed SRAM (BRAM) registers + * + */ +#ifndef __ASSEMBLER__ +/* Battery backed RAM indices. */ +#define BRAM_MAGIC_FIELD_OFFSET 0xbc +enum bram_indices { + + /* This field is used to indicate BRAM is valid or not. */ + BRAM_IDX_VALID_FLAGS0 = BRAM_MAGIC_FIELD_OFFSET, + BRAM_IDX_VALID_FLAGS1, + BRAM_IDX_VALID_FLAGS2, + BRAM_IDX_VALID_FLAGS3 +}; +#endif /* !__ASSEMBLER__ */ + +#ifndef __ASSEMBLER__ +/* + * EC2I bridge registers + */ +struct ec2i_regs { + /* 0x00: Indirect Host I/O Address Register */ + volatile uint8_t IHIOA; + /* 0x01: Indirect Host Data Register */ + volatile uint8_t IHD; + /* 0x02: Lock Super I/O Host Access Register */ + volatile uint8_t LSIOHA; + /* 0x03: Super I/O Access Lock Violation Register */ + volatile uint8_t SIOLV; + /* 0x04: EC to I-Bus Modules Access Enable Register */ + volatile uint8_t IBMAE; + /* 0x05: I-Bus Control Register */ + volatile uint8_t IBCTL; +}; + +/* Index list of the host interface registers of PNPCFG */ +enum host_pnpcfg_index { + /* Logical Device Number */ + HOST_INDEX_LDN = 0x07, + /* Chip ID Byte 1 */ + HOST_INDEX_CHIPID1 = 0x20, + /* Chip ID Byte 2 */ + HOST_INDEX_CHIPID2 = 0x21, + /* Chip Version */ + HOST_INDEX_CHIPVER = 0x22, + /* Super I/O Control */ + HOST_INDEX_SIOCTRL = 0x23, + /* Super I/O IRQ Configuration */ + HOST_INDEX_SIOIRQ = 0x25, + /* Super I/O General Purpose */ + HOST_INDEX_SIOGP = 0x26, + /* Super I/O Power Mode */ + HOST_INDEX_SIOPWR = 0x2D, + /* Depth 2 I/O Address */ + HOST_INDEX_D2ADR = 0x2E, + /* Depth 2 I/O Data */ + HOST_INDEX_D2DAT = 0x2F, + /* Logical Device Activate Register */ + HOST_INDEX_LDA = 0x30, + /* I/O Port Base Address Bits [15:8] for Descriptor 0 */ + HOST_INDEX_IOBAD0_MSB = 0x60, + /* I/O Port Base Address Bits [7:0] for Descriptor 0 */ + HOST_INDEX_IOBAD0_LSB = 0x61, + /* I/O Port Base Address Bits [15:8] for Descriptor 1 */ + HOST_INDEX_IOBAD1_MSB = 0x62, + /* I/O Port Base Address Bits [7:0] for Descriptor 1 */ + HOST_INDEX_IOBAD1_LSB = 0x63, + /* Interrupt Request Number and Wake-Up on IRQ Enabled */ + HOST_INDEX_IRQNUMX = 0x70, + /* Interrupt Request Type Select */ + HOST_INDEX_IRQTP = 0x71, + /* DMA Channel Select 0 */ + HOST_INDEX_DMAS0 = 0x74, + /* DMA Channel Select 1 */ + HOST_INDEX_DMAS1 = 0x75, + /* Device Specific Logical Device Configuration 1 to 10 */ + HOST_INDEX_DSLDC1 = 0xF0, + HOST_INDEX_DSLDC2 = 0xF1, + HOST_INDEX_DSLDC3 = 0xF2, + HOST_INDEX_DSLDC4 = 0xF3, + HOST_INDEX_DSLDC5 = 0xF4, + HOST_INDEX_DSLDC6 = 0xF5, + HOST_INDEX_DSLDC7 = 0xF6, + HOST_INDEX_DSLDC8 = 0xF7, + HOST_INDEX_DSLDC9 = 0xF8, + HOST_INDEX_DSLDC10 = 0xF9, +}; + +/* List of logical device number (LDN) assignments */ +enum logical_device_number { + /* Serial Port 1 */ + LDN_UART1 = 0x01, + /* Serial Port 2 */ + LDN_UART2 = 0x02, + /* System Wake-Up Control */ + LDN_SWUC = 0x04, + /* KBC/Mouse Interface */ + LDN_KBC_MOUSE = 0x05, + /* KBC/Keyboard Interface */ + LDN_KBC_KEYBOARD = 0x06, + /* Consumer IR */ + LDN_CIR = 0x0A, + /* Shared Memory/Flash Interface */ + LDN_SMFI = 0x0F, + /* RTC-like Timer */ + LDN_RTCT = 0x10, + /* Power Management I/F Channel 1 */ + LDN_PMC1 = 0x11, + /* Power Management I/F Channel 2 */ + LDN_PMC2 = 0x12, + /* Serial Peripheral Interface */ + LDN_SSPI = 0x13, + /* Platform Environment Control Interface */ + LDN_PECI = 0x14, + /* Power Management I/F Channel 3 */ + LDN_PMC3 = 0x17, + /* Power Management I/F Channel 4 */ + LDN_PMC4 = 0x18, + /* Power Management I/F Channel 5 */ + LDN_PMC5 = 0x19, +}; + +/* Structure for initializing PNPCFG via ec2i. */ +struct ec2i_t { + /* index port */ + enum host_pnpcfg_index index_port; + /* data port */ + uint8_t data_port; +}; + +/* EC2I access index/data port */ +enum ec2i_access { + /* index port */ + EC2I_ACCESS_INDEX = 0, + /* data port */ + EC2I_ACCESS_DATA = 1, +}; + +/* EC to I-Bus Access Enabled */ +#define EC2I_IBCTL_CSAE BIT(0) +/* EC Read from I-Bus */ +#define EC2I_IBCTL_CRIB BIT(1) +/* EC Write to I-Bus */ +#define EC2I_IBCTL_CWIB BIT(2) +#define EC2I_IBCTL_CRWIB (EC2I_IBCTL_CRIB | EC2I_IBCTL_CWIB) + +/* PNPCFG Register EC Access Enable */ +#define EC2I_IBMAE_CFGAE BIT(0) + +/* + * KBC registers + */ +struct kbc_regs { + /* 0x00: KBC Host Interface Control Register */ + volatile uint8_t KBHICR; + /* 0x01: Reserved1 */ + volatile uint8_t reserved1; + /* 0x02: KBC Interrupt Control Register */ + volatile uint8_t KBIRQR; + /* 0x03: Reserved2 */ + volatile uint8_t reserved2; + /* 0x04: KBC Host Interface Keyboard/Mouse Status Register */ + volatile uint8_t KBHISR; + /* 0x05: Reserved3 */ + volatile uint8_t reserved3; + /* 0x06: KBC Host Interface Keyboard Data Output Register */ + volatile uint8_t KBHIKDOR; + /* 0x07: Reserved4 */ + volatile uint8_t reserved4; + /* 0x08: KBC Host Interface Mouse Data Output Register */ + volatile uint8_t KBHIMDOR; + /* 0x09: Reserved5 */ + volatile uint8_t reserved5; + /* 0x0a: KBC Host Interface Keyboard/Mouse Data Input Register */ + volatile uint8_t KBHIDIR; +}; + +/* Output Buffer Full */ +#define KBC_KBHISR_OBF BIT(0) +/* Input Buffer Full */ +#define KBC_KBHISR_IBF BIT(1) +/* A2 Address (A2) */ +#define KBC_KBHISR_A2_ADDR BIT(3) +#define KBC_KBHISR_STS_MASK (KBC_KBHISR_OBF | KBC_KBHISR_IBF \ + | KBC_KBHISR_A2_ADDR) + +/* Clear Output Buffer Full */ +#define KBC_KBHICR_COBF BIT(6) +/* IBF/OBF Clear Mode Enable */ +#define KBC_KBHICR_IBFOBFCME BIT(5) +/* Input Buffer Full CPU Interrupt Enable */ +#define KBC_KBHICR_IBFCIE BIT(3) +/* Output Buffer Empty CPU Interrupt Enable */ +#define KBC_KBHICR_OBECIE BIT(2) +/* Output Buffer Full Mouse Interrupt Enable */ +#define KBC_KBHICR_OBFMIE BIT(1) +/* Output Buffer Full Keyboard Interrupt Enable */ +#define KBC_KBHICR_OBFKIE BIT(0) + +/* + * PMC registers + */ +struct pmc_regs { + /* 0x00: Host Interface PM Channel 1 Status */ + volatile uint8_t PM1STS; + /* 0x01: Host Interface PM Channel 1 Data Out Port */ + volatile uint8_t PM1DO; + /* 0x02: Host Interface PM Channel 1 Data Out Port with SCI# */ + volatile uint8_t PM1DOSCI; + /* 0x03: Host Interface PM Channel 1 Data Out Port with SMI# */ + volatile uint8_t PM1DOSMI; + /* 0x04: Host Interface PM Channel 1 Data In Port */ + volatile uint8_t PM1DI; + /* 0x05: Host Interface PM Channel 1 Data In Port with SCI# */ + volatile uint8_t PM1DISCI; + /* 0x06: Host Interface PM Channel 1 Control */ + volatile uint8_t PM1CTL; + /* 0x07: Host Interface PM Channel 1 Interrupt Control */ + volatile uint8_t PM1IC; + /* 0x08: Host Interface PM Channel 1 Interrupt Enable */ + volatile uint8_t PM1IE; + /* 0x09-0x0f: Reserved1 */ + volatile uint8_t reserved1[7]; + /* 0x10: Host Interface PM Channel 2 Status */ + volatile uint8_t PM2STS; + /* 0x11: Host Interface PM Channel 2 Data Out Port */ + volatile uint8_t PM2DO; + /* 0x12: Host Interface PM Channel 2 Data Out Port with SCI# */ + volatile uint8_t PM2DOSCI; + /* 0x13: Host Interface PM Channel 2 Data Out Port with SMI# */ + volatile uint8_t PM2DOSMI; + /* 0x14: Host Interface PM Channel 2 Data In Port */ + volatile uint8_t PM2DI; + /* 0x15: Host Interface PM Channel 2 Data In Port with SCI# */ + volatile uint8_t PM2DISCI; + /* 0x16: Host Interface PM Channel 2 Control */ + volatile uint8_t PM2CTL; + /* 0x17: Host Interface PM Channel 2 Interrupt Control */ + volatile uint8_t PM2IC; + /* 0x18: Host Interface PM Channel 2 Interrupt Enable */ + volatile uint8_t PM2IE; + /* 0x19: Mailbox Control */ + volatile uint8_t MBXCTRL; + /* 0x1a-0x1f: Reserved2 */ + volatile uint8_t reserved2[6]; + /* 0x20-0xff: Reserved3 */ + volatile uint8_t reserved3[0xe0]; +}; + +/* Input Buffer Full Interrupt Enable */ +#define PMC_PM1CTL_IBFIE BIT(0) +/* Output Buffer Full */ +#define PMC_PM1STS_OBF BIT(0) +/* Input Buffer Full */ +#define PMC_PM1STS_IBF BIT(1) +/* General Purpose Flag */ +#define PMC_PM1STS_GPF BIT(2) +/* A2 Address (A2) */ +#define PMC_PM1STS_A2_ADDR BIT(3) + +/* PMC2 Input Buffer Full Interrupt Enable */ +#define PMC_PM2CTL_IBFIE BIT(0) +/* General Purpose Flag */ +#define PMC_PM2STS_GPF BIT(2) + +/* + * Dedicated Interrupt + * 0b: + * INT3: PMC Output Buffer Empty Int + * INT25: PMC Input Buffer Full Int + * 1b: + * INT3: PMC1 Output Buffer Empty Int + * INT25: PMC1 Input Buffer Full Int + * INT26: PMC2 Output Buffer Empty Int + * INT27: PMC2 Input Buffer Full Int + */ +#define PMC_MBXCTRL_DINT BIT(5) + +/* + * eSPI slave registers + */ +struct espi_slave_regs { + /* 0x00-0x03: Reserved1 */ + volatile uint8_t reserved1[4]; + + /* 0x04: General Capabilities and Configuration 0 */ + volatile uint8_t GCAPCFG0; + /* 0x05: General Capabilities and Configuration 1 */ + volatile uint8_t GCAPCFG1; + /* 0x06: General Capabilities and Configuration 2 */ + volatile uint8_t GCAPCFG2; + /* 0x07: General Capabilities and Configuration 3 */ + volatile uint8_t GCAPCFG3; + + /* Channel 0 (Peripheral Channel) Capabilities and Configurations */ + /* 0x08: Channel 0 Capabilities and Configuration 0 */ + volatile uint8_t CH_PC_CAPCFG0; + /* 0x09: Channel 0 Capabilities and Configuration 1 */ + volatile uint8_t CH_PC_CAPCFG1; + /* 0x0A: Channel 0 Capabilities and Configuration 2 */ + volatile uint8_t CH_PC_CAPCFG2; + /* 0x0B: Channel 0 Capabilities and Configuration 3 */ + volatile uint8_t CH_PC_CAPCFG3; + + /* Channel 1 (Virtual Wire Channel) Capabilities and Configurations */ + /* 0x0C: Channel 1 Capabilities and Configuration 0 */ + volatile uint8_t CH_VW_CAPCFG0; + /* 0x0D: Channel 1 Capabilities and Configuration 1 */ + volatile uint8_t CH_VW_CAPCFG1; + /* 0x0E: Channel 1 Capabilities and Configuration 2 */ + volatile uint8_t CH_VW_CAPCFG2; + /* 0x0F: Channel 1 Capabilities and Configuration 3 */ + volatile uint8_t CH_VW_CAPCFG3; + + /* Channel 2 (OOB Message Channel) Capabilities and Configurations */ + /* 0x10: Channel 2 Capabilities and Configuration 0 */ + volatile uint8_t CH_OOB_CAPCFG0; + /* 0x11: Channel 2 Capabilities and Configuration 1 */ + volatile uint8_t CH_OOB_CAPCFG1; + /* 0x12: Channel 2 Capabilities and Configuration 2 */ + volatile uint8_t CH_OOB_CAPCFG2; + /* 0x13: Channel 2 Capabilities and Configuration 3 */ + volatile uint8_t CH_OOB_CAPCFG3; + + /* Channel 3 (Flash Access Channel) Capabilities and Configurations */ + /* 0x14: Channel 3 Capabilities and Configuration 0 */ + volatile uint8_t CH_FLASH_CAPCFG0; + /* 0x15: Channel 3 Capabilities and Configuration 1 */ + volatile uint8_t CH_FLASH_CAPCFG1; + /* 0x16: Channel 3 Capabilities and Configuration 2 */ + volatile uint8_t CH_FLASH_CAPCFG2; + /* 0x17: Channel 3 Capabilities and Configuration 3 */ + volatile uint8_t CH_FLASH_CAPCFG3; + /* Channel 3 Capabilities and Configurations 2 */ + /* 0x18: Channel 3 Capabilities and Configuration 2-0 */ + volatile uint8_t CH_FLASH_CAPCFG2_0; + /* 0x19: Channel 3 Capabilities and Configuration 2-1 */ + volatile uint8_t CH_FLASH_CAPCFG2_1; + /* 0x1A: Channel 3 Capabilities and Configuration 2-2 */ + volatile uint8_t CH_FLASH_CAPCFG2_2; + /* 0x1B: Channel 3 Capabilities and Configuration 2-3 */ + volatile uint8_t CH_FLASH_CAPCFG2_3; + + /* 0x1c-0x1f: Reserved2 */ + volatile uint8_t reserved2[4]; + /* 0x20-0x8f: Reserved3 */ + volatile uint8_t reserved3[0x70]; + + /* 0x90: eSPI PC Control 0 */ + volatile uint8_t ESPCTRL0; + /* 0x91: eSPI PC Control 1 */ + volatile uint8_t ESPCTRL1; + /* 0x92: eSPI PC Control 2 */ + volatile uint8_t ESPCTRL2; + /* 0x93: eSPI PC Control 3 */ + volatile uint8_t ESPCTRL3; + /* 0x94: eSPI PC Control 4 */ + volatile uint8_t ESPCTRL4; + /* 0x95: eSPI PC Control 5 */ + volatile uint8_t ESPCTRL5; + /* 0x96: eSPI PC Control 6 */ + volatile uint8_t ESPCTRL6; + /* 0x97: eSPI PC Control 7 */ + volatile uint8_t ESPCTRL7; + /* 0x98-0x9f: Reserved4 */ + volatile uint8_t reserved4[8]; + + /* 0xa0: eSPI General Control 0 */ + volatile uint8_t ESGCTRL0; + /* 0xa1: eSPI General Control 1 */ + volatile uint8_t ESGCTRL1; + /* 0xa2: eSPI General Control 2 */ + volatile uint8_t ESGCTRL2; + /* 0xa3: eSPI General Control 3 */ + volatile uint8_t ESGCTRL3; + /* 0xa4-0xaf: Reserved5 */ + volatile uint8_t reserved5[12]; + + /* 0xb0: eSPI Upstream Control 0 */ + volatile uint8_t ESUCTRL0; + /* 0xb1: eSPI Upstream Control 1 */ + volatile uint8_t ESUCTRL1; + /* 0xb2: eSPI Upstream Control 2 */ + volatile uint8_t ESUCTRL2; + /* 0xb3: eSPI Upstream Control 3 */ + volatile uint8_t ESUCTRL3; + /* 0xb4-0xb5: Reserved6 */ + volatile uint8_t reserved6[2]; + /* 0xb6: eSPI Upstream Control 6 */ + volatile uint8_t ESUCTRL6; + /* 0xb7: eSPI Upstream Control 7 */ + volatile uint8_t ESUCTRL7; + /* 0xb8: eSPI Upstream Control 8 */ + volatile uint8_t ESUCTRL8; + /* 0xb9-0xbf: Reserved7 */ + volatile uint8_t reserved7[7]; + + /* 0xc0: eSPI OOB Control 0 */ + volatile uint8_t ESOCTRL0; + /* 0xc1: eSPI OOB Control 1 */ + volatile uint8_t ESOCTRL1; + /* 0xc2-0xc3: Reserved8 */ + volatile uint8_t reserved8[2]; + /* 0xc4: eSPI OOB Control 4 */ + volatile uint8_t ESOCTRL4; + /* 0xc5-0xcf: Reserved9 */ + volatile uint8_t reserved9[11]; + + /* 0xd0: eSPI SAFS Control 0 */ + volatile uint8_t ESPISAFSC0; + /* 0xd1: eSPI SAFS Control 1 */ + volatile uint8_t ESPISAFSC1; + /* 0xd2: eSPI SAFS Control 2 */ + volatile uint8_t ESPISAFSC2; + /* 0xd3: eSPI SAFS Control 3 */ + volatile uint8_t ESPISAFSC3; + /* 0xd4: eSPI SAFS Control 4 */ + volatile uint8_t ESPISAFSC4; + /* 0xd5: eSPI SAFS Control 5 */ + volatile uint8_t ESPISAFSC5; + /* 0xd6: eSPI SAFS Control 6 */ + volatile uint8_t ESPISAFSC6; + /* 0xd7: eSPI SAFS Control 7 */ + volatile uint8_t ESPISAFSC7; +}; + +/* + * eSPI VW registers + */ +struct espi_vw_regs { + /* 0x00-0x7f: VW index */ + volatile uint8_t VW_INDEX[0x80]; + /* 0x80-0x8f: Reserved1 */ + volatile uint8_t reserved1[0x10]; + /* 0x90: VW Contrl 0 */ + volatile uint8_t VWCTRL0; + /* 0x91: VW Contrl 1 */ + volatile uint8_t VWCTRL1; + /* 0x92: VW Contrl 2 */ + volatile uint8_t VWCTRL2; + /* 0x93: VW Contrl 3 */ + volatile uint8_t VWCTRL3; + /* 0x94: Reserved2 */ + volatile uint8_t reserved2; + /* 0x95: VW Contrl 5 */ + volatile uint8_t VWCTRL5; + /* 0x96: VW Contrl 6 */ + volatile uint8_t VWCTRL6; + /* 0x97: VW Contrl 7 */ + volatile uint8_t VWCTRL7; + /* 0x98-0x99: Reserved3 */ + volatile uint8_t reserved3[2]; +}; + +#define ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE 80 +/* + * eSPI Queue 0 registers + */ +struct espi_queue0_regs { + /* 0x00-0x3f: PUT_PC Data Byte 0-63 */ + volatile uint8_t PUT_PC_DATA[0x40]; + /* 0x40-0x7f: Reserved1 */ + volatile uint8_t reserved1[0x40]; + /* 0x80-0xcf: PUT_OOB Data Byte 0-79 */ + volatile uint8_t PUT_OOB_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE]; +}; + +/* + * eSPI Queue 1 registers + */ +struct espi_queue1_regs { + /* 0x00-0x4f: Upstream Data Byte 0-79 */ + volatile uint8_t UPSTREAM_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE]; + /* 0x50-0x7f: Reserved1 */ + volatile uint8_t reserved1[0x30]; + /* 0x80-0xbf: PUT_FLASH_NP Data Byte 0-63 */ + volatile uint8_t PUT_FLASH_NP_DATA[0x40]; +}; + +#endif /* !__ASSEMBLER__ */ + + +/** + * + * (3Axxh) SPI Slave Controller (SPISC) registers + * + */ +#ifndef __ASSEMBLER__ +struct spisc_it8xxx2_regs { + /* 0x00: SPI Slave General Control */ + volatile uint8_t SPISC_SPISGCR; + /* 0x01: Tx/Rx FIFO Access */ + volatile uint8_t SPISC_TXRXFAR; + /* 0x02: Tx FIFO Control */ + volatile uint8_t SPISC_TXFCR; + /* 0x03: SPI Slave General Control 2 */ + volatile uint8_t SPISC_SPISGCR2; + /* 0x04: Interrupt Mask */ + volatile uint8_t SPISC_IMR; + /* 0x05: Interrupt Status */ + volatile uint8_t SPISC_ISR; + /* 0x06: Tx FIFO Status */ + volatile uint8_t SPISC_TXFSR; + /* 0x07: Rx FIFO Status */ + volatile uint8_t SPISC_RXFSR; + /* 0x08: CPU Write Tx FIFO Data Byte0 */ + volatile uint8_t SPISC_CPUWTXFDB0R; + /* 0x09: FIFO Control / CPU Write Tx FIFO Data Byte1 */ + volatile uint8_t SPISC_FCR; + /* 0x0A: CPU Write Tx FIFO Data Byte2 */ + volatile uint8_t SPISC_CPUWTXFDB2R; + /* 0x0B: SPI Slave Response Data / CPU Write Tx FIFO Data Byte3 */ + volatile uint8_t SPISC_SPISRDR; + /* 0x0C: Rx FIFO Readout Data Byte0 */ + volatile uint8_t SPISC_RXFRDRB0; + /* 0x0D: Rx FIFO Readout Data Byte1 */ + volatile uint8_t SPISC_RXFRDRB1; + /* 0x0E: Rx FIFO Readout Data Byte2 */ + volatile uint8_t SPISC_RXFRDRB2; + /* 0x0F: Rx FIFO Readout Data Byte3 */ + volatile uint8_t SPISC_RXFRDRB3; + /* 0x10-0x17: Reserved1 */ + volatile uint8_t reserved1[8]; + /* 0x18: FIFO Target Count Byte0 */ + volatile uint8_t SPISC_FTCB0R; + /* 0x19: FIFO Target Count Byte1 */ + volatile uint8_t SPISC_FTCB1R; + /* 0x1A: Target Count Capture Byte0 */ + volatile uint8_t SPISC_TCCB0; + /* 0x1B: Target Count Capture Byte1 */ + volatile uint8_t SPISC_TCCB1; + /* 0x1C-0x1D: Reserved2 */ + volatile uint8_t reserved2[2]; + /* 0x1E: Hardware Parsing 2 */ + volatile uint8_t SPISC_HPR2; + /* 0x1F-0x25: Reserved3 */ + volatile uint8_t reserved3[7]; + /* 0x26: Rx Valid Length Interrupt Status Mask */ + volatile uint8_t SPISC_RXVLISMR; + /* 0x27: Rx Valid Length Interrupt Status */ + volatile uint8_t SPISC_RXVLISR; +}; +#endif /* !__ASSEMBLER__ */ + +/* SPISC register fields */ +/* 0x00: SPI Slave General Control */ +#define IT8XXX2_SPISC_SPISCEN BIT(0) +/* 0x01: Tx/Rx FIFO Access */ +#define IT8XXX2_SPISC_CPURXF1A BIT(3) +#define IT8XXX2_SPISC_CPUTFA BIT(1) +/* 0x02: Tx FIFO Control */ +#define IT8XXX2_SPISC_TXFCMR BIT(2) +#define IT8XXX2_SPISC_TXFR BIT(1) +#define IT8XXX2_SPISC_TXFS BIT(0) +/* 0x03: SPI Slave General Control 2 */ +#define IT8XXX2_SPISC_RXF2OC BIT(4) +#define IT8XXX2_SPISC_RXF1OC BIT(3) +#define IT8XXX2_SPISC_RXFAR BIT(0) +/* 0x04: Interrupt Mask */ +#define IT8XXX2_SPISC_EDIM BIT(2) +/* 0x06: Tx FIFO Status */ +#define IT8XXX2_SPISC_ENDDETECTINT BIT(2) +/* 0x09: FIFO Control */ +#define IT8XXX2_SPISC_SPISRTXF BIT(2) +#define IT8XXX2_SPISC_RXFR BIT(1) +#define IT8XXX2_SPISC_RXFCMR BIT(0) +/* 0x26: Rx Valid Length Interrupt Status Mask */ +#define IT8XXX2_SPISC_RVLIM BIT(0) +/* 0x27: Rx Valid Length Interrupt Status */ +#define IT8XXX2_SPISC_RVLI BIT(0) + +#endif /* CHIP_CHIPREGS_H */ diff --git a/soc/riscv/riscv-ite/common/pinctrl_soc.h b/soc/riscv/ite_ec/common/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-ite/common/pinctrl_soc.h rename to soc/riscv/ite_ec/common/pinctrl_soc.h diff --git a/soc/riscv/riscv-ite/common/policy.c b/soc/riscv/ite_ec/common/policy.c similarity index 100% rename from soc/riscv/riscv-ite/common/policy.c rename to soc/riscv/ite_ec/common/policy.c diff --git a/soc/riscv/riscv-ite/common/power.c b/soc/riscv/ite_ec/common/power.c similarity index 100% rename from soc/riscv/riscv-ite/common/power.c rename to soc/riscv/ite_ec/common/power.c diff --git a/soc/riscv/ite_ec/common/soc_common.h b/soc/riscv/ite_ec/common/soc_common.h new file mode 100644 index 00000000000..b7e0cdd5e55 --- /dev/null +++ b/soc/riscv/ite_ec/common/soc_common.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file configuration macros for riscv SOCs supporting the riscv + * privileged architecture specification + */ + +#ifndef __SOC_COMMON_H_ +#define __SOC_COMMON_H_ + +#include "chip_chipregs.h" + +#ifndef _ASMLANGUAGE + +#ifdef CONFIG_HAS_ITE_INTC +/* + * Save current interrupt state of soc-level into ier_setting[] with + * disabling interrupt. + */ +void ite_intc_save_and_disable_interrupts(void); +/* Restore interrupt state of soc-level from ier_setting[], use with care. */ +void ite_intc_restore_interrupts(void); + +extern void ite_intc_irq_enable(unsigned int irq); +extern void ite_intc_irq_disable(unsigned int irq); +extern uint8_t ite_intc_get_irq_num(void); +extern int ite_intc_irq_is_enable(unsigned int irq); +extern void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags); +extern void ite_intc_isr_clear(unsigned int irq); +void ite_intc_init(void); +bool ite_intc_no_irq(void); +#endif /* CONFIG_HAS_ITE_INTC */ + +#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M +void timer_5ms_one_shot(void); +#endif + +uint32_t chip_get_pll_freq(void); +void chip_pll_ctrl(enum chip_pll_mode mode); +void riscv_idle(enum chip_pll_mode mode, unsigned int key); + +#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING +void chip_permit_idle(void); +void chip_block_idle(void); +bool cpu_idle_not_allowed(void); +#endif + +#endif /* !_ASMLANGUAGE */ + +#endif /* __SOC_COMMON_H_ */ diff --git a/soc/riscv/riscv-ite/common/soc_common_irq.c b/soc/riscv/ite_ec/common/soc_common_irq.c similarity index 97% rename from soc/riscv/riscv-ite/common/soc_common_irq.c rename to soc/riscv/ite_ec/common/soc_common_irq.c index aff5fe0d4b5..d2625c2766d 100644 --- a/soc/riscv/riscv-ite/common/soc_common_irq.c +++ b/soc/riscv/ite_ec/common/soc_common_irq.c @@ -11,6 +11,8 @@ */ #include +#include + void arch_irq_enable(unsigned int irq) { if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { diff --git a/soc/riscv/riscv-ite/common/soc_dt.h b/soc/riscv/ite_ec/common/soc_dt.h similarity index 100% rename from soc/riscv/riscv-ite/common/soc_dt.h rename to soc/riscv/ite_ec/common/soc_dt.h diff --git a/soc/riscv/riscv-ite/common/soc_espi.h b/soc/riscv/ite_ec/common/soc_espi.h similarity index 100% rename from soc/riscv/riscv-ite/common/soc_espi.h rename to soc/riscv/ite_ec/common/soc_espi.h diff --git a/soc/riscv/ite_ec/common/soc_irq.S b/soc/riscv/ite_ec/common/soc_irq.S new file mode 100644 index 00000000000..ceb0f3afecb --- /dev/null +++ b/soc/riscv/ite_ec/common/soc_irq.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * common interrupt management code for riscv SOCs supporting the riscv + * privileged architecture specification + */ +#include +#include +#include +#include +#include + +/* exports */ +GTEXT(__soc_handle_irq) + +/* + * SOC-specific function to handle pending IRQ number generating the interrupt. + * Exception number is given as parameter via register a0. + * Jump to get_irq() function directly and return to caller by its + * ret instruction. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + j get_irq diff --git a/soc/riscv/riscv-ite/common/vector.S b/soc/riscv/ite_ec/common/vector.S similarity index 100% rename from soc/riscv/riscv-ite/common/vector.S rename to soc/riscv/ite_ec/common/vector.S diff --git a/soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt b/soc/riscv/ite_ec/it8xxx2/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/CMakeLists.txt rename to soc/riscv/ite_ec/it8xxx2/CMakeLists.txt diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202bx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202bx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202bx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202bx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202cx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202cx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81202cx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81202cx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302bx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302bx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302bx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302bx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302cx b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302cx similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it81302cx rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it81302cx diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82002aw b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82002aw rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82002aw diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82202ax b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82202ax similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82202ax rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82202ax diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82302ax b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82302ax similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it82302ax rename to soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it82302ax diff --git a/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series new file mode 100644 index 00000000000..0ed7358b631 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.series @@ -0,0 +1,59 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_ITE_IT8XXX2 + +config SOC_SERIES + default "it8xxx2" + +config RISCV_GP + default y + +config ARCH_HAS_CUSTOM_BUSY_WAIT + default y + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config SYS_CLOCK_TICKS_PER_SEC + default 4096 + +config UART_NS16550_WA_ISR_REENABLE_INTERRUPT + default y + depends on UART_NS16550 + +config FLASH_INIT_PRIORITY + default 0 + +config IT8XXX2_PLL_SEQUENCE_PRIORITY + int + default 1 + depends on SOC_IT8XXX2_PLL_FLASH_48M + +config VCMP_IT8XXX2_INIT_PRIORITY + default 91 if VCMP_IT8XXX2_WORKQUEUE + +config PINCTRL + default y + +config NUM_IRQS + default 185 + +config DYNAMIC_INTERRUPTS + default y + +config GEN_ISR_TABLES + default y + +config GEN_IRQ_START_VECTOR + default 0 + +config GEN_SW_ISR_TABLE + default y + +config RISCV_SOC_INTERRUPT_INIT + default y + +source "soc/riscv/ite_ec/it8xxx2/Kconfig.defconfig.it8*" + +endif # SOC_SERIES_ITE_IT8XXX2 diff --git a/soc/riscv/ite_ec/it8xxx2/Kconfig.series b/soc/riscv/ite_ec/it8xxx2/Kconfig.series new file mode 100644 index 00000000000..265bf855f12 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.series @@ -0,0 +1,13 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_ITE_IT8XXX2 + bool "ITE IT8XXX2 implementation" + #depends on RISCV + # RV32IAFC is an uncommon configuration which is not supported by + # default in most toolchains, causing link-time errors. + select CPU_HAS_FPU if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" || RISCV_ISA_EXT_M + select SOC_FAMILY_ITE_EC + select HAS_PM + help + Enable support for ITE IT8XXX2 diff --git a/soc/riscv/ite_ec/it8xxx2/Kconfig.soc b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc new file mode 100644 index 00000000000..d918318dfaa --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/Kconfig.soc @@ -0,0 +1,173 @@ +# Copyright (c) 2020 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +choice +prompt "ITE IT8XXX2 system implementation" +depends on SOC_SERIES_ITE_IT8XXX2 + +config SOC_IT8XXX2 + bool "ITE IT8XXX2 system implementation" + select RISCV + select ATOMIC_OPERATIONS_BUILTIN + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + # Workaround mul instruction bug, see: + # https://www.ite.com.tw/uploads/product_download/it81202-bx-chip-errata.pdf + select RISCV_ISA_EXT_M if !(SOC_IT81302_BX || SOC_IT81202_BX) + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select FLASH + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select HAS_FLASH_LOAD_OFFSET + +endchoice + +config SOC_IT8XXX2_REG_SET_V1 + bool + help + This option is selected by a variable of which soc, and will + determine the register for the IT81xx2 specification. + +config SOC_IT8XXX2_REG_SET_V2 + bool + help + This option is selected by a variable of which soc, and will + determine the register for the IT82xx2 specification. + +if SOC_IT8XXX2 + +choice IT8XXX2_SERIES + prompt "IT8XXX2 Series" + default SOC_IT81302_BX + +config SOC_IT81302_BX + bool "IT81302 BX version" + select SOC_IT8XXX2_REG_SET_V1 + +config SOC_IT81202_BX + bool "IT81202 BX version" + select SOC_IT8XXX2_REG_SET_V1 + +config SOC_IT81302_CX + bool "IT81302 CX version" + select SOC_IT8XXX2_REG_SET_V1 + +config SOC_IT81202_CX + bool "IT81202 CX version" + select SOC_IT8XXX2_REG_SET_V1 + +config SOC_IT82202_AX + bool "IT82202 AX version" + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + +config SOC_IT82302_AX + bool "IT82302 AX version" + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + +config SOC_IT82002_AW + bool "IT82002 AW version" + select SOC_IT8XXX2_REG_SET_V2 + select SOC_IT8XXX2_EC_BUS_24MHZ if !DT_HAS_ITE_IT82XX2_USB_ENABLED + +endchoice + +config SOC_IT8XXX2_PLL_FLASH_48M + bool "Flash frequency is 48MHz" + default y + help + Change frequency of PLL, CPU, and flash to 48MHz during initialization. + + Set n to use the default settings. + (PLL and CPU run at 48MHz, flash frequency is 16MHz) + +config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN + bool "The pins of GPIO group K and L aren't bonding with pad" + default y + help + On IT81202 (128-pins package), the pins of GPIO group K and L aren't + bonding with pad. So we configure these pins as internal pull-down + at default to prevent leakage current due to floating. + +config SOC_IT8XXX2_GPIO_H7_DEFAULT_OUTPUT_LOW + bool "The GPIOH7 isn't bonding with pad and is left floating internally" + default y + help + On IT81202/IT81302, the GPIOH7 isn't bonding with pad and is left + floating internally. We need to enable internal pull-down for the pin + to prevent leakage current, but IT81202/IT81302 doesn't have the + capability to pull it down. We can only set it as output low, + so we enable output low for it at initialization to prevent leakage. + +config SOC_IT8XXX2_CPU_IDLE_GATING + bool + help + This option determines whether the entering CPU idle mode can be + gated by individual drivers. When this option is disabled, CPU idle + mode is always permitted. + +config SOC_IT8XXX2_EC_BUS_24MHZ + bool "EC bus is 24MHz" + help + Raise EC bus to 24MHz (default is 8MHz). + This reduces read/write EC registers latency by 50%. + NOTE: There is limitation to enabling this config on it81xx2 series. + The clock_frequency of ite,it8xxx2-i2c node (i2c0, i2c1, and i2c2) will + be fixed at 400KHz. + +choice + prompt "Clock source for PLL reference clock" + +config SOC_IT8XXX2_INT_32K + bool "Use the +/-2.3% internal clock generator" + +config SOC_IT8XXX2_EXT_32K + bool "Use external 32.768 kHz clock source" + +endchoice + +config SOC_IT8XXX2_USE_ILM + bool + default y + help + If enabled, Instruction Local Memory (ILM) will be configured to execute + code placed in the .__ram_code section out of RAM. This consumes RAM in + blocks of 4 kilobytes, but performance of code in ILM is much more + predictable than executing from Flash directly, and some code (such as code + that writes to the internal Flash) must execute out of RAM. + +config SOC_IT8XXX2_EXCEPTIONS_IN_RAM + bool "Place exception handling code in RAM" + default y + select SOC_IT8XXX2_USE_ILM + help + Place exception handling (ISR entry/exit and related) code in ILM, which + has more reliable performance characteristics than executing directly from + Flash. This can significantly improve performance when under I-cache + pressure. + +config SOC_IT8XXX2_SHA256_HW_ACCELERATE + bool "HW SHA256 calculation" + help + IT8XXX2 HW support sha256 calculation, and its calculation is faster than FW. + We place SHA256 message, hash and key data (total 512bytes) in RAM. + If we enable this config, because HW limits, the sha256 data must place in + first 4KB of RAM. + +DT_CHOSEN_ZEPHYR_FLASH := zephyr,flash + +config SOC_IT8XXX2_FLASH_SIZE_BYTES + hex + default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_ZEPHYR_FLASH)) + help + Total size of writable flash. + +config ILM_MAX_SIZE + int "ILM Size in kB" + default 60 if SOC_IT81202_CX || SOC_IT81302_CX + default SRAM_SIZE + +endif # SOC_IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/__arithmetic.S b/soc/riscv/ite_ec/it8xxx2/__arithmetic.S similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/__arithmetic.S rename to soc/riscv/ite_ec/it8xxx2/__arithmetic.S diff --git a/soc/riscv/riscv-ite/it8xxx2/ilm.c b/soc/riscv/ite_ec/it8xxx2/ilm.c similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/ilm.c rename to soc/riscv/ite_ec/it8xxx2/ilm.c diff --git a/soc/riscv/riscv-ite/it8xxx2/ilm.h b/soc/riscv/ite_ec/it8xxx2/ilm.h similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/ilm.h rename to soc/riscv/ite_ec/it8xxx2/ilm.h diff --git a/soc/riscv/riscv-ite/it8xxx2/linker.ld b/soc/riscv/ite_ec/it8xxx2/linker.ld similarity index 100% rename from soc/riscv/riscv-ite/it8xxx2/linker.ld rename to soc/riscv/ite_ec/it8xxx2/linker.ld diff --git a/soc/riscv/ite_ec/it8xxx2/soc.c b/soc/riscv/ite_ec/it8xxx2/soc.c new file mode 100644 index 00000000000..c1ab2e13562 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/soc.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2020 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include +#include +#include +#include "ilm.h" +#include +#include "soc_espi.h" +#include + +/* + * This define gets the total number of USBPD ports available on the + * ITE EC chip from dtsi (include status disable). Both it81202 and + * it81302 support two USBPD ports. + */ +#define SOC_USBPD_ITE_PHY_PORT_COUNT \ +COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1)) + +/* + * This define gets the number of active USB Power Delivery (USB PD) + * ports in use on the ITE microcontroller from dts (only status okay). + * The active port usage should follow the order of ITE TCPC port index, + * ex. if we're active only one ITE USB PD port, then the port should be + * 0x3700 (port0 register base), instead of 0x3800 (port1 register base). + */ +#define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd) + +uint32_t chip_get_pll_freq(void) +{ + uint32_t pllfreq; + + switch (IT8XXX2_ECPM_PLLFREQR & 0x0F) { + case 0: + pllfreq = MHZ(8); + break; + case 1: + pllfreq = MHZ(16); + break; + case 2: + pllfreq = MHZ(24); + break; + case 3: + pllfreq = MHZ(32); + break; + case 4: + pllfreq = MHZ(48); + break; + case 5: + pllfreq = MHZ(64); + break; + case 6: + pllfreq = MHZ(72); + break; + case 7: + pllfreq = MHZ(96); + break; + default: + return -ERANGE; + } + + return pllfreq; +} + +void __soc_ram_code chip_pll_ctrl(enum chip_pll_mode mode) +{ + volatile uint8_t _pll_ctrl __unused; + + IT8XXX2_ECPM_PLLCTRL = mode; + /* + * for deep doze / sleep mode + * This load operation will ensure PLL setting is taken into + * control register before wait for interrupt instruction. + */ + _pll_ctrl = IT8XXX2_ECPM_PLLCTRL; +} + +#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M +struct pll_config_t { + uint8_t pll_freq; + uint8_t div_fnd; + uint8_t div_uart; + uint8_t div_smb; + uint8_t div_sspi; + uint8_t div_ec; + uint8_t div_jtag; + uint8_t div_pwm; + uint8_t div_usbpd; +}; + +static const struct pll_config_t pll_configuration[] = { + /* + * PLL frequency setting = 4 (48MHz) + * FND div = 0 (PLL / 1 = 48 mhz) + * UART div = 1 (PLL / 2 = 24 mhz) + * SMB div = 1 (PLL / 2 = 24 mhz) + * SSPI div = 1 (PLL / 2 = 24 mhz) + * EC div = 6 (FND / 6 = 8 mhz) + * JTAG div = 1 (PLL / 2 = 24 mhz) + * PWM div = 0 (PLL / 1 = 48 mhz) + * USBPD div = 5 (PLL / 6 = 8 mhz) + */ + {.pll_freq = 4, + .div_fnd = 0, + .div_uart = 1, + .div_smb = 1, + .div_sspi = 1, +#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ + .div_ec = 1, +#else + .div_ec = 6, +#endif + .div_jtag = 1, + .div_pwm = 0, + .div_usbpd = 5} +}; + +void __soc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll) +{ + /* Enable HW timer to wakeup chip from the sleep mode */ + timer_5ms_one_shot(); + /* + * Configure PLL clock dividers. + * Writing data to these registers doesn't change the + * PLL frequency immediately until the status is changed + * into wakeup from the sleep mode. + * The following code is intended to make the system + * enter sleep mode, and wait HW timer to wakeup chip to + * complete PLL update. + */ + IT8XXX2_ECPM_PLLFREQR = pll->pll_freq; + /* Pre-set FND clock frequency = PLL / 3 */ + IT8XXX2_ECPM_SCDCR0 = (2 << 4); + /* JTAG and EC */ + IT8XXX2_ECPM_SCDCR3 = (pll->div_jtag << 4) | pll->div_ec; + /* Chip sleep after wait for interrupt (wfi) instruction */ + chip_pll_ctrl(CHIP_PLL_SLEEP); + /* Chip sleep and wait timer wake it up */ + __asm__ volatile ("wfi"); + /* New FND clock frequency */ + IT8XXX2_ECPM_SCDCR0 = pll->div_fnd << 4; + /* Chip doze after wfi instruction */ + chip_pll_ctrl(CHIP_PLL_DOZE); + /* UART */ + IT8XXX2_ECPM_SCDCR1 = pll->div_uart; + /* SSPI and SMB */ + IT8XXX2_ECPM_SCDCR2 = (pll->div_sspi << 4) | pll->div_smb; + /* USBPD and PWM */ + IT8XXX2_ECPM_SCDCR4 = (pll->div_usbpd << 4) | pll->div_pwm; +} + +static void chip_configure_pll(const struct pll_config_t *pll) +{ + /* Re-configure PLL clock or not. */ + if (((IT8XXX2_ECPM_PLLFREQR & 0xf) != pll->pll_freq) || + ((IT8XXX2_ECPM_SCDCR0 & 0xf0) != (pll->div_fnd << 4)) || + ((IT8XXX2_ECPM_SCDCR3 & 0xf) != pll->div_ec)) { +#ifdef CONFIG_ESPI + /* + * We have to disable eSPI pad before changing + * PLL sequence or sequence will fail if CS# pin is low. + */ + espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, false); +#endif + /* Run change PLL sequence */ + chip_run_pll_sequence(pll); +#ifdef CONFIG_ESPI + /* Enable eSPI pad after changing PLL sequence */ + espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, true); +#endif + } +} + +static int chip_change_pll(void) +{ + + if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { + ite_intc_save_and_disable_interrupts(); + } + /* configure PLL/CPU/flash clock */ + chip_configure_pll(&pll_configuration[0]); + if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { + ite_intc_restore_interrupts(); + } + + return 0; +} +SYS_INIT(chip_change_pll, PRE_KERNEL_1, CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY); +BUILD_ASSERT(CONFIG_FLASH_INIT_PRIORITY < CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY, + "CONFIG_FLASH_INIT_PRIORITY must be less than CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY"); +#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */ + +#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING +/* Preventing CPU going into idle mode during command queue. */ +static atomic_t cpu_idle_disabled; + +void chip_permit_idle(void) +{ + atomic_dec(&cpu_idle_disabled); +} + +void chip_block_idle(void) +{ + atomic_inc(&cpu_idle_disabled); +} + +bool cpu_idle_not_allowed(void) +{ + return !!(atomic_get(&cpu_idle_disabled)); +} +#endif + +/* The routine must be called with interrupts locked */ +void riscv_idle(enum chip_pll_mode mode, unsigned int key) +{ + /* + * The routine is called with interrupts locked (in kernel/idle()). + * But on kernel/context test_kernel_cpu_idle test, the routine will be + * called without interrupts locked. Hence we disable M-mode external + * interrupt here to protect the below content. + */ + csr_clear(mie, MIP_MEIP); + sys_trace_idle(); +#ifdef CONFIG_ESPI + /* + * H2RAM feature requires RAM clock to be active. Since the below doze + * mode will disable CPU and RAM clocks, enable eSPI transaction + * interrupt to restore clocks. With this interrupt, EC will not defer + * eSPI bus while transaction is accepted. + */ + espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, true); +#endif + /* Chip doze after wfi instruction */ + chip_pll_ctrl(mode); + + do { + /* Wait for interrupt */ + __asm__ volatile ("wfi"); + /* + * Sometimes wfi instruction may fail due to CPU's MTIP@mip + * register is non-zero. + * If the ite_intc_no_irq() is true at this point, + * it means that EC waked-up by the above issue not an + * interrupt. Hence we loop running wfi instruction here until + * wfi success. + */ + } while (ite_intc_no_irq()); + +#ifdef CONFIG_ESPI + /* CPU has been woken up, the interrupt is no longer needed */ + espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, false); +#endif + /* + * Enable M-mode external interrupt + * An interrupt can not be fired yet until we enable global interrupt + */ + csr_set(mie, MIP_MEIP); + /* Restore global interrupt lockout state */ + irq_unlock(key); +} + +void arch_cpu_idle(void) +{ +#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING + /* + * The EC processor(CPU) cannot be in the k_cpu_idle() during + * the transactions with the CQ mode(DMA mode). Otherwise, + * the EC processor would be clock gated. + */ + if (cpu_idle_not_allowed()) { + /* Restore global interrupt lockout state */ + irq_unlock(MSTATUS_IEN); + } else +#endif + { + riscv_idle(CHIP_PLL_DOZE, MSTATUS_IEN); + } +} + +void arch_cpu_atomic_idle(unsigned int key) +{ + riscv_idle(CHIP_PLL_DOZE, key); +} + +static int ite_it8xxx2_init(void) +{ + struct gpio_it8xxx2_regs *const gpio_regs = GPIO_IT8XXX2_REG_BASE; + struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb0), disabled) + struct usb_it82xx2_regs *const usb_regs = USB_IT82XX2_REGS_BASE; + + usb_regs->port0_misc_control &= ~PULL_DOWN_EN; + usb_regs->port1_misc_control &= ~PULL_DOWN_EN; +#endif + + /* + * bit7: wake up CPU if it is in low power mode and + * an interrupt is pending. + */ + gctrl_regs->GCTRL_WMCR |= BIT(7); + + /* + * Disable this feature that can detect pre-define hardware + * target A through I2C0. This is for debugging use, so it + * can be disabled to avoid illegal access. + */ +#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 + IT8XXX2_SMB_SFFCTL &= ~IT8XXX2_SMB_HSAPE; +#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 + IT8XXX2_SMB_SCLKTS_BRGS &= ~IT8XXX2_SMB_PREDEN; + /* + * Setting this bit will disable EGAD pin output driving to avoid + * leakage when GPIO E1/E2 on it82002 are set to alternate function. + */ + IT8XXX2_EGPIO_EGCR |= IT8XXX2_EGPIO_EEPODD; +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) + /* UART1 board init */ + /* bit2: clocks to UART1 modules are not gated. */ + IT8XXX2_ECPM_CGCTRL3R &= ~BIT(2); + IT8XXX2_ECPM_AUTOCG &= ~BIT(6); + + /* bit3: UART1 belongs to the EC side. */ + gctrl_regs->GCTRL_RSTDMMC |= IT8XXX2_GCTRL_UART1SD; + /* reset UART before config it */ + gctrl_regs->GCTRL_RSTC4 = IT8XXX2_GCTRL_RUART1; + + /* switch UART1 on without hardware flow control */ + gpio_regs->GPIO_GCR1 |= IT8XXX2_GPIO_U1CTRL_SIN0_SOUT0_EN; + +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) */ + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) + /* UART2 board init */ + /* setting voltage 3.3v */ + gpio_regs->GPIO_GCR21 &= ~(IT8XXX2_GPIO_GPH1VS | IT8XXX2_GPIO_GPH2VS); + /* bit2: clocks to UART2 modules are not gated. */ + IT8XXX2_ECPM_CGCTRL3R &= ~BIT(2); + IT8XXX2_ECPM_AUTOCG &= ~BIT(5); + + /* bit3: UART2 belongs to the EC side. */ + gctrl_regs->GCTRL_RSTDMMC |= IT8XXX2_GCTRL_UART2SD; + /* reset UART before config it */ + gctrl_regs->GCTRL_RSTC4 = IT8XXX2_GCTRL_RUART2; + + /* switch UART2 on without hardware flow control */ + gpio_regs->GPIO_GCR1 |= IT8XXX2_GPIO_U2CTRL_SIN1_SOUT1_EN; + +#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) */ + +#if (SOC_USBPD_ITE_PHY_PORT_COUNT > 0) + int port; + + /* + * To prevent cc pins leakage, we disable board not active ITE + * TCPC port cc modules, then cc pins can be used as gpio if needed. + */ + for (port = SOC_USBPD_ITE_ACTIVE_PORT_COUNT; + port < SOC_USBPD_ITE_PHY_PORT_COUNT; port++) { + struct usbpd_it8xxx2_regs *base; + + if (port == 0) { + base = (struct usbpd_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(usbpd0)); + } else if (port == 1) { + base = (struct usbpd_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(usbpd1)); + } else { + /* Currently all ITE embedded pd chip support max two ports */ + break; + } + + /* Power down all CC, and disable CC voltage detector */ + base->CCGCR |= (IT8XXX2_USBPD_DISABLE_CC | + IT8XXX2_USBPD_DISABLE_CC_VOL_DETECTOR); + /* + * Disconnect CC analog module (ex.UP/RD/DET/TX/RX), and + * disconnect CC 5.1K to GND + */ + base->CCCSR |= (IT8XXX2_USBPD_CC2_DISCONNECT | + IT8XXX2_USBPD_CC2_DISCONNECT_5_1K_TO_GND | + IT8XXX2_USBPD_CC1_DISCONNECT | + IT8XXX2_USBPD_CC1_DISCONNECT_5_1K_TO_GND); + /* Disconnect CC 5V tolerant */ + base->CCPSR |= (IT8XXX2_USBPD_DISCONNECT_POWER_CC2 | + IT8XXX2_USBPD_DISCONNECT_POWER_CC1); + /* Dis-connect 5.1K dead battery resistor to CC */ + base->CCPSR |= (IT8XXX2_USBPD_DISCONNECT_5_1K_CC2_DB | + IT8XXX2_USBPD_DISCONNECT_5_1K_CC1_DB); + } +#endif /* (SOC_USBPD_ITE_PHY_PORT_COUNT > 0) */ + + return 0; +} +SYS_INIT(ite_it8xxx2_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/ite_ec/it8xxx2/soc.h b/soc/riscv/ite_ec/it8xxx2/soc.h new file mode 100644 index 00000000000..527152601d5 --- /dev/null +++ b/soc/riscv/ite_ec/it8xxx2/soc.h @@ -0,0 +1,12 @@ +#ifndef __RISCV_ITE_SOC_H_ +#define __RISCV_ITE_SOC_H_ +/* + * Copyright (c) 2020 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ +#include + + +#endif /* __RISCV_ITE_SOC_H_ */ diff --git a/soc/riscv/litex-vexriscv/CMakeLists.txt b/soc/riscv/litex-vexriscv/CMakeLists.txt deleted file mode 100644 index 9d100ea0e2a..00000000000 --- a/soc/riscv/litex-vexriscv/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# -# Copyright (c) 2018 - 2019 Antmicro -# -# SPDX-License-Identifier: Apache-2.0 -# - -zephyr_sources( - ../riscv-privileged/common/soc_irq.S - ../riscv-privileged/common/vector.S -) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/litex-vexriscv/Kconfig.defconfig b/soc/riscv/litex-vexriscv/Kconfig.defconfig deleted file mode 100644 index 9447948b567..00000000000 --- a/soc/riscv/litex-vexriscv/Kconfig.defconfig +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2018 - 2019 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -if SOC_RISCV32_LITEX_VEXRISCV - -config SOC - default "litex-vexriscv" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 100000000 - -config RISCV_HAS_CPU_IDLE - bool - -config RISCV_HAS_PLIC - bool - -config NUM_IRQS - default 12 - -endif # SOC_RISCV32_LITEX_VEXRISCV diff --git a/soc/riscv/litex-vexriscv/soc.h b/soc/riscv/litex-vexriscv/soc.h deleted file mode 100644 index b738deec771..00000000000 --- a/soc/riscv/litex-vexriscv/soc.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2018 - 2019 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV32_LITEX_VEXRISCV_SOC_H_ -#define __RISCV32_LITEX_VEXRISCV_SOC_H_ - -#include "../riscv-privileged/common/soc_common.h" -#include -#include - -#ifndef _ASMLANGUAGE -/* CSR access helpers */ - -static inline unsigned char litex_read8(unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH >= 8 - return sys_read8(addr); -#else -#error CSR data width less than 8 -#endif -} - -static inline unsigned short litex_read16(unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 - return (sys_read8(addr) << 8) - | sys_read8(addr + 0x4); -#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 16 - return sys_read16(addr); -#else -#error Unsupported CSR data width -#endif -} - -static inline unsigned int litex_read32(unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 - return (sys_read8(addr) << 24) - | (sys_read8(addr + 0x4) << 16) - | (sys_read8(addr + 0x8) << 8) - | sys_read8(addr + 0xc); -#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 32 - return sys_read32(addr); -#else -#error Unsupported CSR data width -#endif -} - -static inline uint64_t litex_read64(unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 - return (((uint64_t)sys_read8(addr)) << 56) - | ((uint64_t)sys_read8(addr + 0x4) << 48) - | ((uint64_t)sys_read8(addr + 0x8) << 40) - | ((uint64_t)sys_read8(addr + 0xc) << 32) - | ((uint64_t)sys_read8(addr + 0x10) << 24) - | ((uint64_t)sys_read8(addr + 0x14) << 16) - | ((uint64_t)sys_read8(addr + 0x18) << 8) - | (uint64_t)sys_read8(addr + 0x1c); -#elif CONFIG_LITEX_CSR_DATA_WIDTH == 32 - return ((uint64_t)sys_read32(addr) << 32) | (uint64_t)sys_read32(addr + 0x4); -#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 64 - return sys_read64(addr); -#else -#error Unsupported CSR data width -#endif -} - -static inline void litex_write8(unsigned char value, unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH >= 8 - sys_write8(value, addr); -#else -#error CSR data width less than 8 -#endif -} - -static inline void litex_write16(unsigned short value, unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 - sys_write8(value >> 8, addr); - sys_write8(value, addr + 0x4); -#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 16 - sys_write16(value, addr); -#else -#error Unsupported CSR data width -#endif -} - -static inline void litex_write32(unsigned int value, unsigned long addr) -{ -#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 - sys_write8(value >> 24, addr); - sys_write8(value >> 16, addr + 0x4); - sys_write8(value >> 8, addr + 0x8); - sys_write8(value, addr + 0xC); -#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 32 - sys_write32(value, addr); -#else -#error Unsupported CSR data width -#endif -} - -/* - * Operates on uint32_t values only - * Size is in bytes and meaningful are 1, 2 or 4 - * Address must be aligned to 4 bytes - */ -static inline void litex_write(uint32_t addr, uint32_t size, uint32_t value) -{ - switch (size) { - case 1: - litex_write8(value, addr); - break; - case 2: - litex_write16(value, addr); - break; - case 4: - litex_write32(value, addr); - break; - default: - break; - } -} - -/* - * Operates on uint32_t values only - * Size is in bytes and meaningful are 1, 2 or 4 - * Address must be aligned to 4 bytes - */ -static inline uint32_t litex_read(uint32_t addr, uint32_t size) -{ - switch (size) { - case 1: - return litex_read8(addr); - case 2: - return litex_read16(addr); - case 4: - return litex_read32(addr); - default: - return 0; - } -} - -#endif /* _ASMLANGUAGE */ - -#endif /* __RISCV32_LITEX_VEXRISCV_SOC_H_ */ diff --git a/soc/riscv/litex_vexriscv/CMakeLists.txt b/soc/riscv/litex_vexriscv/CMakeLists.txt new file mode 100644 index 00000000000..98386f6b57a --- /dev/null +++ b/soc/riscv/litex_vexriscv/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2018 - 2019 Antmicro +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources( + ../common/riscv-privileged/soc_irq.S + ../common/riscv-privileged/vector.S +) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/litex_vexriscv/Kconfig.defconfig b/soc/riscv/litex_vexriscv/Kconfig.defconfig new file mode 100644 index 00000000000..0088420459f --- /dev/null +++ b/soc/riscv/litex_vexriscv/Kconfig.defconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2018 - 2019 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RISCV32_LITEX_VEXRISCV + +config SOC + default "litex_vexriscv" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 100000000 + +config NUM_IRQS + default 12 + +endif # SOC_RISCV32_LITEX_VEXRISCV diff --git a/soc/riscv/litex-vexriscv/Kconfig.soc b/soc/riscv/litex_vexriscv/Kconfig.soc similarity index 100% rename from soc/riscv/litex-vexriscv/Kconfig.soc rename to soc/riscv/litex_vexriscv/Kconfig.soc diff --git a/soc/riscv/litex_vexriscv/soc.h b/soc/riscv/litex_vexriscv/soc.h new file mode 100644 index 00000000000..4334be4ec1c --- /dev/null +++ b/soc/riscv/litex_vexriscv/soc.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018 - 2019 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RISCV32_LITEX_VEXRISCV_SOC_H_ +#define __RISCV32_LITEX_VEXRISCV_SOC_H_ + +#include +#include + +#ifndef _ASMLANGUAGE +/* CSR access helpers */ + +static inline unsigned char litex_read8(unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH >= 8 + return sys_read8(addr); +#else +#error CSR data width less than 8 +#endif +} + +static inline unsigned short litex_read16(unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 + return (sys_read8(addr) << 8) + | sys_read8(addr + 0x4); +#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 16 + return sys_read16(addr); +#else +#error Unsupported CSR data width +#endif +} + +static inline unsigned int litex_read32(unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 + return (sys_read8(addr) << 24) + | (sys_read8(addr + 0x4) << 16) + | (sys_read8(addr + 0x8) << 8) + | sys_read8(addr + 0xc); +#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 32 + return sys_read32(addr); +#else +#error Unsupported CSR data width +#endif +} + +static inline uint64_t litex_read64(unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 + return (((uint64_t)sys_read8(addr)) << 56) + | ((uint64_t)sys_read8(addr + 0x4) << 48) + | ((uint64_t)sys_read8(addr + 0x8) << 40) + | ((uint64_t)sys_read8(addr + 0xc) << 32) + | ((uint64_t)sys_read8(addr + 0x10) << 24) + | ((uint64_t)sys_read8(addr + 0x14) << 16) + | ((uint64_t)sys_read8(addr + 0x18) << 8) + | (uint64_t)sys_read8(addr + 0x1c); +#elif CONFIG_LITEX_CSR_DATA_WIDTH == 32 + return ((uint64_t)sys_read32(addr) << 32) | (uint64_t)sys_read32(addr + 0x4); +#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 64 + return sys_read64(addr); +#else +#error Unsupported CSR data width +#endif +} + +static inline void litex_write8(unsigned char value, unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH >= 8 + sys_write8(value, addr); +#else +#error CSR data width less than 8 +#endif +} + +static inline void litex_write16(unsigned short value, unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 + sys_write8(value >> 8, addr); + sys_write8(value, addr + 0x4); +#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 16 + sys_write16(value, addr); +#else +#error Unsupported CSR data width +#endif +} + +static inline void litex_write32(unsigned int value, unsigned long addr) +{ +#if CONFIG_LITEX_CSR_DATA_WIDTH == 8 + sys_write8(value >> 24, addr); + sys_write8(value >> 16, addr + 0x4); + sys_write8(value >> 8, addr + 0x8); + sys_write8(value, addr + 0xC); +#elif CONFIG_LITEX_CSR_DATA_WIDTH >= 32 + sys_write32(value, addr); +#else +#error Unsupported CSR data width +#endif +} + +/* + * Operates on uint32_t values only + * Size is in bytes and meaningful are 1, 2 or 4 + * Address must be aligned to 4 bytes + */ +static inline void litex_write(uint32_t addr, uint32_t size, uint32_t value) +{ + switch (size) { + case 1: + litex_write8(value, addr); + break; + case 2: + litex_write16(value, addr); + break; + case 4: + litex_write32(value, addr); + break; + default: + break; + } +} + +/* + * Operates on uint32_t values only + * Size is in bytes and meaningful are 1, 2 or 4 + * Address must be aligned to 4 bytes + */ +static inline uint32_t litex_read(uint32_t addr, uint32_t size) +{ + switch (size) { + case 1: + return litex_read8(addr); + case 2: + return litex_read16(addr); + case 4: + return litex_read32(addr); + default: + return 0; + } +} + +#endif /* _ASMLANGUAGE */ + +#endif /* __RISCV32_LITEX_VEXRISCV_SOC_H_ */ diff --git a/soc/riscv/microchip_miv/CMakeLists.txt b/soc/riscv/microchip_miv/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/microchip_miv/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/microchip_miv/Kconfig b/soc/riscv/microchip_miv/Kconfig new file mode 100644 index 00000000000..46616636aa1 --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_MICROCHIP_MIV + bool + +if SOC_FAMILY_MICROCHIP_MIV + +config SOC_FAMILY + string + default "microchip_miv" + +source "soc/riscv/microchip_miv/*/Kconfig.soc" + +endif # SOC_FAMILY_MICROCHIP_MIV diff --git a/soc/riscv/microchip_miv/Kconfig.defconfig b/soc/riscv/microchip_miv/Kconfig.defconfig new file mode 100644 index 00000000000..2fe508bddba --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/microchip_miv/*/Kconfig.defconfig.series" diff --git a/soc/riscv/microchip_miv/Kconfig.soc b/soc/riscv/microchip_miv/Kconfig.soc new file mode 100644 index 00000000000..8677f1ba448 --- /dev/null +++ b/soc/riscv/microchip_miv/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/microchip_miv/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/miv/CMakeLists.txt b/soc/riscv/microchip_miv/miv/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/miv/CMakeLists.txt rename to soc/riscv/microchip_miv/miv/CMakeLists.txt diff --git a/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series new file mode 100644 index 00000000000..35f4365b02b --- /dev/null +++ b/soc/riscv/microchip_miv/miv/Kconfig.defconfig.series @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_MIV + +config SOC_SERIES + default "miv" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 4000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 30 + +config NUM_IRQS + default 42 + +endif # SOC_SERIES_MIV diff --git a/soc/riscv/microchip_miv/miv/Kconfig.series b/soc/riscv/microchip_miv/miv/Kconfig.series new file mode 100644 index 00000000000..9f348619624 --- /dev/null +++ b/soc/riscv/microchip_miv/miv/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV32_MIV implementation + +# Copyright (c) 2018 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_MIV + bool "Microchip Mi-V implementation" + select SOC_FAMILY_MICROCHIP_MIV + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + help + Enable support for Microchip Mi-V diff --git a/soc/riscv/microchip_miv/miv/Kconfig.soc b/soc/riscv/microchip_miv/miv/Kconfig.soc new file mode 100644 index 00000000000..0a48c2e0524 --- /dev/null +++ b/soc/riscv/microchip_miv/miv/Kconfig.soc @@ -0,0 +1,20 @@ +# RISCV32_MIV configuration options + +# Copyright (c) 2018 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Microchip Mi-V system implementation" + depends on SOC_SERIES_MIV + +config SOC_MIV + bool "Microchip Mi-V system implementation" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/riscv-privileged/mpfs/CMakeLists.txt b/soc/riscv/microchip_miv/polarfire/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/mpfs/CMakeLists.txt rename to soc/riscv/microchip_miv/polarfire/CMakeLists.txt diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series new file mode 100644 index 00000000000..53e88f1096e --- /dev/null +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# Copyright (c) 2020-2021 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_POLARFIRE + +config SOC_SERIES + default "polarfire" + +# MPFS should be configured so that the mtimer clock is 1MHz independent of the CPU clock... + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 13 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 186 + +config NUM_IRQS + default 186 + +endif # SOC_SERIES_POLARFIRE diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.series b/soc/riscv/microchip_miv/polarfire/Kconfig.series new file mode 100644 index 00000000000..59ec4dbdd7a --- /dev/null +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV64_MIV implementation + +# Copyright (c) 2018 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_POLARFIRE + bool "Microchip RV64 implementation" + select SOC_FAMILY_MICROCHIP_MIV + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + help + Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/microchip_miv/polarfire/Kconfig.soc b/soc/riscv/microchip_miv/polarfire/Kconfig.soc new file mode 100644 index 00000000000..101e8b4d029 --- /dev/null +++ b/soc/riscv/microchip_miv/polarfire/Kconfig.soc @@ -0,0 +1,30 @@ +# RISCV64_MIV Microchip Polarfire SOC configuration options + +# Copyright (c) 2020-2021 Microchip Technology Inc +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "Microchip Polarfire SOC implementation" + depends on SOC_SERIES_POLARFIRE + +config SOC_POLARFIRE + bool "Microchip MPFS system implementation" + select ATOMIC_OPERATIONS_BUILTIN + select RISCV_GP + select USE_SWITCH_SUPPORTED + select USE_SWITCH + select CPU_HAS_FPU + select SCHED_IPI_SUPPORTED + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice + +config MPFS_HAL + depends on SOC_POLARFIRE + bool "Microchip Polarfire SOC hardware abstracton layer" + select HAS_MPFS_HAL diff --git a/soc/riscv/riscv-privileged/neorv32/CMakeLists.txt b/soc/riscv/neorv32/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/CMakeLists.txt rename to soc/riscv/neorv32/CMakeLists.txt diff --git a/soc/riscv/neorv32/Kconfig.defconfig b/soc/riscv/neorv32/Kconfig.defconfig new file mode 100644 index 00000000000..bc37ea74727 --- /dev/null +++ b/soc/riscv/neorv32/Kconfig.defconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2021 Henrik Brix Andersen +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NEORV32 + +config SOC + default "neorv32" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if RISCV_MACHINE_TIMER + +config NUM_IRQS + default 32 + +config RISCV_GP + default y + +config SYSCON + default y + +config SERIAL_INIT_PRIORITY + default 55 + depends on SERIAL + +config ENTROPY_INIT_PRIORITY + default 55 + depends on ENTROPY_GENERATOR + +endif # SOC_NEORV32 diff --git a/soc/riscv/neorv32/Kconfig.soc b/soc/riscv/neorv32/Kconfig.soc new file mode 100644 index 00000000000..3155d1b7c31 --- /dev/null +++ b/soc/riscv/neorv32/Kconfig.soc @@ -0,0 +1,50 @@ +# Copyright (c) 2021 Henrik Brix Andersen +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NEORV32 + bool "NEORV32 Processor" + select RISCV + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_PRIVILEGED + help + Enable support for the NEORV32 Processor (SoC). + + The NEORV32 CPU implementation must have the following RISC-V ISA + extensions enabled in order to support Zephyr: + - M (Integer Multiplication and Division) + - Zicsr (Control and Status Register (CSR) Instructions) + + The following NEORV32 CPU ISA extensions are not currently supported + by Zephyr and can safely be disabled: + - A (Atomic Instructions) + - E (Embedded, only 16 integer registers) + - Zbb (Basic Bit Manipulation) + - Zfinx (Floating Point in Integer Registers) + +if SOC_NEORV32 + +config SOC_NEORV32_V1_8_6 + bool "v1.8.6" + # NEORV32 RISC-V ISA A extension implements only LR/SC, not AMO + select ATOMIC_OPERATIONS_C + +config SOC_NEORV32_VERSION + hex + default 0x01080600 if SOC_NEORV32_V1_8_6 + help + The targeted NEORV32 version as BCD-coded number. The format is + identical to that of the NEORV32 Machine implementation ID (mimpid) + register. + +config SOC_NEORV32_ISA_C + bool "RISC-V ISA Extension \"C\"" + select RISCV_ISA_EXT_C + help + Enable this if the NEORV32 CPU implementation supports the RISC-V ISA + "C" extension (Compressed Instructions). + +endif # SOC_NEORV32 diff --git a/soc/riscv/riscv-privileged/neorv32/linker.ld b/soc/riscv/neorv32/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/linker.ld rename to soc/riscv/neorv32/linker.ld diff --git a/soc/riscv/riscv-privileged/neorv32/reset.S b/soc/riscv/neorv32/reset.S similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/reset.S rename to soc/riscv/neorv32/reset.S diff --git a/soc/riscv/riscv-privileged/neorv32/soc.c b/soc/riscv/neorv32/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/soc.c rename to soc/riscv/neorv32/soc.c diff --git a/soc/riscv/neorv32/soc.h b/soc/riscv/neorv32/soc.h new file mode 100644 index 00000000000..a97daa0fc15 --- /dev/null +++ b/soc/riscv/neorv32/soc.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 Henrik Brix Andersen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RISCV_NEORV32_SOC_H +#define RISCV_NEORV32_SOC_H + +/* System information (SYSINFO) register offsets */ +#define NEORV32_SYSINFO_CLK 0x00U +#define NEORV32_SYSINFO_CPU 0x04U +#define NEORV32_SYSINFO_FEATURES 0x08U +#define NEORV32_SYSINFO_CACHE 0x0cU +#define NEORV32_SYSINFO_ISPACE_BASE 0xf0U +#define NEORV32_SYSINFO_IMEM_SIZE 0xf4U +#define NEORV32_SYSINFO_DSPACE_BASE 0xf8U +#define NEORV32_SYSINFO_DMEM_SIZE 0xfcU + +/* System information (SYSINFO) CPU register bits */ +#define NEORV32_SYSINFO_CPU_ZICSR BIT(0) +#define NEORV32_SYSINFO_CPU_ZIFENCEI BIT(1) +#define NEORV32_SYSINFO_CPU_ZMMUL BIT(2) +#define NEORV32_SYSINFO_CPU_ZBB BIT(3) +#define NEORV32_SYSINFO_CPU_ZFINX BIT(5) +#define NEORV32_SYSINFO_CPU_ZXSCNT BIT(6) +#define NEORV32_SYSINFO_CPU_ZXNOCNT BIT(7) +#define NEORV32_SYSINFO_CPU_PMP BIT(8) +#define NEORV32_SYSINFO_CPU_HPM BIT(9) +#define NEORV32_SYSINFO_CPU_DEBUGMODE BIT(10) +#define NEORV32_SYSINFO_CPU_FASTMUL BIT(30) +#define NEORV32_SYSINFO_CPU_FASTSHIFT BIT(31) + +/* System information (SYSINFO) FEATURES register bits */ +#define NEORV32_SYSINFO_FEATURES_BOOTLOADER BIT(0) +#define NEORV32_SYSINFO_FEATURES_MEM_EXT BIT(1) +#define NEORV32_SYSINFO_FEATURES_MEM_INT_IMEM BIT(2) +#define NEORV32_SYSINFO_FEATURES_MEM_INT_DMEM BIT(3) +#define NEORV32_SYSINFO_FEATURES_MEM_EXT_ENDIAN BIT(4) +#define NEORV32_SYSINFO_FEATURES_ICACHE BIT(5) +#define NEORV32_SYSINFO_FEATURES_OCD BIT(14) +#define NEORV32_SYSINFO_FEATURES_HW_RESET BIT(15) +#define NEORV32_SYSINFO_FEATURES_IO_GPIO BIT(16) +#define NEORV32_SYSINFO_FEATURES_IO_MTIME BIT(17) +#define NEORV32_SYSINFO_FEATURES_IO_UART0 BIT(18) +#define NEORV32_SYSINFO_FEATURES_IO_SPI BIT(19) +#define NEORV32_SYSINFO_FEATURES_IO_TWI BIT(20) +#define NEORV32_SYSINFO_FEATURES_IO_PWM BIT(21) +#define NEORV32_SYSINFO_FEATURES_IO_WDT BIT(22) +#define NEORV32_SYSINFO_FEATURES_IO_CFS BIT(23) +#define NEORV32_SYSINFO_FEATURES_IO_TRNG BIT(24) +#define NEORV32_SYSINFO_FEATURES_IO_SLINK BIT(25) +#define NEORV32_SYSINFO_FEATURES_IO_UART1 BIT(26) +#define NEORV32_SYSINFO_FEATURES_IO_NEOLED BIT(27) + +#endif /* RISCV_NEORV32_SOC_H */ diff --git a/soc/riscv/riscv-privileged/neorv32/soc_irq.S b/soc/riscv/neorv32/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/neorv32/soc_irq.S rename to soc/riscv/neorv32/soc_irq.S diff --git a/soc/riscv/nordic_nrf/CMakeLists.txt b/soc/riscv/nordic_nrf/CMakeLists.txt new file mode 100644 index 00000000000..6a5b10545ff --- /dev/null +++ b/soc/riscv/nordic_nrf/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/nordic_nrf/Kconfig b/soc/riscv/nordic_nrf/Kconfig new file mode 100644 index 00000000000..a39db4671d5 --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_NRF + bool + +if SOC_FAMILY_NRF + +config SOC_FAMILY + string + default "nordic_nrf" + +source "soc/riscv/nordic_nrf/common/Kconfig" + +source "soc/common/nordic_nrf/Kconfig.peripherals" +source "soc/riscv/nordic_nrf/*/Kconfig.soc" + +endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/Kconfig.defconfig b/soc/riscv/nordic_nrf/Kconfig.defconfig new file mode 100644 index 00000000000..cc3ec954985 --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig.defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_NRF + +source "soc/riscv/nordic_nrf/*/Kconfig.defconfig.series" +source "soc/riscv/nordic_nrf/common/Kconfig.defconfig" + +config BUILD_OUTPUT_HEX + default y + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 if NRF_GRTC_TIMER + default 32768 if NRF_RTC_TIMER + +endif # SOC_FAMILY_NRF diff --git a/soc/riscv/nordic_nrf/Kconfig.soc b/soc/riscv/nordic_nrf/Kconfig.soc new file mode 100644 index 00000000000..593d6f91769 --- /dev/null +++ b/soc/riscv/nordic_nrf/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/nordic_nrf/*/Kconfig.series" diff --git a/soc/riscv/nordic_nrf/common/CMakeLists.txt b/soc/riscv/nordic_nrf/common/CMakeLists.txt new file mode 100644 index 00000000000..806a295ea22 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_RISCV_CORE_NORDIC_VPR vpr) diff --git a/soc/riscv/nordic_nrf/common/Kconfig b/soc/riscv/nordic_nrf/common/Kconfig new file mode 100644 index 00000000000..610689ecc6d --- /dev/null +++ b/soc/riscv/nordic_nrf/common/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/nordic_nrf/common/vpr/Kconfig" diff --git a/soc/riscv/nordic_nrf/common/Kconfig.defconfig b/soc/riscv/nordic_nrf/common/Kconfig.defconfig new file mode 100644 index 00000000000..9beb943edb8 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/Kconfig.defconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if RISCV_CORE_NORDIC_VPR + +source "soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig" + +endif # RISCV_CORE_NORDIC_VPR diff --git a/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt b/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt new file mode 100644 index 00000000000..e0331bb8e0b --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_library() +zephyr_library_sources(soc_irq.S soc_irq.c vector.S) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/nordic_nrf/common/vpr/Kconfig b/soc/riscv/nordic_nrf/common/vpr/Kconfig new file mode 100644 index 00000000000..40a7d199c0c --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config RISCV_CORE_NORDIC_VPR + bool "RISC-V Nordic VPR core" + default y + depends on DT_HAS_NORDIC_VPR_ENABLED + depends on RISCV + select ATOMIC_OPERATIONS_C + select RISCV_ISA_RV32E + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_SOC_HAS_ISR_STACKING + select RISCV_SOC_CONTEXT_SAVE + help + Enable support for the RISC-V Nordic VPR core. diff --git a/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig b/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig new file mode 100644 index 00000000000..f0014455b3a --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/Kconfig.defconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CPU_PATH := $(dt_nodelabel_path,cpu) +CPU_ID := $(dt_node_reg_addr_int,$(CPU_PATH)) + +config RV_BOOT_HART + default $(CPU_ID) + +config RISCV_MCAUSE_EXCEPTION_MASK + default 0xFFF + +config RISCV_RESERVED_IRQ_ISR_TABLES_OFFSET + default 16 + +config GEN_IRQ_VECTOR_TABLE + default y + +choice IRQ_VECTOR_TABLE_TYPE + default IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS +endchoice + +config ARCH_SW_ISR_TABLE_ALIGN + default 64 + +config RISCV_ALWAYS_SWITCH_THROUGH_ECALL + default y if MULTITHREADING diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_context.h b/soc/riscv/nordic_nrf/common/vpr/soc_context.h new file mode 100644 index 00000000000..8cd0d1e5094 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_context.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ + +#define SOC_ESF_MEMBERS unsigned long minttresh +#define SOC_ESF_INIT 0 + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_CONTEXT_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_irq.S b/soc/riscv/nordic_nrf/common/vpr/soc_irq.S new file mode 100644 index 00000000000..0e9db48d9b4 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_irq.S @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* Exports */ +GTEXT(__soc_handle_irq) +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) + +/* + * No need to clear anything, pending bit is cleared by HW. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + ret + +SECTION_FUNC(exception.other, __soc_save_context) + csrr t0, 0x347 + sw t0, __soc_esf_t_minttresh_OFFSET(a0) + + ret + +SECTION_FUNC(exception.other, __soc_restore_context) + lw t0, __soc_esf_t_minttresh_OFFSET(a0) + csrw 0x347, t0 + + ret diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_irq.c b/soc/riscv/nordic_nrf/common/vpr/soc_irq.c new file mode 100644 index 00000000000..88655f6efa0 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_irq.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +void arch_irq_enable(unsigned int irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, true); +} + +void arch_irq_disable(unsigned int irq) +{ + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, irq, false); +} + +void arch_irq_priority_set(unsigned int irq, unsigned int prio) +{ + nrf_vpr_clic_int_priority_set(NRF_VPRCLIC, irq, prio); +} + +int arch_irq_is_enabled(unsigned int irq) +{ + return nrf_vpr_clic_int_enable_check(NRF_VPRCLIC, irq); +} diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h b/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h new file mode 100644 index 00000000000..d5b139111d0 --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_isr_stacking.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ + +#include + +#if !defined(_ASMLANGUAGE) + +#include + +#define VPR_CPU DT_INST(0, nordic_vpr) + +#if DT_PROP(VPR_CPU, nordic_bus_width) == 64 + +#define SOC_ISR_STACKING_ESF_DECLARE \ + struct __esf { \ + unsigned long s0; \ + unsigned long mstatus; \ + unsigned long tp; \ + struct soc_esf soc_context; \ + \ + unsigned long t2; \ + unsigned long ra; \ + unsigned long t0; \ + unsigned long t1; \ + unsigned long a4; \ + unsigned long a5; \ + unsigned long a2; \ + unsigned long a3; \ + unsigned long a0; \ + unsigned long a1; \ + unsigned long mepc; \ + unsigned long _mcause; \ + } __aligned(16); + +#else /* DT_PROP(VPR_CPU, nordic_bus_width) == 32 */ + +#define SOC_ISR_STACKING_ESF_DECLARE \ + struct __esf { \ + unsigned long s0; \ + unsigned long mstatus; \ + unsigned long tp; \ + struct soc_esf soc_context; \ + \ + unsigned long ra; \ + unsigned long t2; \ + unsigned long t1; \ + unsigned long t0; \ + unsigned long a5; \ + unsigned long a4; \ + unsigned long a3; \ + unsigned long a2; \ + unsigned long a1; \ + unsigned long a0; \ + unsigned long mepc; \ + unsigned long _mcause; \ + } __aligned(16); + +#endif /* DT_PROP(VPR_CPU, nordic_bus_width) == 64 */ + +#else /* _ASMLANGUAGE */ + +/* + * Size of the HW managed part of the ESF: + * sizeof(_mcause) + sizeof(_mepc) + */ +#define ESF_HW_SIZEOF (0x8) + +/* + * Size of the SW managed part of the ESF in case of exception + */ +#define ESF_SW_EXC_SIZEOF (__z_arch_esf_t_SIZEOF - ESF_HW_SIZEOF) + +/* + * Size of the SW managed part of the ESF in case of interrupt + * sizeof(__padding) + ... + sizeof(soc_context) + */ +#define ESF_SW_IRQ_SIZEOF (0x10) + +#define SOC_ISR_SW_STACKING \ + csrw mscratch, t0; \ + \ + csrr t0, mcause; \ + srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ + bnez t0, stacking_is_interrupt; \ + \ + csrrw t0, mscratch, zero; \ + \ + addi sp, sp, -ESF_SW_EXC_SIZEOF; \ + DO_CALLER_SAVED(sr); \ + j stacking_keep_going; \ + \ +stacking_is_interrupt: \ + addi sp, sp, -ESF_SW_IRQ_SIZEOF; \ + \ +stacking_keep_going: + +#define SOC_ISR_SW_UNSTACKING \ + csrr t0, mcause; \ + srli t0, t0, RISCV_MCAUSE_IRQ_POS; \ + bnez t0, unstacking_is_interrupt; \ + \ + DO_CALLER_SAVED(lr); \ + addi sp, sp, ESF_SW_EXC_SIZEOF; \ + j unstacking_keep_going; \ + \ +unstacking_is_interrupt: \ + addi sp, sp, ESF_SW_IRQ_SIZEOF; \ + \ +unstacking_keep_going: + +#endif /* _ASMLANGUAGE */ + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_ISR_STACKING_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h b/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h new file mode 100644 index 00000000000..92d91044e1a --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/soc_offsets.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ +#define SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ + +#define GEN_SOC_OFFSET_SYMS() GEN_OFFSET_SYM(soc_esf_t, minttresh) + +#endif /* SOC_RISCV_NORDIC_NRF_COMMON_VPR_SOC_OFFSETS_H_ */ diff --git a/soc/riscv/nordic_nrf/common/vpr/vector.S b/soc/riscv/nordic_nrf/common/vpr/vector.S new file mode 100644 index 00000000000..b8c6d97170c --- /dev/null +++ b/soc/riscv/nordic_nrf/common/vpr/vector.S @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Imports */ +GTEXT(__initialize) + +/* Exports */ +GTEXT(__start) + +SECTION_FUNC(vectors, __start) + /* Set mtvec.base (mtvec.mode is RO, no need to mask it). */ + la t0, _isr_wrapper + csrw mtvec, t0 + + /* Set mtvt. */ + la t0, _irq_vector_table + csrw 0x307, t0 + + /* Enable mstatus.mie */ + li t0, 0x1888 + csrw mstatus, t0 + + /* Call into Zephyr initialization. */ + tail __initialize diff --git a/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt b/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt new file mode 100644 index 00000000000..5b37b3a54d8 --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +# Ensure that image size aligns with 16 bytes so that MRAMC finalizes all writes +# for the image correctly +zephyr_linker_sources(SECTIONS SORT_KEY zzz_place_align_at_end align.ld) diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr new file mode 100644 index 00000000000..a36d24c72ae --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.nrf54h20_enga_cpuppr @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_NRF54H20_ENGA_CPUPPR + +config SOC + default "nrf54h20_enga_cpuppr" + +config NUM_IRQS + default 496 + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +endif # SOC_NRF54H20_ENGA_CPUPPR diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series new file mode 100644 index 00000000000..0f827fbe96b --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.defconfig.series @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NRF54HX + +rsource "Kconfig.defconfig.nrf54h*" + +config SOC_SERIES + default "nrf54h" + +DT_CHOSEN_Z_SRAM = zephyr,sram +DT_CHOSEN_Z_CODE = zephyr,code-partition + +config BUILD_OUTPUT_ADJUST_LMA + depends on !XIP + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_Z_CODE)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_SRAM))" + +endif # SOC_SERIES_NRF54HX diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.series b/soc/riscv/nordic_nrf/nrf54h/Kconfig.series new file mode 100644 index 00000000000..acb85b5623a --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NRF54HX + bool "Nordic Semiconductor nRF54H series MCU" + select SOC_FAMILY_NRF + select HAS_NRFX + select HAS_NORDIC_DRIVERS + help + Enable support for nRF54H MCU series diff --git a/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc b/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc new file mode 100644 index 00000000000..17a6dd667c6 --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/Kconfig.soc @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_NRF54H20 + bool "nRF54H20" + depends on SOC_SERIES_NRF54HX + +if SOC_NRF54H20 + +choice + prompt "nRF54Hx MCU Selection" + +config SOC_NRF54H20_ENGA_CPUPPR + bool "nRF54H20 ENGA CPUPPR" + select RISCV + +endchoice + +endif # SOC_NRF54H20 diff --git a/soc/riscv/nordic_nrf/nrf54h/align.ld b/soc/riscv/nordic_nrf/nrf54h/align.ld new file mode 100644 index 00000000000..0905aa7f7bc --- /dev/null +++ b/soc/riscv/nordic_nrf/nrf54h/align.ld @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA. + * SPDX-License-Identifier: Apache-2.0 + */ + +SECTION_PROLOGUE(.align16,,) +{ + . = (ALIGN(16) > 0 ? ALIGN(16) : 16) - 1; + BYTE(0); +} GROUP_LINK_IN(ROMABLE_REGION) diff --git a/soc/riscv/openisa_rv32m1/Kconfig.defconfig b/soc/riscv/openisa_rv32m1/Kconfig.defconfig index 3976c9940c5..52d652a061e 100644 --- a/soc/riscv/openisa_rv32m1/Kconfig.defconfig +++ b/soc/riscv/openisa_rv32m1/Kconfig.defconfig @@ -33,6 +33,9 @@ config RISCV_SOC_OFFSETS config RISCV_SOC_INTERRUPT_INIT default y +config RISCV_MCAUSE_EXCEPTION_MASK + default 0x1F + # We need to disable the watchdog out of reset, as it's enabled by # default. Use the WDOG_INIT hook for doing that. config WDOG_INIT diff --git a/soc/riscv/openisa_rv32m1/soc.c b/soc/riscv/openisa_rv32m1/soc.c index 2d99535bd9c..95edf0c5383 100644 --- a/soc/riscv/openisa_rv32m1/soc.c +++ b/soc/riscv/openisa_rv32m1/soc.c @@ -16,6 +16,8 @@ #include #endif +#include + #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL #include LOG_MODULE_REGISTER(soc); diff --git a/soc/riscv/openisa_rv32m1/soc.h b/soc/riscv/openisa_rv32m1/soc.h index 1b2643d0b66..75011d36283 100644 --- a/soc/riscv/openisa_rv32m1/soc.h +++ b/soc/riscv/openisa_rv32m1/soc.h @@ -94,8 +94,6 @@ static inline uint32_t rv32m1_intmux_line(unsigned int irq) return ((irq >> 8) & 0xff) - 1; } -void soc_interrupt_init(void); - #endif /* !_ASMLANGUAGE */ #if defined(CONFIG_SOC_OPENISA_RV32M1_RI5CY) diff --git a/soc/riscv/openisa_rv32m1/soc_irq.S b/soc/riscv/openisa_rv32m1/soc_irq.S index 23222ea2c70..d3059d2bd28 100644 --- a/soc/riscv/openisa_rv32m1/soc_irq.S +++ b/soc/riscv/openisa_rv32m1/soc_irq.S @@ -10,22 +10,12 @@ #include /* Exports */ -GTEXT(__soc_is_irq) GTEXT(__soc_handle_irq) #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE GTEXT(__soc_save_context) GTEXT(__soc_restore_context) #endif -/* - * Whether we're in an IRQ is bog-standard RISC-V on this SoC: - * yes if the top mcause bit is set, otherwise no. - */ -SECTION_FUNC(exception.other, __soc_is_irq) - csrr a0, mcause - srli a0, a0, 31 - ret - /* * With a0 == irq_num, this is equivalent to: * diff --git a/soc/riscv/openisa_rv32m1/soc_offsets.h b/soc/riscv/openisa_rv32m1/soc_offsets.h index 8e0efdc7d62..7e7ac08de78 100644 --- a/soc/riscv/openisa_rv32m1/soc_offsets.h +++ b/soc/riscv/openisa_rv32m1/soc_offsets.h @@ -11,6 +11,8 @@ #ifndef SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_ #define SOC_RISCV32_OPENISA_RV32M1_SOC_OFFSETS_H_ +#include + #ifdef CONFIG_SOC_OPENISA_RV32M1_RI5CY #ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE diff --git a/soc/riscv/openisa_rv32m1/soc_ri5cy.h b/soc/riscv/openisa_rv32m1/soc_ri5cy.h index 27ebcbe6f35..d9158935e08 100644 --- a/soc/riscv/openisa_rv32m1/soc_ri5cy.h +++ b/soc/riscv/openisa_rv32m1/soc_ri5cy.h @@ -40,21 +40,4 @@ #define RI5CY_PRIVLV 0xC10 #define RI5CY_MHARTID 0xF14 -/* - * Map from SoC-specific configuration to generic Zephyr macros. - * - * These are expected by the code in arch/, and must be provided for - * the kernel to work (or even build at all). - * - * Some of these may also apply to ZERO-RISCY; needs investigation. - */ - -/* - * Exception code mask. Use of the bottom five bits is a subset of - * what the standard allocates (which is XLEN-1 bits). - */ -#define SOC_MCAUSE_EXP_MASK 0x1F - -/* The ecall exception number. This is a standard value. */ -#define SOC_MCAUSE_ECALL_EXP 11 #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_RI5CY_H_ */ diff --git a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h index d5fa48297f7..43cd144823a 100644 --- a/soc/riscv/openisa_rv32m1/soc_zero_riscy.h +++ b/soc/riscv/openisa_rv32m1/soc_zero_riscy.h @@ -28,22 +28,4 @@ #define ZERO_RISCY_PCMR 0x7A1U #define ZERO_RISCY_MHARTID 0xF14U -/* - * Map from SoC-specific configuration to generic Zephyr macros. - * - * These are expected by the code in arch/, and must be provided for - * the kernel to work (or even build at all). - * - * Some of these may also apply to ZERO-RISCY; needs investigation. - */ - -/* - * Exception code mask. Use of the bottom five bits is a subset of - * what the standard allocates (which is XLEN-1 bits). - */ -#define SOC_MCAUSE_EXP_MASK 0x1F - -/* The ecall exception number. This is a standard value. */ -#define SOC_MCAUSE_ECALL_EXP 11 - #endif /* SOC_RISCV32_OPENISA_RV32M1_SOC_ZERO_RISCY_H_ */ diff --git a/soc/riscv/riscv-privileged/opentitan/CMakeLists.txt b/soc/riscv/opentitan/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/CMakeLists.txt rename to soc/riscv/opentitan/CMakeLists.txt diff --git a/soc/riscv/opentitan/Kconfig.defconfig b/soc/riscv/opentitan/Kconfig.defconfig new file mode 100644 index 00000000000..4b067ef76af --- /dev/null +++ b/soc/riscv/opentitan/Kconfig.defconfig @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Rivos Inc. +# SPDX-License-Identifier: Apache-2.0 + +if SOC_OPENTITAN + +config SOC + default "opentitan" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 1000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 32 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config NUM_IRQS + default 256 + +endif # SOC_OPENTITAN diff --git a/soc/riscv/opentitan/Kconfig.soc b/soc/riscv/opentitan/Kconfig.soc new file mode 100644 index 00000000000..c76cfe013b1 --- /dev/null +++ b/soc/riscv/opentitan/Kconfig.soc @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Rivos Inc. +# SPDX-License-Identifier: Apache-2.0 + +config SOC_OPENTITAN + bool "OpenTitan implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_ISA_EXT_ZBA + select RISCV_ISA_EXT_ZBB + select RISCV_ISA_EXT_ZBC + select RISCV_ISA_EXT_ZBS + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. + select RISCV_VECTORED_MODE + select GEN_IRQ_VECTOR_TABLE diff --git a/soc/riscv/riscv-privileged/opentitan/rom_header.S b/soc/riscv/opentitan/rom_header.S similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/rom_header.S rename to soc/riscv/opentitan/rom_header.S diff --git a/soc/riscv/riscv-privileged/opentitan/rom_header.ld b/soc/riscv/opentitan/rom_header.ld similarity index 100% rename from soc/riscv/riscv-privileged/opentitan/rom_header.ld rename to soc/riscv/opentitan/rom_header.ld diff --git a/soc/riscv/opentitan/soc.c b/soc/riscv/opentitan/soc.c new file mode 100644 index 00000000000..d627356c58f --- /dev/null +++ b/soc/riscv/opentitan/soc.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Rivos Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* OpenTitan power management regs. */ +#define PWRMGR_BASE (DT_REG_ADDR(DT_NODELABEL(pwrmgr))) +#define PWRMGR_CFG_CDC_SYNC_REG_OFFSET 0x018 +#define PWRMGR_RESET_EN_REG_OFFSET 0x02c +#define PWRMGR_RESET_EN_WDOG_SRC_MASK 0x002 + +/* Ibex timer registers. */ +#define RV_TIMER_BASE (DT_REG_ADDR(DT_NODELABEL(mtimer))) +#define RV_TIMER_CTRL_REG_OFFSET 0x004 +#define RV_TIMER_INTR_ENABLE_REG_OFFSET 0x100 +#define RV_TIMER_CFG0_REG_OFFSET 0x10c +#define RV_TIMER_CFG0_PRESCALE_MASK 0xfff +#define RV_TIMER_CFG0_PRESCALE_OFFSET 0 +#define RV_TIMER_CFG0_STEP_MASK 0xff +#define RV_TIMER_CFG0_STEP_OFFSET 16 +#define RV_TIMER_LOWER0_OFFSET 0x110 +#define RV_TIMER_COMPARE_LOWER0_OFFSET 0x118 + +static int soc_opentitan_init(void) +{ + /* Enable the watchdog reset (bit 1). */ + sys_write32(2u, PWRMGR_BASE + PWRMGR_RESET_EN_REG_OFFSET); + /* Write CFG_CDC_SYNC to commit change. */ + sys_write32(1u, PWRMGR_BASE + PWRMGR_CFG_CDC_SYNC_REG_OFFSET); + /* Poll CFG_CDC_SYNC register until it reads 0. */ + while (sys_read32(PWRMGR_BASE + PWRMGR_CFG_CDC_SYNC_REG_OFFSET)) { + } + + /* Initialize the Machine Timer, so it behaves as a regular one. */ + sys_write32(1u, RV_TIMER_BASE + RV_TIMER_CTRL_REG_OFFSET); + /* Enable timer interrupts. */ + sys_write32(1u, RV_TIMER_BASE + RV_TIMER_INTR_ENABLE_REG_OFFSET); + return 0; +} +SYS_INIT(soc_opentitan_init, PRE_KERNEL_1, 0); diff --git a/soc/riscv/renode_virt/CMakeLists.txt b/soc/riscv/renode_virt/CMakeLists.txt new file mode 100644 index 00000000000..56d36b84ec8 --- /dev/null +++ b/soc/riscv/renode_virt/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources() + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/renode_virt/Kconfig.defconfig b/soc/riscv/renode_virt/Kconfig.defconfig new file mode 100644 index 00000000000..fab59719595 --- /dev/null +++ b/soc/riscv/renode_virt/Kconfig.defconfig @@ -0,0 +1,42 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RISCV32_VIRTUAL_RENODE + +config SOC + default "renode_virt" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 4000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 1ST_LEVEL_INTERRUPT_BITS + default 4 + +config NUM_2ND_LEVEL_AGGREGATORS + default 2 + +config 2ND_LEVEL_INTERRUPT_BITS + default 11 + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config 2ND_LVL_INTR_01_OFFSET + default 4 + +config MAX_IRQ_PER_AGGREGATOR + default 1023 + +config NUM_IRQS + default 2058 + +endif # SOC_RISCV32_VIRTUAL_RENODE diff --git a/soc/riscv/renode_virt/Kconfig.soc b/soc/riscv/renode_virt/Kconfig.soc new file mode 100644 index 00000000000..ba42c40c28d --- /dev/null +++ b/soc/riscv/renode_virt/Kconfig.soc @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Meta +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RISCV32_VIRTUAL_RENODE + bool "Renode RISCV32 Virtual system implementation" + select RISCV + select RISCV_PRIVILEGED + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_HAS_PLIC diff --git a/soc/riscv/riscv-ite/Kconfig b/soc/riscv/riscv-ite/Kconfig deleted file mode 100644 index f25c53d1ffb..00000000000 --- a/soc/riscv/riscv-ite/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_RISCV_ITE - bool - help - omit prompt to signify a "hidden" option - -config SOC_FAMILY - string - default "riscv-ite" - depends on SOC_FAMILY_RISCV_ITE - -source "soc/riscv/riscv-ite/*/Kconfig.soc" diff --git a/soc/riscv/riscv-ite/Kconfig.defconfig b/soc/riscv/riscv-ite/Kconfig.defconfig deleted file mode 100644 index ae18beac098..00000000000 --- a/soc/riscv/riscv-ite/Kconfig.defconfig +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-ite/*/Kconfig.defconfig.series" diff --git a/soc/riscv/riscv-ite/Kconfig.soc b/soc/riscv/riscv-ite/Kconfig.soc deleted file mode 100644 index 925edb1543c..00000000000 --- a/soc/riscv/riscv-ite/Kconfig.soc +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-ite/*/Kconfig.series" diff --git a/soc/riscv/riscv-ite/common/chip_chipregs.h b/soc/riscv/riscv-ite/common/chip_chipregs.h deleted file mode 100644 index b1009e3eee5..00000000000 --- a/soc/riscv/riscv-ite/common/chip_chipregs.h +++ /dev/null @@ -1,2158 +0,0 @@ -/* - * Copyright (c) 2020 ITE Corporation. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef CHIP_CHIPREGS_H -#define CHIP_CHIPREGS_H - -#include - -#define EC_REG_BASE_ADDR 0x00f00000 - -#ifdef _ASMLANGUAGE -#define ECREG(x) x -#else - -/* - * Macros for hardware registers access. - */ -#define ECREG(x) (*((volatile unsigned char *)(x))) -#define ECREG_u16(x) (*((volatile unsigned short *)(x))) -#define ECREG_u32(x) (*((volatile unsigned long *)(x))) - -/* - * MASK operation macros - */ -#define SET_MASK(reg, bit_mask) ((reg) |= (bit_mask)) -#define CLEAR_MASK(reg, bit_mask) ((reg) &= (~(bit_mask))) -#define IS_MASK_SET(reg, bit_mask) (((reg) & (bit_mask)) != 0) -#endif /* _ASMLANGUAGE */ - -#ifndef REG_BASE_ADDR -#define REG_BASE_ADDR EC_REG_BASE_ADDR -#endif - -/* Common definition */ -/* - * EC clock frequency (PWM and tachometer driver need it to reply - * to api or calculate RPM) - */ -#define EC_FREQ MHZ(8) - - -/* --- General Control (GCTRL) --- */ -#define IT8XXX2_GCTRL_BASE 0x00F02000 -#define IT8XXX2_GCTRL_EIDSR ECREG(IT8XXX2_GCTRL_BASE + 0x31) - -/** - * - * (11xxh) Interrupt controller (INTC) - * - */ -#define ISR0 ECREG(EC_REG_BASE_ADDR + 0x3F00) -#define ISR1 ECREG(EC_REG_BASE_ADDR + 0x3F01) -#define ISR2 ECREG(EC_REG_BASE_ADDR + 0x3F02) -#define ISR3 ECREG(EC_REG_BASE_ADDR + 0x3F03) -#define ISR4 ECREG(EC_REG_BASE_ADDR + 0x3F14) -#define ISR5 ECREG(EC_REG_BASE_ADDR + 0x3F18) -#define ISR6 ECREG(EC_REG_BASE_ADDR + 0x3F1C) -#define ISR7 ECREG(EC_REG_BASE_ADDR + 0x3F20) -#define ISR8 ECREG(EC_REG_BASE_ADDR + 0x3F24) -#define ISR9 ECREG(EC_REG_BASE_ADDR + 0x3F28) -#define ISR10 ECREG(EC_REG_BASE_ADDR + 0x3F2C) -#define ISR11 ECREG(EC_REG_BASE_ADDR + 0x3F30) -#define ISR12 ECREG(EC_REG_BASE_ADDR + 0x3F34) -#define ISR13 ECREG(EC_REG_BASE_ADDR + 0x3F38) -#define ISR14 ECREG(EC_REG_BASE_ADDR + 0x3F3C) -#define ISR15 ECREG(EC_REG_BASE_ADDR + 0x3F40) -#define ISR16 ECREG(EC_REG_BASE_ADDR + 0x3F44) -#define ISR17 ECREG(EC_REG_BASE_ADDR + 0x3F48) -#define ISR18 ECREG(EC_REG_BASE_ADDR + 0x3F4C) -#define ISR19 ECREG(EC_REG_BASE_ADDR + 0x3F50) -#define ISR20 ECREG(EC_REG_BASE_ADDR + 0x3F54) -#define ISR21 ECREG(EC_REG_BASE_ADDR + 0x3F58) -#define ISR22 ECREG(EC_REG_BASE_ADDR + 0x3F5C) -#define ISR23 ECREG(EC_REG_BASE_ADDR + 0x3F90) - -#define IER0 ECREG(EC_REG_BASE_ADDR + 0x3F04) -#define IER1 ECREG(EC_REG_BASE_ADDR + 0x3F05) -#define IER2 ECREG(EC_REG_BASE_ADDR + 0x3F06) -#define IER3 ECREG(EC_REG_BASE_ADDR + 0x3F07) -#define IER4 ECREG(EC_REG_BASE_ADDR + 0x3F15) -#define IER5 ECREG(EC_REG_BASE_ADDR + 0x3F19) -#define IER6 ECREG(EC_REG_BASE_ADDR + 0x3F1D) -#define IER7 ECREG(EC_REG_BASE_ADDR + 0x3F21) -#define IER8 ECREG(EC_REG_BASE_ADDR + 0x3F25) -#define IER9 ECREG(EC_REG_BASE_ADDR + 0x3F29) -#define IER10 ECREG(EC_REG_BASE_ADDR + 0x3F2D) -#define IER11 ECREG(EC_REG_BASE_ADDR + 0x3F31) -#define IER12 ECREG(EC_REG_BASE_ADDR + 0x3F35) -#define IER13 ECREG(EC_REG_BASE_ADDR + 0x3F39) -#define IER14 ECREG(EC_REG_BASE_ADDR + 0x3F3D) -#define IER15 ECREG(EC_REG_BASE_ADDR + 0x3F41) -#define IER16 ECREG(EC_REG_BASE_ADDR + 0x3F45) -#define IER17 ECREG(EC_REG_BASE_ADDR + 0x3F49) -#define IER18 ECREG(EC_REG_BASE_ADDR + 0x3F4D) -#define IER19 ECREG(EC_REG_BASE_ADDR + 0x3F51) -#define IER20 ECREG(EC_REG_BASE_ADDR + 0x3F55) -#define IER21 ECREG(EC_REG_BASE_ADDR + 0x3F59) -#define IER22 ECREG(EC_REG_BASE_ADDR + 0x3F5D) -#define IER23 ECREG(EC_REG_BASE_ADDR + 0x3F91) - -#define IELMR0 ECREG(EC_REG_BASE_ADDR + 0x3F08) -#define IELMR1 ECREG(EC_REG_BASE_ADDR + 0x3F09) -#define IELMR2 ECREG(EC_REG_BASE_ADDR + 0x3F0A) -#define IELMR3 ECREG(EC_REG_BASE_ADDR + 0x3F0B) -#define IELMR4 ECREG(EC_REG_BASE_ADDR + 0x3F16) -#define IELMR5 ECREG(EC_REG_BASE_ADDR + 0x3F1A) -#define IELMR6 ECREG(EC_REG_BASE_ADDR + 0x3F1E) -#define IELMR7 ECREG(EC_REG_BASE_ADDR + 0x3F22) -#define IELMR8 ECREG(EC_REG_BASE_ADDR + 0x3F26) -#define IELMR9 ECREG(EC_REG_BASE_ADDR + 0x3F2A) -#define IELMR10 ECREG(EC_REG_BASE_ADDR + 0x3F2E) -#define IELMR11 ECREG(EC_REG_BASE_ADDR + 0x3F32) -#define IELMR12 ECREG(EC_REG_BASE_ADDR + 0x3F36) -#define IELMR13 ECREG(EC_REG_BASE_ADDR + 0x3F3A) -#define IELMR14 ECREG(EC_REG_BASE_ADDR + 0x3F3E) -#define IELMR15 ECREG(EC_REG_BASE_ADDR + 0x3F42) -#define IELMR16 ECREG(EC_REG_BASE_ADDR + 0x3F46) -#define IELMR17 ECREG(EC_REG_BASE_ADDR + 0x3F4A) -#define IELMR18 ECREG(EC_REG_BASE_ADDR + 0x3F4E) -#define IELMR19 ECREG(EC_REG_BASE_ADDR + 0x3F52) -#define IELMR20 ECREG(EC_REG_BASE_ADDR + 0x3F56) -#define IELMR21 ECREG(EC_REG_BASE_ADDR + 0x3F5A) -#define IELMR22 ECREG(EC_REG_BASE_ADDR + 0x3F5E) -#define IELMR23 ECREG(EC_REG_BASE_ADDR + 0x3F92) - -#define IPOLR0 ECREG(EC_REG_BASE_ADDR + 0x3F0C) -#define IPOLR1 ECREG(EC_REG_BASE_ADDR + 0x3F0D) -#define IPOLR2 ECREG(EC_REG_BASE_ADDR + 0x3F0E) -#define IPOLR3 ECREG(EC_REG_BASE_ADDR + 0x3F0F) -#define IPOLR4 ECREG(EC_REG_BASE_ADDR + 0x3F17) -#define IPOLR5 ECREG(EC_REG_BASE_ADDR + 0x3F1B) -#define IPOLR6 ECREG(EC_REG_BASE_ADDR + 0x3F1F) -#define IPOLR7 ECREG(EC_REG_BASE_ADDR + 0x3F23) -#define IPOLR8 ECREG(EC_REG_BASE_ADDR + 0x3F27) -#define IPOLR9 ECREG(EC_REG_BASE_ADDR + 0x3F2B) -#define IPOLR10 ECREG(EC_REG_BASE_ADDR + 0x3F2F) -#define IPOLR11 ECREG(EC_REG_BASE_ADDR + 0x3F33) -#define IPOLR12 ECREG(EC_REG_BASE_ADDR + 0x3F37) -#define IPOLR13 ECREG(EC_REG_BASE_ADDR + 0x3F3B) -#define IPOLR14 ECREG(EC_REG_BASE_ADDR + 0x3F3F) -#define IPOLR15 ECREG(EC_REG_BASE_ADDR + 0x3F43) -#define IPOLR16 ECREG(EC_REG_BASE_ADDR + 0x3F47) -#define IPOLR17 ECREG(EC_REG_BASE_ADDR + 0x3F4B) -#define IPOLR18 ECREG(EC_REG_BASE_ADDR + 0x3F4F) -#define IPOLR19 ECREG(EC_REG_BASE_ADDR + 0x3F53) -#define IPOLR20 ECREG(EC_REG_BASE_ADDR + 0x3F57) -#define IPOLR21 ECREG(EC_REG_BASE_ADDR + 0x3F5B) -#define IPOLR22 ECREG(EC_REG_BASE_ADDR + 0x3F5F) -#define IPOLR23 ECREG(EC_REG_BASE_ADDR + 0x3F93) - -#define IVECT ECREG(EC_REG_BASE_ADDR + 0x3F10) - - -/* - * TODO: use pinctrl node instead of following register declarations - * to fix in tcpm\it83xx_pd.h. - */ -/* GPIO control register */ -#define GPCRF4 ECREG(EC_REG_BASE_ADDR + 0x163C) -#define GPCRF5 ECREG(EC_REG_BASE_ADDR + 0x163D) -#define GPCRH1 ECREG(EC_REG_BASE_ADDR + 0x1649) -#define GPCRH2 ECREG(EC_REG_BASE_ADDR + 0x164A) - -/* - * IT8XXX2 register structure size/offset checking macro function to mitigate - * the risk of unexpected compiling results. - */ -#define IT8XXX2_REG_SIZE_CHECK(reg_def, size) \ - BUILD_ASSERT(sizeof(struct reg_def) == size, \ - "Failed in size check of register structure!") -#define IT8XXX2_REG_OFFSET_CHECK(reg_def, member, offset) \ - BUILD_ASSERT(offsetof(struct reg_def, member) == offset, \ - "Failed in offset check of register structure member!") - -/** - * - * (18xxh) PWM & SmartAuto Fan Control (PWM) - * - */ -#ifndef __ASSEMBLER__ -struct pwm_it8xxx2_regs { - /* 0x000: Channel0 Clock Prescaler */ - volatile uint8_t C0CPRS; - /* 0x001: Cycle Time0 */ - volatile uint8_t CTR; - /* 0x002~0x00A: Reserved1 */ - volatile uint8_t Reserved1[9]; - /* 0x00B: Prescaler Clock Frequency Select */ - volatile uint8_t PCFSR; - /* 0x00C~0x00F: Reserved2 */ - volatile uint8_t Reserved2[4]; - /* 0x010: Cycle Time1 MSB */ - volatile uint8_t CTR1M; - /* 0x011~0x022: Reserved3 */ - volatile uint8_t Reserved3[18]; - /* 0x023: PWM Clock Control */ - volatile uint8_t ZTIER; - /* 0x024~0x026: Reserved4 */ - volatile uint8_t Reserved4[3]; - /* 0x027: Channel4 Clock Prescaler */ - volatile uint8_t C4CPRS; - /* 0x028: Channel4 Clock Prescaler MSB */ - volatile uint8_t C4MCPRS; - /* 0x029~0x02A: Reserved5 */ - volatile uint8_t Reserved5[2]; - /* 0x02B: Channel6 Clock Prescaler */ - volatile uint8_t C6CPRS; - /* 0x02C: Channel6 Clock Prescaler MSB */ - volatile uint8_t C6MCPRS; - /* 0x02D: Channel7 Clock Prescaler */ - volatile uint8_t C7CPRS; - /* 0x02E: Channel7 Clock Prescaler MSB */ - volatile uint8_t C7MCPRS; - /* 0x02F~0x040: Reserved6 */ - volatile uint8_t reserved6[18]; - /* 0x041: Cycle Time1 */ - volatile uint8_t CTR1; - /* 0x042: Cycle Time2 */ - volatile uint8_t CTR2; - /* 0x043: Cycle Time3 */ - volatile uint8_t CTR3; - /* 0x044~0x048: Reserved7 */ - volatile uint8_t reserved7[5]; - /* 0x049: PWM Output Open-Drain Enable */ - volatile uint8_t PWMODENR; -}; -#endif /* !__ASSEMBLER__ */ - -/* PWM register fields */ -/* 0x023: PWM Clock Control */ -#define IT8XXX2_PWM_PCCE BIT(1) -/* 0x048: Tachometer Switch Control */ -#define IT8XXX2_PWM_T0DVS BIT(3) -#define IT8XXX2_PWM_T0CHSEL BIT(2) -#define IT8XXX2_PWM_T1DVS BIT(1) -#define IT8XXX2_PWM_T1CHSEL BIT(0) - - -/* --- Wake-Up Control (WUC) --- */ -#define IT8XXX2_WUC_BASE 0x00F01B00 - -/* TODO: should a defined interface for configuring wake-up interrupts */ -#define IT8XXX2_WUC_WUEMR1 (IT8XXX2_WUC_BASE + 0x00) -#define IT8XXX2_WUC_WUEMR5 (IT8XXX2_WUC_BASE + 0x0c) -#define IT8XXX2_WUC_WUESR1 (IT8XXX2_WUC_BASE + 0x04) -#define IT8XXX2_WUC_WUESR5 (IT8XXX2_WUC_BASE + 0x0d) -#define IT8XXX2_WUC_WUBEMR1 (IT8XXX2_WUC_BASE + 0x3c) -#define IT8XXX2_WUC_WUBEMR5 (IT8XXX2_WUC_BASE + 0x0f) - -/** - * - * (1Dxxh) Keyboard Matrix Scan control (KSCAN) - * - */ -#ifndef __ASSEMBLER__ -struct kscan_it8xxx2_regs { - /* 0x000: Keyboard Scan Out */ - volatile uint8_t KBS_KSOL; - /* 0x001: Keyboard Scan Out */ - volatile uint8_t KBS_KSOH1; - /* 0x002: Keyboard Scan Out Control */ - volatile uint8_t KBS_KSOCTRL; - /* 0x003: Keyboard Scan Out */ - volatile uint8_t KBS_KSOH2; - /* 0x004: Keyboard Scan In */ - volatile uint8_t KBS_KSI; - /* 0x005: Keyboard Scan In Control */ - volatile uint8_t KBS_KSICTRL; - /* 0x006: Keyboard Scan In [7:0] GPIO Control */ - volatile uint8_t KBS_KSIGCTRL; - /* 0x007: Keyboard Scan In [7:0] GPIO Output Enable */ - volatile uint8_t KBS_KSIGOEN; - /* 0x008: Keyboard Scan In [7:0] GPIO Data */ - volatile uint8_t KBS_KSIGDAT; - /* 0x009: Keyboard Scan In [7:0] GPIO Data Mirror */ - volatile uint8_t KBS_KSIGDMRR; - /* 0x00A: Keyboard Scan Out [15:8] GPIO Control */ - volatile uint8_t KBS_KSOHGCTRL; - /* 0x00B: Keyboard Scan Out [15:8] GPIO Output Enable */ - volatile uint8_t KBS_KSOHGOEN; - /* 0x00C: Keyboard Scan Out [15:8] GPIO Data Mirror */ - volatile uint8_t KBS_KSOHGDMRR; - /* 0x00D: Keyboard Scan Out [7:0] GPIO Control */ - volatile uint8_t KBS_KSOLGCTRL; - /* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */ - volatile uint8_t KBS_KSOLGOEN; -}; -#endif /* !__ASSEMBLER__ */ - -/* KBS register fields */ -/* 0x002: Keyboard Scan Out Control */ -#define IT8XXX2_KBS_KSOPU BIT(2) -#define IT8XXX2_KBS_KSOOD BIT(0) -/* 0x005: Keyboard Scan In Control */ -#define IT8XXX2_KBS_KSIPU BIT(2) -/* 0x00D: Keyboard Scan Out [7:0] GPIO Control */ -#define IT8XXX2_KBS_KSO2GCTRL BIT(2) -/* 0x00E: Keyboard Scan Out [7:0] GPIO Output Enable */ -#define IT8XXX2_KBS_KSO2GOEN BIT(2) - - -/** - * - * (1Fxxh) External Timer & External Watchdog (ETWD) - * - */ -#ifndef __ASSEMBLER__ -struct wdt_it8xxx2_regs { - /* 0x000: Reserved1 */ - volatile uint8_t reserved1; - /* 0x001: External Timer1/WDT Configuration */ - volatile uint8_t ETWCFG; - /* 0x002: External Timer1 Prescaler */ - volatile uint8_t ET1PSR; - /* 0x003: External Timer1 Counter High Byte */ - volatile uint8_t ET1CNTLHR; - /* 0x004: External Timer1 Counter Low Byte */ - volatile uint8_t ET1CNTLLR; - /* 0x005: External Timer1/WDT Control */ - volatile uint8_t ETWCTRL; - /* 0x006: External WDT Counter Low Byte */ - volatile uint8_t EWDCNTLR; - /* 0x007: External WDT Key */ - volatile uint8_t EWDKEYR; - /* 0x008: Reserved2 */ - volatile uint8_t reserved2; - /* 0x009: External WDT Counter High Byte */ - volatile uint8_t EWDCNTHR; - /* 0x00A: External Timer2 Prescaler */ - volatile uint8_t ET2PSR; - /* 0x00B: External Timer2 Counter High Byte */ - volatile uint8_t ET2CNTLHR; - /* 0x00C: External Timer2 Counter Low Byte */ - volatile uint8_t ET2CNTLLR; - /* 0x00D: Reserved3 */ - volatile uint8_t reserved3; - /* 0x00E: External Timer2 Counter High Byte2 */ - volatile uint8_t ET2CNTLH2R; -}; -#endif /* !__ASSEMBLER__ */ - -/* WDT register fields */ -/* 0x001: External Timer1/WDT Configuration */ -#define IT8XXX2_WDT_EWDKEYEN BIT(5) -#define IT8XXX2_WDT_EWDSRC BIT(4) -#define IT8XXX2_WDT_LEWDCNTL BIT(3) -#define IT8XXX2_WDT_LET1CNTL BIT(2) -#define IT8XXX2_WDT_LET1PS BIT(1) -#define IT8XXX2_WDT_LETWCFG BIT(0) -/* 0x002: External Timer1 Prescaler */ -#define IT8XXX2_WDT_ETPS_32P768_KHZ 0x00 -#define IT8XXX2_WDT_ETPS_1P024_KHZ 0x01 -#define IT8XXX2_WDT_ETPS_32_HZ 0x02 -/* 0x005: External Timer1/WDT Control */ -#define IT8XXX2_WDT_EWDSCEN BIT(5) -#define IT8XXX2_WDT_EWDSCMS BIT(4) -#define IT8XXX2_WDT_ET2TC BIT(3) -#define IT8XXX2_WDT_ET2RST BIT(2) -#define IT8XXX2_WDT_ET1TC BIT(1) -#define IT8XXX2_WDT_ET1RST BIT(0) - -/* External Timer register fields */ -/* External Timer 3~8 control */ -#define IT8XXX2_EXT_ETX_COMB_RST_EN (IT8XXX2_EXT_ETXCOMB | \ - IT8XXX2_EXT_ETXRST | \ - IT8XXX2_EXT_ETXEN) -#define IT8XXX2_EXT_ETXCOMB BIT(3) -#define IT8XXX2_EXT_ETXRST BIT(1) -#define IT8XXX2_EXT_ETXEN BIT(0) - -/* Control external timer3~8 */ -#define IT8XXX2_EXT_TIMER_BASE DT_REG_ADDR(DT_NODELABEL(timer)) /*0x00F01F10*/ -#define IT8XXX2_EXT_CTRLX(n) ECREG(IT8XXX2_EXT_TIMER_BASE + (n << 3)) -#define IT8XXX2_EXT_PSRX(n) ECREG(IT8XXX2_EXT_TIMER_BASE + 0x01 + (n << 3)) -#define IT8XXX2_EXT_CNTX(n) ECREG_u32(IT8XXX2_EXT_TIMER_BASE + 0x04 + \ - (n << 3)) -#define IT8XXX2_EXT_CNTOX(n) ECREG_u32(IT8XXX2_EXT_TIMER_BASE + 0x38 + \ - (n << 2)) - -/* Free run timer configurations */ -#define FREE_RUN_TIMER EXT_TIMER_4 -#define FREE_RUN_TIMER_IRQ DT_IRQ_BY_IDX(DT_NODELABEL(timer), 1, irq) -/* Free run timer configurations */ -#define FREE_RUN_TIMER_FLAG DT_IRQ_BY_IDX(DT_NODELABEL(timer), 1, flags) -/* Free run timer max count is 36.4 hr (base on clock source 32768Hz) */ -#define FREE_RUN_TIMER_MAX_CNT 0xFFFFFFFFUL - -#ifndef __ASSEMBLER__ -enum ext_clk_src_sel { - EXT_PSR_32P768K = 0, - EXT_PSR_1P024K, - EXT_PSR_32, - EXT_PSR_8M, -}; -/* - * 24-bit timers: external timer 3, 5, and 7 - * 32-bit timers: external timer 4, 6, and 8 - */ -enum ext_timer_idx { - EXT_TIMER_3 = 0, /* Event timer */ - EXT_TIMER_4, /* Free run timer */ - EXT_TIMER_5, /* Busy wait low timer */ - EXT_TIMER_6, /* Busy wait high timer */ - EXT_TIMER_7, - EXT_TIMER_8, -}; -#endif - - -/* - * - * (2Cxxh) Platform Environment Control Interface (PECI) - * - */ -#ifndef __ASSEMBLER__ -struct peci_it8xxx2_regs { - /* 0x00: Host Status */ - volatile uint8_t HOSTAR; - /* 0x01: Host Control */ - volatile uint8_t HOCTLR; - /* 0x02: Host Command */ - volatile uint8_t HOCMDR; - /* 0x03: Host Target Address */ - volatile uint8_t HOTRADDR; - /* 0x04: Host Write Length */ - volatile uint8_t HOWRLR; - /* 0x05: Host Read Length */ - volatile uint8_t HORDLR; - /* 0x06: Host Write Data */ - volatile uint8_t HOWRDR; - /* 0x07: Host Read Data */ - volatile uint8_t HORDDR; - /* 0x08: Host Control 2 */ - volatile uint8_t HOCTL2R; - /* 0x09: Received Write FCS value */ - volatile uint8_t RWFCSV; - /* 0x0A: Received Read FCS value */ - volatile uint8_t RRFCSV; - /* 0x0B: Write FCS Value */ - volatile uint8_t WFCSV; - /* 0x0C: Read FCS Value */ - volatile uint8_t RFCSV; - /* 0x0D: Assured Write FCS Value */ - volatile uint8_t AWFCSV; - /* 0x0E: Pad Control */ - volatile uint8_t PADCTLR; -}; -#endif /* !__ASSEMBLER__ */ - -/** - * - * (2Fxxh) USB Device Controller (USBDC) Registers - * - */ -#define EP_EXT_REGS_9X 1 -#define EP_EXT_REGS_BX 2 -#define EP_EXT_REGS_DX 3 - -#ifndef __ASSEMBLER__ - -/* EP0 to EP15 Enumeration */ -enum usb_dc_endpoints { - EP0, - EP1, - EP2, - EP3, - EP4, - EP5, - EP6, - EP7, - EP8, - EP9, - EP10, - EP11, - EP12, - EP13, - EP14, - EP15 -}; - -struct it82xx2_usb_ep_regs { - volatile uint8_t ep_ctrl; - volatile uint8_t ep_status; - volatile uint8_t ep_transtype_sts; - volatile uint8_t ep_nak_transtype_sts; -}; - -/* Reserved EP Extended Registers */ -struct ep_ext_regs_7x { - /* 0x75 Reserved */ - volatile uint8_t ep_ext_ctrl_75; - /* 0x76 Reserved */ - volatile uint8_t ep_ext_ctrl_76; - /* 0x77 Reserved */ - volatile uint8_t ep_ext_ctrl_77; - /* 0x78 Reserved */ - volatile uint8_t ep_ext_ctrl_78; - /* 0x79 Reserved */ - volatile uint8_t ep_ext_ctrl_79; - /* 0x7A Reserved */ - volatile uint8_t ep_ext_ctrl_7a; - /* 0x7B Reserved */ - volatile uint8_t ep_ext_ctrl_7b; - /* 0x7C Reserved */ - volatile uint8_t ep_ext_ctrl_7c; - /* 0x7D Reserved */ - volatile uint8_t ep_ext_ctrl_7d; - /* 0x7E Reserved */ - volatile uint8_t ep_ext_ctrl_7e; - /* 0x7F Reserved */ - volatile uint8_t ep_ext_ctrl_7f; -}; - -/* From 98h to 9Dh, the EP45/67/89/1011/1213/1415 Extended Control Registers - * are defined, and their bits definitions are as follows: - * - * Bit Description - * 7 Reserved - * 6 EPPOINT5_ISO_ENABLE - * 5 EPPOINT5_SEND_STALL - * 4 EPPOINT5_OUT_DATA_SEQUENCE - * 3 Reserved - * 2 EPPOINT4_ISO_ENABLE - * 1 EPPOINT4_SEND_STALL - * 0 EPPOINT4_OUT_DATA_SEQUENCE - * - * Apparently, we can tell that the EP4 and EP5 share the same register, and - * the EP6 and EP7 share the same one, and the rest EPs are defined in the - * same way. - */ -struct ep_ext_regs_9x { - /* 0x95 Reserved */ - volatile uint8_t ep_ext_ctrl_95; - /* 0x96 Reserved */ - volatile uint8_t ep_ext_ctrl_96; - /* 0x97 Reserved */ - volatile uint8_t ep_ext_ctrl_97; - /* 0x98 ~ 0x9D EP45/67/89/1011/1213/1415 Extended Control Registers */ - volatile uint8_t epn0n1_ext_ctrl[6]; - /* 0x9E Reserved */ - volatile uint8_t ep_ext_ctrl_9e; - /* 0x9F Reserved */ - volatile uint8_t ep_ext_ctrl_9f; -}; - -/* From BXh to BDh are EP FIFO 1-3 Control 0/1 Registers, and their - * definitions as as follows: - * B8h: EP_FIFO1_CONTROL0_REG - * B9h: EP_FIFO1_CONTROL1_REG - * BAh: EP_FIFO2_CONTROL0_REG - * BBh: EP_FIFO2_CONTROL1_REG - * BCh: EP_FIFO3_CONTROL0_REG - * BDh: EP_FIFO3_CONTROL1_REG - * - * For each one, its bits definitions are as follows: - * (take EP_FIFO1_CONTROL1_REG as example, which controls from EP8 to EP15) - * - * Bit Description - * - * 7 EP15 select FIFO1 as data buffer - * 6 EP14 select FIFO1 as data buffer - * 5 EP13 select FIFO1 as data buffer - * 4 EP12 select FIFO1 as data buffer - * 3 EP11 select FIFO1 as data buffer - * 2 EP10 select FIFO1 as data buffer - * 1 EP9 select FIFO1 as data buffer - * 0 EP8 select FIFO1 as data buffer - * - * 1: Select - * 0: Not select - */ -struct ep_ext_regs_bx { - /* 0xB5 Reserved */ - volatile uint8_t ep_ext_ctrl_b5; - /* 0xB6 Reserved */ - volatile uint8_t ep_ext_ctrl_b6; - /* 0xB7 Reserved */ - volatile uint8_t ep_ext_ctrl_b7; - /* 0xB8 ~ 0xBD EP FIFO 1-3 Control 0/1 Registers */ - volatile uint8_t ep_fifo_ctrl[6]; - /* 0xBE Reserved */ - volatile uint8_t ep_ext_ctrl_be; - /* 0xBF Reserved */ - volatile uint8_t ep_ext_ctrl_bf; -}; - - -/* From D6h to DDh are EP Extended Control Registers, and their - * definitions as as follows: - * D6h: EP0_EXT_CTRL1 - * D7h: EP0_EXT_CTRL2 - * D8h: EP1_EXT_CTRL1 - * D9h: EP1_EXT_CTRL2 - * DAh: EP2_EXT_CTRL1 - * DBh: EP2_EXT_CTRL2 - * DCh: EP3_EXT_CTRL1 - * DDh: EP3_EXT_CTRL2 - * - * We classify them into 4 groups which each of them contains Control 1 and 2 - * according to the EP number as follows: - */ -struct epn_ext_ctrl_regs { - /* 0xD6/0xD8/0xDA/0xDC EPN Extended Control1 Register */ - volatile uint8_t epn_ext_ctrl1; - /* 0xD7/0xD9/0xDB/0xDD EPB Extended Control2 Register */ - volatile uint8_t epn_ext_ctrl2; -}; - -struct ep_ext_regs_dx { - /* 0xD5 Reserved */ - volatile uint8_t ep_ext_ctrl_d5; - /* 0xD6 ~ 0xDD EPN Extended Control 1/2 Registers */ - struct epn_ext_ctrl_regs epn_ext_ctrl[4]; - /* 0xDE Reserved */ - volatile uint8_t ep_ext_ctrl_de; - /* 0xDF Reserved */ - volatile uint8_t ep_ext_ctrl_df; -}; - - -/* The USB EPx FIFO Registers Definitions - * EP0: 60h ~ 74h - * EP1: 80h ~ 94h - * EP2: A0h ~ B4h - * EP3: C0h ~ D4h (D6h to DDh will be defined as marcos for usage) - */ -struct it82xx2_usb_ep_fifo_regs { - /* 0x60 + ep * 0x20 : EP RX FIFO Data Register */ - volatile uint8_t ep_rx_fifo_data; - /* 0x61 + ep * 0x20 : EP RX FIFO DMA Count Register */ - volatile uint8_t ep_rx_fifo_dma_count; - /* 0x62 + ep * 0x20 : EP RX FIFO Data Count MSB */ - volatile uint8_t ep_rx_fifo_dcnt_msb; - /* 0x63 + ep * 0x20 : EP RX FIFO Data Count LSB */ - volatile uint8_t ep_rx_fifo_dcnt_lsb; - /* 0x64 + ep * 0x20 : EP RX FIFO Control Register */ - volatile uint8_t ep_rx_fifo_ctrl; - /* (0x65 ~ 0x6F) + ep * 0x20 */ - volatile uint8_t reserved_65_6f_add_20[11]; - /* 0x70 + ep * 0x20 : EP TX FIFO Data Register */ - volatile uint8_t ep_tx_fifo_data; - /* (0x71 ~ 0x73) + ep * 0x20 */ - volatile uint8_t reserved_71_73_add_20[3]; - /* 0x74 + ep * 0x20 : EP TX FIFO Control Register */ - volatile uint8_t ep_tx_fifo_ctrl; - /* (0x75 ~ 0x7F) + ep * 0x20 */ - union { - struct ep_ext_regs_7x ep_res; - struct ep_ext_regs_9x ext_4_15; - struct ep_ext_regs_bx fifo_ctrl; - struct ep_ext_regs_dx ext_0_3; - }; - -}; - -struct usb_it82xx2_regs { - /* 0x00: Host TX Contrl Register */ - volatile uint8_t host_tx_ctrl; - /* 0x01: Host TX Transaction Type Register */ - volatile uint8_t host_tx_trans_type; - /* 0x02: Host TX Line Control Register */ - volatile uint8_t host_tx_line_ctrl; - /* 0x03: Host TX SOF Enable Register */ - volatile uint8_t host_tx_sof_enable; - /* 0x04: Host TX Address Register */ - volatile uint8_t host_tx_addr; - /* 0x05: Host TX EP Number Register */ - volatile uint8_t host_tx_endp; - /* 0x06: Host Frame Number MSP Register */ - volatile uint8_t host_frame_num_msp; - /* 0x07: Host Frame Number LSP Register */ - volatile uint8_t host_frame_num_lsp; - /* 0x08: Host Interrupt Status Register */ - volatile uint8_t host_interrupt_status; - /* 0x09: Host Interrupt Mask Register */ - volatile uint8_t host_interrupt_mask; - /* 0x0A: Host RX Status Register */ - volatile uint8_t host_rx_status; - /* 0x0B: Host RX PID Register */ - volatile uint8_t host_rx_pid; - /* 0x0C: MISC Control Register */ - volatile uint8_t misc_control; - /* 0x0D: MISC Status Register */ - volatile uint8_t misc_status; - /* 0x0E: Host RX Connect State Register */ - volatile uint8_t host_rx_connect_state; - /* 0x0F: Host SOF Timer MSB Register */ - volatile uint8_t host_sof_timer_msb; - /* 0x10 ~ 0x1F: Reserved Registers 10h - 1Fh */ - volatile uint8_t reserved_10_1f[16]; - /* 0x20: Host RX FIFO Data Port Register */ - volatile uint8_t host_rx_fifo_data; - /* 0x21: Host RX FIFO DMA Input Data Count Register */ - volatile uint8_t host_rx_fifo_dma_data_count; - /* 0x22: Host TX FIFO Data Count MSB Register */ - volatile uint8_t host_rx_fifo_data_count_msb; - /* 0x23: Host TX FIFO Data Count LSB Register */ - volatile uint8_t host_rx_fifo_data_count_lsb; - /* 0x24: Host RX FIFO Data Port Register */ - volatile uint8_t host_rx_fifo_control; - /* 0x25 ~ 0x2F: Reserved Registers 25h - 2Fh */ - volatile uint8_t reserved_25_2f[11]; - /* 0x30: Host TX FIFO Data Port Register */ - volatile uint8_t host_tx_fifo_data; - /* 0x31 ~ 0x3F: Reserved Registers 31h - 3Fh */ - volatile uint8_t reserved_31_3f[15]; - /* 0x40 ~ 0x4F: Endpoint Registers 40h - 4Fh */ - struct it82xx2_usb_ep_regs usb_ep_regs[4]; - /* 0x50: Device Controller Control Register */ - volatile uint8_t dc_control; - /* 0x51: Device Controller LINE Status Register */ - volatile uint8_t dc_line_status; - /* 0x52: Device Controller Interrupt Status Register */ - volatile uint8_t dc_interrupt_status; - /* 0x53: Device Controller Interrupt Mask Register */ - volatile uint8_t dc_interrupt_mask; - /* 0x54: Device Controller Address Register */ - volatile uint8_t dc_address; - /* 0x55: Device Controller Frame Number MSP Register */ - volatile uint8_t dc_frame_num_msp; - /* 0x56: Device Controller Frame Number LSP Register */ - volatile uint8_t dc_frame_num_lsp; - /* 0x57 ~ 0x5F: Reserved Registers 57h - 5Fh */ - volatile uint8_t reserved_57_5f[9]; - /* 0x60 ~ 0xDF: EP FIFO Registers 60h - DFh */ - struct it82xx2_usb_ep_fifo_regs fifo_regs[4]; - /* 0xE0: Host/Device Control Register */ - volatile uint8_t host_device_control; - /* 0xE1 ~ 0xE3: Reserved Registers E1h - E3h */ - volatile uint8_t reserved_e1_e3[3]; - /* 0xE4: Port0 MISC Control Register */ - volatile uint8_t port0_misc_control; - /* 0xE5 ~ 0xE7: Reserved Registers E5h - E7h */ - volatile uint8_t reserved_e5_e7[3]; - /* 0xE8: Port1 MISC Control Register */ - volatile uint8_t port1_misc_control; -}; -#endif /* #ifndef __ASSEMBLER__ */ - -/** - * - * (37xxh, 38xxh) USBPD Controller - * - */ -#ifndef __ASSEMBLER__ -struct usbpd_it8xxx2_regs { - /* 0x000~0x003: Reserved1 */ - volatile uint8_t Reserved1[4]; - /* 0x004: CC General Configuration */ - volatile uint8_t CCGCR; - /* 0x005: CC Channel Setting */ - volatile uint8_t CCCSR; - /* 0x006: CC Pad Setting */ - volatile uint8_t CCPSR; -}; -#endif /* !__ASSEMBLER__ */ - -/* USBPD controller register fields */ -/* 0x004: CC General Configuration */ -#define IT8XXX2_USBPD_DISABLE_CC BIT(7) -#define IT8XXX2_USBPD_DISABLE_CC_VOL_DETECTOR BIT(6) -#define IT8XXX2_USBPD_CC_SELECT_RP_RESERVED (BIT(3) | BIT(2) | BIT(1)) -#define IT8XXX2_USBPD_CC_SELECT_RP_DEF (BIT(3) | BIT(2)) -#define IT8XXX2_USBPD_CC_SELECT_RP_1A5 BIT(3) -#define IT8XXX2_USBPD_CC_SELECT_RP_3A0 BIT(2) -#define IT8XXX2_USBPD_CC1_CC2_SELECTION BIT(0) -/* 0x005: CC Channel Setting */ -#define IT8XXX2_USBPD_CC2_DISCONNECT BIT(7) -#define IT8XXX2_USBPD_CC2_DISCONNECT_5_1K_TO_GND BIT(6) -#define IT8XXX2_USBPD_CC1_DISCONNECT BIT(3) -#define IT8XXX2_USBPD_CC1_DISCONNECT_5_1K_TO_GND BIT(2) -#define IT8XXX2_USBPD_CC1_CC2_RP_RD_SELECT (BIT(1) | BIT(5)) -/* 0x006: CC Pad Setting */ -#define IT8XXX2_USBPD_DISCONNECT_5_1K_CC2_DB BIT(6) -#define IT8XXX2_USBPD_DISCONNECT_POWER_CC2 BIT(5) -#define IT8XXX2_USBPD_DISCONNECT_5_1K_CC1_DB BIT(2) -#define IT8XXX2_USBPD_DISCONNECT_POWER_CC1 BIT(1) - - -/** - * - * (10xxh) Shared Memory Flash Interface Bridge (SMFI) registers - * - */ -#ifndef __ASSEMBLER__ -struct smfi_it8xxx2_regs { - volatile uint8_t reserved1[59]; - /* 0x3B: EC-Indirect memory address 0 */ - volatile uint8_t SMFI_ECINDAR0; - /* 0x3C: EC-Indirect memory address 1 */ - volatile uint8_t SMFI_ECINDAR1; - /* 0x3D: EC-Indirect memory address 2 */ - volatile uint8_t SMFI_ECINDAR2; - /* 0x3E: EC-Indirect memory address 3 */ - volatile uint8_t SMFI_ECINDAR3; - /* 0x3F: EC-Indirect memory data */ - volatile uint8_t SMFI_ECINDDR; - /* 0x40: Scratch SRAM 0 address low byte */ - volatile uint8_t SMFI_SCAR0L; - /* 0x41: Scratch SRAM 0 address middle byte */ - volatile uint8_t SMFI_SCAR0M; - /* 0x42: Scratch SRAM 0 address high byte */ - volatile uint8_t SMFI_SCAR0H; - volatile uint8_t reserved1_1[23]; - /* 0x5A: Host RAM Window Control */ - volatile uint8_t SMFI_HRAMWC; - /* 0x5B: Host RAM Window 0 Base Address [11:4] */ - volatile uint8_t SMFI_HRAMW0BA; - /* 0x5C: Host RAM Window 1 Base Address [11:4] */ - volatile uint8_t SMFI_HRAMW1BA; - /* 0x5D: Host RAM Window 0 Access Allow Size */ - volatile uint8_t SMFI_HRAMW0AAS; - /* 0x5E: Host RAM Window 1 Access Allow Size */ - volatile uint8_t SMFI_HRAMW1AAS; - volatile uint8_t reserved2[67]; - /* 0xA2: Flash control 6 */ - volatile uint8_t SMFI_FLHCTRL6R; - volatile uint8_t reserved3[46]; -}; -#endif /* !__ASSEMBLER__ */ - -/* SMFI register fields */ -/* EC-Indirect read internal flash */ -#define EC_INDIRECT_READ_INTERNAL_FLASH BIT(6) -/* Enable EC-indirect page program command */ -#define IT8XXX2_SMFI_MASK_ECINDPP BIT(3) -/* Scratch SRAM 0 address(BIT(19)) */ -#define IT8XXX2_SMFI_SC0A19 BIT(7) -/* Scratch SRAM enable */ -#define IT8XXX2_SMFI_SCAR0H_ENABLE BIT(3) - -/* H2RAM Path Select. 1b: H2RAM through LPC IO cycle. */ -#define SMFI_H2RAMPS BIT(4) -/* H2RAM Window 1 Enable */ -#define SMFI_H2RAMW1E BIT(1) -/* H2RAM Window 0 Enable */ -#define SMFI_H2RAMW0E BIT(0) - -/* Host RAM Window x Write Protect Enable (All protected) */ -#define SMFI_HRAMWXWPE_ALL (BIT(5) | BIT(4)) - - -/** - * - * (16xxh) General Purpose I/O Port (GPIO) registers - * - */ -#define GPIO_IT8XXX2_REG_BASE \ - ((struct gpio_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gpiogcr))) - -#ifndef __ASSEMBLER__ -#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 -struct gpio_it8xxx2_regs { - /* 0x00: General Control */ - volatile uint8_t GPIO_GCR; - /* 0x01-D0: Reserved1 */ - volatile uint8_t reserved1[208]; - /* 0xD1: General Control 25 */ - volatile uint8_t GPIO_GCR25; - /* 0xD2: General Control 26 */ - volatile uint8_t GPIO_GCR26; - /* 0xD3: General Control 27 */ - volatile uint8_t GPIO_GCR27; - /* 0xD4: General Control 28 */ - volatile uint8_t GPIO_GCR28; - /* 0xD5: General Control 31 */ - volatile uint8_t GPIO_GCR31; - /* 0xD6: General Control 32 */ - volatile uint8_t GPIO_GCR32; - /* 0xD7: General Control 33 */ - volatile uint8_t GPIO_GCR33; - /* 0xD8-0xDF: Reserved2 */ - volatile uint8_t reserved2[8]; - /* 0xE0: General Control 16 */ - volatile uint8_t GPIO_GCR16; - /* 0xE1: General Control 17 */ - volatile uint8_t GPIO_GCR17; - /* 0xE2: General Control 18 */ - volatile uint8_t GPIO_GCR18; - /* 0xE3: Reserved3 */ - volatile uint8_t reserved3; - /* 0xE4: General Control 19 */ - volatile uint8_t GPIO_GCR19; - /* 0xE5: General Control 20 */ - volatile uint8_t GPIO_GCR20; - /* 0xE6: General Control 21 */ - volatile uint8_t GPIO_GCR21; - /* 0xE7: General Control 22 */ - volatile uint8_t GPIO_GCR22; - /* 0xE8: General Control 23 */ - volatile uint8_t GPIO_GCR23; - /* 0xE9: General Control 24 */ - volatile uint8_t GPIO_GCR24; - /* 0xEA-0xEC: Reserved4 */ - volatile uint8_t reserved4[3]; - /* 0xED: General Control 30 */ - volatile uint8_t GPIO_GCR30; - /* 0xEE: General Control 29 */ - volatile uint8_t GPIO_GCR29; - /* 0xEF: Reserved5 */ - volatile uint8_t reserved5; - /* 0xF0: General Control 1 */ - volatile uint8_t GPIO_GCR1; - /* 0xF1: General Control 2 */ - volatile uint8_t GPIO_GCR2; - /* 0xF2: General Control 3 */ - volatile uint8_t GPIO_GCR3; - /* 0xF3: General Control 4 */ - volatile uint8_t GPIO_GCR4; - /* 0xF4: General Control 5 */ - volatile uint8_t GPIO_GCR5; - /* 0xF5: General Control 6 */ - volatile uint8_t GPIO_GCR6; - /* 0xF6: General Control 7 */ - volatile uint8_t GPIO_GCR7; - /* 0xF7: General Control 8 */ - volatile uint8_t GPIO_GCR8; - /* 0xF8: General Control 9 */ - volatile uint8_t GPIO_GCR9; - /* 0xF9: General Control 10 */ - volatile uint8_t GPIO_GCR10; - /* 0xFA: General Control 11 */ - volatile uint8_t GPIO_GCR11; - /* 0xFB: General Control 12 */ - volatile uint8_t GPIO_GCR12; - /* 0xFC: General Control 13 */ - volatile uint8_t GPIO_GCR13; - /* 0xFD: General Control 14 */ - volatile uint8_t GPIO_GCR14; - /* 0xFE: General Control 15 */ - volatile uint8_t GPIO_GCR15; - /* 0xFF: Power Good Watch Control */ - volatile uint8_t GPIO_PGWCR; -}; -#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 -struct gpio_it8xxx2_regs { - /* 0x00: General Control */ - volatile uint8_t GPIO_GCR; - /* 0x01-0x0F: Reserved1 */ - volatile uint8_t reserved1[15]; - /* 0x10: General Control 1 */ - volatile uint8_t GPIO_GCR1; - /* 0x11: General Control 2 */ - volatile uint8_t GPIO_GCR2; - /* 0x12: General Control 3 */ - volatile uint8_t GPIO_GCR3; - /* 0x13: General Control 4 */ - volatile uint8_t GPIO_GCR4; - /* 0x14: General Control 5 */ - volatile uint8_t GPIO_GCR5; - /* 0x15: General Control 6 */ - volatile uint8_t GPIO_GCR6; - /* 0x16: General Control 7 */ - volatile uint8_t GPIO_GCR7; - /* 0x17: General Control 8 */ - volatile uint8_t GPIO_GCR8; - /* 0x18: General Control 9 */ - volatile uint8_t GPIO_GCR9; - /* 0x19: General Control 10 */ - volatile uint8_t GPIO_GCR10; - /* 0x1A: General Control 11 */ - volatile uint8_t GPIO_GCR11; - /* 0x1B: General Control 12 */ - volatile uint8_t GPIO_GCR12; - /* 0x1C: General Control 13 */ - volatile uint8_t GPIO_GCR13; - /* 0x1D: General Control 14 */ - volatile uint8_t GPIO_GCR14; - /* 0x1E: General Control 15 */ - volatile uint8_t GPIO_GCR15; - /* 0x1F: Power Good Watch Control */ - volatile uint8_t GPIO_PGWCR; - /* 0x20: General Control 16 */ - volatile uint8_t GPIO_GCR16; - /* 0x21: General Control 17 */ - volatile uint8_t GPIO_GCR17; - /* 0x22: General Control 18 */ - volatile uint8_t GPIO_GCR18; - /* 0x23: Reserved2 */ - volatile uint8_t reserved2; - /* 0x24: General Control 19 */ - volatile uint8_t GPIO_GCR19; - /* 0x25: Reserved3 */ - volatile uint8_t reserved3; - /* 0x26: General Control 21 */ - volatile uint8_t GPIO_GCR21; - /* 0x27-0x28: Reserved4 */ - volatile uint8_t reserved4[2]; - /* 0x29: General Control 24 */ - volatile uint8_t GPIO_GCR24; - /* 0x2A-0x2C: Reserved5 */ - volatile uint8_t reserved5[3]; - /* 0x2D: General Control 30 */ - volatile uint8_t GPIO_GCR30; - /* 0x2E: General Control 29 */ - volatile uint8_t GPIO_GCR29; -}; - -/* GPIO register fields */ -/* 0x16: General Control 7 */ -#define IT8XXX2_GPIO_SMB2PS BIT(7) -#define IT8XXX2_GPIO_SMB3PS BIT(6) -#define IT8XXX2_GPIO_SMB5PS BIT(5) - -#endif -#endif /* !__ASSEMBLER__ */ - -/* GPIO register fields */ -/* 0x00: General Control */ -#define IT8XXX2_GPIO_LPCRSTEN (BIT(2) | BIT(1)) -#define IT8XXX2_GPIO_GCR_ESPI_RST_D2 0x2 -#define IT8XXX2_GPIO_GCR_ESPI_RST_POS 1 -#define IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK (0x3 << IT8XXX2_GPIO_GCR_ESPI_RST_POS) -/* 0xF0: General Control 1 */ -#define IT8XXX2_GPIO_U2CTRL_SIN1_SOUT1_EN BIT(2) -#define IT8XXX2_GPIO_U1CTRL_SIN0_SOUT0_EN BIT(0) -/* 0xE6: General Control 21 */ -#define IT8XXX2_GPIO_GPH1VS BIT(1) -#define IT8XXX2_GPIO_GPH2VS BIT(0) - -#define GPCR_PORT_PIN_MODE_INPUT BIT(7) -#define GPCR_PORT_PIN_MODE_OUTPUT BIT(6) -#define GPCR_PORT_PIN_MODE_PULLUP BIT(2) -#define GPCR_PORT_PIN_MODE_PULLDOWN BIT(1) - -/* - * If both PULLUP and PULLDOWN are set to 1b, the corresponding port would be - * configured as tri-state. - */ -#define GPCR_PORT_PIN_MODE_TRISTATE (GPCR_PORT_PIN_MODE_INPUT | \ - GPCR_PORT_PIN_MODE_PULLUP | \ - GPCR_PORT_PIN_MODE_PULLDOWN) - -/* --- GPIO --- */ -#define IT8XXX2_GPIO_BASE 0x00F01600 -#define IT8XXX2_GPIO2_BASE 0x00F03E00 - -#define IT8XXX2_GPIO_GCRX(offset) ECREG(IT8XXX2_GPIO_BASE + (offset)) -#define IT8XXX2_GPIO_GCR25_OFFSET 0xd1 -#define IT8XXX2_GPIO_GCR26_OFFSET 0xd2 -#define IT8XXX2_GPIO_GCR27_OFFSET 0xd3 -#define IT8XXX2_GPIO_GCR28_OFFSET 0xd4 -#define IT8XXX2_GPIO_GCR31_OFFSET 0xd5 -#define IT8XXX2_GPIO_GCR32_OFFSET 0xd6 -#define IT8XXX2_GPIO_GCR33_OFFSET 0xd7 -#define IT8XXX2_GPIO_GCR19_OFFSET 0xe4 -#define IT8XXX2_GPIO_GCR20_OFFSET 0xe5 -#define IT8XXX2_GPIO_GCR21_OFFSET 0xe6 -#define IT8XXX2_GPIO_GCR22_OFFSET 0xe7 -#define IT8XXX2_GPIO_GCR23_OFFSET 0xe8 -#define IT8XXX2_GPIO_GCR24_OFFSET 0xe9 -#define IT8XXX2_GPIO_GCR30_OFFSET 0xed -#define IT8XXX2_GPIO_GCR29_OFFSET 0xee - -/* - * TODO: use pinctrl node instead of following register declarations - * to fix in tcpm\it83xx_pd.h. - */ -#define IT8XXX2_GPIO_GPCRP0 ECREG(IT8XXX2_GPIO2_BASE + 0x18) -#define IT8XXX2_GPIO_GPCRP1 ECREG(IT8XXX2_GPIO2_BASE + 0x19) - - -/** - * - * (19xxh) Analog to Digital Converter (ADC) registers - * - */ -#ifndef __ASSEMBLER__ - -/* Data structure to define ADC channel 13-16 control registers. */ -struct adc_vchs_ctrl_t { - /* 0x60: Voltage Channel Control */ - volatile uint8_t VCHCTL; - /* 0x61: Voltage Channel Data Buffer MSB */ - volatile uint8_t VCHDATM; - /* 0x62: Voltage Channel Data Buffer LSB */ - volatile uint8_t VCHDATL; -}; - -struct adc_it8xxx2_regs { - /* 0x00: ADC Status */ - volatile uint8_t ADCSTS; - /* 0x01: ADC Configuration */ - volatile uint8_t ADCCFG; - /* 0x02: ADC Clock Control */ - volatile uint8_t ADCCTL; - /* 0x03: General Control */ - volatile uint8_t ADCGCR; - /* 0x04: Voltage Channel 0 Control */ - volatile uint8_t VCH0CTL; - /* 0x05: Calibration Data Control */ - volatile uint8_t KDCTL; - /* 0x06-0x17: Reserved1 */ - volatile uint8_t reserved1[18]; - /* 0x18: Voltage Channel 0 Data Buffer LSB */ - volatile uint8_t VCH0DATL; - /* 0x19: Voltage Channel 0 Data Buffer MSB */ - volatile uint8_t VCH0DATM; - /* 0x1a-0x43: Reserved2 */ - volatile uint8_t reserved2[42]; - /* 0x44: ADC Data Valid Status */ - volatile uint8_t ADCDVSTS; - /* 0x45-0x54: Reserved2-1 */ - volatile uint8_t reserved2_1[16]; - /* 0x55: ADC Input Voltage Mapping Full-Scale Code Selection 1 */ - volatile uint8_t ADCIVMFSCS1; - /* 0x56: ADC Input Voltage Mapping Full-Scale Code Selection 2 */ - volatile uint8_t ADCIVMFSCS2; - /* 0x57: ADC Input Voltage Mapping Full-Scale Code Selection 3 */ - volatile uint8_t ADCIVMFSCS3; - /* 0x58-0x5f: Reserved3 */ - volatile uint8_t reserved3[8]; - /* 0x60-0x6b: ADC channel 13~16 controller */ - struct adc_vchs_ctrl_t adc_vchs_ctrl[4]; - /* 0x6c: ADC Data Valid Status 2 */ - volatile uint8_t ADCDVSTS2; -}; -#endif /* !__ASSEMBLER__ */ - -/* ADC conversion time select 1 */ -#define IT8XXX2_ADC_ADCCTS1 BIT(7) -/* Analog accuracy initialization */ -#define IT8XXX2_ADC_AINITB BIT(3) -/* ADC conversion time select 0 */ -#define IT8XXX2_ADC_ADCCTS0 BIT(5) -/* ADC module enable */ -#define IT8XXX2_ADC_ADCEN BIT(0) -/* ADC data buffer keep enable */ -#define IT8XXX2_ADC_DBKEN BIT(7) -/* W/C data valid flag */ -#define IT8XXX2_ADC_DATVAL BIT(7) -/* Data valid interrupt of adc */ -#define IT8XXX2_ADC_INTDVEN BIT(5) -/* Voltage channel enable (Channel 4~7 and 13~16) */ -#define IT8XXX2_ADC_VCHEN BIT(4) -/* Automatic hardware calibration enable */ -#define IT8XXX2_ADC_AHCE BIT(7) -/* 0x046, 0x049, 0x04c, 0x06e, 0x071, 0x074: Voltage comparator x control */ -#define IT8XXX2_VCMP_CMPEN BIT(7) -#define IT8XXX2_VCMP_CMPINTEN BIT(6) -#define IT8XXX2_VCMP_GREATER_THRESHOLD BIT(5) -#define IT8XXX2_VCMP_EDGE_TRIGGER BIT(4) -#define IT8XXX2_VCMP_GPIO_ACTIVE_LOW BIT(3) -/* 0x077~0x07c: Voltage comparator x channel select MSB */ -#define IT8XXX2_VCMP_VCMPXCSELM BIT(0) - -/** - * - * (1Exxh) Clock and Power Management (ECPM) registers - * - */ -#define IT8XXX2_ECPM_BASE 0x00F01E00 - -#ifndef __ASSEMBLER__ -enum chip_pll_mode { - CHIP_PLL_DOZE = 0, - CHIP_PLL_SLEEP = 1, - CHIP_PLL_DEEP_DOZE = 3, -}; -#endif -/* - * TODO: use ecpm_it8xxx2_regs instead of following register declarations - * to fix in soc.c. - */ -#define IT8XXX2_ECPM_PLLCTRL ECREG(IT8XXX2_ECPM_BASE + 0x03) -#define IT8XXX2_ECPM_AUTOCG ECREG(IT8XXX2_ECPM_BASE + 0x04) -#define IT8XXX2_ECPM_CGCTRL3R ECREG(IT8XXX2_ECPM_BASE + 0x05) -#define IT8XXX2_ECPM_PLLFREQR ECREG(IT8XXX2_ECPM_BASE + 0x06) -#define IT8XXX2_ECPM_PLLCSS ECREG(IT8XXX2_ECPM_BASE + 0x08) -#define IT8XXX2_ECPM_SCDCR0 ECREG(IT8XXX2_ECPM_BASE + 0x0c) -#define IT8XXX2_ECPM_SCDCR1 ECREG(IT8XXX2_ECPM_BASE + 0x0d) -#define IT8XXX2_ECPM_SCDCR2 ECREG(IT8XXX2_ECPM_BASE + 0x0e) -#define IT8XXX2_ECPM_SCDCR3 ECREG(IT8XXX2_ECPM_BASE + 0x0f) -#define IT8XXX2_ECPM_SCDCR4 ECREG(IT8XXX2_ECPM_BASE + 0x10) - -/* - * The count number of the counter for 25 ms register. - * The 25 ms register is calculated by (count number *1.024 kHz). - */ - -#define I2C_CLK_LOW_TIMEOUT 255 /* ~=249 ms */ - -/** - * - * (1Cxxh) SMBus Interface (SMB) registers - * - */ -#define IT8XXX2_SMB_BASE 0x00F01C00 -#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 -#define IT8XXX2_SMB_4P7USL ECREG(IT8XXX2_SMB_BASE + 0x00) -#define IT8XXX2_SMB_4P0USL ECREG(IT8XXX2_SMB_BASE + 0x01) -#define IT8XXX2_SMB_300NS ECREG(IT8XXX2_SMB_BASE + 0x02) -#define IT8XXX2_SMB_250NS ECREG(IT8XXX2_SMB_BASE + 0x03) -#define IT8XXX2_SMB_25MS ECREG(IT8XXX2_SMB_BASE + 0x04) -#define IT8XXX2_SMB_45P3USL ECREG(IT8XXX2_SMB_BASE + 0x05) -#define IT8XXX2_SMB_45P3USH ECREG(IT8XXX2_SMB_BASE + 0x06) -#define IT8XXX2_SMB_4P7A4P0H ECREG(IT8XXX2_SMB_BASE + 0x07) -#define IT8XXX2_SMB_SLVISELR ECREG(IT8XXX2_SMB_BASE + 0x08) -#define IT8XXX2_SMB_SCLKTS(ch) ECREG(IT8XXX2_SMB_BASE + 0x09 + ch) -#define IT8XXX2_SMB_MSTFCTRL1 ECREG(IT8XXX2_SMB_BASE + 0x0D) -#define IT8XXX2_SMB_MSTFSTS1 ECREG(IT8XXX2_SMB_BASE + 0x0E) -#define IT8XXX2_SMB_MSTFCTRL2 ECREG(IT8XXX2_SMB_BASE + 0x0F) -#define IT8XXX2_SMB_MSTFSTS2 ECREG(IT8XXX2_SMB_BASE + 0x10) -#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x11) -#define IT8XXX2_SMB_I2CW2RF ECREG(IT8XXX2_SMB_BASE + 0x12) -#define IT8XXX2_SMB_IWRFISTA ECREG(IT8XXX2_SMB_BASE + 0x13) -#define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x20) -#define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x21) -#define IT8XXX2_SMB_SFFCTL ECREG(IT8XXX2_SMB_BASE + 0x55) -#define IT8XXX2_SMB_HOSTA(base) ECREG(base + 0x00) -#define IT8XXX2_SMB_HOCTL(base) ECREG(base + 0x01) -#define IT8XXX2_SMB_HOCMD(base) ECREG(base + 0x02) -#define IT8XXX2_SMB_TRASLA(base) ECREG(base + 0x03) -#define IT8XXX2_SMB_D0REG(base) ECREG(base + 0x04) -#define IT8XXX2_SMB_D1REG(base) ECREG(base + 0x05) -#define IT8XXX2_SMB_HOBDB(base) ECREG(base + 0x06) -#define IT8XXX2_SMB_PECERC(base) ECREG(base + 0x07) -#define IT8XXX2_SMB_SMBPCTL(base) ECREG(base + 0x0A) -#define IT8XXX2_SMB_HOCTL2(base) ECREG(base + 0x10) -#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 -#define IT8XXX2_SMB_SLVISEL ECREG(IT8XXX2_SMB_BASE + 0x08) -#define IT8XXX2_SMB_SMB01CHS ECREG(IT8XXX2_SMB_BASE + 0x09) -#define IT8XXX2_SMB_SMB23CHS ECREG(IT8XXX2_SMB_BASE + 0x0A) -#define IT8XXX2_SMB_SMB45CHS ECREG(IT8XXX2_SMB_BASE + 0x0B) -#define IT8XXX2_SMB_SCLKTS_BRGS ECREG(IT8XXX2_SMB_BASE + 0x80) -#define IT8XXX2_SMB_SCLKTS_BRGM ECREG(IT8XXX2_SMB_BASE + 0x81) -#define IT8XXX2_SMB_CHSBRG ECREG(IT8XXX2_SMB_BASE + 0x82) -#define IT8XXX2_SMB_CHSMOT ECREG(IT8XXX2_SMB_BASE + 0x83) - -/* SMBus register fields */ -/* 0x80: SMCLK Timing Setting Register Bridge Slave */ -#define IT8XXX2_SMB_PREDEN BIT(7) -#endif - -/** - * Enhanced SMBus/I2C Interface - * Ch_D: 0x00F03680, Ch_E: 0x00F03500, Ch_F: 0x00F03580 - * Ch_D: ch = 0x03, Ch_E: ch = 0x00, Ch_F: ch = 0x01 - */ -#define IT8XXX2_I2C_DRR(base) ECREG(base + 0x00) -#define IT8XXX2_I2C_PSR(base) ECREG(base + 0x01) -#define IT8XXX2_I2C_HSPR(base) ECREG(base + 0x02) -#define IT8XXX2_I2C_STR(base) ECREG(base + 0x03) -#define IT8XXX2_I2C_DHTR(base) ECREG(base + 0x04) -#define IT8XXX2_I2C_TOR(base) ECREG(base + 0x05) -#define IT8XXX2_I2C_DTR(base) ECREG(base + 0x08) -#define IT8XXX2_I2C_CTR(base) ECREG(base + 0x09) -#define IT8XXX2_I2C_CTR1(base) ECREG(base + 0x0A) -#define IT8XXX2_I2C_BYTE_CNT_H(base) ECREG(base + 0x0B) -#define IT8XXX2_I2C_BYTE_CNT_L(base) ECREG(base + 0x0C) -#define IT8XXX2_I2C_IRQ_ST(base) ECREG(base + 0x0D) -#define IT8XXX2_I2C_IDR(base) ECREG(base + 0x06) -#define IT8XXX2_I2C_TOS(base) ECREG(base + 0x07) -#define IT8XXX2_I2C_SLV_NUM_H(base) ECREG(base + 0x10) -#define IT8XXX2_I2C_SLV_NUM_L(base) ECREG(base + 0x11) -#define IT8XXX2_I2C_STR2(base) ECREG(base + 0x12) -#define IT8XXX2_I2C_NST(base) ECREG(base + 0x13) -#define IT8XXX2_I2C_TO_ARB_ST(base) ECREG(base + 0x18) -#define IT8XXX2_I2C_ERR_ST(base) ECREG(base + 0x19) -#define IT8XXX2_I2C_FST(base) ECREG(base + 0x1B) -#define IT8XXX2_I2C_EM(base) ECREG(base + 0x1C) -#define IT8XXX2_I2C_MODE_SEL(base) ECREG(base + 0x1D) -#define IT8XXX2_I2C_IDR2(base) ECREG(base + 0x1F) -#define IT8XXX2_I2C_CTR2(base) ECREG(base + 0x20) -#define IT8XXX2_I2C_RAMHA(base) ECREG(base + 0x23) -#define IT8XXX2_I2C_RAMLA(base) ECREG(base + 0x24) -#define IT8XXX2_I2C_RAMHA2(base) ECREG(base + 0x2C) -#define IT8XXX2_I2C_RAMLA2(base) ECREG(base + 0x2D) -#define IT8XXX2_I2C_CMD_ADDH(base) ECREG(base + 0x25) -#define IT8XXX2_I2C_CMD_ADDL(base) ECREG(base + 0x26) -#define IT8XXX2_I2C_RAMH2A(base) ECREG(base + 0x50) -#define IT8XXX2_I2C_CMD_ADDH2(base) ECREG(base + 0x52) - -/* SMBus/I2C register fields */ -/* 0x09-0xB: SMCLK Timing Setting */ -#define IT8XXX2_SMB_SMCLKS_1M 4 -#define IT8XXX2_SMB_SMCLKS_400K 3 -#define IT8XXX2_SMB_SMCLKS_100K 2 -#define IT8XXX2_SMB_SMCLKS_50K 1 - -/* 0x0E: SMBus FIFO Status 1 */ -#define IT8XXX2_SMB_FIFO1_EMPTY BIT(7) -#define IT8XXX2_SMB_FIFO1_FULL BIT(6) -/* 0x0D: SMBus FIFO Control 1 */ -/* 0x0F: SMBus FIFO Control 2 */ -#define IT8XXX2_SMB_BLKDS BIT(4) -#define IT8XXX2_SMB_FFEN BIT(3) -#define IT8XXX2_SMB_FFCHSEL2_B 0 -#define IT8XXX2_SMB_FFCHSEL2_C BIT(0) -/* 0x10: SMBus FIFO Status 2 */ -#define IT8XXX2_SMB_FIFO2_EMPTY BIT(7) -#define IT8XXX2_SMB_FIFO2_FULL BIT(6) -/* 0x12: I2C Wr To Rd FIFO */ -#define IT8XXX2_SMB_MAIF BIT(7) -#define IT8XXX2_SMB_MBCIF BIT(6) -#define IT8XXX2_SMB_MCIFI BIT(2) -#define IT8XXX2_SMB_MBIFI BIT(1) -#define IT8XXX2_SMB_MAIFI BIT(0) -/* 0x13: I2C Wr To Rd FIFO Interrupt Status */ -#define IT8XXX2_SMB_MCIFID BIT(2) -#define IT8XXX2_SMB_MAIFID BIT(0) -/* 0x41 0x81 0xC1: Host Control */ -#define IT8XXX2_SMB_SRT BIT(6) -#define IT8XXX2_SMB_LABY BIT(5) -#define IT8XXX2_SMB_SMCD_EXTND BIT(4) | BIT(3) | BIT(2) -#define IT8XXX2_SMB_KILL BIT(1) -#define IT8XXX2_SMB_INTREN BIT(0) -/* 0x43 0x83 0xC3: Transmit Slave Address */ -#define IT8XXX2_SMB_DIR BIT(0) -/* 0x4A 0x8A 0xCA: SMBus Pin Control */ -#define IT8XXX2_SMB_SMBDCS BIT(1) -#define IT8XXX2_SMB_SMBCS BIT(0) -/* 0x50 0x90 0xD0: Host Control 2 */ -#define IT8XXX2_SMB_SMD_TO_EN BIT(4) -#define IT8XXX2_SMB_I2C_SW_EN BIT(3) -#define IT8XXX2_SMB_I2C_SW_WAIT BIT(2) -#define IT8XXX2_SMB_I2C_EN BIT(1) -#define IT8XXX2_SMB_SMHEN BIT(0) -/* 0x55: Slave A FIFO Control */ -#define IT8XXX2_SMB_HSAPE BIT(1) -/* 0x03: Status Register */ -#define IT8XXX2_I2C_BYTE_DONE BIT(7) -#define IT8XXX2_I2C_RW BIT(2) -#define IT8XXX2_I2C_INT_PEND BIT(1) -/* 0x04: Data Hold Time */ -#define IT8XXX2_I2C_SOFT_RST BIT(7) -/* 0x07: Time Out Status */ -#define IT8XXX2_I2C_CLK_STRETCH BIT(7) -#define IT8XXX2_I2C_SCL_IN BIT(2) -#define IT8XXX2_I2C_SDA_IN BIT(0) -/* 0x09: Control Register */ -#define IT8XXX2_I2C_INT_EN BIT(6) -#define IT8XXX2_I2C_ACK BIT(3) -#define IT8XXX2_I2C_HALT BIT(0) -/* 0x0A: Control 1 */ -#define IT8XXX2_I2C_COMQ_EN BIT(7) -#define IT8XXX2_I2C_MDL_EN BIT(1) -/* 0x0C: Byte count */ -#define IT8XXX2_I2C_DMA_ADDR_RELOAD BIT(5) -#define IT8XXX2_I2C_BYTE_CNT_ENABLE BIT(3) -/* 0x0D: Interrupt Status */ -#define IT8XXX2_I2C_CNT_HOLD BIT(4) -#define IT8XXX2_I2C_IDW_CLR BIT(3) -#define IT8XXX2_I2C_IDR_CLR BIT(2) -#define IT8XXX2_I2C_SLVDATAFLG BIT(1) -#define IT8XXX2_I2C_P_CLR BIT(0) -/* 0x13: Nack Status */ -#define IT8XXX2_I2C_NST_CNS BIT(7) -#define IT8XXX2_I2C_NST_ID_NACK BIT(3) -/* 0x18: Timeout and Arbiter Status */ -#define IT8XXX2_I2C_SCL_TIMEOUT_EN BIT(7) -#define IT8XXX2_I2C_SDA_TIMEOUT_EN BIT(6) -/* 0x19: Error Status */ -#define IT8XXX2_I2C_ERR_ST_DEV1_EIRQ BIT(0) -/* 0x1B: Finish Status */ -#define IT8XXX2_I2C_FST_DEV1_IRQ BIT(4) -/* 0x1C: Error Mask */ -#define IT8XXX2_I2C_EM_DEV1_IRQ BIT(4) - -/* - * TODO: use gctrl_it8xxx2_regs instead of following register declarations - * to fix in cros_flash_it8xxx2.c, cros_shi_it8xxx2.c and tcpm\it8xxx2.c. - */ -/* --- General Control (GCTRL) --- */ -#define IT83XX_GCTRL_BASE 0x00F02000 - -#define IT83XX_GCTRL_CHIPID1 ECREG(IT83XX_GCTRL_BASE + 0x85) -#define IT83XX_GCTRL_CHIPID2 ECREG(IT83XX_GCTRL_BASE + 0x86) -#define IT83XX_GCTRL_CHIPVER ECREG(IT83XX_GCTRL_BASE + 0x02) -#define IT83XX_GCTRL_MCCR3 ECREG(IT83XX_GCTRL_BASE + 0x20) -#define IT83XX_GCTRL_SPISLVPFE BIT(6) -#define IT83XX_GCTRL_EWPR0PFH(i) ECREG(IT83XX_GCTRL_BASE + 0x60 + i) -#define IT83XX_GCTRL_EWPR0PFD(i) ECREG(IT83XX_GCTRL_BASE + 0xA0 + i) -#define IT83XX_GCTRL_EWPR0PFEC(i) ECREG(IT83XX_GCTRL_BASE + 0xC0 + i) - -/* - * TODO: use spisc_it8xxx2_regs instead of following register declarations - * to fix in cros_shi_it8xxx2.c. - */ -/* Serial Peripheral Interface (SPI) */ -#define IT83XX_SPI_BASE 0x00F03A00 - -#define IT83XX_SPI_SPISGCR ECREG(IT83XX_SPI_BASE + 0x00) -#define IT83XX_SPI_SPISCEN BIT(0) -#define IT83XX_SPI_TXRXFAR ECREG(IT83XX_SPI_BASE + 0x01) -#define IT83XX_SPI_CPURXF2A BIT(4) -#define IT83XX_SPI_CPURXF1A BIT(3) -#define IT83XX_SPI_CPUTFA BIT(1) -#define IT83XX_SPI_TXFCR ECREG(IT83XX_SPI_BASE + 0x02) -#define IT83XX_SPI_TXFCMR BIT(2) -#define IT83XX_SPI_TXFR BIT(1) -#define IT83XX_SPI_TXFS BIT(0) -#define IT83XX_SPI_GCR2 ECREG(IT83XX_SPI_BASE + 0x03) -#define IT83XX_SPI_RXF2OC BIT(4) -#define IT83XX_SPI_RXF1OC BIT(3) -#define IT83XX_SPI_RXFAR BIT(0) -#define IT83XX_SPI_IMR ECREG(IT83XX_SPI_BASE + 0x04) -#define IT83XX_SPI_RX_FIFO_FULL BIT(7) -#define IT83XX_SPI_RX_REACH BIT(5) -#define IT83XX_SPI_EDIM BIT(2) -#define IT83XX_SPI_ISR ECREG(IT83XX_SPI_BASE + 0x05) -#define IT83XX_SPI_TXFSR ECREG(IT83XX_SPI_BASE + 0x06) -#define IT83XX_SPI_ENDDETECTINT BIT(2) -#define IT83XX_SPI_RXFSR ECREG(IT83XX_SPI_BASE + 0x07) -#define IT83XX_SPI_RXFFSM (BIT(4) | BIT(3)) -#define IT83XX_SPI_RXF2FS BIT(2) -#define IT83XX_SPI_RXF1FS BIT(1) -#ifdef CHIP_VARIANT_IT83202BX -#define IT83XX_SPI_SPISRDR ECREG(IT83XX_SPI_BASE + 0x08) -#else -#define IT83XX_SPI_SPISRDR ECREG(IT83XX_SPI_BASE + 0x0b) -#endif -#define IT83XX_SPI_CPUWTFDB0 ECREG_u32(IT83XX_SPI_BASE + 0x08) -#define IT83XX_SPI_FCR ECREG(IT83XX_SPI_BASE + 0x09) -#define IT83XX_SPI_SPISRTXF BIT(2) -#define IT83XX_SPI_RXFR BIT(1) -#define IT83XX_SPI_RXFCMR BIT(0) -#define IT83XX_SPI_RXFRDRB0 ECREG_u32(IT83XX_SPI_BASE + 0x0C) -#define IT83XX_SPI_FTCB0R ECREG(IT83XX_SPI_BASE + 0x18) -#define IT83XX_SPI_FTCB1R ECREG(IT83XX_SPI_BASE + 0x19) -#define IT83XX_SPI_TCCB0 ECREG(IT83XX_SPI_BASE + 0x1A) -#define IT83XX_SPI_TCCB1 ECREG(IT83XX_SPI_BASE + 0x1B) -#define IT83XX_SPI_HPR2 ECREG(IT83XX_SPI_BASE + 0x1E) -#define IT83XX_SPI_EMMCBMR ECREG(IT83XX_SPI_BASE + 0x21) -#define IT83XX_SPI_EMMCABM BIT(1) /* eMMC Alternative Boot Mode */ -#define IT83XX_SPI_RX_VLISMR ECREG(IT83XX_SPI_BASE + 0x26) -#define IT83XX_SPI_RVLIM BIT(0) -#define IT83XX_SPI_RX_VLISR ECREG(IT83XX_SPI_BASE + 0x27) -#define IT83XX_SPI_RVLI BIT(0) - -/** - * - * (20xxh) General Control (GCTRL) registers - * - */ -#define GCTRL_IT8XXX2_REGS_BASE \ - ((struct gctrl_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gctrl))) - -#ifndef __ASSEMBLER__ -struct gctrl_it8xxx2_regs { - /* 0x00-0x01: Reserved_00_01 */ - volatile uint8_t reserved_00_01[2]; - /* 0x02: Chip Version */ - volatile uint8_t GCTRL_ECHIPVER; - /* 0x03-0x05: Reserved_03_05 */ - volatile uint8_t reserved_03_05[3]; - /* 0x06: Reset Status */ - volatile uint8_t GCTRL_RSTS; - /* 0x07-0x09: Reserved_07_09 */ - volatile uint8_t reserved_07_09[3]; - /* 0x0A: Base Address Select */ - volatile uint8_t GCTRL_BADRSEL; - /* 0x0B: Wait Next Clock Rising */ - volatile uint8_t GCTRL_WNCKR; - /* 0x0C: reserved_0c */ - volatile uint8_t reserved_0c; - /* 0x0D: Special Control 1 */ - volatile uint8_t GCTRL_SPCTRL1; - /* 0x0E-0x0F: reserved_0e_0f */ - volatile uint8_t reserved_0e_0f[2]; - /* 0x10: Reset Control DMM */ - volatile uint8_t GCTRL_RSTDMMC; - /* 0x11: Reset Control 4 */ - volatile uint8_t GCTRL_RSTC4; - /* 0x12-0x1B: reserved_12_1b */ - volatile uint8_t reserved_12_1b[10]; - /* 0x1C: Special Control 4 */ - volatile uint8_t GCTRL_SPCTRL4; - /* 0x1D-0x1F: reserved_1d_1f */ - volatile uint8_t reserved_1d_1f[3]; - /* 0x20: Memory Controller Configuration 3 */ - volatile uint8_t GCTRL_MCCR3; - /* 0x21: Reset Control 5 */ - volatile uint8_t GCTRL_RSTC5; - /* 0x22-0x2F: reserved_22_2f */ - volatile uint8_t reserved_22_2f[14]; - /* 0x30: Memory Controller Configuration */ - volatile uint8_t GCTRL_MCCR; - /* 0x31: Externel ILM/DLM Size */ - volatile uint8_t GCTRL_EIDSR; - /* 0x32: Reserved_32 */ - volatile uint8_t reserved_32; - /* 0x33: Pin Multi-function Enable 2 */ - volatile uint8_t gctrl_pmer2; - /* 0x34-0x36: Reserved_34_36 */ - volatile uint8_t reserved_34_36[3]; - /* 0x37: Eflash Protect Lock */ - volatile uint8_t GCTRL_EPLR; - /* 0x38-0x40: Reserved_38_40 */ - volatile uint8_t reserved_38_40[9]; - /* 0x41: Interrupt Vector Table Base Address */ - volatile uint8_t GCTRL_IVTBAR; - /* 0x42-0x43: Reserved_42_43 */ - volatile uint8_t reserved_42_43[2]; - /* 0x44: Memory Controller Configuration 2 */ - volatile uint8_t GCTRL_MCCR2; - /* 0x45: Reserved_45 */ - volatile uint8_t reserved_45; - /* 0x46: Pin Multi-function Enable 3 */ - volatile uint8_t GCTRL_PMER3; - /* 0x47-0x4A: reserved_47_4a */ - volatile uint8_t reserved_47_4a[4]; - /* 0x4B: ETWD and UART Control */ - volatile uint8_t GCTRL_ETWDUARTCR; - /* 0x4C: Wakeup MCU Control */ - volatile uint8_t GCTRL_WMCR; - /* 0x4D-0x4F: reserved_4d_4f */ - volatile uint8_t reserved_4d_4f[3]; - /* 0x50: Port 80h/81h Status Register */ - volatile uint8_t GCTRL_P80H81HSR; - /* 0x51: Port 80h Data Register */ - volatile uint8_t GCTRL_P80HDR; - /* 0x52: Port 81h Data Register */ - volatile uint8_t GCTRL_P81HDR; - /* 0x53: H2RAM Offset Register */ - volatile uint8_t GCTRL_H2ROFSR; - /* 0x54-0x5C: reserved_54_5c */ - volatile uint8_t reserved_54_5c[9]; - /* 0x5D: RISCV ILM Configuration 0 */ - volatile uint8_t GCTRL_RVILMCR0; - /* 0x5E-0x84: reserved_5e_84 */ - volatile uint8_t reserved_5e_84[39]; - /* 0x85: Chip ID Byte 1 */ - volatile uint8_t GCTRL_ECHIPID1; - /* 0x86: Chip ID Byte 2 */ - volatile uint8_t GCTRL_ECHIPID2; - /* 0x87: Chip ID Byte 3 */ - volatile uint8_t GCTRL_ECHIPID3; -}; -#endif /* !__ASSEMBLER__ */ - -/* GCTRL register fields */ -/* 0x06: Reset Status */ -#define IT8XXX2_GCTRL_LRS (BIT(1) | BIT(0)) -#define IT8XXX2_GCTRL_IWDTR BIT(1) -/* 0x10: Reset Control DMM */ -#define IT8XXX2_GCTRL_UART1SD BIT(3) -#define IT8XXX2_GCTRL_UART2SD BIT(2) -/* 0x11: Reset Control 4 */ -#define IT8XXX2_GCTRL_RPECI BIT(4) -#define IT8XXX2_GCTRL_RUART2 BIT(2) -#define IT8XXX2_GCTRL_RUART1 BIT(1) -/* 0x1C: Special Control 4 */ -#define IT8XXX2_GCTRL_LRSIWR BIT(2) -#define IT8XXX2_GCTRL_LRSIPWRSWTR BIT(1) -#define IT8XXX2_GCTRL_LRSIPGWR BIT(0) -/* 0x20: Memory Controller Configuration 3 */ -#define IT8XXX2_GCTRL_SPISLVPFE BIT(6) -/* 0x30: Memory Controller Configuration */ -#define IT8XXX2_GCTRL_ICACHE_RESET BIT(4) -/* 0x37: Eflash Protect Lock */ -#define IT8XXX2_GCTRL_EPLR_ENABLE BIT(0) -/* 0x46: Pin Multi-function Enable 3 */ -#define IT8XXX2_GCTRL_SMB3PSEL BIT(6) -/* 0x4B: ETWD and UART Control */ -#define IT8XXX2_GCTRL_ETWD_HW_RST_EN BIT(0) -/* 0x5D: RISCV ILM Configuration 0 */ -#define IT8XXX2_GCTRL_ILM0_ENABLE BIT(0) -/* Accept Port 80h Cycle */ -#define IT8XXX2_GCTRL_ACP80 BIT(6) -/* USB Debug Enable */ -#define IT8XXX2_GCTRL_MCCR_USB_EN BIT(7) -/* USB Pad Power-On Enable */ -#define IT8XXX2_GCTRL_PMER2_USB_PAD_EN BIT(7) - -/* - * VCC Detector Option. - * bit[7-6] = 1: The VCC power status is treated as power-on. - * The VCC supply of eSPI and related functions (EC2I, KBC, PMC and - * PECI). It means VCC should be logic high before using these - * functions, or firmware treats VCC logic high. - */ -#define IT8XXX2_GCTRL_VCCDO_MASK (BIT(6) | BIT(7)) -#define IT8XXX2_GCTRL_VCCDO_VCC_ON BIT(6) -/* - * bit[3] = 0: The reset source of PNPCFG is RSTPNP bit in RSTCH - * register and WRST#. - */ -#define IT8XXX2_GCTRL_HGRST BIT(3) -/* bit[2] = 1: Enable global reset. */ -#define IT8XXX2_GCTRL_GRST BIT(2) - -/** - * - * (22xxh) Battery-backed SRAM (BRAM) registers - * - */ -#ifndef __ASSEMBLER__ -/* Battery backed RAM indices. */ -#define BRAM_MAGIC_FIELD_OFFSET 0xbc -enum bram_indices { - - /* This field is used to indicate BRAM is valid or not. */ - BRAM_IDX_VALID_FLAGS0 = BRAM_MAGIC_FIELD_OFFSET, - BRAM_IDX_VALID_FLAGS1, - BRAM_IDX_VALID_FLAGS2, - BRAM_IDX_VALID_FLAGS3 -}; -#endif /* !__ASSEMBLER__ */ - -#ifndef __ASSEMBLER__ -/* - * EC2I bridge registers - */ -struct ec2i_regs { - /* 0x00: Indirect Host I/O Address Register */ - volatile uint8_t IHIOA; - /* 0x01: Indirect Host Data Register */ - volatile uint8_t IHD; - /* 0x02: Lock Super I/O Host Access Register */ - volatile uint8_t LSIOHA; - /* 0x03: Super I/O Access Lock Violation Register */ - volatile uint8_t SIOLV; - /* 0x04: EC to I-Bus Modules Access Enable Register */ - volatile uint8_t IBMAE; - /* 0x05: I-Bus Control Register */ - volatile uint8_t IBCTL; -}; - -/* Index list of the host interface registers of PNPCFG */ -enum host_pnpcfg_index { - /* Logical Device Number */ - HOST_INDEX_LDN = 0x07, - /* Chip ID Byte 1 */ - HOST_INDEX_CHIPID1 = 0x20, - /* Chip ID Byte 2 */ - HOST_INDEX_CHIPID2 = 0x21, - /* Chip Version */ - HOST_INDEX_CHIPVER = 0x22, - /* Super I/O Control */ - HOST_INDEX_SIOCTRL = 0x23, - /* Super I/O IRQ Configuration */ - HOST_INDEX_SIOIRQ = 0x25, - /* Super I/O General Purpose */ - HOST_INDEX_SIOGP = 0x26, - /* Super I/O Power Mode */ - HOST_INDEX_SIOPWR = 0x2D, - /* Depth 2 I/O Address */ - HOST_INDEX_D2ADR = 0x2E, - /* Depth 2 I/O Data */ - HOST_INDEX_D2DAT = 0x2F, - /* Logical Device Activate Register */ - HOST_INDEX_LDA = 0x30, - /* I/O Port Base Address Bits [15:8] for Descriptor 0 */ - HOST_INDEX_IOBAD0_MSB = 0x60, - /* I/O Port Base Address Bits [7:0] for Descriptor 0 */ - HOST_INDEX_IOBAD0_LSB = 0x61, - /* I/O Port Base Address Bits [15:8] for Descriptor 1 */ - HOST_INDEX_IOBAD1_MSB = 0x62, - /* I/O Port Base Address Bits [7:0] for Descriptor 1 */ - HOST_INDEX_IOBAD1_LSB = 0x63, - /* Interrupt Request Number and Wake-Up on IRQ Enabled */ - HOST_INDEX_IRQNUMX = 0x70, - /* Interrupt Request Type Select */ - HOST_INDEX_IRQTP = 0x71, - /* DMA Channel Select 0 */ - HOST_INDEX_DMAS0 = 0x74, - /* DMA Channel Select 1 */ - HOST_INDEX_DMAS1 = 0x75, - /* Device Specific Logical Device Configuration 1 to 10 */ - HOST_INDEX_DSLDC1 = 0xF0, - HOST_INDEX_DSLDC2 = 0xF1, - HOST_INDEX_DSLDC3 = 0xF2, - HOST_INDEX_DSLDC4 = 0xF3, - HOST_INDEX_DSLDC5 = 0xF4, - HOST_INDEX_DSLDC6 = 0xF5, - HOST_INDEX_DSLDC7 = 0xF6, - HOST_INDEX_DSLDC8 = 0xF7, - HOST_INDEX_DSLDC9 = 0xF8, - HOST_INDEX_DSLDC10 = 0xF9, -}; - -/* List of logical device number (LDN) assignments */ -enum logical_device_number { - /* Serial Port 1 */ - LDN_UART1 = 0x01, - /* Serial Port 2 */ - LDN_UART2 = 0x02, - /* System Wake-Up Control */ - LDN_SWUC = 0x04, - /* KBC/Mouse Interface */ - LDN_KBC_MOUSE = 0x05, - /* KBC/Keyboard Interface */ - LDN_KBC_KEYBOARD = 0x06, - /* Consumer IR */ - LDN_CIR = 0x0A, - /* Shared Memory/Flash Interface */ - LDN_SMFI = 0x0F, - /* RTC-like Timer */ - LDN_RTCT = 0x10, - /* Power Management I/F Channel 1 */ - LDN_PMC1 = 0x11, - /* Power Management I/F Channel 2 */ - LDN_PMC2 = 0x12, - /* Serial Peripheral Interface */ - LDN_SSPI = 0x13, - /* Platform Environment Control Interface */ - LDN_PECI = 0x14, - /* Power Management I/F Channel 3 */ - LDN_PMC3 = 0x17, - /* Power Management I/F Channel 4 */ - LDN_PMC4 = 0x18, - /* Power Management I/F Channel 5 */ - LDN_PMC5 = 0x19, -}; - -/* Structure for initializing PNPCFG via ec2i. */ -struct ec2i_t { - /* index port */ - enum host_pnpcfg_index index_port; - /* data port */ - uint8_t data_port; -}; - -/* EC2I access index/data port */ -enum ec2i_access { - /* index port */ - EC2I_ACCESS_INDEX = 0, - /* data port */ - EC2I_ACCESS_DATA = 1, -}; - -/* EC to I-Bus Access Enabled */ -#define EC2I_IBCTL_CSAE BIT(0) -/* EC Read from I-Bus */ -#define EC2I_IBCTL_CRIB BIT(1) -/* EC Write to I-Bus */ -#define EC2I_IBCTL_CWIB BIT(2) -#define EC2I_IBCTL_CRWIB (EC2I_IBCTL_CRIB | EC2I_IBCTL_CWIB) - -/* PNPCFG Register EC Access Enable */ -#define EC2I_IBMAE_CFGAE BIT(0) - -/* - * KBC registers - */ -struct kbc_regs { - /* 0x00: KBC Host Interface Control Register */ - volatile uint8_t KBHICR; - /* 0x01: Reserved1 */ - volatile uint8_t reserved1; - /* 0x02: KBC Interrupt Control Register */ - volatile uint8_t KBIRQR; - /* 0x03: Reserved2 */ - volatile uint8_t reserved2; - /* 0x04: KBC Host Interface Keyboard/Mouse Status Register */ - volatile uint8_t KBHISR; - /* 0x05: Reserved3 */ - volatile uint8_t reserved3; - /* 0x06: KBC Host Interface Keyboard Data Output Register */ - volatile uint8_t KBHIKDOR; - /* 0x07: Reserved4 */ - volatile uint8_t reserved4; - /* 0x08: KBC Host Interface Mouse Data Output Register */ - volatile uint8_t KBHIMDOR; - /* 0x09: Reserved5 */ - volatile uint8_t reserved5; - /* 0x0a: KBC Host Interface Keyboard/Mouse Data Input Register */ - volatile uint8_t KBHIDIR; -}; - -/* Output Buffer Full */ -#define KBC_KBHISR_OBF BIT(0) -/* Input Buffer Full */ -#define KBC_KBHISR_IBF BIT(1) -/* A2 Address (A2) */ -#define KBC_KBHISR_A2_ADDR BIT(3) -#define KBC_KBHISR_STS_MASK (KBC_KBHISR_OBF | KBC_KBHISR_IBF \ - | KBC_KBHISR_A2_ADDR) - -/* Clear Output Buffer Full */ -#define KBC_KBHICR_COBF BIT(6) -/* IBF/OBF Clear Mode Enable */ -#define KBC_KBHICR_IBFOBFCME BIT(5) -/* Input Buffer Full CPU Interrupt Enable */ -#define KBC_KBHICR_IBFCIE BIT(3) -/* Output Buffer Empty CPU Interrupt Enable */ -#define KBC_KBHICR_OBECIE BIT(2) -/* Output Buffer Full Mouse Interrupt Enable */ -#define KBC_KBHICR_OBFMIE BIT(1) -/* Output Buffer Full Keyboard Interrupt Enable */ -#define KBC_KBHICR_OBFKIE BIT(0) - -/* - * PMC registers - */ -struct pmc_regs { - /* 0x00: Host Interface PM Channel 1 Status */ - volatile uint8_t PM1STS; - /* 0x01: Host Interface PM Channel 1 Data Out Port */ - volatile uint8_t PM1DO; - /* 0x02: Host Interface PM Channel 1 Data Out Port with SCI# */ - volatile uint8_t PM1DOSCI; - /* 0x03: Host Interface PM Channel 1 Data Out Port with SMI# */ - volatile uint8_t PM1DOSMI; - /* 0x04: Host Interface PM Channel 1 Data In Port */ - volatile uint8_t PM1DI; - /* 0x05: Host Interface PM Channel 1 Data In Port with SCI# */ - volatile uint8_t PM1DISCI; - /* 0x06: Host Interface PM Channel 1 Control */ - volatile uint8_t PM1CTL; - /* 0x07: Host Interface PM Channel 1 Interrupt Control */ - volatile uint8_t PM1IC; - /* 0x08: Host Interface PM Channel 1 Interrupt Enable */ - volatile uint8_t PM1IE; - /* 0x09-0x0f: Reserved1 */ - volatile uint8_t reserved1[7]; - /* 0x10: Host Interface PM Channel 2 Status */ - volatile uint8_t PM2STS; - /* 0x11: Host Interface PM Channel 2 Data Out Port */ - volatile uint8_t PM2DO; - /* 0x12: Host Interface PM Channel 2 Data Out Port with SCI# */ - volatile uint8_t PM2DOSCI; - /* 0x13: Host Interface PM Channel 2 Data Out Port with SMI# */ - volatile uint8_t PM2DOSMI; - /* 0x14: Host Interface PM Channel 2 Data In Port */ - volatile uint8_t PM2DI; - /* 0x15: Host Interface PM Channel 2 Data In Port with SCI# */ - volatile uint8_t PM2DISCI; - /* 0x16: Host Interface PM Channel 2 Control */ - volatile uint8_t PM2CTL; - /* 0x17: Host Interface PM Channel 2 Interrupt Control */ - volatile uint8_t PM2IC; - /* 0x18: Host Interface PM Channel 2 Interrupt Enable */ - volatile uint8_t PM2IE; - /* 0x19: Mailbox Control */ - volatile uint8_t MBXCTRL; - /* 0x1a-0x1f: Reserved2 */ - volatile uint8_t reserved2[6]; - /* 0x20-0xff: Reserved3 */ - volatile uint8_t reserved3[0xe0]; -}; - -/* Input Buffer Full Interrupt Enable */ -#define PMC_PM1CTL_IBFIE BIT(0) -/* Output Buffer Full */ -#define PMC_PM1STS_OBF BIT(0) -/* Input Buffer Full */ -#define PMC_PM1STS_IBF BIT(1) -/* General Purpose Flag */ -#define PMC_PM1STS_GPF BIT(2) -/* A2 Address (A2) */ -#define PMC_PM1STS_A2_ADDR BIT(3) - -/* PMC2 Input Buffer Full Interrupt Enable */ -#define PMC_PM2CTL_IBFIE BIT(0) -/* General Purpose Flag */ -#define PMC_PM2STS_GPF BIT(2) - -/* - * Dedicated Interrupt - * 0b: - * INT3: PMC Output Buffer Empty Int - * INT25: PMC Input Buffer Full Int - * 1b: - * INT3: PMC1 Output Buffer Empty Int - * INT25: PMC1 Input Buffer Full Int - * INT26: PMC2 Output Buffer Empty Int - * INT27: PMC2 Input Buffer Full Int - */ -#define PMC_MBXCTRL_DINT BIT(5) - -/* - * eSPI slave registers - */ -struct espi_slave_regs { - /* 0x00-0x03: Reserved1 */ - volatile uint8_t reserved1[4]; - - /* 0x04: General Capabilities and Configuration 0 */ - volatile uint8_t GCAPCFG0; - /* 0x05: General Capabilities and Configuration 1 */ - volatile uint8_t GCAPCFG1; - /* 0x06: General Capabilities and Configuration 2 */ - volatile uint8_t GCAPCFG2; - /* 0x07: General Capabilities and Configuration 3 */ - volatile uint8_t GCAPCFG3; - - /* Channel 0 (Peripheral Channel) Capabilities and Configurations */ - /* 0x08: Channel 0 Capabilities and Configuration 0 */ - volatile uint8_t CH_PC_CAPCFG0; - /* 0x09: Channel 0 Capabilities and Configuration 1 */ - volatile uint8_t CH_PC_CAPCFG1; - /* 0x0A: Channel 0 Capabilities and Configuration 2 */ - volatile uint8_t CH_PC_CAPCFG2; - /* 0x0B: Channel 0 Capabilities and Configuration 3 */ - volatile uint8_t CH_PC_CAPCFG3; - - /* Channel 1 (Virtual Wire Channel) Capabilities and Configurations */ - /* 0x0C: Channel 1 Capabilities and Configuration 0 */ - volatile uint8_t CH_VW_CAPCFG0; - /* 0x0D: Channel 1 Capabilities and Configuration 1 */ - volatile uint8_t CH_VW_CAPCFG1; - /* 0x0E: Channel 1 Capabilities and Configuration 2 */ - volatile uint8_t CH_VW_CAPCFG2; - /* 0x0F: Channel 1 Capabilities and Configuration 3 */ - volatile uint8_t CH_VW_CAPCFG3; - - /* Channel 2 (OOB Message Channel) Capabilities and Configurations */ - /* 0x10: Channel 2 Capabilities and Configuration 0 */ - volatile uint8_t CH_OOB_CAPCFG0; - /* 0x11: Channel 2 Capabilities and Configuration 1 */ - volatile uint8_t CH_OOB_CAPCFG1; - /* 0x12: Channel 2 Capabilities and Configuration 2 */ - volatile uint8_t CH_OOB_CAPCFG2; - /* 0x13: Channel 2 Capabilities and Configuration 3 */ - volatile uint8_t CH_OOB_CAPCFG3; - - /* Channel 3 (Flash Access Channel) Capabilities and Configurations */ - /* 0x14: Channel 3 Capabilities and Configuration 0 */ - volatile uint8_t CH_FLASH_CAPCFG0; - /* 0x15: Channel 3 Capabilities and Configuration 1 */ - volatile uint8_t CH_FLASH_CAPCFG1; - /* 0x16: Channel 3 Capabilities and Configuration 2 */ - volatile uint8_t CH_FLASH_CAPCFG2; - /* 0x17: Channel 3 Capabilities and Configuration 3 */ - volatile uint8_t CH_FLASH_CAPCFG3; - /* Channel 3 Capabilities and Configurations 2 */ - /* 0x18: Channel 3 Capabilities and Configuration 2-0 */ - volatile uint8_t CH_FLASH_CAPCFG2_0; - /* 0x19: Channel 3 Capabilities and Configuration 2-1 */ - volatile uint8_t CH_FLASH_CAPCFG2_1; - /* 0x1A: Channel 3 Capabilities and Configuration 2-2 */ - volatile uint8_t CH_FLASH_CAPCFG2_2; - /* 0x1B: Channel 3 Capabilities and Configuration 2-3 */ - volatile uint8_t CH_FLASH_CAPCFG2_3; - - /* 0x1c-0x1f: Reserved2 */ - volatile uint8_t reserved2[4]; - /* 0x20-0x8f: Reserved3 */ - volatile uint8_t reserved3[0x70]; - - /* 0x90: eSPI PC Control 0 */ - volatile uint8_t ESPCTRL0; - /* 0x91: eSPI PC Control 1 */ - volatile uint8_t ESPCTRL1; - /* 0x92: eSPI PC Control 2 */ - volatile uint8_t ESPCTRL2; - /* 0x93: eSPI PC Control 3 */ - volatile uint8_t ESPCTRL3; - /* 0x94: eSPI PC Control 4 */ - volatile uint8_t ESPCTRL4; - /* 0x95: eSPI PC Control 5 */ - volatile uint8_t ESPCTRL5; - /* 0x96: eSPI PC Control 6 */ - volatile uint8_t ESPCTRL6; - /* 0x97: eSPI PC Control 7 */ - volatile uint8_t ESPCTRL7; - /* 0x98-0x9f: Reserved4 */ - volatile uint8_t reserved4[8]; - - /* 0xa0: eSPI General Control 0 */ - volatile uint8_t ESGCTRL0; - /* 0xa1: eSPI General Control 1 */ - volatile uint8_t ESGCTRL1; - /* 0xa2: eSPI General Control 2 */ - volatile uint8_t ESGCTRL2; - /* 0xa3: eSPI General Control 3 */ - volatile uint8_t ESGCTRL3; - /* 0xa4-0xaf: Reserved5 */ - volatile uint8_t reserved5[12]; - - /* 0xb0: eSPI Upstream Control 0 */ - volatile uint8_t ESUCTRL0; - /* 0xb1: eSPI Upstream Control 1 */ - volatile uint8_t ESUCTRL1; - /* 0xb2: eSPI Upstream Control 2 */ - volatile uint8_t ESUCTRL2; - /* 0xb3: eSPI Upstream Control 3 */ - volatile uint8_t ESUCTRL3; - /* 0xb4-0xb5: Reserved6 */ - volatile uint8_t reserved6[2]; - /* 0xb6: eSPI Upstream Control 6 */ - volatile uint8_t ESUCTRL6; - /* 0xb7: eSPI Upstream Control 7 */ - volatile uint8_t ESUCTRL7; - /* 0xb8: eSPI Upstream Control 8 */ - volatile uint8_t ESUCTRL8; - /* 0xb9-0xbf: Reserved7 */ - volatile uint8_t reserved7[7]; - - /* 0xc0: eSPI OOB Control 0 */ - volatile uint8_t ESOCTRL0; - /* 0xc1: eSPI OOB Control 1 */ - volatile uint8_t ESOCTRL1; - /* 0xc2-0xc3: Reserved8 */ - volatile uint8_t reserved8[2]; - /* 0xc4: eSPI OOB Control 4 */ - volatile uint8_t ESOCTRL4; - /* 0xc5-0xcf: Reserved9 */ - volatile uint8_t reserved9[11]; - - /* 0xd0: eSPI SAFS Control 0 */ - volatile uint8_t ESPISAFSC0; - /* 0xd1: eSPI SAFS Control 1 */ - volatile uint8_t ESPISAFSC1; - /* 0xd2: eSPI SAFS Control 2 */ - volatile uint8_t ESPISAFSC2; - /* 0xd3: eSPI SAFS Control 3 */ - volatile uint8_t ESPISAFSC3; - /* 0xd4: eSPI SAFS Control 4 */ - volatile uint8_t ESPISAFSC4; - /* 0xd5: eSPI SAFS Control 5 */ - volatile uint8_t ESPISAFSC5; - /* 0xd6: eSPI SAFS Control 6 */ - volatile uint8_t ESPISAFSC6; - /* 0xd7: eSPI SAFS Control 7 */ - volatile uint8_t ESPISAFSC7; -}; - -/* - * eSPI VW registers - */ -struct espi_vw_regs { - /* 0x00-0x7f: VW index */ - volatile uint8_t VW_INDEX[0x80]; - /* 0x80-0x8f: Reserved1 */ - volatile uint8_t reserved1[0x10]; - /* 0x90: VW Contrl 0 */ - volatile uint8_t VWCTRL0; - /* 0x91: VW Contrl 1 */ - volatile uint8_t VWCTRL1; - /* 0x92: VW Contrl 2 */ - volatile uint8_t VWCTRL2; - /* 0x93: VW Contrl 3 */ - volatile uint8_t VWCTRL3; - /* 0x94: Reserved2 */ - volatile uint8_t reserved2; - /* 0x95: VW Contrl 5 */ - volatile uint8_t VWCTRL5; - /* 0x96: VW Contrl 6 */ - volatile uint8_t VWCTRL6; - /* 0x97: VW Contrl 7 */ - volatile uint8_t VWCTRL7; - /* 0x98-0x99: Reserved3 */ - volatile uint8_t reserved3[2]; -}; - -#define ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE 80 -/* - * eSPI Queue 0 registers - */ -struct espi_queue0_regs { - /* 0x00-0x3f: PUT_PC Data Byte 0-63 */ - volatile uint8_t PUT_PC_DATA[0x40]; - /* 0x40-0x7f: Reserved1 */ - volatile uint8_t reserved1[0x40]; - /* 0x80-0xcf: PUT_OOB Data Byte 0-79 */ - volatile uint8_t PUT_OOB_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE]; -}; - -/* - * eSPI Queue 1 registers - */ -struct espi_queue1_regs { - /* 0x00-0x4f: Upstream Data Byte 0-79 */ - volatile uint8_t UPSTREAM_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE]; - /* 0x50-0x7f: Reserved1 */ - volatile uint8_t reserved1[0x30]; - /* 0x80-0xbf: PUT_FLASH_NP Data Byte 0-63 */ - volatile uint8_t PUT_FLASH_NP_DATA[0x40]; -}; - -#endif /* !__ASSEMBLER__ */ - - -/** - * - * (3Axxh) SPI Slave Controller (SPISC) registers - * - */ -#ifndef __ASSEMBLER__ -struct spisc_it8xxx2_regs { - /* 0x00: SPI Slave General Control */ - volatile uint8_t SPISC_SPISGCR; - /* 0x01: Tx/Rx FIFO Access */ - volatile uint8_t SPISC_TXRXFAR; - /* 0x02: Tx FIFO Control */ - volatile uint8_t SPISC_TXFCR; - /* 0x03: SPI Slave General Control 2 */ - volatile uint8_t SPISC_SPISGCR2; - /* 0x04: Interrupt Mask */ - volatile uint8_t SPISC_IMR; - /* 0x05: Interrupt Status */ - volatile uint8_t SPISC_ISR; - /* 0x06: Tx FIFO Status */ - volatile uint8_t SPISC_TXFSR; - /* 0x07: Rx FIFO Status */ - volatile uint8_t SPISC_RXFSR; - /* 0x08: CPU Write Tx FIFO Data Byte0 */ - volatile uint8_t SPISC_CPUWTXFDB0R; - /* 0x09: FIFO Control / CPU Write Tx FIFO Data Byte1 */ - volatile uint8_t SPISC_FCR; - /* 0x0A: CPU Write Tx FIFO Data Byte2 */ - volatile uint8_t SPISC_CPUWTXFDB2R; - /* 0x0B: SPI Slave Response Data / CPU Write Tx FIFO Data Byte3 */ - volatile uint8_t SPISC_SPISRDR; - /* 0x0C: Rx FIFO Readout Data Byte0 */ - volatile uint8_t SPISC_RXFRDRB0; - /* 0x0D: Rx FIFO Readout Data Byte1 */ - volatile uint8_t SPISC_RXFRDRB1; - /* 0x0E: Rx FIFO Readout Data Byte2 */ - volatile uint8_t SPISC_RXFRDRB2; - /* 0x0F: Rx FIFO Readout Data Byte3 */ - volatile uint8_t SPISC_RXFRDRB3; - /* 0x10-0x17: Reserved1 */ - volatile uint8_t reserved1[8]; - /* 0x18: FIFO Target Count Byte0 */ - volatile uint8_t SPISC_FTCB0R; - /* 0x19: FIFO Target Count Byte1 */ - volatile uint8_t SPISC_FTCB1R; - /* 0x1A: Target Count Capture Byte0 */ - volatile uint8_t SPISC_TCCB0; - /* 0x1B: Target Count Capture Byte1 */ - volatile uint8_t SPISC_TCCB1; - /* 0x1C-0x1D: Reserved2 */ - volatile uint8_t reserved2[2]; - /* 0x1E: Hardware Parsing 2 */ - volatile uint8_t SPISC_HPR2; - /* 0x1F-0x25: Reserved3 */ - volatile uint8_t reserved3[7]; - /* 0x26: Rx Valid Length Interrupt Status Mask */ - volatile uint8_t SPISC_RXVLISMR; - /* 0x27: Rx Valid Length Interrupt Status */ - volatile uint8_t SPISC_RXVLISR; -}; -#endif /* !__ASSEMBLER__ */ - -/* SPISC register fields */ -/* 0x00: SPI Slave General Control */ -#define IT8XXX2_SPISC_SPISCEN BIT(0) -/* 0x01: Tx/Rx FIFO Access */ -#define IT8XXX2_SPISC_CPURXF1A BIT(3) -#define IT8XXX2_SPISC_CPUTFA BIT(1) -/* 0x02: Tx FIFO Control */ -#define IT8XXX2_SPISC_TXFCMR BIT(2) -#define IT8XXX2_SPISC_TXFR BIT(1) -#define IT8XXX2_SPISC_TXFS BIT(0) -/* 0x03: SPI Slave General Control 2 */ -#define IT8XXX2_SPISC_RXF2OC BIT(4) -#define IT8XXX2_SPISC_RXF1OC BIT(3) -#define IT8XXX2_SPISC_RXFAR BIT(0) -/* 0x04: Interrupt Mask */ -#define IT8XXX2_SPISC_EDIM BIT(2) -/* 0x06: Tx FIFO Status */ -#define IT8XXX2_SPISC_ENDDETECTINT BIT(2) -/* 0x09: FIFO Control */ -#define IT8XXX2_SPISC_SPISRTXF BIT(2) -#define IT8XXX2_SPISC_RXFR BIT(1) -#define IT8XXX2_SPISC_RXFCMR BIT(0) -/* 0x26: Rx Valid Length Interrupt Status Mask */ -#define IT8XXX2_SPISC_RVLIM BIT(0) -/* 0x27: Rx Valid Length Interrupt Status */ -#define IT8XXX2_SPISC_RVLI BIT(0) - -#endif /* CHIP_CHIPREGS_H */ diff --git a/soc/riscv/riscv-ite/common/soc_common.h b/soc/riscv/riscv-ite/common/soc_common.h deleted file mode 100644 index 5b981783164..00000000000 --- a/soc/riscv/riscv-ite/common/soc_common.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file configuration macros for riscv SOCs supporting the riscv - * privileged architecture specification - */ - -#ifndef __SOC_COMMON_H_ -#define __SOC_COMMON_H_ - -#include "chip_chipregs.h" - -/* SOC-specific MCAUSE bitfields */ - -/* Interrupt Mask. 1 (interrupt) or 0 (exception) */ -#define SOC_MCAUSE_IRQ_MASK BIT(31) - -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF - -/* Exception code of environment call from M-mode */ -#define SOC_MCAUSE_ECALL_EXP 11 - -#ifndef _ASMLANGUAGE - -#ifdef CONFIG_HAS_ITE_INTC -/* - * Save current interrupt state of soc-level into ier_setting[] with - * disabling interrupt. - */ -void ite_intc_save_and_disable_interrupts(void); -/* Restore interrupt state of soc-level from ier_setting[], use with care. */ -void ite_intc_restore_interrupts(void); - -extern void ite_intc_irq_enable(unsigned int irq); -extern void ite_intc_irq_disable(unsigned int irq); -extern uint8_t ite_intc_get_irq_num(void); -extern int ite_intc_irq_is_enable(unsigned int irq); -extern void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags); -extern void ite_intc_isr_clear(unsigned int irq); -void ite_intc_init(void); -bool ite_intc_no_irq(void); -#endif /* CONFIG_HAS_ITE_INTC */ - -#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M -void timer_5ms_one_shot(void); -#endif - -uint32_t chip_get_pll_freq(void); -void chip_pll_ctrl(enum chip_pll_mode mode); -void riscv_idle(enum chip_pll_mode mode, unsigned int key); - -#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING -void chip_permit_idle(void); -void chip_block_idle(void); -bool cpu_idle_not_allowed(void); -#endif - -#endif /* !_ASMLANGUAGE */ - -#endif /* __SOC_COMMON_H_ */ diff --git a/soc/riscv/riscv-ite/common/soc_irq.S b/soc/riscv/riscv-ite/common/soc_irq.S deleted file mode 100644 index a412ca6a796..00000000000 --- a/soc/riscv/riscv-ite/common/soc_irq.S +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020 ITE Corporation. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * common interrupt management code for riscv SOCs supporting the riscv - * privileged architecture specification - */ -#include -#include -#include -#include -#include - -/* exports */ -GTEXT(__soc_handle_irq) - -/* - * SOC-specific function to handle pending IRQ number generating the interrupt. - * Exception number is given as parameter via register a0. - * Jump to get_irq() function directly and return to caller by its - * ret instruction. - */ -SECTION_FUNC(exception.other, __soc_handle_irq) - j get_irq - -/* - * __soc_is_irq is defined as .weak to allow re-implementation by - * SOCs that does not truely follow the riscv privilege specification. - */ -WTEXT(__soc_is_irq) - -/* - * SOC-specific function to determine if the exception is the result of a - * an interrupt or an exception - * return 1 (interrupt) or 0 (exception) - * - */ -SECTION_FUNC(exception.other, __soc_is_irq) - /* Read mcause and check if interrupt bit (bit 31) is set */ - csrr a0, mcause - srli a0, a0, 31 - ret diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series b/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series deleted file mode 100644 index 4e6b7c18cca..00000000000 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV32_IT8XXX2 - -config SOC_SERIES - default "it8xxx2" - -config RISCV_GP - default y - -config ARCH_HAS_CUSTOM_BUSY_WAIT - default y - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 32768 - -config SYS_CLOCK_TICKS_PER_SEC - default 4096 - -config UART_NS16550_WA_ISR_REENABLE_INTERRUPT - default y - depends on UART_NS16550 - -config RISCV_HAS_CPU_IDLE - default y - -config FLASH_INIT_PRIORITY - default 0 - -config IT8XXX2_PLL_SEQUENCE_PRIORITY - int - default 1 - depends on SOC_IT8XXX2_PLL_FLASH_48M - -config VCMP_IT8XXX2_INIT_PRIORITY - default 91 if VCMP_IT8XXX2_WORKQUEUE - -config PINCTRL - default y - -config NUM_IRQS - default 185 - -config DYNAMIC_INTERRUPTS - default y - -config GEN_ISR_TABLES - default y - -config GEN_IRQ_START_VECTOR - default 0 - -config GEN_SW_ISR_TABLE - default y - -config RISCV_SOC_INTERRUPT_INIT - default y - -source "soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.it8*" - -endif # SOC_SERIES_RISCV32_IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series b/soc/riscv/riscv-ite/it8xxx2/Kconfig.series deleted file mode 100644 index ebed0fcd120..00000000000 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.series +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV32_IT8XXX2 - bool "ITE IT8XXX2 implementation" - #depends on RISCV - # RV32IAFC is an uncommon configuration which is not supported by - # default in most toolchains, causing link-time errors. - select CPU_HAS_FPU if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "zephyr" || RISCV_ISA_EXT_M - select SOC_FAMILY_RISCV_ITE - select HAS_PM - help - Enable support for ITE IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc b/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc deleted file mode 100644 index 38525449f89..00000000000 --- a/soc/riscv/riscv-ite/it8xxx2/Kconfig.soc +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright (c) 2020 ITE Corporation. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 - -choice -prompt "ITE IT8XXX2 system implementation" -depends on SOC_SERIES_RISCV32_IT8XXX2 - -config SOC_IT8XXX2 - bool "ITE IT8XXX2 system implementation" - select RISCV - select ATOMIC_OPERATIONS_BUILTIN - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - # Workaround mul instruction bug, see: - # https://www.ite.com.tw/uploads/product_download/it81202-bx-chip-errata.pdf - select RISCV_ISA_EXT_M if !(SOC_IT81302_BX || SOC_IT81202_BX) - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select FLASH - select FLASH_HAS_PAGE_LAYOUT - select FLASH_HAS_DRIVER_ENABLED - select HAS_FLASH_LOAD_OFFSET - -endchoice - -config SOC_IT8XXX2_REG_SET_V1 - bool - help - This option is selected by a variable of which soc, and will - determine the register for the IT81xx2 specification. - -config SOC_IT8XXX2_REG_SET_V2 - bool - help - This option is selected by a variable of which soc, and will - determine the register for the IT82xx2 specification. - -if SOC_IT8XXX2 - -choice IT8XXX2_SERIES - prompt "IT8XXX2 Series" - default SOC_IT81302_BX - -config SOC_IT81302_BX - bool "IT81302 BX version" - select SOC_IT8XXX2_REG_SET_V1 - -config SOC_IT81202_BX - bool "IT81202 BX version" - select SOC_IT8XXX2_REG_SET_V1 - -config SOC_IT81302_CX - bool "IT81302 CX version" - select SOC_IT8XXX2_REG_SET_V1 - -config SOC_IT81202_CX - bool "IT81202 CX version" - select SOC_IT8XXX2_REG_SET_V1 - -config SOC_IT82202_AX - bool "IT82202 AX version" - select SOC_IT8XXX2_REG_SET_V2 - -config SOC_IT82302_AX - bool "IT82302 AX version" - select SOC_IT8XXX2_REG_SET_V2 - -config SOC_IT82002_AW - bool "IT82002 AW version" - select SOC_IT8XXX2_REG_SET_V2 - -endchoice - -config SOC_IT8XXX2_PLL_FLASH_48M - bool "Flash frequency is 48MHz" - default y - help - Change frequency of PLL, CPU, and flash to 48MHz during initialization. - - Set n to use the default settings. - (PLL and CPU run at 48MHz, flash frequency is 16MHz) - -config SOC_IT8XXX2_GPIO_GROUP_K_L_DEFAULT_PULL_DOWN - bool "The pins of GPIO group K and L aren't bonding with pad" - default y - help - On IT81202 (128-pins package), the pins of GPIO group K and L aren't - bonding with pad. So we configure these pins as internal pull-down - at default to prevent leakage current due to floating. - -config SOC_IT8XXX2_GPIO_H7_DEFAULT_OUTPUT_LOW - bool "The GPIOH7 isn't bonding with pad and is left floating internally" - default y - help - On IT81202/IT81302, the GPIOH7 isn't bonding with pad and is left - floating internally. We need to enable internal pull-down for the pin - to prevent leakage current, but IT81202/IT81302 doesn't have the - capability to pull it down. We can only set it as output low, - so we enable output low for it at initialization to prevent leakage. - -config SOC_IT8XXX2_CPU_IDLE_GATING - bool - help - This option determines whether the entering CPU idle mode can be - gated by individual drivers. When this option is disabled, CPU idle - mode is always permitted. - -choice - prompt "Clock source for PLL reference clock" - -config SOC_IT8XXX2_INT_32K - bool "Use the +/-2.3% internal clock generator" - -config SOC_IT8XXX2_EXT_32K - bool "Use external 32.768 kHz clock source" - -endchoice - -config SOC_IT8XXX2_USE_ILM - bool - default y - help - If enabled, Instruction Local Memory (ILM) will be configured to execute - code placed in the .__ram_code section out of RAM. This consumes RAM in - blocks of 4 kilobytes, but performance of code in ILM is much more - predictable than executing from Flash directly, and some code (such as code - that writes to the internal Flash) must execute out of RAM. - -config SOC_IT8XXX2_EXCEPTIONS_IN_RAM - bool "Place exception handling code in RAM" - default y - select SOC_IT8XXX2_USE_ILM - help - Place exception handling (ISR entry/exit and related) code in ILM, which - has more reliable performance characteristics than executing directly from - Flash. This can significantly improve performance when under I-cache - pressure. - -config SOC_IT8XXX2_SHA256_HW_ACCELERATE - bool "HW SHA256 calculation" - help - IT8XXX2 HW support sha256 calculation, and its calculation is faster than FW. - We place SHA256 message, hash and key data (total 512bytes) in RAM. - If we enable this config, because HW limits, the sha256 data must place in - first 4KB of RAM. - -DT_CHOSEN_ZEPHYR_FLASH := zephyr,flash - -config SOC_IT8XXX2_FLASH_SIZE_BYTES - hex - default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_ZEPHYR_FLASH)) - help - Total size of writable flash. - -config ILM_MAX_SIZE - int "ILM Size in kB" - default 60 if SOC_IT81202_CX || SOC_IT81302_CX - default SRAM_SIZE - -endif # SOC_IT8XXX2 diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.c b/soc/riscv/riscv-ite/it8xxx2/soc.c deleted file mode 100644 index 7bf213ad695..00000000000 --- a/soc/riscv/riscv-ite/it8xxx2/soc.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2020 ITE Corporation. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#include -#include -#include -#include -#include "ilm.h" -#include -#include "soc_espi.h" -#include - - -uint32_t chip_get_pll_freq(void) -{ - uint32_t pllfreq; - - switch (IT8XXX2_ECPM_PLLFREQR & 0x0F) { - case 0: - pllfreq = MHZ(8); - break; - case 1: - pllfreq = MHZ(16); - break; - case 2: - pllfreq = MHZ(24); - break; - case 3: - pllfreq = MHZ(32); - break; - case 4: - pllfreq = MHZ(48); - break; - case 5: - pllfreq = MHZ(64); - break; - case 6: - pllfreq = MHZ(72); - break; - case 7: - pllfreq = MHZ(96); - break; - default: - return -ERANGE; - } - - return pllfreq; -} - -void __soc_ram_code chip_pll_ctrl(enum chip_pll_mode mode) -{ - volatile uint8_t _pll_ctrl __unused; - - IT8XXX2_ECPM_PLLCTRL = mode; - /* - * for deep doze / sleep mode - * This load operation will ensure PLL setting is taken into - * control register before wait for interrupt instruction. - */ - _pll_ctrl = IT8XXX2_ECPM_PLLCTRL; -} - -#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M -struct pll_config_t { - uint8_t pll_freq; - uint8_t div_fnd; - uint8_t div_uart; - uint8_t div_smb; - uint8_t div_sspi; - uint8_t div_ec; - uint8_t div_jtag; - uint8_t div_pwm; - uint8_t div_usbpd; -}; - -static const struct pll_config_t pll_configuration[] = { - /* - * PLL frequency setting = 4 (48MHz) - * FND div = 0 (PLL / 1 = 48 mhz) - * UART div = 1 (PLL / 2 = 24 mhz) - * SMB div = 1 (PLL / 2 = 24 mhz) - * SSPI div = 1 (PLL / 2 = 24 mhz) - * EC div = 6 (FND / 6 = 8 mhz) - * JTAG div = 1 (PLL / 2 = 24 mhz) - * PWM div = 0 (PLL / 1 = 48 mhz) - * USBPD div = 5 (PLL / 6 = 8 mhz) - */ - {.pll_freq = 4, - .div_fnd = 0, - .div_uart = 1, - .div_smb = 1, - .div_sspi = 1, - .div_ec = 6, - .div_jtag = 1, - .div_pwm = 0, - .div_usbpd = 5} -}; - -void __soc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll) -{ - /* Enable HW timer to wakeup chip from the sleep mode */ - timer_5ms_one_shot(); - /* - * Configure PLL clock dividers. - * Writing data to these registers doesn't change the - * PLL frequency immediately until the status is changed - * into wakeup from the sleep mode. - * The following code is intended to make the system - * enter sleep mode, and wait HW timer to wakeup chip to - * complete PLL update. - */ - IT8XXX2_ECPM_PLLFREQR = pll->pll_freq; - /* Pre-set FND clock frequency = PLL / 3 */ - IT8XXX2_ECPM_SCDCR0 = (2 << 4); - /* JTAG and EC */ - IT8XXX2_ECPM_SCDCR3 = (pll->div_jtag << 4) | pll->div_ec; - /* Chip sleep after wait for interrupt (wfi) instruction */ - chip_pll_ctrl(CHIP_PLL_SLEEP); - /* Chip sleep and wait timer wake it up */ - __asm__ volatile ("wfi"); - /* New FND clock frequency */ - IT8XXX2_ECPM_SCDCR0 = pll->div_fnd << 4; - /* Chip doze after wfi instruction */ - chip_pll_ctrl(CHIP_PLL_DOZE); - /* UART */ - IT8XXX2_ECPM_SCDCR1 = pll->div_uart; - /* SSPI and SMB */ - IT8XXX2_ECPM_SCDCR2 = (pll->div_sspi << 4) | pll->div_smb; - /* USBPD and PWM */ - IT8XXX2_ECPM_SCDCR4 = (pll->div_usbpd << 4) | pll->div_pwm; -} - -static void chip_configure_pll(const struct pll_config_t *pll) -{ - /* Re-configure PLL clock or not. */ - if (((IT8XXX2_ECPM_PLLFREQR & 0xf) != pll->pll_freq) || - ((IT8XXX2_ECPM_SCDCR0 & 0xf0) != (pll->div_fnd << 4)) || - ((IT8XXX2_ECPM_SCDCR3 & 0xf) != pll->div_ec)) { -#ifdef CONFIG_ESPI - /* - * We have to disable eSPI pad before changing - * PLL sequence or sequence will fail if CS# pin is low. - */ - espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, false); -#endif - /* Run change PLL sequence */ - chip_run_pll_sequence(pll); -#ifdef CONFIG_ESPI - /* Enable eSPI pad after changing PLL sequence */ - espi_it8xxx2_enable_pad_ctrl(ESPI_IT8XXX2_SOC_DEV, true); -#endif - } -} - -static int chip_change_pll(void) -{ - - if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { - ite_intc_save_and_disable_interrupts(); - } - /* configure PLL/CPU/flash clock */ - chip_configure_pll(&pll_configuration[0]); - if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) { - ite_intc_restore_interrupts(); - } - - return 0; -} -SYS_INIT(chip_change_pll, PRE_KERNEL_1, CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY); -BUILD_ASSERT(CONFIG_FLASH_INIT_PRIORITY < CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY, - "CONFIG_FLASH_INIT_PRIORITY must be less than CONFIG_IT8XXX2_PLL_SEQUENCE_PRIORITY"); -#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */ - -#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING -/* Preventing CPU going into idle mode during command queue. */ -static atomic_t cpu_idle_disabled; - -void chip_permit_idle(void) -{ - atomic_dec(&cpu_idle_disabled); -} - -void chip_block_idle(void) -{ - atomic_inc(&cpu_idle_disabled); -} - -bool cpu_idle_not_allowed(void) -{ - return !!(atomic_get(&cpu_idle_disabled)); -} -#endif - -/* The routine must be called with interrupts locked */ -void riscv_idle(enum chip_pll_mode mode, unsigned int key) -{ - /* - * The routine is called with interrupts locked (in kernel/idle()). - * But on kernel/context test_kernel_cpu_idle test, the routine will be - * called without interrupts locked. Hence we disable M-mode external - * interrupt here to protect the below content. - */ - csr_clear(mie, MIP_MEIP); - sys_trace_idle(); -#ifdef CONFIG_ESPI - /* - * H2RAM feature requires RAM clock to be active. Since the below doze - * mode will disable CPU and RAM clocks, enable eSPI transaction - * interrupt to restore clocks. With this interrupt, EC will not defer - * eSPI bus while transaction is accepted. - */ - espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, true); -#endif - /* Chip doze after wfi instruction */ - chip_pll_ctrl(mode); - - do { - /* Wait for interrupt */ - __asm__ volatile ("wfi"); - /* - * Sometimes wfi instruction may fail due to CPU's MTIP@mip - * register is non-zero. - * If the ite_intc_no_irq() is true at this point, - * it means that EC waked-up by the above issue not an - * interrupt. Hence we loop running wfi instruction here until - * wfi success. - */ - } while (ite_intc_no_irq()); - -#ifdef CONFIG_ESPI - /* CPU has been woken up, the interrupt is no longer needed */ - espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, false); -#endif - /* - * Enable M-mode external interrupt - * An interrupt can not be fired yet until we enable global interrupt - */ - csr_set(mie, MIP_MEIP); - /* Restore global interrupt lockout state */ - irq_unlock(key); -} - -void arch_cpu_idle(void) -{ -#ifdef CONFIG_SOC_IT8XXX2_CPU_IDLE_GATING - /* - * The EC processor(CPU) cannot be in the k_cpu_idle() during - * the transactions with the CQ mode(DMA mode). Otherwise, - * the EC processor would be clock gated. - */ - if (cpu_idle_not_allowed()) { - /* Restore global interrupt lockout state */ - irq_unlock(MSTATUS_IEN); - } else -#endif - { - riscv_idle(CHIP_PLL_DOZE, MSTATUS_IEN); - } -} - -void arch_cpu_atomic_idle(unsigned int key) -{ - riscv_idle(CHIP_PLL_DOZE, key); -} - -static int ite_it8xxx2_init(void) -{ - struct gpio_it8xxx2_regs *const gpio_regs = GPIO_IT8XXX2_REG_BASE; - struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE; - - /* - * bit7: wake up CPU if it is in low power mode and - * an interrupt is pending. - */ - gctrl_regs->GCTRL_WMCR |= BIT(7); - - /* - * Disable this feature that can detect pre-define hardware - * target A through I2C0. This is for debugging use, so it - * can be disabled to avoid illegal access. - */ -#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1 - IT8XXX2_SMB_SFFCTL &= ~IT8XXX2_SMB_HSAPE; -#elif CONFIG_SOC_IT8XXX2_REG_SET_V2 - IT8XXX2_SMB_SCLKTS_BRGS &= ~IT8XXX2_SMB_PREDEN; -#endif - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) - /* UART1 board init */ - /* bit2: clocks to UART1 modules are not gated. */ - IT8XXX2_ECPM_CGCTRL3R &= ~BIT(2); - IT8XXX2_ECPM_AUTOCG &= ~BIT(6); - - /* bit3: UART1 belongs to the EC side. */ - gctrl_regs->GCTRL_RSTDMMC |= IT8XXX2_GCTRL_UART1SD; - /* reset UART before config it */ - gctrl_regs->GCTRL_RSTC4 = IT8XXX2_GCTRL_RUART1; - - /* switch UART1 on without hardware flow control */ - gpio_regs->GPIO_GCR1 |= IT8XXX2_GPIO_U1CTRL_SIN0_SOUT0_EN; - -#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart1), okay) */ - -#if DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) - /* UART2 board init */ - /* setting voltage 3.3v */ - gpio_regs->GPIO_GCR21 &= ~(IT8XXX2_GPIO_GPH1VS | IT8XXX2_GPIO_GPH2VS); - /* bit2: clocks to UART2 modules are not gated. */ - IT8XXX2_ECPM_CGCTRL3R &= ~BIT(2); - IT8XXX2_ECPM_AUTOCG &= ~BIT(5); - - /* bit3: UART2 belongs to the EC side. */ - gctrl_regs->GCTRL_RSTDMMC |= IT8XXX2_GCTRL_UART2SD; - /* reset UART before config it */ - gctrl_regs->GCTRL_RSTC4 = IT8XXX2_GCTRL_RUART2; - - /* switch UART2 on without hardware flow control */ - gpio_regs->GPIO_GCR1 |= IT8XXX2_GPIO_U2CTRL_SIN1_SOUT1_EN; - -#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(uart2), okay) */ - -#if (SOC_USBPD_ITE_PHY_PORT_COUNT > 0) - int port; - - /* - * To prevent cc pins leakage, we disable board not active ITE - * TCPC port cc modules, then cc pins can be used as gpio if needed. - */ - for (port = SOC_USBPD_ITE_ACTIVE_PORT_COUNT; - port < SOC_USBPD_ITE_PHY_PORT_COUNT; port++) { - struct usbpd_it8xxx2_regs *base; - - if (port == 0) { - base = (struct usbpd_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(usbpd0)); - } else if (port == 1) { - base = (struct usbpd_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(usbpd1)); - } else { - /* Currently all ITE embedded pd chip support max two ports */ - break; - } - - /* Power down all CC, and disable CC voltage detector */ - base->CCGCR |= (IT8XXX2_USBPD_DISABLE_CC | - IT8XXX2_USBPD_DISABLE_CC_VOL_DETECTOR); - /* - * Disconnect CC analog module (ex.UP/RD/DET/TX/RX), and - * disconnect CC 5.1K to GND - */ - base->CCCSR |= (IT8XXX2_USBPD_CC2_DISCONNECT | - IT8XXX2_USBPD_CC2_DISCONNECT_5_1K_TO_GND | - IT8XXX2_USBPD_CC1_DISCONNECT | - IT8XXX2_USBPD_CC1_DISCONNECT_5_1K_TO_GND); - /* Disconnect CC 5V tolerant */ - base->CCPSR |= (IT8XXX2_USBPD_DISCONNECT_POWER_CC2 | - IT8XXX2_USBPD_DISCONNECT_POWER_CC1); - /* Dis-connect 5.1K dead battery resistor to CC */ - base->CCPSR |= (IT8XXX2_USBPD_DISCONNECT_5_1K_CC2_DB | - IT8XXX2_USBPD_DISCONNECT_5_1K_CC1_DB); - } -#endif /* (SOC_USBPD_ITE_PHY_PORT_COUNT > 0) */ - - return 0; -} -SYS_INIT(ite_it8xxx2_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/riscv-ite/it8xxx2/soc.h b/soc/riscv/riscv-ite/it8xxx2/soc.h deleted file mode 100644 index bc790768369..00000000000 --- a/soc/riscv/riscv-ite/it8xxx2/soc.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __RISCV_ITE_SOC_H_ -#define __RISCV_ITE_SOC_H_ -/* - * Copyright (c) 2020 ITE Corporation. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - */ -#include - -/* - * This define gets the total number of USBPD ports available on the - * ITE EC chip from dtsi (include status disable). Both it81202 and - * it81302 support two USBPD ports. - */ -#define SOC_USBPD_ITE_PHY_PORT_COUNT \ -COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1)) - -/* - * This define gets the number of active USB Power Delivery (USB PD) - * ports in use on the ITE microcontroller from dts (only status okay). - * The active port usage should follow the order of ITE TCPC port index, - * ex. if we're active only one ITE USB PD port, then the port should be - * 0x3700 (port0 register base), instead of 0x3800 (port1 register base). - */ -#define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd) - -#ifndef _ASMLANGUAGE -void soc_interrupt_init(void); -#endif - -#endif /* __RISCV_ITE_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/CMakeLists.txt b/soc/riscv/riscv-privileged/CMakeLists.txt deleted file mode 100644 index c5f97039eb7..00000000000 --- a/soc/riscv/riscv-privileged/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -add_subdirectory(common) -add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/riscv-privileged/Kconfig b/soc/riscv/riscv-privileged/Kconfig deleted file mode 100644 index abbeeac242b..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -# Configuration options for riscv SOCs supporting the riscv privileged -# architecture specification - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -config SOC_FAMILY_RISCV_PRIVILEGE - bool - select DEPRECATED - -config SOC_FAMILY_RISCV_PRIVILEGED - bool - select ARCH_HAS_RAMFUNC_SUPPORT if XIP - -config SOC_FAMILY - string - default "riscv-privileged" - depends on SOC_FAMILY_RISCV_PRIVILEGED - -config RISCV_HAS_PLIC - bool "Does the SOC provide support for a Platform Level Interrupt Controller (PLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Does the SOC provide support for a Platform Level Interrupt Controller (PLIC). - -config RISCV_HAS_CLIC - bool "Does the SOC provide support for a Core-Local Interrupt Controller (CLIC)" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Does the SOC provide support for a Core-Local Interrupt Controller (CLIC). - -config RISCV_VECTORED_MODE - bool "Should the SOC use vectored mode" - depends on SOC_FAMILY_RISCV_PRIVILEGED - help - Should the SOC use vectored mode. - -source "soc/riscv/riscv-privileged/*/Kconfig.soc" diff --git a/soc/riscv/riscv-privileged/Kconfig.defconfig b/soc/riscv/riscv-privileged/Kconfig.defconfig deleted file mode 100644 index 6793d72a385..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig.defconfig +++ /dev/null @@ -1,6 +0,0 @@ -# riscv SOC family supporting the riscv privileged architecture spec - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-privileged/*/Kconfig.defconfig.series" diff --git a/soc/riscv/riscv-privileged/Kconfig.soc b/soc/riscv/riscv-privileged/Kconfig.soc deleted file mode 100644 index 14d141223e0..00000000000 --- a/soc/riscv/riscv-privileged/Kconfig.soc +++ /dev/null @@ -1,6 +0,0 @@ -# riscv SOC series supporting the riscv privileged architecture spec - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -source "soc/riscv/riscv-privileged/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt b/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt deleted file mode 100644 index 21268312347..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(${CONFIG_SOC}) - -zephyr_sources( - start.S - soc_irq.S -) - -zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_PMA pma.c) -zephyr_sources_ifdef(CONFIG_SOC_ANDES_V5_L2C l2_cache.c) -zephyr_linker_sources(ROM_START SORT_KEY 0x0 common_linker/init.ld) -zephyr_linker_sources_ifdef(CONFIG_SOC_ANDES_V5_EXECIT RODATA SORT_KEY 0x0 common_linker/execit.ld) -zephyr_linker_sources_ifdef(CONFIG_XIP RAM_SECTIONS SORT_KEY 0x0 common_linker/ram_start_nonzero.ld) - -# Note: AndeStar V5 DSP needs custom Andes V5 toolchain -if(CONFIG_SOC_ANDES_V5_HWDSP) - zephyr_cc_option(-mext-dsp) -endif() - -# Note: AndeStar V5 EXEC.IT needs custom Andes V5 toolchain -if(CONFIG_SOC_ANDES_V5_EXECIT) - zephyr_cc_option(-mexecit) - zephyr_ld_options(-Wl,--mexecit) -endif() - -if(CONFIG_SOC_RISCV_ANDES_AE350) - set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/ae350/linker.ld CACHE INTERNAL "") -endif() diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series deleted file mode 100644 index c6436807825..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.series +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2021 Andes Technology Corporation -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV_ANDES_V5 - -# Kconfig picks the first default with a satisfied condition. -# SoC defaults should be parsed before SoC Series defaults, because SoCs usually -# overrides SoC Series values. -source "soc/riscv/riscv-privileged/andes_v5/Kconfig.defconfig.ae*" - -config SOC_SERIES - default "andes_v5" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 60000000 - -config KERNEL_ENTRY - default "entry" - -config RISCV_GENERIC_TOOLCHAIN - default y if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "zephyr" - default n - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 12 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config MAX_IRQ_PER_AGGREGATOR - default 52 - -config NUM_IRQS - default 64 - -endif # SOC_SERIES_RISCV_ANDES_V5 diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series b/soc/riscv/riscv-privileged/andes_v5/Kconfig.series deleted file mode 100644 index 9a99711b04c..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2021 Andes Technology Corporation -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_ANDES_V5 - bool "Andes V5 SoC Series Implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Andes V5 SoC Series diff --git a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc b/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc deleted file mode 100644 index 19f215e2c5a..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/Kconfig.soc +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2021 Andes Technology Corporation -# SPDX-License-Identifier: Apache-2.0 - -choice -prompt "Andes V5 SoC Selection" -depends on SOC_SERIES_RISCV_ANDES_V5 - -config SOC_RISCV_ANDES_AE350 - bool "Andes AE350 SoC implementation" - select ATOMIC_OPERATIONS_BUILTIN - select INCLUDE_RESET_VECTOR - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select CPU_HAS_DCACHE - select CPU_HAS_ICACHE - select RISCV_PMP - -endchoice - -if SOC_SERIES_RISCV_ANDES_V5 - -choice -prompt "Base CPU ISA options" -default RV32I_CPU - -config RV32I_CPU - bool "RISCV32 CPU ISA" - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config RV32E_CPU - bool "RISCV32E CPU ISA" - select RISCV_ISA_RV32E - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config RV64I_CPU - bool "RISCV64 CPU ISA" - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - select 64BIT - -endchoice - -choice -prompt "FPU options" -default NO_FPU - -config NO_FPU - bool "No FPU" - -config SINGLE_PRECISION_FPU - bool "Single precision FPU" - select CPU_HAS_FPU - -config DOUBLE_PRECISION_FPU - bool "Double precision FPU" - select CPU_HAS_FPU_DOUBLE_PRECISION - -endchoice - -config SOC_ANDES_V5_HWDSP - bool "AndeStar V5 DSP ISA" - select RISCV_SOC_CONTEXT_SAVE - depends on !RISCV_GENERIC_TOOLCHAIN - help - This option enables the AndeStar v5 hardware DSP, in order to - support using the DSP instructions. - -config SOC_ANDES_V5_PFT - bool "Andes V5 PowerBrake extension" - default y - select RISCV_SOC_CONTEXT_SAVE - help - The PowerBrake extension throttles performance by reducing instruction - executing rate. - -config SOC_ANDES_V5_EXECIT - bool "Andes V5 EXEC.IT extension" - depends on RISCV_ISA_EXT_C - depends on !RISCV_GENERIC_TOOLCHAIN - depends on !LINKER_USE_NO_RELAX - help - The EXEC.IT extension (Execution on Instruction Table) generate - a look-up table and replaces suitable 32-bit instructions with - the 16-bit "exec.it ". - -config SOC_ANDES_V5_PMA - bool "Andes V5 Physical Memory Attribute (PMA)" - select ARCH_HAS_NOCACHE_MEMORY_SUPPORT - help - This option enables the Andes V5 PMA, in order to support SW to - configure physical memory attribute by PMA CSRs. The address - matching of Andes V5 PMA is like RISC-V PMP NAPOT mode - (power-of-two alignment). - -config SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE - int - depends on SOC_ANDES_V5_PMA - default 4096 - help - Minimum size (and alignment) of an PMA region. Use this symbol - to guarantee minimum size and alignment of PMA regions. - -# Workaround for not being able to have commas in macro arguments -DT_ANDESTECH_L2C := andestech,l2c - -config SOC_ANDES_V5_L2C - bool - default $(dt_compat_enabled,$(DT_ANDESTECH_L2C)) - -config SOC_ANDES_V5_IOCP - bool "Andes V5 I/O Coherence Port (IOCP)" - depends on SOC_ANDES_V5_L2C - depends on DCACHE - help - Support Andes V5 I/O Coherence Port to handle cache coherency - between cache and external non-caching master, such as DMA - controller. - -endif # SOC_SERIES_RISCV_ANDES_V5 diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld b/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld deleted file mode 100644 index a47aceb6038..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/linker.ld +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2016-2017 Jean-Paul Etienne - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the ae350 platform - */ - -#include -#include - -#include -#include - -#include -#include - -#ifdef CONFIG_XIP -#define ROMABLE_REGION ROM -#else -#define ROMABLE_REGION RAM -#endif -#define RAMABLE_REGION RAM - -#define _EXCEPTION_SECTION_NAME exceptions -#define _RESET_SECTION_NAME reset - -#ifdef CONFIG_XIP -#if DT_NODE_HAS_COMPAT_STATUS(DT_CHOSEN(zephyr_flash), soc_nv_flash, okay) -#ifdef CONFIG_FLASH_LOAD_OFFSET -#define ROM_BASE (DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) + \ - CONFIG_FLASH_LOAD_OFFSET) -#else /* !CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_BASE DT_REG_ADDR(DT_CHOSEN(zephyr_flash)) -#endif /* CONFIG_FLASH_LOAD_OFFSET */ -#define ROM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_flash)) -#elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_flash), jedec_spi_nor) -/* For jedec,spi-nor we expect the spi controller to memory map the flash - * and for that mapping to be the second register property of the spi - * controller. - */ -#define SPI_CTRL DT_PARENT(DT_CHOSEN(zephyr_flash)) -#define ROM_BASE DT_REG_ADDR_BY_IDX(SPI_CTRL, 1) -#define ROM_SIZE DT_REG_SIZE_BY_IDX(SPI_CTRL, 1) -#endif -#else /* CONFIG_XIP */ -#define ROM_BASE CONFIG_SRAM_BASE_ADDRESS -#define ROM_SIZE KB(CONFIG_SRAM_SIZE) -#endif /* CONFIG_XIP */ - -#define RAM_BASE CONFIG_SRAM_BASE_ADDRESS -#define RAM_SIZE KB(CONFIG_SRAM_SIZE) - -#ifdef CONFIG_RISCV_PMP - #define MPU_MIN_SIZE CONFIG_PMP_GRANULARITY - #define MPU_MIN_SIZE_ALIGN . = ALIGN(MPU_MIN_SIZE); - #if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) - #define MPU_ALIGN(region_size) \ - . = ALIGN(MPU_MIN_SIZE); \ - . = ALIGN( 1 << LOG2CEIL(region_size)) - #else - #define MPU_ALIGN(region_size) \ - . = ALIGN(MPU_MIN_SIZE) - #endif -#else - #define MPU_MIN_SIZE_ALIGN - #define MPU_ALIGN(region_size) . = ALIGN(4) -#endif - -MEMORY -{ -#ifdef CONFIG_XIP - ROM (rx) : ORIGIN = ROM_BASE, LENGTH = ROM_SIZE -#endif - RAM (rwx) : ORIGIN = RAM_BASE, LENGTH = RAM_SIZE - - LINKER_DT_REGIONS() - - /* Used by and documented in include/linker/intlist.ld */ - IDT_LIST (wx) : ORIGIN = 0xFFFFF7FF, LENGTH = 2K -} - -ENTRY(CONFIG_KERNEL_ENTRY) - -SECTIONS - { - -#include - - /* - * The .plt and .iplt are here according to - * 'riscv32-zephyr-elf-ld --verbose', before text section. - */ - SECTION_PROLOGUE(.plt,,) - { - *(.plt) - } - - SECTION_PROLOGUE(.iplt,,) - { - *(.iplt) - } - - GROUP_START(ROMABLE_REGION) - - SECTION_PROLOGUE(rom_start,,) - { - . = ALIGN(16); - MPU_ALIGN(__rom_region_size); - __rom_region_start = .; -/* Located in generated directory. This file is populated by calling - * zephyr_linker_sources(ROM_START ...). - */ -#include - } GROUP_LINK_IN(ROMABLE_REGION) - -#ifdef CONFIG_CODE_DATA_RELOCATION -#include -#endif - - SECTION_PROLOGUE(_RESET_SECTION_NAME,,) - { - KEEP(*(.reset.*)) - } GROUP_LINK_IN(ROMABLE_REGION) - - SECTION_PROLOGUE(_EXCEPTION_SECTION_NAME,,) - { - KEEP(*(".exception.entry.*")) - *(".exception.other.*") - } GROUP_LINK_IN(ROMABLE_REGION) - - SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) - { - . = ALIGN(4); - KEEP(*(.openocd_debug)) - KEEP(*(".openocd_debug.*")) - - __text_region_start = .; - - *(.text) - *(".text.*") - *(.gnu.linkonce.t.*) -#include - } GROUP_LINK_IN(ROMABLE_REGION) - - __text_region_end = .; - - __rodata_region_start = .; -#include -#include - - SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) - { - . = ALIGN(4); - *(.srodata) - *(".srodata.*") - *(.rodata) - *(".rodata.*") - *(.gnu.linkonce.r.*) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include -#include - . = ALIGN(4); - } GROUP_LINK_IN(ROMABLE_REGION) - -#include - __rodata_region_end = .; - - /* For non-XIP system, __rom_region_end symbol should be set to - * the end of common ROMABLE_REGIONs (text and rodata) instead of - * the linker script end, so it wouldn't mistakenly contain - * RAMABLE_REGION in it. - */ -#ifndef CONFIG_XIP -#ifdef CONFIG_RISCV_PMP - SECTION_PROLOGUE(rom_mpu_padding,,) - { - MPU_ALIGN(__rodata_region_end - __rom_region_start); - } GROUP_LINK_IN(ROMABLE_REGION) -#endif /* CONFIG_RISCV_PMP */ - - __rom_region_end = .; - __rom_region_size = __rom_region_end - __rom_region_start; -#endif /* CONFIG_XIP */ - GROUP_END(ROMABLE_REGION) - - GROUP_START(RAMABLE_REGION) - - . = RAM_BASE; - _image_ram_start = .; - -#ifdef CONFIG_SOC_ANDES_V5_PMA -#pragma push_macro("MPU_ALIGN") -#undef MPU_ALIGN -/* Make linker section alignment comply with PMA granularity. */ -#define MPU_ALIGN(region_size) \ - . = ALIGN(CONFIG_SOC_ANDES_V5_PMA_REGION_MIN_ALIGN_AND_SIZE); \ - . = ALIGN( 1 << LOG2CEIL(region_size)) -#endif - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - -#ifdef CONFIG_SOC_ANDES_V5_PMA -#pragma pop_macro("MPU_ALIGN") -#endif - -#if defined(CONFIG_USERSPACE) -#define APP_SHARED_ALIGN MPU_MIN_SIZE_ALIGN -#define SMEM_PARTITION_ALIGN MPU_ALIGN - -#include - - _app_smem_size = _app_smem_end - _app_smem_start; - _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); -#endif /* CONFIG_USERSPACE */ - - SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) - { - MPU_MIN_SIZE_ALIGN - /* - * For performance, BSS section is assumed to be 4 byte aligned and - * a multiple of 4 bytes - */ - . = ALIGN(4); - __bss_start = .; - __kernel_ram_start = .; - *(.sbss) - *(".sbss.*") - *(.bss) - *(".bss.*") - COMMON_SYMBOLS - -#ifdef CONFIG_CODE_DATA_RELOCATION -#include -#endif - - /* - * As memory is cleared in words only, it is simpler to ensure the BSS - * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. - */ - __bss_end = ALIGN(4); - } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) - -#include - - SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) - { - . = ALIGN(4); - /* _image_ram_start = .; */ - __data_region_start = .; - __data_start = .; - - *(.data) - *(".data.*") - -#ifdef CONFIG_RISCV_GP - /* - * RISC-V architecture has 12-bit signed immediate offsets in the - * instructions. If we can put the most commonly accessed globals - * in a special 4K span of memory addressed by the GP register, then - * we can access those values in a single instruction, saving both - * codespace and runtime. - * - * Since these immediate offsets are signed, place gp 0x800 past the - * beginning of .sdata so that we can use both positive and negative - * offsets. - */ - . = ALIGN(8); - PROVIDE (__global_pointer$ = . + 0x800); -#endif - - *(.sdata .sdata.* .gnu.linkonce.s.*) - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - -#ifdef CONFIG_CODE_DATA_RELOCATION -#include -#endif - - __data_end = .; - - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) - __data_size = __data_end - __data_start; - __data_load_start = LOADADDR(_DATA_SECTION_NAME); - - __data_region_load_start = LOADADDR(_DATA_SECTION_NAME); - -#include -#include -#include - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - - __data_region_end = .; - - __kernel_ram_end = .; - __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; - -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_itcm), okay) -GROUP_START(ITCM) - - SECTION_PROLOGUE(_ITCM_SECTION_NAME,,SUBALIGN(8)) - { - __itcm_start = .; - *(.itcm) - *(".itcm.*") - __itcm_end = .; - } GROUP_LINK_IN(ITCM AT> ROMABLE_REGION) - - __itcm_size = __itcm_end - __itcm_start; - __itcm_load_start = LOADADDR(_ITCM_SECTION_NAME); - -GROUP_END(ITCM) -#endif - -#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_dtcm), okay) -GROUP_START(DTCM) - - SECTION_PROLOGUE(_DTCM_BSS_SECTION_NAME, (NOLOAD),SUBALIGN(8)) - { - __dtcm_start = .; - __dtcm_bss_start = .; - *(.dtcm_bss) - *(".dtcm_bss.*") - __dtcm_bss_end = .; - } GROUP_LINK_IN(DTCM) - - SECTION_PROLOGUE(_DTCM_NOINIT_SECTION_NAME, (NOLOAD),SUBALIGN(8)) - { - __dtcm_noinit_start = .; - *(.dtcm_noinit) - *(".dtcm_noinit.*") - __dtcm_noinit_end = .; - } GROUP_LINK_IN(DTCM) - - SECTION_PROLOGUE(_DTCM_DATA_SECTION_NAME,,SUBALIGN(8)) - { - __dtcm_data_start = .; - *(.dtcm_data) - *(".dtcm_data.*") - __dtcm_data_end = .; - } GROUP_LINK_IN(DTCM AT> ROMABLE_REGION) - - __dtcm_end = .; - - __dtcm_data_load_start = LOADADDR(_DTCM_DATA_SECTION_NAME); - -GROUP_END(DTCM) -#endif - -/* Located in generated directory. This file is populated by the - * zephyr_linker_sources() Cmake function. - */ -#include - -#define LAST_RAM_ALIGN MPU_MIN_SIZE_ALIGN - -#include - - GROUP_END(RAMABLE_REGION) - -#include - - /DISCARD/ : { *(.note.GNU-stack) } - - SECTION_PROLOGUE(.riscv.attributes, 0,) - { - KEEP(*(.riscv.attributes)) - KEEP(*(.gnu.attributes)) - } - - /* Sections generated from 'zephyr,memory-region' nodes */ - LINKER_DT_SECTIONS() - -/* Because ROMABLE_REGION != RAMABLE_REGION in XIP-system, it is valid - * to set __rom_region_end symbol at the end of linker script and - * doesn't mistakenly contain the RAMABLE_REGION in it. - */ -#ifdef CONFIG_XIP -/* Must be last in romable region */ -SECTION_PROLOGUE(.last_section,,) -{ -#ifdef CONFIG_LINKER_LAST_SECTION_ID - /* Fill last section with a word to ensure location counter and actual rom - * region data usage match. */ - LONG(CONFIG_LINKER_LAST_SECTION_ID_PATTERN) -#endif -} GROUP_LINK_IN(ROMABLE_REGION) - -#ifndef CONFIG_RISCV_PMP -/* To provide the image size as a const expression, - * calculate this value here. */ -__rom_region_end = LOADADDR(.last_section) + SIZEOF(.last_section); -#else -SECTION_PROLOGUE(rom_mpu_padding,(NOLOAD),) -{ - MPU_ALIGN(__rom_region_size); - __rom_region_end = .; -} GROUP_LINK_IN(ROMABLE_REGION) -#endif /* !CONFIG_RISCV_PMP */ -__rom_region_size = __rom_region_end - __rom_region_start; -#endif - -} diff --git a/soc/riscv/riscv-privileged/andes_v5/ae350/soc.h b/soc/riscv/riscv-privileged/andes_v5/ae350/soc.h deleted file mode 100644 index 95ea7486fd3..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/ae350/soc.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @brief Macros for the Andes AE350 platform - */ - -#ifndef __RISCV_ANDES_AE350_SOC_H_ -#define __RISCV_ANDES_AE350_SOC_H_ - -#include - -/* Include CSRs available for Andes V5 SoCs */ -#include "soc_v5.h" - -#endif /* __RISCV_ANDES_AE350_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/andes_v5/soc_irq.S b/soc/riscv/riscv-privileged/andes_v5/soc_irq.S deleted file mode 100644 index 459285c1281..00000000000 --- a/soc/riscv/riscv-privileged/andes_v5/soc_irq.S +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021 Andes Technology Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE - -/* Exports */ -GTEXT(__soc_save_context) -GTEXT(__soc_restore_context) - -SECTION_FUNC(exception.other, __soc_save_context) - -#ifdef CONFIG_SOC_ANDES_V5_PFT - csrr t0, NDS_MXSTATUS -#endif -#ifdef CONFIG_SOC_ANDES_V5_HWDSP - csrr t1, NDS_UCODE -#endif - -#ifdef CONFIG_SOC_ANDES_V5_PFT - sw t0, __soc_esf_t_mxstatus_OFFSET(a0) -#endif -#ifdef CONFIG_SOC_ANDES_V5_HWDSP - sw t1, __soc_esf_t_ucode_OFFSET(a0) -#endif - ret - -SECTION_FUNC(exception.other, __soc_restore_context) - -#ifdef CONFIG_SOC_ANDES_V5_PFT - lw t0, __soc_esf_t_mxstatus_OFFSET(a0) -#endif -#ifdef CONFIG_SOC_ANDES_V5_HWDSP - lw t1, __soc_esf_t_ucode_OFFSET(a0) -#endif - -#ifdef CONFIG_SOC_ANDES_V5_PFT - csrw NDS_MXSTATUS, t0 -#endif -#ifdef CONFIG_SOC_ANDES_V5_HWDSP - csrw NDS_UCODE, t1 -#endif - ret - -#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ diff --git a/soc/riscv/riscv-privileged/common/CMakeLists.txt b/soc/riscv/riscv-privileged/common/CMakeLists.txt deleted file mode 100644 index 50ee91a2c33..00000000000 --- a/soc/riscv/riscv-privileged/common/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_include_directories(.) - -zephyr_sources( - idle.c - soc_irq.S - soc_common_irq.c - vector.S - ) diff --git a/soc/riscv/riscv-privileged/common/idle.c b/soc/riscv/riscv-privileged/common/idle.c deleted file mode 100644 index e61ce72b280..00000000000 --- a/soc/riscv/riscv-privileged/common/idle.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * Contributors: 2018 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include - -static ALWAYS_INLINE void riscv_idle(unsigned int key) -{ - sys_trace_idle(); - /* unlock interrupts */ - irq_unlock(key); - - /* Wait for interrupt */ - __asm__ volatile("wfi"); -} - -/** - * @brief Power save idle routine - * - * This function will be called by the kernel idle loop or possibly within - * an implementation of _pm_save_idle in the kernel when the - * '_pm_save_flag' variable is non-zero. - */ -void arch_cpu_idle(void) -{ - riscv_idle(MSTATUS_IEN); -} - -/** - * @brief Atomically re-enable interrupts and enter low power mode - * - * INTERNAL - * The requirements for arch_cpu_atomic_idle() are as follows: - * 1) The enablement of interrupts and entering a low-power mode needs to be - * atomic, i.e. there should be no period of time where interrupts are - * enabled before the processor enters a low-power mode. See the comments - * in k_lifo_get(), for example, of the race condition that - * occurs if this requirement is not met. - * - * 2) After waking up from the low-power mode, the interrupt lockout state - * must be restored as indicated in the 'imask' input parameter. - */ -void arch_cpu_atomic_idle(unsigned int key) -{ - riscv_idle(key); -} diff --git a/soc/riscv/riscv-privileged/common/soc_common.h b/soc/riscv/riscv-privileged/common/soc_common.h deleted file mode 100644 index 79f458924c6..00000000000 --- a/soc/riscv/riscv-privileged/common/soc_common.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file configuration macros for riscv SOCs supporting the riscv - * privileged architecture specification - */ - -#ifndef __SOC_COMMON_H_ -#define __SOC_COMMON_H_ - -/* IRQ numbers */ -#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ -#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ - -/* ECALL Exception numbers */ -#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ -#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ - -/* SOC-specific MCAUSE bitfields */ -#ifdef CONFIG_64BIT -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 63) -#else -/* Interrupt Mask */ -#define SOC_MCAUSE_IRQ_MASK (1 << 31) -#endif - -/* Exception code Mask */ -#define SOC_MCAUSE_EXP_MASK CONFIG_RISCV_SOC_MCAUSE_EXCEPTION_MASK - -#ifndef _ASMLANGUAGE - -#include -#include - -#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) -void soc_interrupt_init(void); -#endif - -#endif /* !_ASMLANGUAGE */ - -#endif /* __SOC_COMMON_H_ */ diff --git a/soc/riscv/riscv-privileged/common/soc_irq.S b/soc/riscv/riscv-privileged/common/soc_irq.S deleted file mode 100644 index 73fc24431d5..00000000000 --- a/soc/riscv/riscv-privileged/common/soc_irq.S +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* - * common interrupt management code for riscv SOCs supporting the riscv - * privileged architecture specification - */ -#include -#include -#include -#include -#include - -/* - * __soc_handle_irq is defined as .weak to allow re-implementation by - * SOCs that do not truly follow the riscv privilege specification. - */ -WTEXT(__soc_handle_irq) - -/* - * SOC-specific function to handle pending IRQ number generating the interrupt. - * Exception number is given as parameter via register a0. - */ -SECTION_FUNC(exception.other, __soc_handle_irq) - /* Clear exception number from CSR mip register */ - li t1, 1 - sll t0, t1, a0 - csrrc t1, mip, t0 - - /* Return */ - ret - -/* - * __soc_is_irq is defined as .weak to allow re-implementation by - * SOCs that do not truly follow the riscv privilege specification. - */ -WTEXT(__soc_is_irq) - -/* - * SOC-specific function to determine if the exception is the result of a - * an interrupt or an exception - * return 1 (interrupt) or 0 (exception) - * - */ -SECTION_FUNC(exception.other, __soc_is_irq) - /* Read mcause and check if interrupt bit is set */ - csrr t0, mcause - li t1, SOC_MCAUSE_IRQ_MASK - and t0, t0, t1 - - /* If interrupt bit is not set, return with 0 */ - addi a0, x0, 0 - beqz t0, not_interrupt - addi a0, a0, 1 - -not_interrupt: - /* return */ - ret diff --git a/soc/riscv/riscv-privileged/common/vector.S b/soc/riscv/riscv-privileged/common/vector.S deleted file mode 100644 index 5883bdcca85..00000000000 --- a/soc/riscv/riscv-privileged/common/vector.S +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * Contributors: 2018 Antmicro - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -/* exports */ -GTEXT(__start) - -/* imports */ -GTEXT(__initialize) -GTEXT(_isr_wrapper) - -SECTION_FUNC(vectors, __start) -#if defined(CONFIG_RISCV_GP) - /* Initialize global pointer */ - .option push - .option norelax - la gp, __global_pointer$ - .option pop -#endif - - .option norvc; - -#if defined(CONFIG_RISCV_VECTORED_MODE) -#if defined(CONFIG_RISCV_HAS_CLIC) - - /* - * CLIC vectored mode - * - * CLIC vectored mode uses mtvec exclusively for exception handling and - * mtvec.base must be aligned to 64 bytes (this is done using - * CONFIG_ARCH_SW_ISR_TABLE_ALIGN) - */ - la t0, _isr_wrapper - addi t0, t0, 0x03 /* Enable CLIC vectored mode by setting LSB */ - csrw mtvec, t0 - - /* - * CLIC vectored mode has a similar concept to CLINT vectored mode, - * where an interrupt vector table is used for specific interrupts. - * However, in CLIC vectored mode, the handler table contains the - * address of the interrupt handler instead of an opcode containing a - * jump instruction, this is done by leveraging - * CONFIG_IRQ_VECTOR_TABLE_JUMP_BY_ADDRESS. - * When an interrupt occurs in CLIC vectored mode, the address of the - * handler entry from the vector table is loaded and then jumped to in - * hardware. This time mtvt is used as the base address for the - * interrupt table. - */ - la t0, _irq_vector_table - csrw 0x307, t0 /* mtvt */ - -#else /* !CONFIG_RISCV_HAS_CLIC */ - - /* - * CLINT vectored mode - * - * Set mtvec (Machine Trap-Vector Base-Address Register) - * to _irq_vector_table (interrupt vector table). Add 1 to base - * address of _irq_vector_table to indicate that vectored mode - * is used (LSB = 0x1). CPU will mask the LSB out of - * the address so that base address of _irq_vector_table is used. - * - * NOTE: _irq_vector_table is 256-byte aligned. Incorrect alignment - * of _irq_vector_table breaks this code. - */ - la t0, _irq_vector_table /* Load address of interrupt vector table */ - addi t0, t0, 0x01 /* Enable vectored mode by setting LSB */ - csrw mtvec, t0 - -#endif /* CONFIG_RISCV_HAS_CLIC */ - -#else /* !CONFIG_RISCV_VECTORED_MODE */ - - /* - * CLINT direct mode - * - * Set mtvec (Machine Trap-Vector Base-Address Register) - * to _isr_wrapper. - */ - la t0, _isr_wrapper - csrw mtvec, t0 - -#endif /* CONFIG_RISCV_VECTORED_MODE */ - - /* Jump to __reset */ - tail __reset diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series deleted file mode 100644 index 233428931a3..00000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.defconfig.series +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2023 Efinix Inc. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_EFINIX_SAPPHIRE - -config SOC_SERIES - default "efinix-sapphire" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 100000000 - -config RISCV_HAS_CPU_IDLE - bool - -config RISCV_SOC_INTERRUPT_INIT - bool - default y - -config RISCV_HAS_PLIC - bool - default y - -config NUM_IRQS - int - default 36 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -endif # SOC_SERIES_EFINIX_SAPPHIRE diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series deleted file mode 100644 index 8505cf1318a..00000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2023 Efinix Inc. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_EFINIX_SAPPHIRE - bool "Efinix Sapphire SOC implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Efinix Sapphire SOC implementation diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc b/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc deleted file mode 100644 index dba8491b8bd..00000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/Kconfig.soc +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2023 Efinix Inc. -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "Efinix SoC selection" - depends on SOC_SERIES_EFINIX_SAPPHIRE - -config SOC_RISCV32_EFINIX_SAPPHIRE - bool "Efinix Sapphire VexRiscv system implementation" - select ATOMIC_OPERATIONS_BUILTIN - select INCLUDE_RESET_VECTOR - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice diff --git a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h b/soc/riscv/riscv-privileged/efinix-sapphire/soc.h deleted file mode 100644 index 1d566e2f293..00000000000 --- a/soc/riscv/riscv-privileged/efinix-sapphire/soc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2023 Efinix Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV32_EFINIX_SAPPHIRE_SOC_H_ -#define __RISCV32_EFINIX_SAPPHIRE_SOC_H_ - -#include "soc_common.h" -#include -#include - -#ifndef _ASMLANGUAGE - -#endif /* _ASMLANGUAGE */ - -#endif /* __RISCV32_EFINIX_SAPPHIRE_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt b/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt deleted file mode 100644 index be61e4a64df..00000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2021 Tokita, Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources(entry.S) -zephyr_sources(soc.c) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series deleted file mode 100644 index 061b53b2514..00000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2021 Tokita, Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_GD32VF103 - -source "soc/riscv/riscv-privileged/gd32vf103/Kconfig.defconfig.gd32vf103*" - -config SOC_SERIES - default "gd32vf103" - -endif # SOC_SERIES_GD32VF103 diff --git a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series b/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series deleted file mode 100644 index 3922bf19bdd..00000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/Kconfig.series +++ /dev/null @@ -1,20 +0,0 @@ -# GD32VF103 SOC implementation - -# Copyright (c) 2021 Tokita, Hiroshi -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_GD32VF103 - bool "GigaDevice GD32VF103 series SoC implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select BUILD_OUTPUT_HEX - select XIP - select GD32_HAS_AFIO_PINMUX - select GD32_HAS_IRC_40K - select HAS_GD32_HAL - select RISCV_HAS_CLIC - - help - Enable support for GigaDevice GD32VF1 series SoC diff --git a/soc/riscv/riscv-privileged/gd32vf103/entry.S b/soc/riscv/riscv-privileged/gd32vf103/entry.S deleted file mode 100644 index 5f8af0d691f..00000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/entry.S +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2021 Tokita, Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -GTEXT(__nuclei_start) -SECTION_FUNC(vectors, __nuclei_start) - /* Disable Global Interrupt */ - csrc mstatus, MSTATUS_MIE - /* Jump to logical address first to ensure correct operation of RAM region */ - la a0, __nuclei_start - li a1, 1 - slli a1, a1, 29 - bleu a1, a0, _start0800 - srli a1, a1, 2 - bleu a1, a0, _start0800 - la a0, _start0800 - add a0, a0, a1 - jr a0 - -_start0800: - -#if defined(CONFIG_RISCV_GP) - /* Initialize global pointer */ - .option push - .option norelax - la gp, __global_pointer$ - .option pop -#endif - - .option norvc; - - /* Set the the NMI base to share with mtvec by setting CSR_MMISC_CTL */ - li t0, 0x200 - csrs CSR_MMISC_CTL, t0 - - /* Initial the CSR MTVEC for the Trap ane NMI base addr */ - la t0, trap_entry - csrw mtvec, t0 - - /* Direct Mode: All exceptions set pc to BASE. */ - csrc mtvec, 0x3 - - /* Disable performance counter */ - csrsi mcountinhibit, 0x5 - - /* Jump to __reset */ - tail __reset - -1: - j 1b - -.align 6 -trap_entry: - tail _isr_wrapper diff --git a/soc/riscv/riscv-privileged/gd32vf103/soc.h b/soc/riscv/riscv-privileged/gd32vf103/soc.h deleted file mode 100644 index 14cdd6b733c..00000000000 --- a/soc/riscv/riscv-privileged/gd32vf103/soc.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2021 Tokita, Hiroshi - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file SoC configuration macros for the GigaDevice GD32VF103 processor - */ - -#ifndef RISCV_GD32VF103_SOC_H_ -#define RISCV_GD32VF103_SOC_H_ - -#include - -#endif /* RISCV_GD32VF103_SOC_H */ diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series deleted file mode 100644 index 81b224ed397..00000000000 --- a/soc/riscv/riscv-privileged/miv/Kconfig.defconfig.series +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV32_MIV - -config SOC_SERIES - default "miv" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 4000000 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 12 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config MAX_IRQ_PER_AGGREGATOR - default 30 - -config NUM_IRQS - default 42 - -endif # SOC_SERIES_RISCV32_MIV diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.series b/soc/riscv/riscv-privileged/miv/Kconfig.series deleted file mode 100644 index 00a6f129f9f..00000000000 --- a/soc/riscv/riscv-privileged/miv/Kconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# RISCV32_MIV implementation - -# Copyright (c) 2018 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV32_MIV - bool "Microchip Mi-V implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Microchip Mi-V diff --git a/soc/riscv/riscv-privileged/miv/Kconfig.soc b/soc/riscv/riscv-privileged/miv/Kconfig.soc deleted file mode 100644 index 189abb6879c..00000000000 --- a/soc/riscv/riscv-privileged/miv/Kconfig.soc +++ /dev/null @@ -1,20 +0,0 @@ -# RISCV32_MIV configuration options - -# Copyright (c) 2018 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "Microchip Mi-V system implementation" - depends on SOC_SERIES_RISCV32_MIV - -config SOC_RISCV32_MIV - bool "Microchip Mi-V system implementation" - select ATOMIC_OPERATIONS_BUILTIN - select INCLUDE_RESET_VECTOR - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice diff --git a/soc/riscv/riscv-privileged/miv/soc.h b/soc/riscv/riscv-privileged/miv/soc.h deleted file mode 100644 index 1608c9e6773..00000000000 --- a/soc/riscv/riscv-privileged/miv/soc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef __RISCV32_MIV_SOC_H_ -#define __RISCV32_MIV_SOC_H_ - -#include - -/* UART Configuration */ -#define MIV_UART_0_LINECFG 0x1 - -#endif /* __RISCV32_MIV_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series deleted file mode 100644 index fb9f6d2d3af..00000000000 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.defconfig.series +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2020-2021 Microchip Technology Inc -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV64_MIV - -config SOC_SERIES - default "mpfs" - -# MPFS should be configured so that the mtimer clock is 1MHz independent of the CPU clock... - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 1000000 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 13 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config MAX_IRQ_PER_AGGREGATOR - default 30 - -config NUM_IRQS - default 187 - -# config NO_OPTIMIZATIONS -# default y - -endif # SOC_SERIES_RISCV64_MIV diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.series b/soc/riscv/riscv-privileged/mpfs/Kconfig.series deleted file mode 100644 index ca37731f192..00000000000 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# RISCV64_MIV implementation - -# Copyright (c) 2018 Antmicro -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV64_MIV - bool "Microchip RV64 implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Microchip RISCV 64bit diff --git a/soc/riscv/riscv-privileged/mpfs/Kconfig.soc b/soc/riscv/riscv-privileged/mpfs/Kconfig.soc deleted file mode 100644 index 7f20dc703c2..00000000000 --- a/soc/riscv/riscv-privileged/mpfs/Kconfig.soc +++ /dev/null @@ -1,30 +0,0 @@ -# RISCV64_MIV Microchip Polarfire SOC configuration options - -# Copyright (c) 2020-2021 Microchip Technology Inc -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "Microchip Polarfire SOC implementation" - depends on SOC_SERIES_RISCV64_MIV - -config SOC_MPFS - bool "Microchip MPFS system implementation" - select ATOMIC_OPERATIONS_BUILTIN - select RISCV_GP - select USE_SWITCH_SUPPORTED - select USE_SWITCH - select CPU_HAS_FPU - select SCHED_IPI_SUPPORTED - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice - -config MPFS_HAL - depends on SOC_MPFS - bool "Microchip Polarfire SOC hardware abstracton layer" - select HAS_MPFS_HAL diff --git a/soc/riscv/riscv-privileged/mpfs/soc.h b/soc/riscv/riscv-privileged/mpfs/soc.h deleted file mode 100644 index d6a7d2d2e37..00000000000 --- a/soc/riscv/riscv-privileged/mpfs/soc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright (c) 2020-2021 Microchip Technology Inc - */ -#ifndef __RISCV64_MPFS_SOC_H_ -#define __RISCV64_MPFS_SOC_H_ - -#include -#include - - -#define RISCV_MSIP_BASE 0x02000000 - -#endif /* __RISCV64_MPFS_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series deleted file mode 100644 index 11bd7ef7d33..00000000000 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.defconfig.series +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_NEORV32 - -config SOC_SERIES - default "neorv32" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if RISCV_MACHINE_TIMER - -config NUM_IRQS - default 32 - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_GP - default y - -config SYSCON - default y - -config SERIAL_INIT_PRIORITY - default 55 - depends on SERIAL - -config ENTROPY_INIT_PRIORITY - default 55 - depends on ENTROPY_GENERATOR - -endif # SOC_SERIES_NEORV32 diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.series b/soc/riscv/riscv-privileged/neorv32/Kconfig.series deleted file mode 100644 index 98c7f34024d..00000000000 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.series +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_NEORV32 - bool "NEORV32 Processor" - select RISCV - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for the NEORV32 Processor (SoC). - - The NEORV32 CPU implementation must have the following RISC-V ISA - extensions enabled in order to support Zephyr: - - M (Integer Multiplication and Division) - - Zicsr (Control and Status Register (CSR) Instructions) - - The following NEORV32 CPU ISA extensions are not currently supported - by Zephyr and can safely be disabled: - - A (Atomic Instructions) - - E (Embedded, only 16 integer registers) - - Zbb (Basic Bit Manipulation) - - Zfinx (Floating Point in Integer Registers) diff --git a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc b/soc/riscv/riscv-privileged/neorv32/Kconfig.soc deleted file mode 100644 index 93c9da8cc3d..00000000000 --- a/soc/riscv/riscv-privileged/neorv32/Kconfig.soc +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2021 Henrik Brix Andersen -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "NEORV32 Version" - depends on SOC_SERIES_NEORV32 - -config SOC_NEORV32_V1_8_6 - bool "v1.8.6" - # NEORV32 RISC-V ISA A extension implements only LR/SC, not AMO - select ATOMIC_OPERATIONS_C - -endchoice - -if SOC_SERIES_NEORV32 - -config SOC_NEORV32_VERSION - hex - default 0x01080600 if SOC_NEORV32_V1_8_6 - help - The targeted NEORV32 version as BCD-coded number. The format is - identical to that of the NEORV32 Machine implementation ID (mimpid) - register. - -config SOC_NEORV32_ISA_C - bool "RISC-V ISA Extension \"C\"" - select RISCV_ISA_EXT_C - help - Enable this if the NEORV32 CPU implementation supports the RISC-V ISA - "C" extension (Compressed Instructions). - -endif # SOC_SERIES_NEORV32 diff --git a/soc/riscv/riscv-privileged/neorv32/soc.h b/soc/riscv/riscv-privileged/neorv32/soc.h deleted file mode 100644 index a1e721923a4..00000000000 --- a/soc/riscv/riscv-privileged/neorv32/soc.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021 Henrik Brix Andersen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef RISCV_NEORV32_SOC_H -#define RISCV_NEORV32_SOC_H - -#include - -/* System information (SYSINFO) register offsets */ -#define NEORV32_SYSINFO_CLK 0x00U -#define NEORV32_SYSINFO_CPU 0x04U -#define NEORV32_SYSINFO_FEATURES 0x08U -#define NEORV32_SYSINFO_CACHE 0x0cU -#define NEORV32_SYSINFO_ISPACE_BASE 0xf0U -#define NEORV32_SYSINFO_IMEM_SIZE 0xf4U -#define NEORV32_SYSINFO_DSPACE_BASE 0xf8U -#define NEORV32_SYSINFO_DMEM_SIZE 0xfcU - -/* System information (SYSINFO) CPU register bits */ -#define NEORV32_SYSINFO_CPU_ZICSR BIT(0) -#define NEORV32_SYSINFO_CPU_ZIFENCEI BIT(1) -#define NEORV32_SYSINFO_CPU_ZMMUL BIT(2) -#define NEORV32_SYSINFO_CPU_ZBB BIT(3) -#define NEORV32_SYSINFO_CPU_ZFINX BIT(5) -#define NEORV32_SYSINFO_CPU_ZXSCNT BIT(6) -#define NEORV32_SYSINFO_CPU_ZXNOCNT BIT(7) -#define NEORV32_SYSINFO_CPU_PMP BIT(8) -#define NEORV32_SYSINFO_CPU_HPM BIT(9) -#define NEORV32_SYSINFO_CPU_DEBUGMODE BIT(10) -#define NEORV32_SYSINFO_CPU_FASTMUL BIT(30) -#define NEORV32_SYSINFO_CPU_FASTSHIFT BIT(31) - -/* System information (SYSINFO) FEATURES register bits */ -#define NEORV32_SYSINFO_FEATURES_BOOTLOADER BIT(0) -#define NEORV32_SYSINFO_FEATURES_MEM_EXT BIT(1) -#define NEORV32_SYSINFO_FEATURES_MEM_INT_IMEM BIT(2) -#define NEORV32_SYSINFO_FEATURES_MEM_INT_DMEM BIT(3) -#define NEORV32_SYSINFO_FEATURES_MEM_EXT_ENDIAN BIT(4) -#define NEORV32_SYSINFO_FEATURES_ICACHE BIT(5) -#define NEORV32_SYSINFO_FEATURES_OCD BIT(14) -#define NEORV32_SYSINFO_FEATURES_HW_RESET BIT(15) -#define NEORV32_SYSINFO_FEATURES_IO_GPIO BIT(16) -#define NEORV32_SYSINFO_FEATURES_IO_MTIME BIT(17) -#define NEORV32_SYSINFO_FEATURES_IO_UART0 BIT(18) -#define NEORV32_SYSINFO_FEATURES_IO_SPI BIT(19) -#define NEORV32_SYSINFO_FEATURES_IO_TWI BIT(20) -#define NEORV32_SYSINFO_FEATURES_IO_PWM BIT(21) -#define NEORV32_SYSINFO_FEATURES_IO_WDT BIT(22) -#define NEORV32_SYSINFO_FEATURES_IO_CFS BIT(23) -#define NEORV32_SYSINFO_FEATURES_IO_TRNG BIT(24) -#define NEORV32_SYSINFO_FEATURES_IO_SLINK BIT(25) -#define NEORV32_SYSINFO_FEATURES_IO_UART1 BIT(26) -#define NEORV32_SYSINFO_FEATURES_IO_NEOLED BIT(27) - -#endif /* RISCV_NEORV32_SOC_H */ diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series deleted file mode 100644 index 532a67959d2..00000000000 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.defconfig.series +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_NIOSV - -config SOC_SERIES - default "niosv" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) - -config NUM_IRQS # Platform interrupts IRQs index start from index 16 - default 32 - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_GP - default y - -config RISCV_SOC_INTERRUPT_INIT - default y - -endif # SOC_SERIES_NIOSV diff --git a/soc/riscv/riscv-privileged/niosv/Kconfig.series b/soc/riscv/riscv-privileged/niosv/Kconfig.series deleted file mode 100644 index 7de17cf2db0..00000000000 --- a/soc/riscv/riscv-privileged/niosv/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (C) 2023, Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_NIOSV - bool "INTEL FPGA NIOSV" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for the INTEL FPGA NIOSV. diff --git a/soc/riscv/riscv-privileged/niosv/soc.h b/soc/riscv/riscv-privileged/niosv/soc.h deleted file mode 100644 index 8c10fec4540..00000000000 --- a/soc/riscv/riscv-privileged/niosv/soc.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (C) 2023, Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef RISCV_INTEL_FPGA_NIOSV_H -#define RISCV_INTEL_FPGA_NIOSV_H - -#include -#include - -#endif /* RISCV_INTEL_FPGA_NIOSV_H */ diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series deleted file mode 100644 index c9e7f8396a0..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.defconfig.series +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2023 Rivos Inc. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV_OPENTITAN - -config SOC_SERIES - default "opentitan" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 1000000 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 32 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config NUM_IRQS - default 217 - -endif # SOC_SERIES_RISCV_OPENTITAN diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.series b/soc/riscv/riscv-privileged/opentitan/Kconfig.series deleted file mode 100644 index f8bbc2840fe..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.series +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2023 Rivos Inc. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_OPENTITAN - bool "OpenTitan implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - # OpenTitan Ibex core mtvec mode is read-only / forced to vectored mode. - select RISCV_VECTORED_MODE - select GEN_IRQ_VECTOR_TABLE - help - Enable support for OpenTitan diff --git a/soc/riscv/riscv-privileged/opentitan/Kconfig.soc b/soc/riscv/riscv-privileged/opentitan/Kconfig.soc deleted file mode 100644 index 098b1844e52..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/Kconfig.soc +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2023 Rivos Inc. -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "OpenTitan implementation" - depends on SOC_SERIES_RISCV_OPENTITAN - -config SOC_RISCV_OPENTITAN - bool "OpenTitan implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - select RISCV_ISA_EXT_ZBA - select RISCV_ISA_EXT_ZBB - select RISCV_ISA_EXT_ZBC - select RISCV_ISA_EXT_ZBS - -endchoice diff --git a/soc/riscv/riscv-privileged/opentitan/soc.c b/soc/riscv/riscv-privileged/opentitan/soc.c deleted file mode 100644 index 0b04079233a..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/soc.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Rivos Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#define PWRMGR_BASE (DT_REG_ADDR(DT_NODELABEL(pwrmgr))) -#define RV_TIMER_BASE (DT_REG_ADDR(DT_NODELABEL(mtimer))) - -static int soc_opentitan_init(void) -{ - /* Enable the watchdog reset (bit 1). */ - sys_write32(2u, PWRMGR_BASE + PWRMGR_RESET_EN_REG_OFFSET); - /* Write CFG_CDC_SYNC to commit change. */ - sys_write32(1u, PWRMGR_BASE + PWRMGR_CFG_CDC_SYNC_REG_OFFSET); - /* Poll CFG_CDC_SYNC register until it reads 0. */ - while (sys_read32(PWRMGR_BASE + PWRMGR_CFG_CDC_SYNC_REG_OFFSET)) { - } - - /* Initialize the Machine Timer, so it behaves as a regular one. */ - sys_write32(1u, RV_TIMER_BASE + RV_TIMER_CTRL_REG_OFFSET); - /* Enable timer interrupts. */ - sys_write32(1u, RV_TIMER_BASE + RV_TIMER_INTR_ENABLE_REG_OFFSET); - return 0; -} -SYS_INIT(soc_opentitan_init, PRE_KERNEL_1, 0); diff --git a/soc/riscv/riscv-privileged/opentitan/soc.h b/soc/riscv/riscv-privileged/opentitan/soc.h deleted file mode 100644 index 13bb5c43b54..00000000000 --- a/soc/riscv/riscv-privileged/opentitan/soc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023 Rivos Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_OPENTITAN_SOC_H_ -#define __RISCV_OPENTITAN_SOC_H_ - -#include -#include - -/* OpenTitan power management regs. */ -#define PWRMGR_CFG_CDC_SYNC_REG_OFFSET 0x018 -#define PWRMGR_RESET_EN_REG_OFFSET 0x02c -#define PWRMGR_RESET_EN_WDOG_SRC_MASK 0x002 - -/* Ibex timer registers. */ -#define RV_TIMER_CTRL_REG_OFFSET 0x004 -#define RV_TIMER_INTR_ENABLE_REG_OFFSET 0x100 -#define RV_TIMER_CFG0_REG_OFFSET 0x10c -#define RV_TIMER_CFG0_PRESCALE_MASK 0xfff -#define RV_TIMER_CFG0_PRESCALE_OFFSET 0 -#define RV_TIMER_CFG0_STEP_MASK 0xff -#define RV_TIMER_CFG0_STEP_OFFSET 16 -#define RV_TIMER_LOWER0_OFFSET 0x110 -#define RV_TIMER_COMPARE_LOWER0_OFFSET 0x118 - -#endif /* __RISCV_OPENTITAN_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt b/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt deleted file mode 100644 index ff4cc56d739..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources() -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FREEDOM fe310_clock.c) -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU540 fu540_clock.c) -zephyr_sources_ifdef(CONFIG_SOC_RISCV_SIFIVE_FU740 fu740_clock.c) - -set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series deleted file mode 100644 index 0c3cd541773..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.defconfig.series +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV_SIFIVE_FREEDOM - -config SOC_SERIES - default "sifive-freedom" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 32768 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 12 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config MAX_IRQ_PER_AGGREGATOR - default 52 - -config NUM_IRQS - default 64 - -endif # SOC_SERIES_RISCV_SIFIVE_FREEDOM diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series deleted file mode 100644 index 523f6a4ffe9..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.series +++ /dev/null @@ -1,11 +0,0 @@ -# RISCV_SIFIVE_FREEDOM SOC implementation - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_SIFIVE_FREEDOM - bool "SiFive Freedom SOC implementation" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for SiFive Freedom SOC diff --git a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc b/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc deleted file mode 100644 index 7840f8a09ba..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/Kconfig.soc +++ /dev/null @@ -1,44 +0,0 @@ -# RISCV_SIFIVE_FREEDOM SOC configuration options - -# Copyright (c) 2017 Jean-Paul Etienne -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "SiFive Freedom SOC implementation" - depends on SOC_SERIES_RISCV_SIFIVE_FREEDOM - -config SOC_RISCV_SIFIVE_FREEDOM - bool "SiFive Freedom SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config SOC_RISCV_SIFIVE_FU540 - bool "SiFive Freedom U540 SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select 64BIT - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -config SOC_RISCV_SIFIVE_FU740 - bool "SiFive Freedom U740 SOC implementation" - select ATOMIC_OPERATIONS_C - select INCLUDE_RESET_VECTOR - select 64BIT - select RISCV_ISA_RV64I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c deleted file mode 100644 index 0b642f3e8b2..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fe310_clock.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * Copyright (c) 2017 Palmer Dabbelt - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "fe310_prci.h" - -#define CORECLK_HZ (DT_PROP(DT_NODELABEL(coreclk), clock_frequency)) -BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 1, - "Unsupported TLCLK divider"); - -static int fe310_clock_init(void) -{ - - /* - * HFXOSC (16 MHz) is used to produce coreclk (and therefore tlclk / - * peripheral clock). This code supports the following frequencies: - * - 16 MHz (bypass HFPLL). - * - 48 MHz - 320 MHz, in 8 MHz steps (use HFPLL). - */ - BUILD_ASSERT(MHZ(16) == CORECLK_HZ || - (MHZ(48) <= CORECLK_HZ && MHZ(320) >= CORECLK_HZ && - (CORECLK_HZ % MHZ(8)) == 0), - "Unsupported CORECLK frequency"); - - uint32_t prci; - - if (MHZ(16) == CORECLK_HZ) { - /* Bypass HFPLL. */ - prci = PLL_REFSEL(1) | PLL_BYPASS(1); - } else { - /* refr = 8 MHz. */ - const int pll_r = 0x1; - int pll_q; - - /* Select Q divisor to produce vco on [384 MHz, 768 MHz]. */ - if (MHZ(768) / 8 >= CORECLK_HZ) { - pll_q = 0x3; - } else if (MHZ(768) / 4 >= CORECLK_HZ) { - pll_q = 0x2; - } else { - pll_q = 0x1; - } - /* Select F multiplier to produce vco target. */ - const int pll_f = ((CORECLK_HZ / MHZ(1)) >> (4 - pll_q)) - 1; - - prci = PLL_REFSEL(1) | PLL_R(pll_r) | PLL_F(pll_f) | PLL_Q(pll_q); - } - - PRCI_REG(PRCI_PLLCFG) = prci; - PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0)); - PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1); - PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1); - return 0; -} - -SYS_INIT(fe310_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h deleted file mode 100644 index 07e088fbd82..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fe310_prci.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017 SiFive Inc - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SIFIVE_PRCI_H -#define _SIFIVE_PRCI_H - -#include - -#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) -#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) - -/* Register offsets */ - -#define PRCI_HFROSCCFG (0x0000) -#define PRCI_HFXOSCCFG (0x0004) -#define PRCI_PLLCFG (0x0008) -#define PRCI_PLLDIV (0x000C) -#define PRCI_PROCMONCFG (0x00F0) - -/* Fields */ -#define ROSC_DIV(x) (((x) & 0x2F) << 0) -#define ROSC_TRIM(x) (((x) & 0x1F) << 16) -#define ROSC_EN(x) (((x) & 0x1) << 30) -#define ROSC_RDY(x) (((x) & 0x1) << 31) - -#define XOSC_EN(x) (((x) & 0x1) << 30) -#define XOSC_RDY(x) (((x) & 0x1) << 31) - -#define PLL_R(x) (((x) & 0x7) << 0) -/* single reserved bit for F LSB. */ -#define PLL_F(x) (((x) & 0x3F) << 4) -#define PLL_Q(x) (((x) & 0x3) << 10) -#define PLL_SEL(x) (((x) & 0x1) << 16) -#define PLL_REFSEL(x) (((x) & 0x1) << 17) -#define PLL_BYPASS(x) (((x) & 0x1) << 18) -#define PLL_LOCK(x) (((x) & 0x1) << 31) - -#define PLL_R_default 0x1 -#define PLL_F_default 0x1F -#define PLL_Q_default 0x3 - -#define PLL_REFSEL_HFROSC 0x0 -#define PLL_REFSEL_HFXOSC 0x1 - -#define PLL_SEL_HFROSC 0x0 -#define PLL_SEL_PLL 0x1 - -#define PLL_FINAL_DIV(x) (((x) & 0x3F) << 0) -#define PLL_FINAL_DIV_BY_1(x) (((x) & 0x1) << 8) - -#define PROCMON_DIV(x) (((x) & 0x1F) << 0) -#define PROCMON_TRIM(x) (((x) & 0x1F) << 8) -#define PROCMON_EN(x) (((x) & 0x1) << 16) -#define PROCMON_SEL(x) (((x) & 0x3) << 24) -#define PROCMON_NT_EN(x) (((x) & 0x1) << 28) - -#define PROCMON_SEL_HFCLK 0 -#define PROCMON_SEL_HFXOSCIN 1 -#define PROCMON_SEL_PLLOUTDIV 2 -#define PROCMON_SEL_PROCMON 3 - -#endif /* _SIFIVE_PRCI_H */ diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c deleted file mode 100644 index bc68a502f59..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu540_clock.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 Katsuhiro Suzuki - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include "fu540_prci.h" - -BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), - "Unsupported CORECLK frequency"); -BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 2, - "Unsupported TLCLK divider"); - -/* - * Switch the clock source to 1GHz PLL from 33.333MHz oscillator on the HiFive - * Unleashed board. - */ -static int fu540_clock_init(void) -{ - - PRCI_REG(PRCI_COREPLLCFG0) = - PLL_R(0) | /* input divider: Fin / (0 + 1) = 33.33MHz */ - PLL_F(59) | /* VCO: 2 x (59 + 1) = 120 = 3999.6MHz */ - PLL_Q(2) | /* output divider: VCO / 2^2 = 999.9MHz */ - PLL_RANGE(PLL_RANGE_33MHZ) | - PLL_BYPASS(PLL_BYPASS_DISABLE) | - PLL_FSE(PLL_FSE_INTERNAL); - while ((PRCI_REG(PRCI_COREPLLCFG0) & PLL_LOCK(1)) == 0) - ; - - /* Switch clock to COREPLL */ - PRCI_REG(PRCI_CORECLKSEL) = CORECLKSEL_CORECLKSEL(CORECLKSEL_CORE_PLL); - - return 0; -} - -SYS_INIT(fu540_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h deleted file mode 100644 index 6709d4bfad2..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu540_prci.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021 Katsuhiro Suzuki - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SIFIVE_FU540_PRCI_H -#define _SIFIVE_FU540_PRCI_H - -#include - -#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) -#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) - -/* Register offsets */ - -#define PRCI_HFXOSCCFG (0x0000) -#define PRCI_COREPLLCFG0 (0x0004) -#define PRCI_DDRPLLCFG0 (0x000c) -#define PRCI_DDRPLLCFG1 (0x0010) -#define PRCI_GEMGXLPLLCFG0 (0x001c) -#define PRCI_GEMGXLPLLCFG1 (0x0020) -#define PRCI_CORECLKSEL (0x0024) -#define PRCI_DEVICESRESETREG (0x0028) - -#define PLL_R(x) (((x) & 0x3f) << 0) -#define PLL_F(x) (((x) & 0x1ff) << 6) -#define PLL_Q(x) (((x) & 0x7) << 15) -#define PLL_RANGE(x) (((x) & 0x7) << 18) -#define PLL_BYPASS(x) (((x) & 0x1) << 24) -#define PLL_FSE(x) (((x) & 0x1) << 25) -#define PLL_LOCK(x) (((x) & 0x1) << 31) - -#define PLL_RANGE_33MHZ 4 -#define PLL_BYPASS_DISABLE 0 -#define PLL_BYPASS_ENABLE 1 -#define PLL_FSE_INTERNAL 1 - -#define CORECLKSEL_CORECLKSEL(x) (((x) & 0x1) << 0) - -#define CORECLKSEL_CORE_PLL 0 -#define CORECLKSEL_HFCLK 1 - -#endif /* _SIFIVE_FU540_PRCI_H */ diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c b/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c deleted file mode 100644 index e6bbee93689..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu740_clock.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2021 Katsuhiro Suzuki - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "fu740_prci.h" - -BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), - "Unsupported CORECLK frequency"); -BUILD_ASSERT(KHZ(125125) == DT_PROP(DT_NODELABEL(pclk), clock_frequency), - "Unsupported PCLK frequency"); - -static inline void wait_controller_cycle(void) -{ - /* HACK to get the '1 full controller clock cycle'. */ - __asm__ volatile ("fence"); -} - -/* - * Switch the clock source - * - core: to 1GHz PLL (CORE_PLL) from 26MHz oscillator (HFCLK) - * - peri: to 250MHz PLL (HFPCLKPLL) from HFCLK - * - ddr: to 923MHz PLL (DDRPLL) from HFCLK (half of the data rate) - * on the HiFive Unmatched board. - * - * Note: Valid PLL VCO range is 2400MHz to 4800MHz - */ -static int fu740_clock_init(void) -{ - - PRCI_REG(PRCI_COREPLLCFG) = - PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ - PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */ - PLL_Q(2) | /* output divider: VCO / 2^2 = 1001MHz */ - PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */ - PLL_BYPASS(PLL_BYPASS_DISABLE) | - PLL_FSE(PLL_FSE_INTERNAL); - while ((PRCI_REG(PRCI_COREPLLCFG) & PLL_LOCK(1)) == 0) - ; - - /* Switch CORE_CLK to CORE_PLL from HFCLK */ - PRCI_REG(PRCI_COREPLLSEL) = COREPLLSEL_SEL(COREPLLSEL_COREPLL); - PRCI_REG(PRCI_CORECLKSEL) = CLKSEL_SEL(CLKSEL_PLL); - - PRCI_REG(PRCI_HFPCLKPLLCFG) = - PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ - PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */ - PLL_Q(4) | /* output divider: VCO / 2^4 = 250.25MHz */ - PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */ - PLL_BYPASS(PLL_BYPASS_DISABLE) | - PLL_FSE(PLL_FSE_INTERNAL); - while ((PRCI_REG(PRCI_HFPCLKPLLCFG) & PLL_LOCK(1)) == 0) - ; - - /* Switch PCLK to HFPCLKPLL/2 from HFCLK/2 */ - PRCI_REG(PRCI_HFPCLKPLLOUTDIV) = OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA); - PRCI_REG(PRCI_HFPCLKPLLSEL) = CLKSEL_SEL(CLKSEL_PLL); - - PRCI_REG(PRCI_DDRPLLCFG) = - PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ - PLL_F(70) | /* VCO: 2 x (70 + 1) = 154 = 1872MHz */ - PLL_Q(2) | /* output divider: VCO / 2^2 = 936MHz */ - PLL_RANGE(PLL_RANGE_18MHZ) | - PLL_BYPASS(PLL_BYPASS_DISABLE) | - PLL_FSE(PLL_FSE_INTERNAL); - while ((PRCI_REG(PRCI_DDRPLLCFG) & PLL_LOCK(1)) == 0) - ; - - PRCI_REG(PRCI_DDRPLLOUTDIV) |= OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA); - - PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRCTRL; - wait_controller_cycle(); - - /* Release DDR reset */ - PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRAXI | - DEVICERESETN_DDRAHB | - DEVICERESETN_DDRPHY; - wait_controller_cycle(); - - /* - * These take like 16 cycles to actually propagate. We can't go sending stuff before they - * come out of reset. So wait. - */ - for (int i = 0; i < 256; i++) { - __asm__ volatile ("nop"); - } - return 0; -} - -SYS_INIT(fu740_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h b/soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h deleted file mode 100644 index 00d529388c8..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/fu740_prci.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2021 Katsuhiro Suzuki - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _SIFIVE_FU740_PRCI_H -#define _SIFIVE_FU740_PRCI_H - -#include - -#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) -#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) - -/* Register offsets */ - -#define PRCI_HFXOSCCFG (0x0000) -#define PRCI_COREPLLCFG (0x0004) -#define PRCI_COREPLLOUTDIV (0x0008) -#define PRCI_DDRPLLCFG (0x000c) -#define PRCI_DDRPLLOUTDIV (0x0010) -#define PRCI_GEMGXLPLLCFG (0x001c) -#define PRCI_GEMGXLPLLOUTDIV (0x0020) -#define PRCI_CORECLKSEL (0x0024) -#define PRCI_DEVICESRESETN (0x0028) -#define PRCI_CLKMUXSTATUS (0x002c) -#define PRCI_COREPLLSEL (0x0040) -#define PRCI_HFPCLKPLLCFG (0x0050) -#define PRCI_HFPCLKPLLOUTDIV (0x0054) -#define PRCI_HFPCLKPLLSEL (0x0058) - -#define PLL_R(x) (((x) & 0x3f) << 0) -#define PLL_F(x) (((x) & 0x1ff) << 6) -#define PLL_Q(x) (((x) & 0x7) << 15) -#define PLL_RANGE(x) (((x) & 0x7) << 18) -#define PLL_BYPASS(x) (((x) & 0x1) << 24) -#define PLL_FSE(x) (((x) & 0x1) << 25) -#define PLL_LOCK(x) (((x) & 0x1) << 31) - -#define PLL_RANGE_RESET 0 -#define PLL_RANGE_0MHZ 1 -#define PLL_RANGE_11MHZ 2 -#define PLL_RANGE_18MHZ 3 -#define PLL_RANGE_30MHZ 4 -#define PLL_RANGE_50MHZ 5 -#define PLL_RANGE_80MHZ 6 -#define PLL_RANGE_130MHZ 7 -#define PLL_BYPASS_DISABLE 0 -#define PLL_BYPASS_ENABLE 1 -#define PLL_FSE_INTERNAL 1 - -#define OUTDIV_PLLCKE(x) (((x) & 0x1) << 31) - -#define OUTDIV_PLLCKE_DIS 0 -#define OUTDIV_PLLCKE_ENA 1 - -#define CLKSEL_SEL(x) (((x) & 0x1) << 0) - -#define CLKSEL_PLL 0 -#define CLKSEL_HFCLK 1 - -#define CLKMUXSTATUS_CORECLKPLLSEL_OFF 0 -#define CLKMUXSTATUS_TLCLKSEL_OFF 1 -#define CLKMUXSTATUS_RTCXSEL_OFF 2 -#define CLKMUXSTATUS_DDRCTRLCLKSEL_OFF 3 -#define CLKMUXSTATUS_DDRPHYCLKSEL_OFF 4 -#define CLKMUXSTATUS_GEMGXLCLKSEL_OFF 6 -#define CLKMUXSTATUS_MAINMEMCLKSEL_OFF 7 - -#define COREPLLSEL_SEL(x) (((x) & 0x1) << 0) - -#define COREPLLSEL_COREPLL 0 -#define COREPLLSEL_DVFSCOREPLL 1 - -#define DEVICERESETN_DDRCTRL BIT(0) -#define DEVICERESETN_DDRAXI BIT(1) -#define DEVICERESETN_DDRAHB BIT(2) -#define DEVICERESETN_DDRPHY BIT(3) -#define DEVICERESETN_PCIEAUX BIT(4) -#define DEVICERESETN_GEMGXL BIT(5) - -#endif /* _SIFIVE_FU740_PRCI_H */ diff --git a/soc/riscv/riscv-privileged/sifive-freedom/soc.h b/soc/riscv/riscv-privileged/sifive-freedom/soc.h deleted file mode 100644 index 958891a9d6a..00000000000 --- a/soc/riscv/riscv-privileged/sifive-freedom/soc.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017 Jean-Paul Etienne - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file SoC configuration macros for the SiFive Freedom processor - */ - -#ifndef __RISCV_SIFIVE_FREEDOM_SOC_H_ -#define __RISCV_SIFIVE_FREEDOM_SOC_H_ - -#include - -#if defined(CONFIG_SOC_RISCV_SIFIVE_FREEDOM) -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 32 - -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10008000 - -#elif defined(CONFIG_SOC_RISCV_SIFIVE_FU540) || defined(CONFIG_SOC_RISCV_SIFIVE_FU740) - -/* Clock controller. */ -#define PRCI_BASE_ADDR 0x10000000 - -/* PINMUX MAX PINS */ -#define SIFIVE_PINMUX_PINS 16 - -#endif - -#if defined(CONFIG_SOC_RISCV_SIFIVE_FREEDOM) || defined(CONFIG_SOC_RISCV_SIFIVE_FU540) - -/* - * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked - * by TLCLK, which is derived from CORECLK. - */ -#define SIFIVE_TLCLK_BASE_FREQUENCY \ - DT_PROP_BY_PHANDLE_IDX(DT_NODELABEL(tlclk), clocks, 0, clock_frequency) -#define SIFIVE_TLCLK_DIVIDER DT_PROP(DT_NODELABEL(tlclk), clock_div) -#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ - (SIFIVE_TLCLK_BASE_FREQUENCY / SIFIVE_TLCLK_DIVIDER) - -#elif defined(CONFIG_SOC_RISCV_SIFIVE_FU740) - -/* On FU740, peripherals are clocked by PCLK. */ -#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ - DT_PROP(DT_NODELABEL(pclk), clock_frequency) - -#endif - -#endif /* __RISCV_SIFIVE_FREEDOM_SOC_H_ */ diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series deleted file mode 100644 index c488c614b7d..00000000000 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.defconfig.series +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2021 Rajnesh Kanwal -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_STARFIVE_JH71XX - -config SOC_SERIES - default "starfive_jh71xx" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 6250000 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 12 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config NUM_IRQS - default 139 - -endif diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series b/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series deleted file mode 100644 index b360f78b77b..00000000000 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.series +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2021 Rajnesh Kanwal -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_STARFIVE_JH71XX - bool "Starfive JH71XX series" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED - help - Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/soc.h b/soc/riscv/riscv-privileged/starfive_jh71xx/soc.h deleted file mode 100644 index 796f07201d9..00000000000 --- a/soc/riscv/riscv-privileged/starfive_jh71xx/soc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_VIRT_SOC_H_ -#define __RISCV_VIRT_SOC_H_ - -#include - -#endif diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series deleted file mode 100644 index 986b6240750..00000000000 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.defconfig.series +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2021 Telink Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV_TELINK_B91 - -config SOC_SERIES - string - default "telink_b91" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - int - default 32000 - -config RISCV_SOC_INTERRUPT_INIT - bool - default y - -config RISCV_HAS_CPU_IDLE - bool - default y - -config RISCV_HAS_PLIC - bool - default y - -config RISCV_GP - bool - default y - -config NUM_IRQS - int - default 64 - -config PINCTRL - default y - -config XIP - bool - default n - -config MAIN_STACK_SIZE - int - default 2048 - -config IDLE_STACK_SIZE - int - default 1536 - -config TEST_EXTRA_STACK_SIZE - int - default 1024 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config HAS_FLASH_LOAD_OFFSET - default y if BOOTLOADER_MCUBOOT - -endif # SOC_SERIES_RISCV_TELINK_B91 diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series b/soc/riscv/riscv-privileged/telink_b91/Kconfig.series deleted file mode 100644 index a966dfe447b..00000000000 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.series +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2021 Telink Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_TELINK_B91 - bool "Telink B91 SoC Implementation" - select RISCV - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - select SOC_FAMILY_RISCV_PRIVILEGED - select HAS_TELINK_DRIVERS - help - Enable support for Telink B91 SoC diff --git a/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc b/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc deleted file mode 100644 index 3f4f96c332e..00000000000 --- a/soc/riscv/riscv-privileged/telink_b91/Kconfig.soc +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2021 Telink Semiconductor -# SPDX-License-Identifier: Apache-2.0 - -choice -prompt "CPU Architecture of SoC" -depends on SOC_SERIES_RISCV_TELINK_B91 - -config B91_CPU_RISCV32 - bool "RISCV32 CPU Architecture" - select RISCV_ISA_RV32I - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - select RISCV_ISA_EXT_ZICSR - select RISCV_ISA_EXT_ZIFENCEI - -endchoice - -config TELINK_B91_HWDSP - bool "Support Hardware DSP" - select RISCV_SOC_CONTEXT_SAVE - depends on SOC_SERIES_RISCV_TELINK_B91 - -config TELINK_B91_PFT_ARCH - bool "Support performance throttling" - default y - select RISCV_SOC_CONTEXT_SAVE - depends on SOC_SERIES_RISCV_TELINK_B91 - -choice -prompt "Telink B91 SoC implementation" -depends on SOC_SERIES_RISCV_TELINK_B91 - -config SOC_RISCV_TELINK_B91 - bool "Telink B91 SoC implementation" - select ATOMIC_OPERATIONS_BUILTIN - select CPU_HAS_FPU - select INCLUDE_RESET_VECTOR - -endchoice diff --git a/soc/riscv/riscv-privileged/telink_b91/soc.h b/soc/riscv/riscv-privileged/telink_b91/soc.h deleted file mode 100644 index a46b4c620c7..00000000000 --- a/soc/riscv/riscv-privileged/telink_b91/soc.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (c) 2021 Telink Semiconductor - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef RISCV_TELINK_B91_SOC_H -#define RISCV_TELINK_B91_SOC_H - -#include - -#endif /* RISCV_TELINK_B91_SOC_H */ diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series deleted file mode 100644 index 231d4519d67..00000000000 --- a/soc/riscv/riscv-privileged/virt/Kconfig.defconfig.series +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2020 Cobham Gaisler AB -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_RISCV_VIRT - -config SOC_SERIES - default "virt" - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 10000000 - -config RISCV_SOC_INTERRUPT_INIT - default y - -config RISCV_HAS_CPU_IDLE - default y - -config RISCV_HAS_PLIC - default y - -config RISCV_GP - default y - -config 2ND_LVL_ISR_TBL_OFFSET - default 12 - -config 2ND_LVL_INTR_00_OFFSET - default 11 - -config MAX_IRQ_PER_AGGREGATOR - default 52 - -config NUM_IRQS - default 1035 - -config PMP_SLOTS - default 16 - -endif diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.series b/soc/riscv/riscv-privileged/virt/Kconfig.series deleted file mode 100644 index e9846764f6b..00000000000 --- a/soc/riscv/riscv-privileged/virt/Kconfig.series +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2020 Cobham Gaisler AB -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_RISCV_VIRT - bool "QEMU RISC-V VirtIO Board" - select RISCV - select SOC_FAMILY_RISCV_PRIVILEGED diff --git a/soc/riscv/riscv-privileged/virt/Kconfig.soc b/soc/riscv/riscv-privileged/virt/Kconfig.soc deleted file mode 100644 index 35a2853eb50..00000000000 --- a/soc/riscv/riscv-privileged/virt/Kconfig.soc +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2020 Cobham Gaisler AB -# SPDX-License-Identifier: Apache-2.0 - -choice - prompt "QEMU RISC-V VirtIO Board" - depends on SOC_SERIES_RISCV_VIRT - -config SOC_RISCV_VIRT - bool "QEMU RISC-V VirtIO Board" - select ATOMIC_OPERATIONS_BUILTIN - select INCLUDE_RESET_VECTOR - select RISCV_ISA_EXT_M - select RISCV_ISA_EXT_A - select RISCV_ISA_EXT_C - -endchoice diff --git a/soc/riscv/riscv-privileged/virt/soc.c b/soc/riscv/riscv-privileged/virt/soc.c deleted file mode 100644 index 581f4116c9b..00000000000 --- a/soc/riscv/riscv-privileged/virt/soc.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021 Katsuhiro Suzuki - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief QEMU RISC-V virt machine hardware depended interface - */ - -#include -#include -#include - -/* - * Exit QEMU and tell error number. - * Higher 16bits: indicates error number. - * Lower 16bits : set FINISHER_FAIL - */ -#define FINISHER_FAIL 0x3333 - -/* Exit QEMU successfully */ -#define FINISHER_EXIT 0x5555 - -/* Reboot machine */ -#define FINISHER_REBOOT 0x7777 - -void sys_arch_reboot(int type) -{ - volatile uint32_t *reg = (uint32_t *)SIFIVE_SYSCON_TEST; - - *reg = FINISHER_REBOOT; - - ARG_UNUSED(type); -} diff --git a/soc/riscv/riscv-privileged/virt/soc.h b/soc/riscv/riscv-privileged/virt/soc.h deleted file mode 100644 index 8fd5e2108ce..00000000000 --- a/soc/riscv/riscv-privileged/virt/soc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2020 Cobham Gaisler AB - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __RISCV_VIRT_SOC_H_ -#define __RISCV_VIRT_SOC_H_ - -#include - -#define SIFIVE_SYSCON_TEST 0x00100000 -#define RISCV_MSIP_BASE 0x02000000 - -#endif diff --git a/soc/riscv/sifive_freedom/CMakeLists.txt b/soc/riscv/sifive_freedom/CMakeLists.txt new file mode 100644 index 00000000000..6a5b10545ff --- /dev/null +++ b/soc/riscv/sifive_freedom/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(common) +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/sifive_freedom/Kconfig b/soc/riscv/sifive_freedom/Kconfig new file mode 100644 index 00000000000..0fed11158af --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_SIFIVE_FREEDOM + bool + +if SOC_FAMILY_SIFIVE_FREEDOM + +config SOC_FAMILY + string + default "sifive_freedom" + +source "soc/riscv/sifive_freedom/*/Kconfig.soc" + +endif # SOC_FAMILY_SIFIVE_FREEDOM diff --git a/soc/riscv/sifive_freedom/Kconfig.defconfig b/soc/riscv/sifive_freedom/Kconfig.defconfig new file mode 100644 index 00000000000..5adf8fc437e --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/sifive_freedom/*/Kconfig.defconfig.series" diff --git a/soc/riscv/sifive_freedom/Kconfig.soc b/soc/riscv/sifive_freedom/Kconfig.soc new file mode 100644 index 00000000000..54274defd91 --- /dev/null +++ b/soc/riscv/sifive_freedom/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/sifive_freedom/*/Kconfig.series" diff --git a/soc/riscv/sifive_freedom/common/CMakeLists.txt b/soc/riscv/sifive_freedom/common/CMakeLists.txt new file mode 100644 index 00000000000..f75aec6b311 --- /dev/null +++ b/soc/riscv/sifive_freedom/common/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) diff --git a/soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h b/soc/riscv/sifive_freedom/common/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/sifive-freedom/pinctrl_soc.h rename to soc/riscv/sifive_freedom/common/pinctrl_soc.h diff --git a/soc/riscv/sifive_freedom/e300/CMakeLists.txt b/soc/riscv/sifive_freedom/e300/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 new file mode 100644 index 00000000000..cb0131f1427 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e340 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "e340" if SOC_SIFIVE_FREEDOM_E340 diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series new file mode 100644 index 00000000000..eaa43e68e70 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIFIVE_FREEDOM_E300 + +config SOC_SERIES + default "e300" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +source "soc/riscv/sifive_freedom/e300/Kconfig.defconfig.e*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_E300 diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.series b/soc/riscv/sifive_freedom/e300/Kconfig.series new file mode 100644 index 00000000000..81634da000d --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_E300 + bool "SiFive Freedom E300 SOC implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom FE300 SOC diff --git a/soc/riscv/sifive_freedom/e300/Kconfig.soc b/soc/riscv/sifive_freedom/e300/Kconfig.soc new file mode 100644 index 00000000000..e53b84c0890 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/Kconfig.soc @@ -0,0 +1,20 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_E300 + +config SOC_SIFIVE_FREEDOM_E340 + bool "SiFive Freedom SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/sifive_freedom/e300/clock.c b/soc/riscv/sifive_freedom/e300/clock.c new file mode 100644 index 00000000000..8fde8121db9 --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/clock.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * Copyright (c) 2017 Palmer Dabbelt + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "prci.h" + +#define CORECLK_HZ (DT_PROP(DT_NODELABEL(coreclk), clock_frequency)) +BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 1, + "Unsupported TLCLK divider"); + +static int fe310_clock_init(void) +{ + + /* + * HFXOSC (16 MHz) is used to produce coreclk (and therefore tlclk / + * peripheral clock). This code supports the following frequencies: + * - 16 MHz (bypass HFPLL). + * - 48 MHz - 320 MHz, in 8 MHz steps (use HFPLL). + */ + BUILD_ASSERT(MHZ(16) == CORECLK_HZ || + (MHZ(48) <= CORECLK_HZ && MHZ(320) >= CORECLK_HZ && + (CORECLK_HZ % MHZ(8)) == 0), + "Unsupported CORECLK frequency"); + + uint32_t prci; + + if (MHZ(16) == CORECLK_HZ) { + /* Bypass HFPLL. */ + prci = PLL_REFSEL(1) | PLL_BYPASS(1); + } else { + /* refr = 8 MHz. */ + const int pll_r = 0x1; + int pll_q; + + /* Select Q divisor to produce vco on [384 MHz, 768 MHz]. */ + if (MHZ(768) / 8 >= CORECLK_HZ) { + pll_q = 0x3; + } else if (MHZ(768) / 4 >= CORECLK_HZ) { + pll_q = 0x2; + } else { + pll_q = 0x1; + } + /* Select F multiplier to produce vco target. */ + const int pll_f = ((CORECLK_HZ / MHZ(1)) >> (4 - pll_q)) - 1; + + prci = PLL_REFSEL(1) | PLL_R(pll_r) | PLL_F(pll_f) | PLL_Q(pll_q); + } + + PRCI_REG(PRCI_PLLCFG) = prci; + PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0)); + PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1); + PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1); + return 0; +} + +SYS_INIT(fe310_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/sifive_freedom/e300/prci.h b/soc/riscv/sifive_freedom/e300/prci.h new file mode 100644 index 00000000000..6c2da210aad --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/prci.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017 SiFive Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SIFIVE_PRCI_H +#define _SIFIVE_PRCI_H + +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10008000UL + +#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) +#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) + +/* Register offsets */ + +#define PRCI_HFROSCCFG (0x0000) +#define PRCI_HFXOSCCFG (0x0004) +#define PRCI_PLLCFG (0x0008) +#define PRCI_PLLDIV (0x000C) +#define PRCI_PROCMONCFG (0x00F0) + +/* Fields */ +#define ROSC_DIV(x) (((x) & 0x2F) << 0) +#define ROSC_TRIM(x) (((x) & 0x1F) << 16) +#define ROSC_EN(x) (((x) & 0x1) << 30) +#define ROSC_RDY(x) (((x) & 0x1) << 31) + +#define XOSC_EN(x) (((x) & 0x1) << 30) +#define XOSC_RDY(x) (((x) & 0x1) << 31) + +#define PLL_R(x) (((x) & 0x7) << 0) +/* single reserved bit for F LSB. */ +#define PLL_F(x) (((x) & 0x3F) << 4) +#define PLL_Q(x) (((x) & 0x3) << 10) +#define PLL_SEL(x) (((x) & 0x1) << 16) +#define PLL_REFSEL(x) (((x) & 0x1) << 17) +#define PLL_BYPASS(x) (((x) & 0x1) << 18) +#define PLL_LOCK(x) (((x) & 0x1) << 31) + +#define PLL_R_default 0x1 +#define PLL_F_default 0x1F +#define PLL_Q_default 0x3 + +#define PLL_REFSEL_HFROSC 0x0 +#define PLL_REFSEL_HFXOSC 0x1 + +#define PLL_SEL_HFROSC 0x0 +#define PLL_SEL_PLL 0x1 + +#define PLL_FINAL_DIV(x) (((x) & 0x3F) << 0) +#define PLL_FINAL_DIV_BY_1(x) (((x) & 0x1) << 8) + +#define PROCMON_DIV(x) (((x) & 0x1F) << 0) +#define PROCMON_TRIM(x) (((x) & 0x1F) << 8) +#define PROCMON_EN(x) (((x) & 0x1) << 16) +#define PROCMON_SEL(x) (((x) & 0x3) << 24) +#define PROCMON_NT_EN(x) (((x) & 0x1) << 28) + +#define PROCMON_SEL_HFCLK 0 +#define PROCMON_SEL_HFXOSCIN 1 +#define PROCMON_SEL_PLLOUTDIV 2 +#define PROCMON_SEL_PROCMON 3 + +#endif /* _SIFIVE_PRCI_H */ diff --git a/soc/riscv/sifive_freedom/e300/soc.h b/soc/riscv/sifive_freedom/e300/soc.h new file mode 100644 index 00000000000..3b4c4b54f8e --- /dev/null +++ b/soc/riscv/sifive_freedom/e300/soc.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the SiFive Freedom processor + */ + +#ifndef __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ + +/* + * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked + * by TLCLK, which is derived from CORECLK. + */ +#define SIFIVE_TLCLK_BASE_FREQUENCY \ + DT_PROP_BY_PHANDLE_IDX(DT_NODELABEL(tlclk), clocks, 0, clock_frequency) +#define SIFIVE_TLCLK_DIVIDER DT_PROP(DT_NODELABEL(tlclk), clock_div) +#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ + (SIFIVE_TLCLK_BASE_FREQUENCY / SIFIVE_TLCLK_DIVIDER) + +#endif /* __RISCV_SIFIVE_FREEDOM_FE300_SOC_H_ */ diff --git a/soc/riscv/sifive_freedom/u500/CMakeLists.txt b/soc/riscv/sifive_freedom/u500/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series new file mode 100644 index 00000000000..d306b60252a --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIFIVE_FREEDOM_U500 + +config SOC_SERIES + default "u500" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +source "soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_U500 diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 new file mode 100644 index 00000000000..f559f5914b3 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.defconfig.u540 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "u540" if SOC_SIFIVE_FREEDOM_U540 diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.series b/soc/riscv/sifive_freedom/u500/Kconfig.series new file mode 100644 index 00000000000..7335a1a5293 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_U500 + bool "SiFive Freedom U500 SOC implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom U500 SOC diff --git a/soc/riscv/sifive_freedom/u500/Kconfig.soc b/soc/riscv/sifive_freedom/u500/Kconfig.soc new file mode 100644 index 00000000000..0a88ccf8cc1 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/Kconfig.soc @@ -0,0 +1,22 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_U500 + +config SOC_SIFIVE_FREEDOM_U540 + bool "SiFive Freedom U540 SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select 64BIT + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/sifive_freedom/u500/clock.c b/soc/riscv/sifive_freedom/u500/clock.c new file mode 100644 index 00000000000..87929892f77 --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/clock.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Katsuhiro Suzuki + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "prci.h" + +BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), + "Unsupported CORECLK frequency"); +BUILD_ASSERT(DT_PROP(DT_NODELABEL(tlclk), clock_div) == 2, + "Unsupported TLCLK divider"); + +/* + * Switch the clock source to 1GHz PLL from 33.333MHz oscillator on the HiFive + * Unleashed board. + */ +static int fu540_clock_init(void) +{ + + PRCI_REG(PRCI_COREPLLCFG0) = + PLL_R(0) | /* input divider: Fin / (0 + 1) = 33.33MHz */ + PLL_F(59) | /* VCO: 2 x (59 + 1) = 120 = 3999.6MHz */ + PLL_Q(2) | /* output divider: VCO / 2^2 = 999.9MHz */ + PLL_RANGE(PLL_RANGE_33MHZ) | + PLL_BYPASS(PLL_BYPASS_DISABLE) | + PLL_FSE(PLL_FSE_INTERNAL); + while ((PRCI_REG(PRCI_COREPLLCFG0) & PLL_LOCK(1)) == 0) + ; + + /* Switch clock to COREPLL */ + PRCI_REG(PRCI_CORECLKSEL) = CORECLKSEL_CORECLKSEL(CORECLKSEL_CORE_PLL); + + return 0; +} + +SYS_INIT(fu540_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/sifive_freedom/u500/prci.h b/soc/riscv/sifive_freedom/u500/prci.h new file mode 100644 index 00000000000..4e80b7a131d --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/prci.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Katsuhiro Suzuki + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SIFIVE_FU540_PRCI_H +#define _SIFIVE_FU540_PRCI_H + +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000UL + +#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) +#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) + +/* Register offsets */ + +#define PRCI_HFXOSCCFG (0x0000) +#define PRCI_COREPLLCFG0 (0x0004) +#define PRCI_DDRPLLCFG0 (0x000c) +#define PRCI_DDRPLLCFG1 (0x0010) +#define PRCI_GEMGXLPLLCFG0 (0x001c) +#define PRCI_GEMGXLPLLCFG1 (0x0020) +#define PRCI_CORECLKSEL (0x0024) +#define PRCI_DEVICESRESETREG (0x0028) + +#define PLL_R(x) (((x) & 0x3f) << 0) +#define PLL_F(x) (((x) & 0x1ff) << 6) +#define PLL_Q(x) (((x) & 0x7) << 15) +#define PLL_RANGE(x) (((x) & 0x7) << 18) +#define PLL_BYPASS(x) (((x) & 0x1) << 24) +#define PLL_FSE(x) (((x) & 0x1) << 25) +#define PLL_LOCK(x) (((x) & 0x1) << 31) + +#define PLL_RANGE_33MHZ 4 +#define PLL_BYPASS_DISABLE 0 +#define PLL_BYPASS_ENABLE 1 +#define PLL_FSE_INTERNAL 1 + +#define CORECLKSEL_CORECLKSEL(x) (((x) & 0x1) << 0) + +#define CORECLKSEL_CORE_PLL 0 +#define CORECLKSEL_HFCLK 1 + +#endif /* _SIFIVE_FU540_PRCI_H */ diff --git a/soc/riscv/sifive_freedom/u500/soc.h b/soc/riscv/sifive_freedom/u500/soc.h new file mode 100644 index 00000000000..5ae3f5f00bd --- /dev/null +++ b/soc/riscv/sifive_freedom/u500/soc.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the SiFive Freedom processor + */ + +#ifndef __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ + +/* + * On FE310 and FU540, peripherals such as SPI, UART, I2C and PWM are clocked + * by TLCLK, which is derived from CORECLK. + */ +#define SIFIVE_TLCLK_BASE_FREQUENCY \ + DT_PROP_BY_PHANDLE_IDX(DT_NODELABEL(tlclk), clocks, 0, clock_frequency) +#define SIFIVE_TLCLK_DIVIDER DT_PROP(DT_NODELABEL(tlclk), clock_div) +#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ + (SIFIVE_TLCLK_BASE_FREQUENCY / SIFIVE_TLCLK_DIVIDER) + +#endif /* __RISCV_SIFIVE_FREEDOM_U500_SOC_H_ */ diff --git a/soc/riscv/sifive_freedom/u700/CMakeLists.txt b/soc/riscv/sifive_freedom/u700/CMakeLists.txt new file mode 100644 index 00000000000..baf01a6b047 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(clock.c) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "") diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series new file mode 100644 index 00000000000..a0e730d608f --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.series @@ -0,0 +1,32 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIFIVE_FREEDOM_U700 + +config SOC_SERIES + default "u700" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 64 + +source "soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u*" + +endif # SOC_SERIES_SIFIVE_FREEDOM_U700 diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 new file mode 100644 index 00000000000..ca935f772eb --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.defconfig.u740 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "u740" if SOC_SIFIVE_FREEDOM_U740 diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.series b/soc/riscv/sifive_freedom/u700/Kconfig.series new file mode 100644 index 00000000000..04bdc1fb9b2 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.series @@ -0,0 +1,13 @@ +# RISCV_SIFIVE_FREEDOM SOC implementation + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIFIVE_FREEDOM_U700 + bool "SiFive Freedom SOC U700 implementation" + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + select SOC_FAMILY_SIFIVE_FREEDOM + help + Enable support for SiFive Freedom U700 SOC diff --git a/soc/riscv/sifive_freedom/u700/Kconfig.soc b/soc/riscv/sifive_freedom/u700/Kconfig.soc new file mode 100644 index 00000000000..1eec9b4bb17 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/Kconfig.soc @@ -0,0 +1,22 @@ +# RISCV_SIFIVE_FREEDOM SOC configuration options + +# Copyright (c) 2017 Jean-Paul Etienne +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "SiFive Freedom SOC implementation" + depends on SOC_SERIES_SIFIVE_FREEDOM_U700 + +config SOC_SIFIVE_FREEDOM_U740 + bool "SiFive Freedom U740 SOC implementation" + select ATOMIC_OPERATIONS_C + select INCLUDE_RESET_VECTOR + select 64BIT + select RISCV_ISA_RV64I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + +endchoice diff --git a/soc/riscv/sifive_freedom/u700/clock.c b/soc/riscv/sifive_freedom/u700/clock.c new file mode 100644 index 00000000000..5c3fa567343 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/clock.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Katsuhiro Suzuki + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "prci.h" + +BUILD_ASSERT(MHZ(1000) == DT_PROP(DT_NODELABEL(coreclk), clock_frequency), + "Unsupported CORECLK frequency"); +BUILD_ASSERT(KHZ(125125) == DT_PROP(DT_NODELABEL(pclk), clock_frequency), + "Unsupported PCLK frequency"); + +static inline void wait_controller_cycle(void) +{ + /* HACK to get the '1 full controller clock cycle'. */ + __asm__ volatile ("fence"); +} + +/* + * Switch the clock source + * - core: to 1GHz PLL (CORE_PLL) from 26MHz oscillator (HFCLK) + * - peri: to 250MHz PLL (HFPCLKPLL) from HFCLK + * - ddr: to 923MHz PLL (DDRPLL) from HFCLK (half of the data rate) + * on the HiFive Unmatched board. + * + * Note: Valid PLL VCO range is 2400MHz to 4800MHz + */ +static int fu740_clock_init(void) +{ + + PRCI_REG(PRCI_COREPLLCFG) = + PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ + PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */ + PLL_Q(2) | /* output divider: VCO / 2^2 = 1001MHz */ + PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */ + PLL_BYPASS(PLL_BYPASS_DISABLE) | + PLL_FSE(PLL_FSE_INTERNAL); + while ((PRCI_REG(PRCI_COREPLLCFG) & PLL_LOCK(1)) == 0) + ; + + /* Switch CORE_CLK to CORE_PLL from HFCLK */ + PRCI_REG(PRCI_COREPLLSEL) = COREPLLSEL_SEL(COREPLLSEL_COREPLL); + PRCI_REG(PRCI_CORECLKSEL) = CLKSEL_SEL(CLKSEL_PLL); + + PRCI_REG(PRCI_HFPCLKPLLCFG) = + PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ + PLL_F(76) | /* VCO: 2 x (76 + 1) = 154 = 4004MHz */ + PLL_Q(4) | /* output divider: VCO / 2^4 = 250.25MHz */ + PLL_RANGE(PLL_RANGE_18MHZ) | /* 18MHz <= post divr(= 26MHz) < 30MHz */ + PLL_BYPASS(PLL_BYPASS_DISABLE) | + PLL_FSE(PLL_FSE_INTERNAL); + while ((PRCI_REG(PRCI_HFPCLKPLLCFG) & PLL_LOCK(1)) == 0) + ; + + /* Switch PCLK to HFPCLKPLL/2 from HFCLK/2 */ + PRCI_REG(PRCI_HFPCLKPLLOUTDIV) = OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA); + PRCI_REG(PRCI_HFPCLKPLLSEL) = CLKSEL_SEL(CLKSEL_PLL); + + PRCI_REG(PRCI_DDRPLLCFG) = + PLL_R(0) | /* input divider: Fin / (0 + 1) = 26MHz */ + PLL_F(70) | /* VCO: 2 x (70 + 1) = 154 = 1872MHz */ + PLL_Q(2) | /* output divider: VCO / 2^2 = 936MHz */ + PLL_RANGE(PLL_RANGE_18MHZ) | + PLL_BYPASS(PLL_BYPASS_DISABLE) | + PLL_FSE(PLL_FSE_INTERNAL); + while ((PRCI_REG(PRCI_DDRPLLCFG) & PLL_LOCK(1)) == 0) + ; + + PRCI_REG(PRCI_DDRPLLOUTDIV) |= OUTDIV_PLLCKE(OUTDIV_PLLCKE_ENA); + + PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRCTRL; + wait_controller_cycle(); + + /* Release DDR reset */ + PRCI_REG(PRCI_DEVICESRESETN) |= DEVICERESETN_DDRAXI | + DEVICERESETN_DDRAHB | + DEVICERESETN_DDRPHY; + wait_controller_cycle(); + + /* + * These take like 16 cycles to actually propagate. We can't go sending stuff before they + * come out of reset. So wait. + */ + for (int i = 0; i < 256; i++) { + __asm__ volatile ("nop"); + } + return 0; +} + +SYS_INIT(fu740_clock_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/riscv/sifive_freedom/u700/prci.h b/soc/riscv/sifive_freedom/u700/prci.h new file mode 100644 index 00000000000..ed78e924939 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/prci.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021 Katsuhiro Suzuki + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SIFIVE_FU740_PRCI_H +#define _SIFIVE_FU740_PRCI_H + +/* Clock controller. */ +#define PRCI_BASE_ADDR 0x10000000UL + +#define Z_REG32(p, i) (*(volatile uint32_t *) ((p) + (i))) +#define PRCI_REG(offset) Z_REG32(PRCI_BASE_ADDR, offset) + +/* Register offsets */ + +#define PRCI_HFXOSCCFG (0x0000) +#define PRCI_COREPLLCFG (0x0004) +#define PRCI_COREPLLOUTDIV (0x0008) +#define PRCI_DDRPLLCFG (0x000c) +#define PRCI_DDRPLLOUTDIV (0x0010) +#define PRCI_GEMGXLPLLCFG (0x001c) +#define PRCI_GEMGXLPLLOUTDIV (0x0020) +#define PRCI_CORECLKSEL (0x0024) +#define PRCI_DEVICESRESETN (0x0028) +#define PRCI_CLKMUXSTATUS (0x002c) +#define PRCI_COREPLLSEL (0x0040) +#define PRCI_HFPCLKPLLCFG (0x0050) +#define PRCI_HFPCLKPLLOUTDIV (0x0054) +#define PRCI_HFPCLKPLLSEL (0x0058) + +#define PLL_R(x) (((x) & 0x3f) << 0) +#define PLL_F(x) (((x) & 0x1ff) << 6) +#define PLL_Q(x) (((x) & 0x7) << 15) +#define PLL_RANGE(x) (((x) & 0x7) << 18) +#define PLL_BYPASS(x) (((x) & 0x1) << 24) +#define PLL_FSE(x) (((x) & 0x1) << 25) +#define PLL_LOCK(x) (((x) & 0x1) << 31) + +#define PLL_RANGE_RESET 0 +#define PLL_RANGE_0MHZ 1 +#define PLL_RANGE_11MHZ 2 +#define PLL_RANGE_18MHZ 3 +#define PLL_RANGE_30MHZ 4 +#define PLL_RANGE_50MHZ 5 +#define PLL_RANGE_80MHZ 6 +#define PLL_RANGE_130MHZ 7 +#define PLL_BYPASS_DISABLE 0 +#define PLL_BYPASS_ENABLE 1 +#define PLL_FSE_INTERNAL 1 + +#define OUTDIV_PLLCKE(x) (((x) & 0x1) << 31) + +#define OUTDIV_PLLCKE_DIS 0 +#define OUTDIV_PLLCKE_ENA 1 + +#define CLKSEL_SEL(x) (((x) & 0x1) << 0) + +#define CLKSEL_PLL 0 +#define CLKSEL_HFCLK 1 + +#define CLKMUXSTATUS_CORECLKPLLSEL_OFF 0 +#define CLKMUXSTATUS_TLCLKSEL_OFF 1 +#define CLKMUXSTATUS_RTCXSEL_OFF 2 +#define CLKMUXSTATUS_DDRCTRLCLKSEL_OFF 3 +#define CLKMUXSTATUS_DDRPHYCLKSEL_OFF 4 +#define CLKMUXSTATUS_GEMGXLCLKSEL_OFF 6 +#define CLKMUXSTATUS_MAINMEMCLKSEL_OFF 7 + +#define COREPLLSEL_SEL(x) (((x) & 0x1) << 0) + +#define COREPLLSEL_COREPLL 0 +#define COREPLLSEL_DVFSCOREPLL 1 + +#define DEVICERESETN_DDRCTRL BIT(0) +#define DEVICERESETN_DDRAXI BIT(1) +#define DEVICERESETN_DDRAHB BIT(2) +#define DEVICERESETN_DDRPHY BIT(3) +#define DEVICERESETN_PCIEAUX BIT(4) +#define DEVICERESETN_GEMGXL BIT(5) + +#endif /* _SIFIVE_FU740_PRCI_H */ diff --git a/soc/riscv/sifive_freedom/u700/soc.h b/soc/riscv/sifive_freedom/u700/soc.h new file mode 100644 index 00000000000..dcd37dfdc44 --- /dev/null +++ b/soc/riscv/sifive_freedom/u700/soc.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file SoC configuration macros for the SiFive Freedom processor + */ + +#ifndef __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ +#define __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ + +/* On FU740, peripherals are clocked by PCLK. */ +#define SIFIVE_PERIPHERAL_CLOCK_FREQUENCY \ + DT_PROP(DT_NODELABEL(pclk), clock_frequency) + +#endif /* __RISCV_SIFIVE_FREEDOM_U700_SOC_H_ */ diff --git a/soc/riscv/starfive_jh71xx/CMakeLists.txt b/soc/riscv/starfive_jh71xx/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/starfive_jh71xx/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/starfive_jh71xx/Kconfig b/soc/riscv/starfive_jh71xx/Kconfig new file mode 100644 index 00000000000..65694c07eff --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_STARFIVE_JH71XX + bool + +if SOC_FAMILY_STARFIVE_JH71XX + +config SOC_FAMILY + string + default "starfive_jh71xx" + +source "soc/riscv/starfive_jh71xx/*/Kconfig.soc" + +endif # SOC_FAMILY_STARFIVE_JH71XX diff --git a/soc/riscv/starfive_jh71xx/Kconfig.defconfig b/soc/riscv/starfive_jh71xx/Kconfig.defconfig new file mode 100644 index 00000000000..b399e38b340 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/starfive_jh71xx/*/Kconfig.defconfig.series" diff --git a/soc/riscv/starfive_jh71xx/Kconfig.soc b/soc/riscv/starfive_jh71xx/Kconfig.soc new file mode 100644 index 00000000000..1ff54faa970 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/starfive_jh71xx/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt b/soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/CMakeLists.txt rename to soc/riscv/starfive_jh71xx/jh71xx/CMakeLists.txt diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 new file mode 100644 index 00000000000..6f38d61dd4e --- /dev/null +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh7100 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "jh7100" if SOC_JH7100 diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series new file mode 100644 index 00000000000..0f058cb6c25 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.series @@ -0,0 +1,29 @@ +# Copyright (c) 2021 Rajnesh Kanwal +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_STARFIVE_JH71XX + +config SOC_SERIES + default "jh71xx" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 6250000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config NUM_IRQS + default 139 + +source "soc/riscv/starfive_jh71xx/jh71xx/Kconfig.defconfig.jh71*" + +endif diff --git a/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series new file mode 100644 index 00000000000..f392a5d1f97 --- /dev/null +++ b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.series @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Rajnesh Kanwal +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_STARFIVE_JH71XX + bool "Starfive JH71XX series" + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + help + Enable support for Starfive JH71XX SoC Series. diff --git a/soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc b/soc/riscv/starfive_jh71xx/jh71xx/Kconfig.soc similarity index 100% rename from soc/riscv/riscv-privileged/starfive_jh71xx/Kconfig.soc rename to soc/riscv/starfive_jh71xx/jh71xx/Kconfig.soc diff --git a/soc/riscv/telink_tlsr/CMakeLists.txt b/soc/riscv/telink_tlsr/CMakeLists.txt new file mode 100644 index 00000000000..69b2926358e --- /dev/null +++ b/soc/riscv/telink_tlsr/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(${SOC_SERIES}) diff --git a/soc/riscv/telink_tlsr/Kconfig b/soc/riscv/telink_tlsr/Kconfig new file mode 100644 index 00000000000..144751311ba --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_TELINK_TLSR + bool + +if SOC_FAMILY_TELINK_TLSR + +config SOC_FAMILY + string + default "telink_tlsr" + +source "soc/riscv/telink_tlsr/*/Kconfig.soc" + +endif # SOC_FAMILY_TELINK_TLSR diff --git a/soc/riscv/telink_tlsr/Kconfig.defconfig b/soc/riscv/telink_tlsr/Kconfig.defconfig new file mode 100644 index 00000000000..04a888381fa --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig.defconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/telink_tlsr/*/Kconfig.defconfig.series" diff --git a/soc/riscv/telink_tlsr/Kconfig.soc b/soc/riscv/telink_tlsr/Kconfig.soc new file mode 100644 index 00000000000..db09c69d1f4 --- /dev/null +++ b/soc/riscv/telink_tlsr/Kconfig.soc @@ -0,0 +1,4 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "soc/riscv/telink_tlsr/*/Kconfig.series" diff --git a/soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt b/soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/CMakeLists.txt rename to soc/riscv/telink_tlsr/tlsr951x/CMakeLists.txt diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series new file mode 100644 index 00000000000..2b72ad9960c --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.series @@ -0,0 +1,53 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_TELINK_TLSR951X + +config SOC_SERIES + string + default "tlsr951x" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 32000 + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +config RISCV_GP + bool + default y + +config NUM_IRQS + int + default 64 + +config PINCTRL + default y + +config XIP + bool + default n + +config MAIN_STACK_SIZE + int + default 2048 + +config IDLE_STACK_SIZE + int + default 1536 + +config TEST_EXTRA_STACK_SIZE + int + default 1024 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config HAS_FLASH_LOAD_OFFSET + default y if BOOTLOADER_MCUBOOT + +source "soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr*" + +endif # SOC_SERIES_TELINK_TLSR951X diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 new file mode 100644 index 00000000000..4ffdebdaf6b --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.defconfig.tlsr9518 @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC + default "tlsr9518" if SOC_TELINK_TLSR9518 diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series new file mode 100644 index 00000000000..5d5fc3226e5 --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.series @@ -0,0 +1,21 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_TELINK_TLSR951X + bool "Telink TLSR951X" + select RISCV + select RISCV_ISA_RV32I + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV_ISA_EXT_ZICSR + select RISCV_ISA_EXT_ZIFENCEI + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC + select HAS_TELINK_DRIVERS + select ATOMIC_OPERATIONS_BUILTIN + select CPU_HAS_FPU + select INCLUDE_RESET_VECTOR + select SOC_FAMILY_TELINK_TLSR + help + Enable support for Telink TLSR951X diff --git a/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc new file mode 100644 index 00000000000..2abc12cc58c --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/Kconfig.soc @@ -0,0 +1,23 @@ +# Copyright (c) 2021 Telink Semiconductor +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_TELINK_TLSR951X + +choice + prompt "Telink TLSR951X SoC implementation" + +config SOC_TELINK_TLSR9518 + bool "Telink TLSR9518" + +endchoice + +config TELINK_B91_HWDSP + bool "Support Hardware DSP" + select RISCV_SOC_CONTEXT_SAVE + +config TELINK_B91_PFT_ARCH + bool "Support performance throttling" + default y + select RISCV_SOC_CONTEXT_SAVE + +endif # SOC_SERIES_TELINK_TLSR951X diff --git a/soc/riscv/riscv-privileged/telink_b91/init.ld b/soc/riscv/telink_tlsr/tlsr951x/init.ld similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/init.ld rename to soc/riscv/telink_tlsr/tlsr951x/init.ld diff --git a/soc/riscv/riscv-privileged/telink_b91/linker.ld b/soc/riscv/telink_tlsr/tlsr951x/linker.ld similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/linker.ld rename to soc/riscv/telink_tlsr/tlsr951x/linker.ld diff --git a/soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h b/soc/riscv/telink_tlsr/tlsr951x/pinctrl_soc.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/pinctrl_soc.h rename to soc/riscv/telink_tlsr/tlsr951x/pinctrl_soc.h diff --git a/soc/riscv/riscv-privileged/telink_b91/soc.c b/soc/riscv/telink_tlsr/tlsr951x/soc.c similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc.c rename to soc/riscv/telink_tlsr/tlsr951x/soc.c diff --git a/soc/riscv/telink_tlsr/tlsr951x/soc.h b/soc/riscv/telink_tlsr/tlsr951x/soc.h new file mode 100644 index 00000000000..6acfd63dd02 --- /dev/null +++ b/soc/riscv/telink_tlsr/tlsr951x/soc.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2021 Telink Semiconductor + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RISCV_TELINK_B91_SOC_H +#define RISCV_TELINK_B91_SOC_H + +#endif /* RISCV_TELINK_B91_SOC_H */ diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_context.h b/soc/riscv/telink_tlsr/tlsr951x/soc_context.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_context.h rename to soc/riscv/telink_tlsr/tlsr951x/soc_context.h diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_irq.S b/soc/riscv/telink_tlsr/tlsr951x/soc_irq.S similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_irq.S rename to soc/riscv/telink_tlsr/tlsr951x/soc_irq.S diff --git a/soc/riscv/riscv-privileged/telink_b91/soc_offsets.h b/soc/riscv/telink_tlsr/tlsr951x/soc_offsets.h similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/soc_offsets.h rename to soc/riscv/telink_tlsr/tlsr951x/soc_offsets.h diff --git a/soc/riscv/riscv-privileged/telink_b91/start.S b/soc/riscv/telink_tlsr/tlsr951x/start.S similarity index 100% rename from soc/riscv/riscv-privileged/telink_b91/start.S rename to soc/riscv/telink_tlsr/tlsr951x/start.S diff --git a/soc/riscv/riscv-privileged/virt/CMakeLists.txt b/soc/riscv/virt/CMakeLists.txt similarity index 100% rename from soc/riscv/riscv-privileged/virt/CMakeLists.txt rename to soc/riscv/virt/CMakeLists.txt diff --git a/soc/riscv/virt/Kconfig.defconfig b/soc/riscv/virt/Kconfig.defconfig new file mode 100644 index 00000000000..bed5ff8bec7 --- /dev/null +++ b/soc/riscv/virt/Kconfig.defconfig @@ -0,0 +1,33 @@ +# Copyright (c) 2020 Cobham Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RISCV_VIRT + +config SOC + default "virt" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 10000000 + +config RISCV_SOC_INTERRUPT_INIT + default y + +config RISCV_GP + default y + +config 2ND_LVL_ISR_TBL_OFFSET + default 12 + +config 2ND_LVL_INTR_00_OFFSET + default 11 + +config MAX_IRQ_PER_AGGREGATOR + default 52 + +config NUM_IRQS + default 1035 + +config PMP_SLOTS + default 16 + +endif diff --git a/soc/riscv/virt/Kconfig.soc b/soc/riscv/virt/Kconfig.soc new file mode 100644 index 00000000000..59e553a9d7b --- /dev/null +++ b/soc/riscv/virt/Kconfig.soc @@ -0,0 +1,13 @@ +# Copyright (c) 2020 Cobham Gaisler AB +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RISCV_VIRT + bool "QEMU RISC-V VirtIO Board" + select ATOMIC_OPERATIONS_BUILTIN + select INCLUDE_RESET_VECTOR + select RISCV_ISA_EXT_M + select RISCV_ISA_EXT_A + select RISCV_ISA_EXT_C + select RISCV + select RISCV_PRIVILEGED + select RISCV_HAS_PLIC diff --git a/soc/riscv/virt/soc.c b/soc/riscv/virt/soc.c new file mode 100644 index 00000000000..0bdcf6e80f2 --- /dev/null +++ b/soc/riscv/virt/soc.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Katsuhiro Suzuki + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief QEMU RISC-V virt machine hardware depended interface + */ + +#include +#include +#include + +#define SIFIVE_SYSCON_TEST 0x00100000 + +/* + * Exit QEMU and tell error number. + * Higher 16bits: indicates error number. + * Lower 16bits : set FINISHER_FAIL + */ +#define FINISHER_FAIL 0x3333 + +/* Exit QEMU successfully */ +#define FINISHER_EXIT 0x5555 + +/* Reboot machine */ +#define FINISHER_REBOOT 0x7777 + +void sys_arch_reboot(int type) +{ + volatile uint32_t *reg = (uint32_t *)SIFIVE_SYSCON_TEST; + + *reg = FINISHER_REBOOT; + + ARG_UNUSED(type); +} diff --git a/soc/sparc/gr716a/Kconfig.defconfig b/soc/sparc/gr716a/Kconfig.defconfig index 6feb4ff3d6a..ef9bf0ca778 100644 --- a/soc/sparc/gr716a/Kconfig.defconfig +++ b/soc/sparc/gr716a/Kconfig.defconfig @@ -13,4 +13,17 @@ config SYS_CLOCK_HW_CYCLES_PER_SEC int default 50000000 +if FLASH + +config SPI + default y + +config SPI_NOR + default y + +config SPI_GRLIB_SPIMCTRL + default y + +endif + endif diff --git a/soc/x86/raptor_lake/soc_gpio.h b/soc/x86/raptor_lake/soc_gpio.h index 544df564a08..6901cab9221 100644 --- a/soc/x86/raptor_lake/soc_gpio.h +++ b/soc/x86/raptor_lake/soc_gpio.h @@ -15,14 +15,22 @@ #ifndef __SOC_GPIO_H_ #define __SOC_GPIO_H_ +#if defined(CONFIG_BOARD_INTEL_RPL_S_CRB) #define GPIO_INTEL_NR_SUBDEVS 13 - #define REG_PAD_OWNER_BASE 0x00A0 #define REG_GPI_INT_STS_BASE 0x0200 -#define PAD_CFG0_PMODE_MASK (0x07 << 10) - #define REG_GPI_INT_EN_BASE 0x0220 #define REG_PAD_HOST_SW_OWNER 0x150 + +#elif defined(CONFIG_BOARD_INTEL_RPL_P_CRB) +#define GPIO_INTEL_NR_SUBDEVS 11 +#define REG_PAD_OWNER_BASE 0x0020 +#define REG_GPI_INT_STS_BASE 0x0100 +#define REG_GPI_INT_EN_BASE 0x0120 +#define REG_PAD_HOST_SW_OWNER 0x0B0 +#endif + +#define PAD_CFG0_PMODE_MASK (0x07 << 10) #define PAD_BASE_ADDR_MASK 0xfff #define GPIO_REG_BASE(reg_base) \ diff --git a/soc/xtensa/dc233c/Kconfig.soc b/soc/xtensa/dc233c/Kconfig.soc index 89b814da4d2..ecbe77a9feb 100644 --- a/soc/xtensa/dc233c/Kconfig.soc +++ b/soc/xtensa/dc233c/Kconfig.soc @@ -7,5 +7,9 @@ config SOC_XTENSA_DC233C select XTENSA select XTENSA_HAL select ARCH_HAS_THREAD_LOCAL_STORAGE + select CPU_HAS_DCACHE + select CPU_HAS_ICACHE select CPU_HAS_MMU select ARCH_HAS_RESERVED_PAGE_FRAMES if XTENSA_MMU + select ARCH_HAS_USERSPACE if XTENSA_MMU + select XTENSA_INVALIDATE_MEM_DOMAIN_TLB_ON_SWAP if XTENSA_MMU diff --git a/soc/xtensa/dc233c/include/xtensa-dc233c.ld b/soc/xtensa/dc233c/include/xtensa-dc233c.ld index b165016fa6a..b77effc032b 100644 --- a/soc/xtensa/dc233c/include/xtensa-dc233c.ld +++ b/soc/xtensa/dc233c/include/xtensa-dc233c.ld @@ -20,7 +20,7 @@ #include #define RAMABLE_REGION RAM :sram0_phdr -#define ROMABLE_REGION rom0_seg :rom0_phdr +#define ROMABLE_REGION RAM :sram0_phdr #ifdef CONFIG_MMU #define MMU_PAGE_ALIGN . = ALIGN(CONFIG_MMU_PAGE_SIZE); @@ -287,6 +287,9 @@ SECTIONS _DoubleExceptionVector_text_end = ABSOLUTE(.); } >sram0_18_seg :sram0_18_phdr +#define LIB_OBJ_FUNC_IN_SECT(library, obj_file, func) \ + *##library##:##obj_file##(.literal.##func .text.##func) \ + #ifdef CONFIG_XTENSA_MMU .vec_helpers : { @@ -301,48 +304,45 @@ SECTIONS * TLB multi-hit exception. */ - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.literal) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2-util.S.obj(.iram0.text) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.literal .text) + *libarch__xtensa__core.a:xtensa_asm2_util.S.obj(.iram.text .iram0.text) *libarch__xtensa__core.a:window_vectors.S.obj(.iram.text) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa-asm2.c.obj(.text.*) - - *libarch__xtensa__core.a:fatal.c.obj(.literal.*) - *libarch__xtensa__core.a:fatal.c.obj(.text.*) - - *libarch__xtensa__core.a:crt1.S.obj(.literal) - *libarch__xtensa__core.a:crt1.S.obj(.text) + *libarch__xtensa__core.a:crt1.S.obj(.literal .text) - *libarch__xtensa__core.a:cpu_idle.c.obj(.literal.*) - *libarch__xtensa__core.a:cpu_idle.c.obj(.text.*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_asm2.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,fatal.c.obj,*) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,cpu_idle.c.obj,*) *(.text.arch_is_in_isr) /* To support backtracing */ - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.literal.*) - *libarch__xtensa__core.a:xtensa_backtrace.c.obj(.text.*) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal) - *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,xtensa_backtrace.c.obj,*) - *libkernel.a:fatal.c.obj(.literal.*) - *libkernel.a:fatal.c.obj(.text.*) + *libarch__xtensa__core.a:debug_helpers_asm.S.obj(.iram1.literal .iram1) + + /* Userspace related stuff */ + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,xtensa_do_syscall) + LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,xtensa_swap_update_page_tables) /* Below are to speed up execution by avoiding TLB misses * on frequently used functions. + * + * There is almost 1MB space (due to TLB pinning) so we can + * be generous. */ - *libkernel.a:sched.c.obj(.literal.*) - *libkernel.a:sched.c.obj(.text.*) - *libkernel.a:timeout.c.obj(.literal.*) - *libkernel.a:timeout.c.obj(.text.*) - - *libdrivers__console.a:(.literal.*) - *libdrivers__console.a:(.text.*) - *libdrivers__timer.a:(.literal.*) - *libdrivers__timer.a:(.text.*) + LIB_OBJ_FUNC_IN_SECT(libkernel.a,,*) + + LIB_OBJ_FUNC_IN_SECT(libdrivers__console.a,,*) + LIB_OBJ_FUNC_IN_SECT(libdrivers__timer.a,,*) + + *(.literal.z_vrfy_* .text.z_vrfy_*) + *(.literal.z_mrsh_* .text.z_mrsh_*) + *(.literal.z_impl_* .text.z_impl_*) + *(.literal.z_obj_* .text.z_obj_*) + + *(.literal.k_sys_fatal_error_handler .text.k_sys_fatal_error_handler) } >vec_helpers :vec_helpers_phdr #endif /* CONFIG_XTENSA_MMU */ @@ -380,7 +380,7 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; - } >RAM :sram0_phdr + } >RAMABLE_REGION __text_region_end = .; .rodata : HDR_MMU_PAGE_ALIGN @@ -394,7 +394,16 @@ SECTIONS . = ALIGN(4); #include #include + } >RAMABLE_REGION + +#include + +#include +#include + + .rodata_end : ALIGN(4) + { . = ALIGN(4); /* this table MUST be 4-byte aligned */ _bss_table_start = ABSOLUTE(.); LONG(_bss_start) @@ -404,19 +413,26 @@ SECTIONS MMU_PAGE_ALIGN __rodata_region_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION -#include +#ifdef CONFIG_USERSPACE +#define SMEM_PARTITION_ALIGN(size) MMU_PAGE_ALIGN +#define APP_SHARED_ALIGN MMU_PAGE_ALIGN -#include +#include -#include - -#include + _image_ram_start = _app_smem_start; + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_num_words = _app_smem_size >> 2; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); + _app_smem_num_words = _app_smem_size >> 2; +#endif /* CONFIG_USERSPACE */ .data : HDR_MMU_PAGE_ALIGN { +#ifndef CONFIG_USERSPACE _image_ram_start = ABSOLUTE(.); +#endif __data_start = ABSOLUTE(.); *(.data) *(.data.*) @@ -438,7 +454,9 @@ SECTIONS MMU_PAGE_ALIGN __data_end = ABSOLUTE(.); - } >RAM :sram0_phdr + } >RAMABLE_REGION + +#include #include diff --git a/soc/xtensa/dc233c/mmu.c b/soc/xtensa/dc233c/mmu.c index 4b8d6b154b8..ed6818b3efb 100644 --- a/soc/xtensa/dc233c/mmu.c +++ b/soc/xtensa/dc233c/mmu.c @@ -12,13 +12,11 @@ #include #include -#include "../../arch/xtensa/core/include/xtensa_mmu_priv.h" - const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { { .start = (uint32_t)XCHAL_VECBASE_RESET_VADDR, .end = (uint32_t)CONFIG_SRAM_OFFSET, - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB | XTENSA_MMU_MAP_SHARED, .name = "vecbase", }, { @@ -29,38 +27,9 @@ const struct xtensa_mmu_range xtensa_soc_mmu_ranges[] = { .start = (uint32_t)DT_REG_ADDR(DT_NODELABEL(rom0)), .end = (uint32_t)DT_REG_ADDR(DT_NODELABEL(rom0)) + (uint32_t)DT_REG_SIZE(DT_NODELABEL(rom0)), - .attrs = Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WB, + .attrs = XTENSA_MMU_PERM_X | XTENSA_MMU_CACHED_WB, .name = "rom", }, }; int xtensa_soc_mmu_ranges_num = ARRAY_SIZE(xtensa_soc_mmu_ranges); - -void arch_xtensa_mmu_post_init(bool is_core0) -{ - uint32_t vecbase; - - ARG_UNUSED(is_core0); - - __asm__ volatile("rsr.vecbase %0" : "=r"(vecbase)); - - /* Invalidate any autorefill instr TLBs of VECBASE so we can map it - * permanently below. - */ - xtensa_itlb_vaddr_invalidate((void *)vecbase); - - /* Map VECBASE permanently in instr TLB way 4 so we will always have - * access to exception handlers. Each way 4 TLB covers 1MB (unless - * ITLBCFG has been changed before this, which should not have - * happened). - * - * Note that we don't want to map the first 1MB in data TLB as - * we want to keep page 0 (0x00000000) unmapped to catch null pointer - * de-references. - */ - vecbase = ROUND_DOWN(vecbase, MB(1)); - xtensa_itlb_entry_write_sync( - Z_XTENSA_PTE(vecbase, Z_XTENSA_KERNEL_RING, - Z_XTENSA_MMU_X | Z_XTENSA_MMU_CACHED_WT), - Z_XTENSA_TLB_ENTRY((uint32_t)vecbase, 4)); -} diff --git a/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt index f850e56a9b1..c71c016a706 100644 --- a/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt +++ b/soc/xtensa/espressif_esp32/esp32/CMakeLists.txt @@ -1,10 +1,14 @@ # SPDX-License-Identifier: Apache-2.0 -zephyr_sources( - soc.c - esp32-mp.c - loader.c - ) +if (CONFIG_SOC_ESP32_APPCPU) + zephyr_sources(soc_appcpu.c) +else() + zephyr_sources( + soc.c + loader.c + esp32-mp.c + ) +endif() zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) @@ -13,14 +17,6 @@ zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) zephyr_library_sources_ifdef(CONFIG_PM power.c) zephyr_library_sources_ifdef(CONFIG_POWEROFF poweroff.c) -# get code-partition slot0 address -dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") -dt_reg_addr(img_0_off PATH ${dts_partition_path}) - -# get code-partition boot address -dt_nodelabel(dts_partition_path NODELABEL "boot_partition") -dt_reg_addr(boot_off PATH ${dts_partition_path}) - # get flash size to use in esptool as string math(EXPR esptoolpy_flashsize "${CONFIG_FLASH_SIZE} / 0x100000") @@ -92,12 +88,36 @@ if(CONFIG_MCUBOOT OR CONFIG_BOOTLOADER_ESP_IDF) endif() -board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") +## When building for APPCPU +if (CONFIG_SOC_ESP32_APPCPU) -board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") + if(CONFIG_BUILD_OUTPUT_BIN) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/esp_bin2c_array.py + ARGS -i ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin + -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.c + -a "esp32_appcpu_fw_array") + endif() + +else() + set_property(TARGET bintools PROPERTY disassembly_flag_inline_source) + + # get code-partition slot0 address + dt_nodelabel(dts_partition_path NODELABEL "slot0_partition") + dt_reg_addr(img_0_off PATH ${dts_partition_path}) + + # get code-partition boot address + dt_nodelabel(dts_partition_path NODELABEL "boot_partition") + dt_reg_addr(boot_off PATH ${dts_partition_path}) + + board_finalize_runner_args(esp32 "--esp-boot-address=${boot_off}") + board_finalize_runner_args(esp32 "--esp-app-address=${img_0_off}") +endif() if(CONFIG_MCUBOOT) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.ld CACHE INTERNAL "") +elseif(CONFIG_SOC_ESP32_APPCPU) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default_appcpu.ld CACHE INTERNAL "") else() set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/default.ld CACHE INTERNAL "") endif() diff --git a/soc/xtensa/espressif_esp32/esp32/Kconfig.series b/soc/xtensa/espressif_esp32/esp32/Kconfig.series index 2189f7b2dd9..858386e4fd0 100644 --- a/soc/xtensa/espressif_esp32/esp32/Kconfig.series +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.series @@ -17,3 +17,17 @@ config SOC_SERIES_ESP32 select HAS_POWEROFF help Enable support for Espressif ESP32 + +config SOC_ESP32_PROCPU + bool "Application runs in ESP32 PROCPU (core 0)" + depends on SOC_SERIES_ESP32 + help + When this SOC is enabled, it will run application on PROCPU (core 0). It will automatically + enable AMP support by building, flashing and loading APPCPU (core 1) image if exists. + +config SOC_ESP32_APPCPU + bool "Application runs in ESP32 APPCPU (core 1)" + depends on SOC_SERIES_ESP32 + help + When this SOC is enabled, it will run application on APPCPU (core 1). It is expected that + there is another image running on PROCPU (core 0) to trigger the AMP support. diff --git a/soc/xtensa/espressif_esp32/esp32/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc index 7371c49ed94..6b530767703 100644 --- a/soc/xtensa/espressif_esp32/esp32/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32/Kconfig.soc @@ -13,7 +13,6 @@ config SOC_TOOLCHAIN_NAME choice SOC_PART_NUMBER prompt "ESP32 SOC/SIP Selection" - depends on SOC_SERIES_ESP32 # SoC with/without embedded flash config SOC_ESP32_D0WD_V3 @@ -56,15 +55,26 @@ choice SOC_PART_NUMBER endchoice # SOC_PART_NUMBER +config ESP32_APPCPU_IRAM + hex "ESP32 APPCPU IRAM size" + depends on SOC_ESP32_PROCPU || SOC_ESP32_APPCPU + default 0x20000 + help + Defines APPCPU IRAM area in bytes. + +config ESP32_APPCPU_DRAM + hex "ESP32 APPCPU DRAM size" + depends on SOC_ESP32_PROCPU || SOC_ESP32_APPCPU + default 0x10000 + help + Defines APPCPU DRAM area in bytes. + config ESP_SYSTEM_RTC_EXT_XTAL bool config ESP_SYSTEM_RTC_EXT_OSC bool -config ESP32_NETWORK_CORE - bool "Uses the ESP32 APP_CPU as Network dedicated core" - config ESP32_BT_RESERVE_DRAM hex "Bluetooth controller reserved RAM region" default 0xdb5c if BT @@ -73,7 +83,7 @@ config ESP32_BT_RESERVE_DRAM config ESP_HEAP_MEM_POOL_REGION_1_SIZE int "Internal DRAM region 1 mempool size" default 0 if MCUBOOT - default 1024 if ESP32_NETWORK_CORE + default 1024 if SOC_ESP32_PROCPU default 49152 help ESP32 has two banks of size 192K and 128K which can be used diff --git a/soc/xtensa/espressif_esp32/esp32/default.ld b/soc/xtensa/espressif_esp32/esp32/default.ld index 20dc3c28ef5..d0eb9b46f4a 100644 --- a/soc/xtensa/espressif_esp32/esp32/default.ld +++ b/soc/xtensa/espressif_esp32/esp32/default.ld @@ -18,7 +18,7 @@ #include #define RAMABLE_REGION dram0_0_seg -#ifndef CONFIG_ESP32_NETWORK_CORE +#ifndef CONFIG_SOC_ESP32_PROCPU #define RAMABLE_REGION_1 dram0_1_seg #else #define RAMABLE_REGION_1 dram0_0_seg @@ -57,7 +57,7 @@ MEMORY metadata (RX): org = 0x20, len = 0x20 ROM (RX): org = 0x40, len = FLASH_SIZE - 0x40 - #ifdef CONFIG_ESP32_NETWORK_CORE + #ifdef CONFIG_SOC_ESP32_PROCPU iram0_0_seg(RX): org = 0x40080000, len = 0x08000 #else iram0_0_seg(RX): org = 0x40080000, len = IRAM_SEG_LEN @@ -78,7 +78,7 @@ MEMORY */ dram0_0_seg(RW): org = 0x3FFB0000 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x2c200 - CONFIG_ESP32_BT_RESERVE_DRAM - #ifdef CONFIG_ESP32_NETWORK_CORE + #ifdef CONFIG_SOC_ESP32_PROCPU dram0_shm0_seg(RW): org = 0x3FFE5230, len = 2K /* shared RAM reserved for IPM */ dram0_sem0_seg(RW): org = 0x3FFE5A30, len = 8 /* shared data reserved for IPM data header */ dram0_1_seg(RW): org = 0x3FFE5A38, len = 0K /* for AMP builds dram0_1 is reserved for network core */ @@ -203,14 +203,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -221,6 +215,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. diff --git a/soc/xtensa/espressif_esp32/esp32/default_appcpu.ld b/soc/xtensa/espressif_esp32/esp32/default_appcpu.ld new file mode 100644 index 00000000000..a28399f57c4 --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32/default_appcpu.ld @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2016 Cadence Design Systems, Inc. + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the Xtensa platform. + */ + +#include +#include +#include +#include + +#define RAMABLE_REGION dram0_1_seg +#define RAMABLE_REGION_1 dram0_1_seg +#define RODATA_REGION dram0_1_seg +#define IRAM_REGION iram0_0_seg +#define FLASH_CODE_REGION iram0_0_seg +#define ROMABLE_REGION iram0_0_seg +#define ROMABLE_DATA_REGION dram0_1_seg +#define dram0_0_seg dram0_1_seg + +/* Flash segments (rodata and text) should be mapped in virtual address space by providing VMA. + * Executing directly from LMA is not possible. */ +#undef GROUP_ROM_LINK_IN +#define GROUP_ROM_LINK_IN(vregion, lregion) > RODATA_REGION AT > lregion + +MEMORY +{ + iram0_0_seg(RX): org = 0x40080000 + 0x08000, len = 0x18000 + dram0_shm0_seg(RW): org = 0x3FFE5230, len = 16K /* shared RAM reserved for IPM */ + dram0_sem0_seg(RW): org = 0x3FFED238, len = 8 /*shared data reserved for IPM data header */ + dram0_1_seg(RW): org = 0x3FFE9238 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x17CB0 - 0xEE0 - CONFIG_ESP32_BT_RESERVE_DRAM +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000 +#endif +} + +/* Default entry point: */ +PROVIDE ( _ResetVector = 0x40000400 ); +ENTRY(__app_cpu_start) + +_rom_store_table = 0; + +PROVIDE(_memmap_vecbase_reset = 0x40000450); +PROVIDE(_memmap_reset_vector = 0x40000400); + +SECTIONS +{ +#include + + _image_iram_start = LOADADDR(.iram0.vectors); + _image_iram_size = LOADADDR(_TEXT_SECTION_NAME) + SIZEOF(_TEXT_SECTION_NAME) - _image_iram_start; + _image_iram_vaddr = ADDR(.iram0.vectors); + + /* Send .iram0 code to iram */ + .iram0.vectors : ALIGN(4) + { + /* Vectors go to IRAM */ + _init_start = ABSOLUTE(.); + /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ + . = 0x0; + KEEP(*(.WindowVectors.text)); + . = 0x180; + KEEP(*(.Level2InterruptVector.text)); + . = 0x1c0; + KEEP(*(.Level3InterruptVector.text)); + . = 0x200; + KEEP(*(.Level4InterruptVector.text)); + . = 0x240; + KEEP(*(.Level5InterruptVector.text)); + . = 0x280; + KEEP(*(.DebugExceptionVector.text)); + . = 0x2c0; + KEEP(*(.NMIExceptionVector.text)); + . = 0x300; + KEEP(*(.KernelExceptionVector.text)); + . = 0x340; + KEEP(*(.UserExceptionVector.text)); + . = 0x3C0; + KEEP(*(.DoubleExceptionVector.text)); + . = 0x400; + *(.*Vector.literal) + + *(.UserEnter.literal); + *(.UserEnter.text); + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + _init_end = ABSOLUTE(.); + + /* This goes here, not at top of linker script, so addr2line finds it last, + and uses it in preference to the first symbol in IRAM */ + _iram_start = ABSOLUTE(0); + } GROUP_DATA_LINK_IN(IRAM_REGION, ROMABLE_REGION) + + SECTION_PROLOGUE(_TEXT_SECTION_NAME, , ALIGN(4)) + { + /* Code marked as running out of IRAM */ + _iram_text_start = ABSOLUTE(.); + *(.iram1 .iram1.*) + *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + *libesp32.a:panic.*(.literal .text .literal.* .text.*) + *librtc.a:(.literal .text .literal.* .text.*) + *libsubsys__net__l2__ethernet.a:(.literal .text .literal.* .text.*) + *libsubsys__net__lib__config.a:(.literal .text .literal.* .text.*) + *libsubsys__net__ip.a:(.literal .text .literal.* .text.*) + *libsubsys__net.a:(.literal .text .literal.* .text.*) + *libarch__xtensa__core.a:(.literal .text .literal.* .text.*) + *libkernel.a:(.literal .text .literal.* .text.*) + *libsoc.a:rtc_*.*(.literal .text .literal.* .text.*) + *libsoc.a:cpu_util.*(.literal .text .literal.* .text.*) + *libgcc.a:lib2funcs.*(.literal .text .literal.* .text.*) + *libdrivers__flash.a:flash_esp32.*(.literal .text .literal.* .text.*) + *libzephyr.a:spi_flash_rom_patch.*(.literal .text .literal.* .text.*) + *libzephyr.a:windowspill_asm.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_noos.*(.literal .text .literal.* .text.*) + *libdrivers__timer.a:xtensa_sys_timer.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_core.*(.literal .text .literal.* .text.*) + *libzephyr.a:cbprintf_complete.*(.literal .text .literal.* .text.*) + *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) + *libzephyr.a:log_msg.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_list.*(.literal .text .literal.* .text.*) + *libdrivers__console.a:uart_console.*(.literal.console_out .text.console_out) + *libzephyr.a:log_output.*(.literal .text .literal.* .text.*) + *libzephyr.a:log_backend_uart.*(.literal .text .literal.* .text.*) + *libzephyr.a:loader.*(.literal .text .literal.* .text.*) + *liblib__libc__minimal.a:string.*(.literal .text .literal.* .text.*) + *liblib__libc__newlib.a:string.*(.literal .text .literal.* .text.*) + *libc.a:*(.literal .text .literal.* .text.*) + *libphy.a:( .phyiram .phyiram.*) + *libgcov.a:(.literal .text .literal.* .text.*) + + *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) + *libpp.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.* .wifiorslpiram .wifiorslpiram.*) + + *libnet80211.a:( .wifirxiram .wifirxiram.* .wifislprxiram .wifislprxiram.*) + *libpp.a:( .wifirxiram .wifirxiram.* .wifislprxiram .wifislprxiram.*) + + _iram_text_end = ABSOLUTE(.); + . = ALIGN(4); + _iram_end = ABSOLUTE(.); + } GROUP_DATA_LINK_IN(IRAM_REGION, ROMABLE_REGION) + + _image_drom_start = LOADADDR(_RODATA_SECTION_NAME); + _image_drom_size = LOADADDR(_RODATA_SECTION_END) + SIZEOF(_RODATA_SECTION_END) - _image_drom_start; + _image_drom_vaddr = ADDR(_RODATA_SECTION_NAME); + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + __rodata_region_start = ABSOLUTE(.); + + . = ALIGN(4); + #include + + . = ALIGN(4); + *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) + *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) + + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table .gcc_except_table.*) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + . = (. + 3) & ~ 3; + __eh_frame = ABSOLUTE(.); + KEEP(*(.eh_frame)) + . = (. + 7) & ~ 3; + + /* 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); + __rodata_region_end = ABSOLUTE(.); + /* Literals are also RO data. */ + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + . = ALIGN(4); + _thread_local_start = ABSOLUTE(.); + *(.tdata) + *(.tdata.*) + *(.tbss) + *(.tbss.*) + *(.rodata_wlog) + *(.rodata_wlog*) + _thread_local_end = ABSOLUTE(.); + . = ALIGN(4); + } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_DATA_REGION) + + #include + #include + #include + #include + #include + #include + #include + #include + + /* Create an explicit section at the end of all the data that shall be mapped into drom. + * This is used to calculate the size of the _image_drom_size variable */ + SECTION_PROLOGUE(_RODATA_SECTION_END,,) + { + . = ALIGN(4); + _image_rodata_end = ABSOLUTE(.); + } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) + + _image_dram_start = LOADADDR(.dram0.data); + _image_dram_size = LOADADDR(.dram0.end) + SIZEOF(.dram0.end) - _image_dram_start; + _image_dram_vaddr = ADDR(.dram0.data); + + .dram0.data : + { + __data_start = ABSOLUTE(.); + + _btdm_data_start = ABSOLUTE(.); + *libbtdm_app.a:(.data .data.*) + . = ALIGN (4); + _btdm_data_end = ABSOLUTE(.); + + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + /* rodata for panic handler(libarch__xtensa__core.a) and all + * dependent functions should be placed in DRAM to avoid issue + * when flash cache is disabled */ + *libarch__xtensa__core.a:(.rodata .rodata.*) + *libkernel.a:fatal.*(.rodata .rodata.*) + *libkernel.a:init.*(.rodata .rodata.*) + *libzephyr.a:cbprintf_complete*(.rodata .rodata.*) + *libzephyr.a:log_core.*(.rodata .rodata.*) + *libzephyr.a:log_backend_uart.*(.rodata .rodata.*) + *libzephyr.a:log_output.*(.rodata .rodata.*) + *libzephyr.a:loader.*(.rodata .rodata.*) + *libdrivers__flash.a:flash_esp32.*(.rodata .rodata.*) + *libzephyr.a:spi_flash_rom_patch.*(.rodata .rodata.*) + *libdrivers__serial.a:uart_esp32.*(.rodata .rodata.*) + + KEEP(*(.jcr)) + *(.dram1 .dram1.*) + . = ALIGN(4); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_DATA_REGION) + + #include + #include + #include + #include + #include + + /* logging sections should be placed in RAM area to avoid flash cache disabled issues */ + #pragma push_macro("GROUP_ROM_LINK_IN") + #undef GROUP_ROM_LINK_IN + #define GROUP_ROM_LINK_IN GROUP_DATA_LINK_IN + #include + #pragma pop_macro("GROUP_ROM_LINK_IN") + + .dram0.end : + { + . = ALIGN(4); + #include + . = ALIGN(4); + _end = ABSOLUTE(.); + __data_end = ABSOLUTE(.); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_DATA_REGION) + + /* Shared RAM */ + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); /* required by bluetooth library */ + __bss_start = ABSOLUTE(.); + + _btdm_bss_start = ABSOLUTE(.); + *libbtdm_app.a:(.bss .bss.* COMMON) + . = ALIGN (4); + _btdm_bss_end = ABSOLUTE(.); + + /* Buffer for system heap should be placed in dram0_0_seg */ + *libkernel.a:mempool.*(.noinit.kheap_buf__system_heap .noinit.*.kheap_buf__system_heap) + + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.share.mem) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + __bss_end = ABSOLUTE(.); + _end = ABSOLUTE(.); + } GROUP_LINK_IN(RAMABLE_REGION) + + ASSERT(((__bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), + "DRAM segment data does not fit.") + + SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) + { + . = ALIGN (8); + *(.noinit) + *(.noinit.*) + . = ALIGN (8); + } GROUP_LINK_IN(RAMABLE_REGION_1) + + _image_irom_start = LOADADDR(.flash.text); + _image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) - _image_irom_start; + _image_irom_vaddr = ADDR(.flash.text); + + .flash.text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + + *(.literal .text .literal.* .text.*) + . = ALIGN(4); + _text_end = ABSOLUTE(.); + _etext = .; + + /* Similar to _iram_start, this symbol goes here so it is + resolved by addr2line in preference to the first symbol in + the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); + } GROUP_DATA_LINK_IN(FLASH_CODE_REGION, ROMABLE_REGION) + +_heap_sentry = 0x3ffe3f20; + +#include + + .xtensa.info 0 : { *(.xtensa.info) } + .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.*)) + } + +#ifdef CONFIG_GEN_ISR_TABLES +#include +#endif + +} + +ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), + "IRAM0 segment data does not fit.") diff --git a/soc/xtensa/espressif_esp32/esp32/esp32-mp.c b/soc/xtensa/espressif_esp32/esp32/esp32-mp.c index db166677f2d..7922e6f18cd 100644 --- a/soc/xtensa/espressif_esp32/esp32/esp32-mp.c +++ b/soc/xtensa/espressif_esp32/esp32/esp32-mp.c @@ -5,9 +5,9 @@ */ /* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc/dport_reg.h" -#include "soc/gpio_periph.h" -#include "soc/rtc_periph.h" +#include +#include +#include #include #include @@ -62,7 +62,7 @@ static struct k_spinlock loglock; */ void smp_log(const char *msg) { -#ifndef CONFIG_ESP32_NETWORK_CORE +#ifndef CONFIG_SOC_ESP32_PROCPU k_spinlock_key_t key = k_spin_lock(&loglock); while (*msg) { diff --git a/soc/xtensa/espressif_esp32/esp32/gdbstub.c b/soc/xtensa/espressif_esp32/esp32/gdbstub.c index f7962b61851..c8913b7f5a2 100644 --- a/soc/xtensa/espressif_esp32/esp32/gdbstub.c +++ b/soc/xtensa/espressif_esp32/esp32/gdbstub.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include diff --git a/soc/xtensa/espressif_esp32/esp32/soc.c b/soc/xtensa/espressif_esp32/esp32/soc.c index 2abd0f6a88a..16df3aca645 100644 --- a/soc/xtensa/espressif_esp32/esp32/soc.c +++ b/soc/xtensa/espressif_esp32/esp32/soc.c @@ -5,7 +5,7 @@ */ /* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc.h" +#include #include #include #include @@ -31,9 +31,9 @@ #include "esp_app_format.h" #include "hal/wdt_hal.h" -#ifndef CONFIG_SOC_SERIES_ESP32_NET +#ifndef CONFIG_SOC_ESP32_PROCPU #include "esp_clk_internal.h" -#endif /* CONFIG_SOC_SERIES_ESP32_NET */ +#endif /* CONFIG_SOC_ESP32_PROCPU */ #ifdef CONFIG_MCUBOOT #include "bootloader_init.h" @@ -41,48 +41,46 @@ #include extern void z_cstart(void); +extern void esp_reset_reason_init(void); -#ifdef CONFIG_ESP32_NETWORK_CORE -extern const unsigned char esp32_net_fw_array[]; -extern const int esp_32_net_fw_array_size; +#ifdef CONFIG_SOC_ESP32_PROCPU +extern const unsigned char esp32_appcpu_fw_array[]; -void __attribute__((section(".iram1"))) start_esp32_net_cpu(void) +void IRAM_ATTR esp_start_appcpu(void) { - esp_image_header_t *header = (esp_image_header_t *)&esp32_net_fw_array[0]; + esp_image_header_t *header = (esp_image_header_t *)&esp32_appcpu_fw_array[0]; esp_image_segment_header_t *segment = - (esp_image_segment_header_t *)&esp32_net_fw_array[sizeof(esp_image_header_t)]; + (esp_image_segment_header_t *)&esp32_appcpu_fw_array[sizeof(esp_image_header_t)]; uint8_t *segment_payload; uint32_t entry_addr = header->entry_addr; uint32_t idx = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t); for (int i = 0; i < header->segment_count; i++) { - segment_payload = (uint8_t *)&esp32_net_fw_array[idx]; + segment_payload = (uint8_t *)&esp32_appcpu_fw_array[idx]; if (segment->load_addr >= SOC_IRAM_LOW && segment->load_addr < SOC_IRAM_HIGH) { /* IRAM segment only accepts 4 byte access, avoid memcpy usage here */ volatile uint32_t *src = (volatile uint32_t *)segment_payload; - volatile uint32_t *dst = - (volatile uint32_t *)segment->load_addr; + volatile uint32_t *dst = (volatile uint32_t *)segment->load_addr; - for (int j = 0; j < segment->data_len/4 ; j++) { + for (int j = 0; j < segment->data_len / 4; j++) { dst[j] = src[j]; } } else if (segment->load_addr >= SOC_DRAM_LOW && - segment->load_addr < SOC_DRAM_HIGH) { + segment->load_addr < SOC_DRAM_HIGH) { - memcpy((void *)segment->load_addr, - (const void *)segment_payload, - segment->data_len); + memcpy((void *)segment->load_addr, (const void *)segment_payload, + segment->data_len); } idx += segment->data_len; - segment = (esp_image_segment_header_t *)&esp32_net_fw_array[idx]; + segment = (esp_image_segment_header_t *)&esp32_appcpu_fw_array[idx]; idx += sizeof(esp_image_segment_header_t); } esp_appcpu_start((void *)entry_addr); } -#endif /* CONFIG_ESP32_NETWORK_CORE */ +#endif /* CONFIG_SOC_ESP32_PROCPU */ /* * This is written in C rather than assembly since, during the port bring up, @@ -119,6 +117,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) */ __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ if (bootloader_init()) { @@ -135,7 +135,7 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#ifndef CONFIG_SOC_SERIES_ESP32_NET +#ifndef CONFIG_SOC_ESP32_PROCPU /* Configures the CPU clock, RTC slow and fast clocks, and performs * RTC slow clock calibration. */ @@ -144,11 +144,9 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) esp_timer_early_init(); -#if CONFIG_ESP32_NETWORK_CORE - /* start the esp32 network core before - * start zephyr - */ - start_esp32_net_cpu(); +#if CONFIG_SOC_ESP32_PROCPU + /* start the ESP32 APP CPU */ + esp_start_appcpu(); #endif #if CONFIG_ESP_SPIRAM diff --git a/soc/xtensa/espressif_esp32/esp32/soc_appcpu.c b/soc/xtensa/espressif_esp32/esp32/soc_appcpu.c new file mode 100644 index 00000000000..a8ff116a58a --- /dev/null +++ b/soc/xtensa/espressif_esp32/esp32/soc_appcpu.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Include esp-idf headers first to avoid redefining BIT() macro */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void z_cstart(void); + +/* + * This is written in C rather than assembly since, during the port bring up, + * Zephyr is being booted by the Espressif bootloader. With it, the C stack + * is already set up. + */ +void __app_cpu_start(void) +{ + extern uint32_t _init_start; + extern uint32_t _bss_start; + extern uint32_t _bss_end; + + /* Move the exception vector table to IRAM. */ + __asm__ __volatile__ ( + "wsr %0, vecbase" + : + : "r"(&_init_start)); + + /* Zero out BSS. Clobber _bss_start to avoid memset() elision. */ + z_bss_zero(); + + __asm__ __volatile__ ( + "" + : + : "g"(&__bss_start) + : "memory"); + + /* Disable normal interrupts. */ + __asm__ __volatile__ ( + "wsr %0, PS" + : + : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); + + /* Initialize the architecture CPU pointer. Some of the + * initialization code wants a valid _current before + * arch_kernel_init() is invoked. + */ + __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + + esp_intr_initialize(); + /* Start Zephyr */ + z_cstart(); + + CODE_UNREACHABLE; +} + +/* Boot-time static default printk handler, possibly to be overridden later. */ +int IRAM_ATTR arch_printk_char_out(int c) +{ + ARG_UNUSED(c); + return 0; +} + +void sys_arch_reboot(int type) +{ + esp_restart_noos(); +} + +void IRAM_ATTR esp_restart_noos(void) +{ + /* Disable interrupts */ + z_xt_ints_off(0xFFFFFFFF); + + const uint32_t core_id = cpu_hal_get_core_id(); + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + + soc_ll_reset_core(other_core_id); + soc_ll_stall_core(other_core_id); + + /* Flush any data left in UART FIFOs */ + esp_rom_uart_tx_wait_idle(0); + esp_rom_uart_tx_wait_idle(1); + esp_rom_uart_tx_wait_idle(2); + + /* Disable cache */ + Cache_Read_Disable(0); + Cache_Read_Disable(1); + + /* 2nd stage bootloader reconfigures SPI flash signals. */ + /* Reset them to the defaults expected by ROM */ + WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30); + WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); + + /* Reset wifi/bluetooth/ethernet/sdio (bb/mac) */ + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, + DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | + DPORT_BT_RST | DPORT_BTMAC_RST | + DPORT_SDIO_RST | DPORT_SDIO_HOST_RST | + DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); + DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); + + /* Reset timer/spi/uart */ + DPORT_SET_PERI_REG_MASK( + DPORT_PERIP_RST_EN_REG, + /* UART TX FIFO cannot be reset correctly on ESP32, */ + /* so reset the UART memory by DPORT here. */ + DPORT_TIMERS_RST | DPORT_SPI01_RST | DPORT_UART_RST | + DPORT_UART1_RST | DPORT_UART2_RST | DPORT_UART_MEM_RST); + DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0); + + /* Clear entry point for APP CPU */ + DPORT_REG_WRITE(DPORT_APPCPU_CTRL_D_REG, 0); + + /* Reset CPUs */ + if (core_id == 0) { + /* Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. */ + soc_ll_reset_core(1); + soc_ll_reset_core(0); + } else { + /* Running on APP CPU: need to reset PRO CPU and unstall it, */ + /* then reset APP CPU */ + soc_ll_reset_core(0); + soc_ll_stall_core(0); + soc_ll_reset_core(1); + } + + while (true) { + ; + } +} diff --git a/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt b/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt deleted file mode 100644 index 2997e2e9990..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -zephyr_sources( - soc.c - ) - -zephyr_library_sources_ifdef(CONFIG_NEWLIB_LIBC newlib_fix.c) - -if(CONFIG_BUILD_OUTPUT_BIN) - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/components/esptool_py/esptool/esptool.py - ARGS --chip esp32 elf2image --flash_mode dio --flash_freq 40m - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.elf) - - set_property(GLOBAL APPEND PROPERTY extra_post_build_commands - COMMAND ${PYTHON_EXECUTABLE} ${ESP_IDF_PATH}/tools/esp_bin2c_array.py - ARGS -i ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.bin - -o ${CMAKE_BINARY_DIR}/zephyr/${CONFIG_KERNEL_BIN_NAME}.c - -a "esp32_net_fw_array") -endif() - -set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series deleted file mode 100644 index 8193bbb6149..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.defconfig.series +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_ESP32_NET - -config SOC_SERIES - default "esp32_net" - -config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE - default n - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) - -config XTENSA_CCOUNT_HZ - default SYS_CLOCK_HW_CYCLES_PER_SEC - -config ESPTOOLPY_FLASHFREQ_80M - default y - -endif # SOC_ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series deleted file mode 100644 index 55f794f96e0..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.series +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2023 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -config SOC_SERIES_ESP32_NET - bool "ESP32-NET Series" - select XTENSA - select SOC_FAMILY_ESP32 - select CLOCK_CONTROL - select DYNAMIC_INTERRUPTS - select HAS_ESPRESSIF_HAL - help - Enable support for Espressif ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc deleted file mode 100644 index 975b777b790..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/Kconfig.soc +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. -# SPDX-License-Identifier: Apache-2.0 - -if SOC_SERIES_ESP32_NET - -config IDF_TARGET_ESP32 - bool "ESP32 as target board" - default y - -config SOC_TOOLCHAIN_NAME - string - default "espressif_esp32" - -choice SOC_PART_NUMBER - prompt "ESP32-NET SOC Selection" - depends on SOC_SERIES_ESP32_NET - - # SoC with/without embedded flash - config SOC_ESP32_NET - bool "ESP32_NET" - -endchoice # SOC_PART_NUMBER - -config ESP32_BT_RESERVE_DRAM - hex "Bluetooth controller reserved RAM region" - default 0xdb5c if BT - default 0 - -choice ESP32_UNIVERSAL_MAC_ADDRESSES - bool "Number of universally administered (by IEEE) MAC address" - default ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - help - Configure the number of universally administered (by IEEE) MAC addresses. - During initialization, MAC addresses for each network interface are generated or - derived from a single base MAC address. If the number of universal MAC addresses is four, - all four interfaces (WiFi station, WiFi softap, Bluetooth and Ethernet) receive a universally - administered MAC address. These are generated sequentially by adding 0, 1, 2 and 3 (respectively) - to the final octet of the base MAC address. If the number of universal MAC addresses is two, - only two interfaces (WiFi station and Bluetooth) receive a universally administered MAC address. - These are generated sequentially by adding 0 and 1 (respectively) to the base MAC address. - The remaining two interfaces (WiFi softap and Ethernet) receive local MAC addresses. - These are derived from the universal WiFi station and Bluetooth MAC addresses, respectively. - When using the default (Espressif-assigned) base MAC address, either setting can be used. - When using a custom universal MAC address range, the correct setting will depend on the - allocation of MAC addresses in this range (either 2 or 4 per device.) - -config ESP32_UNIVERSAL_MAC_ADDRESSES_TWO - bool "Two" - select ESP_MAC_ADDR_UNIVERSE_WIFI_STA - select ESP_MAC_ADDR_UNIVERSE_BT - -config ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - bool "Four" - select ESP_MAC_ADDR_UNIVERSE_WIFI_STA - select ESP_MAC_ADDR_UNIVERSE_WIFI_AP - select ESP_MAC_ADDR_UNIVERSE_BT - select ESP_MAC_ADDR_UNIVERSE_ETH - -endchoice # ESP32_UNIVERSAL_MAC_ADDRESSES - -config ESP_MAC_ADDR_UNIVERSE_WIFI_AP - bool - -config ESP_MAC_ADDR_UNIVERSE_WIFI_STA - bool - -config ESP_MAC_ADDR_UNIVERSE_BT - bool - -config ESP_MAC_ADDR_UNIVERSE_ETH - bool - -config ESP32_UNIVERSAL_MAC_ADDRESSES - int - default 2 if ESP32_UNIVERSAL_MAC_ADDRESSES_TWO - default 4 if ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR - -endif # SOC_ESP32_NET diff --git a/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h b/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h deleted file mode 100644 index 63d6eef4c81..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/include/_soc_inthandlers.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#if !defined(XCHAL_INT0_LEVEL) || XCHAL_INT0_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT1_LEVEL) || XCHAL_INT1_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT2_LEVEL) || XCHAL_INT2_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT3_LEVEL) || XCHAL_INT3_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT4_LEVEL) || XCHAL_INT4_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT5_LEVEL) || XCHAL_INT5_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT6_LEVEL) || XCHAL_INT6_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT7_LEVEL) || XCHAL_INT7_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT8_LEVEL) || XCHAL_INT8_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT9_LEVEL) || XCHAL_INT9_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT10_LEVEL) || XCHAL_INT10_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT12_LEVEL) || XCHAL_INT12_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT13_LEVEL) || XCHAL_INT13_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT17_LEVEL) || XCHAL_INT17_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT18_LEVEL) || XCHAL_INT18_LEVEL != 1 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT11_LEVEL) || XCHAL_INT11_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT15_LEVEL) || XCHAL_INT15_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT22_LEVEL) || XCHAL_INT22_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT23_LEVEL) || XCHAL_INT23_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT27_LEVEL) || XCHAL_INT27_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT29_LEVEL) || XCHAL_INT29_LEVEL != 3 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT14_LEVEL) || XCHAL_INT14_LEVEL != 7 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT16_LEVEL) || XCHAL_INT16_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT26_LEVEL) || XCHAL_INT26_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT31_LEVEL) || XCHAL_INT31_LEVEL != 5 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT19_LEVEL) || XCHAL_INT19_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT20_LEVEL) || XCHAL_INT20_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT21_LEVEL) || XCHAL_INT21_LEVEL != 2 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT24_LEVEL) || XCHAL_INT24_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT25_LEVEL) || XCHAL_INT25_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT28_LEVEL) || XCHAL_INT28_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif -#if !defined(XCHAL_INT30_LEVEL) || XCHAL_INT30_LEVEL != 4 -#error core-isa.h interrupt level does not match dispatcher! -#endif - -static inline int _xtensa_handle_one_int1(unsigned int mask) -{ - int irq; - - if (mask & 0x7f) { - if (mask & 0x7) { - if (mask & BIT(0)) { - mask = BIT(0); - irq = 0; - goto handle_irq; - } - if (mask & BIT(1)) { - mask = BIT(1); - irq = 1; - goto handle_irq; - } - if (mask & BIT(2)) { - mask = BIT(2); - irq = 2; - goto handle_irq; - } - } else { - if (mask & 0x18) { - if (mask & BIT(3)) { - mask = BIT(3); - irq = 3; - goto handle_irq; - } - if (mask & BIT(4)) { - mask = BIT(4); - irq = 4; - goto handle_irq; - } - } else { - if (mask & BIT(5)) { - mask = BIT(5); - irq = 5; - goto handle_irq; - } - if (mask & BIT(6)) { - mask = BIT(6); - irq = 6; - goto handle_irq; - } - } - } - } else { - if (mask & 0x780) { - if (mask & 0x180) { - if (mask & BIT(7)) { - mask = BIT(7); - irq = 7; - goto handle_irq; - } - if (mask & BIT(8)) { - mask = BIT(8); - irq = 8; - goto handle_irq; - } - } else { - if (mask & BIT(9)) { - mask = BIT(9); - irq = 9; - goto handle_irq; - } - if (mask & BIT(10)) { - mask = BIT(10); - irq = 10; - goto handle_irq; - } - } - } else { - if (mask & 0x3000) { - if (mask & BIT(12)) { - mask = BIT(12); - irq = 12; - goto handle_irq; - } - if (mask & BIT(13)) { - mask = BIT(13); - irq = 13; - goto handle_irq; - } - } else { - if (mask & BIT(17)) { - mask = BIT(17); - irq = 17; - goto handle_irq; - } - if (mask & BIT(18)) { - mask = BIT(18); - irq = 18; - goto handle_irq; - } - } - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int3(unsigned int mask) -{ - int irq; - - if (mask & 0x408800) { - if (mask & BIT(11)) { - mask = BIT(11); - irq = 11; - goto handle_irq; - } - if (mask & BIT(15)) { - mask = BIT(15); - irq = 15; - goto handle_irq; - } - if (mask & BIT(22)) { - mask = BIT(22); - irq = 22; - goto handle_irq; - } - } else { - if (mask & BIT(23)) { - mask = BIT(23); - irq = 23; - goto handle_irq; - } - if (mask & BIT(27)) { - mask = BIT(27); - irq = 27; - goto handle_irq; - } - if (mask & BIT(29)) { - mask = BIT(29); - irq = 29; - goto handle_irq; - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int7(unsigned int mask) -{ - int irq; - - if (mask & BIT(14)) { - mask = BIT(14); - irq = 14; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int5(unsigned int mask) -{ - int irq; - - if (mask & BIT(16)) { - mask = BIT(16); - irq = 16; - goto handle_irq; - } - if (mask & BIT(26)) { - mask = BIT(26); - irq = 26; - goto handle_irq; - } - if (mask & BIT(31)) { - mask = BIT(31); - irq = 31; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int2(unsigned int mask) -{ - int irq; - - if (mask & BIT(19)) { - mask = BIT(19); - irq = 19; - goto handle_irq; - } - if (mask & BIT(20)) { - mask = BIT(20); - irq = 20; - goto handle_irq; - } - if (mask & BIT(21)) { - mask = BIT(21); - irq = 21; - goto handle_irq; - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int4(unsigned int mask) -{ - int irq; - - if (mask & 0x3000000) { - if (mask & BIT(24)) { - mask = BIT(24); - irq = 24; - goto handle_irq; - } - if (mask & BIT(25)) { - mask = BIT(25); - irq = 25; - goto handle_irq; - } - } else { - if (mask & BIT(28)) { - mask = BIT(28); - irq = 28; - goto handle_irq; - } - if (mask & BIT(30)) { - mask = BIT(30); - irq = 30; - goto handle_irq; - } - } - return 0; -handle_irq: - _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); - return mask; -} - -static inline int _xtensa_handle_one_int0(unsigned int mask) -{ - return 0; -} -static inline int _xtensa_handle_one_int6(unsigned int mask) -{ - return 0; -} diff --git a/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h b/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h deleted file mode 100644 index 03e0c5df0b2..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/include/gdbstub/soc.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2021 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#ifndef SOC_XTENSA_ESP32_GDBSTUB_H_ -#define SOC_XTENSA_ESP32_GDBSTUB_H_ - -#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_GDBSTUB_SYS_H_ -#error "Must be included after arch/xtensa/gdbstub.h" -#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_GDBSTUB_SYS_H_ */ - -#define SOC_GDB_GPKT_BIN_SIZE 420 -#define SOC_GDB_GPKT_HEX_SIZE (SOC_GDB_GPKT_BIN_SIZE * 2) - -#define SOC_GDB_REGNO_A1 0x0001 - -#endif /* SOC_XTENSA_ESP32_GDBSTUB_H_ */ diff --git a/soc/xtensa/espressif_esp32/esp32_net/linker.ld b/soc/xtensa/espressif_esp32/esp32_net/linker.ld deleted file mode 100644 index 69a4c48ef78..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/linker.ld +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2016 Cadence Design Systems, Inc. - * Copyright (c) 2017 Intel Corporation - * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd. - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief Linker command/script file - * - * Linker script for the Xtensa platform. - */ - -#include -#include -#include -#include - -#define RAMABLE_REGION dram0_1_seg -#define RAMABLE_REGION_1 dram0_1_seg -#define RODATA_REGION dram0_1_seg -#define IRAM_REGION iram0_0_seg -#define FLASH_CODE_REGION iram0_0_seg -#define ROMABLE_REGION iram0_0_seg -#define ROMABLE_DATA_REGION dram0_1_seg -#define dram0_0_seg dram0_1_seg - -/* Flash segments (rodata and text) should be mapped in virtual address space by providing VMA. - * Executing directly from LMA is not possible. */ -#undef GROUP_ROM_LINK_IN -#define GROUP_ROM_LINK_IN(vregion, lregion) > RODATA_REGION AT > lregion - -MEMORY -{ - iram0_0_seg(RX): org = 0x40080000 + 0x08000, len = 0x18000 - dram0_shm0_seg(RW): org = 0x3FFE5230, len = 16K /* shared RAM reserved for IPM */ - dram0_sem0_seg(RW): org = 0x3FFED238, len = 8 /*shared data reserved for IPM data header */ - dram0_1_seg(RW): org = 0x3FFE9238 + CONFIG_ESP32_BT_RESERVE_DRAM, len = 0x17CB0 - 0xEE0 - CONFIG_ESP32_BT_RESERVE_DRAM -#ifdef CONFIG_GEN_ISR_TABLES - IDT_LIST(RW): org = 0x3ebfe010, len = 0x2000 -#endif -} - -/* Default entry point: */ -PROVIDE ( _ResetVector = 0x40000400 ); -ENTRY(__app_cpu_start) - -_rom_store_table = 0; - -PROVIDE(_memmap_vecbase_reset = 0x40000450); -PROVIDE(_memmap_reset_vector = 0x40000400); - -SECTIONS -{ -#include - - _image_iram_start = LOADADDR(.iram0.vectors); - _image_iram_size = LOADADDR(_TEXT_SECTION_NAME) + SIZEOF(_TEXT_SECTION_NAME) - _image_iram_start; - _image_iram_vaddr = ADDR(.iram0.vectors); - - /* Send .iram0 code to iram */ - .iram0.vectors : ALIGN(4) - { - /* Vectors go to IRAM */ - _init_start = ABSOLUTE(.); - /* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */ - . = 0x0; - KEEP(*(.WindowVectors.text)); - . = 0x180; - KEEP(*(.Level2InterruptVector.text)); - . = 0x1c0; - KEEP(*(.Level3InterruptVector.text)); - . = 0x200; - KEEP(*(.Level4InterruptVector.text)); - . = 0x240; - KEEP(*(.Level5InterruptVector.text)); - . = 0x280; - KEEP(*(.DebugExceptionVector.text)); - . = 0x2c0; - KEEP(*(.NMIExceptionVector.text)); - . = 0x300; - KEEP(*(.KernelExceptionVector.text)); - . = 0x340; - KEEP(*(.UserExceptionVector.text)); - . = 0x3C0; - KEEP(*(.DoubleExceptionVector.text)); - . = 0x400; - *(.*Vector.literal) - - *(.UserEnter.literal); - *(.UserEnter.text); - . = ALIGN (16); - *(.entry.text) - *(.init.literal) - *(.init) - _init_end = ABSOLUTE(.); - - /* This goes here, not at top of linker script, so addr2line finds it last, - and uses it in preference to the first symbol in IRAM */ - _iram_start = ABSOLUTE(0); - } GROUP_DATA_LINK_IN(IRAM_REGION, ROMABLE_REGION) - - SECTION_PROLOGUE(_TEXT_SECTION_NAME, , ALIGN(4)) - { - /* Code marked as running out of IRAM */ - _iram_text_start = ABSOLUTE(.); - *(.iram1 .iram1.*) - *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) - *libesp32.a:panic.*(.literal .text .literal.* .text.*) - *librtc.a:(.literal .text .literal.* .text.*) - *libsubsys__net__l2__ethernet.a:(.literal .text .literal.* .text.*) - *libsubsys__net__lib__config.a:(.literal .text .literal.* .text.*) - *libsubsys__net__ip.a:(.literal .text .literal.* .text.*) - *libsubsys__net.a:(.literal .text .literal.* .text.*) - *libarch__xtensa__core.a:(.literal .text .literal.* .text.*) - *libkernel.a:(.literal .text .literal.* .text.*) - *libsoc.a:rtc_*.*(.literal .text .literal.* .text.*) - *libsoc.a:cpu_util.*(.literal .text .literal.* .text.*) - *libgcc.a:lib2funcs.*(.literal .text .literal.* .text.*) - *libdrivers__flash.a:flash_esp32.*(.literal .text .literal.* .text.*) - *libzephyr.a:spi_flash_rom_patch.*(.literal .text .literal.* .text.*) - *libzephyr.a:windowspill_asm.*(.literal .text .literal.* .text.*) - *libzephyr.a:log_noos.*(.literal .text .literal.* .text.*) - *libdrivers__timer.a:xtensa_sys_timer.*(.literal .text .literal.* .text.*) - *libzephyr.a:log_core.*(.literal .text .literal.* .text.*) - *libzephyr.a:cbprintf_complete.*(.literal .text .literal.* .text.*) - *libzephyr.a:printk.*(.literal.printk .literal.vprintk .literal.char_out .text.printk .text.vprintk .text.char_out) - *libzephyr.a:log_msg.*(.literal .text .literal.* .text.*) - *libzephyr.a:log_list.*(.literal .text .literal.* .text.*) - *libdrivers__console.a:uart_console.*(.literal.console_out .text.console_out) - *libzephyr.a:log_output.*(.literal .text .literal.* .text.*) - *libzephyr.a:log_backend_uart.*(.literal .text .literal.* .text.*) - *libzephyr.a:loader.*(.literal .text .literal.* .text.*) - *liblib__libc__minimal.a:string.*(.literal .text .literal.* .text.*) - *liblib__libc__newlib.a:string.*(.literal .text .literal.* .text.*) - *libc.a:*(.literal .text .literal.* .text.*) - *libphy.a:( .phyiram .phyiram.*) - *libgcov.a:(.literal .text .literal.* .text.*) - - *libnet80211.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.*) - *libpp.a:( .wifi0iram .wifi0iram.* .wifislpiram .wifislpiram.* .wifiorslpiram .wifiorslpiram.*) - - *libnet80211.a:( .wifirxiram .wifirxiram.* .wifislprxiram .wifislprxiram.*) - *libpp.a:( .wifirxiram .wifirxiram.* .wifislprxiram .wifislprxiram.*) - - _iram_text_end = ABSOLUTE(.); - . = ALIGN(4); - _iram_end = ABSOLUTE(.); - } GROUP_DATA_LINK_IN(IRAM_REGION, ROMABLE_REGION) - - _image_drom_start = LOADADDR(_RODATA_SECTION_NAME); - _image_drom_size = LOADADDR(_RODATA_SECTION_END) + SIZEOF(_RODATA_SECTION_END) - _image_drom_start; - _image_drom_vaddr = ADDR(_RODATA_SECTION_NAME); - - SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) - { - __rodata_region_start = ABSOLUTE(.); - - . = ALIGN(4); - #include - - . = ALIGN(4); - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata) - *(EXCLUDE_FILE (*libarch__xtensa__core.a:* *libkernel.a:fatal.* *libkernel.a:init.* *libzephyr.a:cbprintf_complete* *libzephyr.a:log_core.* *libzephyr.a:log_backend_uart.* *libdrivers__flash.a:esp32_mp.* *libzephyr.a:log_output.* *libzephyr.a:loader.* *libdrivers__flash.a:flash_esp32.* *libdrivers__serial.a:uart_esp32.* *libzephyr.a:spi_flash_rom_patch.*) .rodata.*) - - *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ - *(.gnu.linkonce.r.*) - *(.rodata1) - __XT_EXCEPTION_TABLE_ = ABSOLUTE(.); - *(.xt_except_table) - *(.gcc_except_table .gcc_except_table.*) - *(.gnu.linkonce.e.*) - *(.gnu.version_r) - . = (. + 3) & ~ 3; - __eh_frame = ABSOLUTE(.); - KEEP(*(.eh_frame)) - . = (. + 7) & ~ 3; - - /* 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); - __rodata_region_end = ABSOLUTE(.); - /* Literals are also RO data. */ - _lit4_start = ABSOLUTE(.); - *(*.lit4) - *(.lit4.*) - *(.gnu.linkonce.lit4.*) - _lit4_end = ABSOLUTE(.); - . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) - *(.rodata_wlog) - *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); - . = ALIGN(4); - } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_DATA_REGION) - - #include - #include - #include - #include - #include - #include - #include - #include - - /* Create an explicit section at the end of all the data that shall be mapped into drom. - * This is used to calculate the size of the _image_drom_size variable */ - SECTION_PROLOGUE(_RODATA_SECTION_END,,) - { - . = ALIGN(4); - _image_rodata_end = ABSOLUTE(.); - } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) - - _image_dram_start = LOADADDR(.dram0.data); - _image_dram_size = LOADADDR(.dram0.end) + SIZEOF(.dram0.end) - _image_dram_start; - _image_dram_vaddr = ADDR(.dram0.data); - - .dram0.data : - { - __data_start = ABSOLUTE(.); - - _btdm_data_start = ABSOLUTE(.); - *libbtdm_app.a:(.data .data.*) - . = ALIGN (4); - _btdm_data_end = ABSOLUTE(.); - - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - *(.data1) - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - /* rodata for panic handler(libarch__xtensa__core.a) and all - * dependent functions should be placed in DRAM to avoid issue - * when flash cache is disabled */ - *libarch__xtensa__core.a:(.rodata .rodata.*) - *libkernel.a:fatal.*(.rodata .rodata.*) - *libkernel.a:init.*(.rodata .rodata.*) - *libzephyr.a:cbprintf_complete*(.rodata .rodata.*) - *libzephyr.a:log_core.*(.rodata .rodata.*) - *libzephyr.a:log_backend_uart.*(.rodata .rodata.*) - *libzephyr.a:log_output.*(.rodata .rodata.*) - *libzephyr.a:loader.*(.rodata .rodata.*) - *libdrivers__flash.a:flash_esp32.*(.rodata .rodata.*) - *libzephyr.a:spi_flash_rom_patch.*(.rodata .rodata.*) - *libdrivers__serial.a:uart_esp32.*(.rodata .rodata.*) - - KEEP(*(.jcr)) - *(.dram1 .dram1.*) - . = ALIGN(4); - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_DATA_REGION) - - #include - #include - #include - #include - #include - - /* logging sections should be placed in RAM area to avoid flash cache disabled issues */ - #pragma push_macro("GROUP_ROM_LINK_IN") - #undef GROUP_ROM_LINK_IN - #define GROUP_ROM_LINK_IN GROUP_DATA_LINK_IN - #include - #pragma pop_macro("GROUP_ROM_LINK_IN") - - .dram0.end : - { - . = ALIGN(4); - #include - . = ALIGN(4); - _end = ABSOLUTE(.); - __data_end = ABSOLUTE(.); - } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_DATA_REGION) - - /* Shared RAM */ - SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD),) - { - . = ALIGN (8); - _bss_start = ABSOLUTE(.); /* required by bluetooth library */ - __bss_start = ABSOLUTE(.); - - _btdm_bss_start = ABSOLUTE(.); - *libbtdm_app.a:(.bss .bss.* COMMON) - . = ALIGN (4); - _btdm_bss_end = ABSOLUTE(.); - - /* Buffer for system heap should be placed in dram0_0_seg */ - *libkernel.a:mempool.*(.noinit.kheap_buf__system_heap .noinit.*.kheap_buf__system_heap) - - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - *(.dynbss) - *(.bss) - *(.bss.*) - *(.share.mem) - *(.gnu.linkonce.b.*) - *(COMMON) - . = ALIGN (8); - __bss_end = ABSOLUTE(.); - _end = ABSOLUTE(.); - } GROUP_LINK_IN(RAMABLE_REGION) - - ASSERT(((__bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), - "DRAM segment data does not fit.") - - SECTION_DATA_PROLOGUE(_NOINIT_SECTION_NAME, (NOLOAD),) - { - . = ALIGN (8); - *(.noinit) - *(.noinit.*) - . = ALIGN (8); - } GROUP_LINK_IN(RAMABLE_REGION_1) - - _image_irom_start = LOADADDR(.flash.text); - _image_irom_size = LOADADDR(.flash.text) + SIZEOF(.flash.text) - _image_irom_start; - _image_irom_vaddr = ADDR(.flash.text); - - .flash.text : ALIGN(4) - { - _stext = .; - _text_start = ABSOLUTE(.); - - *(.literal .text .literal.* .text.*) - . = ALIGN(4); - _text_end = ABSOLUTE(.); - _etext = .; - - /* Similar to _iram_start, this symbol goes here so it is - resolved by addr2line in preference to the first symbol in - the flash.text segment. - */ - _flash_cache_start = ABSOLUTE(0); - } GROUP_DATA_LINK_IN(FLASH_CODE_REGION, ROMABLE_REGION) - -_heap_sentry = 0x3ffe3f20; - -#include - - .xtensa.info 0 : { *(.xtensa.info) } - .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.*)) - } - -#ifdef CONFIG_GEN_ISR_TABLES -#include -#endif - -} - -ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), - "IRAM0 segment data does not fit.") diff --git a/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c b/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c deleted file mode 100644 index b0a0efcc4e6..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/newlib_fix.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2019, Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include - -#include - -int __weak _gettimeofday_r(struct _reent *r, struct timeval *__tp, void *__tzp) -{ - ARG_UNUSED(r); - ARG_UNUSED(__tp); - ARG_UNUSED(__tzp); - - return -1; -} diff --git a/soc/xtensa/espressif_esp32/esp32_net/soc.c b/soc/xtensa/espressif_esp32/esp32_net/soc.c deleted file mode 100644 index ac53ccb7e74..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/soc.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* Include esp-idf headers first to avoid redefining BIT() macro */ -#include "soc.h" -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "esp_private/system_internal.h" -#include "esp32/rom/cache.h" -#include "hal/soc_ll.h" -#include "soc/cpu.h" -#include "soc/gpio_periph.h" -#include "esp_spi_flash.h" -#include "esp_err.h" -#include "esp32/spiram.h" -#include "esp_app_format.h" -#include - -extern void z_cstart(void); - -/* - * This is written in C rather than assembly since, during the port bring up, - * Zephyr is being booted by the Espressif bootloader. With it, the C stack - * is already set up. - */ -void __app_cpu_start(void) -{ - extern uint32_t _init_start; - extern uint32_t _bss_start; - extern uint32_t _bss_end; - - /* Move the exception vector table to IRAM. */ - __asm__ __volatile__ ( - "wsr %0, vecbase" - : - : "r"(&_init_start)); - - /* Zero out BSS. Clobber _bss_start to avoid memset() elision. */ - z_bss_zero(); - - __asm__ __volatile__ ( - "" - : - : "g"(&__bss_start) - : "memory"); - - /* Disable normal interrupts. */ - __asm__ __volatile__ ( - "wsr %0, PS" - : - : "r"(PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE)); - - /* Initialize the architecture CPU pointer. Some of the - * initialization code wants a valid _current before - * arch_kernel_init() is invoked. - */ - __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); - - esp_intr_initialize(); - /* Start Zephyr */ - z_cstart(); - - CODE_UNREACHABLE; -} - -/* Boot-time static default printk handler, possibly to be overridden later. */ -int IRAM_ATTR arch_printk_char_out(int c) -{ - ARG_UNUSED(c); - return 0; -} - -void sys_arch_reboot(int type) -{ - esp_restart_noos(); -} - -void IRAM_ATTR esp_restart_noos(void) -{ - /* Disable interrupts */ - z_xt_ints_off(0xFFFFFFFF); - - const uint32_t core_id = cpu_hal_get_core_id(); - const uint32_t other_core_id = (core_id == 0) ? 1 : 0; - - soc_ll_reset_core(other_core_id); - soc_ll_stall_core(other_core_id); - - /* Flush any data left in UART FIFOs */ - esp_rom_uart_tx_wait_idle(0); - esp_rom_uart_tx_wait_idle(1); - esp_rom_uart_tx_wait_idle(2); - - /* Disable cache */ - Cache_Read_Disable(0); - Cache_Read_Disable(1); - - /* 2nd stage bootloader reconfigures SPI flash signals. */ - /* Reset them to the defaults expected by ROM */ - WRITE_PERI_REG(GPIO_FUNC0_IN_SEL_CFG_REG, 0x30); - WRITE_PERI_REG(GPIO_FUNC1_IN_SEL_CFG_REG, 0x30); - WRITE_PERI_REG(GPIO_FUNC2_IN_SEL_CFG_REG, 0x30); - WRITE_PERI_REG(GPIO_FUNC3_IN_SEL_CFG_REG, 0x30); - WRITE_PERI_REG(GPIO_FUNC4_IN_SEL_CFG_REG, 0x30); - WRITE_PERI_REG(GPIO_FUNC5_IN_SEL_CFG_REG, 0x30); - - /* Reset wifi/bluetooth/ethernet/sdio (bb/mac) */ - DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, - DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | - DPORT_BT_RST | DPORT_BTMAC_RST | - DPORT_SDIO_RST | DPORT_SDIO_HOST_RST | - DPORT_EMAC_RST | DPORT_MACPWR_RST | - DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); - DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); - - /* Reset timer/spi/uart */ - DPORT_SET_PERI_REG_MASK( - DPORT_PERIP_RST_EN_REG, - /* UART TX FIFO cannot be reset correctly on ESP32, */ - /* so reset the UART memory by DPORT here. */ - DPORT_TIMERS_RST | DPORT_SPI01_RST | DPORT_UART_RST | - DPORT_UART1_RST | DPORT_UART2_RST | DPORT_UART_MEM_RST); - DPORT_REG_WRITE(DPORT_PERIP_RST_EN_REG, 0); - - /* Clear entry point for APP CPU */ - DPORT_REG_WRITE(DPORT_APPCPU_CTRL_D_REG, 0); - - /* Reset CPUs */ - if (core_id == 0) { - /* Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. */ - soc_ll_reset_core(1); - soc_ll_reset_core(0); - } else { - /* Running on APP CPU: need to reset PRO CPU and unstall it, */ - /* then reset APP CPU */ - soc_ll_reset_core(0); - soc_ll_stall_core(0); - soc_ll_reset_core(1); - } - - while (true) { - ; - } -} diff --git a/soc/xtensa/espressif_esp32/esp32_net/soc.h b/soc/xtensa/espressif_esp32/esp32_net/soc.h deleted file mode 100644 index 7bd495bffb8..00000000000 --- a/soc/xtensa/espressif_esp32/esp32_net/soc.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2022 Espressif Systems (Shanghai) Co., Ltd. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __SOC_H__ -#define __SOC_H__ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -void __esp_platform_start(void); - -static inline void esp32_set_mask32(uint32_t v, uint32_t mem_addr) -{ - sys_write32(sys_read32(mem_addr) | v, mem_addr); -} - -static inline void esp32_clear_mask32(uint32_t v, uint32_t mem_addr) -{ - sys_write32(sys_read32(mem_addr) & ~v, mem_addr); -} - -static inline uint32_t esp_core_id(void) -{ - uint32_t id; - - __asm__ volatile ( - "rsr.prid %0\n" - "extui %0,%0,13,1" : "=r" (id)); - return id; -} - -extern void esp_rom_intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num); - -extern int esp_rom_gpio_matrix_in(uint32_t gpio, uint32_t signal_index, - bool inverted); -extern int esp_rom_gpio_matrix_out(uint32_t gpio, uint32_t signal_index, - bool out_inverted, - bool out_enabled_inverted); - -extern void esp_rom_uart_attach(void); -extern void esp_rom_uart_tx_wait_idle(uint8_t uart_no); -extern int esp_rom_uart_tx_one_char(uint8_t chr); -extern int esp_rom_uart_rx_one_char(uint8_t *chr); - -extern void esp_rom_Cache_Flush(int cpu); -extern void esp_rom_Cache_Read_Enable(int cpu); -extern void esp_rom_ets_set_appcpu_boot_addr(void *addr); - -/* ROM functions which read/write internal i2c control bus for PLL, APLL */ -extern uint8_t esp_rom_i2c_readReg(uint8_t block, uint8_t host_id, uint8_t reg_add); -extern void esp_rom_i2c_writeReg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data); - -/* ROM information related to SPI Flash chip timing and device */ -extern esp_rom_spiflash_chip_t g_rom_flashchip; -extern uint8_t g_rom_spiflash_dummy_len_plus[]; - -#endif /* __SOC_H__ */ diff --git a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series index c1618783ae5..177c5184e98 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s2/Kconfig.defconfig.series @@ -18,9 +18,6 @@ config MP_MAX_NUM_CPUS config ISR_STACK_SIZE default 2048 -config HEAP_MEM_POOL_SIZE - default 32768 - config ESPTOOLPY_FLASHFREQ_80M default y diff --git a/soc/xtensa/espressif_esp32/esp32s2/default.ld b/soc/xtensa/espressif_esp32/esp32s2/default.ld index 15f654d4b99..8a78bb89ac2 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s2/default.ld @@ -175,14 +175,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -192,6 +186,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. diff --git a/soc/xtensa/espressif_esp32/esp32s2/soc.c b/soc/xtensa/espressif_esp32/esp32s2/soc.c index 45edde47178..5e1ec21c075 100644 --- a/soc/xtensa/espressif_esp32/esp32s2/soc.c +++ b/soc/xtensa/espressif_esp32/esp32s2/soc.c @@ -37,6 +37,7 @@ #endif /* CONFIG_MCUBOOT */ extern void rtc_clk_cpu_freq_set_xtal(void); +extern void esp_reset_reason_init(void); #if CONFIG_ESP_SPIRAM extern int _ext_ram_bss_start; @@ -91,6 +92,8 @@ void __attribute__((section(".iram1"))) __esp_platform_start(void) */ __asm__ volatile("wsr.MISC0 %0; rsync" : : "r"(&_kernel.cpus[0])); + esp_reset_reason_init(); + #ifdef CONFIG_MCUBOOT /* MCUboot early initialisation. */ if (bootloader_init()) { diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series index 31f7bdbff50..30d0480cad2 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.defconfig.series @@ -6,9 +6,6 @@ if SOC_SERIES_ESP32S3 config SOC_SERIES default "esp32s3" -config HEAP_MEM_POOL_SIZE - default 32768 - config MINIMAL_LIBC_OPTIMIZE_STRING_FOR_SIZE default n diff --git a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc index b8cc95b62cb..ad8b4b4234b 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc +++ b/soc/xtensa/espressif_esp32/esp32s3/Kconfig.soc @@ -43,7 +43,13 @@ choice SOC_PART_NUMBER config SOC_ESP32S3_WROOM_N8R8 bool "ESP32S3_WROOM_N8R8" config SOC_ESP32S3_WROOM_N16R8 - bool "ESP32S3_WROOM_N16" + bool "ESP32S3_WROOM_N16R8" + config SOC_ESP32S3_WROOM_N4R2 + bool "ESP32S3_WROOM_N4R2" + config SOC_ESP32S3_WROOM_N8R2 + bool "ESP32S3_WROOM_N8R2" + config SOC_ESP32S3_WROOM_N16R2 + bool "ESP32S3_WROOM_N16R2" endchoice # SOC_PART_NUMBER diff --git a/soc/xtensa/espressif_esp32/esp32s3/default.ld b/soc/xtensa/espressif_esp32/esp32s3/default.ld index 90b6c89ada2..4076ea7c1af 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/default.ld +++ b/soc/xtensa/espressif_esp32/esp32s3/default.ld @@ -211,14 +211,8 @@ SECTIONS *(.gnu.linkonce.lit4.*) _lit4_end = ABSOLUTE(.); . = ALIGN(4); - _thread_local_start = ABSOLUTE(.); - *(.tdata) - *(.tdata.*) - *(.tbss) - *(.tbss.*) *(.rodata_wlog) *(.rodata_wlog*) - _thread_local_end = ABSOLUTE(.); . = ALIGN(4); } GROUP_DATA_LINK_IN(RODATA_REGION, ROMABLE_REGION) @@ -229,6 +223,7 @@ SECTIONS #include #include #include + #include #include /* Create an explicit section at the end of all the data that shall be mapped into drom. diff --git a/soc/xtensa/espressif_esp32/esp32s3/soc.c b/soc/xtensa/espressif_esp32/esp32s3/soc.c index ad971b907b2..d250657c49e 100644 --- a/soc/xtensa/espressif_esp32/esp32s3/soc.c +++ b/soc/xtensa/espressif_esp32/esp32s3/soc.c @@ -47,6 +47,7 @@ extern int _ext_ram_bss_end; #endif extern void z_cstart(void); +extern void esp_reset_reason_init(void); #ifdef CONFIG_SOC_ESP32S3_PROCPU extern const unsigned char esp32s3_appcpu_fw_array[]; @@ -184,6 +185,8 @@ void IRAM_ATTR __esp_platform_start(void) wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); + esp_reset_reason_init(); + esp_clk_init(); esp_timer_early_init(); diff --git a/soc/xtensa/intel_adsp/Kconfig b/soc/xtensa/intel_adsp/Kconfig index a3d93d976ea..32dae7612f5 100644 --- a/soc/xtensa/intel_adsp/Kconfig +++ b/soc/xtensa/intel_adsp/Kconfig @@ -7,6 +7,8 @@ config SOC_FAMILY_INTEL_ADSP select WINSTREAM select ARCH_SUPPORTS_COREDUMP select CPU_HAS_DCACHE + select ARCH_HAS_USERSPACE if XTENSA_MMU + select CPU_CACHE_INCOHERENT bool if SOC_FAMILY_INTEL_ADSP @@ -125,4 +127,12 @@ config XTENSA_WAITI_BUG platforms which prefixes a WAITI entry with 128 NOP instructions followed by an ISYNC and EXTW. +config ADSP_IDLE_CLOCK_GATING + bool "DSP clock gating in Idle" + help + When true, FW will run with enabled clock gating. This options change + HW configuration of a DSP. Evry time core goes to the WAITI state + (wait for interrupt) during idle, the clock can be gated (however, this + does not mean that this will happen). + endif # SOC_FAMILY_INTEL_ADSP diff --git a/soc/xtensa/intel_adsp/ace/CMakeLists.txt b/soc/xtensa/intel_adsp/ace/CMakeLists.txt index a5aa90b59d0..28626787c5e 100644 --- a/soc/xtensa/intel_adsp/ace/CMakeLists.txt +++ b/soc/xtensa/intel_adsp/ace/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources( power_down.S power.c boot.c + timestamp.c ) zephyr_include_directories(include) diff --git a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series index 198f0b35f70..5057e5cb16a 100644 --- a/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series +++ b/soc/xtensa/intel_adsp/ace/Kconfig.defconfig.series @@ -14,6 +14,9 @@ config SOC_TOOLCHAIN_NAME config SMP default y +config POWER_DOMAIN + default y + # MTL leaves the upper mapping in the same spot as cAVS, but moves the # lower one inexplicably. config XTENSA_UNCACHED_REGION diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_imr_layout.h b/soc/xtensa/intel_adsp/ace/include/adsp_imr_layout.h similarity index 100% rename from soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_imr_layout.h rename to soc/xtensa/intel_adsp/ace/include/adsp_imr_layout.h diff --git a/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h b/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h new file mode 100644 index 00000000000..4c7796a5ae4 --- /dev/null +++ b/soc/xtensa/intel_adsp/ace/include/adsp_timestamp.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ +#define ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ + +#include + +/* Captured timestamp data - contains a copy of all DfTTS snapshot registers. */ +struct intel_adsp_timestamp { + uint32_t iscs; /* copy of DfISCS register */ + uint64_t lscs; /* copy of DfLSCS register */ + uint64_t dwccs; /* copy of DfDWCCS register */ + uint64_t artcs; /* copy of DfARTCS register */ + uint32_t lwccs; /* copy of DfLWCCS register */ +}; + +/* + * @brief Perform timestamping process using DfTTS logic. + * + * @param tsctrl Value to be applied to DfTSCTRL register to control timestamping logic + * @param timestamp Captured timestamp data + */ +int intel_adsp_get_timestamp(uint32_t tsctrl, struct intel_adsp_timestamp *timestamp); + +#endif /* ZEPHYR_SOC_INTEL_ADSP_ACE_TIMESTAMP_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h index 6efcde4a491..4da0e07508c 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_power.h @@ -88,5 +88,18 @@ static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); } +/** + * @brief Retrieve node identifier for Intel ADSP HOST power domain. + */ +#define INTEL_ADSP_HST_DOMAIN_DTNODE DT_NODELABEL(hst_domain) + +/** + * @brief Intel ADSP HOST power domain pointer. + */ +#define INTEL_ADSP_HST_DOMAIN_DEV DEVICE_DT_GET(INTEL_ADSP_HST_DOMAIN_DTNODE) + +#define INTEL_ADSP_HST_DOMAIN_BIT DT_PROP(INTEL_ADSP_HST_DOMAIN_DTNODE, bit_position) + +#define INTEL_ADSP_ACE15_MAGIC_KEY 0xFFFACE15 #endif /* ZEPHYR_SOC_INTEL_ADSP_POWER_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h index 56997ee84d1..521dc4e5fb1 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace15_mtpm/adsp_shim.h @@ -8,6 +8,8 @@ #ifndef _ASMLANGUAGE +#include + /** * DfPMCCH * Power Management / Clock Control (HST) Registers @@ -138,6 +140,15 @@ struct ace_dfpmccu { #define ADSP_SHIM_DSPWCTCS_TTIE(c) BIT(8 + (c)) +#define ADSP_SHIM_TSCTRL_NTK BIT(31) +#define ADSP_SHIM_TSCTRL_IONTE BIT(30) +#define ADSP_SHIM_TSCTRL_DMATS GENMASK(13, 12) +#define ADSP_SHIM_TSCTRL_CLNKS GENMASK(11, 10) +#define ADSP_SHIM_TSCTRL_HHTSE BIT(7) +#define ADSP_SHIM_TSCTRL_LWCS BIT(6) +#define ADSP_SHIM_TSCTRL_ODTS BIT(5) +#define ADSP_SHIM_TSCTRL_CDMAS GENMASK(4, 0) + #endif /* _ASMLANGUAGE */ #define ACE_CLKCTL_WOVCRO BIT(21) /* Request WOVCRO clock */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h deleted file mode 100644 index 6e953991a81..00000000000 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_imr_layout.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2022 Intel Corporation - * SPDX-License-Identifier: Apache-2.0 - */ -#ifndef ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ -#define ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ - -/* These structs and macros are from from the ROM code header - * on cAVS platforms, please keep them immutable - */ - -/* - * A magic that tells ROM to jump to imr_restore_vector instead of normal boot - */ -#define ADSP_IMR_MAGIC_VALUE 0x02468ACE -#define IMR_LAYOUT_OFFSET 0x20000 -#define IMR_LAYOUT_ADDRESS (L3_MEM_BASE_ADDR + IMR_LAYOUT_OFFSET) - -struct imr_header { - uint32_t adsp_imr_magic; - uint32_t structure_version; - uint32_t structure_size; - uint32_t imr_state; - uint32_t imr_size; - void *imr_restore_vector; - void *imr_auth_api_vector; - uint8_t *imr_ram_storage; -}; - -struct imr_state { - struct imr_header header; - uint8_t reserved[0x1000 - sizeof(struct imr_header)]; -}; - -struct imr_layout { - struct imr_state imr_state; -}; - -#endif /* ZEPHYR_SOC_INTEL_ADSP_ACE_IMR_LAYOUT_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h index 60631945da3..5d12c79fdcb 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_power.h @@ -88,4 +88,14 @@ static ALWAYS_INLINE bool soc_cpu_is_powered(int cpu_num) return (ACE_PWRSTS->dsphpxpgs & BIT(cpu_num)) == BIT(cpu_num); } +/** + * @brief Retrieve node identifier for Intel ADSP HOST power domain. + */ +#define INTEL_ADSP_HST_DOMAIN_DTNODE DT_NODELABEL(hst_domain) + +/** + * @brief Intel ADSP HOST power domain pointer. + */ +#define INTEL_ADSP_HST_DOMAIN_DEV DEVICE_DT_GET(INTEL_ADSP_HST_DOMAIN_DTNODE) + #endif /* ZEPHYR_SOC_INTEL_ADSP_POWER_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h index 363feb14fa0..f640a0a9f59 100644 --- a/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h +++ b/soc/xtensa/intel_adsp/ace/include/intel_ace20_lnl/adsp_shim.h @@ -8,6 +8,8 @@ #ifndef _ASMLANGUAGE +#include + /** * DfPMCCH * Power Management / Clock Control (HST) Registers @@ -138,6 +140,15 @@ struct ace_dfpmccu { #define ADSP_SHIM_DSPWCTCS_TTIE(c) BIT(8 + (c)) +#define ADSP_SHIM_TSCTRL_NTK BIT(31) +#define ADSP_SHIM_TSCTRL_IONTE BIT(30) +#define ADSP_SHIM_TSCTRL_DMATS GENMASK(13, 12) +#define ADSP_SHIM_TSCTRL_CLNKS GENMASK(11, 10) +#define ADSP_SHIM_TSCTRL_HHTSE BIT(7) +#define ADSP_SHIM_TSCTRL_LWCS BIT(6) +#define ADSP_SHIM_TSCTRL_ODTS BIT(5) +#define ADSP_SHIM_TSCTRL_CDMAS GENMASK(4, 0) + #endif /* _ASMLANGUAGE */ #define ACE_CLKCTL_WOVCRO BIT(4) /* Request WOVCRO clock */ @@ -170,4 +181,6 @@ struct ace_dfpmccu { #define GENO_MDIVOSEL BIT(1) #define GENO_DIOPTOSEL BIT(2) +#define ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT BIT(1) + #endif /* ZEPHYR_SOC_INTEL_ADSP_SHIM_H_ */ diff --git a/soc/xtensa/intel_adsp/ace/multiprocessing.c b/soc/xtensa/intel_adsp/ace/multiprocessing.c index e762245e669..3170a8f1090 100644 --- a/soc/xtensa/intel_adsp/ace/multiprocessing.c +++ b/soc/xtensa/intel_adsp/ace/multiprocessing.c @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include @@ -25,6 +27,11 @@ #define ACE_INTC_IRQ DT_IRQN(DT_NODELABEL(ace_intc)) +#if CONFIG_SOC_INTEL_ACE15_MTPM +/* .bss is uncached, we further check it below */ +uint32_t g_key_read_holder; +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ + static void ipc_isr(void *arg) { uint32_t cpu_id = arch_proc_id(); @@ -81,8 +88,25 @@ void soc_mp_init(void) /* Set the core 0 active */ soc_cpus_active[0] = true; +#if CONFIG_SOC_INTEL_ACE15_MTPM +#if defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) + /* + * Only when more than 1 CPUs is enabled, then this is in uncached area. + * Otherwise, this is in cached area and will fail this test. + */ + __ASSERT(!sys_cache_is_ptr_cached(&g_key_read_holder), + "g_key_read_holder must be uncached"); +#endif /* defined(CONFIG_SMP) && (CONFIG_MP_MAX_NUM_CPUS > 1) */ + g_key_read_holder = INTEL_ADSP_ACE15_MAGIC_KEY; +#endif /* CONFIG_SOC_INTEL_ACE15_MTPM */ } +static int host_runtime_get(void) +{ + return pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); +} +SYS_INIT(host_runtime_get, POST_KERNEL, 99); + #ifdef CONFIG_ADSP_IMR_CONTEXT_SAVE /* * Called after exiting D3 state when context restore is enabled. @@ -159,11 +183,15 @@ void soc_start_core(int cpu_num) void soc_mp_startup(uint32_t cpu) { /* Must have this enabled always */ - z_xtensa_irq_enable(ACE_INTC_IRQ); + xtensa_irq_enable(ACE_INTC_IRQ); - /* Prevent idle from powering us off */ - DSPCS.bootctl[cpu].bctl |= - DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#if CONFIG_ADSP_IDLE_CLOCK_GATING + /* Disable idle power gating */ + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPPG; +#else + /* Disable idle power and clock gating */ + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ } void arch_sched_ipi(void) diff --git a/soc/xtensa/intel_adsp/ace/power.c b/soc/xtensa/intel_adsp/ace/power.c index 7fe33c3feaf..b77246ad50e 100644 --- a/soc/xtensa/intel_adsp/ace/power.c +++ b/soc/xtensa/intel_adsp/ace/power.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -26,8 +27,13 @@ __imr void power_init(void) { +#if CONFIG_ADSP_IDLE_CLOCK_GATING /* Disable idle power gating */ + DSPCS.bootctl[0].bctl |= DSPBR_BCTL_WAITIPPG; +#else + /* Disable idle power and clock gating */ DSPCS.bootctl[0].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ } #ifdef CONFIG_PM @@ -105,6 +111,7 @@ struct core_state { uint32_t excsave3; uint32_t thread_ptr; uint32_t intenable; + uint32_t ps; uint32_t bctl; }; @@ -121,6 +128,7 @@ struct lpsram_header { static ALWAYS_INLINE void _save_core_context(uint32_t core_id) { + core_desc[core_id].ps = XTENSA_RSR("PS"); core_desc[core_id].vecbase = XTENSA_RSR("VECBASE"); core_desc[core_id].excsave2 = XTENSA_RSR("EXCSAVE2"); core_desc[core_id].excsave3 = XTENSA_RSR("EXCSAVE3"); @@ -134,6 +142,7 @@ static ALWAYS_INLINE void _restore_core_context(void) { uint32_t core_id = arch_proc_id(); + XTENSA_WSR("PS", core_desc[core_id].ps); XTENSA_WSR("VECBASE", core_desc[core_id].vecbase); XTENSA_WSR("EXCSAVE2", core_desc[core_id].excsave2); XTENSA_WSR("EXCSAVE3", core_desc[core_id].excsave3); @@ -144,6 +153,7 @@ static ALWAYS_INLINE void _restore_core_context(void) } void dsp_restore_vector(void); +void mp_resume_entry(void); void power_gate_entry(uint32_t core_id) { @@ -174,6 +184,11 @@ void power_gate_exit(void) cpu_early_init(); sys_cache_data_flush_and_invd_all(); _restore_core_context(); + + /* Secondary core is resumed by set_dx */ + if (arch_proc_id()) { + mp_resume_entry(); + } } __asm__(".align 4\n\t" @@ -212,7 +227,7 @@ __imr void pm_state_imr_restore(void) { struct imr_layout *imr_layout = (struct imr_layout *)(IMR_LAYOUT_ADDRESS); /* restore lpsram power and contents */ - bmemcpy(z_soc_uncached_ptr((__sparse_force void __sparse_cache *) + bmemcpy(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) UINT_TO_POINTER(LP_SRAM_BASE)), imr_layout->imr_state.header.imr_ram_storage, LP_SRAM_SIZE); @@ -229,12 +244,16 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) { ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); + int ret; + + ARG_UNUSED(ret); /* save interrupt state and turn off all interrupts */ core_desc[cpu].intenable = XTENSA_RSR("INTENABLE"); z_xt_ints_off(0xffffffff); - if (state == PM_STATE_SOFT_OFF) { + switch (state) { + case PM_STATE_SOFT_OFF: core_desc[cpu].bctl = DSPCS.bootctl[cpu].bctl; DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG; if (cpu == 0) { @@ -291,12 +310,15 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) hpsram_mask = (1 << ebb_banks) - 1; #endif /* CONFIG_ADSP_POWER_DOWN_HPSRAM */ /* do power down - this function won't return */ + ret = pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV); + __ASSERT_NO_MSG(ret == 0); power_down(true, uncache_to_cache(&hpsram_mask), true); } else { power_gate_entry(cpu); } - } else if (state == PM_STATE_RUNTIME_IDLE) { + break; + case PM_STATE_RUNTIME_IDLE: DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPPG; DSPCS.bootctl[cpu].bctl &= ~DSPBR_BCTL_WAITIPCG; soc_cpu_power_down(cpu); @@ -306,8 +328,12 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) battr |= (DSPBR_BATTR_LPSCTL_RESTORE_BOOT & LPSCTL_BATTR_MASK); DSPCS.bootctl[cpu].battr = battr; } + + ret = pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV); + __ASSERT_NO_MSG(ret == 0); power_gate_entry(cpu); - } else { + break; + default: __ASSERT(false, "invalid argument - unsupported power state"); } } @@ -318,6 +344,13 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) ARG_UNUSED(substate_id); uint32_t cpu = arch_proc_id(); + if (cpu == 0) { + int ret = pm_device_runtime_get(INTEL_ADSP_HST_DOMAIN_DEV); + + ARG_UNUSED(ret); + __ASSERT_NO_MSG(ret == 0); + } + if (state == PM_STATE_SOFT_OFF) { /* restore clock gating state */ DSPCS.bootctl[cpu].bctl |= @@ -358,8 +391,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) k_panic(); } - DSPCS.bootctl[cpu].bctl |= - DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#if CONFIG_ADSP_IDLE_CLOCK_GATING + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPPG; +#else + DSPCS.bootctl[cpu].bctl |= DSPBR_BCTL_WAITIPCG | DSPBR_BCTL_WAITIPPG; +#endif /* CONFIG_ADSP_IDLE_CLOCK_GATING */ if (cpu == 0) { DSPCS.bootctl[cpu].battr &= (~LPSCTL_BATTR_MASK); } @@ -371,6 +407,11 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } z_xt_ints_on(core_desc[cpu].intenable); + + /* We don't have the key used to lock interruptions here. + * Just set PS.INTLEVEL to 0. + */ + __asm__ volatile ("rsil a2, 0"); } -#endif +#endif /* CONFIG_PM */ diff --git a/soc/xtensa/intel_adsp/ace/timestamp.c b/soc/xtensa/intel_adsp/ace/timestamp.c new file mode 100644 index 00000000000..7f3168d87f4 --- /dev/null +++ b/soc/xtensa/intel_adsp/ace/timestamp.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define TTS_BASE_ADDR DT_REG_ADDR(DT_NODELABEL(tts)) + +#define TSCTRL_ADDR (TTS_BASE_ADDR + ADSP_TSCTRL_OFFSET) +#define ISCS_ADDR (TTS_BASE_ADDR + ADSP_ISCS_OFFSET) +#define LSCS_ADDR (TTS_BASE_ADDR + ADSP_LSCS_OFFSET) +#define DWCCS_ADDR (TTS_BASE_ADDR + ADSP_DWCCS_OFFSET) +#define ARTCS_ADDR (TTS_BASE_ADDR + ADSP_ARTCS_OFFSET) +#define LWCCS_ADDR (TTS_BASE_ADDR + ADSP_LWCCS_OFFSET) + +/* Copies the bit-field specified by mask from src to dest */ +#define BITS_COPY(dest, src, mask) ((dest) = ((dest) & ~(mask)) | ((src) & (mask))) + +static struct k_spinlock lock; + +int intel_adsp_get_timestamp(uint32_t tsctrl, struct intel_adsp_timestamp *timestamp) +{ + uint32_t trigger_mask = ADSP_SHIM_TSCTRL_HHTSE | ADSP_SHIM_TSCTRL_ODTS; + uint32_t trigger_bits = tsctrl & trigger_mask; + uint32_t tsctrl_temp; + k_spinlock_key_t key; + int ret = 0; + + /* Exactly one trigger bit must be set in a valid request */ + if (POPCOUNT(trigger_bits) != 1) { + return -EINVAL; + } + + key = k_spin_lock(&lock); + + tsctrl_temp = sys_read32(TSCTRL_ADDR); + + /* Abort if any timestamp capture in progress */ + if (tsctrl_temp & trigger_mask) { + ret = -EBUSY; + goto out; + } + + /* Clear NTK (RW/1C) bit if needed */ + if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) { + sys_write32(tsctrl_temp, TSCTRL_ADDR); + tsctrl_temp &= ~ADSP_SHIM_TSCTRL_NTK; + } + + /* Setup the timestamping logic according to request */ + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_IONTE); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_DMATS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CLNKS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_LWCS); + BITS_COPY(tsctrl_temp, tsctrl, ADSP_SHIM_TSCTRL_CDMAS); + sys_write32(tsctrl_temp, TSCTRL_ADDR); + + /* Start new timestamp capture by setting one of mutually exclusive + * trigger bits. + */ + tsctrl_temp |= trigger_bits; + sys_write32(tsctrl_temp, TSCTRL_ADDR); + + /* Wait for timestamp capture to complete */ + while (1) { + tsctrl_temp = sys_read32(TSCTRL_ADDR); + if (tsctrl_temp & ADSP_SHIM_TSCTRL_NTK) { + break; + } + } + + /* Copy the timestamp data from HW registers to the snapshot buffer + * provided by caller. As NTK bit is high at this stage, the timestamp + * data in HW is guaranteed to be valid and static. + */ + timestamp->iscs = sys_read32(ISCS_ADDR); + timestamp->lscs = sys_read64(LSCS_ADDR); + timestamp->dwccs = sys_read64(DWCCS_ADDR); + timestamp->artcs = sys_read64(ARTCS_ADDR); + timestamp->lwccs = sys_read32(LWCCS_ADDR); + + /* Clear NTK (RW/1C) bit */ + tsctrl_temp |= ADSP_SHIM_TSCTRL_NTK; + sys_write32(tsctrl_temp, TSCTRL_ADDR); + +out: + k_spin_unlock(&lock, key); + + return ret; +} diff --git a/soc/xtensa/intel_adsp/cavs/Kconfig.series b/soc/xtensa/intel_adsp/cavs/Kconfig.series index adbc1f39e1d..a88bec1ec2e 100644 --- a/soc/xtensa/intel_adsp/cavs/Kconfig.series +++ b/soc/xtensa/intel_adsp/cavs/Kconfig.series @@ -9,6 +9,7 @@ config SOC_SERIES_INTEL_ADSP_CAVS select XTENSA_RESET_VECTOR select XTENSA_USE_CORE_CRT1 select ATOMIC_OPERATIONS_BUILTIN if "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" + select ATOMIC_OPERATIONS_ARCH if "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "xcc" select ARCH_HAS_COHERENCE select HAS_PM help diff --git a/soc/xtensa/intel_adsp/cavs/irq.c b/soc/xtensa/intel_adsp/cavs/irq.c index c273e5252bb..dc9a573a3b1 100644 --- a/soc/xtensa/intel_adsp/cavs/irq.c +++ b/soc/xtensa/intel_adsp/cavs/irq.c @@ -42,7 +42,7 @@ void z_soc_irq_enable(uint32_t irq) break; default: /* regular interrupt */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); return; } @@ -55,7 +55,7 @@ void z_soc_irq_enable(uint32_t irq) * The specified interrupt is in CAVS interrupt controller. * So enable core interrupt first. */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); /* Then enable the interrupt in CAVS interrupt controller */ irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq)); @@ -80,7 +80,7 @@ void z_soc_irq_disable(uint32_t irq) break; default: /* regular interrupt */ - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); return; } @@ -97,7 +97,7 @@ void z_soc_irq_disable(uint32_t irq) /* Then disable the parent IRQ if all children are disabled */ if (!irq_is_enabled_next_level(dev_cavs)) { - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); + xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); } } @@ -121,7 +121,7 @@ int z_soc_irq_is_enabled(unsigned int irq) break; default: /* regular interrupt */ - ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); + ret = xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); goto out; } diff --git a/soc/xtensa/intel_adsp/cavs/multiprocessing.c b/soc/xtensa/intel_adsp/cavs/multiprocessing.c index 85d834065a7..2a38f20355d 100644 --- a/soc/xtensa/intel_adsp/cavs/multiprocessing.c +++ b/soc/xtensa/intel_adsp/cavs/multiprocessing.c @@ -5,9 +5,9 @@ #include #include #include -#include #include #include +#include /* IDC power up message to the ROM firmware. This isn't documented * anywhere, it's basically just a magic number (except the high bit, @@ -62,7 +62,8 @@ void soc_start_core(int cpu_num) * such that the standard system bootstrap out of IMR can * place it there. But this is fine for now. */ - void **lpsram = z_soc_uncached_ptr((__sparse_force void __sparse_cache *)LP_SRAM_BASE); + void **lpsram = sys_cache_uncached_ptr_get( + (__sparse_force void __sparse_cache *)LP_SRAM_BASE); uint8_t tramp[] = { 0x06, 0x01, 0x00, /* J (jump to L32R) */ 0, /* (padding to align entry_addr) */ @@ -186,19 +187,25 @@ __imr void soc_mp_init(void) int soc_adsp_halt_cpu(int id) { + unsigned int irq_mask; + if (id == 0 || id == arch_curr_cpu()->id) { return -EINVAL; } + irq_mask = CAVS_L2_IDC; + #ifdef CONFIG_INTEL_ADSP_TIMER /* * Mask timer interrupt for this CPU so it won't wake up * by itself once WFI (wait for interrupt) instruction * runs. */ - CAVS_INTCTRL[id].l2.set = CAVS_L2_DWCT0; + irq_mask |= CAVS_L2_DWCT0; #endif + CAVS_INTCTRL[id].l2.set = irq_mask; + /* Stop sending IPIs to this core */ soc_cpus_active[id] = false; diff --git a/soc/xtensa/intel_adsp/cavs/power.c b/soc/xtensa/intel_adsp/cavs/power.c index c0a75f5c0ec..704d7aa9d3f 100644 --- a/soc/xtensa/intel_adsp/cavs/power.c +++ b/soc/xtensa/intel_adsp/cavs/power.c @@ -20,7 +20,6 @@ #include #include #include -#include "soc.h" #ifdef CONFIG_DYNAMIC_INTERRUPTS #include @@ -52,6 +51,7 @@ LOG_MODULE_REGISTER(soc); * @biref FW entry point called by ROM during normal boot flow */ extern void rom_entry(void); +void mp_resume_entry(void); struct core_state { uint32_t a0; @@ -104,6 +104,11 @@ void power_gate_exit(void) cpu_early_init(); sys_cache_data_flush_and_invd_all(); _restore_core_context(); + + /* Secondary core is resumed by set_dx */ + if (arch_proc_id()) { + mp_resume_entry(); + } } __asm__(".align 4\n\t" @@ -144,7 +149,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) .imr_restore_vector = rom_entry, }; struct imr_layout *imr_layout = - z_soc_uncached_ptr((__sparse_force void __sparse_cache *) + sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) L3_MEM_BASE_ADDR); imr_layout->imr_state.header = hdr; @@ -157,7 +162,7 @@ void pm_state_set(enum pm_state state, uint8_t substate_id) /* do power down - this function won't return */ power_down_cavs(true, uncache_to_cache(&hpsram_mask[0])); } else { - k_cpu_idle(); + k_cpu_atomic_idle(arch_irq_lock()); } } else { __ASSERT(false, "invalid argument - unsupported power state"); @@ -177,6 +182,12 @@ void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) } else { __ASSERT(false, "invalid argument - unsupported power state"); } + + /** + * We don't have the key used to lock interruptions here. + * Just set PS.INTLEVEL to 0. + */ + __asm__ volatile ("rsil a2, 0"); } #endif /* CONFIG_PM */ diff --git a/soc/xtensa/intel_adsp/common/boot_complete.c b/soc/xtensa/intel_adsp/common/boot_complete.c index 445fd57b064..3d27ae18d13 100644 --- a/soc/xtensa/intel_adsp/common/boot_complete.c +++ b/soc/xtensa/intel_adsp/common/boot_complete.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include @@ -22,7 +22,7 @@ int boot_complete(void) } config = dev->config; - win = z_soc_uncached_ptr((__sparse_force void __sparse_cache *)config->mem_base); + win = sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *)config->mem_base); /* Software protocol: "firmware entered" has the value 5 */ win[0] = 5; diff --git a/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h b/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h index ddd94e77ce3..868d549c5e5 100644 --- a/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h +++ b/soc/xtensa/intel_adsp/common/include/adsp_debug_window.h @@ -6,6 +6,7 @@ #include #include +#include /* * SRAM window for debug info (window 2) is organized in slots, @@ -67,7 +68,7 @@ struct adsp_debug_window { #define WIN2_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window2), memory)) #define ADSP_DW ((volatile struct adsp_debug_window *) \ - (z_soc_uncached_ptr((__sparse_force void __sparse_cache *) \ + (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \ (WIN2_MBASE + WIN2_OFFSET)))) #endif diff --git a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h index 2b403eb17a4..f56c77e2523 100644 --- a/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h +++ b/soc/xtensa/intel_adsp/common/include/intel_adsp_hda.h @@ -10,6 +10,7 @@ #include #include #include +#include /** * @brief HDA stream functionality for Intel ADSP @@ -27,6 +28,8 @@ /* Buffers must be 128 byte aligned, this mask enforces that */ #define HDA_ALIGN_MASK 0xFFFFFF80 +/* Buffer size must match the mask of BS field in DGBS register */ +#define HDA_BUFFER_SIZE_MASK 0x00FFFFF0 /* Calculate base address of the stream registers */ #define HDA_ADDR(base, regblock_size, stream) ((base) + (stream)*(regblock_size)) @@ -156,16 +159,16 @@ static inline int intel_adsp_hda_set_buffer(uint32_t base, * region or not, we do need a consistent address space to check * against for our assertion. This is cheap. */ - uint32_t addr = (uint32_t)arch_xtensa_cached_ptr(buf); + uint32_t addr = (uint32_t)sys_cache_cached_ptr_get(buf); uint32_t aligned_addr = addr & HDA_ALIGN_MASK; - uint32_t aligned_size = buf_size & HDA_ALIGN_MASK; + uint32_t aligned_size = buf_size & HDA_BUFFER_SIZE_MASK; __ASSERT(aligned_addr == addr, "Buffer must be 128 byte aligned"); __ASSERT(aligned_addr >= L2_SRAM_BASE && aligned_addr < L2_SRAM_BASE + L2_SRAM_SIZE, "Buffer must be in L2 address space"); __ASSERT(aligned_size == buf_size, - "Buffer must be 128 byte aligned in size"); + "Buffer must be 16 byte aligned in size"); __ASSERT(aligned_addr + aligned_size < L2_SRAM_BASE + L2_SRAM_SIZE, "Buffer must end in L2 address space"); @@ -441,6 +444,20 @@ static inline void intel_adsp_hda_disable_buffer_interrupt(uint32_t base, uint32 *DGCS(base, regblock_size, sid) &= ~DGCS_BSCIE; } +static inline void intel_adsp_force_dmi_l0_state(void) +{ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg |= ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT; +#endif +} + +static inline void intel_adsp_allow_dmi_l1_state(void) +{ +#ifdef CONFIG_SOC_SERIES_INTEL_ACE + ACE_DfPMCCH.svcfg &= ~(ADSP_FORCE_DECOUPLED_HDMA_L1_EXIT_BIT); +#endif +} + /** * @brief Clear BSC interrupt * diff --git a/soc/xtensa/intel_adsp/common/include/soc.h b/soc/xtensa/intel_adsp/common/include/soc.h index 014ba18e434..1db8320428f 100644 --- a/soc/xtensa/intel_adsp/common/include/soc.h +++ b/soc/xtensa/intel_adsp/common/include/soc.h @@ -26,10 +26,6 @@ extern void soc_start_core(int cpu_num); extern bool soc_cpus_active[CONFIG_MP_MAX_NUM_CPUS]; -/* Legacy cache APIs still used in a few places */ -#define z_soc_cached_ptr(p) arch_xtensa_cached_ptr(p) -#define z_soc_uncached_ptr(p) arch_xtensa_uncached_ptr(p) - /** * @brief Halts and offlines a running CPU * diff --git a/soc/xtensa/intel_adsp/common/ipc.c b/soc/xtensa/intel_adsp/common/ipc.c index cdb5757d356..6ae1956ffac 100644 --- a/soc/xtensa/intel_adsp/common/ipc.c +++ b/soc/xtensa/intel_adsp/common/ipc.c @@ -82,7 +82,6 @@ void z_intel_adsp_ipc_isr(const void *devarg) } regs->ida = INTEL_ADSP_IPC_DONE; - pm_device_busy_clear(dev); } k_spin_unlock(&devdata->lock, key); @@ -163,6 +162,7 @@ int intel_adsp_ipc_send_message(const struct device *dev, config->regs->idd = ext_data; config->regs->idr = data | INTEL_ADSP_IPC_BUSY; k_spin_unlock(&devdata->lock, key); + pm_device_busy_clear(dev); return 0; } diff --git a/soc/xtensa/intel_adsp/common/multiprocessing.c b/soc/xtensa/intel_adsp/common/multiprocessing.c index de76fa37eac..79d7d1883e0 100644 --- a/soc/xtensa/intel_adsp/common/multiprocessing.c +++ b/soc/xtensa/intel_adsp/common/multiprocessing.c @@ -110,6 +110,11 @@ __imr void z_mp_entry(void) __ASSERT(false, "arch_start_cpu() handler should never return"); } +void mp_resume_entry(void) +{ + start_rec.fn(start_rec.arg); +} + bool arch_cpu_active(int cpu_num) { return soc_cpus_active[cpu_num]; diff --git a/soc/xtensa/intel_adsp/tools/acetool.py b/soc/xtensa/intel_adsp/tools/acetool.py new file mode 100755 index 00000000000..0d0897c0234 --- /dev/null +++ b/soc/xtensa/intel_adsp/tools/acetool.py @@ -0,0 +1,727 @@ +#!/usr/bin/env python3 +# Copyright(c) 2022 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import os +import sys +import struct +import logging +import asyncio +import time +import subprocess +import ctypes +import mmap +import argparse + +start_output = True + +logging.basicConfig(level=logging.INFO) +log = logging.getLogger("ace-fw") + +PAGESZ = 4096 +HUGEPAGESZ = 2 * 1024 * 1024 +HUGEPAGE_FILE = "/dev/hugepages/ace-fw-dma.tmp." + +# SRAM windows. Each appears in a 128k region starting at 512k. +# +# Window 0 is the FW_STATUS area, and 4k after that the IPC "outbox" +# Window 1 is the IPC "inbox" (host-writable memory, just 384 bytes currently) +# Window 2 is unused by this script +# Window 3 is winstream-formatted log output +WINDOW_BASE = 0x180000 +WINDOW_STRIDE = 0x8000 + +OUTBOX_OFFSET = (512 + (0 * 128)) * 1024 + 4096 +INBOX_OFFSET = (512 + (1 * 128)) * 1024 +WINSTREAM_OFFSET = WINDOW_BASE + WINDOW_STRIDE*3 + +# ADSPCS bits +CRST = 0 +CSTALL = 8 +SPA = 16 +CPA = 24 + +class HDAStream: + # creates an hda stream with at 2 buffers of buf_len + def __init__(self, stream_id: int): + self.stream_id = stream_id + self.base = hdamem + 0x0080 + (stream_id * 0x20) + log.info(f"Mapping registers for hda stream {self.stream_id} at base {self.base:x}") + + self.hda = Regs(hdamem) + self.hda.GCAP = 0x0000 + self.hda.GCTL = 0x0008 + self.hda.DPLBASE = 0x0070 + self.hda.DPUBASE = 0x0074 + self.hda.SPBFCH = 0x0700 + self.hda.SPBFCTL = 0x0704 + self.hda.PPCH = 0x0800 + self.hda.PPCTL = 0x0804 + self.hda.PPSTS = 0x0808 + self.hda.SPIB = 0x0708 + stream_id*0x08 + self.hda.freeze() + + self.regs = Regs(self.base) + self.regs.CTL = 0x00 + self.regs.STS = 0x03 + self.regs.LPIB = 0x04 + self.regs.CBL = 0x08 + self.regs.LVI = 0x0c + self.regs.FIFOW = 0x0e + self.regs.FIFOS = 0x10 + self.regs.FMT = 0x12 + self.regs.FIFOL= 0x14 + self.regs.BDPL = 0x18 + self.regs.BDPU = 0x1c + self.regs.freeze() + + self.dbg0 = Regs(hdamem + 0x0084 + (0x20*stream_id)) + self.dbg0.DPIB = 0x00 + self.dbg0.EFIFOS = 0x10 + self.dbg0.freeze() + + self.reset() + + def __del__(self): + self.reset() + + def config(self, buf_len: int): + log.info(f"Configuring stream {self.stream_id}") + self.buf_len = buf_len + log.info("Allocating huge page and setting up buffers") + self.mem, self.hugef, self.buf_list_addr, self.pos_buf_addr, self.n_bufs = self.setup_buf(buf_len) + + log.info("Setting buffer list, length, and stream id and traffic priority bit") + self.regs.CTL = ((self.stream_id & 0xFF) << 20) | (1 << 18) # must be set to something other than 0? + self.regs.BDPU = (self.buf_list_addr >> 32) & 0xffffffff + self.regs.BDPL = self.buf_list_addr & 0xffffffff + self.regs.CBL = buf_len + self.regs.LVI = self.n_bufs - 1 + self.mem.seek(0) + self.debug() + log.info(f"Configured stream {self.stream_id}") + + def write(self, data): + + bufl = min(len(data), self.buf_len) + log.info(f"Writing data to stream {self.stream_id}, len {bufl}, SPBFCTL {self.hda.SPBFCTL:x}, SPIB {self.hda.SPIB}") + self.mem[0:bufl] = data[0:bufl] + self.mem[bufl:bufl+bufl] = data[0:bufl] + self.hda.SPBFCTL |= (1 << self.stream_id) + self.hda.SPIB += bufl + log.info(f"Wrote data to stream {self.stream_id}, SPBFCTL {self.hda.SPBFCTL:x}, SPIB {self.hda.SPIB}") + + def start(self): + log.info(f"Starting stream {self.stream_id}, CTL {self.regs.CTL:x}") + self.regs.CTL |= 2 + log.info(f"Started stream {self.stream_id}, CTL {self.regs.CTL:x}") + + def stop(self): + log.info(f"Stopping stream {self.stream_id}, CTL {self.regs.CTL:x}") + self.regs.CTL &= 2 + time.sleep(0.1) + self.regs.CTL |= 1 + log.info(f"Stopped stream {self.stream_id}, CTL {self.regs.CTL:x}") + + def setup_buf(self, buf_len: int): + (mem, phys_addr, hugef) = map_phys_mem(self.stream_id) + + log.info(f"Mapped 2M huge page at 0x{phys_addr:x} for buf size ({buf_len})") + + # create two buffers in the page of buf_len and mark them + # in a buffer descriptor list for the hardware to use + buf0_len = buf_len + buf1_len = buf_len + bdl_off = buf0_len + buf1_len + # bdl is 2 (64bits, 16 bytes) per entry, we have two + mem[bdl_off:bdl_off + 32] = struct.pack("> self.stream_id) & 1, self.regs.CTL, self.regs.LPIB, self.regs.BDPU, + self.regs.BDPL, self.regs.CBL, self.regs.LVI) + log.debug(" FIFOW %d, FIFOS %d, FMT %x, FIFOL %d, DPIB %d, EFIFOS %d", + self.regs.FIFOW & 0x7, self.regs.FIFOS, self.regs.FMT, self.regs.FIFOL, self.dbg0.DPIB, self.dbg0.EFIFOS) + log.debug(" status: FIFORDY %d, DESE %d, FIFOE %d, BCIS %d", + (self.regs.STS >> 5) & 1, (self.regs.STS >> 4) & 1, (self.regs.STS >> 3) & 1, (self.regs.STS >> 2) & 1) + + def reset(self): + # Turn DMA off and reset the stream. Clearing START first is a + # noop per the spec, but absolutely required for stability. + # Apparently the reset doesn't stop the stream, and the next load + # starts before it's ready and kills the load (and often the DSP). + # The sleep too is required, on at least one board (a fast + # chromebook) putting the two writes next each other also hangs + # the DSP! + log.info(f"Resetting stream {self.stream_id}") + self.debug() + self.regs.CTL &= ~2 # clear START + time.sleep(0.1) + # set enter reset bit + self.regs.CTL = 1 + while (self.regs.CTL & 1) == 0: pass + # clear enter reset bit to exit reset + self.regs.CTL = 0 + while (self.regs.CTL & 1) == 1: pass + + log.info(f"Disable SPIB and set position 0 of stream {self.stream_id}") + self.hda.SPBFCTL = 0 + self.hda.SPIB = 0 + + #log.info("Setting dma position buffer and enable it") + #self.hda.DPUBASE = self.pos_buf_addr >> 32 & 0xffffffff + #self.hda.DPLBASE = self.pos_buf_addr & 0xfffffff0 | 1 + + log.info(f"Enabling dsp capture (PROCEN) of stream {self.stream_id}") + self.hda.PPCTL |= (1 << self.stream_id) + + self.debug() + log.info(f"Reset stream {self.stream_id}") + + +def map_regs(): + p = runx(f"grep -iEl 'PCI_CLASS=40(10|38)0' /sys/bus/pci/devices/*/uevent") + pcidir = os.path.dirname(p) + + # Platform/quirk detection. ID lists cribbed from the SOF kernel driver + did = int(open(f"{pcidir}/device").read().rstrip(), 16) + ace15 = did in [ 0x7e28 ] + ace20 = did in [ 0xa828 ] + if ace15: + log.info("Detected MTL hardware") + elif ace20: + log.info("Detected LNL hardware") + + # Check sysfs for a loaded driver and remove it + if os.path.exists(f"{pcidir}/driver"): + mod = os.path.basename(os.readlink(f"{pcidir}/driver/module")) + found_msg = f"Existing driver \"{mod}\" found" + if args.log_only: + log.info(found_msg) + else: + log.warning(found_msg + ", unloading module") + runx(f"rmmod -f {mod}") + # Disengage runtime power management so the kernel doesn't put it to sleep + log.info(f"Forcing {pcidir}/power/control to always 'on'") + with open(f"{pcidir}/power/control", "w") as ctrl: + ctrl.write("on") + + # Make sure PCI memory space access and busmastering are enabled. + # Also disable interrupts so as not to confuse the kernel. + with open(f"{pcidir}/config", "wb+") as cfg: + cfg.seek(4) + cfg.write(b'\x06\x04') + + # Standard HD Audio Registers + global hdamem + (hdamem, _) = bar_map(pcidir, 0) + hda = Regs(hdamem) + hda.GCAP = 0x0000 + hda.GCTL = 0x0008 + hda.SPBFCTL = 0x0704 + hda.PPCTL = 0x0804 + + # Find the ID of the first output stream + hda_ostream_id = (hda.GCAP >> 8) & 0x0f # number of input streams + log.info(f"Selected output stream {hda_ostream_id} (GCAP = 0x{hda.GCAP:x})") + hda.SD_SPIB = 0x0708 + (8 * hda_ostream_id) + hda.freeze() + + + # Standard HD Audio Stream Descriptor + sd = Regs(hdamem + 0x0080 + (hda_ostream_id * 0x20)) + sd.CTL = 0x00 + sd.CBL = 0x08 + sd.LVI = 0x0c + sd.BDPL = 0x18 + sd.BDPU = 0x1c + sd.freeze() + + # Intel ACE Audio DSP Registers + global bar4_mmap + (bar4_mem, bar4_mmap) = bar_map(pcidir, 4) + dsp = Regs(bar4_mem) + dsp.HFDSSCS = 0x1000 + dsp.HFPWRCTL = 0x1d18 + dsp.HFPWRSTS = 0x1d1c + dsp.DSP2CXCTL_PRIMARY = 0x178d04 + dsp.HFIPCXTDR = 0x73200 + dsp.HFIPCXTDA = 0x73204 + dsp.HFIPCXIDR = 0x73210 + dsp.HFIPCXIDA = 0x73214 + dsp.HFIPCXCTL = 0x73228 + dsp.HFIPCXTDDY = 0x73300 + dsp.HFIPCXIDDY = 0x73380 + dsp.SRAM_FW_STATUS = WINDOW_BASE + dsp.freeze() + + return (hda, sd, dsp, hda_ostream_id) + +def setup_dma_mem(fw_bytes): + (mem, phys_addr, _) = map_phys_mem(hda_ostream_id) + mem[0:len(fw_bytes)] = fw_bytes + + log.info("Mapped 2M huge page at 0x%x to contain %d bytes of firmware" + % (phys_addr, len(fw_bytes))) + + # HDA requires at least two buffers be defined, but we don't care about + # boundaries because it's all a contiguous region. Place a vestigial + # 128-byte (minimum size and alignment) buffer after the main one, and put + # the 4-entry BDL list into the final 128 bytes of the page. + buf0_len = HUGEPAGESZ - 2 * 128 + buf1_len = 128 + bdl_off = buf0_len + buf1_len + mem[bdl_off:bdl_off + 32] = struct.pack(" /proc/sys/vm/nr_hugepages") + + hugef_name = HUGEPAGE_FILE + str(stream_id) + hugef = open(hugef_name, "w+") + hugef.truncate(HUGEPAGESZ) + mem = mmap.mmap(hugef.fileno(), HUGEPAGESZ) + log.info("type of mem is %s", str(type(mem))) + global_mmaps.append(mem) + os.unlink(hugef_name) + + # Find the local process address of the mapping, then use that to extract + # the physical address from the kernel's pagemap interface. The physical + # page frame number occupies the bottom bits of the entry. + mem[0] = 0 # Fault the page in so it has an address! + vaddr = ctypes.addressof(ctypes.c_int.from_buffer(mem)) + vpagenum = vaddr >> 12 + pagemap = open("/proc/self/pagemap", "rb") + pagemap.seek(vpagenum * 8) + pent = pagemap.read(8) + paddr = (struct.unpack("Q", pent)[0] & ((1 << 55) - 1)) * PAGESZ + pagemap.close() + return (mem, paddr, hugef) + +# Maps a PCI BAR and returns the in-process address +def bar_map(pcidir, barnum): + f = open(pcidir + "/resource" + str(barnum), "r+") + mm = mmap.mmap(f.fileno(), os.fstat(f.fileno()).st_size) + global_mmaps.append(mm) + log.info("Mapped PCI bar %d of length %d bytes." + % (barnum, os.fstat(f.fileno()).st_size)) + return (ctypes.addressof(ctypes.c_int.from_buffer(mm)), mm) + +# Syntactic sugar to make register block definition & use look nice. +# Instantiate from a base address, assign offsets to (uint32) named registers as +# fields, call freeze(), then the field acts as a direct alias for the register! +class Regs: + def __init__(self, base_addr): + vars(self)["base_addr"] = base_addr + vars(self)["ptrs"] = {} + vars(self)["frozen"] = False + def freeze(self): + vars(self)["frozen"] = True + def __setattr__(self, name, val): + if not self.frozen and name not in self.ptrs: + addr = self.base_addr + val + self.ptrs[name] = ctypes.c_uint32.from_address(addr) + else: + self.ptrs[name].value = val + def __getattr__(self, name): + return self.ptrs[name].value + +def runx(cmd): + return subprocess.check_output(cmd, shell=True).decode().rstrip() + +def load_firmware(fw_file): + try: + fw_bytes = open(fw_file, "rb").read() + # Resize fw_bytes for MTL + if len(fw_bytes) < 512 * 1024: + fw_bytes += b'\x00' * (512 * 1024 - len(fw_bytes)) + except Exception as e: + log.error(f"Could not read firmware file: `{fw_file}'") + log.error(e) + sys.exit(1) + + (magic, sz) = struct.unpack("4sI", fw_bytes[0:8]) + if magic == b'$AE1': + log.info(f"Trimming {sz} bytes of extended manifest") + fw_bytes = fw_bytes[sz:len(fw_bytes)] + + # This actually means "enable access to BAR4 registers"! + hda.PPCTL |= (1 << 30) # GPROCEN, "global processing enable" + + log.info("Resetting HDA device") + hda.GCTL = 0 + while hda.GCTL & 1: pass + hda.GCTL = 1 + while not hda.GCTL & 1: pass + + log.info("Turning of DSP subsystem") + dsp.HFDSSCS &= ~(1 << 16) # clear SPA bit + time.sleep(0.002) + # wait for CPA bit clear + while dsp.HFDSSCS & (1 << 24): + log.info("Waiting for DSP subsystem power off") + time.sleep(0.1) + + log.info("Turning on DSP subsystem") + dsp.HFDSSCS |= (1 << 16) # set SPA bit + time.sleep(0.002) # needed as the CPA bit may be unstable + # wait for CPA bit + while not dsp.HFDSSCS & (1 << 24): + log.info("Waiting for DSP subsystem power on") + time.sleep(0.1) + + log.info("Turning on Domain0") + dsp.HFPWRCTL |= 0x1 # set SPA bit + time.sleep(0.002) # needed as the CPA bit may be unstable + # wait for CPA bit + while not dsp.HFPWRSTS & 0x1: + log.info("Waiting for DSP domain0 power on") + time.sleep(0.1) + + log.info("Turning off Primary Core") + dsp.DSP2CXCTL_PRIMARY &= ~(0x1) # clear SPA + time.sleep(0.002) # wait for CPA settlement + while dsp.DSP2CXCTL_PRIMARY & (1 << 8): + log.info("Waiting for DSP primary core power off") + time.sleep(0.1) + + + log.info(f"Configuring HDA stream {hda_ostream_id} to transfer firmware image") + (buf_list_addr, num_bufs) = setup_dma_mem(fw_bytes) + sd.CTL = 1 + while (sd.CTL & 1) == 0: pass + sd.CTL = 0 + while (sd.CTL & 1) == 1: pass + sd.CTL |= (1 << 20) # Set stream ID to anything non-zero + sd.BDPU = (buf_list_addr >> 32) & 0xffffffff + sd.BDPL = buf_list_addr & 0xffffffff + sd.CBL = len(fw_bytes) + sd.LVI = num_bufs - 1 + hda.PPCTL |= (1 << hda_ostream_id) + + # SPIB ("Software Position In Buffer") is an Intel HDA extension + # that puts a transfer boundary into the stream beyond which the + # other side will not read. The ROM wants to poll on a "buffer + # full" bit on the other side that only works with this enabled. + hda.SPBFCTL |= (1 << hda_ostream_id) + hda.SD_SPIB = len(fw_bytes) + + + # Send the DSP an IPC message to tell the device how to boot. + # Note: with cAVS 1.8+ the ROM receives the stream argument as an + # index within the array of output streams (and we always use the + # first one by construction). But with 1.5 it's the HDA index, + # and depends on the number of input streams on the device. + stream_idx = 0 + ipcval = ( (1 << 31) # BUSY bit + | (0x01 << 24) # type = PURGE_FW + | (1 << 14) # purge_fw = 1 + | (stream_idx << 9)) # dma_id + log.info(f"Sending IPC command, HFIPCXIDR = 0x{ipcval:x}") + dsp.HFIPCXIDR = ipcval + + + log.info("Turning on Primary Core") + dsp.DSP2CXCTL_PRIMARY |= 0x1 # clear SPA + time.sleep(0.002) # wait for CPA settlement + while not dsp.DSP2CXCTL_PRIMARY & (1 << 8): + log.info("Waiting for DSP primary core power on") + time.sleep(0.1) + + log.info("Waiting for IPC acceptance") + while dsp.HFIPCXIDR & (1 << 31): + log.info("Waiting for IPC busy bit clear") + time.sleep(0.1) + + log.info("ACK IPC") + dsp.HFIPCXIDA |= (1 << 31) + + log.info(f"Starting DMA, FW_STATUS = 0x{dsp.SRAM_FW_STATUS:x}") + sd.CTL |= 2 # START flag + + wait_fw_entered() + + # Turn DMA off and reset the stream. Clearing START first is a + # noop per the spec, but absolutely required for stability. + # Apparently the reset doesn't stop the stream, and the next load + # starts before it's ready and kills the load (and often the DSP). + # The sleep too is required, on at least one board (a fast + # chromebook) putting the two writes next each other also hangs + # the DSP! + sd.CTL &= ~2 # clear START + time.sleep(0.1) + sd.CTL |= 1 + log.info(f"cAVS firmware load complete") + +def fw_is_alive(): + return dsp.SRAM_FW_STATUS & ((1 << 28) - 1) == 5 # "FW_ENTERED" + +def wait_fw_entered(timeout_s=2): + log.info("Waiting %s for firmware handoff, FW_STATUS = 0x%x", + "forever" if timeout_s is None else f"{timeout_s} seconds", + dsp.SRAM_FW_STATUS) + hertz = 100 + attempts = None if timeout_s is None else timeout_s * hertz + while True: + alive = fw_is_alive() + if alive: + break + if attempts is not None: + attempts -= 1 + if attempts < 0: + break + time.sleep(1 / hertz) + + if not alive: + log.warning("Load failed? FW_STATUS = 0x%x", dsp.SRAM_FW_STATUS) + else: + log.info("FW alive, FW_STATUS = 0x%x", dsp.SRAM_FW_STATUS) + + +# This SHOULD be just "mem[start:start+length]", but slicing an mmap +# array seems to be unreliable on one of my machines (python 3.6.9 on +# Ubuntu 18.04). Read out bytes individually. +def win_read(start, length): + try: + return b''.join(bar4_mmap[WINSTREAM_OFFSET + x].to_bytes(1, 'little') + for x in range(start, start + length)) + except IndexError as ie: + # A FW in a bad state may cause winstream garbage + log.error("IndexError in bar4_mmap[%d + %d]", WINSTREAM_OFFSET, start) + log.error("bar4_mmap.size()=%d", bar4_mmap.size()) + raise ie + +def win_hdr(): + return struct.unpack(" ((end - start) % wlen): + return (seq, "") + copy = (end - behind) % wlen + suffix = min(behind, wlen - copy) + result = win_read(16 + copy, suffix) + if suffix < behind: + result += win_read(16, behind - suffix) + (wlen, start1, end, seq1) = win_hdr() + if start1 == start and seq1 == seq: + # Best effort attempt at decoding, replacing unusable characters + # Found to be useful when it really goes wrong + return (seq, result.decode("utf-8", "replace")) + + +async def ipc_delay_done(): + await asyncio.sleep(0.1) + dsp.HFIPCXTDA = ~(1<<31) & dsp.HFIPCXTDA # Signal done + + +ipc_timestamp = 0 + +# Super-simple command language, driven by the test code on the DSP +def ipc_command(data, ext_data): + send_msg = False + done = True + log.debug ("ipc data %d, ext_data %x", data, ext_data) + if data == 0: # noop, with synchronous DONE + pass + elif data == 1: # async command: signal DONE after a delay (on 1.8+) + done = False + asyncio.ensure_future(ipc_delay_done()) + elif data == 2: # echo back ext_data as a message command + send_msg = True + elif data == 3: # set ADSPCS + dsp.ADSPCS = ext_data + elif data == 4: # echo back microseconds since last timestamp command + global ipc_timestamp + t = round(time.time() * 1e6) + ext_data = t - ipc_timestamp + ipc_timestamp = t + send_msg = True + elif data == 5: # copy word at outbox[ext_data >> 16] to inbox[ext_data & 0xffff] + src = OUTBOX_OFFSET + 4 * (ext_data >> 16) + dst = INBOX_OFFSET + 4 * (ext_data & 0xffff) + for i in range(4): + bar4_mmap[dst + i] = bar4_mmap[src + i] + elif data == 6: # HDA RESET (init if not exists) + stream_id = ext_data & 0xff + if stream_id in hda_streams: + hda_streams[stream_id].reset() + else: + hda_str = HDAStream(stream_id) + hda_streams[stream_id] = hda_str + elif data == 7: # HDA CONFIG + stream_id = ext_data & 0xFF + buf_len = ext_data >> 8 & 0xFFFF + hda_str = hda_streams[stream_id] + hda_str.config(buf_len) + elif data == 8: # HDA START + stream_id = ext_data & 0xFF + hda_streams[stream_id].start() + hda_streams[stream_id].mem.seek(0) + + elif data == 9: # HDA STOP + stream_id = ext_data & 0xFF + hda_streams[stream_id].stop() + elif data == 10: # HDA VALIDATE + stream_id = ext_data & 0xFF + hda_str = hda_streams[stream_id] + hda_str.debug() + is_ramp_data = True + hda_str.mem.seek(0) + for (i, val) in enumerate(hda_str.mem.read(256)): + if i != val: + is_ramp_data = False + # log.info("stream[%d][%d]: %d", stream_id, i, val) # debug helper + log.info("Is ramp data? " + str(is_ramp_data)) + ext_data = int(is_ramp_data) + log.info(f"Ext data to send back on ramp status {ext_data}") + send_msg = True + elif data == 11: # HDA HOST OUT SEND + stream_id = ext_data & 0xff + buf = bytearray(256) + for i in range(0, 256): + buf[i] = i + hda_streams[stream_id].write(buf) + elif data == 12: # HDA PRINT + stream_id = ext_data & 0xFF + buf_len = ext_data >> 8 & 0xFFFF + hda_str = hda_streams[stream_id] + # check for wrap here + pos = hda_str.mem.tell() + read_lens = [buf_len, 0] + if pos + buf_len >= hda_str.buf_len*2: + read_lens[0] = hda_str.buf_len*2 - pos + read_lens[1] = buf_len - read_lens[0] + # validate the read lens + assert (read_lens[0] + pos) <= (hda_str.buf_len*2) + assert read_lens[0] % 128 == 0 + assert read_lens[1] % 128 == 0 + buf_data0 = hda_str.mem.read(read_lens[0]) + hda_msg0 = buf_data0.decode("utf-8", "replace") + sys.stdout.write(hda_msg0) + if read_lens[1] != 0: + hda_str.mem.seek(0) + buf_data1 = hda_str.mem.read(read_lens[1]) + hda_msg1 = buf_data1.decode("utf-8", "replace") + sys.stdout.write(hda_msg1) + pos = hda_str.mem.tell() + sys.stdout.flush() + else: + log.warning(f"acetool: Unrecognized IPC command 0x{data:x} ext 0x{ext_data:x}") + if not fw_is_alive(): + if args.log_only: + log.info("DSP power seems off") + wait_fw_entered(timeout_s=None) + else: + log.warning("DSP power seems off?!") + time.sleep(2) # potential spam reduction + + return + + dsp.HFIPCXTDR = 1<<31 # Ack local interrupt, also signals DONE on v1.5 + if done: + dsp.HFIPCXTDA = ~(1<<31) & dsp.HFIPCXTDA # Signal done + if send_msg: + log.debug("ipc: sending msg 0x%08x" % ext_data) + dsp.HFIPCXIDDY = ext_data + dsp.HFIPCXIDR = (1<<31) | ext_data + +async def main(): + #TODO this bit me, remove the globals, write a little FirmwareLoader class or something to contain. + global hda, sd, dsp, hda_ostream_id, hda_streams + + try: + (hda, sd, dsp, hda_ostream_id) = map_regs() + except Exception as e: + log.error("Could not map device in sysfs; run as root?") + log.error(e) + sys.exit(1) + + if args.log_only: + wait_fw_entered(timeout_s=None) + else: + if not args.fw_file: + log.error("Firmware file argument missing") + sys.exit(1) + + load_firmware(args.fw_file) + time.sleep(0.1) + if not args.quiet: + sys.stdout.write("--\n") + + hda_streams = dict() + + last_seq = 0 + while start_output is True: + await asyncio.sleep(0.03) + (last_seq, output) = winstream_read(last_seq) + if output: + sys.stdout.write(output) + sys.stdout.flush() + if not args.log_only: + if dsp.HFIPCXIDA & 0x80000000: + log.debug("ipc: Ack DSP reply with IDA_DONE") + dsp.HFIPCXIDA = 1<<31 # must ACK any DONE interrupts that arrive! + if dsp.HFIPCXTDR & 0x80000000: + ipc_command(dsp.HFIPCXTDR & ~0x80000000, dsp.HFIPCXTDDY) + + +ap = argparse.ArgumentParser(description="DSP loader/logger tool", allow_abbrev=False) +ap.add_argument("-q", "--quiet", action="store_true", + help="No loader output, just DSP logging") +ap.add_argument("-v", "--verbose", action="store_true", + help="More loader output, DEBUG logging level") +ap.add_argument("-l", "--log-only", action="store_true", + help="Don't load firmware, just show log output") +ap.add_argument("-n", "--no-history", action="store_true", + help="No current log buffer at start, just new output") +ap.add_argument("fw_file", nargs="?", help="Firmware file") + +args = ap.parse_args() + +if args.quiet: + log.setLevel(logging.WARN) +elif args.verbose: + log.setLevel(logging.DEBUG) + +if __name__ == "__main__": + try: + asyncio.get_event_loop().run_until_complete(main()) + except KeyboardInterrupt: + start_output = False diff --git a/soc/xtensa/nxp_adsp/common/CMakeLists.txt b/soc/xtensa/nxp_adsp/common/CMakeLists.txt index 02c2ef503e3..5c53c771f08 100644 --- a/soc/xtensa/nxp_adsp/common/CMakeLists.txt +++ b/soc/xtensa/nxp_adsp/common/CMakeLists.txt @@ -4,15 +4,3 @@ # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(include) - -zephyr_interface_library_named(NXP_ADSP_COMMON) - -zephyr_library_named(nxp_adsp_common) -zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) - -zephyr_library_sources(soc.c) - -zephyr_library_link_libraries(NXP_ADSP_COMMON) - -target_include_directories(NXP_ADSP_COMMON INTERFACE include) -target_link_libraries(NXP_ADSP_COMMON INTERFACE nxp_adsp_common) diff --git a/soc/xtensa/nxp_adsp/common/soc.c b/soc/xtensa/nxp_adsp/common/soc.c deleted file mode 100644 index 8c80ff77308..00000000000 --- a/soc/xtensa/nxp_adsp/common/soc.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2021 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#include "soc.h" - -#ifdef CONFIG_DYNAMIC_INTERRUPTS -#include -#endif -#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL -#include -LOG_MODULE_REGISTER(soc); - -void z_soc_irq_enable(uint32_t irq) -{ - /* - * enable core interrupt - */ - z_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq)); -} - -void z_soc_irq_disable(uint32_t irq) -{ - /* - * disable the interrupt in interrupt controller - */ - z_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq)); -} - -int z_soc_irq_is_enabled(unsigned int irq) -{ - int ret = 0; - - /* regular interrupt */ - ret = z_xtensa_irq_is_enabled(XTENSA_IRQ_NUMBER(irq)); - - return ret; -} diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series new file mode 100644 index 00000000000..ebd9377660b --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.defconfig.series @@ -0,0 +1,30 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_NXP_IMX8ULP + +config SOC_SERIES + string + default "imx8ulp" + +config SOC_TOOLCHAIN_NAME + string + default "nxp_imx8ulp_adsp" + +config SOC + string + default "nxp_imx8ulp" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 528000000 if XTENSA_TIMER + +config SYS_CLOCK_TICKS_PER_SEC + default 50000 + +config DCACHE_LINE_SIZE + default 128 + +config GEN_IRQ_VECTOR_TABLE + default n + +endif # SOC_SERIES_NXP_IMX8ULP diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series new file mode 100644 index 00000000000..34e9b3a1a1d --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.series @@ -0,0 +1,15 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_NXP_IMX8ULP + bool "NXP i.MX8ULP Audio DSP Series" + select SOC_FAMILY_NXP_ADSP + select XTENSA + select XTENSA_HAL if ("$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xcc" && "$(ZEPHYR_TOOLCHAIN_VARIANT)" != "xt-clang") + select XTENSA_RESET_VECTOR + select XTENSA_USE_CORE_CRT1 + select ATOMIC_OPERATIONS_BUILTIN + select GEN_ISR_TABLES + select XTENSA_SMALL_VECTOR_TABLE_ENTRY + help + Enable support for NXP i.MX8ULP Audio DSP diff --git a/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc new file mode 100644 index 00000000000..b90fada22d4 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright (c) 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "NXP i.MX8ULP Audio DSP Selection" + depends on SOC_SERIES_NXP_IMX8ULP + + config SOC_NXP_IMX8ULP + bool "NXP i.MX8ULP Audio DSP" + +endchoice diff --git a/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h b/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h new file mode 100644 index 00000000000..28129b65758 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/include/_soc_inthandlers.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + * + * Functions here are designed to produce efficient code to + * search an Xtensa bitmask of interrupts, inspecting only those bits + * declared to be associated with a given interrupt level. Each + * dispatcher will handle exactly one flagged interrupt, in numerical + * order (low bits first) and will return a mask of that bit that can + * then be cleared by the calling code. Unrecognized bits for the + * level will invoke an error handler. + */ + +#include +#include +#include + +#if !defined(XCHAL_INT0_LEVEL) || XCHAL_INT0_LEVEL != 5 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT1_LEVEL) || XCHAL_INT1_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT2_LEVEL) || XCHAL_INT2_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT16_LEVEL) || XCHAL_INT16_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT17_LEVEL) || XCHAL_INT17_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT18_LEVEL) || XCHAL_INT18_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT19_LEVEL) || XCHAL_INT19_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT20_LEVEL) || XCHAL_INT20_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT21_LEVEL) || XCHAL_INT21_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT22_LEVEL) || XCHAL_INT22_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT23_LEVEL) || XCHAL_INT23_LEVEL != 2 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT3_LEVEL) || XCHAL_INT3_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT4_LEVEL) || XCHAL_INT4_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT5_LEVEL) || XCHAL_INT5_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT24_LEVEL) || XCHAL_INT24_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT25_LEVEL) || XCHAL_INT25_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT26_LEVEL) || XCHAL_INT26_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT27_LEVEL) || XCHAL_INT27_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT28_LEVEL) || XCHAL_INT28_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT29_LEVEL) || XCHAL_INT29_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT30_LEVEL) || XCHAL_INT30_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT31_LEVEL) || XCHAL_INT31_LEVEL != 3 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT6_LEVEL) || XCHAL_INT6_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT7_LEVEL) || XCHAL_INT7_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT8_LEVEL) || XCHAL_INT8_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT9_LEVEL) || XCHAL_INT9_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT10_LEVEL) || XCHAL_INT10_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT11_LEVEL) || XCHAL_INT11_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT12_LEVEL) || XCHAL_INT12_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT13_LEVEL) || XCHAL_INT13_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT14_LEVEL) || XCHAL_INT14_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif +#if !defined(XCHAL_INT15_LEVEL) || XCHAL_INT15_LEVEL != 1 +#error core-isa.h interrupt level does not match dispatcher! +#endif + +static inline int _xtensa_handle_one_int5(unsigned int mask) +{ + int irq; + + if (mask & BIT(0)) { + mask = BIT(0); + irq = 0; + goto handle_irq; + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int2(unsigned int mask) +{ + int irq; + + if (mask & 0x70006) { + if (mask & 0x6) { + if (mask & BIT(1)) { + mask = BIT(1); + irq = 1; + goto handle_irq; + } + if (mask & BIT(2)) { + mask = BIT(2); + irq = 2; + goto handle_irq; + } + } else { + if (mask & BIT(16)) { + mask = BIT(16); + irq = 16; + goto handle_irq; + } + if (mask & BIT(17)) { + mask = BIT(17); + irq = 17; + goto handle_irq; + } + if (mask & BIT(18)) { + mask = BIT(18); + irq = 18; + goto handle_irq; + } + } + } else { + if (mask & 0x180000) { + if (mask & BIT(19)) { + mask = BIT(19); + irq = 19; + goto handle_irq; + } + if (mask & BIT(20)) { + mask = BIT(20); + irq = 20; + goto handle_irq; + } + } else { + if (mask & BIT(21)) { + mask = BIT(21); + irq = 21; + goto handle_irq; + } + if (mask & BIT(22)) { + mask = BIT(22); + irq = 22; + goto handle_irq; + } + if (mask & BIT(23)) { + mask = BIT(23); + irq = 23; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int3(unsigned int mask) +{ + int irq; + + if (mask & 0x3000038) { + if (mask & 0x18) { + if (mask & BIT(3)) { + mask = BIT(3); + irq = 3; + goto handle_irq; + } + if (mask & BIT(4)) { + mask = BIT(4); + irq = 4; + goto handle_irq; + } + } else { + if (mask & BIT(5)) { + mask = BIT(5); + irq = 5; + goto handle_irq; + } + if (mask & BIT(24)) { + mask = BIT(24); + irq = 24; + goto handle_irq; + } + if (mask & BIT(25)) { + mask = BIT(25); + irq = 25; + goto handle_irq; + } + } + } else { + if (mask & 0x1c000000) { + if (mask & BIT(26)) { + mask = BIT(26); + irq = 26; + goto handle_irq; + } + if (mask & BIT(27)) { + mask = BIT(27); + irq = 27; + goto handle_irq; + } + if (mask & BIT(28)) { + mask = BIT(28); + irq = 28; + goto handle_irq; + } + } else { + if (mask & BIT(29)) { + mask = BIT(29); + irq = 29; + goto handle_irq; + } + if (mask & BIT(30)) { + mask = BIT(30); + irq = 30; + goto handle_irq; + } + if (mask & BIT(31)) { + mask = BIT(31); + irq = 31; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int1(unsigned int mask) +{ + int irq; + + if (mask & 0x7c0) { + if (mask & 0xc0) { + if (mask & BIT(6)) { + mask = BIT(6); + irq = 6; + goto handle_irq; + } + if (mask & BIT(7)) { + mask = BIT(7); + irq = 7; + goto handle_irq; + } + } else { + if (mask & BIT(8)) { + mask = BIT(8); + irq = 8; + goto handle_irq; + } + if (mask & BIT(9)) { + mask = BIT(9); + irq = 9; + goto handle_irq; + } + if (mask & BIT(10)) { + mask = BIT(10); + irq = 10; + goto handle_irq; + } + } + } else { + if (mask & 0x1800) { + if (mask & BIT(11)) { + mask = BIT(11); + irq = 11; + goto handle_irq; + } + if (mask & BIT(12)) { + mask = BIT(12); + irq = 12; + goto handle_irq; + } + } else { + if (mask & BIT(13)) { + mask = BIT(13); + irq = 13; + goto handle_irq; + } + if (mask & BIT(14)) { + mask = BIT(14); + irq = 14; + goto handle_irq; + } + if (mask & BIT(15)) { + mask = BIT(15); + irq = 15; + goto handle_irq; + } + } + } + return 0; +handle_irq: + _sw_isr_table[irq].isr(_sw_isr_table[irq].arg); + return mask; +} + +static inline int _xtensa_handle_one_int0(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int4(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int6(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int7(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int8(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int9(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int10(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int11(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int12(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int13(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int14(unsigned int mask) +{ + return 0; +} +static inline int _xtensa_handle_one_int15(unsigned int mask) +{ + return 0; +} diff --git a/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h b/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h new file mode 100644 index 00000000000..d6384477e71 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/include/memory.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ +#define ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ + +#define IRAM_RESERVE_HEADER_SPACE 0x400 + +#define IRAM_BASE 0x21170000 +#define IRAM_SIZE 0x10000 + +#define SDRAM0_BASE 0x1a000000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x1a800000 +#define SDRAM1_SIZE 0x800000 + +/* The reset vector address in SRAM and its size */ +#define MEM_RESET_TEXT_SIZE 0x2e0 +#define MEM_RESET_LIT_SIZE 0x120 + +/* This is the base address of all the vectors defined in IRAM */ +#define XCHAL_VECBASE_RESET_PADDR_IRAM \ + (IRAM_BASE + IRAM_RESERVE_HEADER_SPACE) + +#define MEM_VECBASE_LIT_SIZE 0x178 + +/* + * EXCEPTIONS and VECTORS + */ +#define XCHAL_RESET_VECTOR0_PADDR_IRAM 0x21170000 + +/* Vector and literal sizes */ +#define MEM_VECT_LIT_SIZE 0x4 +#define MEM_VECT_TEXT_SIZE 0x1C +#define MEM_VECT_SIZE (MEM_VECT_TEXT_SIZE +\ + MEM_VECT_LIT_SIZE) + +/* The addresses of the vectors. + * Only the mem_error vector continues to point to its ROM address. + */ +#define XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x17C) + +#define XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x19C) + +#define XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1BC) + +#define XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1DC) + +#define XCHAL_KERNEL_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x1FC) + +#define XCHAL_USER_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x21C) + +#define XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM \ + (XCHAL_VECBASE_RESET_PADDR_IRAM + 0x23C) + +/* Location for the intList section which is later used to construct the + * Interrupt Descriptor Table (IDT). This is a bogus address as this + * section will be stripped off in the final image. + */ +#define IDT_BASE (IRAM_BASE + IRAM_SIZE) + +/* size of the Interrupt Descriptor Table (IDT) */ +#define IDT_SIZE 0x2000 + +/* physical DSP addresses */ +#define IRAM_BASE 0x21170000 +#define IRAM_SIZE 0x10000 + +#define DRAM0_BASE 0x21180000 +#define DRAM0_SIZE 0x10000 + +#define SDRAM0_BASE 0x1a000000 +#define SDRAM0_SIZE 0x800000 + +#define SDRAM1_BASE 0x1a800000 +#define SDRAM1_SIZE 0x800000 + +#define XSHAL_MU13_SIDEB_BYPASS_PADDR 0x2DA20000 +#define MU_BASE XSHAL_MU13_SIDEB_BYPASS_PADDR + +#define EDMA2_BASE 0x2D810000 +#define EDMA2_SIZE 0x10000 + +#define SAI_5_BASE 0x29890000 +#define SAI_5_SIZE 0x00010000 +#define SAI_6_BASE 0x2DA90000 +#define SAI_6_SIZE 0x00010000 +#define SAI_7_BASE 0x2DAA0000 +#define SAI_7_SIZE 0x00010000 + +#define UUID_ENTRY_ELF_BASE 0x1FFFA000 +#define UUID_ENTRY_ELF_SIZE 0x6000 + +#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 + +/* + * The Heap and Stack on i.MX8 are organized like this :- + * + * +--------------------------------------------------------------------------+ + * | Offset | Region | Size | + * +---------------------+----------------+-----------------------------------+ + * | SDRAM_BASE | RO Data | SOF_DATA_SIZE | + * | | Data | | + * | | BSS | | + * +---------------------+----------------+-----------------------------------+ + * | 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 | | | + * +---------------------+----------------+-----------------------------------+ + */ + +#define SRAM_OUTBOX_BASE SDRAM1_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 0x2800 +#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) + +#define SOF_MAILBOX_SIZE (SRAM_INBOX_SIZE + SRAM_OUTBOX_SIZE \ + + SRAM_DEBUG_SIZE + SRAM_EXCEPT_SIZE \ + + SRAM_STREAM_SIZE + SRAM_TRACE_SIZE) + +#endif /* ZEPHYR_SOC_NXP_ADSP_MEMORY_H_ */ diff --git a/soc/xtensa/nxp_adsp/imx8ulp/linker.ld b/soc/xtensa/nxp_adsp/imx8ulp/linker.ld new file mode 100644 index 00000000000..4b5aec29742 --- /dev/null +++ b/soc/xtensa/nxp_adsp/imx8ulp/linker.ld @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Linker command/script file + * + * Linker script for the NXP i.MX8ULP platform + */ + +OUTPUT_ARCH(xtensa) + +#include +#include +#include +#include + +#include +#include + +PROVIDE(__memctl_default = 0x00000000); +PROVIDE(_MemErrorHandler = 0x00000000); + +#define RAMABLE_REGION sdram0 :sdram0_phdr +#define ROMABLE_REGION sdram0 :sdram0_phdr + +MEMORY +{ + vector_reset_text : + org = XCHAL_RESET_VECTOR0_PADDR_IRAM, + len = MEM_RESET_TEXT_SIZE + vector_reset_lit : + org = XCHAL_RESET_VECTOR0_PADDR_IRAM + MEM_RESET_TEXT_SIZE, + len = MEM_RESET_LIT_SIZE + vector_base_text : + org = XCHAL_VECBASE_RESET_PADDR_IRAM, + len = MEM_VECBASE_LIT_SIZE + vector_int2_lit : + org = XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int2_text : + org = XCHAL_INTLEVEL2_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int3_lit : + org = XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int3_text : + org = XCHAL_INTLEVEL3_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int4_lit : + org = XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int4_text : + org = XCHAL_INTLEVEL4_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_int5_lit : + org = XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_int5_text : + org = XCHAL_INTLEVEL5_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_kernel_lit : + org = XCHAL_KERNEL_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_kernel_text : + org = XCHAL_KERNEL_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_user_lit : + org = XCHAL_USER_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_user_text : + org = XCHAL_USER_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + vector_double_lit : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM - MEM_VECT_LIT_SIZE, + len = MEM_VECT_LIT_SIZE + vector_double_text : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM, + len = MEM_VECT_TEXT_SIZE + iram_text_start : + org = XCHAL_DOUBLEEXC_VECTOR_PADDR_IRAM + MEM_VECT_TEXT_SIZE, + len = (IRAM_BASE + IRAM_SIZE) - (XCHAL_DOUBLEEXC_VECTOR_PADDR + MEM_VECT_TEXT_SIZE) + sdram0 : + org = SDRAM0_BASE, + len = SDRAM0_SIZE + sdram1 : + org = SDRAM1_BASE + SOF_MAILBOX_SIZE, + len = SDRAM1_SIZE - SOF_MAILBOX_SIZE +#ifdef CONFIG_GEN_ISR_TABLES + IDT_LIST : + org = IDT_BASE, + len = IDT_SIZE +#endif + + 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; + iram_text_start_phdr PT_LOAD; + sdram0_phdr PT_LOAD; + sdram1_phdr PT_LOAD; + static_uuid_entries_phdr PT_NOTE; + static_log_entries_phdr PT_NOTE; + metadata_entries_phdr PT_NOTE; +} + +_rom_store_table = 0; + +PROVIDE(_memmap_vecbase_reset = XCHAL_VECBASE_RESET_PADDR); + +ENTRY(CONFIG_KERNEL_ENTRY) + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x44024000; +_memmap_cacheattr_wt_base = 0x11021000; +_memmap_cacheattr_bp_base = 0x22022000; +_memmap_cacheattr_unused_mask = 0x00F00FFF; +_memmap_cacheattr_wb_trapnull = 0x4422422F; +_memmap_cacheattr_wba_trapnull = 0x4422422F; +_memmap_cacheattr_wbna_trapnull = 0x25222222; +_memmap_cacheattr_wt_trapnull = 0x1122122F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0x44F24FFF; +_memmap_cacheattr_wt_strict = 0x11F21FFF; +_memmap_cacheattr_bp_strict = 0x22F22FFF; +_memmap_cacheattr_wb_allvalid = 0x44224222; +_memmap_cacheattr_wt_allvalid = 0x11221222; +_memmap_cacheattr_bp_allvalid = 0x22222222; +/* + * Every 512M in 4GB space has dedicate cache attribute. + * 1: write through + * 2: cache bypass + * 4: write back + * F: invalid access + */ +_memmap_cacheattr_imx8_wt_allvalid = 0x222222221; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_imx8_wt_allvalid); + +_EXT_MAN_ALIGN_ = 16; +EXTERN(ext_man_fw_ver) + +SECTIONS +{ + +#include + .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 + + .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 + + .iram.text : ALIGN(4) + { + _stext = .; + _iram_text_start = ABSOLUTE(.); + *(.iram0.literal .iram.literal .iram.text.literal .iram0.text .iram.text) + _iram_text_end = ABSOLUTE(.); + } >iram_text_start :iram_text_start_phdr + + .rodata : ALIGN(4) + { + __rodata_region_start = ABSOLUTE(.); + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + KEEP (*(.xt_except_table)) + KEEP (*(.gcc_except_table .gcc_except_table.*)) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + KEEP (*(.eh_frame)) + 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)) + __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); + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + __rodata_region_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + + .module_init : ALIGN(4) + { + _module_init_start = ABSOLUTE(.); + *(*.initcall) + _module_init_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + KEEP (*(.ResetVector.text)) + *(.ResetVector.literal) + *(.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 = .; + } >sdram0 :sdram0_phdr + +#include + + .fw_ready : ALIGN(4) + { + KEEP(*(".fw_ready")); + KEEP (*(.fw_ready_metadata)) + } >sdram0 :sdram0_phdr + + .noinit : ALIGN(4) + { + *(.noinit) + *(.noinit.*) + } >sdram0 :sdram0_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(.); + . = ALIGN(4); + *(.gna_model) + __data_end = ABSOLUTE(.); + . = ALIGN(4096); + } >sdram0 :sdram0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >sdram0 :sdram0_phdr + +#include + + .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(.); + } >sdram0 :sdram0_phdr + + .heap_mem (NOLOAD) : ALIGN(8) + { + . = ALIGN (8); + _heap_mem_start = ABSOLUTE(.); + *(*.heap_mem) + _heap_mem_end = ABSOLUTE(.); + } >sdram1 :sdram1_phdr + + /* stack */ + _end = ALIGN (8); + PROVIDE(end = ALIGN (8)); + + __stack = SDRAM1_BASE + SDRAM1_SIZE; + .comment 0 : { *(.comment) } + .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) } + .debug_ranges 0 : { *(.debug_ranges) } + .xtensa.info 0 : { *(.xtensa.info) } + .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.*)) + } +#ifdef CONFIG_GEN_ISR_TABLES +#include +#endif + + .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/submanifests/optional.yaml b/submanifests/optional.yaml index 54b3d77c0cb..127930a65c7 100644 --- a/submanifests/optional.yaml +++ b/submanifests/optional.yaml @@ -28,19 +28,19 @@ manifest: groups: - optional - name: psa-arch-tests - revision: 6a17330e0dfb5f319730f974d5b05f7b7f04757b + revision: 2cadb02a72eacda7042505dcbdd492371e8ce024 path: modules/tee/tf-m/psa-arch-tests remote: upstream groups: - optional - name: sof - revision: e7cb489d430dc2181e4a5f7f953ed1eaeec6668d + revision: 0606152d4aafc1f7ed43df1b1813252bfc74e154 path: modules/audio/sof remote: upstream groups: - optional - name: tf-m-tests - revision: a878426da78fbd1486dfc29d6c6b82be4ee79e72 + revision: 08a3158f0623a4205608a52d880b17ae394e31d2 path: modules/tee/tf-m/tf-m-tests remote: upstream groups: @@ -60,7 +60,7 @@ manifest: - optional - name: zscilib path: modules/lib/zscilib - revision: 34a94b0995683822fa3626dcd5d838301c94c350 + revision: a4bb6cfd6800e14373261904825f7f34a3a7f2e5 remote: upstream groups: - optional diff --git a/subsys/Kconfig b/subsys/Kconfig index f0dab7c8c72..2e083fb4c89 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -53,4 +53,14 @@ source "subsys/usb/usb_c/Kconfig" source "subsys/zbus/Kconfig" # zephyr-keep-sorted-stop +config MODULES + bool "Make tristate Kconfig options and an 'm' selection available" + help + Zephyr supports dynamically loadable code, e.g. using llext. Code, + that can either be built as a part of the system image or as a + loadable extension, can use tristate Kconfig options. For this to work + the CONFIG_MODULES option must be enabled by the project. Enabling + this option alone doesn't change the build on its own, it only allows + using 'm' for tristate Kconfig options. + endmenu diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 912846e4cda..c8f71afb207 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -128,7 +128,7 @@ if BT_CONN config BT_HCI_ACL_FLOW_CONTROL bool "Controller to Host ACL flow control support" # Enable if building a Host-only build - default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 + default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 && !BT_STM32WBA # Enable if building a Controller-only build default y if BT_HCI_RAW select POLL diff --git a/subsys/bluetooth/Kconfig.logging b/subsys/bluetooth/Kconfig.logging index b6505f6e53a..c103a42c316 100644 --- a/subsys/bluetooth/Kconfig.logging +++ b/subsys/bluetooth/Kconfig.logging @@ -659,6 +659,11 @@ legacy-debug-sym = BT_BAP_DEBUG_STREAM module-str = "Bluetooth Audio Stream" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +parent-module = BT +module = BT_BAP_BASE +module-str = "Bluetooth Basic Audio Profile Broadcast Audio Source Endpoint" +source "subsys/logging/Kconfig.template.log_config_inherit" + parent-module = BT module = BT_AUDIO_CODEC module-str = "Bluetooth Audio Codec" @@ -721,6 +726,11 @@ module = BT_CAP_COMMANDER module-str = "Common Audio Profile Commander" source "subsys/logging/Kconfig.template.log_config_inherit" +parent-module = BT +module = BT_CAP_COMMON +module-str = "Common Audio Profile Common" +source "subsys/logging/Kconfig.template.log_config_inherit" + parent-module = BT module = BT_CAP_STREAM module-str = "Common Audio Profile Stream" @@ -836,6 +846,12 @@ legacy-debug-sym = BT_DEBUG_VOCS_CLIENT module-str = "Volume Offset Control Service client" source "subsys/bluetooth/common/Kconfig.template.log_config_bt" +# PBP + +module = BT_PBP +module-str = "Public Broadcast Profile" +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + endmenu # Audio menu "Others" diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 2ae08c2d7b5..293498fbd40 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -49,6 +49,7 @@ zephyr_library_sources_ifdef(CONFIG_MCTL media_proxy.c) zephyr_library_sources_ifdef(CONFIG_BT_ASCS ascs.c) zephyr_library_sources_ifdef(CONFIG_BT_PACS pacs.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_STREAM bap_stream.c codec.c bap_iso.c) +zephyr_library_sources_ifdef(CONFIG_BT_BAP_BASE bap_base.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_UNICAST_SERVER bap_unicast_server.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_UNICAST_CLIENT bap_unicast_client.c) zephyr_library_sources_ifdef(CONFIG_BT_BAP_BROADCAST_SOURCE bap_broadcast_source.c) @@ -61,4 +62,9 @@ zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_ACCEPTOR cap_acceptor.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_INITIATOR cap_initiator.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_COMMANDER cap_commander.c) +if (CONFIG_BT_CAP_INITIATOR OR CONFIG_BT_CAP_COMMANDER) + zephyr_library_sources(cap_common.c) +endif() zephyr_library_sources_ifdef(CONFIG_BT_TMAP tmap.c) +zephyr_library_sources_ifdef(CONFIG_BT_GMAP gmap_client.c gmap_server.c) +zephyr_library_sources_ifdef(CONFIG_BT_PBP pbp.c) diff --git a/subsys/bluetooth/audio/Kconfig b/subsys/bluetooth/audio/Kconfig index 7e7bbfd0951..b60475c02e2 100644 --- a/subsys/bluetooth/audio/Kconfig +++ b/subsys/bluetooth/audio/Kconfig @@ -60,6 +60,8 @@ rsource "Kconfig.mpl" rsource "Kconfig.mctl" rsource "Kconfig.cap" rsource "Kconfig.tmap" +rsource "Kconfig.gmap" +rsource "Kconfig.pbp" module = BT_AUDIO module-str = "Bluetooth Audio" diff --git a/subsys/bluetooth/audio/Kconfig.bap b/subsys/bluetooth/audio/Kconfig.bap index 0b5e1c3e291..ae3b6c8d5fa 100644 --- a/subsys/bluetooth/audio/Kconfig.bap +++ b/subsys/bluetooth/audio/Kconfig.bap @@ -235,6 +235,15 @@ config BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS help The maximum number of BIS subgroups supported. +config BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT + int "Milliseconds of timeout when handle concurrent access to the long read ASE buffer" + range 0 1000 + default 50 + help + The maximum number of milliseconds that the scan delegator implementation will wait + before rejecting a read or dropping a notification if the scan delegator state is + being accessed by another thread. + endif # BT_BAP_SCAN_DELEGATOR config BT_BAP_BROADCAST_ASSISTANT @@ -286,5 +295,8 @@ config BT_BAP_DEBUG_STREAM_SEQ_NUM the Bluetooth Audio functionality. This will provide a warning if the application provides unexpected sequence numbers. +config BT_BAP_BASE + def_bool BT_BAP_BROADCAST_SINK || BT_BAP_BROADCAST_ASSISTANT || BT_BAP_SCAN_DELEGATOR + rsource "Kconfig.pacs" rsource "Kconfig.ascs" diff --git a/subsys/bluetooth/audio/Kconfig.cap b/subsys/bluetooth/audio/Kconfig.cap index 0488b610a08..2a130f53d9a 100644 --- a/subsys/bluetooth/audio/Kconfig.cap +++ b/subsys/bluetooth/audio/Kconfig.cap @@ -28,6 +28,9 @@ config BT_CAP_ACCEPTOR_SET_MEMBER Enabling will take one of the allocated CSIS instances (BT_CSIP_SET_MEMBER_MAX_INSTANCE_COUNT). +config BT_CAP_INITIATOR_UNICAST + def_bool BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT + config BT_CAP_INITIATOR bool "Common Audio Profile Initiator Role Support [EXPERIMENTAL]" depends on (BT_BAP_UNICAST_CLIENT && BT_CSIP_SET_COORDINATOR) || BT_BAP_BROADCAST_SOURCE diff --git a/subsys/bluetooth/audio/Kconfig.gmap b/subsys/bluetooth/audio/Kconfig.gmap new file mode 100644 index 00000000000..a9bd3024aa3 --- /dev/null +++ b/subsys/bluetooth/audio/Kconfig.gmap @@ -0,0 +1,30 @@ +# Bluetooth Audio - Gaming Audio Profile (GMAP) options +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_GMAP_UGG_SUPPORTED + def_bool BT_CAP_INITIATOR && BT_BAP_UNICAST_CLIENT && BT_VCP_VOL_CTLR + +config BT_GMAP_UGT_SUPPORTED + def_bool BT_CAP_ACCEPTOR && BT_BAP_UNICAST_SERVER + +config BT_GMAP_BGS_SUPPORTED + def_bool BT_CAP_INITIATOR && BT_BAP_BROADCAST_SOURCE + +config BT_GMAP_BGR_SUPPORTED + def_bool BT_CAP_ACCEPTOR && BT_BAP_BROADCAST_SINK && BT_VCP_VOL_REND + +config BT_GMAP + bool "Gaming Audio Profile [EXPERIMENTAL]" + depends on BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + select EXPERIMENTAL + help + Enabling this will enable GMAP. + +parent-module = BT +module = BT_GMAP +module-str = "Bluetooth Gaming Audio Profile" +source "subsys/logging/Kconfig.template.log_config_inherit" diff --git a/subsys/bluetooth/audio/Kconfig.mcs b/subsys/bluetooth/audio/Kconfig.mcs index 50f6064d44e..d0b139e90b1 100644 --- a/subsys/bluetooth/audio/Kconfig.mcs +++ b/subsys/bluetooth/audio/Kconfig.mcs @@ -121,4 +121,106 @@ config BT_MCC_SHELL help This option enables shell support for the Media Control Client. +config BT_MCC_MINIMAL + bool "Minimal Media Control Client without optional procedures" + help + This option disables all optional procedures in the Media Control Client. + +config BT_MCC_READ_MEDIA_PLAYER_ICON_URL + bool "Support reading Media Player Icon URL" + default !BT_MCC_MINIMAL + help + This option enables support for Read Media Information procedure + optionally read the Media Player Icon URL. + +config BT_MCC_READ_TRACK_TITLE + bool "Support reading Track Title" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Title. + +config BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION + bool "Support to enable or disable the subscription of Track Title" + default !BT_MCC_MINIMAL + help + This option enables support for the subscription of Track Title. + +config BT_MCC_READ_TRACK_DURATION + bool "Support reading Track Duration" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Duration. + +config BT_MCC_READ_TRACK_POSITION + bool "Support reading Track Position" + default !BT_MCC_MINIMAL + help + This option enables support for reading Track Position. + +config BT_MCC_SET_TRACK_POSITION + bool "Support setting Track Position" + default !BT_MCC_MINIMAL + help + This option enables support for setting Track Position. + +config BT_MCC_READ_PLAYBACK_SPEED + bool "Support reading Playback Speed" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playback Speed. + +config BT_MCC_SET_PLAYBACK_SPEED + bool "Support setting Playback Speed" + default !BT_MCC_MINIMAL + help + This option enables support for setting Playback Speed. + +config BT_MCC_READ_SEEKING_SPEED + bool "Support reading Seeking Speed" + default !BT_MCC_MINIMAL + help + This option enables support for reading Seeking Speed. + +config BT_MCC_READ_PLAYING_ORDER + bool "Support reading Playing Order" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order. + +config BT_MCC_SET_PLAYING_ORDER + bool "Support setting Playing Order" + default !BT_MCC_MINIMAL + help + This option enables support for setting Playing Order. + +config BT_MCC_READ_PLAYING_ORDER_SUPPORTED + bool "Support reading Playing Order Supported" + default !BT_MCC_MINIMAL + help + This option enables support for reading Playing Order Supported. + +config BT_MCC_READ_MEDIA_STATE + bool "Support reading Media State" + default !BT_MCC_MINIMAL + help + This option enables support for reading Media State. + +config BT_MCC_SET_MEDIA_CONTROL_POINT + bool "Support setting Media Control Point" + default !BT_MCC_MINIMAL + help + This option enables support for setting Media Control Point. + +config BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + bool "Support reading Media Control Point Opcodes Supported" + default !BT_MCC_MINIMAL + help + This option enables support for reading Media Control Point Opcodes Supported. + +config BT_MCC_READ_CONTENT_CONTROL_ID + bool "Support reading Content Control ID" + default !BT_MCC_MINIMAL + help + This option enables support for reading Content Control ID. + endif # BT_MCC diff --git a/subsys/bluetooth/audio/Kconfig.pbp b/subsys/bluetooth/audio/Kconfig.pbp new file mode 100644 index 00000000000..cb24845b202 --- /dev/null +++ b/subsys/bluetooth/audio/Kconfig.pbp @@ -0,0 +1,12 @@ +# Bluetooth Audio - Public Broadcast Profile (PBP) options +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config BT_PBP + bool "Public Broadcast Profile [EXPERIMENTAL]" + select EXPERIMENTAL + help + Enabling this will enable PBP. diff --git a/subsys/bluetooth/audio/aics.c b/subsys/bluetooth/audio/aics.c index f4ff95cac06..1e42cc73da5 100644 --- a/subsys/bluetooth/audio/aics.c +++ b/subsys/bluetooth/audio/aics.c @@ -512,10 +512,8 @@ int bt_aics_register(struct bt_aics *aics, struct bt_aics_register_param *param) k_work_init_delayable(&aics->srv.notify_work, notify_work_handler); if (param->description) { - strncpy(aics->srv.description, param->description, - sizeof(aics->srv.description) - 1); - /* strncpy may not always null-terminate */ - aics->srv.description[sizeof(aics->srv.description) - 1] = '\0'; + (void)utf8_lcpy(aics->srv.description, param->description, + sizeof(aics->srv.description)); if (IS_ENABLED(CONFIG_BT_AICS_LOG_LEVEL_DBG) && strcmp(aics->srv.description, param->description)) { LOG_DBG("Input desc clipped to %s", aics->srv.description); diff --git a/subsys/bluetooth/audio/aics_client.c b/subsys/bluetooth/audio/aics_client.c index 3f160ed0d13..943f6475a38 100644 --- a/subsys/bluetooth/audio/aics_client.c +++ b/subsys/bluetooth/audio/aics_client.c @@ -608,6 +608,8 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att } if (sub_params) { + int err; + sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = chrc->value_handle; /* @@ -616,7 +618,18 @@ static uint8_t aics_discover_func(struct bt_conn *conn, const struct bt_gatt_att */ sub_params->ccc_handle = attr->handle + 2; sub_params->notify = aics_client_notify_handler; - bt_gatt_subscribe(conn, sub_params); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0 && err != -EALREADY) { + LOG_ERR("Failed to subscribe: %d", err); + + if (inst->cli.cb && inst->cli.cb->discover) { + inst->cli.cb->discover(inst, err); + } + + return BT_GATT_ITER_STOP; + } } } @@ -640,16 +653,6 @@ static void aics_client_reset(struct bt_aics *inst) if (inst->cli.conn != NULL) { struct bt_conn *conn = inst->cli.conn; - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &inst->cli.state_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.status_sub_params); - (void)bt_gatt_unsubscribe(conn, &inst->cli.desc_sub_params); - bt_conn_unref(conn); inst->cli.conn = NULL; } @@ -700,7 +703,6 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, (void)memset(&inst->cli.discover_params, 0, sizeof(inst->cli.discover_params)); - inst->cli.conn = bt_conn_ref(conn); inst->cli.discover_params.start_handle = param->start_handle; inst->cli.discover_params.end_handle = param->end_handle; inst->cli.discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; @@ -711,6 +713,7 @@ int bt_aics_discover(struct bt_conn *conn, struct bt_aics *inst, LOG_DBG("Discover failed (err %d)", err); } else { inst->cli.busy = true; + inst->cli.conn = bt_conn_ref(conn); } return err; diff --git a/subsys/bluetooth/audio/ascs.c b/subsys/bluetooth/audio/ascs.c index 6df91e5f43e..40f673166a6 100644 --- a/subsys/bluetooth/audio/ascs.c +++ b/subsys/bluetooth/audio/ascs.c @@ -101,6 +101,52 @@ NET_BUF_SIMPLE_DEFINE_STATIC(ase_buf, ASE_BUF_SIZE); static int control_point_notify(struct bt_conn *conn, const void *data, uint16_t len); static int ascs_ep_get_status(struct bt_bap_ep *ep, struct net_buf_simple *buf); +static void ascs_app_rsp_warn_valid(const struct bt_bap_ascs_rsp *rsp) +{ + /* Validate application error code */ + switch (rsp->code) { + case BT_BAP_ASCS_RSP_CODE_SUCCESS: + case BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_NO_MEM: + case BT_BAP_ASCS_RSP_CODE_UNSPECIFIED: + case BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_CONF_REJECTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED: + break; + default: + LOG_WRN("Invalid application error code: %u", rsp->code); + return; + } + + /* Validate application error code and reason combinations */ + switch (rsp->code) { + case BT_BAP_ASCS_RSP_CODE_SUCCESS: + case BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_NO_MEM: + case BT_BAP_ASCS_RSP_CODE_UNSPECIFIED: + if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { + LOG_WRN("Invalid reason %u for code %u", rsp->reason, rsp->code); + } + break; + case BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_CONF_REJECTED: + if (!IN_RANGE(rsp->reason, BT_BAP_ASCS_REASON_NONE, BT_BAP_ASCS_REASON_CIS)) { + LOG_WRN("Invalid reason %u for code %u", rsp->reason, rsp->code); + } + break; + case BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED: + case BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED: + if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(rsp->metadata_type)) { + LOG_WRN("Invalid metadata type %u for code %u", rsp->metadata_type, + rsp->code); + } + break; + default: + break; + } +} + static bool is_valid_ase_id(uint8_t ase_id) { return IN_RANGE(ase_id, 1, ASE_COUNT); @@ -339,6 +385,7 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; struct bt_bap_stream_ops *ops; + const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep); uint8_t reason = ase->ep.reason; __ASSERT_NO_MSG(stream != NULL); @@ -349,6 +396,20 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) } ops = stream->ops; + + /* + * On link-loss we go from streaming state to QOS configured state, + * and it makes sense to do the disabled callback before entering the + * QOS configured state + */ + if (next_state == BT_BAP_EP_STATE_QOS_CONFIGURED) { + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(stream); + } else { + LOG_WRN("No callback for disabled set"); + } + } + if (ops != NULL && ops->stopped != NULL) { ops->stopped(stream, reason); } else { @@ -356,6 +417,29 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase) } } +static void ase_exit_state_enabling(struct bt_ascs_ase *ase) +{ + struct bt_bap_stream *stream = ase->ep.stream; + struct bt_bap_stream_ops *ops; + const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep); + + ops = stream->ops; + + /* + * When the EP direction is BT_AUDIO_DIR_SOURCE the state machine goes from + * enabled to disabled where the disabled calback will be called, + * for BT_AUDIO_DIR_SINK we go from enabled to qos_configured, + * and logically we have to do the disabled callback first + */ + if (next_state == BT_BAP_EP_STATE_QOS_CONFIGURED && ase->ep.dir == BT_AUDIO_DIR_SINK) { + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(stream); + } else { + LOG_WRN("No callback for disabled set"); + } + } +} + static void ase_enter_state_disabling(struct bt_ascs_ase *ase) { struct bt_bap_stream *stream = ase->ep.stream; @@ -433,7 +517,7 @@ static void state_transition_work_handler(struct k_work *work) } } - LOG_DBG("ase %p id 0x%02x %s -> %s", ase, ase->ep.status.id, + LOG_DBG("ase %p ep %p id 0x%02x %s -> %s", ase, &ase->ep, ase->ep.status.id, bt_bap_ep_state_str(old_state), bt_bap_ep_state_str(new_state)); if (old_state == new_state) { @@ -452,6 +536,9 @@ static void state_transition_work_handler(struct k_work *work) case BT_BAP_EP_STATE_STREAMING: ase_exit_state_streaming(ase); break; + case BT_BAP_EP_STATE_ENABLING: + ase_exit_state_enabling(ase); + break; default: break; } @@ -766,7 +853,8 @@ static void ascs_iso_recv(struct bt_iso_chan *chan, * host as HCI ISO data packets, which we should just ignore */ if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { - LOG_ERR("iso %p not bound with ep", chan); + LOG_DBG("Valid ISO packet of len %zu received for iso %p not bound with ep", + net_buf_frags_len(buf), chan); } return; @@ -853,6 +941,7 @@ static void ascs_update_sdu_size(struct bt_bap_ep *ep) static void ascs_ep_iso_connected(struct bt_bap_ep *ep) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; if (ep->status.state != BT_BAP_EP_STATE_ENABLING) { @@ -877,6 +966,13 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep) */ ascs_update_sdu_size(ep); + LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir)); + + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->connected != NULL) { + stream_ops->connected(stream); + } + if (ep->dir == BT_AUDIO_DIR_SINK && ep->receiver_ready) { /* Source ASEs shall be ISO connected first, and then receive * the receiver start ready command to enter the streaming @@ -884,8 +980,6 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep) */ ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING); } - - LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir)); } static void ascs_iso_connected(struct bt_iso_chan *chan) @@ -909,6 +1003,7 @@ static void ascs_iso_connected(struct bt_iso_chan *chan) static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) { struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; stream = ep->stream; @@ -917,7 +1012,13 @@ static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) return; } - LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); + LOG_DBG("stream %p ep %p state %s reason 0x%02x", stream, stream->ep, + bt_bap_ep_state_str(ep->status.state), reason); + + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->disconnected != NULL) { + stream_ops->disconnected(stream, reason); + } /* Cancel ASE disconnect work if pending */ (void)k_work_cancel_delayable(&ase->disconnect_work); @@ -944,7 +1045,6 @@ static void ascs_iso_disconnected(struct bt_iso_chan *chan, uint8_t reason) struct bt_bap_iso *iso = CONTAINER_OF(chan, struct bt_bap_iso, chan); if (iso->rx.ep == NULL && iso->tx.ep == NULL) { - LOG_ERR("iso %p not bound with ep", chan); return; } @@ -1464,6 +1564,7 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) sys_le16_to_cpu(cfg->codec.vid), (uint8_t *)cfg->cc, cfg->cc_len, &rsp); if (err) { + ascs_app_rsp_warn_valid(&rsp); (void)memcpy(&ase->ep.codec_cfg, &codec_cfg, sizeof(codec_cfg)); ascs_cp_rsp_add(ASE_ID(ase), rsp.code, rsp.reason); return err; @@ -1482,6 +1583,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -1511,6 +1614,8 @@ static int ase_config(struct bt_ascs_ase *ase, const struct bt_ascs_config *cfg) } if (err || stream == NULL) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -1725,23 +1830,15 @@ void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_ } } -static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qos *qos, - struct bt_conn *conn, uint8_t cig_id, uint8_t cis_id, - struct bt_bap_ascs_rsp *rsp) +static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, + struct bt_audio_codec_qos *qos, struct bt_bap_ascs_rsp *rsp) { - struct bt_bap_ep *ep; - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - - CHECKIF(stream == NULL || stream->ep == NULL || qos == NULL) { - LOG_DBG("Invalid input stream, ep or qos pointers"); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, - BT_BAP_ASCS_REASON_NONE); - return -EINVAL; - } - - LOG_DBG("stream %p ep %p qos %p", stream, stream->ep, qos); + struct bt_bap_ep *ep = &ase->ep; + struct bt_bap_stream *stream; - ep = stream->ep; + LOG_DBG("ase %p cig 0x%02x cis 0x%02x interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u " + "latency %u pd %u", ase, cig_id, cis_id, qos->interval, qos->framing, qos->phy, + qos->sdu, qos->rtn, qos->latency, qos->pd); switch (ep->status.state) { /* Valid only if ASE_State field = 0x01 (Codec Configured) */ @@ -1753,19 +1850,32 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state)); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE); - return -EBADMSG; + return; + } + + stream = ep->stream; + if (stream == NULL) { + LOG_ERR("NULL stream"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); + return; + } + + if (stream->ep == NULL) { + LOG_ERR("NULL stream->ep"); + *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); + return; } rsp->reason = bt_audio_verify_qos(qos); if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID; - return -EINVAL; + return; } rsp->reason = bt_bap_stream_verify_qos(stream, qos); if (rsp->reason != BT_BAP_ASCS_REASON_NONE) { rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID; - return -EINVAL; + return; } if (unicast_server_cb != NULL && unicast_server_cb->qos != NULL) { @@ -1779,7 +1889,7 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo LOG_DBG("Application returned error: err %d status %u reason %u", err, rsp->code, rsp->reason); - return err; + return; } } @@ -1791,12 +1901,12 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo if (ep->iso == NULL) { struct bt_bap_iso *iso; - iso = bap_iso_get_or_new(conn, cig_id, cis_id); + iso = bap_iso_get_or_new(ase->conn, cig_id, cis_id); if (iso == NULL) { LOG_ERR("Could not allocate bap_iso"); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE); - return -ENOMEM; + return; } if (bt_bap_iso_get_ep(false, iso, ep->dir) != NULL) { @@ -1805,7 +1915,7 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo bt_bap_iso_unref(iso); *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_CIS); - return -EALREADY; + return; } bt_bap_iso_bind_ep(iso, ep); @@ -1827,32 +1937,6 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_audio_codec_qo ascs_ep_set_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); - return 0; -} - -static void ase_qos(struct bt_ascs_ase *ase, uint8_t cig_id, uint8_t cis_id, - struct bt_audio_codec_qos *cqos, struct bt_bap_ascs_rsp *rsp) -{ - struct bt_bap_ep *ep = &ase->ep; - struct bt_bap_stream *stream = ep->stream; - int err; - - LOG_DBG("ase %p cig 0x%02x cis 0x%02x interval %u framing 0x%02x phy 0x%02x sdu %u rtn %u " - "latency %u pd %u", ase, cig_id, cis_id, cqos->interval, cqos->framing, cqos->phy, - cqos->sdu, cqos->rtn, cqos->latency, cqos->pd); - - err = ase_stream_qos(stream, cqos, ase->conn, cig_id, cis_id, rsp); - if (err) { - if (rsp->code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, - BT_BAP_ASCS_REASON_NONE); - } - - LOG_ERR("QoS failed: err %d, code %u, reason %u", err, rsp->code, rsp->reason); - return; - } - *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE); } @@ -1948,10 +2032,16 @@ static ssize_t ascs_qos(struct bt_conn *conn, struct net_buf_simple *buf) struct ascs_parse_result { int err; + struct bt_conn *conn; struct bt_bap_ascs_rsp *rsp; const struct bt_bap_ep *ep; }; +static bool is_context_available(struct bt_conn *conn, enum bt_audio_dir dir, uint16_t context) +{ + return (context & bt_pacs_get_available_contexts_for_conn(conn, dir)) == context; +} + static bool ascs_parse_metadata(struct bt_data *data, void *user_data) { struct ascs_parse_result *result = user_data; @@ -1991,7 +2081,7 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) /* The CAP acceptor shall not accept metadata with unsupported stream context. */ if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR) && data_type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) { - if (!bt_pacs_context_available(ep->dir, context)) { + if (!is_context_available(result->conn, ep->dir, context)) { LOG_WRN("Context 0x%04x is unavailable", context); *result->rsp = BT_BAP_ASCS_RSP( BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data_type); @@ -2076,7 +2166,9 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data) static int ascs_verify_metadata(struct bt_bap_ep *ep, const struct bt_ascs_metadata *meta, struct bt_bap_ascs_rsp *rsp) { + struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep); struct ascs_parse_result result = { + .conn = ase->conn, .rsp = rsp, .err = 0, .ep = ep, @@ -2150,6 +2242,8 @@ static void ase_metadata(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2205,6 +2299,8 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2351,6 +2447,8 @@ static void ase_start(struct bt_ascs_ase *ase) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); @@ -2553,6 +2651,8 @@ static void ase_stop(struct bt_ascs_ase *ase) } if (err) { + ascs_app_rsp_warn_valid(&rsp); + if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) { rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED, BT_BAP_ASCS_REASON_NONE); diff --git a/subsys/bluetooth/audio/audio.c b/subsys/bluetooth/audio/audio.c index 31e8548376e..164a52afa5e 100644 --- a/subsys/bluetooth/audio/audio.c +++ b/subsys/bluetooth/audio/audio.c @@ -154,214 +154,3 @@ ssize_t bt_audio_ccc_cfg_write(struct bt_conn *conn, const struct bt_gatt_attr * return sizeof(value); } #endif /* CONFIG_BT_CONN */ - -/* Broadcast sink depends on Scan Delegator, so we can just guard it with the Scan Delegator */ -#if defined(CONFIG_BT_BAP_SCAN_DELEGATOR) - -static int decode_bis_data(struct net_buf_simple *buf, struct bt_bap_base_bis_data *bis) -{ - uint8_t len; - - if (buf->len < BT_BAP_BASE_BIS_DATA_MIN_SIZE) { - LOG_DBG("Not enough bytes (%u) to decode BIS data", buf->len); - - return -ENOMEM; - } - - bis->index = net_buf_simple_pull_u8(buf); - if (!IN_RANGE(bis->index, BT_ISO_BIS_INDEX_MIN, BT_ISO_BIS_INDEX_MAX)) { - LOG_DBG("Invalid BIS index %u", bis->index); - - return -EINVAL; - } - - /* codec config data length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid BIS specific codec config data length: %u (buf is %u)", len, - buf->len); - - return -EMSGSIZE; - } - - if (len > 0) { -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - void *ltv_data; - - if (len > sizeof(bis->data)) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } - - ltv_data = net_buf_simple_pull_mem(buf, len); - - bis->data_len = len; - memcpy(bis->data, ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */ - LOG_DBG("Cannot store codec config data"); - - return -ENOMEM; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */ - } - - return 0; -} - -static int decode_subgroup(struct net_buf_simple *buf, struct bt_bap_base_subgroup *subgroup) -{ - struct bt_audio_codec_cfg *codec_cfg; - uint8_t len; - - codec_cfg = &subgroup->codec_cfg; - - subgroup->bis_count = net_buf_simple_pull_u8(buf); - if (subgroup->bis_count > ARRAY_SIZE(subgroup->bis_data)) { - LOG_DBG("BASE has more BIS %u than we support %u", subgroup->bis_count, - (uint8_t)ARRAY_SIZE(subgroup->bis_data)); - - return -ENOMEM; - } - - codec_cfg->id = net_buf_simple_pull_u8(buf); - codec_cfg->cid = net_buf_simple_pull_le16(buf); - codec_cfg->vid = net_buf_simple_pull_le16(buf); - - /* codec configuration data length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid codec config data length: %u (buf is %u)", len, buf->len); - - return -EINVAL; - } - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 - void *cfg_ltv_data; - - if (len > sizeof(subgroup->codec_cfg.data)) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } - - cfg_ltv_data = net_buf_simple_pull_mem(buf, len); - - subgroup->codec_cfg.data_len = len; - memcpy(subgroup->codec_cfg.data, cfg_ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE == 0 */ - if (len > 0) { - LOG_DBG("Cannot store codec config data of length %u", len); - - return -ENOMEM; - } -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ - - /* codec metadata length */ - len = net_buf_simple_pull_u8(buf); - if (len > buf->len) { - LOG_DBG("Invalid codec config data length: %u (buf is %u)", len, buf->len); - - return -EMSGSIZE; - } - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - void *meta_ltv_data; - - if (len > sizeof(subgroup->codec_cfg.meta)) { - LOG_DBG("Cannot store codec config meta of length %u", len); - - return -ENOMEM; - } - - meta_ltv_data = net_buf_simple_pull_mem(buf, len); - - subgroup->codec_cfg.meta_len = len; - memcpy(subgroup->codec_cfg.meta, meta_ltv_data, len); -#else /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE == 0 */ - if (len > 0) { - LOG_DBG("Cannot store metadata"); - - return -ENOMEM; - } -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE */ - - for (size_t i = 0U; i < subgroup->bis_count; i++) { - const int err = decode_bis_data(buf, &subgroup->bis_data[i]); - - if (err != 0) { - LOG_DBG("Failed to decode BIS data for bis[%zu]: %d", i, err); - - return err; - } - } - - return 0; -} - -int bt_bap_decode_base(struct bt_data *data, struct bt_bap_base *base) -{ - struct bt_uuid_16 broadcast_uuid; - struct net_buf_simple net_buf; - void *uuid; - - CHECKIF(data == NULL) { - LOG_DBG("data is NULL"); - - return -EINVAL; - } - - CHECKIF(base == NULL) { - LOG_DBG("base is NULL"); - - return -EINVAL; - } - - if (data->type != BT_DATA_SVC_DATA16) { - LOG_DBG("Invalid type: %u", data->type); - - return -ENOMSG; - } - - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { - return -EMSGSIZE; - } - - net_buf_simple_init_with_data(&net_buf, (void *)data->data, - data->data_len); - - uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16); - if (!bt_uuid_create(&broadcast_uuid.uuid, uuid, BT_UUID_SIZE_16)) { - LOG_ERR("bt_uuid_create failed"); - - return -EINVAL; - } - - if (bt_uuid_cmp(&broadcast_uuid.uuid, BT_UUID_BASIC_AUDIO) != 0) { - LOG_DBG("Invalid UUID"); - - return -ENOMSG; - } - - base->pd = net_buf_simple_pull_le24(&net_buf); - base->subgroup_count = net_buf_simple_pull_u8(&net_buf); - - if (base->subgroup_count > ARRAY_SIZE(base->subgroups)) { - LOG_DBG("Cannot decode BASE with %u subgroups (max supported is %zu)", - base->subgroup_count, ARRAY_SIZE(base->subgroups)); - - return -ENOMEM; - } - - for (size_t i = 0U; i < base->subgroup_count; i++) { - const int err = decode_subgroup(&net_buf, &base->subgroups[i]); - - if (err != 0) { - LOG_DBG("Failed to decode subgroup[%zu]: %d", i, err); - - return err; - } - } - - return 0; -} -#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */ diff --git a/subsys/bluetooth/audio/bap_base.c b/subsys/bluetooth/audio/bap_base.c new file mode 100644 index 00000000000..67a58c27a3b --- /dev/null +++ b/subsys/bluetooth/audio/bap_base.c @@ -0,0 +1,564 @@ +/* bap_base.c - BAP BASE handling */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bt_bap_base, CONFIG_BT_BAP_BASE_LOG_LEVEL); + +/* The BASE and the following defines are defined by BAP v1.0.1, section 3.7.2.2 Basic Audio + * Announcements + */ +#define BASE_MAX_SIZE (UINT8_MAX - 1 /* type */ - BT_UUID_SIZE_16) +#define BASE_CODEC_ID_SIZE (1 /* id */ + 2 /* cid */ + 2 /* vid */) +#define BASE_PD_SIZE 3 +#define BASE_SUBGROUP_COUNT_SIZE 1 +#define BASE_NUM_BIS_SIZE 1 +#define BASE_CC_LEN_SIZE 1 +#define BASE_META_LEN_SIZE 1 +#define BASE_BIS_INDEX_SIZE 1 +#define BASE_BIS_CC_LEN_SIZE 1 +#define BASE_SUBGROUP_MAX_SIZE (BASE_MAX_SIZE - BASE_PD_SIZE - BASE_SUBGROUP_COUNT_SIZE) +#define BASE_SUBGROUP_MIN_SIZE \ + (BASE_NUM_BIS_SIZE + BASE_CODEC_ID_SIZE + BASE_CC_LEN_SIZE + BASE_META_LEN_SIZE + \ + BASE_BIS_INDEX_SIZE + BASE_BIS_CC_LEN_SIZE) +#define BASE_MIN_SIZE \ + (BT_UUID_SIZE_16 + BASE_PD_SIZE + BASE_SUBGROUP_COUNT_SIZE + BASE_SUBGROUP_MIN_SIZE) +#define BASE_SUBGROUP_MAX_COUNT (BASE_MAX_SIZE / BASE_SUBGROUP_MIN_SIZE) + +static uint32_t base_pull_pd(struct net_buf_simple *net_buf) +{ + return net_buf_simple_pull_le24(net_buf); +} + +static uint8_t base_pull_bis_count(struct net_buf_simple *net_buf) +{ + return net_buf_simple_pull_u8(net_buf); +} + +static void base_pull_codec_id(struct net_buf_simple *net_buf, + struct bt_bap_base_codec_id *codec_id) +{ + struct bt_bap_base_codec_id codec; + + codec.id = net_buf_simple_pull_u8(net_buf); /* coding format */ + codec.cid = net_buf_simple_pull_le16(net_buf); /* company id */ + codec.vid = net_buf_simple_pull_le16(net_buf); /* VS codec id */ + + if (codec_id != NULL) { + *codec_id = codec; + } +} + +static uint8_t base_pull_ltv(struct net_buf_simple *net_buf, uint8_t **data) +{ + const uint8_t len = net_buf_simple_pull_u8(net_buf); + + if (data == NULL) { + net_buf_simple_pull_mem(net_buf, len); + } else { + *data = net_buf_simple_pull_mem(net_buf, len); + } + + return len; +} + +static bool check_pull_ltv(struct net_buf_simple *net_buf) +{ + uint8_t ltv_len; + + if (net_buf->len < sizeof(ltv_len)) { + return false; + } + + ltv_len = net_buf_simple_pull_u8(net_buf); + if (net_buf->len < ltv_len) { + return false; + } + net_buf_simple_pull_mem(net_buf, ltv_len); + + return true; +} + +const struct bt_bap_base *bt_bap_base_get_base_from_ad(const struct bt_data *ad) +{ + struct bt_uuid_16 broadcast_uuid; + const struct bt_bap_base *base; + struct net_buf_simple net_buf; + uint8_t subgroup_count; + void *uuid; + + CHECKIF(ad == NULL) { + LOG_DBG("data is NULL"); + + return NULL; + } + + if (ad->type != BT_DATA_SVC_DATA16) { + LOG_DBG("Invalid type: %u", ad->type); + + return NULL; + } + + if (ad->data_len < BASE_MIN_SIZE) { + LOG_DBG("Invalid len: %u", ad->data_len); + + return NULL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)ad->data, ad->data_len); + + uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16); + if (!bt_uuid_create(&broadcast_uuid.uuid, uuid, BT_UUID_SIZE_16)) { + LOG_ERR("bt_uuid_create failed"); + + return NULL; + } + + if (bt_uuid_cmp(&broadcast_uuid.uuid, BT_UUID_BASIC_AUDIO) != 0) { + LOG_DBG("Invalid UUID"); + + return NULL; + } + + /* Store the start of the BASE */ + base = (const struct bt_bap_base *)net_buf.data; + + /* Pull all data to verify that the result BASE is valid */ + base_pull_pd(&net_buf); + subgroup_count = net_buf_simple_pull_u8(&net_buf); + if (subgroup_count == 0 || subgroup_count > BASE_SUBGROUP_MAX_COUNT) { + LOG_DBG("Invalid subgroup count: %u", subgroup_count); + + return NULL; + } + + for (uint8_t i = 0U; i < subgroup_count; i++) { + uint8_t bis_count; + + if (net_buf.len < sizeof(bis_count)) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + + bis_count = base_pull_bis_count(&net_buf); + if (bis_count == 0 || bis_count > BT_ISO_MAX_GROUP_ISO_COUNT) { + LOG_DBG("Subgroup[%u]: Invalid BIS count: %u", i, bis_count); + + return NULL; + } + + if (net_buf.len < BASE_CODEC_ID_SIZE) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + + base_pull_codec_id(&net_buf, NULL); + + /* Pull CC */ + if (!check_pull_ltv(&net_buf)) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + + /* Pull meta */ + if (!check_pull_ltv(&net_buf)) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + + for (uint8_t j = 0U; j < bis_count; j++) { + uint8_t bis_index; + + if (net_buf.len < sizeof(bis_index)) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + + bis_index = net_buf_simple_pull_u8(&net_buf); + if (bis_index == 0 || bis_index > BT_ISO_BIS_INDEX_MAX) { + LOG_DBG("Subgroup[%u]: Invalid BIS index: %u", i, bis_index); + + return NULL; + } + + /* Pull BIS CC data */ + if (!check_pull_ltv(&net_buf)) { + LOG_DBG("Invalid BASE length: %u", ad->data_len); + + return NULL; + } + } + } + + return base; +} + +int bt_bap_base_get_pres_delay(const struct bt_bap_base *base) +{ + struct net_buf_simple net_buf; + uint32_t pd; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, sizeof(pd)); + pd = base_pull_pd(&net_buf); + + return (int)pd; /* PD is 24-bit so it fits in an int */ +} + +int bt_bap_base_get_subgroup_count(const struct bt_bap_base *base) +{ + struct net_buf_simple net_buf; + uint8_t subgroup_count; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE); + base_pull_pd(&net_buf); + subgroup_count = net_buf_simple_pull_u8(&net_buf); + + return (int)subgroup_count; /* subgroup_count is 8-bit so it fits in an int */ +} + +int bt_bap_base_foreach_subgroup(const struct bt_bap_base *base, + bool (*func)(const struct bt_bap_base_subgroup *data, + void *user_data), + void *user_data) +{ + struct bt_bap_base_subgroup *subgroup; + struct net_buf_simple net_buf; + uint8_t subgroup_count; + + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + CHECKIF(func == NULL) { + LOG_DBG("func is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)base, BASE_MAX_SIZE); + base_pull_pd(&net_buf); + subgroup_count = net_buf_simple_pull_u8(&net_buf); + + for (uint8_t i = 0U; i < subgroup_count; i++) { + subgroup = (struct bt_bap_base_subgroup *)net_buf.data; + if (!func(subgroup, user_data)) { + LOG_DBG("user stopped parsing"); + + return -ECANCELED; + } + + /* Parse subgroup data to get next subgroup pointer */ + if (subgroup_count > 1) { /* Only parse data if it isn't the last one */ + uint8_t bis_count; + + bis_count = base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + + /* meta */ + base_pull_ltv(&net_buf, NULL); + + for (uint8_t j = 0U; j < bis_count; j++) { + net_buf_simple_pull_u8(&net_buf); /* index */ + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + } + } + } + + return 0; +} + +int bt_bap_base_get_subgroup_codec_id(const struct bt_bap_base_subgroup *subgroup, + struct bt_bap_base_codec_id *codec_id) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_id == NULL) { + LOG_DBG("codec_id is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, codec_id); + + return 0; +} + +int bt_bap_base_get_subgroup_codec_data(const struct bt_bap_base_subgroup *subgroup, uint8_t **data) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(data == NULL) { + LOG_DBG("data is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + return base_pull_ltv(&net_buf, data); +} + +int bt_bap_base_get_subgroup_codec_meta(const struct bt_bap_base_subgroup *subgroup, uint8_t **meta) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + + /* meta */ + return base_pull_ltv(&net_buf, meta); +} + +int bt_bap_base_subgroup_codec_to_codec_cfg(const struct bt_bap_base_subgroup *subgroup, + struct bt_audio_codec_cfg *codec_cfg) +{ + struct bt_bap_base_codec_id codec_id; + struct net_buf_simple net_buf; + uint8_t *ltv_data; + uint8_t ltv_len; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, &codec_id); + + codec_cfg->id = codec_id.id; + codec_cfg->cid = codec_id.cid; + codec_cfg->vid = codec_id.vid; + + /* Codec config */ + ltv_len = base_pull_ltv(&net_buf, <v_data); + + if (ltv_len > ARRAY_SIZE(codec_cfg->data)) { + LOG_DBG("Cannot fit %u octets of codec data (max %zu)", ltv_len, + ARRAY_SIZE(codec_cfg->data)); + + return -ENOMEM; + } + + codec_cfg->data_len = ltv_len; + memcpy(codec_cfg->data, ltv_data, ltv_len); + + /* Meta */ + ltv_len = base_pull_ltv(&net_buf, <v_data); + + if (ltv_len > ARRAY_SIZE(codec_cfg->meta)) { + LOG_DBG("Cannot fit %u octets of codec meta (max %zu)", ltv_len, + ARRAY_SIZE(codec_cfg->meta)); + + return -ENOMEM; + } + + codec_cfg->meta_len = ltv_len; + memcpy(codec_cfg->meta, ltv_data, ltv_len); + + return 0; +} +int bt_bap_base_get_subgroup_bis_count(const struct bt_bap_base_subgroup *subgroup) +{ + struct net_buf_simple net_buf; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + + return base_pull_bis_count(&net_buf); +} + +int bt_bap_base_subgroup_foreach_bis(const struct bt_bap_base_subgroup *subgroup, + bool (*func)(const struct bt_bap_base_subgroup_bis *subgroup, + void *user_data), + void *user_data) +{ + struct net_buf_simple net_buf; + uint8_t bis_count; + + CHECKIF(subgroup == NULL) { + LOG_DBG("subgroup is NULL"); + + return -EINVAL; + } + + CHECKIF(func == NULL) { + LOG_DBG("func is NULL"); + + return -EINVAL; + } + + net_buf_simple_init_with_data(&net_buf, (void *)subgroup, BASE_SUBGROUP_MAX_SIZE); + + bis_count = base_pull_bis_count(&net_buf); + base_pull_codec_id(&net_buf, NULL); + + /* Codec config */ + base_pull_ltv(&net_buf, NULL); + + /* meta */ + base_pull_ltv(&net_buf, NULL); + + for (uint8_t i = 0U; i < bis_count; i++) { + struct bt_bap_base_subgroup_bis bis; + + bis.index = net_buf_simple_pull_u8(&net_buf); /* index */ + + /* Codec config */ + bis.data_len = base_pull_ltv(&net_buf, &bis.data); + + if (!func(&bis, user_data)) { + LOG_DBG("user stopped parsing"); + + return -ECANCELED; + } + } + + return 0; +} + +int bt_bap_base_subgroup_bis_codec_to_codec_cfg(const struct bt_bap_base_subgroup_bis *bis, + struct bt_audio_codec_cfg *codec_cfg) +{ + CHECKIF(bis == NULL) { + LOG_DBG("bis is NULL"); + + return -EINVAL; + } + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + + return -EINVAL; + } + + if (bis->data_len > ARRAY_SIZE(codec_cfg->data)) { + LOG_DBG("Cannot fit %u octets of codec data (max %zu)", bis->data_len, + ARRAY_SIZE(codec_cfg->data)); + + return -ENOMEM; + } + + codec_cfg->data_len = bis->data_len; + memcpy(codec_cfg->data, bis->data, bis->data_len); + + return 0; +} + +static bool base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + uint32_t *base_bis_index_bitfield = user_data; + + *base_bis_index_bitfield |= BIT(bis->index); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + const int err = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_cb, user_data); + + if (err != 0) { + LOG_DBG("Failed to parse all BIS: %d", err); + return false; + } + + return true; +} + +int bt_bap_base_get_bis_indexes(const struct bt_bap_base *base, uint32_t *bis_indexes) +{ + CHECKIF(base == NULL) { + LOG_DBG("base is NULL"); + + return -EINVAL; + } + + CHECKIF(bis_indexes == NULL) { + LOG_DBG("bis_indexes is NULL"); + + return -EINVAL; + } + + *bis_indexes = 0U; + + return bt_bap_base_foreach_subgroup(base, base_subgroup_cb, bis_indexes); +} diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 36c8c46171f..b2047998ce8 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,7 +35,7 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_assistant, CONFIG_BT_BAP_BROADCAST_ASSISTAN #define MINIMUM_RECV_STATE_LEN 15 struct bap_broadcast_assistant_instance { - bool discovering; + struct bt_conn *conn; bool scanning; uint8_t pa_sync; uint8_t recv_state_cnt; @@ -57,6 +59,9 @@ struct bap_broadcast_assistant_instance { struct bt_gatt_read_params read_params; struct bt_gatt_write_params write_params; struct bt_gatt_discover_params disc_params; + + struct k_work_delayable bap_read_work; + uint16_t long_read_handle; }; static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; @@ -64,7 +69,8 @@ static struct bt_bap_broadcast_assistant_cb *broadcast_assistant_cbs; static struct bap_broadcast_assistant_instance broadcast_assistant; static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); -NET_BUF_SIMPLE_DEFINE_STATIC(cp_buf, CONFIG_BT_L2CAP_TX_MTU); +#define ATT_BUF_SIZE BT_ATT_MAX_ATTRIBUTE_LEN +NET_BUF_SIMPLE_DEFINE_STATIC(att_buf, ATT_BUF_SIZE); static int16_t lookup_index_by_handle(uint16_t handle) { @@ -184,6 +190,144 @@ static int parse_recv_state(const void *data, uint16_t length, return 0; } +static void bap_long_op_reset(void) +{ + broadcast_assistant.busy = false; + broadcast_assistant.long_read_handle = 0; + net_buf_simple_reset(&att_buf); +} + +static uint8_t parse_and_send_recv_state(struct bt_conn *conn, uint16_t handle, + const void *data, uint16_t length, + struct bt_bap_scan_delegator_recv_state *recv_state) +{ + int err; + int16_t index; + + err = parse_recv_state(data, length, recv_state); + if (err != 0) { + LOG_WRN("Invalid receive state received"); + + return BT_GATT_ITER_STOP; + } + + index = lookup_index_by_handle(handle); + if (index < 0) { + LOG_DBG("Invalid index"); + + return BT_GATT_ITER_STOP; + } + + broadcast_assistant.src_ids[index] = recv_state->src_id; + broadcast_assistant.past_avail[index] = past_available(conn, + &recv_state->addr, + recv_state->adv_sid); + + if (broadcast_assistant_cbs != NULL && + broadcast_assistant_cbs->recv_state != NULL) { + broadcast_assistant_cbs->recv_state(conn, 0, recv_state); + } + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t broadcast_assistant_bap_ntf_read_func(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *read, + const void *data, uint16_t length) +{ + struct bt_bap_scan_delegator_recv_state recv_state; + uint16_t handle = read->single.handle; + uint16_t data_length; + + LOG_DBG("conn %p err 0x%02x len %u", conn, err, length); + + if (err) { + LOG_DBG("Failed to read: %u", err); + memset(read, 0, sizeof(*read)); + bap_long_op_reset(); + + return BT_GATT_ITER_STOP; + } + + LOG_DBG("handle 0x%04x", handle); + + if (data != NULL) { + if (net_buf_simple_tailroom(&att_buf) < length) { + LOG_DBG("Buffer full, invalid server response of size %u", + length + att_buf.len); + memset(read, 0, sizeof(*read)); + bap_long_op_reset(); + + return BT_GATT_ITER_STOP; + } + + /* store data*/ + net_buf_simple_add_mem(&att_buf, data, length); + + return BT_GATT_ITER_CONTINUE; + } + + /* we reset the buffer so that it is ready for new data */ + memset(read, 0, sizeof(*read)); + data_length = att_buf.len; + bap_long_op_reset(); + + /* do the parse and callback to send notify to application*/ + parse_and_send_recv_state(conn, handle, + att_buf.data, data_length, &recv_state); + + return BT_GATT_ITER_STOP; +} + +static void long_bap_read(struct bt_conn *conn, uint16_t handle) +{ + int err; + + LOG_DBG("conn %p busy %u", conn, broadcast_assistant.busy); + + if (broadcast_assistant.busy) { + /* If the client is busy reading or writing something else, reschedule the + * long read. + */ + struct bt_conn_info conn_info; + + err = bt_conn_get_info(conn, &conn_info); + if (err != 0) { + LOG_DBG("Failed to get conn info, use default interval"); + + conn_info.le.interval = BT_GAP_INIT_CONN_INT_MIN; + } + + /* Wait a connection interval to retry */ + err = k_work_reschedule(&broadcast_assistant.bap_read_work, + K_USEC(BT_CONN_INTERVAL_TO_US(conn_info.le.interval))); + if (err < 0) { + LOG_DBG("Failed to reschedule read work: %d", err); + bap_long_op_reset(); + } + + return; + } + + broadcast_assistant.read_params.func = broadcast_assistant_bap_ntf_read_func; + broadcast_assistant.read_params.handle_count = 1U; + broadcast_assistant.read_params.single.handle = handle; + broadcast_assistant.read_params.single.offset = att_buf.len; + + err = bt_gatt_read(conn, &broadcast_assistant.read_params); + if (err != 0) { + LOG_DBG("Failed to read: %d", err); + bap_long_op_reset(); + } else { + broadcast_assistant.busy = true; + } +} + +static void delayed_bap_read_handler(struct k_work *work) +{ + long_bap_read(broadcast_assistant.conn, broadcast_assistant.long_read_handle); +} + /** @brief Handles notifications and indications from the server */ static uint8_t notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, @@ -191,7 +335,6 @@ static uint8_t notify_handler(struct bt_conn *conn, { uint16_t handle = params->value_handle; struct bt_bap_scan_delegator_recv_state recv_state; - int err; int16_t index; if (data == NULL) { @@ -206,30 +349,37 @@ static uint8_t notify_handler(struct bt_conn *conn, index = lookup_index_by_handle(handle); if (index < 0) { LOG_DBG("Invalid index"); + return BT_GATT_ITER_STOP; } if (length != 0) { - err = parse_recv_state(data, length, &recv_state); + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ + uint16_t max_ntf_size; - if (err != 0) { - /* TODO: Likely due to the length. - * Start a read autonomously - */ - LOG_WRN("Invalid receive state received"); + /* Cancel any pending long reads containing now obsolete information */ + (void)k_work_cancel_delayable(&broadcast_assistant.bap_read_work); - return BT_GATT_ITER_STOP; + if (conn != NULL) { + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; + } else { + max_ntf_size = MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU) - att_ntf_header_size; } - broadcast_assistant.src_ids[index] = recv_state.src_id; - broadcast_assistant.past_avail[index] = past_available(conn, - &recv_state.addr, - recv_state.adv_sid); + if (length == max_ntf_size) { + /* TODO: if we are busy we should not overwrite the long_read_handle, + * we'll have to keep track of the handle and parameters separately + * for each characteristic, similar to the bt_bap_unicast_client_ep + * struct for the unicast client + */ + broadcast_assistant.long_read_handle = handle; - if (broadcast_assistant_cbs != NULL && - broadcast_assistant_cbs->recv_state != NULL) { - broadcast_assistant_cbs->recv_state(conn, 0, & - recv_state); + if (!broadcast_assistant.busy) { + net_buf_simple_add_mem(&att_buf, data, length); + } + long_bap_read(conn, handle); + } else { + return parse_and_send_recv_state(conn, handle, data, length, &recv_state); } } else if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->recv_state_removed != NULL) { @@ -280,8 +430,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, if (cb_err != 0) { LOG_DBG("err: %d", cb_err); - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -296,8 +446,8 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, } } } else if (handle == last_handle) { - if (broadcast_assistant.discovering) { - broadcast_assistant.discovering = false; + if (broadcast_assistant.busy) { + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover( @@ -333,6 +483,13 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +static void discover_init(void) +{ + k_work_init_delayable(&broadcast_assistant.bap_read_work, delayed_bap_read_handler); + + net_buf_simple_reset(&att_buf); +} + /** * @brief This will discover all characteristics on the server, retrieving the * handles of the writeable characteristics and subscribing to all notify and @@ -352,7 +509,7 @@ static uint8_t char_discover_func(struct bt_conn *conn, err = bt_bap_broadcast_assistant_read_recv_state(conn, 0); if (err != 0) { - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, err, 0); @@ -392,13 +549,14 @@ static uint8_t char_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = attr->handle + 1; sub_params->notify = notify_handler; - err = bt_gatt_subscribe(conn, sub_params); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - if (err != 0 && err != -EALREADY) { + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0) { LOG_DBG("Could not subscribe to handle 0x%04x: %d", sub_params->value_handle, err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { broadcast_assistant_cbs->discover(conn, @@ -425,7 +583,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, LOG_DBG("Could not discover BASS"); (void)memset(params, 0, sizeof(*params)); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -452,7 +610,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &broadcast_assistant.disc_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - broadcast_assistant.discovering = false; + broadcast_assistant.busy = false; if (broadcast_assistant_cbs != NULL && broadcast_assistant_cbs->discover != NULL) { @@ -467,7 +625,7 @@ static uint8_t service_discover_func(struct bt_conn *conn, static void bap_broadcast_assistant_write_cp_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - uint8_t opcode = net_buf_simple_pull_u8(&cp_buf); + uint8_t opcode = net_buf_simple_pull_u8(&att_buf); broadcast_assistant.busy = false; @@ -475,6 +633,9 @@ static void bap_broadcast_assistant_write_cp_cb(struct bt_conn *conn, uint8_t er return; } + /* we reset the buffer, so that we are ready for new notifications and writes */ + net_buf_simple_reset(&att_buf); + switch (opcode) { case BT_BAP_BASS_OP_SCAN_STOP: if (broadcast_assistant_cbs->scan_stop != NULL) { @@ -594,6 +755,70 @@ static struct bt_le_scan_cb scan_cb = { /****************************** PUBLIC API ******************************/ +static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *inst) +{ + inst->busy = false; + inst->scanning = false; + inst->pa_sync = 0U; + inst->recv_state_cnt = 0U; + inst->start_handle = 0U; + inst->end_handle = 0U; + inst->cp_handle = 0U; + inst->long_read_handle = 0; + (void)k_work_cancel_delayable(&inst->bap_read_work); + + for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT; i++) { + inst->src_ids[i] = 0U; + inst->past_avail[i] = false; + inst->recv_state_handles[i] = 0U; + } + + if (inst->conn != NULL) { + struct bt_conn *conn = inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + for (size_t i = 0U; i < ARRAY_SIZE(inst->recv_state_sub_params); i++) { + /* It's okay if this fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &inst->recv_state_sub_params[i]); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to state: %d", err); + + return err; + } + } + } + + bt_conn_unref(conn); + inst->conn = NULL; + } + + /* The subscribe parameters must remain instact so they can get cleaned up by GATT */ + memset(&inst->disc_params, 0, sizeof(inst->disc_params)); + memset(&inst->recv_state_disc_params, 0, sizeof(inst->recv_state_disc_params)); + memset(&inst->read_params, 0, sizeof(inst->read_params)); + memset(&inst->write_params, 0, sizeof(inst->write_params)); + + return 0; +} + +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + (void)broadcast_assistant_reset(&broadcast_assistant); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected_cb, +}; + int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) { int err; @@ -604,21 +829,34 @@ int bt_bap_broadcast_assistant_discover(struct bt_conn *conn) return -EINVAL; } + if (broadcast_assistant.busy) { + LOG_DBG("Instance is busy"); + return -EBUSY; + } + + err = broadcast_assistant_reset(&broadcast_assistant); + if (err != 0) { + LOG_DBG("Failed to reset broadcast assistant: %d", err); + + return err; + } + /* Discover BASS on peer, setup handles and notify */ - (void)memset(&broadcast_assistant, 0, sizeof(broadcast_assistant)); + discover_init(); + (void)memcpy(&uuid, BT_UUID_BASS, sizeof(uuid)); broadcast_assistant.disc_params.func = service_discover_func; broadcast_assistant.disc_params.uuid = &uuid.uuid; broadcast_assistant.disc_params.type = BT_GATT_DISCOVER_PRIMARY; broadcast_assistant.disc_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; broadcast_assistant.disc_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - err = bt_gatt_discover(conn, &broadcast_assistant.disc_params); if (err != 0) { return err; } - broadcast_assistant.discovering = true; + broadcast_assistant.busy = true; + broadcast_assistant.conn = bt_conn_ref(conn); return 0; } @@ -666,12 +904,12 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_SCAN_START; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn) @@ -705,12 +943,12 @@ int bt_bap_broadcast_assistant_scan_stop(struct bt_conn *conn) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_SCAN_STOP; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, @@ -733,8 +971,8 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_ADD_SRC; cp->adv_sid = param->adv_sid; @@ -760,15 +998,16 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, sizeof(subgroup->metadata_len) + param->subgroups[i].metadata_len; - if (cp_buf.len + subgroup_size > cp_buf.size) { - LOG_DBG("MTU is too small to send %zu octets", cp_buf.len + subgroup_size); + if (att_buf.len + subgroup_size > att_buf.size) { + LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size); return -EINVAL; } - subgroup = net_buf_simple_add(&cp_buf, subgroup_size); + subgroup = net_buf_simple_add(&att_buf, subgroup_size); - subgroup->bis_sync = param->subgroups[i].bis_sync; + /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ + subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) { LOG_DBG("Only syncing to BIS is not allowed"); @@ -786,7 +1025,7 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn, } - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, @@ -811,8 +1050,8 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_MOD_SRC; cp->src_id = param->src_id; @@ -854,13 +1093,14 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, sizeof(subgroup->metadata_len) + param->subgroups[i].metadata_len; - if (cp_buf.len + subgroup_size > cp_buf.size) { - LOG_DBG("MTU is too small to send %zu octets", cp_buf.len + subgroup_size); + if (att_buf.len + subgroup_size > att_buf.size) { + LOG_DBG("MTU is too small to send %zu octets", att_buf.len + subgroup_size); return -EINVAL; } - subgroup = net_buf_simple_add(&cp_buf, subgroup_size); + subgroup = net_buf_simple_add(&att_buf, subgroup_size); - subgroup->bis_sync = param->subgroups[i].bis_sync; + /* The BIS Index bitfield to be sent must use BIT(0) for BIS Index 1 */ + subgroup->bis_sync = param->subgroups[i].bis_sync >> 1; CHECKIF(param->pa_sync == 0 && subgroup->bis_sync != 0) { LOG_DBG("Only syncing to BIS is not allowed"); @@ -877,7 +1117,7 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn, } } - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_set_broadcast_code( @@ -901,8 +1141,8 @@ int bt_bap_broadcast_assistant_set_broadcast_code( } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_BROADCAST_CODE; cp->src_id = src_id; @@ -912,7 +1152,7 @@ int bt_bap_broadcast_assistant_set_broadcast_code( LOG_HEXDUMP_DBG(cp->broadcast_code, BT_AUDIO_BROADCAST_CODE_SIZE, "broadcast code:"); - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id) @@ -934,13 +1174,13 @@ int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id) } /* Reset buffer before using */ - net_buf_simple_reset(&cp_buf); - cp = net_buf_simple_add(&cp_buf, sizeof(*cp)); + net_buf_simple_reset(&att_buf); + cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp->opcode = BT_BAP_BASS_OP_REM_SRC; cp->src_id = src_id; - return bt_bap_broadcast_assistant_common_cp(conn, &cp_buf); + return bt_bap_broadcast_assistant_common_cp(conn, &att_buf); } int bt_bap_broadcast_assistant_read_recv_state(struct bt_conn *conn, diff --git a/subsys/bluetooth/audio/bap_broadcast_sink.c b/subsys/bluetooth/audio/bap_broadcast_sink.c index aa4bc08f761..3ec003349f5 100644 --- a/subsys/bluetooth/audio/bap_broadcast_sink.c +++ b/subsys/bluetooth/audio/bap_broadcast_sink.c @@ -41,7 +41,7 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_sink, CONFIG_BT_BAP_BROADCAST_SINK_LOG_LEVE #define INVALID_BROADCAST_ID 0xFFFFFFFF static struct bt_bap_ep broadcast_sink_eps[CONFIG_BT_BAP_BROADCAST_SNK_COUNT] - [BROADCAST_SNK_STREAM_CNT]; + [CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct bt_bap_broadcast_sink broadcast_sinks[CONFIG_BT_BAP_BROADCAST_SNK_COUNT]; struct codec_cap_lookup_id_data { @@ -91,8 +91,7 @@ static bool find_recv_state_by_pa_sync_cb(const struct bt_bap_scan_delegator_rec static void update_recv_state_big_synced(const struct bt_bap_broadcast_sink *sink) { const struct bt_bap_scan_delegator_recv_state *recv_state; - struct bt_bap_scan_delegator_mod_src_param mod_src_param = { 0 }; - const struct bt_bap_base *base; + struct bt_bap_scan_delegator_mod_src_param mod_src_param = {0}; int err; recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_sink_cb, (void *)sink); @@ -102,24 +101,13 @@ static void update_recv_state_big_synced(const struct bt_bap_broadcast_sink *sin return; } - base = &sink->base; - - mod_src_param.num_subgroups = base->subgroup_count; - for (uint8_t i = 0U; i < base->subgroup_count; i++) { + mod_src_param.num_subgroups = sink->subgroup_count; + for (uint8_t i = 0U; i < sink->subgroup_count; i++) { struct bt_bap_scan_delegator_subgroup *subgroup_param = &mod_src_param.subgroups[i]; - const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; - - /* Update the BIS sync indexes for the subgroup based on the BASE*/ - for (size_t j = 0U; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data = &subgroup->bis_data[j]; - - subgroup_param->bis_sync |= BIT(bis_data->index); - } + const struct bt_bap_broadcast_sink_subgroup *sink_subgroup = &sink->subgroups[i]; - /* Update the bis_sync so that the bis_sync value only contains the indexes that we - * are actually synced to - */ - subgroup_param->bis_sync &= sink->indexes_bitfield; + /* Set the bis_sync value to the indexes available per subgroup */ + subgroup_param->bis_sync = sink_subgroup->bis_indexes & sink->indexes_bitfield; } if (recv_state->encrypt_state == BT_BAP_BIG_ENC_STATE_BCODE_REQ) { @@ -308,10 +296,13 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan) return; } - ops = stream->ops; - LOG_DBG("stream %p", stream); + ops = stream->ops; + if (ops != NULL && ops->connected != NULL) { + ops->connected(stream); + } + sink = broadcast_sink_lookup_iso_chan(chan); if (sink == NULL) { LOG_ERR("Could not lookup sink by iso %p", chan); @@ -323,7 +314,7 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan) if (ops != NULL && ops->started != NULL) { ops->started(stream); } else { - LOG_WRN("No callback for connected set"); + LOG_WRN("No callback for started set"); } all_connected = true; @@ -361,10 +352,13 @@ static void broadcast_sink_iso_disconnected(struct bt_iso_chan *chan, return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason); + ops = stream->ops; + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(stream, reason); + } + broadcast_sink_set_ep_state(ep, BT_BAP_EP_STATE_IDLE); sink = broadcast_sink_lookup_iso_chan(chan); @@ -443,33 +437,44 @@ static void broadcast_sink_add_src(struct bt_bap_broadcast_sink *sink) } } -static int update_recv_state_base_copy_meta(const struct bt_bap_base *base, - struct bt_bap_scan_delegator_mod_src_param *param) +static bool base_subgroup_meta_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) { - if (base->subgroup_count > ARRAY_SIZE(param->subgroups)) { - LOG_DBG("Could not fit %zu subgroups in the mod param (max %zu)", - base->subgroup_count, ARRAY_SIZE(param->subgroups)); + struct bt_bap_scan_delegator_mod_src_param *mod_src_param = user_data; + struct bt_bap_scan_delegator_subgroup *subgroup_param; + uint8_t *meta; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &meta); + if (ret < 0) { + return false; } - param->num_subgroups = base->subgroup_count; + subgroup_param = &mod_src_param->subgroups[mod_src_param->num_subgroups++]; + subgroup_param->metadata_len = (uint8_t)ret; + memcpy(subgroup_param->metadata, meta, subgroup_param->metadata_len); - for (uint8_t i = 0U; i < base->subgroup_count; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup_param = ¶m->subgroups[i]; - const struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; + return true; +} - subgroup_param->metadata_len = subgroup->codec_cfg.meta_len; - memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta, - subgroup->codec_cfg.meta_len); +static int update_recv_state_base_copy_meta(const struct bt_bap_base *base, + struct bt_bap_scan_delegator_mod_src_param *param) +{ + int err; + + err = bt_bap_base_foreach_subgroup(base, base_subgroup_meta_cb, param); + if (err != 0) { + LOG_DBG("Failed to parse subgroups: %d", err); + return err; } return 0; } -static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) +static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink, + const struct bt_bap_base *base) { struct bt_bap_scan_delegator_mod_src_param mod_src_param = { 0 }; const struct bt_bap_scan_delegator_recv_state *recv_state; - const struct bt_bap_base *base; int err; recv_state = bt_bap_scan_delegator_find_state(find_recv_state_by_sink_cb, (void *)sink); @@ -479,8 +484,6 @@ static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) return; } - base = &sink->base; - err = update_recv_state_base_copy_meta(base, &mod_src_param); if (err != 0) { LOG_WRN("Failed to modify Receive State for sink %p: %d", sink, err); @@ -498,55 +501,180 @@ static void update_recv_state_base(const struct bt_bap_broadcast_sink *sink) } } -static bool pa_decode_base(struct bt_data *data, void *user_data) +static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) { - struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data; - struct bt_bap_broadcast_sink_cb *listener; - struct bt_bap_base base = { 0 }; + struct codec_cap_lookup_id_data *data = user_data; - if (data->type != BT_DATA_SVC_DATA16) { - return true; + if (cap->codec_cap->id == data->id) { + data->codec_cap = cap->codec_cap; + + return false; } - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { - return true; + return true; +} + +static bool base_subgroup_bis_index_cb(const struct bt_bap_base_subgroup_bis *bis, void *user_data) +{ + uint32_t *bis_indexes = user_data; + + *bis_indexes |= BIT(bis->index); + + return true; +} + +static bool base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + struct bt_bap_broadcast_sink *sink = user_data; + struct bt_bap_broadcast_sink_subgroup *sink_subgroup = + &sink->subgroups[sink->subgroup_count]; + struct codec_cap_lookup_id_data lookup_data = {0}; + int ret; + + if (sink->subgroup_count == ARRAY_SIZE(sink->subgroups)) { + /* We've parsed as many subgroups as we support */ + LOG_DBG("Could only store %u subgroups", sink->subgroup_count); + return false; } - if (bt_bap_decode_base(data, &base) != 0) { + ret = bt_bap_base_subgroup_codec_to_codec_cfg(subgroup, &sink_subgroup->codec_cfg); + if (ret < 0) { + LOG_DBG("Could not store codec_cfg: %d", ret); return false; } - if (atomic_test_bit(sink->flags, - BT_BAP_BROADCAST_SINK_FLAG_BIGINFO_RECEIVED)) { - uint8_t num_bis = 0; + ret = bt_bap_base_subgroup_foreach_bis(subgroup, base_subgroup_bis_index_cb, + &sink_subgroup->bis_indexes); + if (ret < 0) { + LOG_DBG("Could not parse BISes: %d", ret); + return false; + } - for (int i = 0; i < base.subgroup_count; i++) { - num_bis += base.subgroups[i].bis_count; - } + /* Lookup and assign path_id based on capabilities */ + lookup_data.id = sink_subgroup->codec_cfg.id; + + bt_pacs_cap_foreach(BT_AUDIO_DIR_SINK, codec_lookup_id, &lookup_data); + if (lookup_data.codec_cap == NULL) { + LOG_DBG("Codec with id %u is not supported by our capabilities", lookup_data.id); + } else { + /* Add BIS to bitfield of valid BIS indexes we support */ + sink->valid_indexes_bitfield |= sink_subgroup->bis_indexes; + } + + sink->subgroup_count++; + + return true; +} + +static int store_base_info(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +{ + int ret; + + sink->valid_indexes_bitfield = 0U; + sink->subgroup_count = 0U; + + ret = bt_bap_base_get_pres_delay(base); + if (ret < 0) { + LOG_DBG("Could not get presentation delay: %d", ret); + return ret; + } - if (num_bis > sink->biginfo_num_bis) { - LOG_WRN("BASE contains more BIS than reported by BIGInfo"); + sink->codec_qos.pd = (uint32_t)ret; + + ret = bt_bap_base_foreach_subgroup(base, base_subgroup_cb, sink); + if (ret != 0) { + LOG_DBG("Failed to parse all subgroups: %d", ret); + return ret; + } + + return 0; +} + +static bool base_subgroup_bis_count_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data) +{ + uint8_t *bis_cnt = user_data; + int ret; + + ret = bt_bap_base_get_subgroup_bis_count(subgroup); + if (ret < 0) { + return false; + } + + *bis_cnt += (uint8_t)ret; + + return true; +} + +static int base_get_bis_count(const struct bt_bap_base *base) +{ + uint8_t bis_cnt = 0U; + int err; + + err = bt_bap_base_foreach_subgroup(base, base_subgroup_bis_count_cb, &bis_cnt); + if (err != 0) { + LOG_DBG("Failed to parse subgroups: %d", err); + return err; + } + + return bis_cnt; +} + +static bool pa_decode_base(struct bt_data *data, void *user_data) +{ + struct bt_bap_broadcast_sink *sink = (struct bt_bap_broadcast_sink *)user_data; + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); + struct bt_bap_broadcast_sink_cb *listener; + size_t base_size; + int ret; + + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { + return true; + } + + if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_BIGINFO_RECEIVED)) { + ret = base_get_bis_count(base); + + if (ret < 0) { + LOG_DBG("Invalid BASE: %d", ret); + return false; + } else if (ret != sink->biginfo_num_bis) { + LOG_DBG("BASE contains different amount of BIS (%u) than reported by " + "BIGInfo (%u)", + ret, sink->biginfo_num_bis); return false; } } - sink->codec_qos.pd = base.pd; - if (memcmp(&sink->base, &base, sizeof(base)) != 0) { - /* We only overwrite the sink->base data once the base has - * successfully been decoded to avoid overwriting it with - * invalid data - */ - (void)memcpy(&sink->base, &base, sizeof(base)); + /* Store newest BASE info until we are BIG synced */ + if (sink->big == NULL) { + LOG_DBG("Updating BASE for sink %p with %d subgroups\n", sink, + bt_bap_base_get_subgroup_count(base)); - if (atomic_test_bit(sink->flags, - BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID)) { - update_recv_state_base(sink); + ret = store_base_info(sink, base); + if (ret < 0) { + LOG_DBG("Could not store BASE information: %d", ret); + + /* If it returns -ECANCELED it means that we stopped parsing ourselves due + * to lack of memory. In this case we can still provide the BASE to the + * application else abort + */ + if (ret != -ECANCELED) { + return false; + } } } + if (atomic_test_bit(sink->flags, BT_BAP_BROADCAST_SINK_FLAG_SRC_ID_VALID)) { + update_recv_state_base(sink, base); + } + + /* We provide the BASE without the service data UUID */ + base_size = data->data_len - BT_UUID_SIZE_16; + SYS_SLIST_FOR_EACH_CONTAINER(&sink_cbs, listener, _node) { if (listener->base_recv != NULL) { - listener->base_recv(sink, &base); + listener->base_recv(sink, base, base_size); } } @@ -815,36 +943,20 @@ static void broadcast_sink_cleanup(struct bt_bap_broadcast_sink *sink) (void)memset(sink, 0, sizeof(*sink)); /* also clears flags */ } - -static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_base *base, +static struct bt_audio_codec_cfg *codec_cfg_from_base_by_index(struct bt_bap_broadcast_sink *sink, uint8_t index) { - for (size_t i = 0U; i < base->subgroup_count; i++) { - struct bt_bap_base_subgroup *subgroup = &base->subgroups[i]; + for (size_t i = 0U; i < sink->subgroup_count; i++) { + struct bt_bap_broadcast_sink_subgroup *subgroup = &sink->subgroups[i]; - for (size_t j = 0U; j < subgroup->bis_count; j++) { - if (subgroup->bis_data[j].index == index) { - return &subgroup->codec_cfg; - } + if ((subgroup->bis_indexes & BIT(index)) != 0) { + return &subgroup->codec_cfg; } } return NULL; } -static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data) -{ - struct codec_cap_lookup_id_data *data = user_data; - - if (cap->codec_cap->id == data->id) { - data->codec_cap = cap->codec_cap; - - return false; - } - - return true; -} - int bt_bap_broadcast_sink_create(struct bt_le_per_adv_sync *pa_sync, uint32_t broadcast_id, struct bt_bap_broadcast_sink **out_sink) { @@ -906,7 +1018,7 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde struct bt_bap_stream *streams[], const uint8_t broadcast_code[16]) { struct bt_iso_big_sync_param param; - struct bt_audio_codec_cfg *codec_cfgs[BROADCAST_SNK_STREAM_CNT] = {NULL}; + struct bt_audio_codec_cfg *codec_cfgs[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT] = {NULL}; uint8_t stream_count; int err; @@ -954,37 +1066,26 @@ int bt_bap_broadcast_sink_sync(struct bt_bap_broadcast_sink *sink, uint32_t inde } /* Validate that number of bits set is less than number of streams */ + if ((indexes_bitfield & sink->valid_indexes_bitfield) != indexes_bitfield) { + LOG_DBG("Request BIS indexes 0x%08X contains bits not support by the Broadcast " + "Sink 0x%08X", + indexes_bitfield, sink->valid_indexes_bitfield); + return -EINVAL; + } + stream_count = 0; for (int i = 1; i < BT_ISO_MAX_GROUP_ISO_COUNT; i++) { if ((indexes_bitfield & BIT(i)) != 0) { struct bt_audio_codec_cfg *codec_cfg = - codec_cfg_from_base_by_index(&sink->base, i); - struct codec_cap_lookup_id_data lookup_data = {}; - - if (codec_cfg == NULL) { - LOG_DBG("Index %d not found in BASE", i); - return -EINVAL; - } - - /* Lookup and assign path_id based on capabilities */ - lookup_data.id = codec_cfg->id; - - bt_pacs_cap_foreach(BT_AUDIO_DIR_SINK, codec_lookup_id, - &lookup_data); - if (lookup_data.codec_cap == NULL) { - LOG_DBG("Codec with id %u is not supported by our capabilities", - codec_cfg->id); - - return -ENOENT; - } + codec_cfg_from_base_by_index(sink, i); - codec_cfg->path_id = lookup_data.codec_cap->path_id; + __ASSERT(codec_cfg != NULL, "Index %d not found in sink", i); codec_cfgs[stream_count++] = codec_cfg; - if (stream_count > BROADCAST_SNK_STREAM_CNT) { - LOG_DBG("Cannot sync to more than %d streams", - BROADCAST_SNK_STREAM_CNT); + if (stream_count > CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT) { + LOG_DBG("Cannot sync to more than %d streams (%u was requested)", + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT, stream_count); return -EINVAL; } } diff --git a/subsys/bluetooth/audio/bap_broadcast_source.c b/subsys/bluetooth/audio/bap_broadcast_source.c index 33fd1f0e17d..3982be82e74 100644 --- a/subsys/bluetooth/audio/bap_broadcast_source.c +++ b/subsys/bluetooth/audio/bap_broadcast_source.c @@ -166,10 +166,13 @@ static void broadcast_source_iso_connected(struct bt_iso_chan *chan) return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p", stream, ep); + ops = stream->ops; + if (ops != NULL && ops->connected != NULL) { + ops->connected(stream); + } + broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING); if (ops != NULL && ops->started != NULL) { @@ -197,10 +200,13 @@ static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t return; } - ops = stream->ops; - LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason); + ops = stream->ops; + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(stream, reason); + } + broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED); if (ops != NULL && ops->stopped != NULL) { @@ -788,7 +794,7 @@ int bt_bap_broadcast_source_reconfig(struct bt_bap_broadcast_source *source, for (size_t i = 0U; i < subgroup_param->params_count; i++) { struct bt_bap_stream *subgroup_stream; struct bt_bap_stream *param_stream; - bool stream_in_subgroup; + bool stream_in_subgroup = false; param_stream = subgroup_param->params[i].stream; @@ -938,6 +944,7 @@ int bt_bap_broadcast_source_update_metadata(struct bt_bap_broadcast_source *sour SYS_SLIST_FOR_EACH_CONTAINER(&source->subgroups, subgroup, _node) { memset(subgroup->codec_cfg->meta, 0, sizeof(subgroup->codec_cfg->meta)); memcpy(subgroup->codec_cfg->meta, meta, meta_len); + subgroup->codec_cfg->meta_len = meta_len; } return 0; diff --git a/subsys/bluetooth/audio/bap_endpoint.h b/subsys/bluetooth/audio/bap_endpoint.h index 1c5aa3d5fc5..aa2f326a71f 100644 --- a/subsys/bluetooth/audio/bap_endpoint.h +++ b/subsys/bluetooth/audio/bap_endpoint.h @@ -124,19 +124,27 @@ enum bt_bap_broadcast_sink_flag { BT_BAP_BROADCAST_SINK_FLAG_NUM_FLAGS, }; +struct bt_bap_broadcast_sink_subgroup { + uint32_t bis_indexes; + struct bt_audio_codec_cfg codec_cfg; +}; + +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) struct bt_bap_broadcast_sink { uint8_t index; /* index of broadcast_snks array */ uint8_t stream_count; uint8_t bass_src_id; + uint8_t subgroup_count; uint16_t iso_interval; uint16_t biginfo_num_bis; uint32_t broadcast_id; /* 24 bit */ uint32_t indexes_bitfield; - struct bt_bap_base base; + uint32_t valid_indexes_bitfield; /* based on codec support */ struct bt_audio_codec_qos codec_qos; struct bt_le_per_adv_sync *pa_sync; struct bt_iso_big *big; - struct bt_iso_chan *bis[BROADCAST_SNK_STREAM_CNT]; + struct bt_iso_chan *bis[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; + struct bt_bap_broadcast_sink_subgroup subgroups[CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT]; const struct bt_bap_scan_delegator_recv_state *recv_state; /* The streams used to create the broadcast sink */ sys_slist_t streams; @@ -144,6 +152,7 @@ struct bt_bap_broadcast_sink { /** Flags */ ATOMIC_DEFINE(flags, BT_BAP_BROADCAST_SINK_FLAG_NUM_FLAGS); }; +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ static inline const char *bt_bap_ep_state_str(uint8_t state) { diff --git a/subsys/bluetooth/audio/bap_internal.h b/subsys/bluetooth/audio/bap_internal.h index 5a4bf8fb819..5eb53f5de58 100644 --- a/subsys/bluetooth/audio/bap_internal.h +++ b/subsys/bluetooth/audio/bap_internal.h @@ -89,3 +89,37 @@ union bt_bap_bass_cp { struct bt_bap_bass_cp_broadcase_code broadcast_code; struct bt_bap_bass_cp_rem_src rem_src; }; + +static inline const char *bt_bap_pa_state_str(uint8_t state) +{ + switch (state) { + case BT_BAP_PA_STATE_NOT_SYNCED: + return "Not synchronized to PA"; + case BT_BAP_PA_STATE_INFO_REQ: + return "SyncInfo Request"; + case BT_BAP_PA_STATE_SYNCED: + return "Synchronized to PA"; + case BT_BAP_PA_STATE_FAILED: + return "Failed to synchronize to PA"; + case BT_BAP_PA_STATE_NO_PAST: + return "No PAST"; + default: + return "unknown state"; + } +} + +static inline const char *bt_bap_big_enc_state_str(uint8_t state) +{ + switch (state) { + case BT_BAP_BIG_ENC_STATE_NO_ENC: + return "Not encrypted"; + case BT_BAP_BIG_ENC_STATE_BCODE_REQ: + return "Broadcast_Code required"; + case BT_BAP_BIG_ENC_STATE_DEC: + return "Decrypting"; + case BT_BAP_BIG_ENC_STATE_BAD_CODE: + return "Bad_Code (incorrect encryption key)"; + default: + return "unknown state"; + } +} diff --git a/subsys/bluetooth/audio/bap_scan_delegator.c b/subsys/bluetooth/audio/bap_scan_delegator.c index 3cef96bd1b8..79901fd3c46 100644 --- a/subsys/bluetooth/audio/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/bap_scan_delegator.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,8 @@ LOG_MODULE_REGISTER(bt_bap_scan_delegator, CONFIG_BT_BAP_SCAN_DELEGATOR_LOG_LEVE #define PAST_TIMEOUT K_SECONDS(10) +#define SCAN_DELEGATOR_BUF_SEM_TIMEOUT K_MSEC(CONFIG_BT_BAP_SCAN_DELEGATOR_BUF_TIMEOUT) +static K_SEM_DEFINE(read_buf_sem, 1, 1); NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN); enum bass_recv_state_internal_flag { @@ -137,11 +140,29 @@ static void bt_debug_dump_recv_state(const struct bass_recv_state_internal *recv } } -static void bass_notify_receive_state(const struct bass_recv_state_internal *internal_state) +static void bass_notify_receive_state(struct bt_conn *conn, + const struct bass_recv_state_internal *internal_state) { - int err = bt_gatt_notify_uuid(NULL, BT_UUID_BASS_RECV_STATE, - internal_state->attr, read_buf.data, - read_buf.len); + const uint8_t att_ntf_header_size = 3; /* opcode (1) + handle (2) */ + uint16_t max_ntf_size; + uint16_t ntf_size; + int err; + + if (conn != NULL) { + max_ntf_size = bt_gatt_get_mtu(conn) - att_ntf_header_size; + } else { + max_ntf_size = MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU) - att_ntf_header_size; + } + + ntf_size = MIN(max_ntf_size, read_buf.len); + if (ntf_size < read_buf.len) { + LOG_DBG("Sending truncated notification (%u/%u)", ntf_size, read_buf.len); + } + + LOG_DBG("Sending bytes %d", ntf_size); + err = bt_gatt_notify_uuid(NULL, BT_UUID_BASS_RECV_STATE, + internal_state->attr, read_buf.data, + ntf_size); if (err != 0 && err != -ENOTCONN) { LOG_DBG("Could not notify receive state: %d", err); @@ -158,6 +179,7 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s if (!recv_state->active) { /* Notify empty */ + return; } @@ -177,7 +199,7 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s for (int i = 0; i < state->num_subgroups; i++) { const struct bt_bap_scan_delegator_subgroup *subgroup = &state->subgroups[i]; - (void)net_buf_simple_add_le32(&read_buf, subgroup->bis_sync); + (void)net_buf_simple_add_le32(&read_buf, subgroup->bis_sync >> 1); (void)net_buf_simple_add_u8(&read_buf, subgroup->metadata_len); (void)net_buf_simple_add_mem(&read_buf, subgroup->metadata, subgroup->metadata_len); @@ -187,21 +209,31 @@ static void net_buf_put_recv_state(const struct bass_recv_state_internal *recv_s static void receive_state_updated(struct bt_conn *conn, const struct bass_recv_state_internal *internal_state) { + int err; + /* If something is holding the NOTIFY_PEND flag we should not notify now */ if (atomic_test_bit(internal_state->flags, BASS_RECV_STATE_INTERNAL_FLAG_NOTIFY_PEND)) { return; } + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + + return; + } + bt_debug_dump_recv_state(internal_state); net_buf_put_recv_state(internal_state); - bass_notify_receive_state(internal_state); - + bass_notify_receive_state(conn, internal_state); if (scan_delegator_cbs != NULL && scan_delegator_cbs->recv_state_updated != NULL) { scan_delegator_cbs->recv_state_updated(conn, &internal_state->state); } + + k_sem_give(&read_buf_sem); } static void bis_sync_request_updated(struct bt_conn *conn, @@ -254,11 +286,21 @@ static void scan_delegator_security_changed(struct bt_conn *conn, continue; } + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + + return; + } + net_buf_put_recv_state(internal_state); gatt_err = bt_gatt_notify_uuid(conn, BT_UUID_BASS_RECV_STATE, internal_state->attr, read_buf.data, read_buf.len); + + k_sem_give(&read_buf_sem); + if (gatt_err != 0) { LOG_WRN("Could not notify receive state[%d] to reconnecting assistant: %d", i, gatt_err); @@ -514,6 +556,10 @@ static int scan_delegator_add_source(struct bt_conn *conn, } internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf); + if (internal_state->requested_bis_sync[i] != BT_BAP_BIS_SYNC_NO_PREF) { + /* Received BIS Index bitfield uses BIT(0) for BIS Index 1 */ + internal_state->requested_bis_sync[i] <<= 1; + } if (internal_state->requested_bis_sync[i] && pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC) { @@ -581,10 +627,10 @@ static int scan_delegator_add_source(struct bt_conn *conn, if (err != 0) { (void)memset(state, 0, sizeof(*state)); - LOG_DBG("PA sync %u from %p was reject with reason %d", - pa_sync, conn, err); + LOG_DBG("PA sync %u from %p was rejected with reason %d", pa_sync, conn, + err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } @@ -670,6 +716,11 @@ static int scan_delegator_mod_src(struct bt_conn *conn, old_bis_sync_req = internal_state->requested_bis_sync[i]; internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf); + if (internal_state->requested_bis_sync[i] != BT_BAP_BIS_SYNC_NO_PREF) { + /* Received BIS Index bitfield uses BIT(0) for BIS Index 1 */ + internal_state->requested_bis_sync[i] <<= 1; + } + if (internal_state->requested_bis_sync[i] && pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC) { LOG_DBG("Cannot sync to BIS without PA"); @@ -756,7 +807,7 @@ static int scan_delegator_mod_src(struct bt_conn *conn, * we are not already synced to the device */ if (pa_sync != BT_BAP_BASS_PA_REQ_NO_SYNC && - (state_changed || state->pa_sync_state != BT_BAP_PA_STATE_SYNCED)) { + state->pa_sync_state != BT_BAP_PA_STATE_SYNCED) { const int err = pa_sync_request(conn, state, pa_sync, pa_interval); @@ -765,10 +816,10 @@ static int scan_delegator_mod_src(struct bt_conn *conn, (void)memcpy(state, &backup_state, sizeof(backup_state)); - LOG_DBG("PA sync %u from %p was reject with reason %d", - pa_sync, conn, err); + LOG_DBG("PA sync %u from %p was rejected with reason %d", pa_sync, conn, + err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } else if (pa_sync == BT_BAP_BASS_PA_REQ_NO_SYNC && (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ || @@ -777,10 +828,9 @@ static int scan_delegator_mod_src(struct bt_conn *conn, const int err = pa_sync_term_request(conn, &internal_state->state); if (err != 0) { - LOG_DBG("PA sync term from %p was reject with reason %d", - conn, err); + LOG_DBG("PA sync term from %p was rejected with reason %d", conn, err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } state_changed = true; @@ -870,10 +920,9 @@ static int scan_delegator_rem_src(struct bt_conn *conn, /* Terminate PA sync */ err = pa_sync_term_request(conn, &internal_state->state); if (err != 0) { - LOG_DBG("PA sync term from %p was reject with reason %d", - conn, err); + LOG_DBG("PA sync term from %p was rejected with reason %d", conn, err); - return err; + return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } } @@ -1018,14 +1067,27 @@ static ssize_t read_recv_state(struct bt_conn *conn, struct bt_bap_scan_delegator_recv_state *state = &recv_state->state; if (recv_state->active) { + ssize_t ret_val; + int err; + LOG_DBG("Index %u: Source ID 0x%02x", idx, state->src_id); - bt_debug_dump_recv_state(recv_state); + err = k_sem_take(&read_buf_sem, SCAN_DELEGATOR_BUF_SEM_TIMEOUT); + if (err != 0) { + LOG_DBG("Failed to take read_buf_sem: %d", err); + return err; + } + + bt_debug_dump_recv_state(recv_state); net_buf_put_recv_state(recv_state); - return bt_gatt_attr_read(conn, attr, buf, len, offset, - read_buf.data, read_buf.len); + ret_val = bt_gatt_attr_read(conn, attr, buf, len, offset, + read_buf.data, read_buf.len); + + k_sem_give(&read_buf_sem); + + return ret_val; } else { LOG_DBG("Index %u: Not active", idx); diff --git a/subsys/bluetooth/audio/bap_stream.c b/subsys/bluetooth/audio/bap_stream.c index d6df9524e14..07ff97c064e 100644 --- a/subsys/bluetooth/audio/bap_stream.c +++ b/subsys/bluetooth/audio/bap_stream.c @@ -245,6 +245,7 @@ static bool bt_bap_stream_can_send(const struct bt_bap_stream *stream) int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, uint16_t seq_num, uint32_t ts) { + int ret; struct bt_bap_ep *ep; if (stream == NULL || stream->ep == NULL) { @@ -265,6 +266,12 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, return -EBADMSG; } + ret = bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream), + buf, seq_num, ts); + if (ret) { + return ret; + } + #if defined(CONFIG_BT_BAP_DEBUG_STREAM_SEQ_NUM) if (stream->_prev_seq_num != 0U && seq_num != 0U && (stream->_prev_seq_num + 1U) != seq_num) { @@ -277,8 +284,7 @@ int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf, /* TODO: Add checks for broadcast sink */ - return bt_iso_chan_send(bt_bap_stream_iso_chan_get(stream), - buf, seq_num, ts); + return ret; } int bt_bap_stream_get_tx_sync(struct bt_bap_stream *stream, struct bt_iso_tx_info *info) @@ -394,20 +400,25 @@ void bt_bap_stream_detach(struct bt_bap_stream *stream) stream->ep = NULL; if (!is_broadcast) { - bt_bap_stream_disconnect(stream); + const int err = bt_bap_stream_disconnect(stream); + + if (err != 0) { + LOG_DBG("Failed to disconnect stream %p: %d", stream, err); + } } } int bt_bap_stream_disconnect(struct bt_bap_stream *stream) { - struct bt_iso_chan *iso_chan = bt_bap_stream_iso_chan_get(stream); + struct bt_iso_chan *iso_chan; - LOG_DBG("stream %p iso %p", stream, iso_chan); + LOG_DBG("stream %p", stream); if (stream == NULL) { return -EINVAL; } + iso_chan = bt_bap_stream_iso_chan_get(stream); if (iso_chan == NULL || iso_chan->iso == NULL) { return -ENOTCONN; } diff --git a/subsys/bluetooth/audio/bap_unicast_client.c b/subsys/bluetooth/audio/bap_unicast_client.c index b6de9b61a66..14e89b4da60 100644 --- a/subsys/bluetooth/audio/bap_unicast_client.c +++ b/subsys/bluetooth/audio/bap_unicast_client.c @@ -231,7 +231,8 @@ static void unicast_client_ep_iso_recv(struct bt_iso_chan *chan, * host as HCI ISO data packets, which we should just ignore */ if ((info->flags & BT_ISO_FLAGS_VALID) != 0) { - LOG_ERR("iso %p not bound with ep", chan); + LOG_DBG("Valid ISO packet of len %zu received for iso %p not bound with ep", + net_buf_frags_len(buf), chan); } return; @@ -296,6 +297,7 @@ static void unicast_client_ep_iso_sent(struct bt_iso_chan *chan) static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep) { + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; if (ep->status.state != BT_BAP_EP_STATE_ENABLING) { @@ -313,6 +315,11 @@ static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep) LOG_DBG("stream %p ep %p dir %s receiver_ready %u", stream, ep, bt_audio_dir_str(ep->dir), ep->receiver_ready); + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->connected != NULL) { + stream_ops->connected(stream); + } + if (ep->receiver_ready && ep->dir == BT_AUDIO_DIR_SOURCE) { const int err = unicast_client_send_start(ep); @@ -345,6 +352,7 @@ static void unicast_client_iso_connected(struct bt_iso_chan *chan) static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason) { + const struct bt_bap_stream_ops *stream_ops; struct bt_bap_stream *stream; stream = ep->stream; @@ -356,6 +364,11 @@ static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t rea LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason); ep->reason = reason; + stream_ops = stream->ops; + if (stream_ops != NULL && stream_ops->disconnected != NULL) { + stream_ops->disconnected(stream, reason); + } + /* If we were in the idle state when we started the ISO disconnection * then we need to call unicast_client_ep_idle_state again when * the ISO has finalized the disconnection @@ -714,6 +727,7 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_simple *buf, uint8_t old_state) { + const struct bt_bap_stream_ops *ops; struct bt_ascs_ase_status_qos *qos; struct bt_bap_stream *stream; @@ -727,17 +741,36 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim LOG_ERR("No stream active for endpoint"); return; } + ops = stream->ops; - if (ep->dir == BT_AUDIO_DIR_SINK && stream->ops != NULL && stream->ops->disabled != NULL) { - /* If the old state was enabling or streaming, then the sink - * ASE has been disabled. Since the sink ASE does not have a - * disabling state, we can check if by comparing the old_state - */ - const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING || - old_state == BT_BAP_EP_STATE_STREAMING; + if (ops != NULL) { + if (ep->dir == BT_AUDIO_DIR_SINK && ops->disabled != NULL) { + /* If the old state was enabling or streaming, then the sink + * ASE has been disabled. Since the sink ASE does not have a + * disabling state, we can check if by comparing the old_state + */ + const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING || + old_state == BT_BAP_EP_STATE_STREAMING; - if (disabled) { - stream->ops->disabled(stream); + if (disabled) { + ops->disabled(stream); + } + } else if (ep->dir == BT_AUDIO_DIR_SOURCE && + old_state == BT_BAP_EP_STATE_DISABLING && ops->stopped != NULL) { + /* We left the disabling state, let the upper layers know that the stream is + * stopped + */ + uint8_t reason = ep->reason; + + if (reason == BT_HCI_ERR_SUCCESS) { + /* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */ + reason = BT_HCI_ERR_UNSPECIFIED; + } else { + /* Reset reason */ + ep->reason = BT_HCI_ERR_SUCCESS; + } + + ops->stopped(stream, reason); } } @@ -1015,6 +1048,8 @@ static void unicast_client_ep_set_status(struct bt_bap_ep *ep, struct net_buf_si case BT_BAP_EP_STATE_CODEC_CONFIGURED: /* or 0x02 (QoS Configured) */ case BT_BAP_EP_STATE_QOS_CONFIGURED: + /* or 0x04 (Streaming) if there is a disconnect */ + case BT_BAP_EP_STATE_STREAMING: /* or 0x05 (Disabling) */ case BT_BAP_EP_STATE_DISABLING: break; @@ -1576,6 +1611,7 @@ static uint8_t unicast_client_ep_notify(struct bt_conn *conn, static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *ep) { struct bt_bap_unicast_client_ep *client_ep; + int err; client_ep = CONTAINER_OF(ep, struct bt_bap_unicast_client_ep, ep); @@ -1593,7 +1629,12 @@ static int unicast_client_ep_subscribe(struct bt_conn *conn, struct bt_bap_ep *e client_ep->subscribe.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(client_ep->subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(conn, &client_ep->subscribe); + err = bt_gatt_subscribe(conn, &client_ep->subscribe); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static void pac_record_cb(struct bt_conn *conn, const struct bt_audio_codec_cap *codec_cap) @@ -1683,10 +1724,10 @@ static void unicast_client_ep_set_cp(struct bt_conn *conn, uint16_t handle) atomic_set_bit(client->cp_subscribe.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, &client->cp_subscribe); - if (err != 0) { + if (err != 0 && err != -EALREADY) { LOG_DBG("Failed to subscribe: %d", err); - discover_cb(conn, BT_ATT_ERR_UNLIKELY); + discover_cb(conn, err); return; } @@ -2052,6 +2093,7 @@ static void unicast_client_reset(struct bt_bap_ep *ep, uint8_t reason) static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason) { + struct unicast_client *client; uint8_t index; LOG_DBG("conn %p", conn); @@ -2073,6 +2115,11 @@ static void unicast_client_ep_reset(struct bt_conn *conn, uint8_t reason) unicast_client_reset(ep, reason); } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */ + + client = &uni_cli_insts[index]; + client->busy = false; + client->dir = 0U; + reset_att_buf(client); } static void bt_audio_codec_qos_to_cig_param(struct bt_iso_cig_param *cig_param, @@ -3188,10 +3235,12 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, struct unicast_client *client; struct net_buf_simple *buf; struct bt_bap_ep *ep; + int cb_err; LOG_DBG("conn %p err 0x%02x len %u", conn, err, length); if (err) { + cb_err = err; goto fail; } @@ -3205,7 +3254,7 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, LOG_DBG("Buffer full, invalid server response of size %u", length + client->net_buf.len); - err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; goto fail; } @@ -3221,7 +3270,7 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, if (buf->len < sizeof(struct bt_ascs_ase_status)) { LOG_DBG("Read response too small (%u)", buf->len); - err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + cb_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; goto fail; } @@ -3233,28 +3282,32 @@ static uint8_t unicast_client_ase_read_func(struct bt_conn *conn, uint8_t err, * consider the discovery procedure as failing. */ LOG_WRN("No space left to parse ASE"); - err = -ENOMEM; + cb_err = -ENOMEM; goto fail; } unicast_client_ep_set_status(ep, buf); - unicast_client_ep_subscribe(conn, ep); + cb_err = unicast_client_ep_subscribe(conn, ep); + if (cb_err != 0) { + LOG_DBG("Failed to subcribe to ep %p: %d", ep, cb_err); + goto fail; + } + reset_att_buf(client); endpoint_cb(conn, ep); - err = unicast_client_ase_discover(conn, handle); - if (err != 0) { - LOG_DBG("Failed to read ASE: %d", err); - - discover_cb(conn, err); + cb_err = unicast_client_ase_discover(conn, handle); + if (cb_err != 0) { + LOG_DBG("Failed to read ASE: %d", cb_err); + goto fail; } return BT_GATT_ITER_STOP; fail: - discover_cb(conn, err); + discover_cb(conn, cb_err); return BT_GATT_ITER_STOP; } @@ -3272,7 +3325,7 @@ static uint8_t unicast_client_ase_discover_cb(struct bt_conn *conn, if (err != 0) { LOG_ERR("Unable to discover ASE Control Point"); - discover_cb(conn, BT_ATT_ERR_UNLIKELY); + discover_cb(conn, err); } return BT_GATT_ITER_STOP; @@ -3363,7 +3416,7 @@ static uint8_t unicast_client_pacs_avail_ctx_read_func(struct bt_conn *conn, uin if (cb_err != 0) { LOG_ERR("Unable to read ASE: %d", cb_err); - discover_cb(conn, err); + discover_cb(conn, cb_err); } return BT_GATT_ITER_STOP; @@ -3463,6 +3516,7 @@ static uint8_t unicast_client_pacs_avail_ctx_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].avail_ctx_cc_disc; sub_params->notify = unicast_client_pacs_avail_ctx_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { @@ -3661,6 +3715,7 @@ static uint8_t unicast_client_pacs_location_discover_cb(struct bt_conn *conn, sub_params->disc_params = &uni_cli_insts[index].loc_cc_disc; sub_params->notify = unicast_client_pacs_location_notify_cb; sub_params->value = BT_GATT_CCC_NOTIFY; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); if (err != 0 && err != -EALREADY) { diff --git a/subsys/bluetooth/audio/cap_acceptor.c b/subsys/bluetooth/audio/cap_acceptor.c index 56ed5fa2daa..d84fad1e8fb 100644 --- a/subsys/bluetooth/audio/cap_acceptor.c +++ b/subsys/bluetooth/audio/cap_acceptor.c @@ -50,7 +50,15 @@ int bt_cap_acceptor_register(const struct bt_csip_set_member_register_param *par err = bt_gatt_service_register(&cas); if (err) { + const int csip_err = bt_csip_set_member_unregister(*svc_inst); + + if (csip_err) { + LOG_ERR("Failed to unregister CSIS: %d", csip_err); + } + + cas.attrs[1].user_data = NULL; LOG_DBG("Failed to register CAS"); + return err; } diff --git a/subsys/bluetooth/audio/cap_commander.c b/subsys/bluetooth/audio/cap_commander.c index ffe8cd0f89a..90490ebaa7f 100644 --- a/subsys/bluetooth/audio/cap_commander.c +++ b/subsys/bluetooth/audio/cap_commander.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include "cap_internal.h" #include "ccid_internal.h" #include "csip_internal.h" @@ -20,9 +21,59 @@ LOG_MODULE_REGISTER(bt_cap_commander, CONFIG_BT_CAP_COMMANDER_LOG_LEVEL); #include "common/bt_str.h" -int bt_cap_commander_unicast_discover(struct bt_conn *conn) +static const struct bt_cap_commander_cb *cap_cb; + +int bt_cap_commander_register_cb(const struct bt_cap_commander_cb *cb) { - return -ENOSYS; + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + return -EINVAL; + } + + CHECKIF(cap_cb != NULL) { + LOG_DBG("callbacks already registered"); + return -EALREADY; + } + + cap_cb = cb; + + return 0; +} + +int bt_cap_commander_unregister_cb(const struct bt_cap_commander_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + return -EINVAL; + } + + CHECKIF(cap_cb != cb) { + LOG_DBG("cb is not registered"); + return -EINVAL; + } + + cap_cb = NULL; + + return 0; +} + +static void +cap_commander_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (cap_cb && cap_cb->discovery_complete) { + cap_cb->discovery_complete(conn, err, csis_inst); + } +} + +int bt_cap_commander_discover(struct bt_conn *conn) +{ + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn"); + return -EINVAL; + } + + return bt_cap_common_discover(conn, cap_commander_discover_complete); } int bt_cap_commander_broadcast_reception_start( @@ -36,23 +87,463 @@ int bt_cap_commander_broadcast_reception_stop( { return -ENOSYS; } +static void cap_commander_unicast_audio_proc_complete(void) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + enum bt_cap_common_proc_type proc_type; + struct bt_conn *failed_conn; + int err; + + failed_conn = active_proc->failed_conn; + err = active_proc->err; + proc_type = active_proc->proc_type; + bt_cap_common_clear_active_proc(); + + if (cap_cb == NULL) { + return; + } + + switch (proc_type) { +#if defined(CONFIG_BT_VCP_VOL_CTLR) + case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE: + if (cap_cb->volume_changed != NULL) { + cap_cb->volume_changed(failed_conn, err); + } + break; +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE: + if (cap_cb->volume_offset_changed != NULL) { + cap_cb->volume_offset_changed(failed_conn, err); + } + break; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ +#endif /* CONFIG_BT_VCP_VOL_CTLR */ + case BT_CAP_COMMON_PROC_TYPE_NONE: + default: + __ASSERT(false, "Invalid proc_type: %u", proc_type); + } +} + +int bt_cap_commander_cancel(void) +{ + if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) { + LOG_DBG("No CAP procedure is in progress"); + + return -EALREADY; + } + + bt_cap_common_abort_proc(NULL, -ECANCELED); + cap_commander_unicast_audio_proc_complete(); + + return 0; +} + +#if defined(CONFIG_BT_VCP_VOL_CTLR) +static struct bt_vcp_vol_ctlr_cb vol_ctlr_cb; +static bool vcp_cb_registered; + +static int cap_commander_register_vcp_cb(void) +{ + int err; + + err = bt_vcp_vol_ctlr_cb_register(&vol_ctlr_cb); + if (err != 0) { + LOG_DBG("Failed to register VCP callbacks: %d", err); + + return -ENOEXEC; + } + + vcp_cb_registered = true; + + return 0; +} + +static bool valid_change_volume_param(const struct bt_cap_commander_change_volume_param *param) +{ + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->members == NULL) { + LOG_DBG("param->members is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_MAX_CONN) { + LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count, + CONFIG_BT_MAX_CONN); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const union bt_cap_set_member *member = ¶m->members[i]; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + + if (client == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return false; + } + + if (bt_vcp_vol_ctlr_get_by_conn(client->conn) == NULL) { + LOG_DBG("Volume control not available for param->members[%zu]", i); + return false; + } + + for (size_t j = 0U; j < i; j++) { + const union bt_cap_set_member *other = ¶m->members[j]; + + if (other == member) { + LOG_DBG("param->members[%zu] (%p) is duplicated by " + "param->members[%zu] (%p)", + j, other, i, member); + return false; + } + } + } + + return true; +} + +static void cap_commander_vcp_vol_set_cb(struct bt_vcp_vol_ctlr *vol_ctlr, int err) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_conn *conn; + int vcp_err; + + LOG_DBG("vol_ctlr %p", (void *)vol_ctlr); + + vcp_err = bt_vcp_vol_ctlr_conn_get(vol_ctlr, &conn); + if (vcp_err != 0) { + LOG_ERR("Failed to get conn by vol_ctrl: %d", vcp_err); + return; + } + + LOG_DBG("conn %p", (void *)conn); + if (!bt_cap_common_conn_in_active_proc(conn)) { + /* State change happened outside of a procedure; ignore */ + return; + } + + if (err != 0) { + LOG_DBG("Failed to set volume: %d", err); + bt_cap_common_abort_proc(conn, err); + } else { + active_proc->proc_done_cnt++; + + LOG_DBG("Conn %p volume updated (%zu/%zu streams done)", (void *)conn, + active_proc->proc_done_cnt, active_proc->proc_cnt); + } + + if (bt_cap_common_proc_is_aborted()) { + LOG_DBG("Proc is aborted"); + if (bt_cap_common_proc_all_handled()) { + LOG_DBG("All handled"); + cap_commander_unicast_audio_proc_complete(); + } + + return; + } + + if (!bt_cap_common_proc_is_done()) { + const struct bt_cap_commander_proc_param *proc_param; + + proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), + proc_param->change_volume.volume); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + bt_cap_common_abort_proc(conn, err); + cap_commander_unicast_audio_proc_complete(); + } + } else { + cap_commander_unicast_audio_proc_complete(); + } +} int bt_cap_commander_change_volume(const struct bt_cap_commander_change_volume_param *param) { - return -ENOSYS; + const struct bt_cap_commander_proc_param *proc_param; + struct bt_cap_common_proc *active_proc; + struct bt_conn *conn; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_change_volume_param(param)) { + return -EINVAL; + } + + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, param->count); + + vol_ctlr_cb.vol_set = cap_commander_vcp_vol_set_cb; + if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) { + LOG_DBG("Failed to register VCP callbacks"); + + return -ENOEXEC; + } + + active_proc = bt_cap_common_get_active_proc(); + + for (size_t i = 0U; i < param->count; i++) { + struct bt_conn *member_conn = + bt_cap_common_get_member_conn(param->type, ¶m->members[i]); + + if (member_conn == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return -EINVAL; + } + + /* Store the necessary parameters as we cannot assume that the supplied parameters + * are kept valid + */ + active_proc->proc_param.commander[i].conn = member_conn; + active_proc->proc_param.commander[i].change_volume.volume = param->volume; + } + + proc_param = &active_proc->proc_param.commander[0]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + err = bt_vcp_vol_ctlr_set_vol(bt_vcp_vol_ctlr_get_by_conn(conn), + proc_param->change_volume.volume); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + return -ENOEXEC; + } + + return 0; +} + +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) +static bool +valid_change_offset_param(const struct bt_cap_commander_change_volume_offset_param *param) +{ + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->param == NULL) { + LOG_DBG("param->param is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_MAX_CONN) { + LOG_DBG("param->count (%zu) is larger than CONFIG_BT_MAX_CONN (%d)", param->count, + CONFIG_BT_MAX_CONN); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_commander_change_volume_offset_member_param *member_param = + ¶m->param[i]; + const union bt_cap_set_member *member = &member_param->member; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + struct bt_vcp_vol_ctlr *vol_ctlr; + struct bt_vcp_included included; + int err; + + if (client == NULL) { + LOG_DBG("Invalid param->param[%zu].member", i); + return false; + } + + vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(client->conn); + if (vol_ctlr == NULL) { + LOG_DBG("Volume control not available for param->param[%zu].member", i); + return false; + } + + err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included); + if (err != 0 || included.vocs_cnt == 0) { + LOG_DBG("Volume offset control not available for param->param[%zu].member", + i); + return -ENOEXEC; + } + + if (!IN_RANGE(member_param->offset, BT_VOCS_MIN_OFFSET, BT_VOCS_MAX_OFFSET)) { + LOG_DBG("Invalid offset %d for param->param[%zu].offset", + member_param->offset, i); + return false; + } + + for (size_t j = 0U; j < i; j++) { + const union bt_cap_set_member *other = ¶m->param[j].member; + + if (other == member) { + LOG_DBG("param->param[%zu].member (%p) is duplicated by " + "param->param[%zu].member (%p)", + j, other, i, member); + return false; + } + } + } + + return true; +} + +static void cap_commander_vcp_set_offset_cb(struct bt_vocs *inst, int err) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_conn *conn; + int vocs_err; + + LOG_DBG("bt_vocs %p", (void *)inst); + + vocs_err = bt_vocs_client_conn_get(inst, &conn); + if (vocs_err != 0) { + LOG_ERR("Failed to get conn by inst: %d", vocs_err); + return; + } + + LOG_DBG("conn %p", (void *)conn); + if (!bt_cap_common_conn_in_active_proc(conn)) { + /* State change happened outside of a procedure; ignore */ + return; + } + + if (err != 0) { + LOG_DBG("Failed to set offset: %d", err); + bt_cap_common_abort_proc(conn, err); + } else { + active_proc->proc_done_cnt++; + + LOG_DBG("Conn %p offset updated (%zu/%zu streams done)", (void *)conn, + active_proc->proc_done_cnt, active_proc->proc_cnt); + } + + if (bt_cap_common_proc_is_aborted()) { + LOG_DBG("Proc is aborted"); + if (bt_cap_common_proc_all_handled()) { + LOG_DBG("All handled"); + cap_commander_unicast_audio_proc_complete(); + } + + return; + } + + if (!bt_cap_common_proc_is_done()) { + const struct bt_cap_commander_proc_param *proc_param; + + proc_param = &active_proc->proc_param.commander[active_proc->proc_done_cnt]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + + err = bt_vocs_state_set(proc_param->change_offset.vocs, + proc_param->change_offset.offset); + if (err != 0) { + LOG_DBG("Failed to set offset for conn %p: %d", (void *)conn, err); + bt_cap_common_abort_proc(conn, err); + cap_commander_unicast_audio_proc_complete(); + } + } else { + cap_commander_unicast_audio_proc_complete(); + } } int bt_cap_commander_change_volume_offset( const struct bt_cap_commander_change_volume_offset_param *param) { - return -ENOSYS; + const struct bt_cap_commander_proc_param *proc_param; + struct bt_cap_common_proc *active_proc; + struct bt_vcp_vol_ctlr *vol_ctlr; + struct bt_conn *conn; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); + + return -EBUSY; + } + + if (!valid_change_offset_param(param)) { + return -EINVAL; + } + + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, param->count); + + vol_ctlr_cb.vocs_cb.set_offset = cap_commander_vcp_set_offset_cb; + if (!vcp_cb_registered && cap_commander_register_vcp_cb() != 0) { + LOG_DBG("Failed to register VCP callbacks"); + + return -ENOEXEC; + } + + active_proc = bt_cap_common_get_active_proc(); + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_commander_change_volume_offset_member_param *member_param = + ¶m->param[i]; + struct bt_conn *member_conn = + bt_cap_common_get_member_conn(param->type, &member_param->member); + struct bt_vcp_included included; + + if (member_conn == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return -EINVAL; + } + + vol_ctlr = bt_vcp_vol_ctlr_get_by_conn(member_conn); + if (vol_ctlr == NULL) { + LOG_DBG("Invalid param->members[%zu] vol_ctlr", i); + return -EINVAL; + } + + err = bt_vcp_vol_ctlr_included_get(vol_ctlr, &included); + if (err != 0 || included.vocs_cnt == 0) { + LOG_DBG("Invalid param->members[%zu] vocs", i); + return -EINVAL; + } + + /* Store the necessary parameters as we cannot assume that the supplied parameters + * are kept valid + */ + active_proc->proc_param.commander[i].conn = member_conn; + active_proc->proc_param.commander[i].change_offset.offset = member_param->offset; + /* TODO: For now we just use the first VOCS instance + * - How should we handle multiple? + */ + active_proc->proc_param.commander[i].change_offset.vocs = included.vocs[0]; + } + + proc_param = &active_proc->proc_param.commander[0]; + conn = proc_param->conn; + active_proc->proc_initiated_cnt++; + + err = bt_vocs_state_set(proc_param->change_offset.vocs, proc_param->change_offset.offset); + if (err != 0) { + LOG_DBG("Failed to set volume for conn %p: %d", (void *)conn, err); + return -ENOEXEC; + } + + return 0; } +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ int bt_cap_commander_change_volume_mute_state( const struct bt_cap_commander_change_volume_mute_state_param *param) { return -ENOSYS; } +#endif /* CONFIG_BT_VCP_VOL_CTLR */ int bt_cap_commander_change_microphone_mute_state( const struct bt_cap_commander_change_microphone_mute_state_param *param) diff --git a/subsys/bluetooth/audio/cap_common.c b/subsys/bluetooth/audio/cap_common.c new file mode 100644 index 00000000000..bf166fffd0c --- /dev/null +++ b/subsys/bluetooth/audio/cap_common.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "cap_internal.h" +#include "csip_internal.h" + +LOG_MODULE_REGISTER(bt_cap_common, CONFIG_BT_CAP_COMMON_LOG_LEVEL); + +#include "common/bt_str.h" + +static struct bt_cap_common_client bt_cap_common_clients[CONFIG_BT_MAX_CONN]; +static const struct bt_uuid *cas_uuid = BT_UUID_CAS; +static struct bt_cap_common_proc active_proc; +static bt_cap_common_discover_func_t discover_cb_func; + +struct bt_cap_common_proc *bt_cap_common_get_active_proc(void) +{ + return &active_proc; +} + +void bt_cap_common_clear_active_proc(void) +{ + (void)memset(&active_proc, 0, sizeof(active_proc)); +} + +void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt) +{ + atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE); + active_proc.proc_cnt = proc_cnt; + active_proc.proc_type = proc_type; + active_proc.proc_done_cnt = 0U; + active_proc.proc_initiated_cnt = 0U; +} + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) +void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type) +{ + active_proc.proc_done_cnt = 0U; + active_proc.proc_initiated_cnt = 0U; + active_proc.subproc_type = subproc_type; +} + +bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type) +{ + return active_proc.subproc_type == subproc_type; +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, + const union bt_cap_set_member *member) +{ + if (type == BT_CAP_SET_TYPE_CSIP) { + struct bt_cap_common_client *client; + + /* We have verified that `client` won't be NULL in + * `valid_change_volume_param`. + */ + client = bt_cap_common_get_client_by_csis(member->csip); + if (client != NULL) { + return client->conn; + } + } + + return member->member; +} + +bool bt_cap_common_proc_is_active(void) +{ + return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ACTIVE); +} + +bool bt_cap_common_proc_is_aborted(void) +{ + return atomic_test_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED); +} + +bool bt_cap_common_proc_all_handled(void) +{ + return active_proc.proc_done_cnt == active_proc.proc_initiated_cnt; +} + +bool bt_cap_common_proc_is_done(void) +{ + return active_proc.proc_done_cnt == active_proc.proc_cnt; +} + +void bt_cap_common_abort_proc(struct bt_conn *conn, int err) +{ + if (bt_cap_common_proc_is_aborted()) { + /* no-op */ + return; + } + + active_proc.err = err; + active_proc.failed_conn = conn; + atomic_set_bit(active_proc.proc_state_flags, BT_CAP_COMMON_PROC_STATE_ABORTED); +} + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) +static bool active_proc_is_initiator(void) +{ + switch (active_proc.proc_type) { + case BT_CAP_COMMON_PROC_TYPE_START: + case BT_CAP_COMMON_PROC_TYPE_UPDATE: + case BT_CAP_COMMON_PROC_TYPE_STOP: + return true; + default: + return false; + } +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +#if defined(CONFIG_BT_CAP_COMMANDER) +static bool active_proc_is_commander(void) +{ + switch (active_proc.proc_type) { + case BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE: + case BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE: + return true; + default: + return false; + } +} +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + +bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn) +{ + if (!bt_cap_common_proc_is_active()) { + return false; + } + + for (size_t i = 0U; i < active_proc.proc_initiated_cnt; i++) { +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + if (active_proc_is_initiator()) { + if (active_proc.proc_param.initiator[i].stream->bap_stream.conn == conn) { + return true; + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#if defined(CONFIG_BT_CAP_COMMANDER) + if (active_proc_is_commander()) { + if (active_proc.proc_param.commander[i].conn == conn) { + return true; + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + } + + return false; +} + +bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream) +{ + if (!bt_cap_common_proc_is_active()) { + return false; + } + +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + if (active_proc_is_initiator()) { + for (size_t i = 0U; i < active_proc.proc_cnt; i++) { + if (active_proc.proc_param.initiator[i].stream == cap_stream) { + return true; + } + } + } +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ + + return false; +} + +void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_cap_common_client *client = bt_cap_common_get_client_by_acl(conn); + + if (client->conn != NULL) { + bt_conn_unref(client->conn); + } + (void)memset(client, 0, sizeof(*client)); + + if (bt_cap_common_conn_in_active_proc(conn)) { + bt_cap_common_abort_proc(conn, -ENOTCONN); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = bt_cap_common_disconnected, +}; + +struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl) +{ + if (acl == NULL) { + return NULL; + } + + return &bt_cap_common_clients[bt_conn_index(acl)]; +} + +struct bt_cap_common_client * +bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (csis_inst == NULL) { + return NULL; + } + + for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_common_clients); i++) { + struct bt_cap_common_client *client = &bt_cap_common_clients[i]; + + if (client->csis_inst == csis_inst) { + return client; + } + } + + return NULL; +} + +struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type, + const union bt_cap_set_member *member) +{ + struct bt_cap_common_client *client = NULL; + + if (type == BT_CAP_SET_TYPE_AD_HOC) { + CHECKIF(member->member == NULL) { + LOG_DBG("member->member is NULL"); + return NULL; + } + + client = bt_cap_common_get_client_by_acl(member->member); + } else if (type == BT_CAP_SET_TYPE_CSIP) { + CHECKIF(member->csip == NULL) { + LOG_DBG("member->csip is NULL"); + return NULL; + } + + client = bt_cap_common_get_client_by_csis(member->csip); + if (client == NULL) { + LOG_DBG("CSIS was not found for member"); + return NULL; + } + } + + if (client == NULL || !client->cas_found) { + LOG_DBG("CAS was not found for member %p", member); + return NULL; + } + + return client; +} + +static void cap_common_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) +{ + if (discover_cb_func != NULL) { + const bt_cap_common_discover_func_t cb_func = discover_cb_func; + + discover_cb_func = NULL; + cb_func(conn, err, csis_inst); + } +} + +static void csis_client_discover_cb(struct bt_conn *conn, + const struct bt_csip_set_coordinator_set_member *member, + int err, size_t set_count) +{ + struct bt_cap_common_client *client; + + if (err != 0) { + LOG_DBG("CSIS client discover failed: %d", err); + + cap_common_discover_complete(conn, err, NULL); + + return; + } + + client = bt_cap_common_get_client_by_acl(conn); + client->csis_inst = + bt_csip_set_coordinator_csis_inst_by_handle(conn, client->csis_start_handle); + + if (member == NULL || set_count == 0 || client->csis_inst == NULL) { + LOG_ERR("Unable to find CSIS for CAS"); + + cap_common_discover_complete(conn, -ENODATA, NULL); + } else { + LOG_DBG("Found CAS with CSIS"); + cap_common_discover_complete(conn, 0, client->csis_inst); + } +} + +static uint8_t bt_cap_common_discover_included_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + if (attr == NULL) { + LOG_DBG("CAS CSIS include not found"); + + cap_common_discover_complete(conn, 0, NULL); + } else { + const struct bt_gatt_include *included_service = attr->user_data; + struct bt_cap_common_client *client = + CONTAINER_OF(params, struct bt_cap_common_client, param); + + /* If the remote CAS includes CSIS, we first check if we + * have already discovered it, and if so we can just retrieve it + * and forward it to the application. If not, then we start + * CSIS discovery + */ + client->csis_start_handle = included_service->start_handle; + client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( + conn, client->csis_start_handle); + if (client->csis_inst == NULL) { + static struct bt_csip_set_coordinator_cb csis_client_cb = { + .discover = csis_client_discover_cb, + }; + static bool csis_cbs_registered; + int err; + + LOG_DBG("CAS CSIS not known, discovering"); + + if (!csis_cbs_registered) { + bt_csip_set_coordinator_register_cb(&csis_client_cb); + csis_cbs_registered = true; + } + + err = bt_csip_set_coordinator_discover(conn); + if (err != 0) { + LOG_DBG("Discover failed (err %d)", err); + cap_common_discover_complete(conn, err, NULL); + } + } else { + LOG_DBG("Found CAS with CSIS"); + cap_common_discover_complete(conn, 0, client->csis_inst); + } + } + + return BT_GATT_ITER_STOP; +} + +static uint8_t bt_cap_common_discover_cas_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + if (attr == NULL) { + cap_common_discover_complete(conn, -ENODATA, NULL); + } else { + const struct bt_gatt_service_val *prim_service = attr->user_data; + struct bt_cap_common_client *client = + CONTAINER_OF(params, struct bt_cap_common_client, param); + int err; + + client->cas_found = true; + client->conn = bt_conn_ref(conn); + + if (attr->handle == prim_service->end_handle) { + LOG_DBG("Found CAS without CSIS"); + cap_common_discover_complete(conn, 0, NULL); + + return BT_GATT_ITER_STOP; + } + + LOG_DBG("Found CAS, discovering included CSIS"); + + params->uuid = NULL; + params->start_handle = attr->handle + 1; + params->end_handle = prim_service->end_handle; + params->type = BT_GATT_DISCOVER_INCLUDE; + params->func = bt_cap_common_discover_included_cb; + + err = bt_gatt_discover(conn, params); + if (err != 0) { + LOG_DBG("Discover failed (err %d)", err); + + cap_common_discover_complete(conn, err, NULL); + } + } + + return BT_GATT_ITER_STOP; +} + +int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func) +{ + struct bt_gatt_discover_params *param; + int err; + + if (discover_cb_func != NULL) { + return -EBUSY; + } + + param = &bt_cap_common_clients[bt_conn_index(conn)].param; + param->func = bt_cap_common_discover_cas_cb; + param->uuid = cas_uuid; + param->type = BT_GATT_DISCOVER_PRIMARY; + param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + discover_cb_func = func; + + err = bt_gatt_discover(conn, param); + if (err != 0) { + discover_cb_func = NULL; + + /* Report expected possible errors */ + if (err == -ENOTCONN || err == -ENOMEM) { + return err; + } + + LOG_DBG("Unexpected err %d from bt_gatt_discover", err); + return -ENOEXEC; + } + + return 0; +} diff --git a/subsys/bluetooth/audio/cap_initiator.c b/subsys/bluetooth/audio/cap_initiator.c index 46b39afcb41..b75b1c327c8 100644 --- a/subsys/bluetooth/audio/cap_initiator.c +++ b/subsys/bluetooth/audio/cap_initiator.c @@ -312,363 +312,30 @@ int bt_cap_initiator_broadcast_get_base(struct bt_cap_broadcast_source *broadcas #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) -enum { - CAP_UNICAST_PROC_STATE_ACTIVE, - CAP_UNICAST_PROC_STATE_ABORTED, - - CAP_UNICAST_PROC_STATE_FLAG_NUM, -} cap_unicast_proc_state; - -enum cap_unicast_proc_type { - CAP_UNICAST_PROC_TYPE_NONE, - CAP_UNICAST_PROC_TYPE_START, - CAP_UNICAST_PROC_TYPE_UPDATE, - CAP_UNICAST_PROC_TYPE_STOP, -}; - -enum cap_unicast_subproc_type { - CAP_UNICAST_SUBPROC_TYPE_NONE, - CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG, - CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG, - CAP_UNICAST_SUBPROC_TYPE_ENABLE, - CAP_UNICAST_SUBPROC_TYPE_START, - CAP_UNICAST_SUBPROC_TYPE_META_UPDATE, - CAP_UNICAST_SUBPROC_TYPE_RELEASE, -}; - -struct cap_unicast_proc_param { - struct bt_cap_stream *stream; - union { - struct { - struct bt_conn *conn; - struct bt_bap_ep *ep; - struct bt_audio_codec_cfg codec_cfg; - } start; - struct { - /** Codec Specific Capabilities Metadata count */ - size_t meta_len; - /** Codec Specific Capabilities Metadata */ - uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; - } meta_update; - }; -}; - -struct cap_unicast_proc { - ATOMIC_DEFINE(proc_state_flags, CAP_UNICAST_PROC_STATE_FLAG_NUM); - /* Total number of streams in the procedure*/ - size_t stream_cnt; - /* Number of streams where a subprocedure have been started */ - size_t stream_initiated_cnt; - /* Number of streams done with the procedure */ - size_t stream_done_cnt; - enum cap_unicast_proc_type proc_type; - enum cap_unicast_subproc_type subproc_type; - int err; - struct bt_conn *failed_conn; - struct cap_unicast_proc_param proc_param[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; - struct bt_bap_unicast_group *unicast_group; -}; - -struct cap_unicast_client { - struct bt_conn *conn; - struct bt_gatt_discover_params param; - uint16_t csis_start_handle; - const struct bt_csip_set_coordinator_csis_inst *csis_inst; - bool cas_found; -}; - -static struct cap_unicast_client bt_cap_unicast_clients[CONFIG_BT_MAX_CONN]; -static const struct bt_uuid *cas_uuid = BT_UUID_CAS; -static struct cap_unicast_proc active_proc; - -static void cap_set_subproc(enum cap_unicast_subproc_type subproc_type) -{ - active_proc.stream_done_cnt = 0U; - active_proc.stream_initiated_cnt = 0U; - active_proc.subproc_type = subproc_type; -} - -static bool cap_proc_is_active(void) -{ - return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); -} - -static bool cap_proc_is_aborted(void) -{ - return atomic_test_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED); -} - -static bool cap_proc_all_streams_handled(void) -{ - return active_proc.stream_done_cnt == active_proc.stream_initiated_cnt; -} - -static bool cap_proc_is_done(void) -{ - return active_proc.stream_done_cnt == active_proc.stream_cnt; -} - -static void cap_abort_proc(struct bt_conn *conn, int err) -{ - if (cap_proc_is_aborted()) { - /* no-op */ - return; - } - - active_proc.err = err; - active_proc.failed_conn = conn; - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ABORTED); -} - -static bool cap_conn_in_active_proc(const struct bt_conn *conn) -{ - if (!cap_proc_is_active()) { - return false; - } - - for (size_t i = 0U; i < active_proc.stream_initiated_cnt; i++) { - if (active_proc.proc_param[i].stream->bap_stream.conn == conn) { - return true; - } - } - - return false; -} - -static void cap_initiator_disconnected(struct bt_conn *conn, uint8_t reason) -{ - struct cap_unicast_client *client; - - client = &bt_cap_unicast_clients[bt_conn_index(conn)]; - - if (client->conn != NULL) { - bt_conn_unref(client->conn); - } - (void)memset(client, 0, sizeof(*client)); - - if (cap_conn_in_active_proc(conn)) { - cap_abort_proc(conn, -ENOTCONN); - } -} - -BT_CONN_CB_DEFINE(conn_callbacks) = { - .disconnected = cap_initiator_disconnected, -}; - -static struct cap_unicast_client *lookup_unicast_client_by_csis( - const struct bt_csip_set_coordinator_csis_inst *csis_inst) -{ - if (csis_inst == NULL) { - return NULL; - } - - for (size_t i = 0U; i < ARRAY_SIZE(bt_cap_unicast_clients); i++) { - struct cap_unicast_client *client = &bt_cap_unicast_clients[i]; - - if (client->csis_inst == csis_inst) { - return client; - } - } - - return NULL; -} - -static void csis_client_discover_cb(struct bt_conn *conn, - const struct bt_csip_set_coordinator_set_member *member, - int err, size_t set_count) -{ - struct cap_unicast_client *client; - - if (err != 0) { - LOG_DBG("CSIS client discover failed: %d", err); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, err, NULL); - } - - return; - } - - client = &bt_cap_unicast_clients[bt_conn_index(conn)]; - client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( - conn, client->csis_start_handle); - - if (member == NULL || set_count == 0 || client->csis_inst == NULL) { - LOG_ERR("Unable to find CSIS for CAS"); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, -ENODATA, - NULL); - } - } else { - LOG_DBG("Found CAS with CSIS"); - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, 0, - client->csis_inst); - } - } -} -static uint8_t cap_unicast_discover_included_cb(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) +static void +bt_cap_initiator_discover_complete(struct bt_conn *conn, int err, + const struct bt_csip_set_coordinator_csis_inst *csis_inst) { - params->func = NULL; - - if (attr == NULL) { - LOG_DBG("CAS CSIS include not found"); - - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, 0, NULL); - } - } else { - const struct bt_gatt_include *included_service = attr->user_data; - struct cap_unicast_client *client = CONTAINER_OF(params, - struct cap_unicast_client, - param); - - /* If the remote CAS includes CSIS, we first check if we - * have already discovered it, and if so we can just retrieve it - * and forward it to the application. If not, then we start - * CSIS discovery - */ - client->csis_start_handle = included_service->start_handle; - client->csis_inst = bt_csip_set_coordinator_csis_inst_by_handle( - conn, client->csis_start_handle); - - if (client->csis_inst == NULL) { - static struct bt_csip_set_coordinator_cb csis_client_cb = { - .discover = csis_client_discover_cb - }; - static bool csis_cbs_registered; - int err; - - LOG_DBG("CAS CSIS not known, discovering"); - - if (!csis_cbs_registered) { - bt_csip_set_coordinator_register_cb(&csis_client_cb); - csis_cbs_registered = true; - } - - err = bt_csip_set_coordinator_discover(conn); - if (err != 0) { - LOG_DBG("Discover failed (err %d)", err); - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, - err, - NULL); - } - } - } else if (cap_cb && cap_cb->unicast_discovery_complete) { - LOG_DBG("Found CAS with CSIS"); - cap_cb->unicast_discovery_complete(conn, 0, - client->csis_inst); - } + if (cap_cb && cap_cb->unicast_discovery_complete) { + cap_cb->unicast_discovery_complete(conn, err, csis_inst); } - - return BT_GATT_ITER_STOP; -} - -static uint8_t cap_unicast_discover_cas_cb(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) -{ - params->func = NULL; - - if (attr == NULL) { - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, -ENODATA, - NULL); - } - } else { - const struct bt_gatt_service_val *prim_service = attr->user_data; - struct cap_unicast_client *client = CONTAINER_OF(params, - struct cap_unicast_client, - param); - int err; - - client->cas_found = true; - client->conn = bt_conn_ref(conn); - - if (attr->handle == prim_service->end_handle) { - LOG_DBG("Found CAS without CSIS"); - cap_cb->unicast_discovery_complete(conn, 0, NULL); - - return BT_GATT_ITER_STOP; - } - - LOG_DBG("Found CAS, discovering included CSIS"); - - params->uuid = NULL; - params->start_handle = attr->handle + 1; - params->end_handle = prim_service->end_handle; - params->type = BT_GATT_DISCOVER_INCLUDE; - params->func = cap_unicast_discover_included_cb; - - err = bt_gatt_discover(conn, params); - if (err != 0) { - LOG_DBG("Discover failed (err %d)", err); - - params->func = NULL; - if (cap_cb && cap_cb->unicast_discovery_complete) { - cap_cb->unicast_discovery_complete(conn, err, - NULL); - } - } - } - - return BT_GATT_ITER_STOP; } int bt_cap_initiator_unicast_discover(struct bt_conn *conn) { - struct bt_gatt_discover_params *param; - int err; - CHECKIF(conn == NULL) { LOG_DBG("NULL conn"); return -EINVAL; } - param = &bt_cap_unicast_clients[bt_conn_index(conn)].param; - - /* use param->func to tell if a client is "busy" */ - if (param->func != NULL) { - return -EBUSY; - } - - param->func = cap_unicast_discover_cas_cb; - param->uuid = cas_uuid; - param->type = BT_GATT_DISCOVER_PRIMARY; - param->start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; - param->end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; - - err = bt_gatt_discover(conn, param); - if (err != 0) { - param->func = NULL; - } - - return err; + return bt_cap_common_discover(conn, bt_cap_initiator_discover_complete); } -static bool cap_stream_in_active_proc(const struct bt_cap_stream *cap_stream) +static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param) { - if (!cap_proc_is_active()) { - return false; - } - - for (size_t i = 0U; i < active_proc.stream_cnt; i++) { - if (active_proc.proc_param[i].stream == cap_stream) { - return true; - } - } + struct bt_bap_unicast_group *unicast_group = NULL; - return false; -} - -static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group) -{ CHECKIF(param == NULL) { LOG_DBG("param is NULL"); return false; @@ -699,6 +366,13 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st const struct bt_cap_stream *cap_stream = stream_param->stream; const struct bt_audio_codec_cfg *codec_cfg = stream_param->codec_cfg; const struct bt_bap_stream *bap_stream; + const struct bt_cap_common_client *client = + bt_cap_common_get_client(param->type, member); + + if (client == NULL) { + LOG_DBG("Invalid param->members[%zu]", i); + return false; + } CHECKIF(stream_param->codec_cfg == NULL) { LOG_DBG("param->stream_params[%zu].codec_cfg is NULL", i); @@ -720,37 +394,6 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st return false; } - if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - struct cap_unicast_client *client; - - CHECKIF(member->member == NULL) { - LOG_DBG("param->members[%zu] is NULL", i); - return false; - } - - client = &bt_cap_unicast_clients[bt_conn_index(member->member)]; - - if (!client->cas_found) { - LOG_DBG("CAS was not found for param->members[%zu]", i); - return false; - } - } - - if (param->type == BT_CAP_SET_TYPE_CSIP) { - struct cap_unicast_client *client; - - CHECKIF(member->csip == NULL) { - LOG_DBG("param->csip.set[%zu] is NULL", i); - return false; - } - - client = lookup_unicast_client_by_csis(member->csip); - if (client == NULL) { - LOG_DBG("CSIS was not found for param->members[%zu]", i); - return false; - } - } - CHECKIF(cap_stream == NULL) { LOG_DBG("param->streams[%zu] is NULL", i); return false; @@ -768,9 +411,15 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st return false; } - CHECKIF(bap_stream->group != unicast_group) { - LOG_DBG("param->streams[%zu] is not in this group %p", i, unicast_group); - return false; + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->streams[%zu] is not in this group %p", i, + unicast_group); + return false; + } } for (size_t j = 0U; j < i; j++) { @@ -790,38 +439,37 @@ static bool valid_unicast_audio_start_param(const struct bt_cap_unicast_audio_st static void cap_initiator_unicast_audio_proc_complete(void) { - struct bt_bap_unicast_group *unicast_group; - enum cap_unicast_proc_type proc_type; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + enum bt_cap_common_proc_type proc_type; struct bt_conn *failed_conn; int err; - unicast_group = active_proc.unicast_group; - failed_conn = active_proc.failed_conn; - err = active_proc.err; - proc_type = active_proc.proc_type; - (void)memset(&active_proc, 0, sizeof(active_proc)); + failed_conn = active_proc->failed_conn; + err = active_proc->err; + proc_type = active_proc->proc_type; + bt_cap_common_clear_active_proc(); if (cap_cb == NULL) { return; } switch (proc_type) { - case CAP_UNICAST_PROC_TYPE_START: + case BT_CAP_COMMON_PROC_TYPE_START: if (cap_cb->unicast_start_complete != NULL) { - cap_cb->unicast_start_complete(unicast_group, err, failed_conn); + cap_cb->unicast_start_complete(err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_UPDATE: + case BT_CAP_COMMON_PROC_TYPE_UPDATE: if (cap_cb->unicast_update_complete != NULL) { cap_cb->unicast_update_complete(err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_STOP: + case BT_CAP_COMMON_PROC_TYPE_STOP: if (cap_cb->unicast_stop_complete != NULL) { - cap_cb->unicast_stop_complete(unicast_group, err, failed_conn); + cap_cb->unicast_stop_complete(err, failed_conn); } break; - case CAP_UNICAST_PROC_TYPE_NONE: + case BT_CAP_COMMON_PROC_TYPE_NONE: default: __ASSERT(false, "Invalid proc_type: %u", proc_type); } @@ -830,7 +478,8 @@ static void cap_initiator_unicast_audio_proc_complete(void) static int cap_initiator_unicast_audio_configure( const struct bt_cap_unicast_audio_start_param *param) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_audio_codec_cfg *codec_cfg; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep; @@ -847,18 +496,7 @@ static int cap_initiator_unicast_audio_configure( union bt_cap_set_member *member = &stream_param->member; struct bt_cap_stream *cap_stream = stream_param->stream; - if (param->type == BT_CAP_SET_TYPE_AD_HOC) { - conn = member->member; - } else { - struct cap_unicast_client *client; - - /* We have verified that `client` wont be NULL in - * `valid_unicast_audio_start_param`. - */ - client = lookup_unicast_client_by_csis(member->csip); - __ASSERT(client != NULL, "client is NULL"); - conn = client->conn; - } + conn = bt_cap_common_get_member_conn(param->type, member); /* Ensure that ops are registered before any procedures are started */ bt_cap_stream_ops_register_bap(cap_stream); @@ -866,26 +504,25 @@ static int cap_initiator_unicast_audio_configure( /* Store the necessary parameters as we cannot assume that the supplied parameters * are kept valid */ - active_proc.proc_param[i].stream = cap_stream; - active_proc.proc_param[i].start.ep = stream_param->ep; - active_proc.proc_param[i].start.conn = conn; - memcpy(&active_proc.proc_param[i].start.codec_cfg, stream_param->codec_cfg, - sizeof(*stream_param->codec_cfg)); + active_proc->proc_param.initiator[i].stream = cap_stream; + active_proc->proc_param.initiator[i].start.ep = stream_param->ep; + active_proc->proc_param.initiator[i].start.conn = conn; + memcpy(&active_proc->proc_param.initiator[i].start.codec_cfg, + stream_param->codec_cfg, sizeof(*stream_param->codec_cfg)); } /* Store the information about the active procedure so that we can * continue the procedure after each step */ - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = param->count; - - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG); + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_START, param->count); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG); - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; codec_cfg = &proc_param->start.codec_cfg; conn = proc_param->start.conn; ep = proc_param->start.ep; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a time. @@ -895,35 +532,24 @@ static int cap_initiator_unicast_audio_configure( if (err != 0) { LOG_DBG("Failed to config stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); - } else { - active_proc.stream_initiated_cnt++; + bt_cap_common_clear_active_proc(); } return err; } -int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param, - struct bt_bap_unicast_group *unicast_group) +int bt_cap_initiator_unicast_audio_start(const struct bt_cap_unicast_audio_start_param *param) { - if (cap_proc_is_active()) { + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; } - CHECKIF(unicast_group == NULL) { - LOG_DBG("unicast_group is NULL"); - return -EINVAL; - } - - if (!valid_unicast_audio_start_param(param, unicast_group)) { + if (!valid_unicast_audio_start_param(param)) { return -EINVAL; } - active_proc.unicast_group = unicast_group; - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_START; - return cap_initiator_unicast_audio_configure(param); } @@ -931,49 +557,56 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) { struct bt_conn *conns[MIN(CONFIG_BT_MAX_CONN, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT)]; - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_unicast_group *unicast_group; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type == CAP_UNICAST_SUBPROC_TYPE_RELEASE) { + if (bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) { /* When releasing a stream, it may go into the codec configured state if * the unicast server caches the configuration - We treat it as a release */ bt_cap_initiator_released(cap_stream); return; - } else if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_CODEC_CONFIG) { + } else if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p configured (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { - struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; - struct bt_conn *conn = - active_proc.proc_param[active_proc.stream_done_cnt].start.conn; - struct bt_bap_ep *ep = active_proc.proc_param[active_proc.stream_done_cnt].start.ep; - struct bt_audio_codec_cfg *codec_cfg = - &active_proc.proc_param[active_proc.stream_done_cnt].start.codec_cfg; - struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; + if (!bt_cap_common_proc_is_done()) { + const size_t proc_done_cnt = active_proc->proc_done_cnt; + struct bt_cap_stream *next_cap_stream; + struct bt_audio_codec_cfg *codec_cfg; + struct bt_bap_stream *bap_stream; + struct bt_conn *conn; + struct bt_bap_ep *ep; int err; + proc_param = &active_proc->proc_param.initiator[proc_done_cnt]; + next_cap_stream = proc_param->stream; + conn = proc_param->start.conn; + ep = proc_param->start.ep; + codec_cfg = &proc_param->start.codec_cfg; + bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -984,10 +617,8 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to config stream %p: %d", next_cap_stream, err); - cap_abort_proc(conn, err); + bt_cap_common_abort_proc(conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc.stream_initiated_cnt++; } return; @@ -998,8 +629,9 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) * for the procedure */ (void)memset(conns, 0, sizeof(conns)); - for (size_t i = 0U; i < active_proc.stream_cnt; i++) { - struct bt_conn *stream_conn = active_proc.proc_param[i].stream->bap_stream.conn; + for (size_t i = 0U; i < active_proc->proc_cnt; i++) { + struct bt_conn *stream_conn = + active_proc->proc_param.initiator[i].stream->bap_stream.conn; struct bt_conn **free_conn = NULL; bool already_added = false; @@ -1026,9 +658,9 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) /* All streams in the procedure share the same unicast group, so we just * use the reference from the first stream */ - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; unicast_group = (struct bt_bap_unicast_group *)proc_param->stream->bap_stream.group; - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG); for (size_t i = 0U; i < ARRAY_SIZE(conns); i++) { int err; @@ -1038,6 +670,8 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) break; } + active_proc->proc_initiated_cnt++; + err = bt_bap_stream_qos(conns[i], unicast_group); if (err != 0) { LOG_DBG("Failed to set stream QoS for conn %p and group %p: %d", @@ -1047,57 +681,57 @@ void bt_cap_initiator_codec_configured(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(conns[i], err); + bt_cap_common_abort_proc(conns[i], err); if (i == 0U) { cap_initiator_unicast_audio_proc_complete(); } return; } - - active_proc.stream_initiated_cnt++; } } void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_cap_stream *next_cap_stream; struct bt_bap_stream *bap_stream; int err; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_QOS_CONFIG) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p QoS configured (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { /* Not yet finished, wait for all */ return; } - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_ENABLE); - proc_param = &active_proc.proc_param[0]; + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE); + proc_param = &active_proc->proc_param.initiator[0]; next_cap_stream = proc_param->stream; bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, we * cannot assume that we can do multiple streams at once, thus do it one at a time. @@ -1108,47 +742,48 @@ void bt_cap_initiator_qos_configured(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc.stream_initiated_cnt++; } } void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) { - struct cap_unicast_proc_param *proc_param; + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; int err; - if (!cap_stream_in_active_proc(cap_stream)) { + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_ENABLE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_ENABLE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; LOG_DBG("Stream %p enabled (%zu/%zu streams done)", cap_stream, - active_proc.stream_done_cnt, active_proc.stream_cnt); + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *next_bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -1160,17 +795,15 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to enable stream %p: %d", next_cap_stream, err); - cap_abort_proc(next_bap_stream->conn, err); + bt_cap_common_abort_proc(next_bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc.stream_initiated_cnt++; } return; } - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_START); - proc_param = &active_proc.proc_param[0]; + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_START); + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; /* Since BAP operations may require a write long or a read long on the notification, we @@ -1185,7 +818,7 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); return; @@ -1194,29 +827,30 @@ void bt_cap_initiator_enabled(struct bt_cap_stream *cap_stream) void bt_cap_initiator_started(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_START) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_START)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p started (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p started (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } /* Since bt_bap_stream_start connects the ISO, we can, at this point, * only do this one by one due to a restriction in the ISO layer * (maximum 1 outstanding ISO connection request at any one time). */ - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; int err; @@ -1229,7 +863,7 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream) * If we have sent any requests over air, we will abort * once all sent requests has completed */ - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); } } else { @@ -1257,93 +891,147 @@ static bool can_update_metadata(const struct bt_bap_stream *bap_stream) ep_info.state == BT_BAP_EP_STATE_STREAMING; } -int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param params[], - size_t count) +static bool valid_unicast_audio_update_param(const struct bt_cap_unicast_audio_update_param *param) { - struct cap_unicast_proc_param *proc_param; - struct bt_bap_stream *bap_stream; - const uint8_t *meta; - size_t meta_len; - int err; - - CHECKIF(params == NULL) { - LOG_DBG("params is NULL"); + struct bt_bap_unicast_group *unicast_group = NULL; - return -EINVAL; + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; } - CHECKIF(count == 0) { - LOG_DBG("count is 0"); - - return -EINVAL; + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; } - if (cap_proc_is_active()) { - LOG_DBG("A CAP procedure is already in progress"); + CHECKIF(param->stream_params == NULL) { + LOG_DBG("param->stream_params is NULL"); + return false; + } - return -EBUSY; + CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + LOG_DBG("param->count (%zu) is larger than " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)", + param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + return false; } - for (size_t i = 0U; i < count; i++) { - struct bt_cap_stream *cap_stream = params[i].stream; + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_unicast_audio_update_stream_param *stream_param = + ¶m->stream_params[i]; + const struct bt_cap_stream *cap_stream = stream_param->stream; + const struct bt_bap_stream *bap_stream; + struct bt_cap_common_client *client; + struct bt_conn *conn; CHECKIF(cap_stream == NULL) { - LOG_DBG("params[%zu].stream is NULL", i); + LOG_DBG("param->stream_params[%zu] is NULL", i); + return false; + } + + bap_stream = &cap_stream->bap_stream; + conn = bap_stream->conn; + CHECKIF(conn == NULL) { + LOG_DBG("param->stream_params[%zu].stream->bap_stream.conn is NULL", i); return -EINVAL; } - CHECKIF(cap_stream->bap_stream.conn == NULL) { - LOG_DBG("params[%zu].stream->bap_stream.conn is NULL", i); + client = bt_cap_common_get_client_by_acl(conn); + if (!client->cas_found) { + LOG_DBG("CAS was not found for param->stream_params[%zu].stream", i); + return false; + } + + CHECKIF(bap_stream->group == NULL) { + LOG_DBG("param->stream_params[%zu] is not in a unicast group", i); + return false; + } - return -EINVAL; + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->stream_params[%zu] is not in this group %p", i, + unicast_group); + return false; + } } - CHECKIF(!cap_initiator_valid_metadata(params[i].meta, - params[i].meta_len)) { - LOG_DBG("params[%zu].meta is invalid", i); + if (!can_update_metadata(bap_stream)) { + LOG_DBG("param->stream_params[%zu].stream is not in right state to be " + "updated", + i); - return -EINVAL; + return false; + } + + if (!cap_initiator_valid_metadata(stream_param->meta, stream_param->meta_len)) { + LOG_DBG("param->stream_params[%zu] invalid metadata", i); + + return false; } for (size_t j = 0U; j < i; j++) { - if (params[j].stream == cap_stream) { - LOG_DBG("param.streams[%zu] is duplicated by param.streams[%zu]", - j, i); - return -EINVAL; + if (param->stream_params[j].stream == cap_stream) { + LOG_DBG("param->stream_params[%zu] (%p) is " + "duplicated by " + "param->stream_params[%zu] (%p)", + j, param->stream_params[j].stream, i, cap_stream); + return false; } } + } - if (!can_update_metadata(&cap_stream->bap_stream)) { - LOG_DBG("params[%zu].stream is not in right state to be updated", i); + return true; +} - return -EINVAL; - } +int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_update_param *param) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; + struct bt_bap_stream *bap_stream; + const uint8_t *meta; + size_t meta_len; + int err; + + if (bt_cap_common_proc_is_active()) { + LOG_DBG("A CAP procedure is already in progress"); - active_proc.proc_param[i].stream = cap_stream; - active_proc.proc_param[i].meta_update.meta_len = params[i].meta_len; - memcpy(&active_proc.proc_param[i].meta_update.meta, params[i].meta, - params[i].meta_len); + return -EBUSY; + } + + if (!valid_unicast_audio_update_param(param)) { + return -EINVAL; } - atomic_set_bit(active_proc.proc_state_flags, CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = count; + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_unicast_audio_update_stream_param *stream_param = + ¶m->stream_params[i]; + struct bt_cap_stream *cap_stream = stream_param->stream; + + active_proc->proc_param.initiator[i].stream = cap_stream; + active_proc->proc_param.initiator[i].meta_update.meta_len = stream_param->meta_len; + memcpy(&active_proc->proc_param.initiator[i].meta_update.meta, stream_param->meta, + stream_param->meta_len); + } - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_UPDATE; - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_META_UPDATE); + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_UPDATE, param->count); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE); - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; meta_len = proc_param->meta_update.meta_len; meta = proc_param->meta_update.meta; + active_proc->proc_initiated_cnt++; err = bt_bap_stream_metadata(bap_stream, meta, meta_len); if (err != 0) { LOG_DBG("Failed to update metadata for stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); - } else { - active_proc.stream_initiated_cnt++; + bt_cap_common_clear_active_proc(); } return err; @@ -1351,13 +1039,13 @@ int bt_cap_initiator_unicast_audio_update(const struct bt_cap_unicast_audio_upda int bt_cap_initiator_unicast_audio_cancel(void) { - if (!cap_proc_is_active() && !cap_proc_is_aborted()) { + if (!bt_cap_common_proc_is_active() && !bt_cap_common_proc_is_aborted()) { LOG_DBG("No CAP procedure is in progress"); return -EALREADY; } - cap_abort_proc(NULL, -ECANCELED); + bt_cap_common_abort_proc(NULL, -ECANCELED); cap_initiator_unicast_audio_proc_complete(); return 0; @@ -1365,40 +1053,47 @@ int bt_cap_initiator_unicast_audio_cancel(void) void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_META_UPDATE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p QoS metadata updated (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { - const size_t meta_len = - active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta_len; - const uint8_t *meta = - active_proc.proc_param[active_proc.stream_done_cnt].meta_update.meta; - struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; - struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; + if (!bt_cap_common_proc_is_done()) { + const size_t proc_done_cnt = active_proc->proc_done_cnt; + struct bt_cap_initiator_proc_param *proc_param; + struct bt_cap_stream *next_cap_stream; + struct bt_bap_stream *bap_stream; + const uint8_t *meta; + size_t meta_len; int err; + proc_param = &active_proc->proc_param.initiator[proc_done_cnt]; + meta_len = proc_param->meta_update.meta_len; + meta = proc_param->meta_update.meta; + next_cap_stream = proc_param->stream; + bap_stream = &next_cap_stream->bap_stream; + active_proc->proc_initiated_cnt++; + /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -1411,10 +1106,8 @@ void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream) LOG_DBG("Failed to update metadata for stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc.stream_initiated_cnt++; } return; @@ -1442,62 +1135,133 @@ static bool can_release(const struct bt_bap_stream *bap_stream) return ep_info.state != BT_BAP_EP_STATE_IDLE; } -int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_group) +static bool valid_unicast_audio_stop_param(const struct bt_cap_unicast_audio_stop_param *param) { - struct cap_unicast_proc_param *proc_param; + struct bt_bap_unicast_group *unicast_group = NULL; + + CHECKIF(param == NULL) { + LOG_DBG("param is NULL"); + return false; + } + + CHECKIF(param->count == 0) { + LOG_DBG("Invalid param->count: %u", param->count); + return false; + } + + CHECKIF(param->streams == NULL) { + LOG_DBG("param->streams is NULL"); + return false; + } + + CHECKIF(param->count > CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT) { + LOG_DBG("param->count (%zu) is larger than " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d)", + param->count, CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + return false; + } + + for (size_t i = 0U; i < param->count; i++) { + const struct bt_cap_stream *cap_stream = param->streams[i]; + const struct bt_bap_stream *bap_stream; + struct bt_cap_common_client *client; + struct bt_conn *conn; + + CHECKIF(cap_stream == NULL) { + LOG_DBG("param->streams[%zu] is NULL", i); + return false; + } + + bap_stream = &cap_stream->bap_stream; + conn = bap_stream->conn; + CHECKIF(conn == NULL) { + LOG_DBG("param->streams[%zu]->bap_stream.conn is NULL", i); + + return -EINVAL; + } + + client = bt_cap_common_get_client_by_acl(conn); + if (!client->cas_found) { + LOG_DBG("CAS was not found for param->streams[%zu]", i); + return false; + } + + CHECKIF(bap_stream->group == NULL) { + LOG_DBG("param->streams[%zu] is not in a unicast group", i); + return false; + } + + /* Use the group of the first stream for comparison */ + if (unicast_group == NULL) { + unicast_group = bap_stream->group; + } else { + CHECKIF(bap_stream->group != unicast_group) { + LOG_DBG("param->streams[%zu] is not in this group %p", i, + unicast_group); + return false; + } + } + + if (!can_release(bap_stream)) { + LOG_DBG("Cannot stop param->streams[%zu]", i); + + return false; + } + + for (size_t j = 0U; j < i; j++) { + if (param->streams[j] == cap_stream) { + LOG_DBG("param->stream_params[%zu] (%p) is " + "duplicated by " + "param->stream_params[%zu] (%p)", + j, param->streams[j], i, cap_stream); + return false; + } + } + } + + return true; +} + +int bt_cap_initiator_unicast_audio_stop(const struct bt_cap_unicast_audio_stop_param *param) +{ + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + struct bt_cap_initiator_proc_param *proc_param; struct bt_bap_stream *bap_stream; - size_t stream_cnt; int err; - if (cap_proc_is_active()) { + if (bt_cap_common_proc_is_active()) { LOG_DBG("A CAP procedure is already in progress"); return -EBUSY; } - CHECKIF(unicast_group == NULL) { - LOG_DBG("unicast_group is NULL"); + if (!valid_unicast_audio_stop_param(param)) { return -EINVAL; } - stream_cnt = 0U; - SYS_SLIST_FOR_EACH_CONTAINER(&unicast_group->streams, bap_stream, _node) { - if (can_release(bap_stream)) { - struct bt_cap_stream *cap_stream = - CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); - active_proc.proc_param[stream_cnt].stream = cap_stream; - stream_cnt++; - } - } - - if (stream_cnt == 0U) { - LOG_DBG("All streams are already stopped"); + for (size_t i = 0U; i < param->count; i++) { + struct bt_cap_stream *cap_stream = param->streams[i]; - return -EALREADY; + active_proc->proc_param.initiator[i].stream = cap_stream; } - atomic_set_bit(active_proc.proc_state_flags, - CAP_UNICAST_PROC_STATE_ACTIVE); - active_proc.stream_cnt = stream_cnt; - active_proc.unicast_group = unicast_group; - active_proc.proc_type = CAP_UNICAST_PROC_TYPE_STOP; + bt_cap_common_start_proc(BT_CAP_COMMON_PROC_TYPE_STOP, param->count); - cap_set_subproc(CAP_UNICAST_SUBPROC_TYPE_RELEASE); + bt_cap_common_set_subproc(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE); /** TODO: If this is a CSIP set, then the order of the procedures may * not match the order in the parameters, and the CSIP ordered access * procedure should be used. */ - proc_param = &active_proc.proc_param[0]; + proc_param = &active_proc->proc_param.initiator[0]; bap_stream = &proc_param->stream->bap_stream; + active_proc->proc_initiated_cnt++; err = bt_bap_stream_release(bap_stream); if (err != 0) { LOG_DBG("Failed to stop bap_stream %p: %d", proc_param->stream, err); - (void)memset(&active_proc, 0, sizeof(active_proc)); - } else { - active_proc.stream_initiated_cnt++; + bt_cap_common_clear_active_proc(); } return err; @@ -1505,36 +1269,38 @@ int bt_cap_initiator_unicast_audio_stop(struct bt_bap_unicast_group *unicast_gro void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) { - if (!cap_stream_in_active_proc(cap_stream)) { + struct bt_cap_common_proc *active_proc = bt_cap_common_get_active_proc(); + + if (!bt_cap_common_stream_in_active_proc(cap_stream)) { /* State change happened outside of a procedure; ignore */ return; } - if (active_proc.subproc_type != CAP_UNICAST_SUBPROC_TYPE_RELEASE) { + if (!bt_cap_common_subproc_is_type(BT_CAP_COMMON_SUBPROC_TYPE_RELEASE)) { /* Unexpected callback - Abort */ - cap_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); + bt_cap_common_abort_proc(cap_stream->bap_stream.conn, -EBADMSG); } else { - active_proc.stream_done_cnt++; + active_proc->proc_done_cnt++; - LOG_DBG("Stream %p released (%zu/%zu streams done)", - cap_stream, active_proc.stream_done_cnt, - active_proc.stream_cnt); + LOG_DBG("Stream %p released (%zu/%zu streams done)", cap_stream, + active_proc->proc_done_cnt, active_proc->proc_cnt); } - if (cap_proc_is_aborted()) { - if (cap_proc_all_streams_handled()) { + if (bt_cap_common_proc_is_aborted()) { + if (bt_cap_common_proc_all_handled()) { cap_initiator_unicast_audio_proc_complete(); } return; } - if (!cap_proc_is_done()) { + if (!bt_cap_common_proc_is_done()) { struct bt_cap_stream *next_cap_stream = - active_proc.proc_param[active_proc.stream_done_cnt].stream; + active_proc->proc_param.initiator[active_proc->proc_done_cnt].stream; struct bt_bap_stream *bap_stream = &next_cap_stream->bap_stream; int err; + active_proc->proc_initiated_cnt++; /* Since BAP operations may require a write long or a read long on the notification, * we cannot assume that we can do multiple streams at once, thus do it one at a * time. @@ -1545,10 +1311,8 @@ void bt_cap_initiator_released(struct bt_cap_stream *cap_stream) if (err != 0) { LOG_DBG("Failed to release stream %p: %d", next_cap_stream, err); - cap_abort_proc(bap_stream->conn, err); + bt_cap_common_abort_proc(bap_stream->conn, err); cap_initiator_unicast_audio_proc_complete(); - } else { - active_proc.stream_initiated_cnt++; } } else { cap_initiator_unicast_audio_proc_complete(); diff --git a/subsys/bluetooth/audio/cap_internal.h b/subsys/bluetooth/audio/cap_internal.h index ac07f3f817c..145cb2fd24e 100644 --- a/subsys/bluetooth/audio/cap_internal.h +++ b/subsys/bluetooth/audio/cap_internal.h @@ -1,14 +1,18 @@ /* Bluetooth Audio Common Audio Profile internal header */ /* - * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2022-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include +#include +#include #include +#include bool bt_cap_acceptor_ccid_exist(const struct bt_conn *conn, uint8_t ccid); @@ -19,3 +23,127 @@ void bt_cap_initiator_started(struct bt_cap_stream *cap_stream); void bt_cap_initiator_metadata_updated(struct bt_cap_stream *cap_stream); void bt_cap_initiator_released(struct bt_cap_stream *cap_stream); void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream); + +enum bt_cap_common_proc_state { + BT_CAP_COMMON_PROC_STATE_ACTIVE, + BT_CAP_COMMON_PROC_STATE_ABORTED, + + BT_CAP_COMMON_PROC_STATE_FLAG_NUM, +}; + +enum bt_cap_common_proc_type { + BT_CAP_COMMON_PROC_TYPE_NONE, + BT_CAP_COMMON_PROC_TYPE_START, + BT_CAP_COMMON_PROC_TYPE_UPDATE, + BT_CAP_COMMON_PROC_TYPE_STOP, + BT_CAP_COMMON_PROC_TYPE_VOLUME_CHANGE, + BT_CAP_COMMON_PROC_TYPE_VOLUME_OFFSET_CHANGE, +}; + +enum bt_cap_common_subproc_type { + BT_CAP_COMMON_SUBPROC_TYPE_NONE, + BT_CAP_COMMON_SUBPROC_TYPE_CODEC_CONFIG, + BT_CAP_COMMON_SUBPROC_TYPE_QOS_CONFIG, + BT_CAP_COMMON_SUBPROC_TYPE_ENABLE, + BT_CAP_COMMON_SUBPROC_TYPE_START, + BT_CAP_COMMON_SUBPROC_TYPE_META_UPDATE, + BT_CAP_COMMON_SUBPROC_TYPE_RELEASE, +}; + +struct bt_cap_initiator_proc_param { + struct bt_cap_stream *stream; + union { + struct { + struct bt_conn *conn; + struct bt_bap_ep *ep; + struct bt_audio_codec_cfg codec_cfg; + } start; + struct { + /** Codec Specific Capabilities Metadata count */ + size_t meta_len; + /** Codec Specific Capabilities Metadata */ + uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE]; + } meta_update; + }; +}; + +struct bt_cap_commander_proc_param { + struct bt_conn *conn; + union { +#if defined(CONFIG_BT_VCP_VOL_CTLR) + struct { + uint8_t volume; + } change_volume; +#endif /* CONFIG_BT_VCP_VOL_CTLR */ +#if defined(CONFIG_BT_VCP_VOL_CTLR_VOCS) + struct { + int16_t offset; + struct bt_vocs *vocs; + } change_offset; +#endif /* CONFIG_BT_VCP_VOL_CTLR_VOCS */ + + /* TODO Add other procedures */ + }; +}; + +struct bt_cap_common_proc_param { + union { +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + struct bt_cap_initiator_proc_param + initiator[CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT]; +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +#if defined(CONFIG_BT_CAP_COMMANDER) + struct bt_cap_commander_proc_param commander[CONFIG_BT_MAX_CONN]; +#endif /* CONFIG_BT_CAP_COMMANDER */ + }; +}; + +struct bt_cap_common_proc { + ATOMIC_DEFINE(proc_state_flags, BT_CAP_COMMON_PROC_STATE_FLAG_NUM); + /* Total number of items (streams or connections) in the procedure*/ + size_t proc_cnt; + /* Number of items where a subprocedure have been started */ + size_t proc_initiated_cnt; + /* Number of items done with the procedure */ + size_t proc_done_cnt; + enum bt_cap_common_proc_type proc_type; + int err; + struct bt_conn *failed_conn; + struct bt_cap_common_proc_param proc_param; +#if defined(CONFIG_BT_CAP_INITIATOR_UNICAST) + enum bt_cap_common_subproc_type subproc_type; +#endif /* CONFIG_BT_CAP_INITIATOR_UNICAST */ +}; + +struct bt_cap_common_client { + struct bt_conn *conn; + struct bt_gatt_discover_params param; + uint16_t csis_start_handle; + const struct bt_csip_set_coordinator_csis_inst *csis_inst; + bool cas_found; +}; + +struct bt_cap_common_proc *bt_cap_common_get_active_proc(void); +void bt_cap_common_clear_active_proc(void); +void bt_cap_common_start_proc(enum bt_cap_common_proc_type proc_type, size_t proc_cnt); +void bt_cap_common_set_subproc(enum bt_cap_common_subproc_type subproc_type); +bool bt_cap_common_subproc_is_type(enum bt_cap_common_subproc_type subproc_type); +struct bt_conn *bt_cap_common_get_member_conn(enum bt_cap_set_type type, + const union bt_cap_set_member *member); +bool bt_cap_common_proc_is_active(void); +bool bt_cap_common_proc_is_aborted(void); +bool bt_cap_common_proc_all_handled(void); +bool bt_cap_common_proc_is_done(void); +void bt_cap_common_abort_proc(struct bt_conn *conn, int err); +bool bt_cap_common_conn_in_active_proc(const struct bt_conn *conn); +bool bt_cap_common_stream_in_active_proc(const struct bt_cap_stream *cap_stream); +void bt_cap_common_disconnected(struct bt_conn *conn, uint8_t reason); +struct bt_cap_common_client *bt_cap_common_get_client_by_acl(const struct bt_conn *acl); +struct bt_cap_common_client * +bt_cap_common_get_client_by_csis(const struct bt_csip_set_coordinator_csis_inst *csis_inst); +struct bt_cap_common_client *bt_cap_common_get_client(enum bt_cap_set_type type, + const union bt_cap_set_member *member); + +typedef void (*bt_cap_common_discover_func_t)( + struct bt_conn *conn, int err, const struct bt_csip_set_coordinator_csis_inst *csis_inst); +int bt_cap_common_discover(struct bt_conn *conn, bt_cap_common_discover_func_t func); diff --git a/subsys/bluetooth/audio/cap_stream.c b/subsys/bluetooth/audio/cap_stream.c index 863d32874a2..9d0a1004517 100644 --- a/subsys/bluetooth/audio/cap_stream.c +++ b/subsys/bluetooth/audio/cap_stream.c @@ -182,6 +182,28 @@ static void cap_stream_sent_cb(struct bt_bap_stream *bap_stream) } #endif /* CONFIG_BT_AUDIO_TX */ +static void cap_stream_connected_cb(struct bt_bap_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct bt_bap_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->connected != NULL) { + ops->connected(bap_stream); + } +} + +static void cap_stream_disconnected_cb(struct bt_bap_stream *bap_stream, uint8_t reason) +{ + struct bt_cap_stream *cap_stream = + CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream); + struct bt_bap_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->disconnected != NULL) { + ops->disconnected(bap_stream, reason); + } +} + static struct bt_bap_stream_ops bap_stream_ops = { #if defined(CONFIG_BT_BAP_UNICAST) .configured = cap_stream_configured_cb, @@ -199,6 +221,8 @@ static struct bt_bap_stream_ops bap_stream_ops = { #if defined(CONFIG_BT_AUDIO_TX) .sent = cap_stream_sent_cb, #endif /* CONFIG_BT_AUDIO_TX */ + .connected = cap_stream_connected_cb, + .disconnected = cap_stream_disconnected_cb, }; void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream) diff --git a/subsys/bluetooth/audio/ccid_internal.h b/subsys/bluetooth/audio/ccid_internal.h index 87cca3d7098..bf48877529d 100644 --- a/subsys/bluetooth/audio/ccid_internal.h +++ b/subsys/bluetooth/audio/ccid_internal.h @@ -10,7 +10,6 @@ #ifndef ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ #define ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ -#include #include /** diff --git a/subsys/bluetooth/audio/codec.c b/subsys/bluetooth/audio/codec.c index 38b1ef7d22b..c62a48b95c0 100644 --- a/subsys/bluetooth/audio/codec.c +++ b/subsys/bluetooth/audio/codec.c @@ -142,6 +142,8 @@ static bool parse_cb(struct bt_data *data, void *user_data) static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t *data, size_t data_len) { + size_t new_buf_len; + for (uint16_t i = 0U; i < buf->len;) { uint8_t *len = &buf->data[i++]; const uint8_t data_type = buf->data[i++]; @@ -162,8 +164,8 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * if (value + value_len == buf->data + buf->len) { data_len_to_move = 0U; } else { - old_next_data_start = value + value_len + 1; - new_next_data_start = value + data_len + 1; + old_next_data_start = value + value_len; + new_next_data_start = value + data_len; data_len_to_move = buf->len - (old_next_data_start - buf->data); } @@ -207,11 +209,12 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * } /* If we reach here, we did not find the data in the buffer, so we simply add it */ - if ((buf->len + data_len) <= buf->size) { - net_buf_simple_add_u8(buf, data_len + sizeof(type)); - net_buf_simple_add_u8(buf, type); + new_buf_len = buf->len + 1 /* len */ + sizeof(type) + data_len; + if (new_buf_len <= buf->size) { + net_buf_simple_add_u8(buf, data_len + sizeof(type)); /* len */ + net_buf_simple_add_u8(buf, type); /* type */ if (data_len > 0) { - net_buf_simple_add_mem(buf, data, data_len); + net_buf_simple_add_mem(buf, data, data_len); /* value */ } } else { LOG_DBG("Cannot fit data_len %zu in codec_cfg with len %u and size %u", data_len, @@ -221,6 +224,44 @@ static int ltv_set_val(struct net_buf_simple *buf, uint8_t type, const uint8_t * return buf->len; } + +static int ltv_unset_val(struct net_buf_simple *buf, uint8_t type) +{ + for (uint16_t i = 0U; i < buf->len;) { + uint8_t *ltv_start = &buf->data[i]; + const uint8_t len = buf->data[i++]; + const uint8_t data_type = buf->data[i++]; + const uint8_t value_len = len - sizeof(data_type); + + if (data_type == type) { + const uint8_t ltv_size = value_len + sizeof(data_type) + sizeof(len); + uint8_t *value = &buf->data[i]; + + /* Check if this is not the last value in the buffer */ + if (value + value_len != buf->data + buf->len) { + uint8_t *next_data_start; + uint8_t data_len_to_move; + + next_data_start = value + value_len; + data_len_to_move = buf->len - (next_data_start - buf->data); + memmove(ltv_start, next_data_start, data_len_to_move); + + LOG_ERR("buf->data %p, ltv_start %p, value_len %u next_data_start " + "%p data_len_to_move %u", + buf->data, ltv_start, value_len, next_data_start, + data_len_to_move); + } /* else just reduce the length of the buffer */ + + buf->len -= ltv_size; + + return buf->len; + } + + i += value_len; + } + + return buf->len; +} #endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 || \ * CONFIG_BT_AUDIO_CODEC_CAP_MAX_DATA_SIZE > 0 || \ @@ -238,8 +279,8 @@ static void init_net_buf_simple_from_codec_cfg(struct net_buf_simple *buf, buf->len = codec_cfg->data_len; } -uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, - enum bt_audio_codec_config_type type, const uint8_t **data) +int bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type, const uint8_t **data) { struct search_type_param param = { .found = false, @@ -251,12 +292,12 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, CHECKIF(codec_cfg == NULL) { LOG_DBG("codec is NULL"); - return 0; + return -EINVAL; } CHECKIF(data == NULL) { LOG_DBG("data is NULL"); - return 0; + return -EINVAL; } *data = NULL; @@ -264,12 +305,12 @@ uint8_t bt_audio_codec_cfg_get_val(const struct bt_audio_codec_cfg *codec_cfg, err = bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, parse_cb, ¶m); if (err != 0 && err != -ECANCELED) { LOG_DBG("Could not parse the data: %d", err); - return 0; + return err; } - if (param.data == NULL) { + if (!param.found) { LOG_DBG("Could not find the type %u", type); - return 0; + return -ENODATA; } return param.data_len; @@ -307,6 +348,27 @@ int bt_audio_codec_cfg_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_codec_config_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cfg(&buf, codec_cfg); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cfg->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_get_freq(const struct bt_audio_codec_cfg *codec_cfg) { enum bt_audio_codec_config_freq freq; @@ -529,12 +591,12 @@ static void init_net_buf_simple_from_meta(struct net_buf_simple *buf, uint8_t me buf->len = meta_len; } -static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, uint8_t type, - const uint8_t **data) +static int codec_meta_get_val(const uint8_t meta[], size_t meta_len, + enum bt_audio_metadata_type type, const uint8_t **data) { struct search_type_param param = { .found = false, - .type = type, + .type = (uint8_t)type, .data_len = 0, .data = data, }; @@ -592,6 +654,21 @@ static int codec_meta_set_val(uint8_t meta[], size_t meta_len, size_t meta_size, return ltv_set_val(&buf, (uint8_t)type, data, data_len); } +static int codec_meta_unset_val(uint8_t meta[], size_t meta_len, size_t meta_size, + enum bt_audio_metadata_type type) +{ + struct net_buf_simple buf; + + CHECKIF(meta == NULL) { + LOG_DBG("meta is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_meta(&buf, meta, meta_len, meta_size); + + return ltv_unset_val(&buf, type); +} + static int codec_meta_get_pref_context(const uint8_t meta[], size_t meta_len) { const uint8_t *data; @@ -1080,6 +1157,25 @@ int bt_audio_codec_cfg_meta_set_val(struct bt_audio_codec_cfg *codec_cfg, return ret; } +int bt_audio_codec_cfg_meta_unset_val(struct bt_audio_codec_cfg *codec_cfg, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cfg == NULL) { + LOG_DBG("codec_cfg is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cfg->meta, codec_cfg->meta_len, + ARRAY_SIZE(codec_cfg->meta), type); + if (ret >= 0) { + codec_cfg->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cfg_meta_get_pref_context(const struct bt_audio_codec_cfg *codec_cfg) { CHECKIF(codec_cfg == NULL) { @@ -1388,6 +1484,25 @@ int bt_audio_codec_cap_meta_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_meta_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_metadata_type type) +{ + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + ret = codec_meta_unset_val(codec_cap->meta, codec_cap->meta_len, + ARRAY_SIZE(codec_cap->meta), type); + if (ret >= 0) { + codec_cap->meta_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_meta_get_pref_context(const struct bt_audio_codec_cap *codec_cap) { CHECKIF(codec_cap == NULL) { @@ -1678,8 +1793,8 @@ static void init_net_buf_simple_from_codec_cap(struct net_buf_simple *buf, buf->len = codec_cap->data_len; } -uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, - enum bt_audio_codec_capability_type type, const uint8_t **data) +int bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type, const uint8_t **data) { struct search_type_param param = { .found = false, @@ -1691,12 +1806,12 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, CHECKIF(codec_cap == NULL) { LOG_DBG("codec_cap is NULL"); - return 0; + return -EINVAL; } CHECKIF(data == NULL) { LOG_DBG("data is NULL"); - return 0; + return -EINVAL; } *data = NULL; @@ -1704,12 +1819,12 @@ uint8_t bt_audio_codec_cap_get_val(const struct bt_audio_codec_cap *codec_cap, err = bt_audio_data_parse(codec_cap->data, codec_cap->data_len, parse_cb, ¶m); if (err != 0 && err != -ECANCELED) { LOG_DBG("Could not parse the data: %d", err); - return 0; + return err; } - if (param.data == NULL) { + if (!param.found) { LOG_DBG("Could not find the type %u", type); - return 0; + return -ENODATA; } return param.data_len; @@ -1747,6 +1862,27 @@ int bt_audio_codec_cap_set_val(struct bt_audio_codec_cap *codec_cap, return ret; } +int bt_audio_codec_cap_unset_val(struct bt_audio_codec_cap *codec_cap, + enum bt_audio_codec_capability_type type) +{ + struct net_buf_simple buf; + int ret; + + CHECKIF(codec_cap == NULL) { + LOG_DBG("codec_cap is NULL"); + return -EINVAL; + } + + init_net_buf_simple_from_codec_cap(&buf, codec_cap); + + ret = ltv_unset_val(&buf, type); + if (ret >= 0) { + codec_cap->data_len = ret; + } + + return ret; +} + int bt_audio_codec_cap_get_freq(const struct bt_audio_codec_cap *codec_cap) { const uint8_t *data; diff --git a/subsys/bluetooth/audio/csip_crypto.c b/subsys/bluetooth/audio/csip_crypto.c index d51855f02a5..3240e6d053e 100644 --- a/subsys/bluetooth/audio/csip_crypto.c +++ b/subsys/bluetooth/audio/csip_crypto.c @@ -11,12 +11,10 @@ */ #include "csip_crypto.h" #include -#include -#include -#include -#include -#include #include +#include + +#include "crypto/bt_crypto.h" #include "common/bt_str.h" @@ -28,39 +26,6 @@ LOG_MODULE_REGISTER(bt_csip_crypto, CONFIG_BT_CSIP_SET_MEMBER_CRYPTO_LOG_LEVEL); #define BT_CSIP_PADDED_RAND_SIZE (BT_CSIP_CRYPTO_PADDING_SIZE + BT_CSIP_CRYPTO_PRAND_SIZE) #define BT_CSIP_R_MASK BIT_MASK(24) /* r is 24 bit / 3 octet */ -static int aes_cmac(const uint8_t key[BT_CSIP_CRYPTO_KEY_SIZE], - const uint8_t *in, size_t in_len, uint8_t *out) -{ - struct tc_aes_key_sched_struct sched; - struct tc_cmac_struct state; - - /* TODO: Copy of the aes_cmac from smp.c: Can we merge them? */ - - if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { - return -EIO; - } - - if (tc_cmac_update(&state, in, in_len) == TC_CRYPTO_FAIL) { - return -EIO; - } - - if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) { - return -EIO; - } - - return 0; -} - -static void xor_128(const uint8_t a[16], const uint8_t b[16], uint8_t out[16]) -{ - size_t len = 16; - /* TODO: Identical to the xor_128 from smp.c: Move to util */ - - while (len--) { - *out++ = *a++ ^ *b++; - } -} - int bt_csip_sih(const uint8_t sirk[BT_CSIP_SET_SIRK_SIZE], uint8_t r[BT_CSIP_CRYPTO_PRAND_SIZE], uint8_t out[BT_CSIP_CRYPTO_HASH_SIZE]) { @@ -139,7 +104,7 @@ static int k1(const uint8_t *n, size_t n_size, LOG_DBG("BE: salt %s", bt_hex(salt, BT_CSIP_CRYPTO_SALT_SIZE)); LOG_DBG("BE: p %s", bt_hex(p, p_size)); - err = aes_cmac(salt, n, n_size, t); + err = bt_crypto_aes_cmac(salt, n, n_size, t); LOG_DBG("BE: t %s", bt_hex(t, sizeof(t))); @@ -147,7 +112,7 @@ static int k1(const uint8_t *n, size_t n_size, return err; } - err = aes_cmac(t, p, p_size, out); + err = bt_crypto_aes_cmac(t, p, p_size, out); LOG_DBG("BE: out %s", bt_hex(out, 16)); @@ -176,7 +141,7 @@ static int s1(const uint8_t *m, size_t m_size, memset(zero, 0, sizeof(zero)); - err = aes_cmac(zero, m, m_size, out); + err = bt_crypto_aes_cmac(zero, m, m_size, out); LOG_DBG("BE: out %s", bt_hex(out, 16)); @@ -229,7 +194,7 @@ int bt_csip_sef(const uint8_t k[BT_CSIP_CRYPTO_KEY_SIZE], sys_mem_swap(k1_out, sizeof(k1_out)); } - xor_128(k1_out, sirk, out_sirk); + mem_xor_128(out_sirk, k1_out, sirk); LOG_DBG("out %s", bt_hex(out_sirk, BT_CSIP_SET_SIRK_SIZE)); return 0; diff --git a/subsys/bluetooth/audio/csip_set_coordinator.c b/subsys/bluetooth/audio/csip_set_coordinator.c index 36e5803b45c..e0fdb8a6084 100644 --- a/subsys/bluetooth/audio/csip_set_coordinator.c +++ b/subsys/bluetooth/audio/csip_set_coordinator.c @@ -740,12 +740,22 @@ static uint8_t discover_func(struct bt_conn *conn, } if (sub_params->value != 0) { + int err; + /* With ccc_handle == 0 it will use auto discovery */ sub_params->ccc_handle = 0; sub_params->end_handle = cur_inst->end_handle; sub_params->value_handle = chrc->value_handle; sub_params->notify = notify_handler; - bt_gatt_subscribe(conn, sub_params); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); + + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0 && err != -EALREADY) { + LOG_DBG("Failed to subscribe (err %d)", err); + discover_complete(client, err); + + return BT_GATT_ITER_STOP; + } } } } @@ -1315,6 +1325,9 @@ static int csip_set_coordinator_read_set_lock(struct bt_csip_set_coordinator_svc static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst) { + inst->inst_count = 0U; + memset(&inst->set_member, 0, sizeof(inst->set_member)); + for (size_t i = 0; i < ARRAY_SIZE(inst->svc_insts); i++) { struct bt_csip_set_coordinator_svc_inst *svc_inst = &inst->svc_insts[i]; @@ -1330,20 +1343,6 @@ static void csip_set_coordinator_reset(struct bt_csip_set_coordinator_inst *inst if (svc_inst->conn != NULL) { struct bt_conn *conn = svc_inst->conn; - /* It's okay if these fail. In case of disconnect, - * we can't unsubscribe and they will just fail. - * In case that we reset due to another call of the - * discover function, we will unsubscribe (regardless of - * bonding state) to accommodate the new discovery - * values. - */ - (void)bt_gatt_unsubscribe(conn, - &svc_inst->sirk_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->size_sub_params); - (void)bt_gatt_unsubscribe(conn, - &svc_inst->lock_sub_params); - bt_conn_unref(conn); svc_inst->conn = NULL; } @@ -1433,7 +1432,7 @@ int bt_csip_set_coordinator_discover(struct bt_conn *conn) client = &client_insts[bt_conn_index(conn)]; - (void)memset(client, 0, sizeof(*client)); + csip_set_coordinator_reset(client); /* Discover CSIS on peer, setup handles and notify */ (void)memset(&discover_params, 0, sizeof(discover_params)); diff --git a/subsys/bluetooth/audio/csip_set_member.c b/subsys/bluetooth/audio/csip_set_member.c index b6bd487af82..a3eb14241c9 100644 --- a/subsys/bluetooth/audio/csip_set_member.c +++ b/subsys/bluetooth/audio/csip_set_member.c @@ -144,9 +144,13 @@ static int notify_lock_value(const struct bt_csip_set_member_svc_inst *svc_inst, struct bt_conn *conn) { LOG_DBG(""); - return csip_gatt_notify_set_lock(conn, svc_inst->service_p->attrs, - &svc_inst->set_lock, - sizeof(svc_inst->set_lock)); + + if (svc_inst->service_p != NULL) { + return csip_gatt_notify_set_lock(conn, svc_inst->service_p->attrs, + &svc_inst->set_lock, sizeof(svc_inst->set_lock)); + } else { + return -EINVAL; + } } static void notify_client(struct bt_conn *conn, void *data) @@ -235,6 +239,10 @@ static int sirk_encrypt(struct bt_conn *conn, LOG_DBG("Encrypting test SIRK"); k = test_k; } else { + if (conn == NULL) { + return -EINVAL; + } + k = conn->le.keys->ltk.val; } @@ -723,6 +731,10 @@ BT_GATT_SERVICE_INSTANCE_DEFINE(csip_set_member_service_list, svc_insts, /****************************** Public API ******************************/ void *bt_csip_set_member_svc_decl_get(const struct bt_csip_set_member_svc_inst *svc_inst) { + if (svc_inst == NULL || svc_inst->service_p == NULL) { + return NULL; + } + return svc_inst->service_p->attrs; } @@ -940,6 +952,27 @@ int bt_csip_set_member_register(const struct bt_csip_set_member_register_param * return 0; } +int bt_csip_set_member_unregister(struct bt_csip_set_member_svc_inst *svc_inst) +{ + int err; + + CHECKIF(svc_inst == NULL) { + LOG_DBG("NULL svc_inst"); + return -EINVAL; + } + + err = bt_gatt_service_unregister(svc_inst->service_p); + if (err != 0) { + LOG_DBG("CSIS service unregister failed: %d", err); + return err; + } + + (void)k_work_cancel_delayable(&svc_inst->set_lock_timer); + memset(svc_inst, 0, sizeof(*svc_inst)); + + return 0; +} + int bt_csip_set_member_lock(struct bt_csip_set_member_svc_inst *svc_inst, bool lock, bool force) { diff --git a/subsys/bluetooth/audio/gmap_client.c b/subsys/bluetooth/audio/gmap_client.c new file mode 100644 index 00000000000..dff67356b76 --- /dev/null +++ b/subsys/bluetooth/audio/gmap_client.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "audio_internal.h" + +LOG_MODULE_REGISTER(bt_gmap_client, CONFIG_BT_GMAP_LOG_LEVEL); + +static const struct bt_uuid *gmas_uuid = BT_UUID_GMAS; +static const struct bt_uuid *gmap_role_uuid = BT_UUID_GMAP_ROLE; +static const struct bt_uuid *gmap_ugg_feat_uuid = BT_UUID_GMAP_UGG_FEAT; +static const struct bt_uuid *gmap_ugt_feat_uuid = BT_UUID_GMAP_UGT_FEAT; +static const struct bt_uuid *gmap_bgs_feat_uuid = BT_UUID_GMAP_BGS_FEAT; +static const struct bt_uuid *gmap_bgr_feat_uuid = BT_UUID_GMAP_BGR_FEAT; + +static const struct bt_gmap_cb *gmap_cb; + +static struct bt_gmap_client { + /** Profile connection reference */ + struct bt_conn *conn; + + /* Remote role and features */ + enum bt_gmap_role role; + struct bt_gmap_feat feat; + + uint16_t svc_start_handle; + uint16_t svc_end_handle; + + bool busy; + + /* GATT procedure parameters */ + union { + struct bt_gatt_read_params read; + struct bt_gatt_discover_params discover; + } params; +} gmap_insts[CONFIG_BT_MAX_CONN]; + +static void gmap_reset(struct bt_gmap_client *gmap_cli) +{ + if (gmap_cli->conn != NULL) { + bt_conn_unref(gmap_cli->conn); + } + + memset(gmap_cli, 0, sizeof(*gmap_cli)); +} + +static struct bt_gmap_client *client_by_conn(struct bt_conn *conn) +{ + struct bt_gmap_client *gmap_cli = &gmap_insts[bt_conn_index(conn)]; + + if (gmap_cli->conn == conn) { + return gmap_cli; + } + + return NULL; +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + + if (gmap_cli != NULL) { + bt_conn_unref(gmap_cli->conn); + gmap_cli->conn = NULL; + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected, +}; + +static void discover_complete(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + gmap_cli->busy = false; + + if (gmap_cb->discover != NULL) { + gmap_cb->discover(gmap_cli->conn, 0, gmap_cli->role, gmap_cli->feat); + } +} + +static void discover_failed(struct bt_gmap_client *gmap_cli, int err) +{ + struct bt_conn *conn = gmap_cli->conn; + + gmap_reset(gmap_cli); + + LOG_DBG("conn %p err %d", (void *)conn, err); + + gmap_cb->discover(conn, err, 0, (struct bt_gmap_feat){0}); +} + +static uint8_t bgr_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.bgr_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("bgr_feat 0x%02x", gmap_cli->feat.bgr_feat); + + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_bgr_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = bgr_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t bgr_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_bgr_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_bgr_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = bgr_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_bgr_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t bgs_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.bgs_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("bgs_feat 0x%02x", gmap_cli->feat.bgs_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_bgs_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = bgs_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t bgs_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_bgs_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_bgs_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = bgs_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_bgs_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t ugt_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.ugt_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("ugt_feat 0x%02x", gmap_cli->feat.ugt_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_ugt_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = ugt_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t ugt_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_ugt_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_ugt_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = ugt_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_ugt_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t ugg_feat_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->feat.ugg_feat = net_buf_simple_pull_u8(&buf); + LOG_DBG("ugg_feat 0x%02x", gmap_cli->feat.ugg_feat); + + if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) { + err = gmap_discover_ugt_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + discover_complete(gmap_cli); + + return BT_GATT_ITER_STOP; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_ugg_feat(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = ugg_feat_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t ugg_feat_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_ugg_feat(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_ugg_feat(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = ugg_feat_discover_func; + gmap_cli->params.discover.uuid = gmap_ugg_feat_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t role_read_cb(struct bt_conn *conn, uint8_t att_err, + struct bt_gatt_read_params *params, const void *data, uint16_t len) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + struct net_buf_simple buf; + int err = att_err; + + __ASSERT(gmap_cli, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, + data, len); + + if (data == NULL || att_err != BT_ATT_ERR_SUCCESS || len != sizeof(uint8_t)) { + if (att_err == BT_ATT_ERR_SUCCESS) { + att_err = BT_ATT_ERR_INVALID_ATTRIBUTE_LEN; + } + + discover_failed(gmap_cli, err); + + return BT_GATT_ITER_STOP; + } + + net_buf_simple_init_with_data(&buf, (void *)data, len); + + gmap_cli->role = net_buf_simple_pull_u8(&buf); + LOG_DBG("role 0x%02x", gmap_cli->role); + + if ((gmap_cli->role & BT_GMAP_ROLE_UGG) != 0) { + err = gmap_discover_ugg_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_UGT) != 0) { + err = gmap_discover_ugt_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGS) != 0) { + err = gmap_discover_bgs_feat(gmap_cli); + } else if ((gmap_cli->role & BT_GMAP_ROLE_BGR) != 0) { + err = gmap_discover_bgr_feat(gmap_cli); + } else { + LOG_DBG("Remote device does not support any known roles"); + err = -ECANCELED; + } + + if (err) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_read_role(struct bt_gmap_client *gmap_cli, uint16_t handle) +{ + LOG_DBG("conn %p handle 0x%04x", (void *)gmap_cli->conn, handle); + + memset(&gmap_cli->params.read, 0, sizeof(gmap_cli->params.read)); + + gmap_cli->params.read.func = role_read_cb; + gmap_cli->params.read.handle_count = 1u; + gmap_cli->params.read.single.handle = handle; + gmap_cli->params.read.single.offset = 0u; + + return bt_gatt_read(gmap_cli->conn, &gmap_cli->params.read); +} + +static uint8_t role_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_chrc *chrc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + chrc = attr->user_data; + + /* Read features */ + err = gmap_read_role(gmap_cli, chrc->value_handle); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +static int gmap_discover_role(struct bt_gmap_client *gmap_cli) +{ + LOG_DBG("conn %p", (void *)gmap_cli->conn); + + memset(&gmap_cli->params.discover, 0, sizeof(gmap_cli->params.discover)); + + gmap_cli->params.discover.func = role_discover_func; + gmap_cli->params.discover.uuid = gmap_role_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; + gmap_cli->params.discover.start_handle = gmap_cli->svc_start_handle; + gmap_cli->params.discover.end_handle = gmap_cli->svc_end_handle; + + return bt_gatt_discover(gmap_cli->conn, &gmap_cli->params.discover); +} + +static uint8_t gmas_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + struct bt_gmap_client *gmap_cli = client_by_conn(conn); + const struct bt_gatt_service_val *svc; + int err; + + __ASSERT(gmap_cli != NULL, "no instance for conn %p", (void *)conn); + + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); + + if (attr == NULL) { + discover_failed(gmap_cli, -ENOENT); + + return BT_GATT_ITER_STOP; + } + + svc = (struct bt_gatt_service_val *)attr->user_data; + gmap_cli->svc_start_handle = attr->handle; + gmap_cli->svc_end_handle = svc->end_handle; + + err = gmap_discover_role(gmap_cli); + if (err != 0) { + discover_failed(gmap_cli, err); + } + + return BT_GATT_ITER_STOP; +} + +int bt_gmap_discover(struct bt_conn *conn) +{ + struct bt_gmap_client *gmap_cli; + int err; + + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn"); + + return -EINVAL; + } + + gmap_cli = &gmap_insts[bt_conn_index(conn)]; + + if (gmap_cli->busy) { + LOG_DBG("Busy"); + + return -EBUSY; + } + + gmap_reset(gmap_cli); + + gmap_cli->params.discover.func = gmas_discover_func; + gmap_cli->params.discover.uuid = gmas_uuid; + gmap_cli->params.discover.type = BT_GATT_DISCOVER_PRIMARY; + gmap_cli->params.discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + gmap_cli->params.discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + + err = bt_gatt_discover(conn, &gmap_cli->params.discover); + if (err != 0) { + LOG_DBG("Failed to initiate discovery: %d", err); + + return -ENOEXEC; + } + + gmap_cli->conn = bt_conn_ref(conn); + + return 0; +} + +int bt_gmap_cb_register(const struct bt_gmap_cb *cb) +{ + CHECKIF(cb == NULL) { + LOG_DBG("cb is NULL"); + + return -EINVAL; + } + + if (gmap_cb != NULL) { + LOG_DBG("GMAP callbacks already registered"); + + return -EALREADY; + } + + gmap_cb = cb; + + return 0; +} diff --git a/subsys/bluetooth/audio/gmap_server.c b/subsys/bluetooth/audio/gmap_server.c new file mode 100644 index 00000000000..5bc16ee686f --- /dev/null +++ b/subsys/bluetooth/audio/gmap_server.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#include "audio_internal.h" + +LOG_MODULE_REGISTER(bt_gmap_server, CONFIG_BT_GMAP_LOG_LEVEL); + +#define BT_GMAP_ROLE_MASK \ + (BT_GMAP_ROLE_UGG | BT_GMAP_ROLE_UGT | BT_GMAP_ROLE_BGS | BT_GMAP_ROLE_BGR) + +static uint8_t gmap_role; +static struct bt_gmap_feat gmap_features; + +static ssize_t read_gmap_role(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + LOG_DBG("role 0x%02X", gmap_role); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &gmap_role, sizeof(gmap_role)); +} + +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) +static ssize_t read_gmap_ugg_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.ugg_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr ugg_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_UGG_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_ugg_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) +static ssize_t read_gmap_ugt_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.ugt_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr ugt_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_UGT_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_ugt_feat, NULL, NULL), +}; + +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) +static ssize_t read_gmap_bgs_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.bgs_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr bgs_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_BGS_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_bgs_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) +static ssize_t read_gmap_bgr_feat(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const uint8_t feat = (uint8_t)gmap_features.bgr_feat; + + LOG_DBG("feat 0x%02X", feat); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &feat, sizeof(feat)); +} + +static const struct bt_gatt_attr bgr_feat_chrc[] = { + BT_AUDIO_CHRC(BT_UUID_GMAP_BGR_FEAT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_bgr_feat, NULL, NULL), +}; +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ + +/* There are 4 optional characteristics - Use a dummy definition to allocate memory and then add the + * characteristics at will when registering or modifying the role(s) + */ +#define GMAS_DUMMY_CHRC BT_AUDIO_CHRC(0, 0, 0, NULL, NULL, NULL) + +/* Gaming Audio Service attributes */ +static struct bt_gatt_attr svc_attrs[] = { + BT_GATT_PRIMARY_SERVICE(BT_UUID_GMAS), + BT_AUDIO_CHRC(BT_UUID_GMAP_ROLE, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT, + read_gmap_role, NULL, NULL), +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + GMAS_DUMMY_CHRC, +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ +}; +static struct bt_gatt_service gmas; + +static bool valid_gmap_role(enum bt_gmap_role role) +{ + if (role == 0 || (role & BT_GMAP_ROLE_MASK) != role) { + LOG_DBG("Invalid role %d", role); + } + + if ((role & BT_GMAP_ROLE_UGG) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_UGG_SUPPORTED)) { + LOG_DBG("Device does not support the UGG role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_UGT) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_UGT_SUPPORTED)) { + LOG_DBG("Device does not support the UGT role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_BGS) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGS_SUPPORTED)) { + LOG_DBG("Device does not support the BGS role"); + + return false; + } + + if ((role & BT_GMAP_ROLE_BGR) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED)) { + LOG_DBG("Device does not support the BGR role"); + + return false; + } + + return true; +} + +static bool valid_gmap_features(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + /* Guard with BT_GMAP_UGG_SUPPORTED as the Kconfigs may not be available without it*/ +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + if ((role & BT_GMAP_ROLE_UGG) != 0) { + enum bt_gmap_ugg_feat ugg_feat = features.ugg_feat; + + if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTIPLEX) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_MULTIPLEX with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugg_feat & BT_GMAP_UGG_FEAT_96KBPS_SOURCE) != 0 && + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_96KBPS_SOURCE with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugg_feat & BT_GMAP_UGG_FEAT_MULTISINK) != 0 && + (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT < 2 || + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGG_FEAT_MULTISINK with " + "CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT (%d) or " + "CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT (%d) < 2", + CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT, + CONFIG_BT_BAP_UNICAST_CLIENT_GROUP_STREAM_COUNT); + + return false; + } + } +#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + if ((role & BT_GMAP_ROLE_UGT) != 0) { + enum bt_gmap_ugt_feat ugt_feat = features.ugt_feat; + enum bt_gmap_bgr_feat bgr_feat = features.bgr_feat; + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 && + (ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0) { + LOG_DBG("Device shall support either BT_GMAP_UGT_FEAT_SOURCE or " + "BT_GMAP_UGT_FEAT_SINK"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 && + ((ugt_feat & BT_GMAP_UGT_FEAT_80KBPS_SOURCE) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_SOURCE if " + "BT_GMAP_UGT_FEAT_80KBPS_SOURCE or BT_GMAP_UGT_FEAT_MULTISOURCE is " + "supported"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) != 0 && + CONFIG_BT_ASCS_ASE_SRC_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SOURCE with " + "CONFIG_BT_ASCS_ASE_SRC_COUNT == 0"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) != 0 && + (CONFIG_BT_ASCS_ASE_SRC_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISOURCE with " + "CONFIG_BT_ASCS_ASE_SRC_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", + CONFIG_BT_ASCS_ASE_SRC_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) != 0 && CONFIG_BT_ASCS_ASE_SNK_COUNT == 0) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_SINK with " + "CONFIG_BT_ASCS_ASE_SNK_COUNT == 0"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0 && + ((ugt_feat & BT_GMAP_UGT_FEAT_64KBPS_SINK) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) != 0 || + (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) != 0)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_SINK if " + "BT_GMAP_UGT_FEAT_64KBPS_SINK, BT_GMAP_UGT_FEAT_MULTISINK or " + "BT_GMAP_UGT_FEAT_MULTIPLEX is supported"); + + return false; + } + + if ((ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) != 0 && + (CONFIG_BT_ASCS_ASE_SNK_COUNT < 2 || CONFIG_BT_ASCS_MAX_ACTIVE_ASES < 2)) { + LOG_DBG("Cannot support BT_GMAP_UGT_FEAT_MULTISINK with " + "CONFIG_BT_ASCS_ASE_SNK_COUNT (%d) or " + "CONFIG_BT_ASCS_MAX_ACTIVE_ASES (%d) < 2", + CONFIG_BT_ASCS_ASE_SNK_COUNT, CONFIG_BT_ASCS_MAX_ACTIVE_ASES); + + return false; + } + + /* If the device supports both the UGT and BGT roles, then it needs have the same + * support for multiplexing for both roles + */ + if ((role & BT_GMAP_ROLE_BGR) != 0 && !IS_ENABLED(CONFIG_BT_GMAP_BGR_SUPPORTED) && + (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) != + (bgr_feat & BT_GMAP_BGR_FEAT_MULTIPLEX)) { + LOG_DBG("Device shall support BT_GMAP_UGT_FEAT_MULTIPLEX if " + "BT_GMAP_BGR_FEAT_MULTIPLEX is supported, and vice versa"); + } + } +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + if ((role & BT_GMAP_ROLE_BGR) != 0) { + enum bt_gmap_bgr_feat bgr_feat = features.bgr_feat; + + if ((bgr_feat & BT_GMAP_BGR_FEAT_MULTISINK) != 0 && + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT < 2) { + LOG_DBG("Cannot support BT_GMAP_BGR_FEAT_MULTISINK with " + "CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT (%d) < 2", + CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT); + + return false; + } + } +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ + + /* If the roles are not supported, then the feature characteristics are not instantiated and + * the feature values do not need to be checked, as they will never be read (thus ignore by + * the stack) + */ + + return true; +} + +static void update_service(enum bt_gmap_role role) +{ + gmas.attrs = svc_attrs; + gmas.attr_count = 3; /* service + 2 attributes for BT_UUID_GMAP_ROLE */ + + /* Add characteristics based on the role selected and what is supported */ +#if defined(CONFIG_BT_GMAP_UGG_SUPPORTED) + if (role & BT_GMAP_ROLE_UGG) { + memcpy(&gmas.attrs[gmas.attr_count], ugg_feat_chrc, sizeof(ugg_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(ugg_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_UGG_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_UGT_SUPPORTED) + if (role & BT_GMAP_ROLE_UGT) { + memcpy(&gmas.attrs[gmas.attr_count], ugt_feat_chrc, sizeof(ugt_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(ugt_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_UGT_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGS_SUPPORTED) + if (role & BT_GMAP_ROLE_BGS) { + memcpy(&gmas.attrs[gmas.attr_count], bgs_feat_chrc, sizeof(bgs_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(bgs_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_BGS_SUPPORTED */ + +#if defined(CONFIG_BT_GMAP_BGR_SUPPORTED) + if (role & BT_GMAP_ROLE_BGR) { + memcpy(&gmas.attrs[gmas.attr_count], bgr_feat_chrc, sizeof(bgr_feat_chrc)); + gmas.attr_count += ARRAY_SIZE(bgr_feat_chrc); + } +#endif /* CONFIG_BT_GMAP_BGR_SUPPORTED */ +} + +int bt_gmap_register(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + int err; + + CHECKIF(!valid_gmap_role(role)) { + LOG_DBG("Invalid role: %d", role); + + return -EINVAL; + } + + CHECKIF(!valid_gmap_features(role, features)) { + LOG_DBG("Invalid features"); + + return -EINVAL; + } + + update_service(role); + + err = bt_gatt_service_register(&gmas); + if (err) { + LOG_DBG("Could not register the GMAS service"); + + return -ENOEXEC; + } + + gmap_role = role; + gmap_features = features; + + return 0; +} + +int bt_gmap_set_role(enum bt_gmap_role role, struct bt_gmap_feat features) +{ + int err; + + if (gmap_role == 0) { /* not registered if this is 0 */ + LOG_DBG("GMAP not registered"); + + return -ENOEXEC; + } + + CHECKIF(!valid_gmap_role(role)) { + LOG_DBG("Invalid role: %d", role); + + return -EINVAL; + } + + CHECKIF(!valid_gmap_features(role, features)) { + LOG_DBG("Invalid features"); + + return -EINVAL; + } + + if (gmap_role == role) { + LOG_DBG("No role change"); + + if (memcmp(&gmap_features, &features, sizeof(gmap_features)) == 0) { + LOG_DBG("No feature change"); + + return -EALREADY; + } + + gmap_features = features; + + return 0; + } + + /* Re-register the service to trigger a db_changed() if the roles changed */ + err = bt_gatt_service_unregister(&gmas); + if (err != 0) { + LOG_DBG("Failed to unregister service: %d", err); + + return -ENOENT; + } + + err = bt_gmap_register(role, gmap_features); + if (err != 0) { + LOG_DBG("Failed to update GMAS: %d", err); + + return -ECANCELED; + } + + return 0; +} diff --git a/subsys/bluetooth/audio/has.c b/subsys/bluetooth/audio/has.c index fc1aba7aec2..b018e034bb7 100644 --- a/subsys/bluetooth/audio/has.c +++ b/subsys/bluetooth/audio/has.c @@ -15,6 +15,7 @@ #include #include "../bluetooth/host/hci_core.h" +#include "../bluetooth/host/settings.h" #include "audio_internal.h" #include "has_internal.h" @@ -204,6 +205,8 @@ static struct has_client { static struct client_context *context_find(const bt_addr_le_t *addr) { + __ASSERT_NO_MSG(addr != NULL); + for (size_t i = 0; i < ARRAY_SIZE(contexts); i++) { if (bt_addr_le_eq(&contexts[i].addr, addr)) { return &contexts[i]; @@ -217,6 +220,8 @@ static struct client_context *context_alloc(const bt_addr_le_t *addr) { struct client_context *context; + __ASSERT_NO_MSG(addr != NULL); + /* Free contexts has BT_ADDR_LE_ANY as the address */ context = context_find(BT_ADDR_LE_ANY); if (context == NULL) { @@ -261,6 +266,7 @@ static struct has_client *client_alloc(struct bt_conn *conn) { struct bt_conn_info info = { 0 }; struct has_client *client = NULL; + int err; for (size_t i = 0; i < ARRAY_SIZE(has_client_list); i++) { if (conn == has_client_list[i].conn) { @@ -283,7 +289,12 @@ static struct has_client *client_alloc(struct bt_conn *conn) k_work_init_delayable(&client->notify_work, notify_work_handler); #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ - bt_conn_get_info(conn, &info); + err = bt_conn_get_info(conn, &info); + if (err != 0) { + LOG_DBG("Could not get conn info: %d", err); + + return NULL; + } client->context = context_find(info.le.dst); if (client->context == NULL) { @@ -298,8 +309,6 @@ static struct has_client *client_alloc(struct bt_conn *conn) } LOG_DBG("New client_context for %s", bt_addr_le_str(info.le.dst)); - } else { - LOG_DBG("Restored client_context for %s", bt_addr_le_str(info.le.dst)); } return client; @@ -508,26 +517,15 @@ static void bond_deleted_cb(uint8_t id, const bt_addr_le_t *addr) if (context != NULL) { context_free(context); } + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_settings_delete("has", 0, addr); + } } static struct bt_conn_auth_info_cb auth_info_cb = { .bond_deleted = bond_deleted_cb, }; - -static void restore_client_context(const struct bt_bond_info *info, void *user_data) -{ - struct client_context *context; - - context = context_alloc(&info->addr); - if (context == NULL) { - LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&info->addr)); - return; - } - - /* Notify all the characteristics values after reboot */ - atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); -} - #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) @@ -868,10 +866,86 @@ static int bt_has_cp_generic_update(struct has_client *client, uint8_t prev_inde } } +#if defined(CONFIG_BT_SETTINGS) +struct client_context_store { + /* Last notified preset index */ + uint8_t last_preset_index_known; +} __packed; + +static int settings_set_cb(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) +{ + struct client_context_store store; + struct client_context *context; + bt_addr_le_t addr; + ssize_t len; + int err; + + if (!name) { + LOG_ERR("Insufficient number of arguments"); + return -EINVAL; + } + + err = bt_settings_decode_key(name, &addr); + if (err) { + LOG_ERR("Unable to decode address %s", name); + return -EINVAL; + } + + context = context_find(&addr); + if (context == NULL) { + /* Find and initialize a free entry */ + context = context_alloc(&addr); + if (context == NULL) { + LOG_ERR("Failed to allocate client_context for %s", bt_addr_le_str(&addr)); + return -ENOMEM; + } + } + + if (len_rd) { + len = read_cb(cb_arg, &store, sizeof(store)); + if (len < 0) { + LOG_ERR("Failed to decode value (err %zd)", len); + return len; + } + + context->last_preset_index_known = store.last_preset_index_known; + } else { + context->last_preset_index_known = 0x00; + } + + /* Notify all the characteristics values after reboot */ + atomic_set(context->flags, BONDED_CLIENT_INIT_FLAGS); + + return 0; +} + +BT_SETTINGS_DEFINE(has, "has", settings_set_cb, NULL); + +static void store_client_context(struct client_context *context) +{ + struct client_context_store store = { + .last_preset_index_known = context->last_preset_index_known, + }; + int err; + + LOG_DBG("%s last_preset_index_known 0x%02x", + bt_addr_le_str(&context->addr), store.last_preset_index_known); + + err = bt_settings_store("has", 0, &context->addr, &store, sizeof(store)); + if (err != 0) { + LOG_ERR("Failed to store err %d", err); + } +} +#else +#define store_client_context(...) +#endif /* CONFIG_BT_SETTINGS */ + static void update_last_preset_index_known(struct has_client *client, uint8_t index) { - if (client != NULL) { + if (client != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); return; } @@ -879,8 +953,10 @@ static void update_last_preset_index_known(struct has_client *client, uint8_t in client = &has_client_list[i]; /* For each connected client */ - if (client->conn != NULL && client->context != NULL) { + if (client->conn != NULL && client->context != NULL && + client->context->last_preset_index_known != index) { client->context->last_preset_index_known = index; + store_client_context(client->context); } } } @@ -933,6 +1009,8 @@ static int bt_has_cp_preset_record_deleted(struct has_client *client, uint8_t in NET_BUF_SIMPLE_DEFINE(buf, sizeof(struct bt_has_cp_hdr) + sizeof(struct bt_has_cp_preset_changed) + sizeof(uint8_t)); + LOG_DBG("client %p index 0x%02x", client, index); + preset_changed_prepare(&buf, BT_HAS_CHANGE_ID_PRESET_DELETED, BT_HAS_IS_LAST); net_buf_simple_add_u8(&buf, index); @@ -1318,6 +1396,8 @@ static uint8_t handle_control_point_op(struct bt_conn *conn, struct net_buf_simp case BT_HAS_OP_WRITE_PRESET_NAME: if (IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC)) { return handle_write_preset_name(conn, buf); + } else { + return BT_HAS_ERR_WRITE_NAME_NOT_ALLOWED; } break; case BT_HAS_OP_SET_ACTIVE_PRESET: @@ -1423,6 +1503,12 @@ int bt_has_preset_register(const struct bt_has_preset_register_param *param) return -EALREADY; } + CHECKIF(!IS_ENABLED(CONFIG_BT_HAS_PRESET_NAME_DYNAMIC) && + (param->properties & BT_HAS_PROP_WRITABLE) > 0) { + LOG_ERR("Writable presets are not supported"); + return -ENOTSUP; + } + preset = preset_alloc(param->index, param->properties, param->name, param->ops); if (preset == NULL) { return -ENOMEM; @@ -1709,8 +1795,6 @@ int bt_has_register(const struct bt_has_features_param *features) #if defined(CONFIG_BT_HAS_PRESET_SUPPORT) || defined(CONFIG_BT_HAS_FEATURES_NOTIFIABLE) bt_conn_auth_info_cb_register(&auth_info_cb); - - bt_foreach_bond(BT_ID_DEFAULT, restore_client_context, NULL); #endif /* CONFIG_BT_HAS_PRESET_SUPPORT || CONFIG_BT_HAS_FEATURES_NOTIFIABLE */ has.registered = true; diff --git a/subsys/bluetooth/audio/has_client.c b/subsys/bluetooth/audio/has_client.c index 77f40d48bd5..9ac33139a96 100644 --- a/subsys/bluetooth/audio/has_client.c +++ b/subsys/bluetooth/audio/has_client.c @@ -19,48 +19,14 @@ LOG_MODULE_REGISTER(bt_has_client, CONFIG_BT_HAS_CLIENT_LOG_LEVEL); -#define HAS_INST(_has) CONTAINER_OF(_has, struct has_inst, has) +#define HAS_INST(_has) CONTAINER_OF(_has, struct bt_has_client, has) #define HANDLE_IS_VALID(handle) ((handle) != 0x0000) - -enum { - HAS_DISCOVER_IN_PROGRESS, - HAS_CP_OPERATION_IN_PROGRESS, - - HAS_NUM_FLAGS, /* keep as last */ -}; - -static struct has_inst { - /** Common profile reference object */ - struct bt_has has; - - /** Profile connection reference */ - struct bt_conn *conn; - - /** Internal flags */ - ATOMIC_DEFINE(flags, HAS_NUM_FLAGS); - - /* GATT procedure parameters */ - union { - struct { - struct bt_uuid_16 uuid; - union { - struct bt_gatt_read_params read; - struct bt_gatt_discover_params discover; - }; - }; - struct bt_gatt_write_params write; - } params; - - struct bt_gatt_subscribe_params features_subscription; - struct bt_gatt_subscribe_params control_point_subscription; - struct bt_gatt_subscribe_params active_index_subscription; -} has_insts[CONFIG_BT_MAX_CONN]; - +static struct bt_has_client clients[CONFIG_BT_MAX_CONN]; static const struct bt_has_client_cb *client_cb; -static struct has_inst *inst_by_conn(struct bt_conn *conn) +static struct bt_has_client *inst_by_conn(struct bt_conn *conn) { - struct has_inst *inst = &has_insts[bt_conn_index(conn)]; + struct bt_has_client *inst = &clients[bt_conn_index(conn)]; if (inst->conn == conn) { return inst; @@ -69,14 +35,14 @@ static struct has_inst *inst_by_conn(struct bt_conn *conn) return NULL; } -static void inst_cleanup(struct has_inst *inst) +static void inst_cleanup(struct bt_has_client *inst) { bt_conn_unref(inst->conn); (void)memset(inst, 0, sizeof(*inst)); } -static enum bt_has_capabilities get_capabilities(const struct has_inst *inst) +static enum bt_has_capabilities get_capabilities(const struct bt_has_client *inst) { enum bt_has_capabilities caps = 0; @@ -88,7 +54,7 @@ static enum bt_has_capabilities get_capabilities(const struct has_inst *inst) return caps; } -static void handle_read_preset_rsp(struct has_inst *inst, struct net_buf_simple *buf) +static void handle_read_preset_rsp(struct bt_has_client *inst, struct net_buf_simple *buf) { const struct bt_has_cp_read_preset_rsp *pdu; struct bt_has_preset_record record; @@ -124,7 +90,8 @@ static void handle_read_preset_rsp(struct has_inst *inst, struct net_buf_simple client_cb->preset_read_rsp(&inst->has, 0, &record, !!pdu->is_last); } -static void handle_generic_update(struct has_inst *inst, struct net_buf_simple *buf, bool is_last) +static void handle_generic_update(struct bt_has_client *inst, struct net_buf_simple *buf, + bool is_last) { const struct bt_has_cp_generic_update *pdu; struct bt_has_preset_record record; @@ -154,7 +121,8 @@ static void handle_generic_update(struct has_inst *inst, struct net_buf_simple * client_cb->preset_update(&inst->has, pdu->prev_index, &record, is_last); } -static void handle_preset_deleted(struct has_inst *inst, struct net_buf_simple *buf, bool is_last) +static void handle_preset_deleted(struct bt_has_client *inst, struct net_buf_simple *buf, + bool is_last) { if (buf->len < sizeof(uint8_t)) { LOG_ERR("malformed PDU"); @@ -164,7 +132,7 @@ static void handle_preset_deleted(struct has_inst *inst, struct net_buf_simple * client_cb->preset_deleted(&inst->has, net_buf_simple_pull_u8(buf), is_last); } -static void handle_preset_availability(struct has_inst *inst, struct net_buf_simple *buf, +static void handle_preset_availability(struct bt_has_client *inst, struct net_buf_simple *buf, bool available, bool is_last) { if (buf->len < sizeof(uint8_t)) { @@ -176,7 +144,7 @@ static void handle_preset_availability(struct has_inst *inst, struct net_buf_sim is_last); } -static void handle_preset_changed(struct has_inst *inst, struct net_buf_simple *buf) +static void handle_preset_changed(struct bt_has_client *inst, struct net_buf_simple *buf) { const struct bt_has_cp_preset_changed *pdu; @@ -223,9 +191,10 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + control_point_subscription); const struct bt_has_cp_hdr *hdr; struct net_buf_simple buf; - struct has_inst *inst; LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -239,12 +208,6 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len < sizeof(*hdr)) { /* Ignore malformed notification */ return BT_GATT_ITER_CONTINUE; } @@ -265,11 +228,11 @@ static uint8_t control_point_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void discover_complete(struct has_inst *inst) +static void discover_complete(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); - atomic_clear_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS); client_cb->discover(inst->conn, 0, &inst->has, inst->has.features & BT_HAS_FEAT_HEARING_AID_TYPE_MASK, @@ -289,7 +252,8 @@ static void discover_failed(struct bt_conn *conn, int err) client_cb->discover(conn, err, NULL, 0, 0); } -static int cp_write(struct has_inst *inst, struct net_buf_simple *buf, bt_gatt_write_func_t func) +static int cp_write(struct bt_has_client *inst, struct net_buf_simple *buf, + bt_gatt_write_func_t func) { const uint16_t value_handle = inst->control_point_subscription.value_handle; @@ -309,20 +273,18 @@ static int cp_write(struct has_inst *inst, struct net_buf_simple *buf, bt_gatt_w static void read_presets_req_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); if (err) { client_cb->preset_read_rsp(&inst->has, err, NULL, true); } } -static int read_presets_req(struct has_inst *inst, uint8_t start_index, uint8_t num_presets) +static int read_presets_req(struct bt_has_client *inst, uint8_t start_index, uint8_t num_presets) { struct bt_has_cp_hdr *hdr; struct bt_has_cp_read_presets_req *req; @@ -344,20 +306,18 @@ static int read_presets_req(struct has_inst *inst, uint8_t start_index, uint8_t static void set_active_preset_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.write); LOG_DBG("conn %p err 0x%02x param %p", (void *)conn, err, params); - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); if (err) { client_cb->preset_switch(&inst->has, err, inst->has.active_index); } } -static int preset_set(struct has_inst *inst, uint8_t opcode, uint8_t index) +static int preset_set(struct bt_has_client *inst, uint8_t opcode, uint8_t index) { struct bt_has_cp_hdr *hdr; struct bt_has_cp_set_active_preset *req; @@ -374,7 +334,7 @@ static int preset_set(struct has_inst *inst, uint8_t opcode, uint8_t index) return cp_write(inst, &buf, set_active_preset_cb); } -static int preset_set_next_or_prev(struct has_inst *inst, uint8_t opcode) +static int preset_set_next_or_prev(struct bt_has_client *inst, uint8_t opcode) { struct bt_has_cp_hdr *hdr; @@ -388,7 +348,7 @@ static int preset_set_next_or_prev(struct has_inst *inst, uint8_t opcode) return cp_write(inst, &buf, set_active_preset_cb); } -static uint8_t active_index_update(struct has_inst *inst, const void *data, uint16_t len) +static uint8_t active_index_update(struct bt_has_client *inst, const void *data, uint16_t len) { struct net_buf_simple buf; const uint8_t prev = inst->has.active_index; @@ -406,7 +366,8 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst; + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + active_index_subscription); uint8_t prev; LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -423,12 +384,6 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len == 0) { /* Ignore empty notification */ return BT_GATT_ITER_CONTINUE; @@ -436,7 +391,7 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, prev = active_index_update(inst, data, len); - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { /* Got notification during discovery process, postpone the active_index callback * until discovery is complete. */ @@ -453,9 +408,8 @@ static uint8_t active_preset_notify_cb(struct bt_conn *conn, static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); - - __ASSERT(inst, "no instance for conn %p", (void *)conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + active_index_subscription); LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params); @@ -469,8 +423,10 @@ static void active_index_subscribe_cb(struct bt_conn *conn, uint8_t att_err, } } -static int active_index_subscribe(struct has_inst *inst, uint16_t value_handle) +static int active_index_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->active_index_subscription.notify = active_preset_notify_cb; @@ -482,18 +438,21 @@ static int active_index_subscribe(struct has_inst *inst, uint16_t value_handle) inst->active_index_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->active_index_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->active_index_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, data, len); @@ -520,7 +479,7 @@ static uint8_t active_index_read_cb(struct bt_conn *conn, uint8_t att_err, return BT_GATT_ITER_STOP; } -static int active_index_read(struct has_inst *inst) +static int active_index_read(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -538,13 +497,12 @@ static int active_index_read(struct has_inst *inst) } static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, - struct bt_gatt_subscribe_params *subscribe) + struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + control_point_subscription); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x", (void *)inst->conn, att_err); if (att_err != BT_ATT_ERR_SUCCESS) { @@ -566,9 +524,11 @@ static void control_point_subscribe_cb(struct bt_conn *conn, uint8_t att_err, discover_failed(conn, err); } -static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, +static int control_point_subscribe(struct bt_has_client *inst, uint16_t value_handle, uint8_t properties) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->control_point_subscription.notify = control_point_notify_cb; @@ -585,19 +545,22 @@ static int control_point_subscribe(struct has_inst *inst, uint16_t value_handle, inst->control_point_subscription.value = BT_GATT_CCC_INDICATE; } - return bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->control_point_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover); const struct bt_gatt_chrc *chrc; int err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - - LOG_DBG("conn %p attr %p params %p", (void *)inst->conn, attr, params); + LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); if (!attr) { LOG_INF("Control Point not found"); @@ -620,7 +583,7 @@ static uint8_t control_point_discover_cb(struct bt_conn *conn, const struct bt_g return BT_GATT_ITER_STOP; } -static int control_point_discover(struct has_inst *inst) +static int control_point_discover(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -637,7 +600,7 @@ static int control_point_discover(struct has_inst *inst) return bt_gatt_discover(inst->conn, &inst->params.discover); } -static void features_update(struct has_inst *inst, const void *data, uint16_t len) +static void features_update(struct bt_has_client *inst, const void *data, uint16_t len) { struct net_buf_simple buf; @@ -651,11 +614,9 @@ static void features_update(struct has_inst *inst, const void *data, uint16_t le static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_read_params *params, const void *data, uint16_t len) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.read); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p att_err 0x%02x params %p data %p len %u", (void *)conn, att_err, params, data, len); @@ -688,7 +649,7 @@ static uint8_t features_read_cb(struct bt_conn *conn, uint8_t att_err, return BT_GATT_ITER_STOP; } -static int features_read(struct has_inst *inst, uint16_t value_handle) +static int features_read(struct bt_has_client *inst, uint16_t value_handle) { LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); @@ -705,12 +666,11 @@ static int features_read(struct has_inst *inst, uint16_t value_handle) static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_subscribe_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + features_subscription); int err = att_err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - - LOG_DBG("conn %p att_err 0x%02x params %p", (void *)inst->conn, att_err, params); + LOG_DBG("conn %p att_err 0x%02x params %p", (void *)conn, att_err, params); if (att_err != BT_ATT_ERR_SUCCESS) { goto fail; @@ -734,7 +694,8 @@ static void features_subscribe_cb(struct bt_conn *conn, uint8_t att_err, static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t len) { - struct has_inst *inst; + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, + features_subscription); LOG_DBG("conn %p params %p data %p len %u", (void *)conn, params, data, len); @@ -750,12 +711,6 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe return BT_GATT_ITER_STOP; } - inst = inst_by_conn(conn); - if (!inst) { - /* Ignore notification from unknown instance */ - return BT_GATT_ITER_STOP; - } - if (len == 0) { /* Ignore empty notification */ return BT_GATT_ITER_CONTINUE; @@ -766,8 +721,10 @@ static uint8_t features_notify_cb(struct bt_conn *conn, struct bt_gatt_subscribe return BT_GATT_ITER_CONTINUE; } -static int features_subscribe(struct has_inst *inst, uint16_t value_handle) +static int features_subscribe(struct bt_has_client *inst, uint16_t value_handle) { + int err; + LOG_DBG("conn %p handle 0x%04x", (void *)inst->conn, value_handle); inst->features_subscription.notify = features_notify_cb; @@ -779,18 +736,21 @@ static int features_subscribe(struct has_inst *inst, uint16_t value_handle) inst->features_subscription.value = BT_GATT_CCC_NOTIFY; atomic_set_bit(inst->features_subscription.flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - return bt_gatt_subscribe(inst->conn, &inst->features_subscription); + err = bt_gatt_subscribe(inst->conn, &inst->features_subscription); + if (err != 0 && err != -EALREADY) { + return err; + } + + return 0; } static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = CONTAINER_OF(params, struct bt_has_client, params.discover); const struct bt_gatt_chrc *chrc; int err; - __ASSERT(inst, "no instance for conn %p", (void *)conn); - LOG_DBG("conn %p attr %p params %p", (void *)conn, attr, params); if (!attr) { @@ -826,7 +786,7 @@ static uint8_t features_discover_cb(struct bt_conn *conn, const struct bt_gatt_a return BT_GATT_ITER_STOP; } -static int features_discover(struct has_inst *inst) +static int features_discover(struct bt_has_client *inst) { LOG_DBG("conn %p", (void *)inst->conn); @@ -868,7 +828,7 @@ int bt_has_client_cb_register(const struct bt_has_client_cb *cb) */ int bt_has_client_discover(struct bt_conn *conn) { - struct has_inst *inst; + struct bt_has_client *inst; int err; LOG_DBG("conn %p", (void *)conn); @@ -877,10 +837,10 @@ int bt_has_client_discover(struct bt_conn *conn) return -EINVAL; } - inst = &has_insts[bt_conn_index(conn)]; + inst = &clients[bt_conn_index(conn)]; - if (atomic_test_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { return -EBUSY; } @@ -892,7 +852,7 @@ int bt_has_client_discover(struct bt_conn *conn) err = features_discover(inst); if (err) { - atomic_clear_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS); } return err; @@ -900,7 +860,7 @@ int bt_has_client_discover(struct bt_conn *conn) int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); *conn = bt_conn_ref(inst->conn); @@ -909,7 +869,7 @@ int bt_has_client_conn_get(const struct bt_has *has, struct bt_conn **conn) int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t count) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); int err; LOG_DBG("conn %p start_index 0x%02x count %d", (void *)inst->conn, start_index, count); @@ -918,8 +878,8 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t return -ENOTCONN; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -933,7 +893,7 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t err = read_presets_req(inst, start_index, count); if (err) { - atomic_clear_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS); + atomic_clear_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS); } return err; @@ -941,7 +901,7 @@ int bt_has_client_presets_read(struct bt_has *has, uint8_t start_index, uint8_t int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p index 0x%02x", (void *)inst->conn, index); @@ -958,8 +918,8 @@ int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -970,7 +930,7 @@ int bt_has_client_preset_set(struct bt_has *has, uint8_t index, bool sync) int bt_has_client_preset_next(struct bt_has *has, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p sync %d", (void *)inst->conn, sync); @@ -983,8 +943,8 @@ int bt_has_client_preset_next(struct bt_has *has, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -995,7 +955,7 @@ int bt_has_client_preset_next(struct bt_has *has, bool sync) int bt_has_client_preset_prev(struct bt_has *has, bool sync) { - struct has_inst *inst = HAS_INST(has); + struct bt_has_client *inst = HAS_INST(has); uint8_t opcode; LOG_DBG("conn %p sync %d", (void *)inst->conn, sync); @@ -1008,8 +968,8 @@ int bt_has_client_preset_prev(struct bt_has *has, bool sync) return -EOPNOTSUPP; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS) || - atomic_test_and_set_bit(inst->flags, HAS_CP_OPERATION_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS) || + atomic_test_and_set_bit(inst->flags, HAS_CLIENT_CP_OPERATION_IN_PROGRESS)) { return -EBUSY; } @@ -1020,13 +980,13 @@ int bt_has_client_preset_prev(struct bt_has *has, bool sync) static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct has_inst *inst = inst_by_conn(conn); + struct bt_has_client *inst = inst_by_conn(conn); if (!inst) { return; } - if (atomic_test_bit(inst->flags, HAS_DISCOVER_IN_PROGRESS)) { + if (atomic_test_bit(inst->flags, HAS_CLIENT_DISCOVER_IN_PROGRESS)) { discover_failed(conn, -ECONNABORTED); } diff --git a/subsys/bluetooth/audio/has_internal.h b/subsys/bluetooth/audio/has_internal.h index c4152eaea1c..5c5dc6b9410 100644 --- a/subsys/bluetooth/audio/has_internal.h +++ b/subsys/bluetooth/audio/has_internal.h @@ -8,6 +8,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include +#include + /* Control Point opcodes */ #define BT_HAS_OP_READ_PRESET_REQ 0x01 #define BT_HAS_OP_READ_PRESET_RSP 0x02 @@ -139,3 +142,37 @@ static inline const char *bt_has_change_id_str(uint8_t change_id) return "Unknown changeId"; } } + +enum has_client_flags { + HAS_CLIENT_DISCOVER_IN_PROGRESS, + HAS_CLIENT_CP_OPERATION_IN_PROGRESS, + + HAS_CLIENT_NUM_FLAGS, /* keep as last */ +}; + +struct bt_has_client { + /** Common profile reference object */ + struct bt_has has; + + /** Profile connection reference */ + struct bt_conn *conn; + + /** Internal flags */ + ATOMIC_DEFINE(flags, HAS_CLIENT_NUM_FLAGS); + + /* GATT procedure parameters */ + union { + struct { + struct bt_uuid_16 uuid; + union { + struct bt_gatt_read_params read; + struct bt_gatt_discover_params discover; + }; + }; + struct bt_gatt_write_params write; + } params; + + struct bt_gatt_subscribe_params features_subscription; + struct bt_gatt_subscribe_params control_point_subscription; + struct bt_gatt_subscribe_params active_index_subscription; +}; diff --git a/subsys/bluetooth/audio/mcc.c b/subsys/bluetooth/audio/mcc.c index 65972e87125..e192c0352db 100644 --- a/subsys/bluetooth/audio/mcc.c +++ b/subsys/bluetooth/audio/mcc.c @@ -19,6 +19,7 @@ #include #include #include +#include "mcc_internal.h" #include #include "../services/ots/ots_client_internal.h" @@ -44,97 +45,6 @@ LOG_MODULE_REGISTER(bt_mcc, CONFIG_BT_MCC_LOG_LEVEL); #include "common/bt_str.h" -struct mcs_instance_t { - uint16_t start_handle; - uint16_t end_handle; - uint16_t player_name_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t icon_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t icon_url_handle; - uint16_t track_changed_handle; - uint16_t track_title_handle; - uint16_t track_duration_handle; - uint16_t track_position_handle; - uint16_t playback_speed_handle; - uint16_t seeking_speed_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t segments_obj_id_handle; - uint16_t current_track_obj_id_handle; - uint16_t next_track_obj_id_handle; - uint16_t current_group_obj_id_handle; - uint16_t parent_group_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t playing_order_handle; - uint16_t playing_orders_supported_handle; - uint16_t media_state_handle; - uint16_t cp_handle; - uint16_t opcodes_supported_handle; -#ifdef CONFIG_BT_MCC_OTS - uint16_t scp_handle; - uint16_t search_results_obj_id_handle; -#endif /* CONFIG_BT_MCC_OTS */ - uint16_t content_control_id_handle; - - - /* The write buffer is used for - * - track position (4 octets) - * - playback speed (1 octet) - * - playing order (1 octet) - * - the control point (5 octets) - * (1 octet opcode + optionally 4 octet param) - * (mpl_cmd.opcode + mpl_cmd.param) - * If the object transfer client is included, it is also used for - * - object IDs (6 octets - BT_OTS_OBJ_ID_SIZE) and - * - the search control point (64 octets - SEARCH_LEN_MAX) - * - * If there is no OTC, the largest is control point - * If OTC is included, the largest is the search control point - */ -#ifdef CONFIG_BT_MCC_OTS - char write_buf[SEARCH_LEN_MAX]; -#else - /* Trick to be able to use sizeof on members of a struct type */ - /* TODO: Rewrite the mpl_cmd to have the "use_param" parameter */ - /* separately, and the opcode and param alone as a struct */ - char write_buf[sizeof(((struct mpl_cmd *)0)->opcode) + - sizeof(((struct mpl_cmd *)0)->param)]; -#endif /* CONFIG_BT_MCC_OTS */ - - struct bt_gatt_discover_params discover_params; - struct bt_gatt_read_params read_params; - struct bt_gatt_write_params write_params; - -/** Any fields below here cannot be memset as part of a reset */ - bool busy; - - struct bt_gatt_subscribe_params player_name_sub_params; - struct bt_gatt_subscribe_params track_changed_sub_params; - struct bt_gatt_subscribe_params track_title_sub_params; - struct bt_gatt_subscribe_params track_duration_sub_params; - struct bt_gatt_subscribe_params track_position_sub_params; - struct bt_gatt_subscribe_params playback_speed_sub_params; - struct bt_gatt_subscribe_params seeking_speed_sub_params; -#ifdef CONFIG_BT_MCC_OTS - struct bt_gatt_subscribe_params current_track_obj_sub_params; - struct bt_gatt_subscribe_params next_track_obj_sub_params; - struct bt_gatt_subscribe_params parent_group_obj_sub_params; - struct bt_gatt_subscribe_params current_group_obj_sub_params; -#endif /* CONFIG_BT_MCC_OTS */ - struct bt_gatt_subscribe_params playing_order_sub_params; - struct bt_gatt_subscribe_params media_state_sub_params; - struct bt_gatt_subscribe_params cp_sub_params; - struct bt_gatt_subscribe_params opcodes_supported_sub_params; -#ifdef CONFIG_BT_MCC_OTS - struct bt_gatt_subscribe_params scp_sub_params; - struct bt_gatt_subscribe_params search_results_obj_sub_params; -#endif /* CONFIG_BT_MCC_OTS */ - -#ifdef CONFIG_BT_MCC_OTS - struct bt_ots_client otc; -#endif /* CONFIG_BT_MCC_OTS */ -}; - static struct mcs_instance_t mcs_instance; static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0); @@ -161,7 +71,7 @@ int on_icon_content(struct bt_ots_client *otc_inst, uint32_t len, uint8_t *data_p, bool is_complete); #endif /* CONFIG_BT_MCC_OTS */ -static struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn) +struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn) { if (conn == NULL) { return NULL; @@ -246,6 +156,7 @@ static uint8_t mcc_read_icon_obj_id_cb(struct bt_conn *conn, uint8_t err, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static uint8_t mcc_read_icon_url_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -275,7 +186,9 @@ static uint8_t mcc_read_icon_url_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static void mcc_track_title_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; @@ -312,7 +225,9 @@ static uint8_t mcc_read_track_title_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE)*/ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static void mcc_track_duration_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -346,7 +261,9 @@ static uint8_t mcc_read_track_duration_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static void mcc_track_position_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -380,7 +297,9 @@ static uint8_t mcc_read_track_position_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static void mcs_write_track_position_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -404,7 +323,9 @@ static void mcs_write_track_position_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_track_position(conn, cb_err, pos); } } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static void mcc_playback_speed_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -438,7 +359,9 @@ static uint8_t mcc_read_playback_speed_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static void mcs_write_playback_speed_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -461,7 +384,9 @@ static void mcs_write_playback_speed_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_playback_speed(conn, cb_err, speed); } } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static void mcc_seeking_speed_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -495,6 +420,7 @@ static uint8_t mcc_read_seeking_speed_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS static uint8_t mcc_read_segments_obj_id_cb(struct bt_conn *conn, uint8_t err, @@ -769,6 +695,7 @@ static void mcs_write_current_group_obj_id_cb(struct bt_conn *conn, uint8_t err, } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static void mcc_playing_order_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -802,7 +729,9 @@ static uint8_t mcc_read_playing_order_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static void mcs_write_playing_order_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -825,7 +754,9 @@ static void mcs_write_playing_order_cb(struct bt_conn *conn, uint8_t err, mcc_cb->set_playing_order(conn, cb_err, order); } } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static uint8_t mcc_read_playing_orders_supported_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -852,7 +783,9 @@ static uint8_t mcc_read_playing_orders_supported_cb(struct bt_conn *conn, uint8_ return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static void mcc_media_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { int cb_err = err; @@ -885,7 +818,9 @@ static uint8_t mcc_read_media_state_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static void mcs_write_cp_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { @@ -919,7 +854,9 @@ static void mcs_write_cp_cb(struct bt_conn *conn, uint8_t err, mcc_cb->send_cmd(conn, cb_err, &cmd); } } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static void mcc_opcodes_supported_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { @@ -954,6 +891,7 @@ static uint8_t mcc_read_opcodes_supported_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS static void mcs_write_scp_cb(struct bt_conn *conn, uint8_t err, @@ -1025,6 +963,7 @@ static uint8_t mcc_read_search_results_obj_id_cb(struct bt_conn *conn, uint8_t e } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static uint8_t mcc_read_content_control_id_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) @@ -1052,6 +991,7 @@ static uint8_t mcc_read_content_control_id_cb(struct bt_conn *conn, uint8_t err, return BT_GATT_ITER_STOP; } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ static uint8_t mcs_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, @@ -1097,25 +1037,35 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_cb->track_changed_ntf(conn, cb_err); } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) } else if (handle == mcs_inst->track_title_handle) { LOG_DBG("Track Title notification"); mcc_track_title_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (handle == mcs_inst->track_duration_handle) { LOG_DBG("Track Duration notification"); mcc_track_duration_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) } else if (handle == mcs_inst->track_position_handle) { LOG_DBG("Track Position notification"); mcc_track_position_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) } else if (handle == mcs_inst->playback_speed_handle) { LOG_DBG("Playback Speed notification"); mcc_playback_speed_cb(conn, 0, data, length); +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (handle == mcs_inst->seeking_speed_handle) { LOG_DBG("Seeking Speed notification"); mcc_seeking_speed_cb(conn, 0, data, length); +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (handle == mcs_inst->current_track_obj_id_handle) { @@ -1135,13 +1085,17 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_current_group_obj_id_cb(conn, 0, data, length); #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) } else if (handle == mcs_inst->playing_order_handle) { LOG_DBG("Playing Order notification"); mcc_playing_order_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (handle == mcs_inst->media_state_handle) { LOG_DBG("Media State notification"); mcc_media_state_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (handle == mcs_inst->cp_handle) { /* The control point is is a special case - only */ @@ -1165,9 +1119,11 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, mcc_cb->cmd_ntf(conn, cb_err, &ntf); } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (handle == mcs_inst->opcodes_supported_handle) { LOG_DBG("Opcodes Supported notification"); mcc_opcodes_supported_cb(conn, 0, data, length); +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (handle == mcs_inst->scp_handle) { @@ -1200,61 +1156,215 @@ static uint8_t mcs_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } -static void reset_mcs_inst(struct mcs_instance_t *mcs_inst, struct bt_conn *conn) +static int reset_mcs_inst(struct mcs_instance_t *mcs_inst) { - (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); + if (mcs_inst->conn != NULL) { + struct bt_conn *conn = mcs_inst->conn; + struct bt_conn_info info; + int err; + + err = bt_conn_get_info(conn, &info); + if (err != 0) { + return err; + } + + if (info.state == BT_CONN_STATE_CONNECTED) { + /* It's okay if these fail with -EINVAL as that means that they are + * not currently subscribed + */ + err = bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to name: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track change: %d", err); + + return err; + } + +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track title: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ + +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track duration: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ + +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) + err = bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to track position: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ + +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) + err = bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playback speed: %d", err); + + return err; + } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ + +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) + err = bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to seeking speed: %d", err); + + return err; + } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ - /* It's okay if these fail. In case of disconnect, we can't - * unsubscribe and they will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->player_name_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_changed_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_title_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_duration_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->track_position_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playback_speed_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->seeking_speed_sub_params); #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->next_track_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to next track object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->parent_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to parent group object: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->current_group_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to current group object: %d", err); + + return err; + } + #endif /* CONFIG_BT_MCC_OTS */ - (void)bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) + err = bt_gatt_unsubscribe(conn, &mcs_inst->playing_order_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to playing order: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ + +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) + err = bt_gatt_unsubscribe(conn, &mcs_inst->media_state_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to media state: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ + + err = bt_gatt_unsubscribe(conn, &mcs_inst->cp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to control point: %d", err); + + return err; + } + +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) + err = bt_gatt_unsubscribe(conn, &mcs_inst->opcodes_supported_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to supported opcodes: %d", err); + + return err; + } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ + #ifdef CONFIG_BT_MCC_OTS - (void)bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + err = bt_gatt_unsubscribe(conn, &mcs_inst->scp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search control point: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->search_results_obj_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to search results: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to oacp: %d", err); + + return err; + } + + err = bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); + if (err != 0 && err != -EINVAL) { + LOG_DBG("Failed to unsubscribe to olcp: %d", err); + + return err; + } #endif /* CONFIG_BT_MCC_OTS */ + } - /* Reset OTC instance as well if supported */ + bt_conn_unref(conn); + mcs_inst->conn = NULL; + } + + (void)memset(mcs_inst, 0, offsetof(struct mcs_instance_t, busy)); #ifdef CONFIG_BT_MCC_OTS - (void)memset(&mcs_inst->otc, 0, - offsetof(struct bt_ots_client, oacp_sub_params)); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.oacp_sub_params); - (void)bt_gatt_unsubscribe(conn, &mcs_inst->otc.olcp_sub_params); + /* Reset OTC instance as well if supported */ + (void)memset(&mcs_inst->otc, 0, offsetof(struct bt_ots_client, oacp_sub_params)); #endif /* CONFIG_BT_MCC_OTS */ + + return 0; } +static void disconnected_cb(struct bt_conn *conn, uint8_t reason) +{ + struct mcs_instance_t *mcs_inst; + + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + (void)reset_mcs_inst(mcs_inst); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = disconnected_cb, +}; + /* Called when discovery is completed - successfully or with error */ static void discovery_complete(struct bt_conn *conn, int err) { - LOG_DBG("Discovery completed, err: %d", err); + struct mcs_instance_t *mcs_inst; - /* TODO: Handle resets of instance, and re-discovery. - * For now, reset instance on error. - */ - if (err) { - struct mcs_instance_t *mcs_inst; + LOG_DBG("Discovery completed, err: %d", err); - mcs_inst = lookup_inst_by_conn(conn); - if (mcs_inst != NULL) { - reset_mcs_inst(mcs_inst, conn); + mcs_inst = lookup_inst_by_conn(conn); + if (mcs_inst != NULL) { + mcs_inst->busy = false; + if (err != 0) { + (void)reset_mcs_inst(mcs_inst); } } @@ -1324,8 +1434,15 @@ static uint8_t discover_otc_char_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_INDICATE; sub_params->value_handle = chrc->value_handle; sub_params->notify = bt_ots_client_indicate_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); - bt_gatt_subscribe(conn, sub_params); + err = bt_gatt_subscribe(conn, sub_params); + if (err != 0) { + LOG_DBG("Failed to subscribe (err %d)", err); + discovery_complete(conn, err); + + return BT_GATT_ITER_STOP; + } } return BT_GATT_ITER_CONTINUE; @@ -1485,7 +1602,7 @@ static int do_subscribe(struct mcs_instance_t *mcs_inst, struct bt_conn *conn, sub_params->subscribe = subscribe_mcs_char_func; /* disc_params pointer is also used as subscription flag */ sub_params->disc_params = &mcs_inst->discover_params; - atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_NO_RESUB); + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); LOG_DBG("Subscring to handle %d", handle); return bt_gatt_subscribe(conn, sub_params); @@ -1518,31 +1635,41 @@ static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst, mcs_inst->track_changed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_changed_sub_params; handle = mcs_inst->track_changed_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) } else if (mcs_inst->track_title_handle && mcs_inst->track_title_sub_params.value && mcs_inst->track_title_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_title_sub_params; handle = mcs_inst->track_title_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (mcs_inst->track_duration_handle && mcs_inst->track_duration_sub_params.value && mcs_inst->track_duration_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_duration_sub_params; handle = mcs_inst->track_duration_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) } else if (mcs_inst->track_position_handle && mcs_inst->track_position_sub_params.value && mcs_inst->track_position_sub_params.disc_params == NULL) { sub_params = &mcs_inst->track_position_sub_params; handle = mcs_inst->track_position_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) } else if (mcs_inst->playback_speed_handle && mcs_inst->playback_speed_sub_params.value && mcs_inst->playback_speed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->playback_speed_sub_params; handle = mcs_inst->playback_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (mcs_inst->seeking_speed_handle && mcs_inst->seeking_speed_sub_params.value && mcs_inst->seeking_speed_sub_params.disc_params == NULL) { sub_params = &mcs_inst->seeking_speed_sub_params; handle = mcs_inst->seeking_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (mcs_inst->current_track_obj_id_handle && mcs_inst->current_track_obj_sub_params.value && @@ -1565,26 +1692,32 @@ static bool subscribe_next_mcs_char(struct mcs_instance_t *mcs_inst, sub_params = &mcs_inst->current_group_obj_sub_params; handle = mcs_inst->current_group_obj_id_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) } else if (mcs_inst->playing_order_handle && mcs_inst->playing_order_sub_params.value && mcs_inst->playing_order_sub_params.disc_params == NULL) { sub_params = &mcs_inst->playing_order_sub_params; handle = mcs_inst->playing_order_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (mcs_inst->media_state_handle && mcs_inst->media_state_sub_params.value && mcs_inst->media_state_sub_params.disc_params == NULL) { sub_params = &mcs_inst->media_state_sub_params; handle = mcs_inst->media_state_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (mcs_inst->cp_handle && mcs_inst->cp_sub_params.value && mcs_inst->cp_sub_params.disc_params == NULL) { sub_params = &mcs_inst->cp_sub_params; handle = mcs_inst->cp_handle; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (mcs_inst->opcodes_supported_handle && mcs_inst->opcodes_supported_sub_params.value && mcs_inst->opcodes_supported_sub_params.disc_params == NULL) { sub_params = &mcs_inst->opcodes_supported_sub_params; handle = mcs_inst->opcodes_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (mcs_inst->scp_handle && mcs_inst->scp_sub_params.value && @@ -1657,9 +1790,11 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, LOG_DBG("Icon Object, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->icon_obj_id_handle = chrc->value_handle; #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_ICON_URL)) { LOG_DBG("Icon URL, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->icon_url_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_CHANGED)) { LOG_DBG("Track Changed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_changed_handle = chrc->value_handle; @@ -1667,13 +1802,18 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_changed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_TITLE)) { LOG_DBG("Track Title, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_title_handle = chrc->value_handle; +#if defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) mcs_inst->track_title_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_title_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_DURATION)) { LOG_DBG("Track Duration, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_duration_handle = chrc->value_handle; @@ -1681,20 +1821,32 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_duration_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_POSITION)) { LOG_DBG("Track Position, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->track_position_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) mcs_inst->track_position_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->track_position_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYBACK_SPEED)) { LOG_DBG("Playback Speed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playback_speed_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) mcs_inst->playback_speed_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->playback_speed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || + * defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) + */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEEKING_SPEED)) { LOG_DBG("Seeking Speed, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->seeking_speed_handle = chrc->value_handle; @@ -1702,6 +1854,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->seeking_speed_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_TRACK_SEGMENTS_OBJ_ID)) { LOG_DBG("Track Segments Object, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1738,16 +1891,23 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, BT_GATT_CCC_NOTIFY; } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDER)) { LOG_DBG("Playing Order, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playing_order_handle = chrc->value_handle; +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) mcs_inst->playing_order_sub_params.disc_params = NULL; if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->playing_order_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_PLAYING_ORDERS)) { LOG_DBG("Playing Orders supported, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->playing_orders_supported_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_STATE)) { LOG_DBG("Media State, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->media_state_handle = chrc->value_handle; @@ -1755,6 +1915,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->media_state_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_POINT)) { LOG_DBG("Media Control Point, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->cp_handle = chrc->value_handle; @@ -1762,6 +1923,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, if (chrc->properties & BT_GATT_CHRC_NOTIFY) { mcs_inst->cp_sub_params.value = BT_GATT_CCC_NOTIFY; } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_MEDIA_CONTROL_OPCODES)) { LOG_DBG("Media control opcodes supported, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1771,6 +1933,7 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, mcs_inst->opcodes_supported_sub_params.value = BT_GATT_CCC_NOTIFY; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_MCS_SEARCH_CONTROL_POINT)) { LOG_DBG("Search control point, UUID: %s", bt_uuid_str(chrc->uuid)); @@ -1788,9 +1951,11 @@ static uint8_t discover_mcs_char_func(struct bt_conn *conn, BT_GATT_CCC_NOTIFY; } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) } else if (!bt_uuid_cmp(chrc->uuid, BT_UUID_CCID)) { LOG_DBG("Content Control ID, UUID: %s", bt_uuid_str(chrc->uuid)); mcs_inst->content_control_id_handle = chrc->value_handle; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ } @@ -1919,6 +2084,7 @@ int bt_mcc_init(struct bt_mcc_cb *cb) int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) { struct mcs_instance_t *mcs_inst; + int err; CHECKIF(!conn) { return -EINVAL; @@ -1935,7 +2101,12 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) } subscribe_all = subscribe; - reset_mcs_inst(mcs_inst, conn); + err = reset_mcs_inst(mcs_inst); + if (err != 0) { + LOG_DBG("Failed to reset MCS instance %p: %d", mcs_inst, err); + + return err; + } (void)memcpy(&uuid, BT_UUID_GMCS, sizeof(uuid)); mcs_inst->discover_params.func = discover_primary_func; @@ -1945,7 +2116,15 @@ int bt_mcc_discover_mcs(struct bt_conn *conn, bool subscribe) mcs_inst->discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; LOG_DBG("start discovery of GMCS primary service"); - return bt_gatt_discover(conn, &mcs_inst->discover_params); + err = bt_gatt_discover(conn, &mcs_inst->discover_params); + if (err != 0) { + return err; + } + + mcs_inst->conn = bt_conn_ref(conn); + mcs_inst->busy = true; + + return 0; } int bt_mcc_read_player_name(struct bt_conn *conn) @@ -2027,6 +2206,7 @@ int bt_mcc_read_icon_obj_id(struct bt_conn *conn) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) int bt_mcc_read_icon_url(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2064,7 +2244,9 @@ int bt_mcc_read_icon_url(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) int bt_mcc_read_track_title(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2102,7 +2284,9 @@ int bt_mcc_read_track_title(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) int bt_mcc_read_track_duration(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2140,7 +2324,9 @@ int bt_mcc_read_track_duration(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) int bt_mcc_read_track_position(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2178,7 +2364,9 @@ int bt_mcc_read_track_position(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos) { struct mcs_instance_t *mcs_inst; @@ -2221,7 +2409,9 @@ int bt_mcc_set_track_position(struct bt_conn *conn, int32_t pos) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) int bt_mcc_read_playback_speed(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2259,7 +2449,9 @@ int bt_mcc_read_playback_speed(struct bt_conn *conn) } return err; } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed) { struct mcs_instance_t *mcs_inst; @@ -2302,7 +2494,9 @@ int bt_mcc_set_playback_speed(struct bt_conn *conn, int8_t speed) } return err; } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) int bt_mcc_read_seeking_speed(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2340,6 +2534,7 @@ int bt_mcc_read_seeking_speed(struct bt_conn *conn) } return err; } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_BT_MCC_OTS int bt_mcc_read_segments_obj_id(struct bt_conn *conn) @@ -2674,6 +2869,7 @@ int bt_mcc_set_current_group_obj_id(struct bt_conn *conn, uint64_t obj_id) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) int bt_mcc_read_playing_order(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2711,7 +2907,9 @@ int bt_mcc_read_playing_order(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order) { struct mcs_instance_t *mcs_inst; @@ -2762,7 +2960,9 @@ int bt_mcc_set_playing_order(struct bt_conn *conn, uint8_t order) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) int bt_mcc_read_playing_orders_supported(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2800,7 +3000,9 @@ int bt_mcc_read_playing_orders_supported(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) int bt_mcc_read_media_state(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2838,7 +3040,9 @@ int bt_mcc_read_media_state(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd) { struct mcs_instance_t *mcs_inst; @@ -2900,7 +3104,9 @@ int bt_mcc_send_cmd(struct bt_conn *conn, const struct mpl_cmd *cmd) } return err; } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) int bt_mcc_read_opcodes_supported(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -2938,6 +3144,7 @@ int bt_mcc_read_opcodes_supported(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_BT_MCC_OTS int bt_mcc_send_search(struct bt_conn *conn, const struct mpl_search *search) @@ -3034,6 +3241,7 @@ int bt_mcc_read_search_results_obj_id(struct bt_conn *conn) } #endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) int bt_mcc_read_content_control_id(struct bt_conn *conn) { struct mcs_instance_t *mcs_inst; @@ -3071,6 +3279,7 @@ int bt_mcc_read_content_control_id(struct bt_conn *conn) } return err; } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #ifdef CONFIG_BT_MCC_OTS diff --git a/subsys/bluetooth/audio/mcc_internal.h b/subsys/bluetooth/audio/mcc_internal.h new file mode 100644 index 00000000000..2838e53ba35 --- /dev/null +++ b/subsys/bluetooth/audio/mcc_internal.h @@ -0,0 +1,152 @@ +/** @file + * @brief Internal APIs for Bluetooth MCP. + */ + +/* + * Copyright (c) 2019 - 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ +#define ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ + +#include +#include +#include +#include "../services/ots/ots_client_internal.h" + +struct mcs_instance_t *lookup_inst_by_conn(struct bt_conn *conn); + +struct mcs_instance_t { + struct bt_conn *conn; + uint16_t start_handle; + uint16_t end_handle; + uint16_t player_name_handle; +#ifdef CONFIG_BT_MCC_OTS + uint16_t icon_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) + uint16_t icon_url_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ + uint16_t track_changed_handle; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) + uint16_t track_title_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) + uint16_t track_duration_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) + uint16_t track_position_handle; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) || defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) + uint16_t playback_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) || */ + /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) + uint16_t seeking_speed_handle; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ +#ifdef CONFIG_BT_MCC_OTS + uint16_t segments_obj_id_handle; + uint16_t current_track_obj_id_handle; + uint16_t next_track_obj_id_handle; + uint16_t current_group_obj_id_handle; + uint16_t parent_group_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) + uint16_t playing_order_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) || defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) + uint16_t playing_orders_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) + uint16_t media_state_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ + uint16_t cp_handle; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) + uint16_t opcodes_supported_handle; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ +#ifdef CONFIG_BT_MCC_OTS + uint16_t scp_handle; + uint16_t search_results_obj_id_handle; +#endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) + uint16_t content_control_id_handle; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ + + + /* The write buffer is used for + * - track position (4 octets) + * - playback speed (1 octet) + * - playing order (1 octet) + * - the control point (5 octets) + * (1 octet opcode + optionally 4 octet param) + * (mpl_cmd.opcode + mpl_cmd.param) + * If the object transfer client is included, it is also used for + * - object IDs (6 octets - BT_OTS_OBJ_ID_SIZE) and + * - the search control point (64 octets - SEARCH_LEN_MAX) + * + * If there is no OTC, the largest is control point + * If OTC is included, the largest is the search control point + */ +#ifdef CONFIG_BT_MCC_OTS + char write_buf[SEARCH_LEN_MAX]; +#else + /* Trick to be able to use sizeof on members of a struct type */ + /* TODO: Rewrite the mpl_cmd to have the "use_param" parameter */ + /* separately, and the opcode and param alone as a struct */ + char write_buf[sizeof(((struct mpl_cmd *)0)->opcode) + + sizeof(((struct mpl_cmd *)0)->param)]; +#endif /* CONFIG_BT_MCC_OTS */ + + struct bt_gatt_discover_params discover_params; + struct bt_gatt_read_params read_params; + struct bt_gatt_write_params write_params; + +/** Any fields below here cannot be memset as part of a reset */ + bool busy; + + struct bt_gatt_subscribe_params player_name_sub_params; + struct bt_gatt_subscribe_params track_changed_sub_params; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) + struct bt_gatt_subscribe_params track_title_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE_ENABLE_SUBSCRIPTION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) + struct bt_gatt_subscribe_params track_duration_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) + struct bt_gatt_subscribe_params track_position_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION)*/ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) + struct bt_gatt_subscribe_params playback_speed_sub_params; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) + struct bt_gatt_subscribe_params seeking_speed_sub_params; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ +#ifdef CONFIG_BT_MCC_OTS + struct bt_gatt_subscribe_params current_track_obj_sub_params; + struct bt_gatt_subscribe_params next_track_obj_sub_params; + struct bt_gatt_subscribe_params parent_group_obj_sub_params; + struct bt_gatt_subscribe_params current_group_obj_sub_params; +#endif /* CONFIG_BT_MCC_OTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) + struct bt_gatt_subscribe_params playing_order_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) + struct bt_gatt_subscribe_params media_state_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ + struct bt_gatt_subscribe_params cp_sub_params; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) + struct bt_gatt_subscribe_params opcodes_supported_sub_params; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ +#ifdef CONFIG_BT_MCC_OTS + struct bt_gatt_subscribe_params scp_sub_params; + struct bt_gatt_subscribe_params search_results_obj_sub_params; +#endif /* CONFIG_BT_MCC_OTS */ + +#ifdef CONFIG_BT_MCC_OTS + struct bt_ots_client otc; +#endif /* CONFIG_BT_MCC_OTS */ +}; + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MCP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/mcs.c b/subsys/bluetooth/audio/mcs.c index 3d31af7a828..271ea690ad7 100644 --- a/subsys/bluetooth/audio/mcs.c +++ b/subsys/bluetooth/audio/mcs.c @@ -89,15 +89,18 @@ static ssize_t read_player_name(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *name = media_proxy_sctrl_get_player_name(); LOG_DBG("Player name read: %s (offset %u)", name, offset); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_PLAYER_NAME_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_PLAYER_NAME_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_PLAYER_NAME_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_PLAYER_NAME_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, name, @@ -131,15 +134,18 @@ static ssize_t read_icon_url(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *url = media_proxy_sctrl_get_icon_url(); LOG_DBG("Icon URL read, offset: %d, len:%d, URL: %s", offset, len, url); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_ICON_URL_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_ICON_URL_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_ICON_URL_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_ICON_URL_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, url, @@ -155,15 +161,18 @@ static ssize_t read_track_title(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; const char *title = media_proxy_sctrl_get_track_title(); LOG_DBG("Track title read, offset: %d, len:%d, title: %s", offset, len, title); - if (offset == 0) { - atomic_clear_bit(client->flags, FLAG_TRACK_TITLE_CHANGED); - } else if (atomic_test_bit(client->flags, FLAG_TRACK_TITLE_CHANGED)) { - return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + if (offset == 0) { + atomic_clear_bit(client->flags, FLAG_TRACK_TITLE_CHANGED); + } else if (atomic_test_bit(client->flags, FLAG_TRACK_TITLE_CHANGED)) { + return BT_GATT_ERR(BT_MCS_ERR_LONG_VAL_CHANGED); + } } return bt_gatt_attr_read(conn, attr, buf, len, offset, title, @@ -180,35 +189,38 @@ static ssize_t read_track_duration(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int32_t duration = media_proxy_sctrl_get_track_duration(); int32_t duration_le = sys_cpu_to_le32(duration); LOG_DBG("Track duration read: %d (0x%08x)", duration, duration); - atomic_clear_bit(client->flags, FLAG_TRACK_DURATION_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_TRACK_DURATION_CHANGED); + } - return bt_gatt_attr_read(conn, attr, buf, len, offset, &duration_le, - sizeof(duration_le)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &duration_le, sizeof(duration_le)); } -static void track_duration_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void track_duration_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_track_position(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_track_position(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int32_t position = media_proxy_sctrl_get_track_position(); int32_t position_le = sys_cpu_to_le32(position); LOG_DBG("Track position read: %d (0x%08x)", position, position); - atomic_clear_bit(client->flags, FLAG_TRACK_POSITION_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_TRACK_POSITION_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &position_le, sizeof(position_le)); @@ -248,21 +260,21 @@ static ssize_t read_playback_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int8_t speed = media_proxy_sctrl_get_playback_speed(); LOG_DBG("Playback speed read: %d", speed); - atomic_clear_bit(client->flags, FLAG_PLAYBACK_SPEED_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, - sizeof(speed)); + atomic_clear_bit(client->flags, FLAG_PLAYBACK_SPEED_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, sizeof(speed)); } -static ssize_t write_playback_speed(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, - uint8_t flags) +static ssize_t write_playback_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { int8_t speed; @@ -282,22 +294,23 @@ static ssize_t write_playback_speed(struct bt_conn *conn, return len; } -static void playback_speed_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void playback_speed_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_seeking_speed(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_seeking_speed(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; int8_t speed = media_proxy_sctrl_get_seeking_speed(); LOG_DBG("Seeking speed read: %d", speed); - atomic_clear_bit(client->flags, FLAG_SEEKING_SPEED_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_SEEKING_SPEED_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &speed, sizeof(speed)); @@ -329,7 +342,6 @@ static ssize_t read_current_track_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t track_id = media_proxy_sctrl_get_current_track_id(); uint8_t track_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -337,7 +349,11 @@ static ssize_t read_current_track_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Current track ID read: ", track_id); - atomic_clear_bit(client->flags, FLAG_CURRENT_TRACK_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_CURRENT_TRACK_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, track_id_le, sizeof(track_id_le)); @@ -383,13 +399,16 @@ static ssize_t read_next_track_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t track_id = media_proxy_sctrl_get_next_track_id(); uint8_t track_id_le[BT_OTS_OBJ_ID_SIZE]; sys_put_le48(track_id, track_id_le); - atomic_clear_bit(client->flags, FLAG_NEXT_TRACK_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_NEXT_TRACK_OBJ_ID_CHANGED); + } if (track_id == MPL_NO_TRACK_ID) { LOG_DBG("Next track read, but it is empty"); @@ -443,7 +462,6 @@ static ssize_t read_parent_group_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t group_id = media_proxy_sctrl_get_parent_group_id(); uint8_t group_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -451,7 +469,11 @@ static ssize_t read_parent_group_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Parent group read: ", group_id); - atomic_clear_bit(client->flags, FLAG_PARENT_GROUP_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_PARENT_GROUP_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, group_id_le, sizeof(group_id_le)); @@ -467,7 +489,6 @@ static ssize_t read_current_group_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t group_id = media_proxy_sctrl_get_current_group_id(); uint8_t group_id_le[BT_OTS_OBJ_ID_SIZE]; @@ -475,7 +496,11 @@ static ssize_t read_current_group_id(struct bt_conn *conn, LOG_DBG_OBJ_ID("Current group read: ", group_id); - atomic_clear_bit(client->flags, FLAG_CURRENT_GROUP_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_CURRENT_GROUP_OBJ_ID_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, group_id_le, sizeof(group_id_le)); @@ -522,21 +547,21 @@ static ssize_t read_playing_order(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint8_t order = media_proxy_sctrl_get_playing_order(); LOG_DBG("Playing order read: %d (0x%02x)", order, order); - atomic_clear_bit(client->flags, FLAG_PLAYING_ORDER_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, &order, - sizeof(order)); + atomic_clear_bit(client->flags, FLAG_PLAYING_ORDER_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &order, sizeof(order)); } -static ssize_t write_playing_order(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, uint16_t offset, - uint8_t flags) +static ssize_t write_playing_order(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { LOG_DBG("Playing order write"); @@ -558,14 +583,12 @@ static ssize_t write_playing_order(struct bt_conn *conn, return len; } -static void playing_order_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void playing_order_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } -static ssize_t read_playing_orders_supported(struct bt_conn *conn, - const struct bt_gatt_attr *attr, +static ssize_t read_playing_orders_supported(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { uint16_t orders = media_proxy_sctrl_get_playing_orders_supported(); @@ -573,20 +596,21 @@ static ssize_t read_playing_orders_supported(struct bt_conn *conn, LOG_DBG("Playing orders read: %d (0x%04x)", orders, orders); - return bt_gatt_attr_read(conn, attr, buf, len, offset, &orders_le, - sizeof(orders_le)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, &orders_le, sizeof(orders_le)); } -static ssize_t read_media_state(struct bt_conn *conn, - const struct bt_gatt_attr *attr, void *buf, +static ssize_t read_media_state(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint8_t state = media_proxy_sctrl_get_media_state(); LOG_DBG("Media state read: %d", state); - atomic_clear_bit(client->flags, FLAG_MEDIA_STATE_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_MEDIA_STATE_CHANGED); + } return bt_gatt_attr_read(conn, attr, buf, len, offset, &state, sizeof(state)); @@ -603,7 +627,6 @@ static ssize_t write_control_point(struct bt_conn *conn, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { - struct client_state *client = &clients[bt_conn_index(conn)]; struct mpl_cmd command; if (offset != 0) { @@ -632,17 +655,23 @@ static ssize_t write_control_point(struct bt_conn *conn, notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); - } else if (atomic_test_and_set_bit(client->flags, FLAG_MEDIA_CONTROL_POINT_BUSY)) { - const struct mpl_cmd_ntf cmd_ntf = { - .requested_opcode = command.opcode, - .result_code = BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED, - }; + } - LOG_DBG("Busy with other operation"); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); + if (atomic_test_and_set_bit(client->flags, FLAG_MEDIA_CONTROL_POINT_BUSY)) { + const struct mpl_cmd_ntf cmd_ntf = { + .requested_opcode = command.opcode, + .result_code = BT_MCS_OPC_NTF_CANNOT_BE_COMPLETED, + }; + + LOG_DBG("Busy with other operation"); + + notify(BT_UUID_MCS_MEDIA_CONTROL_POINT, &cmd_ntf, sizeof(cmd_ntf)); - return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } } if (len == sizeof(command.opcode) + sizeof(command.param)) { @@ -666,31 +695,30 @@ static ssize_t read_opcodes_supported(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint32_t opcodes = media_proxy_sctrl_get_commands_supported(); uint32_t opcodes_le = sys_cpu_to_le32(opcodes); LOG_DBG("Opcodes_supported read: %d (0x%08x)", opcodes, opcodes); - atomic_clear_bit(client->flags, FLAG_MEDIA_CONTROL_OPCODES_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - return bt_gatt_attr_read(conn, attr, buf, len, offset, - &opcodes_le, sizeof(opcodes_le)); + atomic_clear_bit(client->flags, FLAG_MEDIA_CONTROL_OPCODES_CHANGED); + } + + return bt_gatt_attr_read(conn, attr, buf, len, offset, &opcodes_le, sizeof(opcodes_le)); } -static void opcodes_supported_cfg_changed(const struct bt_gatt_attr *attr, - uint16_t value) +static void opcodes_supported_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) { LOG_DBG("value 0x%04x", value); } #ifdef CONFIG_BT_OTS -static ssize_t write_search_control_point(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, uint16_t len, - uint16_t offset, uint8_t flags) +static ssize_t write_search_control_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { - struct client_state *client = &clients[bt_conn_index(conn)]; struct mpl_search search = {0}; if (offset != 0) { @@ -701,14 +729,18 @@ static ssize_t write_search_control_point(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); } - if (atomic_test_and_set_bit(client->flags, FLAG_SEARCH_CONTROL_POINT_BUSY)) { - const uint8_t result_code = BT_MCS_SCP_NTF_FAILURE; + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; - LOG_DBG("Busy with other operation"); + if (atomic_test_and_set_bit(client->flags, FLAG_SEARCH_CONTROL_POINT_BUSY)) { + const uint8_t result_code = BT_MCS_SCP_NTF_FAILURE; - notify(BT_UUID_MCS_SEARCH_CONTROL_POINT, &result_code, sizeof(result_code)); + LOG_DBG("Busy with other operation"); + + notify(BT_UUID_MCS_SEARCH_CONTROL_POINT, &result_code, sizeof(result_code)); - return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + return BT_GATT_ERR(BT_ATT_ERR_PROCEDURE_IN_PROGRESS); + } } memcpy(&search.search, (char *)buf, len); @@ -731,12 +763,15 @@ static ssize_t read_search_results_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { - struct client_state *client = &clients[bt_conn_index(conn)]; uint64_t search_id = media_proxy_sctrl_get_search_results_id(); LOG_DBG_OBJ_ID("Search results id read: ", search_id); - atomic_clear_bit(client->flags, FLAG_SEARCH_RESULTS_OBJ_ID_CHANGED); + if (conn != NULL) { + struct client_state *client = &clients[bt_conn_index(conn)]; + + atomic_clear_bit(client->flags, FLAG_SEARCH_RESULTS_OBJ_ID_CHANGED); + } /* TODO: The permanent solution here should be that the call to */ /* mpl should fill the UUID in a pointed-to value, and return a */ diff --git a/subsys/bluetooth/audio/media_proxy.c b/subsys/bluetooth/audio/media_proxy.c index 3fcf35fc37a..e816b1f20a0 100644 --- a/subsys/bluetooth/audio/media_proxy.c +++ b/subsys/bluetooth/audio/media_proxy.c @@ -278,6 +278,7 @@ static void mcc_read_icon_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) } #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) { if (err) { @@ -290,6 +291,7 @@ static void mcc_read_icon_url_cb(struct bt_conn *conn, int err, const char *url) LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) { @@ -305,6 +307,7 @@ static void mcc_track_changed_ntf_cb(struct bt_conn *conn, int err) } } +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *title) { if (err) { @@ -317,7 +320,9 @@ static void mcc_read_track_title_cb(struct bt_conn *conn, int err, const char *t LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t dur) { if (err) { @@ -330,7 +335,9 @@ static void mcc_read_track_duration_cb(struct bt_conn *conn, int err, int32_t du LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -343,7 +350,9 @@ static void mcc_read_track_position_cb(struct bt_conn *conn, int err, int32_t po LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos) { if (err) { @@ -356,7 +365,9 @@ static void mcc_set_track_position_cb(struct bt_conn *conn, int err, int32_t pos LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -369,7 +380,9 @@ static void mcc_read_playback_speed_cb(struct bt_conn *conn, int err, int8_t spe LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -382,7 +395,9 @@ static void mcc_set_playback_speed_cb(struct bt_conn *conn, int err, int8_t spee LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t speed) { if (err) { @@ -395,6 +410,7 @@ static void mcc_read_seeking_speed_cb(struct bt_conn *conn, int err, int8_t spee LOG_DBG("No callback"); } } +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS static void mcc_read_segments_obj_id_cb(struct bt_conn *conn, int err, uint64_t id) @@ -470,6 +486,7 @@ static void mcc_read_current_group_obj_id_cb(struct bt_conn *conn, int err, uint #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -482,7 +499,9 @@ static void mcc_read_playing_order_cb(struct bt_conn *conn, int err, uint8_t ord LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t order) { if (err) { @@ -495,7 +514,9 @@ static void mcc_set_playing_order_cb(struct bt_conn *conn, int err, uint8_t orde LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, uint16_t orders) { if (err) { @@ -508,7 +529,9 @@ static void mcc_read_playing_orders_supported_cb(struct bt_conn *conn, int err, LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state) { if (err) { @@ -521,7 +544,9 @@ static void mcc_read_media_state_cb(struct bt_conn *conn, int err, uint8_t state LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd *cmd) { if (err) { @@ -535,6 +560,7 @@ static void mcc_send_cmd_cb(struct bt_conn *conn, int err, const struct mpl_cmd LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, const struct mpl_cmd_ntf *ntf) @@ -551,6 +577,7 @@ static void mcc_cmd_ntf_cb(struct bt_conn *conn, int err, } } +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_t opcodes) { if (err) { @@ -563,6 +590,7 @@ static void mcc_read_opcodes_supported_cb(struct bt_conn *conn, int err, uint32_ LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS static void mcc_send_search_cb(struct bt_conn *conn, int err, const struct mpl_search *search) @@ -605,6 +633,7 @@ static void mcc_read_search_results_obj_id_cb(struct bt_conn *conn, int err, uin } #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_t ccid) { if (err) { @@ -617,6 +646,7 @@ static void mcc_read_content_control_id_cb(struct bt_conn *conn, int err, uint8_ LOG_DBG("No callback"); } } +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ @@ -672,15 +702,31 @@ int media_proxy_ctrl_discover_player(struct bt_conn *conn) #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.read_icon_obj_id = mcc_read_icon_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) mprx.mcc_cbs.read_icon_url = mcc_read_icon_url_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) */ mprx.mcc_cbs.track_changed_ntf = mcc_track_changed_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_TRACK_TITLE) mprx.mcc_cbs.read_track_title = mcc_read_track_title_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_TITLE) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_DURATION) mprx.mcc_cbs.read_track_duration = mcc_read_track_duration_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_DURATION) */ +#if defined(CONFIG_BT_MCC_READ_TRACK_POSITION) mprx.mcc_cbs.read_track_position = mcc_read_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_READ_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_SET_TRACK_POSITION) mprx.mcc_cbs.set_track_position = mcc_set_track_position_cb; +#endif /* defined(CONFIG_BT_MCC_SET_TRACK_POSITION) */ +#if defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) mprx.mcc_cbs.read_playback_speed = mcc_read_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) mprx.mcc_cbs.set_playback_speed = mcc_set_playback_speed_cb; +#endif /* defined (CONFIG_BT_MCC_SET_PLAYBACK_SPEED) */ +#if defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) mprx.mcc_cbs.read_seeking_speed = mcc_read_seeking_speed_cb; +#endif /* defined (CONFIG_BT_MCC_READ_SEEKING_SPEED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.read_segments_obj_id = mcc_read_segments_obj_id_cb; mprx.mcc_cbs.read_current_track_obj_id = mcc_read_current_track_obj_id_cb; @@ -688,19 +734,33 @@ int media_proxy_ctrl_discover_player(struct bt_conn *conn) mprx.mcc_cbs.read_parent_group_obj_id = mcc_read_parent_group_obj_id_cb; mprx.mcc_cbs.read_current_group_obj_id = mcc_read_current_group_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) mprx.mcc_cbs.read_playing_order = mcc_read_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) mprx.mcc_cbs.set_playing_order = mcc_set_playing_order_cb; +#endif /* defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) */ +#if defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) mprx.mcc_cbs.read_playing_orders_supported = mcc_read_playing_orders_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) */ +#if defined(CONFIG_BT_MCC_READ_MEDIA_STATE) mprx.mcc_cbs.read_media_state = mcc_read_media_state_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_STATE) */ +#if defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) mprx.mcc_cbs.send_cmd = mcc_send_cmd_cb; +#endif /* defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) */ mprx.mcc_cbs.cmd_ntf = mcc_cmd_ntf_cb; +#if defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) mprx.mcc_cbs.read_opcodes_supported = mcc_read_opcodes_supported_cb; +#endif /* defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) */ #ifdef CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS mprx.mcc_cbs.send_search = mcc_send_search_cb; mprx.mcc_cbs.search_ntf = mcc_search_ntf_cb; mprx.mcc_cbs.read_search_results_obj_id = mcc_read_search_results_obj_id_cb; #endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL_OBJECTS */ +#if defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) mprx.mcc_cbs.read_content_control_id = mcc_read_content_control_id_cb; +#endif /* defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) */ err = bt_mcc_init(&mprx.mcc_cbs); if (err) { @@ -825,11 +885,11 @@ int media_proxy_ctrl_get_icon_url(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_icon_url(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_MEDIA_PLAYER_ICON_URL */ return -EINVAL; } @@ -860,11 +920,11 @@ int media_proxy_ctrl_get_track_title(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_TITLE) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_title(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_TITLE */ return -EINVAL; } @@ -896,11 +956,11 @@ int media_proxy_ctrl_get_track_duration(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_DURATION) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_duration(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_DURATION */ return -EINVAL; } @@ -932,11 +992,11 @@ int media_proxy_ctrl_get_track_position(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_TRACK_POSITION) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_track_position(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_TRACK_POSITION */ return -EINVAL; } @@ -967,11 +1027,11 @@ int media_proxy_ctrl_set_track_position(struct media_player *player, int32_t pos } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && CONFIG_BT_MCC_SET_TRACK_POSITION if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_track_position(mprx.remote_player.conn, position); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_TRACK_POSITION */ return -EINVAL; } @@ -1002,11 +1062,11 @@ int media_proxy_ctrl_get_playback_speed(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_PLAYBACK_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_playback_speed(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYBACK_SPEED */ return -EINVAL; } @@ -1037,11 +1097,11 @@ int media_proxy_ctrl_set_playback_speed(struct media_player *player, int8_t spee } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_PLAYBACK_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_playback_speed(mprx.remote_player.conn, speed); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_PLAYBACK_SPEED */ return -EINVAL; } @@ -1072,11 +1132,11 @@ int media_proxy_ctrl_get_seeking_speed(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_SEEKING_SPEED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_seeking_speed(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_SEEKING_SPEED */ return -EINVAL; } @@ -1409,12 +1469,12 @@ int media_proxy_ctrl_get_playing_order(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_PLAYING_ORDER) if (mprx.remote_player.registered && player == &mprx.remote_player) { LOG_DBG("Remote player"); return bt_mcc_read_playing_order(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYING_ORDER */ return -EINVAL; } @@ -1445,11 +1505,11 @@ int media_proxy_ctrl_set_playing_order(struct media_player *player, uint8_t orde } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_PLAYING_ORDER) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_set_playing_order(mprx.remote_player.conn, order); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_PLAYING_ORDER */ return -EINVAL; } @@ -1481,11 +1541,12 @@ int media_proxy_ctrl_get_playing_orders_supported(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && \ + defined(CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_playing_orders_supported(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_PLAYING_ORDER_SUPPORTED */ return -EINVAL; } @@ -1516,11 +1577,11 @@ int media_proxy_ctrl_get_media_state(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_MEDIA_STATE) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_media_state(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_MEDIA_STATE */ return -EINVAL; } @@ -1551,11 +1612,11 @@ int media_proxy_ctrl_send_command(struct media_player *player, const struct mpl_ } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_send_cmd(mprx.remote_player.conn, cmd); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_SET_MEDIA_CONTROL_POINT */ return -EINVAL; } @@ -1587,11 +1648,14 @@ int media_proxy_ctrl_get_commands_supported(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && \ + defined(CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_opcodes_supported(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && + * CONFIG_BT_MCC_READ_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED + */ return -EINVAL; } @@ -1693,11 +1757,11 @@ uint8_t media_proxy_ctrl_get_content_ctrl_id(struct media_player *player) } #endif /* CONFIG_MCTL_LOCAL_PLAYER_LOCAL_CONTROL */ -#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) +#if defined(CONFIG_MCTL_REMOTE_PLAYER_CONTROL) && defined(CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID) if (mprx.remote_player.registered && player == &mprx.remote_player) { return bt_mcc_read_content_control_id(mprx.remote_player.conn); } -#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL */ +#endif /* CONFIG_MCTL_REMOTE_PLAYER_CONTROL && CONFIG_BT_MCC_READ_CONTENT_CONTROL_ID */ return -EINVAL; } diff --git a/subsys/bluetooth/audio/micp_internal.h b/subsys/bluetooth/audio/micp_internal.h index a68aaca7cdf..ce486bf6fe6 100644 --- a/subsys/bluetooth/audio/micp_internal.h +++ b/subsys/bluetooth/audio/micp_internal.h @@ -29,8 +29,10 @@ struct bt_micp_mic_ctlr { struct bt_gatt_discover_params discover_params; struct bt_conn *conn; +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) uint8_t aics_inst_cnt; - struct bt_aics *aics[CONFIG_BT_AICS_CLIENT_MAX_INSTANCE_COUNT]; + struct bt_aics *aics[CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST]; +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ }; #endif /* ZEPHYR_INCLUDE_BLUETOOTH_AUDIO_MICP_INTERNAL_ */ diff --git a/subsys/bluetooth/audio/micp_mic_ctlr.c b/subsys/bluetooth/audio/micp_mic_ctlr.c index 55fa6c3c5db..45190b7c9b4 100644 --- a/subsys/bluetooth/audio/micp_mic_ctlr.c +++ b/subsys/bluetooth/audio/micp_mic_ctlr.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2020 Bose Corporation - * Copyright (c) 2020-2022 Nordic Semiconductor ASA + * Copyright (c) 2020-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,13 +28,64 @@ LOG_MODULE_REGISTER(bt_micp_mic_ctlr, CONFIG_BT_MICP_MIC_CTLR_LOG_LEVEL); #include "common/bt_str.h" /* Callback functions */ -static struct bt_micp_mic_ctlr_cb *micp_mic_ctlr_cb; +static sys_slist_t micp_mic_ctlr_cbs = SYS_SLIST_STATIC_INIT(&micp_mic_ctlr_cbs); static struct bt_micp_mic_ctlr mic_ctlrs[CONFIG_BT_MAX_CONN]; -static struct bt_uuid *mics_uuid = BT_UUID_MICS; +static const struct bt_uuid *mics_uuid = BT_UUID_MICS; -static uint8_t mute_notify_handler(struct bt_conn *conn, - struct bt_gatt_subscribe_params *params, +static struct bt_micp_mic_ctlr *mic_ctlr_get_by_conn(const struct bt_conn *conn) +{ + return &mic_ctlrs[bt_conn_index(conn)]; +} + +static void micp_mic_ctlr_mute_changed(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->mute) { + listener->mute(mic_ctlr, err, mute_val); + } + } +} + +static void micp_mic_ctlr_mute_written(struct bt_micp_mic_ctlr *mic_ctlr, int err, uint8_t mute_val) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (mute_val == BT_MICP_MUTE_UNMUTED) { + if (listener->unmute_written) { + listener->unmute_written(mic_ctlr, err); + } + } else { + if (listener->mute_written) { + listener->mute_written(mic_ctlr, err); + } + } + } +} + +static void micp_mic_ctlr_discover_complete(struct bt_micp_mic_ctlr *mic_ctlr, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->discover) { + uint8_t aics_cnt = 0U; + +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) + if (err == 0) { + aics_cnt = mic_ctlr->aics_inst_cnt; + } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + + listener->discover(mic_ctlr, err, aics_cnt); + } + } +} + +static uint8_t mute_notify_handler(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length) { uint8_t *mute_val; @@ -44,19 +95,16 @@ static uint8_t mute_notify_handler(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } - mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + mic_ctlr = mic_ctlr_get_by_conn(conn); if (data != NULL) { if (length == sizeof(*mute_val)) { mute_val = (uint8_t *)data; LOG_DBG("Mute %u", *mute_val); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->mute != NULL) { - micp_mic_ctlr_cb->mute(mic_ctlr, 0, *mute_val); - } - } else { - LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val)); + micp_mic_ctlr_mute_changed(mic_ctlr, 0, *mute_val); } + } else { + LOG_DBG("Invalid length %u (expected %zu)", length, sizeof(*mute_val)); } return BT_GATT_ITER_CONTINUE; @@ -66,9 +114,9 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) { + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); uint8_t cb_err = err; uint8_t mute_val = 0; - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; mic_ctlr->busy = false; @@ -84,9 +132,7 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, } } - if (micp_mic_ctlr_cb != NULL && micp_mic_ctlr_cb->mute != NULL) { - micp_mic_ctlr_cb->mute(mic_ctlr, cb_err, mute_val); - } + micp_mic_ctlr_mute_changed(mic_ctlr, cb_err, mute_val); return BT_GATT_ITER_STOP; } @@ -94,25 +140,14 @@ static uint8_t micp_mic_ctlr_read_mute_cb(struct bt_conn *conn, uint8_t err, static void micp_mic_ctlr_write_mics_mute_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); uint8_t mute_val = mic_ctlr->mute_val_buf[0]; LOG_DBG("Write %s (0x%02X)", err ? "failed" : "successful", err); mic_ctlr->busy = false; - if (mute_val == BT_MICP_MUTE_UNMUTED) { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->unmute_written != NULL) { - micp_mic_ctlr_cb->unmute_written(mic_ctlr, err); - } - - } else { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->mute_written != NULL) { - micp_mic_ctlr_cb->mute_written(mic_ctlr, err); - } - } + micp_mic_ctlr_mute_written(mic_ctlr, err, mute_val); } #if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) @@ -131,41 +166,158 @@ static struct bt_micp_mic_ctlr *lookup_micp_by_aics(const struct bt_aics *aics) return NULL; } -static void aics_discover_cb(struct bt_aics *inst, int err) +static void micp_mic_ctlr_aics_state_cb(struct bt_aics *inst, int err, int8_t gain, uint8_t mute, + uint8_t mode) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.state) { + listener->aics_cb.state(inst, err, gain, mute, mode); + } + } +} + +static void micp_mic_ctlr_aics_gain_setting_cb(struct bt_aics *inst, int err, uint8_t units, + int8_t minimum, int8_t maximum) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.gain_setting) { + listener->aics_cb.gain_setting(inst, err, units, minimum, maximum); + } + } +} + +static void micp_mic_ctlr_aics_type_cb(struct bt_aics *inst, int err, uint8_t type) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.type) { + listener->aics_cb.type(inst, err, type); + } + } +} + +static void micp_mic_ctlr_aics_status_cb(struct bt_aics *inst, int err, bool active) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.status) { + listener->aics_cb.status(inst, err, active); + } + } +} + +static void micp_mic_ctlr_aics_description_cb(struct bt_aics *inst, int err, char *description) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.description) { + listener->aics_cb.description(inst, err, description); + } + } +} + +static void micp_mic_ctlr_aics_discover_cb(struct bt_aics *inst, int err) { struct bt_micp_mic_ctlr *mic_ctlr = lookup_micp_by_aics(inst); + struct bt_micp_mic_ctlr_cb *listener, *next; + + if (mic_ctlr == NULL) { + LOG_ERR("Could not lookup mic_ctlr from aics"); + micp_mic_ctlr_discover_complete(mic_ctlr, BT_GATT_ERR(BT_ATT_ERR_UNLIKELY)); + + return; + } if (err == 0) { /* Continue discovery of included services */ - err = bt_gatt_discover(mic_ctlr->conn, - &mic_ctlr->discover_params); + err = bt_gatt_discover(mic_ctlr->conn, &mic_ctlr->discover_params); } if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); + micp_mic_ctlr_discover_complete(mic_ctlr, err); + } + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.discover) { + listener->aics_cb.discover(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_gain_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_gain) { + listener->aics_cb.set_gain(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_unmute_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.unmute) { + listener->aics_cb.unmute(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_mute_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.mute) { + listener->aics_cb.mute(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_manual_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_manual_mode) { + listener->aics_cb.set_manual_mode(inst, err); + } + } +} + +static void micp_mic_ctlr_aics_set_auto_mode_cb(struct bt_aics *inst, int err) +{ + struct bt_micp_mic_ctlr_cb *listener, *next; + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&micp_mic_ctlr_cbs, listener, next, _node) { + if (listener->aics_cb.set_auto_mode) { + listener->aics_cb.set_auto_mode(inst, err); } } } -#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ static uint8_t micp_discover_include_func( struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Discover include complete for MICS: %u AICS", mic_ctlr->aics_inst_cnt); (void)memset(params, 0, sizeof(*params)); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, 0, - mic_ctlr->aics_inst_cnt); - } + micp_mic_ctlr_discover_complete(mic_ctlr, 0); return BT_GATT_ITER_STOP; } @@ -196,18 +348,16 @@ static uint8_t micp_discover_include_func( ¶m); if (err != 0) { LOG_DBG("AICS Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, - 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } + return BT_GATT_ITER_STOP; } } return BT_GATT_ITER_CONTINUE; } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ /** * @brief This will discover all characteristics on the server, retrieving the @@ -218,35 +368,30 @@ static uint8_t micp_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { int err = 0; LOG_DBG("Discovery complete"); (void)memset(params, 0, sizeof(*params)); - if (CONFIG_BT_MICP_MIC_CTLR_MAX_AICS_INST > 0) { - /* Discover included services */ - mic_ctlr->discover_params.start_handle = mic_ctlr->start_handle; - mic_ctlr->discover_params.end_handle = mic_ctlr->end_handle; - mic_ctlr->discover_params.type = BT_GATT_DISCOVER_INCLUDE; - mic_ctlr->discover_params.func = micp_discover_include_func; - - err = bt_gatt_discover(conn, - &mic_ctlr->discover_params); - if (err != 0) { - LOG_DBG("Discover AICS failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } - } - } else { - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } + +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) + /* Discover included services */ + mic_ctlr->discover_params.start_handle = mic_ctlr->start_handle; + mic_ctlr->discover_params.end_handle = mic_ctlr->end_handle; + mic_ctlr->discover_params.type = BT_GATT_DISCOVER_INCLUDE; + mic_ctlr->discover_params.func = micp_discover_include_func; + + err = bt_gatt_discover(conn, &mic_ctlr->discover_params); + if (err != 0) { + LOG_DBG("Discover AICS failed (err %d)", err); + micp_mic_ctlr_discover_complete(mic_ctlr, err); } +#else + micp_mic_ctlr_discover_complete(mic_ctlr, err); +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + return BT_GATT_ITER_STOP; } @@ -272,13 +417,18 @@ static uint8_t micp_discover_func(struct bt_conn *conn, sub_params->value = BT_GATT_CCC_NOTIFY; sub_params->value_handle = chrc->value_handle; sub_params->notify = mute_notify_handler; + atomic_set_bit(sub_params->flags, BT_GATT_SUBSCRIBE_FLAG_VOLATILE); err = bt_gatt_subscribe(conn, sub_params); - if (err == 0) { + if (err == 0 || err == -EALREADY) { LOG_DBG("Subscribed to handle 0x%04X", attr->handle); } else { LOG_DBG("Could not subscribe to handle 0x%04X: %d", attr->handle, err); + + micp_mic_ctlr_discover_complete(mic_ctlr, err); + + return BT_GATT_ITER_STOP; } } } @@ -290,14 +440,12 @@ static uint8_t primary_discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (attr == NULL) { LOG_DBG("Could not find a MICS instance on the server"); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, -ENODATA, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, -ENODATA); + return BT_GATT_ITER_STOP; } @@ -322,10 +470,7 @@ static uint8_t primary_discover_func(struct bt_conn *conn, err = bt_gatt_discover(conn, &mic_ctlr->discover_params); if (err != 0) { LOG_DBG("Discover failed (err %d)", err); - if (micp_mic_ctlr_cb != NULL && - micp_mic_ctlr_cb->discover != NULL) { - micp_mic_ctlr_cb->discover(mic_ctlr, err, 0); - } + micp_mic_ctlr_discover_complete(mic_ctlr, err); } return BT_GATT_ITER_STOP; @@ -339,19 +484,13 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) mic_ctlr->start_handle = 0; mic_ctlr->end_handle = 0; mic_ctlr->mute_handle = 0; +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) mic_ctlr->aics_inst_cnt = 0; +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ if (mic_ctlr->conn != NULL) { struct bt_conn *conn = mic_ctlr->conn; - /* It's okay if this fails. In case of disconnect, we can't - * unsubscribe and it will just fail. - * In case that we reset due to another call of the discover - * function, we will unsubscribe (regardless of bonding state) - * to accommodate the new discovery values. - */ - (void)bt_gatt_unsubscribe(conn, &mic_ctlr->mute_sub_params); - bt_conn_unref(conn); mic_ctlr->conn = NULL; } @@ -359,7 +498,7 @@ static void micp_mic_ctlr_reset(struct bt_micp_mic_ctlr *mic_ctlr) static void disconnected(struct bt_conn *conn, uint8_t reason) { - struct bt_micp_mic_ctlr *mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + struct bt_micp_mic_ctlr *mic_ctlr = mic_ctlr_get_by_conn(conn); if (mic_ctlr->conn == conn) { micp_mic_ctlr_reset(mic_ctlr); @@ -390,7 +529,7 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi return -EINVAL; } - mic_ctlr = &mic_ctlrs[bt_conn_index(conn)]; + mic_ctlr = mic_ctlr_get_by_conn(conn); (void)memset(&mic_ctlr->discover_params, 0, sizeof(mic_ctlr->discover_params)); @@ -400,19 +539,34 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi static bool initialized; if (!initialized) { - for (int i = 0; i < ARRAY_SIZE(mic_ctlr->aics); i++) { - mic_ctlr->aics[i] = bt_aics_client_free_instance_get(); + for (size_t i = 0U; i < ARRAY_SIZE(mic_ctlrs); i++) { + for (size_t j = 0U; j < ARRAY_SIZE(mic_ctlr->aics); j++) { + static struct bt_aics_cb aics_cb = { + .state = micp_mic_ctlr_aics_state_cb, + .gain_setting = micp_mic_ctlr_aics_gain_setting_cb, + .type = micp_mic_ctlr_aics_type_cb, + .status = micp_mic_ctlr_aics_status_cb, + .description = micp_mic_ctlr_aics_description_cb, + .discover = micp_mic_ctlr_aics_discover_cb, + .set_gain = micp_mic_ctlr_aics_set_gain_cb, + .unmute = micp_mic_ctlr_aics_unmute_cb, + .mute = micp_mic_ctlr_aics_mute_cb, + .set_manual_mode = micp_mic_ctlr_aics_set_manual_mode_cb, + .set_auto_mode = micp_mic_ctlr_aics_set_auto_mode_cb, + }; + + mic_ctlrs[i].aics[j] = bt_aics_client_free_instance_get(); + + if (mic_ctlrs[i].aics[j] == NULL) { + return -ENOMEM; + } - if (mic_ctlr->aics[i] == NULL) { - return -ENOMEM; + bt_aics_client_cb_register(mic_ctlrs[i].aics[j], &aics_cb); } - - bt_aics_client_cb_register(mic_ctlr->aics[i], - &micp_mic_ctlr_cb->aics_cb); } - } - initialized = true; + initialized = true; + } #endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ mic_ctlr->conn = bt_conn_ref(conn); @@ -432,37 +586,25 @@ int bt_micp_mic_ctlr_discover(struct bt_conn *conn, struct bt_micp_mic_ctlr **mi int bt_micp_mic_ctlr_cb_register(struct bt_micp_mic_ctlr_cb *cb) { -#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) - struct bt_aics_cb *aics_cb = NULL; - - if (cb != NULL) { - /* Ensure that the cb->aics_cb.discover is the aics_discover_cb */ - CHECKIF(cb->aics_cb.discover != NULL && - cb->aics_cb.discover != aics_discover_cb) { - LOG_ERR("AICS discover callback shall not be set"); - return -EINVAL; - } - cb->aics_cb.discover = aics_discover_cb; + struct bt_micp_mic_ctlr_cb *tmp; - aics_cb = &cb->aics_cb; + CHECKIF(cb == NULL) { + return -EINVAL; } - for (int i = 0; i < ARRAY_SIZE(mic_ctlrs); i++) { - for (int j = 0; j < ARRAY_SIZE(mic_ctlrs[i].aics); j++) { - struct bt_aics *aics = mic_ctlrs[i].aics[j]; - - if (aics != NULL) { - bt_aics_client_cb_register(aics, aics_cb); - } + SYS_SLIST_FOR_EACH_CONTAINER(&micp_mic_ctlr_cbs, tmp, _node) { + if (tmp == cb) { + LOG_DBG("Already registered"); + return -EALREADY; } } -#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ - micp_mic_ctlr_cb = cb; + sys_slist_append(&micp_mic_ctlr_cbs, &cb->_node); return 0; } +#if defined(CONFIG_BT_MICP_MIC_CTLR_AICS) int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, struct bt_micp_included *included) { @@ -480,6 +622,26 @@ int bt_micp_mic_ctlr_included_get(struct bt_micp_mic_ctlr *mic_ctlr, return 0; } +#endif /* CONFIG_BT_MICP_MIC_CTLR_AICS */ + +struct bt_micp_mic_ctlr *bt_micp_mic_ctlr_get_by_conn(const struct bt_conn *conn) +{ + struct bt_micp_mic_ctlr *mic_ctlr; + + CHECKIF(conn == NULL) { + LOG_DBG("NULL conn pointer"); + return NULL; + } + + mic_ctlr = mic_ctlr_get_by_conn(conn); + if (mic_ctlr->conn == NULL) { + LOG_DBG("conn %p is not associated with microphone controller. Do discovery first", + (void *)conn); + return NULL; + } + + return mic_ctlr; +} int bt_micp_mic_ctlr_conn_get(const struct bt_micp_mic_ctlr *mic_ctlr, struct bt_conn **conn) { diff --git a/subsys/bluetooth/audio/mpl.c b/subsys/bluetooth/audio/mpl.c index cce2403b5b6..111482b3e04 100644 --- a/subsys/bluetooth/audio/mpl.c +++ b/subsys/bluetooth/audio/mpl.c @@ -1,12 +1,16 @@ /* Media player skeleton implementation */ /* - * Copyright (c) 2019 - 2021 Nordic Semiconductor ASA + * Copyright (c) 2019 - 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ +#include + +#include #include +#include #include #include @@ -24,6 +28,9 @@ LOG_MODULE_REGISTER(bt_mpl, CONFIG_BT_MPL_LOG_LEVEL); #define TRACK_STATUS_INVALID 0x00 #define TRACK_STATUS_VALID 0x01 +#define TRACK_POS_WORK_DELAY_MS 1000 +#define TRACK_POS_WORK_DELAY K_MSEC(TRACK_POS_WORK_DELAY_MS) + #define PLAYBACK_SPEED_PARAM_DEFAULT MEDIA_PROXY_PLAYBACK_SPEED_UNITY /* Temporary hardcoded setup for groups, tracks and segments */ @@ -244,6 +251,11 @@ static struct mpl_mediaplayer media_player = { .next_track_set = false }; +static void set_track_position(int32_t position); +static void set_relative_track_position(int32_t rel_pos); +static void do_track_change_notifications(struct mpl_mediaplayer *pl); +static void do_group_change_notifications(struct mpl_mediaplayer *pl); + #ifdef CONFIG_BT_MPL_OBJECTS /* The types of objects we keep in the Object Transfer Service */ @@ -450,7 +462,7 @@ static int add_icon_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON; + const struct bt_uuid *icon_type = BT_UUID_OTS_TYPE_MPL_ICON; static char *icon_name = "Icon"; if (obj.busy) { @@ -488,7 +500,7 @@ static int add_current_track_segments_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT; + const struct bt_uuid *segs_type = BT_UUID_OTS_TYPE_TRACK_SEGMENT; if (obj.busy) { LOG_ERR("Object busy"); @@ -522,7 +534,7 @@ static int add_track_object(struct mpl_track *track) { struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK; + const struct bt_uuid *track_type = BT_UUID_OTS_TYPE_TRACK; int ret; if (obj.busy) { @@ -565,7 +577,7 @@ static int add_parent_group_object(struct mpl_mediaplayer *pl) int ret; struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; + const struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; if (obj.busy) { LOG_ERR("Object busy"); @@ -599,7 +611,7 @@ static int add_group_object(struct mpl_group *group) { struct bt_ots_obj_add_param add_param = {}; struct bt_ots_obj_created_desc created_desc = {}; - struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; + const struct bt_uuid *group_type = BT_UUID_OTS_TYPE_GROUP; int ret; if (obj.busy) { @@ -876,7 +888,7 @@ static struct bt_ots_cb ots_cbs = { /* and do_prev_group() with a generic do_prev() command that can be used at */ /* all levels. Similarly for do_next, do_prev, and so on. */ -void do_prev_segment(struct mpl_mediaplayer *pl) +static void do_prev_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -887,7 +899,7 @@ void do_prev_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_next_segment(struct mpl_mediaplayer *pl) +static void do_next_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -898,7 +910,7 @@ void do_next_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_first_segment(struct mpl_mediaplayer *pl) +static void do_first_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -909,7 +921,7 @@ void do_first_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_last_segment(struct mpl_mediaplayer *pl) +static void do_last_segment(struct mpl_mediaplayer *pl) { LOG_DBG("Segment name before: %s", pl->group->track->segment->name); @@ -920,7 +932,7 @@ void do_last_segment(struct mpl_mediaplayer *pl) LOG_DBG("Segment name after: %s", pl->group->track->segment->name); } -void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) +static void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) { int32_t k; @@ -957,47 +969,48 @@ void do_goto_segment(struct mpl_mediaplayer *pl, int32_t segnum) } LOG_DBG("Segment name after: %s", pl->group->track->segment->name); + + set_track_position(pl->group->track->segment->pos); } -static bool do_prev_track(struct mpl_mediaplayer *pl) +static void do_prev_track(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; - track_changed = true; + pl->track_pos = 0; + do_track_change_notifications(pl); + } else { + /* For previous track, the position is reset to 0 */ + /* even if we stay at the same track (goto start of */ + /* track) */ + set_track_position(0); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } /* Change to next track according to the current track's next track */ -static bool do_next_track_normal_order(struct mpl_mediaplayer *pl) +static void do_next_track_normal_order(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; - track_changed = true; + pl->track_pos = 0; + do_track_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } /* Change to next track when the next track has been explicitly set @@ -1007,13 +1020,11 @@ static bool do_next_track_normal_order(struct mpl_mediaplayer *pl) * * Returns true if the _group_ has been changed, otherwise false */ -static bool do_next_track_next_track_set(struct mpl_mediaplayer *pl) +static void do_next_track_next_track_set(struct mpl_mediaplayer *pl) { - bool group_changed = false; - if (pl->next.group != pl->group) { pl->group = pl->next.group; - group_changed = true; + do_group_change_notifications(pl); } pl->group->track = pl->next.track; @@ -1021,11 +1032,21 @@ static bool do_next_track_next_track_set(struct mpl_mediaplayer *pl) pl->next.track = NULL; pl->next.group = NULL; pl->next_track_set = false; + pl->track_pos = 0; + do_track_change_notifications(pl); +} - return group_changed; +static void do_next_track(struct mpl_mediaplayer *pl) +{ + if (pl->next_track_set) { + LOG_DBG("Next track set"); + do_next_track_next_track_set(pl); + } else { + do_next_track_normal_order(pl); + } } -static bool do_first_track(struct mpl_mediaplayer *pl) +static void do_first_track(struct mpl_mediaplayer *pl, bool group_change) { bool track_changed = false; @@ -1033,33 +1054,44 @@ static bool do_first_track(struct mpl_mediaplayer *pl) LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - if (pl->group->track->prev != NULL) { + /* Set first track */ + while (pl->group->track->prev != NULL) { pl->group->track = pl->group->track->prev; track_changed = true; } - while (pl->group->track->prev != NULL) { - pl->group->track = pl->group->track->prev; + + /* Notify about new track */ + if (group_change || track_changed) { + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + /* For first track, the position is reset to 0 even */ + /* if we stay at the same track (goto start of track) */ + set_track_position(0); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } -static bool do_last_track(struct mpl_mediaplayer *pl) +static void do_last_track(struct mpl_mediaplayer *pl) { - bool track_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID before: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; - track_changed = true; + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + + /* For last track, the position is reset to 0 even */ + /* if we stay at the same track (goto start of track) */ + set_track_position(0); } + while (pl->group->track->next != NULL) { pl->group->track = pl->group->track->next; } @@ -1067,11 +1099,9 @@ static bool do_last_track(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Track ID after: ", pl->group->track->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return track_changed; } -static bool do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) +static void do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) { int32_t count = 0; int32_t k; @@ -1116,33 +1146,35 @@ static bool do_goto_track(struct mpl_mediaplayer *pl, int32_t tracknum) /* The track has changed if we have moved more in one direction */ /* than in the other */ - return (count != 0); + if (count != 0) { + media_player.track_pos = 0; + do_track_change_notifications(&media_player); + } else { + /* For goto track, the position is reset to 0 */ + /* even if we stay at the same track (goto */ + /* start of track) */ + set_track_position(0); + } } - -static bool do_prev_group(struct mpl_mediaplayer *pl) +static void do_prev_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->prev != NULL) { pl->group = pl->group->prev; - group_changed = true; + do_group_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_next_group(struct mpl_mediaplayer *pl) +static void do_next_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); @@ -1150,28 +1182,25 @@ static bool do_next_group(struct mpl_mediaplayer *pl) if (pl->group->next != NULL) { pl->group = pl->group->next; - group_changed = true; + do_group_change_notifications(pl); } #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_first_group(struct mpl_mediaplayer *pl) +static void do_first_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->prev != NULL) { pl->group = pl->group->prev; - group_changed = true; + do_group_change_notifications(pl); } + while (pl->group->prev != NULL) { pl->group = pl->group->prev; } @@ -1179,22 +1208,19 @@ static bool do_first_group(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_last_group(struct mpl_mediaplayer *pl) +static void do_last_group(struct mpl_mediaplayer *pl) { - bool group_changed = false; - #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID before: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ if (pl->group->next != NULL) { pl->group = pl->group->next; - group_changed = true; + do_group_change_notifications(pl); } + while (pl->group->next != NULL) { pl->group = pl->group->next; } @@ -1202,11 +1228,9 @@ static bool do_last_group(struct mpl_mediaplayer *pl) #ifdef CONFIG_BT_MPL_OBJECTS LOG_DBG_OBJ_ID("Group ID after: ", pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ - - return group_changed; } -static bool do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) +static void do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) { int32_t count = 0; int32_t k; @@ -1251,10 +1275,12 @@ static bool do_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) /* The group has changed if we have moved more in one direction */ /* than in the other */ - return (count != 0); + if (count != 0) { + do_group_change_notifications(pl); + } } -void do_track_change_notifications(struct mpl_mediaplayer *pl) +static void do_track_change_notifications(struct mpl_mediaplayer *pl) { media_proxy_pl_track_changed_cb(); media_proxy_pl_track_title_cb(pl->group->track->title); @@ -1271,132 +1297,82 @@ void do_track_change_notifications(struct mpl_mediaplayer *pl) #endif /* CONFIG_BT_MPL_OBJECTS */ } -void do_group_change_notifications(struct mpl_mediaplayer *pl) +static void do_group_change_notifications(struct mpl_mediaplayer *pl) { #ifdef CONFIG_BT_MPL_OBJECTS media_proxy_pl_current_group_id_cb(pl->group->id); #endif /* CONFIG_BT_MPL_OBJECTS */ } -void do_full_prev_group(struct mpl_mediaplayer *pl) +static void do_full_prev_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on first group) */ - if (do_prev_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); - } + do_prev_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl, true); } -void do_full_next_group(struct mpl_mediaplayer *pl) +static void do_full_next_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on last group) */ - if (do_next_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); - } + do_next_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl, true); } -void do_full_first_group(struct mpl_mediaplayer *pl) +static void do_full_first_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on first group) */ - if (do_first_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); - } + do_first_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl, true); } -void do_full_last_group(struct mpl_mediaplayer *pl) +static void do_full_last_group(struct mpl_mediaplayer *pl) { /* Change the group (if not already on last group) */ - if (do_last_group(pl)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); - } + do_last_group(pl); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl, true); } -void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) +static void do_full_goto_group(struct mpl_mediaplayer *pl, int32_t groupnum) { /* Change the group (if not already on given group) */ - if (do_goto_group(pl, groupnum)) { - do_group_change_notifications(pl); - /* If group change, also go to first track in group. */ - /* Notify the track info in all cases - it is a track */ - /* change for the player even if the group was set to */ - /* this track already. */ - (void) do_first_track(pl); - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no group change, still switch to first track, if needed */ - } else if (do_first_track(pl)) { - pl->track_pos = 0; - do_track_change_notifications(pl); - /* If no track change, still reset track position, if needed */ - } else if (pl->track_pos != 0) { - pl->track_pos = 0; - media_proxy_pl_track_position_cb(pl->track_pos); + do_goto_group(pl, groupnum); + + /* Whether there is a group change or not, we always go to the first track */ + do_first_track(pl, true); +} + +static void mpl_set_state(uint8_t state) +{ + switch (state) { + case MEDIA_PROXY_STATE_INACTIVE: + case MEDIA_PROXY_STATE_PLAYING: + case MEDIA_PROXY_STATE_PAUSED: + (void)k_work_cancel_delayable(&media_player.pos_work); + break; + case MEDIA_PROXY_STATE_SEEKING: + (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); + break; + default: + __ASSERT(false, "Invalid state: %u", state); } + + media_player.state = state; + media_proxy_pl_media_state_cb(media_player.state); } /* Command handlers (state machines) */ -void inactive_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t inactive_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { @@ -1415,209 +1391,114 @@ void inactive_state_command_handler(const struct mpl_cmd *command, case MEDIA_PROXY_OP_FIRST_SEGMENT: case MEDIA_PROXY_OP_LAST_SEGMENT: case MEDIA_PROXY_OP_GOTO_SEGMENT: - ntf->result_code = MEDIA_PROXY_CMD_PLAYER_INACTIVE; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_PLAYER_INACTIVE; break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_prev_track(&media_player); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_NEXT_TRACK: /* TODO: * The case where the next track has been set explicitly breaks somewhat * with the "next" order hardcoded into the group and track structure */ - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); + /* For next track, the position is kept if the track */ /* does not change */ - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_first_track(&media_player, false); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_last_track(&media_player); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + do_goto_track(&media_player, command->param); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void playing_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t playing_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: /* Continue playing - i.e. do nothing */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FAST_REWIND: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in playing state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: - media_player.track_pos = 0; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(0); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_relative_track_position(command->param); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than */ @@ -1626,224 +1507,122 @@ void playing_state_command_handler(const struct mpl_cmd *command, media_player.group->track->segment->pos) { do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_prev_track(&media_player); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } - /* For next track, the position is kept if the track */ - /* does not change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_next_track(&media_player); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_first_track(&media_player, false); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_last_track(&media_player); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + do_goto_track(&media_player, command->param); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void paused_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t paused_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: - media_player.state = MEDIA_PROXY_STATE_PLAYING; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PLAYING); break; case MEDIA_PROXY_OP_PAUSE: /* No change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = -MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* We're in paused state, seeking speed must have been zero */ media_player.seeking_speed_factor = MPL_SEEKING_SPEED_FACTOR_STEP; - media_player.state = MEDIA_PROXY_STATE_SEEKING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_SEEKING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: - media_player.track_pos = 0; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(0); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_relative_track_position(command->param); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than 5 seconds */ @@ -1854,205 +1633,125 @@ void paused_state_command_handler(const struct mpl_cmd *command, do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_track_position(media_player.group->track->segment->pos); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: if (media_player.group->track->segment != NULL) { do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_track_position(media_player.group->track->segment->pos); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: if (media_player.group->track->segment != NULL) { do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_track_position(media_player.group->track->segment->pos); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_SEGMENT: if (media_player.group->track->segment != NULL) { do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_track_position(media_player.group->track->segment->pos); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param && media_player.group->track->segment != NULL) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_prev_track(&media_player); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_first_track(&media_player, false); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + do_last_track(&media_player); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + do_goto_track(&media_player, command->param); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); + break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void seeking_state_command_handler(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) +static uint8_t seeking_state_command_handler(const struct mpl_cmd *command) { + uint8_t result_code = MEDIA_PROXY_CMD_SUCCESS; + LOG_DBG("Command opcode: %d", command->opcode); if (IS_ENABLED(CONFIG_BT_MPL_LOG_LEVEL_DBG)) { if (command->use_param) { LOG_DBG("Command parameter: %d", command->param); } } + switch (command->opcode) { case MEDIA_PROXY_OP_PLAY: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PLAYING; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PLAYING); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PAUSE: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; /* TODO: Set track and track position */ - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_REWIND: /* TODO: Here, and for FAST_FORWARD */ @@ -2066,8 +1765,6 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.seeking_speed_factor -= MPL_SEEKING_SPEED_FACTOR_STEP; media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_FAST_FORWARD: /* Highest value allowed by spec is 64, notify on change only */ @@ -2076,36 +1773,20 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.seeking_speed_factor += MPL_SEEKING_SPEED_FACTOR_STEP; media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_STOP: media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.track_pos = 0; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); + set_track_position(0); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); media_proxy_pl_seeking_speed_cb(media_player.seeking_speed_factor); - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_MOVE_RELATIVE: if (command->use_param) { - /* Keep within track - i.e. in the range 0 - duration */ - if (command->param > - media_player.group->track->duration - media_player.track_pos) { - media_player.track_pos = media_player.group->track->duration; - } else if (command->param < -media_player.track_pos) { - media_player.track_pos = 0; - } else { - media_player.track_pos += command->param; - } - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + set_relative_track_position(command->param); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_track_position_cb(media_player.track_pos); - media_proxy_pl_command_cb(ntf); + break; case MEDIA_PROXY_OP_PREV_SEGMENT: /* Switch to previous segment if we are less than 5 seconds */ @@ -2114,191 +1795,101 @@ void seeking_state_command_handler(const struct mpl_cmd *command, media_player.group->track->segment->pos) { do_prev_segment(&media_player); } - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_NEXT_SEGMENT: do_next_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_FIRST_SEGMENT: do_first_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_LAST_SEGMENT: do_last_segment(&media_player); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + set_track_position(media_player.group->track->segment->pos); break; case MEDIA_PROXY_OP_GOTO_SEGMENT: if (command->use_param) { if (command->param != 0) { do_goto_segment(&media_player, command->param); - media_player.track_pos = media_player.group->track->segment->pos; - media_proxy_pl_track_position_cb(media_player.track_pos); } /* If the argument to "goto segment" is zero, */ /* the segment shall stay the same, and the */ /* track position shall not change. */ - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_TRACK: - if (do_prev_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For previous track, the position is reset to 0 */ - /* even if we stay at the same track (goto start of */ - /* track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } + do_prev_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_NEXT_TRACK: - if (media_player.next_track_set) { - LOG_DBG("Next track set"); - if (do_next_track_next_track_set(&media_player)) { - do_group_change_notifications(&media_player); - } - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else if (do_next_track_normal_order(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } + do_next_track(&media_player); /* For next track, the position is kept if the track */ /* does not change */ media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_TRACK: - if (do_first_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For first track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } + do_first_track(&media_player, false); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_LAST_TRACK: - if (do_last_track(&media_player)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For last track, the position is reset to 0 even */ - /* if we stay at the same track (goto start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } + do_last_track(&media_player); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_GOTO_TRACK: if (command->use_param) { - if (do_goto_track(&media_player, command->param)) { - media_player.track_pos = 0; - do_track_change_notifications(&media_player); - } else { - /* For goto track, the position is reset to 0 */ - /* even if we stay at the same track (goto */ - /* start of track) */ - media_player.track_pos = 0; - media_proxy_pl_track_position_cb(media_player.track_pos); - } + do_goto_track(&media_player, command->param); media_player.seeking_speed_factor = MEDIA_PROXY_SEEKING_SPEED_FACTOR_ZERO; - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; case MEDIA_PROXY_OP_PREV_GROUP: do_full_prev_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_NEXT_GROUP: do_full_next_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_FIRST_GROUP: do_full_first_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_LAST_GROUP: do_full_last_group(&media_player); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; - media_proxy_pl_command_cb(ntf); + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); break; case MEDIA_PROXY_OP_GOTO_GROUP: if (command->use_param) { do_full_goto_group(&media_player, command->param); - media_player.state = MEDIA_PROXY_STATE_PAUSED; - media_proxy_pl_media_state_cb(media_player.state); - ntf->result_code = MEDIA_PROXY_CMD_SUCCESS; + mpl_set_state(MEDIA_PROXY_STATE_PAUSED); } else { - ntf->result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; + result_code = MEDIA_PROXY_CMD_CANNOT_BE_COMPLETED; } - media_proxy_pl_command_cb(ntf); break; default: LOG_DBG("Invalid command: %d", command->opcode); - ntf->result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; - media_proxy_pl_command_cb(ntf); + result_code = MEDIA_PROXY_CMD_NOT_SUPPORTED; break; } + + return result_code; } -void (*command_handlers[MEDIA_PROXY_STATE_LAST])(const struct mpl_cmd *command, - struct mpl_cmd_ntf *ntf) = { +static uint8_t (*command_handlers[MEDIA_PROXY_STATE_LAST])(const struct mpl_cmd *command) = { inactive_state_command_handler, playing_state_command_handler, paused_state_command_handler, - seeking_state_command_handler + seeking_state_command_handler, }; #ifdef CONFIG_BT_MPL_OBJECTS @@ -2377,39 +1968,39 @@ static bool find_group_by_id(const struct mpl_mediaplayer *pl, uint64_t id, } #endif /* CONFIG_BT_MPL_OBJECTS */ -const char *get_player_name(void) +static const char *get_player_name(void) { return media_player.name; } #ifdef CONFIG_BT_MPL_OBJECTS -uint64_t get_icon_id(void) +static uint64_t get_icon_id(void) { return media_player.icon_id; } #endif /* CONFIG_BT_MPL_OBJECTS */ -const char *get_icon_url(void) +static const char *get_icon_url(void) { return media_player.icon_url; } -const char *get_track_title(void) +static const char *get_track_title(void) { return media_player.group->track->title; } -int32_t get_track_duration(void) +static int32_t get_track_duration(void) { return media_player.group->track->duration; } -int32_t get_track_position(void) +static int32_t get_track_position(void) { return media_player.track_pos; } -void set_track_position(int32_t position) +static void set_track_position(int32_t position) { int32_t old_pos = media_player.track_pos; int32_t new_pos; @@ -2435,19 +2026,43 @@ void set_track_position(int32_t position) LOG_DBG("Pos. given: %d, resulting pos.: %d (duration is %d)", position, new_pos, media_player.group->track->duration); - if (new_pos != old_pos) { + /* Notify when the position changes when not in the playing state, or if the position is set + * to 0 which is a special value that typically indicates that the track has stopped or + * changed. Since this might occur when media_player.group->track->duration is still 0, we + * should always notify this value. + */ + if (new_pos != old_pos || new_pos == 0) { /* Set new position and notify it */ media_player.track_pos = new_pos; - media_proxy_pl_track_position_cb(new_pos); + + /* MCS 1.0, section 3.7.1, states: + * to avoid an excessive number of notifications, the Track Position should + * not be notified when the Media State is set to “Playing” and playback happens + * at a constant speed. + */ + if (media_player.state != MEDIA_PROXY_STATE_PLAYING) { + media_proxy_pl_track_position_cb(new_pos); + } } } -int8_t get_playback_speed(void) +static void set_relative_track_position(int32_t rel_pos) +{ + int64_t pos; + + pos = media_player.track_pos + rel_pos; + /* Clamp to allowed values */ + pos = CLAMP(pos, 0, media_player.group->track->duration); + + set_track_position((int32_t)pos); +} + +static int8_t get_playback_speed(void) { return media_player.playback_speed_param; } -void set_playback_speed(int8_t speed) +static void set_playback_speed(int8_t speed) { /* Set new speed parameter and notify, if different from current */ if (speed != media_player.playback_speed_param) { @@ -2456,23 +2071,23 @@ void set_playback_speed(int8_t speed) } } -int8_t get_seeking_speed(void) +static int8_t get_seeking_speed(void) { return media_player.seeking_speed_factor; } #ifdef CONFIG_BT_MPL_OBJECTS -uint64_t get_track_segments_id(void) +static uint64_t get_track_segments_id(void) { return media_player.group->track->segments_id; } -uint64_t get_current_track_id(void) +static uint64_t get_current_track_id(void) { return media_player.group->track->id; } -void set_current_track_id(uint64_t id) +static void set_current_track_id(uint64_t id) { struct mpl_group *group; struct mpl_track *track; @@ -2502,7 +2117,7 @@ void set_current_track_id(uint64_t id) */ } -uint64_t get_next_track_id(void) +static uint64_t get_next_track_id(void) { /* If the next track has been set explicitly */ if (media_player.next_track_set) { @@ -2518,7 +2133,7 @@ uint64_t get_next_track_id(void) return MPL_NO_TRACK_ID; } -void set_next_track_id(uint64_t id) +static void set_next_track_id(uint64_t id) { struct mpl_group *group; struct mpl_track *track; @@ -2537,20 +2152,19 @@ void set_next_track_id(uint64_t id) LOG_DBG("Track not found"); } -uint64_t get_parent_group_id(void) +static uint64_t get_parent_group_id(void) { return media_player.group->parent->id; } -uint64_t get_current_group_id(void) +static uint64_t get_current_group_id(void) { return media_player.group->id; } -void set_current_group_id(uint64_t id) +static void set_current_group_id(uint64_t id) { struct mpl_group *group; - bool track_change; LOG_DBG_OBJ_ID("Group ID to set: ", id); @@ -2562,10 +2176,7 @@ void set_current_group_id(uint64_t id) do_group_change_notifications(&media_player); /* And change to first track in group */ - track_change = do_first_track(&media_player); - if (track_change) { - do_track_change_notifications(&media_player); - } + do_first_track(&media_player, false); } return; } @@ -2574,12 +2185,12 @@ void set_current_group_id(uint64_t id) } #endif /* CONFIG_BT_MPL_OBJECTS */ -uint8_t get_playing_order(void) +static uint8_t get_playing_order(void) { return media_player.playing_order; } -void set_playing_order(uint8_t order) +static void set_playing_order(uint8_t order) { if (order != media_player.playing_order) { if (BIT(order - 1) & media_player.playing_orders_supported) { @@ -2589,17 +2200,17 @@ void set_playing_order(uint8_t order) } } -uint16_t get_playing_orders_supported(void) +static uint16_t get_playing_orders_supported(void) { return media_player.playing_orders_supported; } -uint8_t get_media_state(void) +static uint8_t get_media_state(void) { return media_player.state; } -void send_command(const struct mpl_cmd *command) +static void send_command(const struct mpl_cmd *command) { struct mpl_cmd_ntf ntf; @@ -2611,13 +2222,15 @@ void send_command(const struct mpl_cmd *command) if (media_player.state < MEDIA_PROXY_STATE_LAST) { ntf.requested_opcode = command->opcode; - command_handlers[media_player.state](command, &ntf); + ntf.result_code = command_handlers[media_player.state](command); + + media_proxy_pl_command_cb(&ntf); } else { LOG_DBG("INVALID STATE"); } } -uint32_t get_commands_supported(void) +static uint32_t get_commands_supported(void) { return media_player.opcodes_supported; } @@ -2676,7 +2289,7 @@ static void parse_search(const struct mpl_search *search) media_proxy_pl_search_results_id_cb(media_player.search_results_id); } -void send_search(const struct mpl_search *search) +static void send_search(const struct mpl_search *search) { if (search->len > SEARCH_LEN_MAX) { LOG_WRN("Search too long: %d", search->len); @@ -2687,17 +2300,36 @@ void send_search(const struct mpl_search *search) parse_search(search); } -uint64_t get_search_results_id(void) +static uint64_t get_search_results_id(void) { return media_player.search_results_id; } #endif /* CONFIG_BT_MPL_OBJECTS */ -uint8_t get_content_ctrl_id(void) +static uint8_t get_content_ctrl_id(void) { return media_player.content_ctrl_id; } +static void pos_work_cb(struct k_work *work) +{ + const int32_t pos_diff_cs = TRACK_POS_WORK_DELAY_MS / 10; /* position is in centiseconds*/ + + if (media_player.state == MEDIA_PROXY_STATE_SEEKING) { + /* When seeking, apply the seeking speed factor */ + set_relative_track_position(pos_diff_cs * media_player.seeking_speed_factor); + } else if (media_player.state == MEDIA_PROXY_STATE_PLAYING) { + set_relative_track_position(pos_diff_cs); + } + + if (media_player.track_pos == media_player.group->track->duration) { + /* Go to next track */ + do_next_track(&media_player); + } + + (void)k_work_schedule(&media_player.pos_work, TRACK_POS_WORK_DELAY); +} + int media_proxy_pl_init(void) { static bool initialized; @@ -2799,6 +2431,8 @@ int media_proxy_pl_init(void) return ret; } + k_work_init_delayable(&media_player.pos_work, pos_work_cb); + initialized = true; return 0; } @@ -2902,8 +2536,7 @@ void mpl_test_unset_parent_group(void) void mpl_test_media_state_set(uint8_t state) { - media_player.state = state; - media_proxy_pl_media_state_cb(media_player.state); + mpl_set_state(state); } void mpl_test_player_name_changed_cb(void) diff --git a/subsys/bluetooth/audio/mpl_internal.h b/subsys/bluetooth/audio/mpl_internal.h index b66b83abed4..c8a553da216 100644 --- a/subsys/bluetooth/audio/mpl_internal.h +++ b/subsys/bluetooth/audio/mpl_internal.h @@ -89,6 +89,8 @@ struct mpl_mediaplayer { struct mpl_track *track; /* The track explicitly set as next track */ struct mpl_group *group; /* The group of the set track */ } next; + + struct k_work_delayable pos_work; }; diff --git a/subsys/bluetooth/audio/pacs.c b/subsys/bluetooth/audio/pacs.c index 2ce6db23a9f..64f750523ff 100644 --- a/subsys/bluetooth/audio/pacs.c +++ b/subsys/bluetooth/audio/pacs.c @@ -41,28 +41,17 @@ LOG_MODULE_REGISTER(bt_pacs, CONFIG_BT_PACS_LOG_LEVEL); #if defined(CONFIG_BT_PAC_SRC) static uint32_t pacs_src_location; static sys_slist_t src_pacs_list = SYS_SLIST_STATIC_INIT(&src_pacs_list); +static uint16_t src_supported_contexts; #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SNK) static uint32_t pacs_snk_location; static sys_slist_t snk_pacs_list = SYS_SLIST_STATIC_INIT(&snk_pacs_list); +static uint16_t snk_supported_contexts; #endif /* CONFIG_BT_PAC_SNK */ -#if defined(CONFIG_BT_PAC_SNK) -static uint16_t snk_available_contexts; -static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; -#else -static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static uint16_t snk_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -#endif /* CONFIG_BT_PAC_SNK */ - -#if defined(CONFIG_BT_PAC_SRC) -static uint16_t src_available_contexts; -static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; -#else static uint16_t src_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -static uint16_t src_supported_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; -#endif /* CONFIG_BT_PAC_SRC */ +static uint16_t snk_available_contexts = BT_AUDIO_CONTEXT_TYPE_PROHIBITED; enum { FLAG_ACTIVE, @@ -78,6 +67,16 @@ enum { static struct pacs_client { bt_addr_le_t addr; +#if defined(CONFIG_BT_PAC_SNK) + /* Sink Available Contexts override value */ + uint16_t *snk_available_contexts; +#endif /* CONFIG_BT_PAC_SNK */ + +#if defined(CONFIG_BT_PAC_SRC) + /* Source Available Contexts override value */ + uint16_t *src_available_contexts; +#endif /* CONFIG_BT_PAC_SRC */ + /* Pending notification flags */ ATOMIC_DEFINE(flags, FLAG_NUM); } clients[CONFIG_BT_MAX_PAIRED]; @@ -87,9 +86,6 @@ static atomic_t notify_rdy; static K_SEM_DEFINE(read_buf_sem, 1, 1); NET_BUF_SIMPLE_DEFINE_STATIC(read_buf, BT_ATT_MAX_ATTRIBUTE_LEN); -#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) -static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir); -#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE*/ static int pacs_gatt_notify(struct bt_conn *conn, const struct bt_uuid *uuid, const struct bt_gatt_attr *attr, @@ -104,6 +100,20 @@ struct pac_records_build_data { struct net_buf_simple *buf; }; +static struct pacs_client *client_lookup_conn(const struct bt_conn *conn) +{ + __ASSERT_NO_MSG(conn != NULL); + + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (atomic_test_bit(clients[i].flags, FLAG_ACTIVE) && + bt_addr_le_eq(&clients[i].addr, bt_conn_get_dst(conn))) { + return &clients[i]; + } + } + + return NULL; +} + static void pacs_set_notify_bit(int bit) { for (size_t i = 0U; i < ARRAY_SIZE(clients); i++) { @@ -189,13 +199,46 @@ static void available_context_cfg_changed(const struct bt_gatt_attr *attr, uint1 LOG_DBG("attr %p value 0x%04x", attr, value); } +static enum bt_audio_context pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir) +{ + const struct pacs_client *client; + + client = client_lookup_conn(conn); + if (client == NULL) { + LOG_DBG("No client context for conn %p", (void *)conn); + return bt_pacs_get_available_contexts(dir); + } + + switch (dir) { + case BT_AUDIO_DIR_SINK: +#if defined(CONFIG_BT_PAC_SNK) + if (client->snk_available_contexts != NULL) { + return POINTER_TO_UINT(client->snk_available_contexts); + } +#endif /* CONFIG_BT_PAC_SNK */ + break; + case BT_AUDIO_DIR_SOURCE: +#if defined(CONFIG_BT_PAC_SRC) + if (client->src_available_contexts != NULL) { + return POINTER_TO_UINT(client->src_available_contexts); + } +#endif /* CONFIG_BT_PAC_SRC */ + break; + } + + return bt_pacs_get_available_contexts(dir); +} + static ssize_t available_contexts_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_available_contexts), - .src = sys_cpu_to_le16(src_available_contexts), + .snk = sys_cpu_to_le16( + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16( + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -212,13 +255,31 @@ static void supported_context_cfg_changed(const struct bt_gatt_attr *attr, } #endif /* CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE */ +static uint16_t supported_context_get(enum bt_audio_dir dir) +{ + switch (dir) { +#if defined(CONFIG_BT_PAC_SNK) + case BT_AUDIO_DIR_SINK: + return snk_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; +#endif /* CONFIG_BT_PAC_SNK */ +#if defined(CONFIG_BT_PAC_SRC) + case BT_AUDIO_DIR_SOURCE: + return src_supported_contexts | BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED; +#endif /* CONFIG_BT_PAC_SRC */ + default: + break; + } + + return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; +} + static ssize_t supported_context_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_supported_contexts), - .src = sys_cpu_to_le16(src_supported_contexts), + .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)), }; LOG_DBG("conn %p attr %p buf %p len %u offset %u", conn, attr, buf, len, offset); @@ -315,28 +376,6 @@ static void snk_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) LOG_DBG("attr %p value 0x%04x", attr, value); } #endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ - -static inline int set_snk_available_contexts(uint16_t contexts) -{ - return set_available_contexts(contexts, &snk_available_contexts, - snk_supported_contexts); -} - -static inline int set_snk_supported_contexts(uint16_t contexts) -{ - return set_supported_contexts(contexts, &snk_supported_contexts, - &snk_available_contexts); -} -#else -static inline int set_snk_available_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} - -static inline int set_snk_supported_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SNK */ #if defined(CONFIG_BT_PAC_SNK_LOC) @@ -397,7 +436,7 @@ static ssize_t snk_loc_write(struct bt_conn *conn, } location = (enum bt_audio_location)sys_get_le32(data); - if (location > BT_AUDIO_LOCATION_MASK || location == 0) { + if (location > BT_AUDIO_LOCATION_MASK) { LOG_DBG("Invalid location value: 0x%08X", location); return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } @@ -442,28 +481,6 @@ static void src_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value) LOG_DBG("attr %p value 0x%04x", attr, value); } #endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ - -static inline int set_src_available_contexts(uint16_t contexts) -{ - return set_available_contexts(contexts, &src_available_contexts, - src_supported_contexts); -} - -static inline int set_src_supported_contexts(uint16_t contexts) -{ - return set_supported_contexts(contexts, &src_supported_contexts, - &src_available_contexts); -} -#else -static inline int set_src_available_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} - -static inline int set_src_supported_contexts(uint16_t contexts) -{ - return -ENOTSUP; -} #endif /* CONFIG_BT_PAC_SRC */ #if defined(CONFIG_BT_PAC_SRC_LOC) @@ -524,7 +541,7 @@ static ssize_t src_loc_write(struct bt_conn *conn, } location = (enum bt_audio_location)sys_get_le32(data); - if (location > BT_AUDIO_LOCATION_MASK || location == 0) { + if (location > BT_AUDIO_LOCATION_MASK) { LOG_DBG("Invalid location value: 0x%08X", location); return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED); } @@ -645,6 +662,7 @@ BT_GATT_SERVICE_DEFINE(pacs_svc, BT_PAC_SUPPORTED_CONTEXT(supported_context_read) ); +#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) { uint32_t location_le; @@ -652,21 +670,17 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) const struct bt_uuid *uuid; switch (dir) { - case BT_AUDIO_DIR_SINK: #if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) + case BT_AUDIO_DIR_SINK: location_le = sys_cpu_to_le32(pacs_snk_location); uuid = pacs_snk_loc_uuid; break; -#else - return -ENOTSUP; #endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ - case BT_AUDIO_DIR_SOURCE: #if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) + case BT_AUDIO_DIR_SOURCE: location_le = sys_cpu_to_le32(pacs_src_location); uuid = pacs_src_loc_uuid; break; -#else - return -ENOTSUP; #endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ default: return -EINVAL; @@ -680,7 +694,9 @@ static int pac_notify_loc(struct bt_conn *conn, enum bt_audio_dir dir) return 0; } +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE || CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ +#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) || defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) { int err = 0; @@ -727,12 +743,15 @@ static int pac_notify(struct bt_conn *conn, enum bt_audio_dir dir) return 0; } } +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE || CONFIG_BT_PAC_SRC_NOTIFIABLE */ static int available_contexts_notify(struct bt_conn *conn) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_available_contexts), - .src = sys_cpu_to_le16(src_available_contexts), + .snk = sys_cpu_to_le16( + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16( + pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE)), }; int err; @@ -749,8 +768,8 @@ static int available_contexts_notify(struct bt_conn *conn) static int supported_contexts_notify(struct bt_conn *conn) { struct bt_pacs_context context = { - .snk = sys_cpu_to_le16(snk_supported_contexts), - .src = sys_cpu_to_le16(src_supported_contexts), + .snk = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SINK)), + .src = sys_cpu_to_le16(supported_context_get(BT_AUDIO_DIR_SOURCE)), }; int err; @@ -804,7 +823,7 @@ static int pacs_gatt_notify(struct bt_conn *conn, static void notify_cb(struct bt_conn *conn, void *data) { - struct pacs_client *client = &clients[bt_conn_index(conn)]; + struct pacs_client *client; struct bt_conn_info info; int err = 0; @@ -821,44 +840,55 @@ static void notify_cb(struct bt_conn *conn, void *data) return; } + client = client_lookup_conn(conn); + if (client == NULL) { + return; + } + /* Check if we have unverified notifications in progress */ if (atomic_get(¬ify_rdy)) { return; } - if (IS_ENABLED(CONFIG_BT_PAC_SNK_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) { +#if defined(CONFIG_BT_PAC_SNK_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SINK_PAC_CHANGED)) { LOG_DBG("Notifying Sink PAC"); err = pac_notify(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_PAC_CHANGED); } } +#endif /* CONFIG_BT_PAC_SNK_NOTIFIABLE */ - if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) { +#if defined(CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Sink Audio Location"); err = pac_notify_loc(conn, BT_AUDIO_DIR_SINK); if (!err) { atomic_clear_bit(client->flags, FLAG_SINK_AUDIO_LOCATIONS_CHANGED); } } - if (IS_ENABLED(CONFIG_BT_PAC_SRC_NOTIFIABLE) && - atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) { +#endif /* CONFIG_BT_PAC_SNK_LOC_NOTIFIABLE */ + +#if defined(CONFIG_BT_PAC_SRC_NOTIFIABLE) + if (atomic_test_bit(client->flags, FLAG_SOURCE_PAC_CHANGED)) { LOG_DBG("Notifying Source PAC"); err = pac_notify(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_PAC_CHANGED); } } - if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) && - atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) { +#endif /* CONFIG_BT_PAC_SRC_NOTIFIABLE */ + +#if defined(CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE) + if (atomic_test_and_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED)) { LOG_DBG("Notifying Source Audio Location"); err = pac_notify_loc(conn, BT_AUDIO_DIR_SOURCE); if (!err) { atomic_clear_bit(client->flags, FLAG_SOURCE_AUDIO_LOCATIONS_CHANGED); } } +#endif /* CONFIG_BT_PAC_SRC_LOC_NOTIFIABLE */ if (atomic_test_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED)) { LOG_DBG("Notifying Available Contexts"); @@ -957,8 +987,43 @@ static void pacs_security_changed(struct bt_conn *conn, bt_security_t level, } } +static void pacs_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct pacs_client *client; + + client = client_lookup_conn(conn); + if (client == NULL) { + return; + } + +#if defined(CONFIG_BT_PAC_SNK) + if (client->snk_available_contexts != NULL) { + uint16_t old = POINTER_TO_UINT(client->snk_available_contexts); + uint16_t new; + + client->snk_available_contexts = NULL; + new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SINK); + + atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); + } +#endif /* CONFIG_BT_PAC_SNK */ + +#if defined(CONFIG_BT_PAC_SRC) + if (client->src_available_contexts != NULL) { + uint16_t old = POINTER_TO_UINT(client->src_available_contexts); + uint16_t new; + + client->src_available_contexts = NULL; + new = pacs_get_available_contexts_for_conn(conn, BT_AUDIO_DIR_SOURCE); + + atomic_set_bit_to(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED, old != new); + } +#endif /* CONFIG_BT_PAC_SRC */ +} + static struct bt_conn_cb conn_callbacks = { .security_changed = pacs_security_changed, + .disconnected = pacs_disconnected, }; static struct bt_conn_auth_info_cb auth_callbacks = { @@ -966,19 +1031,6 @@ static struct bt_conn_auth_info_cb auth_callbacks = { .bond_deleted = pacs_bond_deleted }; -bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context) -{ - if (dir == BT_AUDIO_DIR_SOURCE) { - return (context & src_available_contexts) == context; - } - - if (dir == BT_AUDIO_DIR_SINK) { - return (context & snk_available_contexts) == context; - } - - return false; -} - void bt_pacs_cap_foreach(enum bt_audio_dir dir, bt_pacs_cap_foreach_func_t func, void *user_data) { sys_slist_t *pac; @@ -1118,24 +1170,104 @@ int bt_pacs_set_available_contexts(enum bt_audio_dir dir, enum bt_audio_context { switch (dir) { case BT_AUDIO_DIR_SINK: - return set_snk_available_contexts(contexts); + return set_available_contexts(contexts, &snk_available_contexts, + supported_context_get(dir)); case BT_AUDIO_DIR_SOURCE: - return set_src_available_contexts(contexts); + return set_available_contexts(contexts, &src_available_contexts, + supported_context_get(dir)); } return -EINVAL; } +int bt_pacs_conn_set_available_contexts_for_conn(struct bt_conn *conn, enum bt_audio_dir dir, + enum bt_audio_context *contexts) +{ + enum bt_audio_context old = pacs_get_available_contexts_for_conn(conn, dir); + struct bt_conn_info info = { 0 }; + struct pacs_client *client; + int err; + + client = client_lookup_conn(conn); + if (client == NULL) { + return -ENOENT; + } + + err = bt_conn_get_info(conn, &info); + if (err < 0) { + LOG_ERR("Could not get conn info: %d", err); + return err; + } + + switch (dir) { +#if defined(CONFIG_BT_PAC_SNK) + case BT_AUDIO_DIR_SINK: + if (contexts != NULL) { + client->snk_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->snk_available_contexts = NULL; + } + + break; +#endif /* CONFIG_BT_PAC_SNK */ +#if defined(CONFIG_BT_PAC_SRC) + case BT_AUDIO_DIR_SOURCE: + if (contexts != NULL) { + client->src_available_contexts = UINT_TO_POINTER(*contexts); + } else { + client->src_available_contexts = NULL; + } + + break; +#endif /* CONFIG_BT_PAC_SRC */ + default: + return -EINVAL; + } + + if (pacs_get_available_contexts_for_conn(conn, dir) == old) { + /* No change. Skip notification */ + return 0; + } + + atomic_set_bit(client->flags, FLAG_AVAILABLE_AUDIO_CONTEXT_CHANGED); + + /* Send notification on encrypted link only */ + if (info.security.level > BT_SECURITY_L1) { + k_work_submit(&deferred_nfy_work); + } + + return 0; +} + int bt_pacs_set_supported_contexts(enum bt_audio_dir dir, enum bt_audio_context contexts) { + uint16_t *supported_contexts = NULL; + uint16_t *available_contexts = NULL; + switch (dir) { case BT_AUDIO_DIR_SINK: - return set_snk_supported_contexts(contexts); +#if defined(CONFIG_BT_PAC_SNK) + supported_contexts = &snk_supported_contexts; + available_contexts = &snk_available_contexts; + break; +#endif /* CONFIG_BT_PAC_SNK */ + return -ENOTSUP; case BT_AUDIO_DIR_SOURCE: - return set_src_supported_contexts(contexts); +#if defined(CONFIG_BT_PAC_SRC) + supported_contexts = &src_supported_contexts; + available_contexts = &src_available_contexts; + break; +#endif /* CONFIG_BT_PAC_SRC */ + return -ENOTSUP; + default: + return -EINVAL; } - return -EINVAL; + if (IS_ENABLED(CONFIG_BT_PACS_SUPPORTED_CONTEXT_NOTIFIABLE) || *supported_contexts == 0) { + return set_supported_contexts(contexts, supported_contexts, available_contexts); + } + + return -EALREADY; } enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) @@ -1149,3 +1281,14 @@ enum bt_audio_context bt_pacs_get_available_contexts(enum bt_audio_dir dir) return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; } + +enum bt_audio_context bt_pacs_get_available_contexts_for_conn(struct bt_conn *conn, + enum bt_audio_dir dir) +{ + CHECKIF(conn == NULL) { + LOG_ERR("NULL conn"); + return BT_AUDIO_CONTEXT_TYPE_PROHIBITED; + } + + return pacs_get_available_contexts_for_conn(conn, dir); +} diff --git a/subsys/bluetooth/audio/pacs_internal.h b/subsys/bluetooth/audio/pacs_internal.h index 9f5291ae579..2c449f7f4ad 100644 --- a/subsys/bluetooth/audio/pacs_internal.h +++ b/subsys/bluetooth/audio/pacs_internal.h @@ -36,5 +36,3 @@ struct bt_pacs_context { uint16_t snk; uint16_t src; } __packed; - -bool bt_pacs_context_available(enum bt_audio_dir dir, uint16_t context); diff --git a/subsys/bluetooth/audio/pbp.c b/subsys/bluetooth/audio/pbp.c new file mode 100644 index 00000000000..3b624045de2 --- /dev/null +++ b/subsys/bluetooth/audio/pbp.c @@ -0,0 +1,87 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(bt_pbp, CONFIG_BT_PBP_LOG_LEVEL); + +int bt_pbp_get_announcement(const uint8_t meta[], size_t meta_len, + enum bt_pbp_announcement_feature features, + struct net_buf_simple *pba_data_buf) +{ + CHECKIF(pba_data_buf == NULL) { + LOG_DBG("No buffer provided for advertising data!\n"); + + return -EINVAL; + } + + CHECKIF((meta == NULL && meta_len != 0) || (meta != NULL && meta_len == 0)) { + LOG_DBG("Invalid metadata combination: %p %zu", meta, meta_len); + + return -EINVAL; + } + + CHECKIF(pba_data_buf->size < (meta_len + BT_PBP_MIN_PBA_SIZE)) { + LOG_DBG("Buffer size needs to be at least %d!\n", meta_len + BT_PBP_MIN_PBA_SIZE); + + return -EINVAL; + } + + /* Fill Announcement data */ + net_buf_simple_add_le16(pba_data_buf, BT_UUID_PBA_VAL); + net_buf_simple_add_u8(pba_data_buf, features); + net_buf_simple_add_u8(pba_data_buf, meta_len); + net_buf_simple_add_mem(pba_data_buf, meta, meta_len); + + return 0; +} + +int bt_pbp_parse_announcement(struct bt_data *data, enum bt_pbp_announcement_feature *features, + uint8_t **meta) +{ + struct bt_uuid_16 adv_uuid; + struct net_buf_simple buf; + uint8_t meta_len = 0; + void *uuid; + + CHECKIF(!data || !features || !meta) { + return -EINVAL; + } + + if (data->type != BT_DATA_SVC_DATA16) { + return -ENOENT; + } + + if (data->data_len < BT_PBP_MIN_PBA_SIZE) { + return -EMSGSIZE; + } + + net_buf_simple_init_with_data(&buf, (void *)data->data, data->data_len); + uuid = net_buf_simple_pull_mem(&buf, BT_UUID_SIZE_16); + + (void)bt_uuid_create(&adv_uuid.uuid, uuid, BT_UUID_SIZE_16); /* cannot fail */ + + if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_PBA)) { + return -ENOENT; + } + + /* Copy source features, metadata length and metadata from the Announcement */ + *features = net_buf_simple_pull_u8(&buf); + meta_len = net_buf_simple_pull_u8(&buf); + if (buf.len < meta_len) { + return -EBADMSG; + } + + *meta = (uint8_t *)net_buf_simple_pull_mem(&buf, meta_len); + + return meta_len; +} diff --git a/subsys/bluetooth/audio/shell/CMakeLists.txt b/subsys/bluetooth/audio/shell/CMakeLists.txt index a5230278330..9913d92994a 100644 --- a/subsys/bluetooth/audio/shell/CMakeLists.txt +++ b/subsys/bluetooth/audio/shell/CMakeLists.txt @@ -59,6 +59,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_CAP_INITIATOR cap_initiator.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_CAP_COMMANDER + cap_commander.c + ) zephyr_library_sources_ifdef( CONFIG_BT_HAS_CLIENT has_client.c @@ -67,6 +71,10 @@ zephyr_library_sources_ifdef( CONFIG_BT_TMAP tmap.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_GMAP + gmap.c + ) # We use BT_BAP_STREAM as a common ground for audio, as that is set whenever # any audio stream functionality is enabled. zephyr_library_sources_ifdef( @@ -81,3 +89,7 @@ zephyr_library_sources_ifdef( CONFIG_BT_BAP_BROADCAST_ASSISTANT bap_broadcast_assistant.c ) +zephyr_library_sources_ifdef( + CONFIG_BT_PBP + pbp.c + ) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 8beae301036..a674b474d07 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -29,6 +29,8 @@ ssize_t audio_ad_data_add(struct bt_data *data, const size_t data_size, const bo ssize_t audio_pa_data_add(struct bt_data *data_array, const size_t data_array_size); ssize_t csis_ad_data_add(struct bt_data *data, const size_t data_size, const bool discoverable); size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool discoverable); +size_t gmap_ad_data_add(struct bt_data data[], size_t data_size); +size_t pbp_ad_data_add(struct bt_data data[], size_t data_size); #if defined(CONFIG_BT_AUDIO) /* Must guard before including audio.h as audio.h uses Kconfigs guarded by @@ -39,12 +41,21 @@ size_t cap_acceptor_ad_data_add(struct bt_data data[], size_t data_size, bool di #include #include +#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT +#define CONTEXT \ + (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA | \ + IS_ENABLED(CONFIG_BT_GMAP) ? BT_AUDIO_CONTEXT_TYPE_GAME : 0U) + +const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg); + struct named_lc3_preset { const char *name; struct bt_bap_lc3_preset preset; }; -const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg); +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg); #if defined(CONFIG_BT_BAP_UNICAST) @@ -99,7 +110,8 @@ struct broadcast_source { struct broadcast_sink { struct bt_bap_broadcast_sink *bap_sink; struct bt_le_per_adv_sync *pa_sync; - struct bt_bap_base received_base; + uint8_t received_base[UINT8_MAX]; + uint8_t base_size; uint32_t broadcast_id; size_t stream_cnt; bool syncable; @@ -223,55 +235,91 @@ struct bap_broadcast_ac_param { size_t chan_cnt; }; +int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv, + const struct bap_broadcast_ac_param *param); + extern struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT]; extern struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ -#if BROADCAST_SNK_SUBGROUP_CNT > 0 -static inline void print_base(const struct shell *sh, const struct bt_bap_base *base) +static inline bool print_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) { - uint8_t bis_indexes[BT_ISO_MAX_GROUP_ISO_COUNT] = {0}; - /* "0xXX " requires 5 characters */ - char bis_indexes_str[5 * ARRAY_SIZE(bis_indexes) + 1]; - size_t index_count = 0; + struct bt_bap_base_codec_id *codec_id = user_data; - for (size_t i = 0U; i < base->subgroup_count; i++) { - const struct bt_bap_base_subgroup *subgroup; + shell_print(ctx_shell, "\t\tBIS index: 0x%02X", bis->index); + /* Print CC data */ + if (codec_id->id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\t\tdata", bis->data, bis->data_len); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, bis->data, bis->data_len); + } - subgroup = &base->subgroups[i]; + return true; +} - shell_print(sh, "Subgroup[%d]:", i); - print_codec_cfg(sh, &subgroup->codec_cfg); +static inline bool print_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + struct bt_bap_base_codec_id codec_id; + uint8_t *data; + int ret; - for (size_t j = 0U; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data; + shell_print(ctx_shell, "Subgroup %p:", subgroup); - bis_data = &subgroup->bis_data[j]; + ret = bt_bap_base_get_subgroup_codec_id(subgroup, &codec_id); + if (ret < 0) { + return false; + } - shell_print(sh, "BIS[%d] index 0x%02x", j, bis_data->index); - bis_indexes[index_count++] = bis_data->index; + shell_print(ctx_shell, "\tCodec Format: 0x%02X", codec_id.id); + shell_print(ctx_shell, "\tCompany ID : 0x%04X", codec_id.cid); + shell_print(ctx_shell, "\tVendor ID : 0x%04X", codec_id.vid); -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 - shell_hexdump(sh, bis_data->data, bis_data->data_len); -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE > 0 */ - } + ret = bt_bap_base_get_subgroup_codec_data(subgroup, &data); + if (ret < 0) { + return false; } - (void)memset(bis_indexes_str, 0, sizeof(bis_indexes_str)); + /* Print CC data */ + if (codec_id.id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\tdata", data, (uint8_t)ret); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, data, (uint8_t)ret); + } - /* Create space separated list of indexes as hex values */ - for (size_t i = 0U; i < index_count; i++) { - char bis_index_str[6]; + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data); + if (ret < 0) { + return false; + } - sprintf(bis_index_str, "0x%02x ", bis_indexes[i]); + /* Print metadata */ + if (codec_id.id == BT_HCI_CODING_FORMAT_LC3) { + print_ltv_array(ctx_shell, "\tdata", data, (uint8_t)ret); + } else { /* If not LC3, we cannot assume it's LTV */ + shell_hexdump(ctx_shell, data, (uint8_t)ret); + } - strcat(bis_indexes_str, bis_index_str); - shell_print(sh, "[%d]: %s", i, bis_index_str); + ret = bt_bap_base_subgroup_foreach_bis(subgroup, print_base_subgroup_bis_cb, &codec_id); + if (ret < 0) { + return false; } - shell_print(sh, "Possible indexes: %s", bis_indexes_str); + return true; +} + +static inline void print_base(const struct bt_bap_base *base) +{ + int err; + + shell_print(ctx_shell, "Presentation delay: %d", bt_bap_base_get_pres_delay(base)); + shell_print(ctx_shell, "Subgroup count: %d", bt_bap_base_get_subgroup_count(base)); + + err = bt_bap_base_foreach_subgroup(base, print_base_subgroup_cb, NULL); + if (err < 0) { + shell_info(ctx_shell, "Invalid BASE: %d", err); + } } -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ static inline void copy_unicast_stream_preset(struct shell_stream *stream, const struct named_lc3_preset *named_preset) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index bbddb0d3ee6..302be473d70 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -24,21 +24,19 @@ #include #include #include +#include #include #include "shell/bt.h" #include "audio.h" -#define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT -#define CONTEXT BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA - #if defined(CONFIG_BT_BAP_UNICAST) struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; static const struct bt_audio_codec_qos_pref qos_pref = - BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u); + BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 10000u, 60000u, 10000u, 60000u); #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) struct bt_bap_unicast_group *default_unicast_group; @@ -57,7 +55,7 @@ struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_ struct broadcast_source default_source; #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ #if defined(CONFIG_BT_BAP_BROADCAST_SINK) -static struct bt_bap_stream broadcast_sink_streams[BROADCAST_SNK_STREAM_CNT]; +static struct bt_bap_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT]; static struct broadcast_sink default_broadcast_sink; #endif /* CONFIG_BT_BAP_BROADCAST_SINK */ static struct bt_bap_stream *default_stream; @@ -222,7 +220,7 @@ static void fill_audio_buf_sin(int16_t *buf, int length_us, int frequency_hz, in const float step = 2 * 3.1415 / sine_period_samples; for (size_t i = 0; i < num_samples; i++) { - const float sample = sin(i * step); + const float sample = sinf(i * step); buf[i] = (int16_t)(AUDIO_VOLUME * sample); } @@ -400,7 +398,8 @@ void sdu_sent_cb(struct bt_bap_stream *bap_stream) } #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */ -const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char *preset_arg) +const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir, + const char *preset_arg) { if (is_unicast) { for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) { @@ -416,6 +415,10 @@ const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, const char } } + if (IS_ENABLED(CONFIG_BT_GMAP)) { + return gmap_get_named_preset(is_unicast, dir, preset_arg); + } + return NULL; } @@ -588,8 +591,7 @@ static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_LC3_FREQ_ANY, BT_AUDIO_CODEC_LC3_DURATION_ANY, - BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, - (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA)); + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2, CONTEXT); static const struct bt_bap_unicast_server_cb unicast_server_cb = { .config = lc3_config, @@ -991,11 +993,12 @@ static int cmd_discover(const struct shell *sh, size_t argc, char *argv[]) static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) { - enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED; + enum bt_audio_location location = BT_AUDIO_LOCATION_MONO_AUDIO; const struct named_lc3_preset *named_preset; struct shell_stream *uni_stream; struct bt_bap_stream *bap_stream; struct bt_bap_ep *ep = NULL; + enum bt_audio_dir dir; unsigned long index; uint8_t conn_index; int err = 0; @@ -1029,6 +1032,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 } else if (!strcmp(argv[1], "sink")) { + dir = BT_AUDIO_DIR_SINK; ep = snks[conn_index][index]; named_preset = default_sink_preset; @@ -1036,6 +1040,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 } else if (!strcmp(argv[1], "source")) { + dir = BT_AUDIO_DIR_SOURCE; ep = srcs[conn_index][index]; named_preset = default_source_preset; @@ -1071,8 +1076,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (loc_bits == BT_AUDIO_LOCATION_PROHIBITED || - loc_bits > BT_AUDIO_LOCATION_ANY) { + if (loc_bits > BT_AUDIO_LOCATION_ANY) { shell_error(sh, "Invalid loc_bits: %lu", loc_bits); return -ENOEXEC; @@ -1083,7 +1087,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) if (argc > i) { arg = argv[++i]; - named_preset = bap_get_named_preset(true, arg); + named_preset = bap_get_named_preset(true, dir, arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); return -ENOEXEC; @@ -1104,39 +1108,37 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[]) copy_unicast_stream_preset(uni_stream, named_preset); /* If location has been modifed, we update the location in the codec configuration */ - if (location != BT_AUDIO_LOCATION_PROHIBITED) { - struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg; - - for (size_t i = 0U; i < codec_cfg->data_len;) { - const uint8_t len = codec_cfg->data[i++]; - uint8_t *value; - uint8_t data_len; - uint8_t type; - - if (len == 0 || len > codec_cfg->data_len - i) { - /* Invalid len field */ - return false; - } + struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg; - type = codec_cfg->data[i++]; - value = &codec_cfg->data[i]; + for (size_t i = 0U; i < codec_cfg->data_len;) { + const uint8_t len = codec_cfg->data[i++]; + uint8_t *value; + uint8_t data_len; + uint8_t type; - if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { - const uint32_t loc_32 = location; + if (len == 0 || len > codec_cfg->data_len - i) { + /* Invalid len field */ + return false; + } - sys_put_le32(loc_32, value); + type = codec_cfg->data[i++]; + value = &codec_cfg->data[i]; - shell_print(sh, "Setting location to 0x%08X", location); - break; - } + if (type == BT_AUDIO_CODEC_CONFIG_LC3_CHAN_ALLOC) { + const uint32_t loc_32 = location; - data_len = len - sizeof(type); + sys_put_le32(loc_32, value); - /* Since we are incrementing i by the value_len, we don't need to increment - * it further in the `for` statement - */ - i += data_len; + shell_print(sh, "Setting location to 0x%08X", location); + break; } + + data_len = len - sizeof(type); + + /* Since we are incrementing i by the value_len, we don't need to increment + * it further in the `for` statement + */ + i += data_len; } if (bap_stream->ep == ep) { @@ -1422,14 +1424,18 @@ static int cmd_stop(const struct shell *sh, size_t argc, char *argv[]) static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) { const struct named_lc3_preset *named_preset; + enum bt_audio_dir dir; bool unicast = true; if (!strcmp(argv[1], "sink")) { + dir = BT_AUDIO_DIR_SINK; named_preset = default_sink_preset; } else if (!strcmp(argv[1], "source")) { + dir = BT_AUDIO_DIR_SOURCE; named_preset = default_source_preset; } else if (!strcmp(argv[1], "broadcast")) { unicast = false; + dir = BT_AUDIO_DIR_SOURCE; named_preset = default_broadcast_source_preset; } else { @@ -1438,7 +1444,7 @@ static int cmd_preset(const struct shell *sh, size_t argc, char *argv[]) } if (argc > 2) { - named_preset = bap_get_named_preset(unicast, argv[2]); + named_preset = bap_get_named_preset(unicast, dir, argv[2]); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", argv[2]); return -ENOEXEC; @@ -1701,77 +1707,18 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct } } -static bool print_data_func_cb(struct bt_data *data, void *user_data) -{ - shell_print(ctx_shell, "type 0x%02x len %u", data->type, data->data_len); - shell_hexdump(ctx_shell, data->data, data->data_len); - - return true; -} - -static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base) +static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base, + size_t base_size) { - uint8_t bis_indexes[BROADCAST_SNK_STREAM_CNT] = { 0 }; - /* "0xXX " requires 5 characters */ - char bis_indexes_str[5 * ARRAY_SIZE(bis_indexes) + 1]; - size_t index_count = 0; + /* Don't print duplicates */ + if (base_size != default_broadcast_sink.base_size || + memcmp(base, &default_broadcast_sink.received_base, base_size) != 0) { + shell_print(ctx_shell, "Received BASE from sink %p:", sink); + (void)memcpy(&default_broadcast_sink.received_base, base, base_size); + default_broadcast_sink.base_size = base_size; - if (memcmp(base, &default_broadcast_sink.received_base, - sizeof(default_broadcast_sink.received_base)) == 0) { - /* Don't print duplicates */ - return; + print_base(base); } - - shell_print(ctx_shell, "Received BASE from sink %p:", sink); - shell_print(ctx_shell, "Presentation delay: %u", base->pd); - shell_print(ctx_shell, "Subgroup count: %u", base->subgroup_count); - - for (int i = 0; i < base->subgroup_count; i++) { - const struct bt_bap_base_subgroup *subgroup; - - subgroup = &base->subgroups[i]; - - shell_print(ctx_shell, "%2sSubgroup[%d]:", "", i); - print_codec_cfg(ctx_shell, &subgroup->codec_cfg); - - for (int j = 0; j < subgroup->bis_count; j++) { - const struct bt_bap_base_bis_data *bis_data; - - bis_data = &subgroup->bis_data[j]; - - shell_print(ctx_shell, "%4sBIS[%d] index 0x%02x", "", i, bis_data->index); - bis_indexes[index_count++] = bis_data->index; - - if (subgroup->codec_cfg.id == BT_HCI_CODING_FORMAT_LC3) { - const int err = - bt_audio_data_parse(bis_data->data, bis_data->data_len, - print_data_func_cb, NULL); - - if (err != 0) { - shell_error(ctx_shell, - "Failed to parse BIS codec config: %d", err); - } - } else { - shell_hexdump(ctx_shell, bis_data->data, bis_data->data_len); - } - } - } - - memset(bis_indexes_str, 0, sizeof(bis_indexes_str)); - /* Create space separated list of indexes as hex values */ - for (int i = 0; i < index_count; i++) { - char bis_index_str[6]; - - sprintf(bis_index_str, "0x%02x ", bis_indexes[i]); - - strcat(bis_indexes_str, bis_index_str); - shell_print(ctx_shell, "[%d]: %s", i, bis_index_str); - } - - shell_print(ctx_shell, "Possible indexes: %s", bis_indexes_str); - - (void)memcpy(&default_broadcast_sink.received_base, base, - sizeof(default_broadcast_sink.received_base)); } static void syncable(struct bt_bap_broadcast_sink *sink, bool encrypted) @@ -2112,7 +2059,8 @@ static int cmd_create_broadcast(const struct shell *sh, size_t argc, i++; arg = argv[i]; - named_preset = bap_get_named_preset(false, arg); + named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE, + arg); if (named_preset == NULL) { shell_error(sh, "Unable to parse named_preset %s", arg); @@ -2396,8 +2344,7 @@ static int cmd_set_loc(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (loc_val == BT_AUDIO_LOCATION_PROHIBITED || - loc_val > BT_AUDIO_LOCATION_ANY) { + if (loc_val > BT_AUDIO_LOCATION_ANY) { shell_error(sh, "Invalid location: %lu", loc_val); return -ENOEXEC; @@ -2561,7 +2508,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) #if defined(CONFIG_BT_AUDIO_TX) #define DATA_MTU CONFIG_BT_ISO_TX_MTU -NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, 8, NULL); +NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); static int cmd_send(const struct shell *sh, size_t argc, char *argv[]) { @@ -2746,11 +2693,6 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) shell_print(sh, "Started transmitting on broadcast stream %p", bap_stream); } } else { - if (stream_start_sine_verify(default_stream)) { - shell_error(sh, "Invalid stream %p", default_stream); - return -ENOEXEC; - } - err = init_lc3(default_stream); if (err != 0) { shell_error(sh, "Failed to init LC3 %d", err); @@ -2758,6 +2700,11 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } + if (!stream_start_sine_verify(default_stream)) { + shell_error(sh, "Invalid stream %p", default_stream); + return -ENOEXEC; + } + err = stream_start_sine(default_stream); if (err != 0) { shell_error(sh, "Failed to start TX for stream %p: %d", default_stream, @@ -2991,6 +2938,10 @@ static ssize_t connectable_ad_data_add(struct bt_data *data_array, true); } + if (IS_ENABLED(CONFIG_BT_GMAP)) { + ad_len += gmap_ad_data_add(&data_array[ad_len], data_array_size - ad_len); + } + if (ARRAY_SIZE(ad_ext_uuid16) > 0) { size_t uuid16_size; diff --git a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c index 00892ec6187..64f0f5f3890 100644 --- a/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/shell/bap_broadcast_assistant.c @@ -28,7 +28,8 @@ /* BIS sync is a 32-bit bitfield where BIT(0) is not allowed */ #define VALID_BIS_SYNC(_bis_sync) ((bis_sync & BIT(0)) == 0U && bis_sync < UINT32_MAX) -static struct bt_bap_base received_base; +static uint8_t received_base[UINT8_MAX]; +static uint8_t received_base_size; static struct bt_auto_scan { uint32_t broadcast_id; @@ -40,31 +41,20 @@ static struct bt_auto_scan { static bool pa_decode_base(struct bt_data *data, void *user_data) { - struct bt_bap_base base = { 0 }; - int err; - - if (data->type != BT_DATA_SVC_DATA16) { - return true; - } + const struct bt_bap_base *base = bt_bap_base_get_base_from_ad(data); - if (data->data_len < BT_BAP_BASE_MIN_SIZE) { + /* Base is NULL if the data does not contain a valid BASE */ + if (base == NULL) { return true; } - err = bt_bap_decode_base(data, &base); - if (err != 0 && err != -ENOMSG) { - shell_error(ctx_shell, "Failed to decode BASE: %d", err); - - return false; - } - /* Compare BASE and print if different */ - if (memcmp(&base, &received_base, sizeof(base)) != 0) { - (void)memcpy(&received_base, &base, sizeof(base)); + if (data->data_len != received_base_size || + memcmp(data->data, received_base, data->data_len) != 0) { + (void)memcpy(&received_base, data->data, data->data_len); + received_base_size = data->data_len; -#if BROADCAST_SNK_SUBGROUP_CNT > 0 - print_base(ctx_shell, &received_base); -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ + print_base(base); } return false; @@ -779,6 +769,48 @@ static int cmd_bap_broadcast_assistant_mod_src(const struct shell *sh, return result; } +static inline bool add_pa_sync_base_subgroup_bis_cb(const struct bt_bap_base_subgroup_bis *bis, + void *user_data) +{ + struct bt_bap_scan_delegator_subgroup *subgroup_param = user_data; + + subgroup_param->bis_sync |= BIT(bis->index); + + return true; +} + +static inline bool add_pa_sync_base_subgroup_cb(const struct bt_bap_base_subgroup *subgroup, + void *user_data) +{ + struct bt_bap_broadcast_assistant_add_src_param *param = user_data; + struct bt_bap_scan_delegator_subgroup *subgroup_param; + uint8_t *data; + int ret; + + ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &data); + if (ret < 0) { + return false; + } + + subgroup_param = ¶m->subgroups[param->num_subgroups]; + + if (ret > ARRAY_SIZE(subgroup_param->metadata)) { + shell_info(ctx_shell, "Cannot fit %d octets into subgroup param with size %zu", ret, + ARRAY_SIZE(subgroup_param->metadata)); + return false; + } + + ret = bt_bap_base_subgroup_foreach_bis(subgroup, add_pa_sync_base_subgroup_bis_cb, + subgroup_param); + if (ret < 0) { + return false; + } + + param->num_subgroups++; + + return true; +} + static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, size_t argc, char **argv) { @@ -855,45 +887,12 @@ static int cmd_bap_broadcast_assistant_add_pa_sync(const struct shell *sh, bis_bitfield_req |= BIT(index); } - /* The MIN is used to handle `array-bounds` error on some compilers */ - param.num_subgroups = MIN(received_base.subgroup_count, BROADCAST_SNK_SUBGROUP_CNT); -#if BROADCAST_SNK_SUBGROUP_CNT > 0 - struct bt_bap_scan_delegator_subgroup subgroup_params[BROADCAST_SNK_SUBGROUP_CNT] = {0}; - - param.subgroups = subgroup_params; - for (size_t i = 0; i < param.num_subgroups; i++) { - struct bt_bap_scan_delegator_subgroup *subgroup_param = &subgroup_params[i]; - const struct bt_bap_base_subgroup *subgroup = &received_base.subgroups[i]; - uint32_t subgroup_bis_indexes = 0U; - ssize_t metadata_len; - - for (size_t j = 0U; j < MIN(subgroup->bis_count, ARRAY_SIZE(subgroup->bis_data)); - j++) { - const struct bt_bap_base_bis_data *bis_data = &subgroup->bis_data[j]; - - subgroup_bis_indexes |= BIT(bis_data->index); - } - - subgroup_param->bis_sync = subgroup_bis_indexes & bis_bitfield_req; - -#if CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 - metadata_len = subgroup->codec_cfg.meta_len; - if (metadata_len > sizeof(subgroup_param->metadata)) { - shell_error(sh, - "Could not set %zu octets of metadata for subgroup_param of " - "size %zu", - metadata_len, sizeof(subgroup_param->metadata)); - - return -ENOEXEC; - } - - memcpy(subgroup_param->metadata, subgroup->codec_cfg.meta, metadata_len); -#else - metadata_len = 0U; -#endif /* CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE > 0 */ - subgroup_param->metadata_len = metadata_len; + err = bt_bap_base_foreach_subgroup((const struct bt_bap_base *)received_base, + add_pa_sync_base_subgroup_cb, ¶m); + if (err < 0) { + shell_error(ctx_shell, "Could not add BASE to params %d", err); + return -ENOEXEC; } -#endif /* BROADCAST_SNK_SUBGROUP_CNT > 0 */ err = bt_bap_broadcast_assistant_add_src(default_conn, ¶m); if (err != 0) { diff --git a/subsys/bluetooth/audio/shell/bap_scan_delegator.c b/subsys/bluetooth/audio/shell/bap_scan_delegator.c index 9ca494d36ae..721553f4ad1 100644 --- a/subsys/bluetooth/audio/shell/bap_scan_delegator.c +++ b/subsys/bluetooth/audio/shell/bap_scan_delegator.c @@ -16,6 +16,7 @@ #include #include #include +#include